[前][次][番号順一覧][スレッド一覧]

ruby-changes:73108

From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:51:32 +0900 (JST)
Subject: [ruby-changes:73108] 75c995b0d1 (master): Bias register allocator to reuse first operand

https://git.ruby-lang.org/ruby.git/commit/?id=75c995b0d1

From 75c995b0d10515568ccfe8f67be1bd3bbcbb4b69 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Wed, 18 May 2022 16:00:45 -0400
Subject: Bias register allocator to reuse first operand

---
 yjit/src/backend/ir.rs         | 53 +++++++++++++++++++++++++++++++-----------
 yjit/src/backend/x86_64/mod.rs |  1 +
 2 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index 41eef8c60b..7f6a20c191 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -434,7 +434,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L434
             match op {
                 // Check for Add, Sub, And, Mov, with two memory operands.
                 // Load one operand into memory.
-                Op::Add | Op::Sub | Op::And => {
+                Op::Add | Op::Sub | Op::And | Op::Mov => {
                     match opnds.as_slice() {
                         [Opnd::Mem(_), Opnd::Mem(_)] => {
                             // We load opnd1 because for mov, opnd0 is the output
@@ -508,27 +508,42 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L508
                 }
             }
 
+            // If this instruction is used by another instruction,
+            // we need to allocate a register to it
+            let mut out_reg = Opnd::None;
+            if live_ranges[index] != index {
+                // If this instruction's first operand maps to a register and
+                // this is the last use of the register, reuse the register
+                // We do this to improve register allocation on x86
+                if opnds.len() > 0 {
+                    if let Opnd::InsnOut(idx) = opnds[0] {
+                        if live_ranges[idx] == index {
+                            if let Opnd::Reg(reg) = asm.insns[idx].out {
+                                out_reg = Opnd::Reg(alloc_reg(&mut pool, &vec![reg]))
+                            }
+                        }
+                    }
+                }
+
+                if out_reg == Opnd::None {
+                    // Allocate a new register for this instruction
+                    out_reg = Opnd::Reg(alloc_reg(&mut pool, &regs))
+                }
+            }
+
             // Replace InsnOut operands by their corresponding register
-            let opnds = opnds.into_iter().map(|opnd|
+            let reg_opnds = opnds.into_iter().map(|opnd|
                 match opnd {
                      Opnd::InsnOut(idx) => asm.insns[idx].out,
                      _ => opnd,
                 }
             ).collect();
 
-            asm.push_insn(op, opnds, target);
+            asm.push_insn(op, reg_opnds, target);
 
+            // Set the output register for this instruction
             let num_insns = asm.insns.len();
-            if live_ranges[index] != index {
-                // This instruction is used by another instruction, so we need
-                // to allocate a register for it.
-                asm.insns[num_insns - 1].out = Opnd::Reg(alloc_reg(&mut pool, &regs));
-            }
-            else
-            {
-                // Nobody is using the output of this instruction
-                asm.insns[num_insns - 1].out = Opnd::None;
-            }
+            asm.insns[num_insns - 1].out = out_reg;
         });
 
         assert_eq!(pool, 0, "Expected all registers to be returned to the pool");
@@ -732,7 +747,7 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L747
     fn test_compile()
     {
         let mut asm = Assembler::new();
-        let mut cb = CodeBlock::new_dummy(64 * 1024);
+        let mut cb = CodeBlock::new_dummy(1024);
         let regs = Assembler::get_scrach_regs();
 
         let out = asm.add(Opnd::Reg(regs[0]), Opnd::UImm(2));
@@ -740,4 +755,14 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L755
 
         asm.compile(&mut cb);
     }
+
+    // Test full codegen pipeline
+    #[test]
+    fn test_mov_mem2mem()
+    {
+        let mut asm = Assembler::new();
+        let mut cb = CodeBlock::new_dummy(1024);
+        asm.mov(Opnd::mem(64, SP, 0), Opnd::mem(64, SP, 8));
+        asm.compile(&mut cb);
+    }
 }
diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs
index 2eb12e3d27..00b9998b69 100644
--- a/yjit/src/backend/x86_64/mod.rs
+++ b/yjit/src/backend/x86_64/mod.rs
@@ -69,6 +69,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L69
                 Store,
                 */
 
+                Op::Load => add(cb, insn.out.into(), insn.opnds[0].into()),
                 Op::Mov => add(cb, insn.opnds[0].into(), insn.opnds[1].into()),
 
                 // Test and set flags
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]