1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

YJIT: eliminate redundant mov in csel/cmov on x86 (#6348)

* Eliminate redundant mov in csel/cmov. Translate mov reg,0 into xor

* Fix x86 asm test

* Remove dbg!()

* xor optimization unsound because it resets flags
This commit is contained in:
Maxime Chevalier-Boisvert 2022-09-09 18:41:19 -04:00 committed by GitHub
parent 2a08a39d7d
commit 5b5c627d37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2022-09-10 07:41:48 +09:00
Merged-By: maximecb <maximecb@ruby-lang.org>

View file

@ -145,7 +145,7 @@ impl Assembler
if !value.special_const_p() || imm_num_bits(value.as_i64()) > 32 { if !value.special_const_p() || imm_num_bits(value.as_i64()) > 32 {
asm.load(iterator.map_opnd(*opnd)) asm.load(iterator.map_opnd(*opnd))
} else { } else {
iterator.map_opnd(*opnd) Opnd::UImm(value.as_u64())
} }
} else { } else {
iterator.map_opnd(*opnd) iterator.map_opnd(*opnd)
@ -221,18 +221,25 @@ impl Assembler
Insn::CSelLE { truthy, falsy, out } | Insn::CSelLE { truthy, falsy, out } |
Insn::CSelG { truthy, falsy, out } | Insn::CSelG { truthy, falsy, out } |
Insn::CSelGE { truthy, falsy, out } => { Insn::CSelGE { truthy, falsy, out } => {
match truthy { match unmapped_opnds[0] {
Opnd::Reg(_) | Opnd::InsnOut { .. } => {}, // If we have an instruction output whose live range
_ => { // spans beyond this instruction, we have to load it.
Opnd::InsnOut { idx, .. } => {
if live_ranges[idx] > index {
*truthy = asm.load(*truthy);
}
},
Opnd::UImm(_) | Opnd::Imm(_) | Opnd::Value(_) => {
*truthy = asm.load(*truthy); *truthy = asm.load(*truthy);
} },
_ => {}
}; };
match falsy { match falsy {
Opnd::Reg(_) | Opnd::InsnOut { .. } => {}, Opnd::UImm(_) | Opnd::Imm(_) => {
_ => {
*falsy = asm.load(*falsy); *falsy = asm.load(*falsy);
} },
_ => {}
}; };
*out = asm.next_opnd_out(Opnd::match_num_bits(&[*truthy, *falsy])); *out = asm.next_opnd_out(Opnd::match_num_bits(&[*truthy, *falsy]));
@ -350,6 +357,14 @@ impl Assembler
} }
} }
fn emit_csel(cb: &mut CodeBlock, truthy: Opnd, falsy: Opnd, out: Opnd, cmov_fn: fn(&mut CodeBlock, X86Opnd, X86Opnd)) {
if out != truthy {
mov(cb, out.into(), truthy.into());
}
cmov_fn(cb, out.into(), falsy.into());
}
//dbg!(&self.insns); //dbg!(&self.insns);
// List of GC offsets // List of GC offsets
@ -609,36 +624,28 @@ impl Assembler
Insn::Breakpoint => int3(cb), Insn::Breakpoint => int3(cb),
Insn::CSelZ { truthy, falsy, out } => { Insn::CSelZ { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovnz);
cmovnz(cb, out.into(), falsy.into());
}, },
Insn::CSelNZ { truthy, falsy, out } => { Insn::CSelNZ { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovz);
cmovz(cb, out.into(), falsy.into());
}, },
Insn::CSelE { truthy, falsy, out } => { Insn::CSelE { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovne);
cmovne(cb, out.into(), falsy.into());
}, },
Insn::CSelNE { truthy, falsy, out } => { Insn::CSelNE { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmove);
cmove(cb, out.into(), falsy.into());
}, },
Insn::CSelL { truthy, falsy, out } => { Insn::CSelL { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovge);
cmovge(cb, out.into(), falsy.into());
}, },
Insn::CSelLE { truthy, falsy, out } => { Insn::CSelLE { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovg);
cmovg(cb, out.into(), falsy.into());
}, },
Insn::CSelG { truthy, falsy, out } => { Insn::CSelG { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovle);
cmovle(cb, out.into(), falsy.into());
}, },
Insn::CSelGE { truthy, falsy, out } => { Insn::CSelGE { truthy, falsy, out } => {
mov(cb, out.into(), truthy.into()); emit_csel(cb, *truthy, *falsy, *out, cmovl);
cmovl(cb, out.into(), falsy.into());
} }
Insn::LiveReg { .. } => (), // just a reg alloc signal, no code Insn::LiveReg { .. } => (), // just a reg alloc signal, no code
Insn::PadEntryExit => { Insn::PadEntryExit => {