diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index ca07d50ffc..2f770c2eac 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -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 => {