YJIT: Merge add/sub/and/or/xor and mov on x86_64 (#7492)

This commit is contained in:
Takashi Kokubun 2023-03-13 13:32:45 -07:00 committed by GitHub
parent 309ff928f5
commit c7822b8dbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2023-03-13 20:33:06 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>

View File

@ -166,29 +166,41 @@ impl Assembler
Insn::And { left, right, out } | Insn::And { left, right, out } |
Insn::Or { left, right, out } | Insn::Or { left, right, out } |
Insn::Xor { left, right, out } => { Insn::Xor { left, right, out } => {
match (unmapped_opnds[0], unmapped_opnds[1]) { match (&left, &right, iterator.peek()) {
(Opnd::Mem(_), Opnd::Mem(_)) => { // Merge this insn, e.g. `add REG, right -> out`, and `mov REG, out` if possible
*left = asm.load(*left); (Opnd::Reg(_), Opnd::UImm(value), Some(Insn::Mov { dest, src }))
*right = asm.load(*right); if out == src && left == dest && live_ranges[index] == index + 1 && uimm_num_bits(*value) <= 32 => {
}, *out = *dest;
(Opnd::Mem(_), Opnd::UImm(_) | Opnd::Imm(_)) => { asm.push_insn(insn);
*left = asm.load(*left); iterator.map_insn_index(&mut asm);
}, iterator.next_unmapped(); // Pop merged Insn::Mov
// Instruction output whose live range spans beyond this instruction }
(Opnd::InsnOut { idx, .. }, _) => { _ => {
if live_ranges[idx] > index { match (unmapped_opnds[0], unmapped_opnds[1]) {
*left = asm.load(*left); (Opnd::Mem(_), Opnd::Mem(_)) => {
} *left = asm.load(*left);
}, *right = asm.load(*right);
// We have to load memory operands to avoid corrupting them },
(Opnd::Mem(_) | Opnd::Reg(_), _) => { (Opnd::Mem(_), Opnd::UImm(_) | Opnd::Imm(_)) => {
*left = asm.load(*left); *left = asm.load(*left);
}, },
_ => {} // Instruction output whose live range spans beyond this instruction
}; (Opnd::InsnOut { idx, .. }, _) => {
if live_ranges[idx] > index {
*left = asm.load(*left);
}
},
// We have to load memory operands to avoid corrupting them
(Opnd::Mem(_) | Opnd::Reg(_), _) => {
*left = asm.load(*left);
},
_ => {}
};
*out = asm.next_opnd_out(Opnd::match_num_bits(&[*left, *right])); *out = asm.next_opnd_out(Opnd::match_num_bits(&[*left, *right]));
asm.push_insn(insn); asm.push_insn(insn);
}
}
}, },
Insn::Cmp { left, right } => { Insn::Cmp { left, right } => {
// Replace `cmp REG, 0` (4 bytes) with `test REG, REG` (3 bytes) // Replace `cmp REG, 0` (4 bytes) with `test REG, REG` (3 bytes)
@ -953,4 +965,59 @@ mod tests {
assert_eq!(format!("{:x}", cb), "488b43084885c0b814000000b900000000480f45c14889c0"); assert_eq!(format!("{:x}", cb), "488b43084885c0b814000000b900000000480f45c14889c0");
} }
#[test]
fn test_merge_add_mov() {
let (mut asm, mut cb) = setup_asm();
let sp = asm.add(CFP, Opnd::UImm(0x40));
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
assert_eq!(format!("{:x}", cb), "4983c540");
}
#[test]
fn test_merge_sub_mov() {
let (mut asm, mut cb) = setup_asm();
let sp = asm.sub(CFP, Opnd::UImm(0x40));
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
assert_eq!(format!("{:x}", cb), "4983ed40");
}
#[test]
fn test_merge_and_mov() {
let (mut asm, mut cb) = setup_asm();
let sp = asm.and(CFP, Opnd::UImm(0x40));
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
assert_eq!(format!("{:x}", cb), "4983e540");
}
#[test]
fn test_merge_or_mov() {
let (mut asm, mut cb) = setup_asm();
let sp = asm.or(CFP, Opnd::UImm(0x40));
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
assert_eq!(format!("{:x}", cb), "4983cd40");
}
#[test]
fn test_merge_xor_mov() {
let (mut asm, mut cb) = setup_asm();
let sp = asm.xor(CFP, Opnd::UImm(0x40));
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
assert_eq!(format!("{:x}", cb), "4983f540");
}
} }