summaryrefslogtreecommitdiff
path: root/zjit/src/codegen.rs
diff options
context:
space:
mode:
authorJeff Zhang <jeff@39bytes.dev>2026-01-20 18:31:26 -0500
committerAlan Wu <XrXr@users.noreply.github.com>2026-01-20 19:42:25 -0500
commitf7e73ba3bf9ced61ac9cca5cf042fd0efe398f69 (patch)
treec2aa093c35376c849ac01ad1c4e80f1751633bcb /zjit/src/codegen.rs
parente24b52885feaa87cdb5796c2a08e5995274e83cb (diff)
ZJIT: A64: Avoid gaps in the stack when preserving registers for calls
Previously, we used a `str x, [sp, #-0x10]!` for each value, which left an 8-byte gap. Use STP to store a pair at a time instead.
Diffstat (limited to 'zjit/src/codegen.rs')
-rw-r--r--zjit/src/codegen.rs26
1 files changed, 22 insertions, 4 deletions
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index 0ae85c24a2..4dae41bf02 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -2638,8 +2638,17 @@ pub fn gen_function_stub_hit_trampoline(cb: &mut CodeBlock) -> Result<CodePtr, C
asm.frame_setup(&[]);
asm_comment!(asm, "preserve argument registers");
- for &reg in ALLOC_REGS.iter() {
- asm.cpush(Opnd::Reg(reg));
+
+ for pair in ALLOC_REGS.chunks(2) {
+ match *pair {
+ [reg0, reg1] => {
+ asm.cpush_pair(Opnd::Reg(reg0), Opnd::Reg(reg1));
+ }
+ [reg] => {
+ asm.cpush(Opnd::Reg(reg));
+ }
+ _ => unreachable!("chunks(2)")
+ }
}
if cfg!(target_arch = "x86_64") && ALLOC_REGS.len() % 2 == 1 {
asm.cpush(Opnd::Reg(ALLOC_REGS[0])); // maintain alignment for x86_64
@@ -2653,8 +2662,17 @@ pub fn gen_function_stub_hit_trampoline(cb: &mut CodeBlock) -> Result<CodePtr, C
if cfg!(target_arch = "x86_64") && ALLOC_REGS.len() % 2 == 1 {
asm.cpop_into(Opnd::Reg(ALLOC_REGS[0]));
}
- for &reg in ALLOC_REGS.iter().rev() {
- asm.cpop_into(Opnd::Reg(reg));
+
+ for pair in ALLOC_REGS.chunks(2).rev() {
+ match *pair {
+ [reg] => {
+ asm.cpop_into(Opnd::Reg(reg));
+ }
+ [reg0, reg1] => {
+ asm.cpop_pair_into(Opnd::Reg(reg1), Opnd::Reg(reg0));
+ }
+ _ => unreachable!("chunks(2)")
+ }
}
// Discard the current frame since the JIT function will set it up again