Skip to content

Commit cfc9234

Browse files
committed
Compile Param into VReg and ParallelMov (Shopify/zjit#87)
1 parent dd44935 commit cfc9234

File tree

6 files changed

+344
-256
lines changed

6 files changed

+344
-256
lines changed

test/ruby/test_zjit.rb

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,14 @@ def test(n)
348348
}
349349
end
350350

351+
def test_live_reg_past_ccall
352+
assert_compiles '2', %q{
353+
def callee = 1
354+
def test = callee + callee
355+
test
356+
}
357+
end
358+
351359
def test_recursive_fact
352360
assert_compiles '[1, 6, 720]', %q{
353361
def fact(n)
@@ -360,18 +368,17 @@ def fact(n)
360368
}
361369
end
362370

363-
# FIXME: currently produces the wrong value
364-
#def test_recursive_fib
365-
# assert_compiles '[0, 2, 3]', %q{
366-
# def fib(n)
367-
# if n < 2
368-
# return n
369-
# end
370-
# return fib(n-1) + fib(n-2)
371-
# end
372-
# [fib(0), fib(3), fib(4)]
373-
# }
374-
#end
371+
def test_recursive_fib
372+
assert_compiles '[0, 2, 3]', %q{
373+
def fib(n)
374+
if n < 2
375+
return n
376+
end
377+
return fib(n-1) + fib(n-2)
378+
end
379+
[fib(0), fib(3), fib(4)]
380+
}
381+
end
375382

376383
private
377384

zjit/src/backend/arm64/mod.rs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,7 @@ impl From<Opnd> for A64Opnd {
7070
Opnd::Mem(Mem { base: MemBase::VReg(_), .. }) => {
7171
panic!("attempted to lower an Opnd::Mem with a MemBase::VReg base")
7272
},
73-
Opnd::CArg(_) => panic!("attempted to lower an Opnd::CArg"),
7473
Opnd::VReg { .. } => panic!("attempted to lower an Opnd::VReg"),
75-
Opnd::Param { .. } => panic!("attempted to lower an Opnd::Param"),
7674
Opnd::Value(_) => panic!("attempted to lower an Opnd::Value"),
7775
Opnd::None => panic!(
7876
"Attempted to lower an Opnd::None. This often happens when an out operand was not allocated for an instruction because the output of the instruction was not used. Please ensure you are using the output."
@@ -175,9 +173,19 @@ fn emit_load_value(cb: &mut CodeBlock, rd: A64Opnd, value: u64) -> usize {
175173
}
176174
}
177175

178-
/// List of registers that can be used for stack temps.
179-
/// These are caller-saved registers.
180-
pub static TEMP_REGS: [Reg; 5] = [X1_REG, X9_REG, X10_REG, X14_REG, X15_REG];
176+
/// List of registers that can be used for register allocation.
177+
/// This has the same number of registers for x86_64 and arm64.
178+
/// SCRATCH0 and SCRATCH1 are excluded.
179+
pub const ALLOC_REGS: &'static [Reg] = &[
180+
X0_REG,
181+
X1_REG,
182+
X2_REG,
183+
X3_REG,
184+
X4_REG,
185+
X5_REG,
186+
X11_REG,
187+
X12_REG,
188+
];
181189

182190
#[derive(Debug, PartialEq)]
183191
enum EmitError {
@@ -198,7 +206,7 @@ impl Assembler
198206
/// Note: we intentionally exclude C_RET_REG (X0) from this list
199207
/// because of the way it's used in gen_leave() and gen_leave_exit()
200208
pub fn get_alloc_regs() -> Vec<Reg> {
201-
vec![X11_REG, X12_REG, X13_REG]
209+
ALLOC_REGS.to_vec()
202210
}
203211

204212
/// Get a list of all of the caller-saved registers
@@ -279,7 +287,7 @@ impl Assembler
279287
/// do follow that encoding, and if they don't then we load them first.
280288
fn split_bitmask_immediate(asm: &mut Assembler, opnd: Opnd, dest_num_bits: u8) -> Opnd {
281289
match opnd {
282-
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::VReg { .. } | Opnd::Param { .. } => opnd,
290+
Opnd::Reg(_) | Opnd::VReg { .. } => opnd,
283291
Opnd::Mem(_) => split_load_operand(asm, opnd),
284292
Opnd::Imm(imm) => {
285293
if imm == 0 {
@@ -312,7 +320,7 @@ impl Assembler
312320
/// a certain size. If they don't then we need to load them first.
313321
fn split_shifted_immediate(asm: &mut Assembler, opnd: Opnd) -> Opnd {
314322
match opnd {
315-
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::VReg { .. } | Opnd::Param { .. } => opnd,
323+
Opnd::Reg(_) | Opnd::VReg { .. } => opnd,
316324
Opnd::Mem(_) => split_load_operand(asm, opnd),
317325
Opnd::Imm(imm) => if ShiftedImmediate::try_from(imm as u64).is_ok() {
318326
opnd
@@ -402,9 +410,6 @@ impl Assembler
402410
*opnd = asm.load(*opnd);
403411
}
404412
},
405-
Opnd::Param { idx } => {
406-
*opnd = Assembler::alloc_param_reg(*idx);
407-
}
408413
_ => {}
409414
};
410415
}
@@ -489,6 +494,7 @@ impl Assembler
489494
// register.
490495
// Note: the iteration order is reversed to avoid corrupting x0,
491496
// which is both the return value and first argument register
497+
let mut args: Vec<(Reg, Opnd)> = vec![];
492498
for (idx, opnd) in opnds.into_iter().enumerate().rev() {
493499
// If the value that we're sending is 0, then we can use
494500
// the zero register, so in this case we'll just send
@@ -498,9 +504,9 @@ impl Assembler
498504
Opnd::Mem(_) => split_memory_address(asm, *opnd),
499505
_ => *opnd
500506
};
501-
502-
asm.load_into(Opnd::c_arg(C_ARG_OPNDS[idx]), value);
507+
args.push((C_ARG_OPNDS[idx].unwrap_reg(), value));
503508
}
509+
asm.parallel_mov(args);
504510

505511
// Now we push the CCall without any arguments so that it
506512
// just performs the call.
@@ -1031,12 +1037,6 @@ impl Assembler
10311037
let ptr_offset: u32 = (cb.get_write_pos() as u32) - (SIZEOF_VALUE as u32);
10321038
insn_gc_offsets.push(ptr_offset);
10331039
},
1034-
Opnd::CArg { .. } => {
1035-
unreachable!("C argument operand was not lowered before arm64_emit");
1036-
}
1037-
Opnd::Param { .. } => {
1038-
unreachable!("Param operand was not lowered before arm64_emit");
1039-
}
10401040
Opnd::None => {
10411041
unreachable!("Attempted to load from None operand");
10421042
}
@@ -1054,6 +1054,7 @@ impl Assembler
10541054
_ => unreachable!()
10551055
};
10561056
},
1057+
Insn::ParallelMov { .. } => unreachable!("{insn:?} should have been lowered at alloc_regs()"),
10571058
Insn::Mov { dest, src } => {
10581059
// This supports the following two kinds of immediates:
10591060
// * The value fits into a single movz instruction

0 commit comments

Comments
 (0)