diff --git a/lib/compiler-singlepass/src/emitter_arm64.rs b/lib/compiler-singlepass/src/emitter_arm64.rs index aa7d7c90443..65505f07252 100644 --- a/lib/compiler-singlepass/src/emitter_arm64.rs +++ b/lib/compiler-singlepass/src/emitter_arm64.rs @@ -354,6 +354,12 @@ pub trait EmitterARM64 { reg: Location, label: Label, ) -> Result<(), CompileError>; + fn emit_cbz_label_far( + &mut self, + sz: Size, + reg: Location, + label: Label, + ) -> Result<(), CompileError>; fn emit_tbz_label( &mut self, sz: Size, @@ -2607,6 +2613,36 @@ impl EmitterARM64 for Assembler { } Ok(()) } + fn emit_cbz_label_far( + &mut self, + sz: Size, + reg: Location, + label: Label, + ) -> Result<(), CompileError> { + let near_label: Label = self.get_label(); + let continue_label: Label = self.get_label(); + + match (sz, reg) { + (Size::S32, Location::GPR(reg)) => { + let reg = reg.into_index() as u32; + + dynasm!(self ; cbz W(reg), => near_label); + dynasm!(self ; b => continue_label); + } + (Size::S64, Location::GPR(reg)) => { + let reg = reg.into_index() as u32; + dynasm!(self ; cbz W(reg), => label); + dynasm!(self ; b => continue_label); + } + _ => codegen_error!("singlepass can't emit CBZ {:?} {:?} {:?}", sz, reg, label), + } + self.emit_label(near_label)?; + dynasm!(self ; b => label ); + + self.emit_label(continue_label)?; + + Ok(()) + } fn emit_tbz_label( &mut self, sz: Size, diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index 2518dec0a0a..9d449638a1c 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -2810,7 +2810,7 @@ impl Machine for MachineARM64 { let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.assembler - .emit_cbz_label(Size::S32, src2, integer_division_by_zero)?; + .emit_cbz_label_far(Size::S32, src2, integer_division_by_zero)?; let offset = self.mark_instruction_with_trap_code(TrapCode::IntegerOverflow); self.assembler.emit_udiv(Size::S32, src1, src2, dest)?; if ret != dest { @@ -2835,7 +2835,7 @@ impl Machine for MachineARM64 { let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.assembler - .emit_cbz_label(Size::S32, src2, integer_division_by_zero)?; + .emit_cbz_label_far(Size::S32, src2, integer_division_by_zero)?; let label_nooverflow = self.assembler.get_label(); let tmp = self.location_to_reg( Size::S32, @@ -2887,7 +2887,7 @@ impl Machine for MachineARM64 { dest }; self.assembler - .emit_cbz_label(Size::S32, src2, integer_division_by_zero)?; + .emit_cbz_label_far(Size::S32, src2, integer_division_by_zero)?; let offset = self.mark_instruction_with_trap_code(TrapCode::IntegerOverflow); self.assembler.emit_udiv(Size::S32, src1, src2, dest)?; // unsigned remainder : src1 - (src1/src2)*src2 @@ -2925,7 +2925,7 @@ impl Machine for MachineARM64 { dest }; self.assembler - .emit_cbz_label(Size::S32, src2, integer_division_by_zero)?; + .emit_cbz_label_far(Size::S32, src2, integer_division_by_zero)?; let offset = self.mark_instruction_with_trap_code(TrapCode::IntegerOverflow); self.assembler.emit_sdiv(Size::S32, src1, src2, dest)?; // unsigned remainder : src1 - (src1/src2)*src2 diff --git a/tests/compilers/data/4519_singlepass_panic.wasm b/tests/compilers/data/4519_singlepass_panic.wasm new file mode 100644 index 00000000000..96fb562dc6d Binary files /dev/null and b/tests/compilers/data/4519_singlepass_panic.wasm differ diff --git a/tests/compilers/issues.rs b/tests/compilers/issues.rs index 471e465c30c..3261fce42d2 100644 --- a/tests/compilers/issues.rs +++ b/tests/compilers/issues.rs @@ -442,3 +442,20 @@ fn large_number_local(mut config: crate::Config) -> Result<()> { assert_eq!(&Value::I64(1_i64), result.get(0).unwrap()); Ok(()) } + +#[cfg(target_arch = "aarch64")] +#[compiler_test(issues)] +/// Singlepass panics on aarch64 for long relocations. +/// +/// Note: this one is specific to Singlepass, but we want to test in all +/// available compilers. +/// +/// https://github.com/wasmerio/wasmer/issues/4519 +fn issue_4519(mut config: crate::Config) -> Result<()> { + let wasm = include_bytes!("./data/4519_singlepass_panic.wasm"); + + let mut store = config.store(); + let module = Module::new(&store, wasm)?; + + Ok(()) +}