Skip to content

Commit 3c4de94

Browse files
XrXrmaximecb
andauthored
YJIT: A64: Use ADDS/SUBS/CMP (immediate) when possible (ruby#10402)
* YJIT: A64: Use ADDS/SUBS/CMP (immediate) when possible We were loading 1 into a register and then doing ADDS/SUBS previously. That was particularly bad since those come up in fixnum operations. ```diff # integer left shift with rhs=1 - mov x11, #1 - subs x11, x1, x11 + subs x11, x1, #1 lsl x12, x11, #1 asr x13, x12, #1 cmp x13, x11 - b.ne #0x106ab60f8 - mov x11, #1 - adds x12, x12, x11 + b.ne #0x10903a0f8 + adds x12, x12, #1 mov x1, x12 ``` Note that it's fine to cast between i64 and u64 since the bit pattern is preserved, and the add/sub themselves don't care about the signedness of the operands. CMP is just another mnemonic for SUBS. * YJIT: A64: Split asm.mul() with immediates properly There is in fact no MUL on A64 that takes an immediate, so this instruction was using the wrong split method. No current usages of this form in YJIT. --------- Co-authored-by: Maxime Chevalier-Boisvert <[email protected]>
1 parent 94f7098 commit 3c4de94

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

yjit/src/asm/arm64/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ pub fn cmp(cb: &mut CodeBlock, rn: A64Opnd, rm: A64Opnd) {
276276

277277
DataReg::cmp(rn.reg_no, rm.reg_no, rn.num_bits).into()
278278
},
279+
(A64Opnd::Reg(rn), A64Opnd::Imm(imm12)) => {
280+
DataImm::cmp(rn.reg_no, (imm12 as u64).try_into().unwrap(), rn.num_bits).into()
281+
},
279282
(A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
280283
DataImm::cmp(rn.reg_no, imm12.try_into().unwrap(), rn.num_bits).into()
281284
},

yjit/src/backend/arm64/mod.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,11 @@ impl Assembler
315315
match opnd {
316316
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::InsnOut { .. } => opnd,
317317
Opnd::Mem(_) => split_load_operand(asm, opnd),
318-
Opnd::Imm(_) => asm.load(opnd),
318+
Opnd::Imm(imm) => if ShiftedImmediate::try_from(imm as u64).is_ok() {
319+
opnd
320+
} else {
321+
asm.load(opnd)
322+
}
319323
Opnd::UImm(uimm) => {
320324
if ShiftedImmediate::try_from(uimm).is_ok() {
321325
opnd
@@ -655,7 +659,7 @@ impl Assembler
655659
},
656660
Insn::Mul { left, right, .. } => {
657661
let opnd0 = split_load_operand(asm, *left);
658-
let opnd1 = split_shifted_immediate(asm, *right);
662+
let opnd1 = split_load_operand(asm, *right);
659663
asm.mul(opnd0, opnd1);
660664
},
661665
Insn::Test { left, right } => {
@@ -1704,4 +1708,35 @@ mod tests {
17041708
0x8: csel x1, x11, x12, lt
17051709
"});
17061710
}
1711+
1712+
#[test]
1713+
fn test_add_with_immediate() {
1714+
let (mut asm, mut cb) = setup_asm();
1715+
1716+
let out = asm.add(Opnd::Reg(TEMP_REGS[1]), 1.into());
1717+
let out = asm.add(out, 1_usize.into());
1718+
asm.mov(Opnd::Reg(TEMP_REGS[0]), out);
1719+
asm.compile_with_num_regs(&mut cb, 2);
1720+
1721+
assert_disasm!(cb, "2b0500b16b0500b1e1030baa", {"
1722+
0x0: adds x11, x9, #1
1723+
0x4: adds x11, x11, #1
1724+
0x8: mov x1, x11
1725+
"});
1726+
}
1727+
1728+
#[test]
1729+
fn test_mul_with_immediate() {
1730+
let (mut asm, mut cb) = setup_asm();
1731+
1732+
let out = asm.mul(Opnd::Reg(TEMP_REGS[1]), 3.into());
1733+
asm.mov(Opnd::Reg(TEMP_REGS[0]), out);
1734+
asm.compile_with_num_regs(&mut cb, 2);
1735+
1736+
assert_disasm!(cb, "6b0080d22b7d0b9be1030baa", {"
1737+
0x0: mov x11, #3
1738+
0x4: mul x11, x9, x11
1739+
0x8: mov x1, x11
1740+
"});
1741+
}
17071742
}

0 commit comments

Comments
 (0)