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 коммит произвёл GitHub
Родитель 2a08a39d7d
Коммит 5b5c627d37
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 31 добавлений и 24 удалений

Просмотреть файл

@ -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 => {