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 000000000000..27d639fd2499 --- /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 000000000000..e7d1722bb409 --- /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 diff --git a/winch/codegen/src/isa/aarch64/asm.rs b/winch/codegen/src/isa/aarch64/asm.rs index 2e63478e7938..2c6a668da1cb 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 eb12ceb75364..dbc17b037d19 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) {