summaryrefslogtreecommitdiff
path: root/yjit/src/backend/ir.rs
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2022-09-08 17:09:50 -0400
committerGitHub <noreply@github.com>2022-09-08 17:09:50 -0400
commit35cfc9a3bb0078c297eb70520216ad228f2083e1 (patch)
treee0d98f27ed1f47bb5523e34e2d7f7c2707858fd0 /yjit/src/backend/ir.rs
parente4f5296f065110fa83eb450d3a861253e76e534f (diff)
Remove as many unnecessary moves as possible (#6342)v3_2_0_preview2
This commit does a bunch of stuff to try to eliminate as many unnecessary mov instructions as possible. First, it introduces the Insn::LoadInto instruction. Previously when we needed a value to go into a specific register (like in Insn::CCall when we're putting values into the argument registers or in Insn::CRet when we're putting a value into the return register) we would first load the value and then mov it into the correct register. This resulted in a lot of duplicated work with short live ranges since they basically immediately we unnecessary. The new instruction accepts a destination and does not interact with the register allocator at all, making it much more efficient. We then use the new instruction when we're loading values into argument registers for AArch64 or X86_64, and when we're returning a value from AArch64. Notably we don't do it when we're returning a value from X86_64 because everything can be accomplished with a single mov anyway. A couple of unnecessary movs were also present because when we called the split_load_opnd function in a lot of split passes we were loading all registers and instruction outputs. We no longer do that. This commit also makes it so that UImm(0) passes through the Insn::Store split without attempting to be loaded, which allows it can take advantage of the zero register. So now instead of mov-ing 0 into a register and then calling store, it just stores XZR.
Notes
Notes: Merged-By: maximecb <maximecb@ruby-lang.org>
Diffstat (limited to 'yjit/src/backend/ir.rs')
-rw-r--r--yjit/src/backend/ir.rs10
1 files changed, 10 insertions, 0 deletions
diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index 0b96af7f62..ee6499ff64 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -401,6 +401,9 @@ pub enum Insn {
// A low-level instruction that loads a value into a register.
Load { opnd: Opnd, out: Opnd },
+ // A low-level instruction that loads a value into a specified register.
+ LoadInto { dest: Opnd, opnd: Opnd },
+
// A low-level instruction that loads a value into a register and
// sign-extends it to a 64-bit value.
LoadSExt { opnd: Opnd, out: Opnd },
@@ -502,6 +505,7 @@ impl Insn {
Insn::Lea { .. } => "Lea",
Insn::LiveReg { .. } => "LiveReg",
Insn::Load { .. } => "Load",
+ Insn::LoadInto { .. } => "LoadInto",
Insn::LoadSExt { .. } => "LoadSExt",
Insn::LShift { .. } => "LShift",
Insn::Mov { .. } => "Mov",
@@ -675,6 +679,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
Insn::CSelNZ { truthy: opnd0, falsy: opnd1, .. } |
Insn::CSelZ { truthy: opnd0, falsy: opnd1, .. } |
Insn::IncrCounter { mem: opnd0, value: opnd1, .. } |
+ Insn::LoadInto { dest: opnd0, opnd: opnd1 } |
Insn::LShift { opnd: opnd0, shift: opnd1, .. } |
Insn::Mov { dest: opnd0, src: opnd1 } |
Insn::Or { left: opnd0, right: opnd1, .. } |
@@ -771,6 +776,7 @@ impl<'a> InsnOpndMutIterator<'a> {
Insn::CSelNZ { truthy: opnd0, falsy: opnd1, .. } |
Insn::CSelZ { truthy: opnd0, falsy: opnd1, .. } |
Insn::IncrCounter { mem: opnd0, value: opnd1, .. } |
+ Insn::LoadInto { dest: opnd0, opnd: opnd1 } |
Insn::LShift { opnd: opnd0, shift: opnd1, .. } |
Insn::Mov { dest: opnd0, src: opnd1 } |
Insn::Or { left: opnd0, right: opnd1, .. } |
@@ -1422,6 +1428,10 @@ impl Assembler {
out
}
+ pub fn load_into(&mut self, dest: Opnd, opnd: Opnd) {
+ self.push_insn(Insn::LoadInto { dest, opnd });
+ }
+
#[must_use]
pub fn load_sext(&mut self, opnd: Opnd) -> Opnd {
let out = self.next_opnd_out(Opnd::match_num_bits(&[opnd]));