Repository: bytecodealliance/wasmtime
Pull request #9252 (2024-09-16 09:20:14)

Winch aarch64 dynamic heap
Hey 👋

This PR implements everything needed to run winch for aarch64 with dynamic heap. It implements the following macro instructions : `trap`, `trapif`, `cmov` and `checked_add`.

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->


github-actions[bot]: #### Subscribe to Label Action

cc @saulecabrera

<details>
This issue or pull request has been labeled: "winch"

Thus the following users have been cc'd because of the following labels:

* saulecabrera: winch

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

[Learn more.](https://github.com/bytecodealliance/subscribe-to-label-action)
</details>
saulecabrera: @vulc41n it looks like an update to the filetests is needed?

Patch:
diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml
index 719d570b6..8fcc96cfa 100644
--- a/crates/cranelift/Cargo.toml
+++ b/crates/cranelift/Cargo.toml
@@ -18,7 +18,7 @@ workspace = true
 anyhow = { workspace = true }
 log = { workspace = true }
 wasmtime-environ = { workspace = true, features = ['compile'] }
-cranelift-codegen = { workspace = true, features = ["host-arch"] }
+cranelift-codegen = { workspace = true, features = ["host-arch", "timing"] }
 cranelift-frontend = { workspace = true }
 cranelift-entity = { workspace = true }
 cranelift-native = { workspace = true }
diff --git a/winch/codegen/src/isa/aarch64/asm.rs b/winch/codegen/src/isa/aarch64/asm.rs
index 2e63478e7..2c6a668da 100644
--- a/winch/codegen/src/isa/aarch64/asm.rs
+++ b/winch/codegen/src/isa/aarch64/asm.rs
@@ -6,6 +6,7 @@ use crate::{
     masm::OperandSize,
     reg::{writable, Reg, WritableReg},
 };
+use cranelift_codegen::ir::TrapCode;
 use cranelift_codegen::isa::aarch64::inst::{
     BitOp, BranchTarget, Cond, CondBrKind, FPULeftShiftImm, FPUOp1, FPUOp2,
     FPUOpRI::{self, UShr32, UShr64},
@@ -674,6 +675,17 @@ impl Assembler {
         });
     }
 
+    // If the condition is true, Conditional Select writes rm to rd. If the condition is false,
+    // it writes rn to rd
+    pub fn csel(&mut self, rm: Reg, rn: Reg, rd: WritableReg, cond: Cond) {
+        self.emit(Inst::CSel {
+            rd: rd.map(Into::into),
+            rm: rm.into(),
+            rn: rn.into(),
+            cond,
+        });
+    }
+
     // Population Count per byte.
     pub fn cnt(&mut self, rd: Reg) {
         self.emit(Inst::VecMisc {
@@ -699,6 +711,19 @@ impl Assembler {
         self.emit_alu_rrr(ALUOp::AndS, rm, rn, writable!(regs::zero()), size);
     }
 
+    /// Permanently Undefined.
+    pub fn udf(&mut self, code: TrapCode) {
+        self.emit(Inst::Udf { trap_code: code });
+    }
+
+    /// Conditional trap.
+    pub fn trapif(&mut self, cc: Cond, code: TrapCode) {
+        self.emit(Inst::TrapIf {
+            kind: CondBrKind::Cond(cc),
+            trap_code: code,
+        });
+    }
+
     // Helpers for ALU operations.
 
     fn emit_alu_rri(&mut self, op: ALUOp, imm: Imm12, rn: Reg, rd: WritableReg, size: OperandSize) {
diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs
index eb12ceb75..dbc17b037 100644
--- a/winch/codegen/src/isa/aarch64/masm.rs
+++ b/winch/codegen/src/isa/aarch64/masm.rs
@@ -12,7 +12,7 @@ use crate::{
 use cranelift_codegen::{
     binemit::CodeOffset,
     ir::{RelSourceLoc, SourceLoc},
-    isa::aarch64::inst::VectorSize,
+    isa::aarch64::inst::{Cond, VectorSize},
     settings, Final, MachBufferFinalized, MachLabel,
 };
 use regalloc2::RegClass;
@@ -238,8 +238,8 @@ impl Masm for MacroAssembler {
         }
     }
 
-    fn cmov(&mut self, _dst: WritableReg, _src: Reg, _cc: IntCmpKind, _size: OperandSize) {
-        todo!()
+    fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, _size: OperandSize) {
+        self.asm.csel(src, src, dst, Cond::from(cc));
     }
 
     fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) {
@@ -262,13 +262,14 @@ impl Masm for MacroAssembler {
 
     fn checked_uadd(
         &mut self,
-        _dst: WritableReg,
-        _lhs: Reg,
-        _rhs: RegImm,
-        _size: OperandSize,
-        _trap: TrapCode,
+        dst: WritableReg,
+        lhs: Reg,
+        rhs: RegImm,
+        size: OperandSize,
+        trap: TrapCode,
     ) {
-        todo!()
+        self.add(dst, lhs, rhs, size);
+        self.asm.trapif(Cond::Hs, trap);
     }
 
     fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) {
@@ -632,7 +633,7 @@ impl Masm for MacroAssembler {
     }
 
     fn unreachable(&mut self) {
-        todo!()
+        self.asm.udf(wasmtime_cranelift::TRAP_UNREACHABLE);
     }
 
     fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) {
@@ -647,16 +648,16 @@ impl Masm for MacroAssembler {
         self.asm.jmp_table(rest, default, index, tmp1, tmp);
     }
 
-    fn trap(&mut self, _code: TrapCode) {
-        todo!()
+    fn trap(&mut self, code: TrapCode) {
+        self.asm.udf(code);
     }
 
     fn trapz(&mut self, _src: Reg, _code: TrapCode) {
         todo!()
     }
 
-    fn trapif(&mut self, _cc: IntCmpKind, _code: TrapCode) {
-        todo!()
+    fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) {
+        self.asm.trapif(cc.into(), code);
     }
 
     fn start_source_loc(&mut self, loc: RelSourceLoc) -> (CodeOffset, RelSourceLoc) {


Test patch:
diff --git a/tests/disas/winch/aarch64/load/dynamic_heap.wat b/tests/disas/winch/aarch64/load/dynamic_heap.wat
new file mode 100644
index 000000000..27d639fd2
--- /dev/null
+++ b/tests/disas/winch/aarch64/load/dynamic_heap.wat
@@ -0,0 +1,105 @@
+;;! target = "aarch64"
+;;! test = "winch"
+;;! flags = "-O static-memory-maximum-size=100 -O dynamic-memory-guard-size=0xffff"
+
+(module
+  (memory (export "memory") 17)
+  (func (export "run") (param i32) (result i32 i32 i32)
+    ;; Within the guard region.
+    local.get 0
+    i32.load offset=0
+    ;; Also within the guard region, bounds check should GVN with previous.
+    local.get 0
+    i32.load offset=4
+
+    ;; Outside the guard region, needs additional bounds checks.
+    local.get 0
+    i32.load offset=0x000fffff
+  )
+  (data (i32.const 0) "\45\00\00\00\a4\01\00\00")
+  (data (i32.const 0x000fffff) "\39\05\00\00")
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x1
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x1, [x28, #0x18]
+;;       stur    x2, [x28, #0x10]
+;;       stur    w3, [x28, #0xc]
+;;       stur    x0, [x28]
+;;       ldur    w0, [x28, #0xc]
+;;       ldur    x1, [x9, #0x68]
+;;       mov     w2, w0
+;;       add     x2, x2, #4
+;;       b.hs    #0x134
+;;   3c: cmp     x2, x1, uxtx
+;;       b.hi    #0x138
+;;   44: ldur    x3, [x9, #0x60]
+;;       add     x3, x3, x0, uxtx
+;;       mov     x16, #0
+;;       mov     x4, x16
+;;       cmp     x2, x1, uxtx
+;;       csel    x3, x4, x4, hi
+;;       ldur    w0, [x3]
+;;       ldur    w1, [x28, #0xc]
+;;       ldur    x2, [x9, #0x68]
+;;       mov     w3, w1
+;;       add     x3, x3, #8
+;;       b.hs    #0x13c
+;;   74: cmp     x3, x2, uxtx
+;;       b.hi    #0x140
+;;   7c: ldur    x4, [x9, #0x60]
+;;       add     x4, x4, x1, uxtx
+;;       add     x4, x4, #4
+;;       mov     x16, #0
+;;       mov     x5, x16
+;;       cmp     x3, x2, uxtx
+;;       csel    x4, x5, x5, hi
+;;       ldur    w1, [x4]
+;;       ldur    w2, [x28, #0xc]
+;;       ldur    x3, [x9, #0x68]
+;;       mov     w4, w2
+;;       mov     w16, #3
+;;       movk    w16, #0x10, lsl #16
+;;       add     x4, x4, x16, uxtx
+;;       b.hs    #0x144
+;;   b8: cmp     x4, x3, uxtx
+;;       b.hi    #0x148
+;;   c0: ldur    x5, [x9, #0x60]
+;;       add     x5, x5, x2, uxtx
+;;       orr     x16, xzr, #0xfffff
+;;       add     x5, x5, x16, uxtx
+;;       mov     x16, #0
+;;       mov     x6, x16
+;;       cmp     x4, x3, uxtx
+;;       csel    x5, x6, x6, hi
+;;       ldur    w2, [x5]
+;;       sub     sp, sp, #4
+;;       mov     x28, sp
+;;       stur    w0, [x28]
+;;       sub     sp, sp, #4
+;;       mov     x28, sp
+;;       stur    w1, [x28]
+;;       mov     w0, w2
+;;       ldur    x1, [x28, #8]
+;;       ldur    w16, [x28]
+;;       add     sp, sp, #4
+;;       mov     x28, sp
+;;       stur    w16, [x1]
+;;       ldur    w16, [x28]
+;;       add     sp, sp, #4
+;;       mov     x28, sp
+;;       stur    w16, [x1, #4]
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
+;;  134: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  138: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  13c: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  140: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  144: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  148: .byte   0x1f, 0xc1, 0x00, 0x00
diff --git a/tests/disas/winch/aarch64/store/dynamic_heap.wat b/tests/disas/winch/aarch64/store/dynamic_heap.wat
new file mode 100644
index 000000000..e7d1722bb
--- /dev/null
+++ b/tests/disas/winch/aarch64/store/dynamic_heap.wat
@@ -0,0 +1,94 @@
+;;! target = "aarch64"
+;;! test = "winch"
+;;! flags = "-O static-memory-maximum-size=0 -O dynamic-memory-guard-size=0xffff"
+
+(module
+  (memory (export "memory") 1)
+  (func (export "run") (param i32 i32 i32 i32)
+    ;; Within the guard region.
+    local.get 0
+    local.get 1
+    i32.store offset=0
+    ;; Also within the guard region, bounds check should GVN with previous.
+    local.get 0
+    local.get 2
+    i32.store offset=4
+    ;; Outside the guard region, needs additional bounds checks.
+    local.get 0
+    local.get 3
+    i32.store offset=0x000fffff
+  )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    w2, [x28, #0xc]
+;;       stur    w3, [x28, #8]
+;;       stur    w4, [x28, #4]
+;;       stur    w5, [x28]
+;;       ldur    w0, [x28, #8]
+;;       ldur    w1, [x28, #0xc]
+;;       ldur    x2, [x9, #0x68]
+;;       mov     w3, w1
+;;       add     x3, x3, #4
+;;       b.hs    #0x108
+;;   48: cmp     x3, x2, uxtx
+;;       b.hi    #0x10c
+;;   50: ldur    x4, [x9, #0x60]
+;;       add     x4, x4, x1, uxtx
+;;       mov     x16, #0
+;;       mov     x5, x16
+;;       cmp     x3, x2, uxtx
+;;       csel    x4, x5, x5, hi
+;;       stur    w0, [x4]
+;;       ldur    w0, [x28, #4]
+;;       ldur    w1, [x28, #0xc]
+;;       ldur    x2, [x9, #0x68]
+;;       mov     w3, w1
+;;       add     x3, x3, #8
+;;       b.hs    #0x110
+;;   84: cmp     x3, x2, uxtx
+;;       b.hi    #0x114
+;;   8c: ldur    x4, [x9, #0x60]
+;;       add     x4, x4, x1, uxtx
+;;       add     x4, x4, #4
+;;       mov     x16, #0
+;;       mov     x5, x16
+;;       cmp     x3, x2, uxtx
+;;       csel    x4, x5, x5, hi
+;;       stur    w0, [x4]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #0xc]
+;;       ldur    x2, [x9, #0x68]
+;;       mov     w3, w1
+;;       mov     w16, #3
+;;       movk    w16, #0x10, lsl #16
+;;       add     x3, x3, x16, uxtx
+;;       b.hs    #0x118
+;;   cc: cmp     x3, x2, uxtx
+;;       b.hi    #0x11c
+;;   d4: ldur    x4, [x9, #0x60]
+;;       add     x4, x4, x1, uxtx
+;;       orr     x16, xzr, #0xfffff
+;;       add     x4, x4, x16, uxtx
+;;       mov     x16, #0
+;;       mov     x5, x16
+;;       cmp     x3, x2, uxtx
+;;       csel    x4, x5, x5, hi
+;;       stur    w0, [x4]
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
+;;  108: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  10c: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  110: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  114: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  118: .byte   0x1f, 0xc1, 0x00, 0x00
+;;  11c: .byte   0x1f, 0xc1, 0x00, 0x00