summaryrefslogtreecommitdiff
path: root/yjit
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2022-09-09 18:41:19 -0400
committerGitHub <noreply@github.com>2022-09-09 18:41:19 -0400
commit5b5c627d37c1773dd280e0f14d9510f8fa8db04f (patch)
tree3057e263fa3bb18a398af3927b4b84ab6c43afa0 /yjit
parent2a08a39d7d788fc30b5242ef7ed40cc78d1982c3 (diff)
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
Notes
Notes: Merged-By: maximecb <maximecb@ruby-lang.org>
Diffstat (limited to 'yjit')
-rw-r--r--yjit/src/backend/x86_64/mod.rs55
1 files changed, 31 insertions, 24 deletions
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 => {