diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index a7f7ea7aaa9f..1a5d9a887963 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -65,7 +65,13 @@ pub fn mem_finalize( }; (smallvec![], mem) } else { - let tmp = writable_spilltmp_reg(); + // The stack-limit chain may use x16 as its base. Do not + // overwrite that base while materializing a large offset. + let tmp = if basereg == spilltmp_reg() { + writable_tmp2_reg() + } else { + writable_spilltmp_reg() + }; ( Inst::load_constant(tmp, off as u64), AMode::RegExtended { diff --git a/cranelift/filetests/filetests/runtests/stack-limit-chain-large-offset.clif b/cranelift/filetests/filetests/runtests/stack-limit-chain-large-offset.clif new file mode 100644 index 000000000000..0169afb2f93c --- /dev/null +++ b/cranelift/filetests/filetests/runtests/stack-limit-chain-large-offset.clif @@ -0,0 +1,34 @@ +;; Regression test for https://github.com/bytecodealliance/wasmtime/issues/14946 +;; The second stack-limit load uses x16 as its base. A large negative +;; offset must be materialized in x17 instead of overwriting x16. +test run +target x86_64 +target aarch64 + +function %callee(i64 vmctx) -> i8 system_v { + gv0 = vmctx + gv1 = load.i64 notrap aligned gv0-512 + gv2 = load.i64 notrap aligned gv1-520 + stack_limit = gv2 + ss0 = explicit_slot 64 +block0(v0: i64): + v1 = iconst.i8 1 + return v1 +} + +function %main() -> i8 system_v { + ss0 = explicit_slot 2048 + sig0 = (i64 vmctx) -> i8 system_v + fn0 = %callee sig0 +block0: + v0 = stack_addr.i64 ss0+1024 + v1 = stack_addr.i64 ss0+512 + store.i64 notrap aligned v0, v1 + v2 = stack_addr.i64 ss0+504 + v3 = iconst.i64 0 + store.i64 notrap aligned v3, v2 + v4 = call fn0(v0) + return v4 +} + +; run: %main() == 1