зеркало из https://github.com/github/ruby.git
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:
Родитель
2a08a39d7d
Коммит
5b5c627d37
|
@ -145,7 +145,7 @@ impl Assembler
|
|||
if !value.special_const_p() || imm_num_bits(value.as_i64()) > 32 {
|
||||
asm.load(iterator.map_opnd(*opnd))
|
||||
} else {
|
||||
iterator.map_opnd(*opnd)
|
||||
Opnd::UImm(value.as_u64())
|
||||
}
|
||||
} else {
|
||||
iterator.map_opnd(*opnd)
|
||||
|
@ -221,18 +221,25 @@ impl Assembler
|
|||
Insn::CSelLE { truthy, falsy, out } |
|
||||
Insn::CSelG { truthy, falsy, out } |
|
||||
Insn::CSelGE { truthy, falsy, out } => {
|
||||
match truthy {
|
||||
Opnd::Reg(_) | Opnd::InsnOut { .. } => {},
|
||||
_ => {
|
||||
match unmapped_opnds[0] {
|
||||
// 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);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match falsy {
|
||||
Opnd::Reg(_) | Opnd::InsnOut { .. } => {},
|
||||
_ => {
|
||||
Opnd::UImm(_) | Opnd::Imm(_) => {
|
||||
*falsy = asm.load(*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);
|
||||
|
||||
// List of GC offsets
|
||||
|
@ -609,36 +624,28 @@ impl Assembler
|
|||
Insn::Breakpoint => int3(cb),
|
||||
|
||||
Insn::CSelZ { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovnz(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovnz);
|
||||
},
|
||||
Insn::CSelNZ { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovz(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovz);
|
||||
},
|
||||
Insn::CSelE { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovne(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovne);
|
||||
},
|
||||
Insn::CSelNE { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmove(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmove);
|
||||
},
|
||||
Insn::CSelL { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovge(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovge);
|
||||
},
|
||||
Insn::CSelLE { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovg(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovg);
|
||||
},
|
||||
Insn::CSelG { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovle(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovle);
|
||||
},
|
||||
Insn::CSelGE { truthy, falsy, out } => {
|
||||
mov(cb, out.into(), truthy.into());
|
||||
cmovl(cb, out.into(), falsy.into());
|
||||
emit_csel(cb, *truthy, *falsy, *out, cmovl);
|
||||
}
|
||||
Insn::LiveReg { .. } => (), // just a reg alloc signal, no code
|
||||
Insn::PadEntryExit => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче