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

ruby-changes:73148

From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:55:40 +0900 (JST)
Subject: [ruby-changes:73148] 59b818ec87 (master): Add support for using InsnOut as memory operand base

https://git.ruby-lang.org/ruby.git/commit/?id=59b818ec87

From 59b818ec8757348e3f7fa463ace36489c5ec75ac Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Wed, 15 Jun 2022 14:13:04 -0400
Subject: Add support for using InsnOut as memory operand base

---
 yjit/src/backend/ir.rs         | 98 +++++++++++++++++++++++++++++++++---------
 yjit/src/backend/x86_64/mod.rs | 14 ++++--
 2 files changed, 88 insertions(+), 24 deletions(-)

diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index d14e3485aa..1f6307db9e 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -105,12 +105,20 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L105
     Breakpoint,
 }
 
+// Memory operand base
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum MemBase
+{
+    Reg(u8),
+    InsnOut(usize),
+}
+
 // Memory location
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct Mem
 {
-    // Base register
-    pub(super) base_reg: Reg,
+    // Base register number or instruction index
+    pub(super) base: MemBase,
 
     // Offset relative to the base pointer
     pub(super) disp: i32,
@@ -148,11 +156,20 @@ impl Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L156
             Opnd::Reg(base_reg) => {
                 assert!(base_reg.num_bits == 64);
                 Opnd::Mem(Mem {
+                    base: MemBase::Reg(base_reg.reg_no),
+                    disp: disp,
                     num_bits: num_bits,
-                    base_reg: base_reg,
+                })
+            },
+
+            Opnd::InsnOut(idx) => {
+                Opnd::Mem(Mem {
+                    base: MemBase::InsnOut(idx),
                     disp: disp,
+                    num_bits: num_bits,
                 })
             },
+
             _ => unreachable!("memory operand with non-register base")
         }
     }
@@ -161,6 +178,13 @@ impl Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L178
     pub fn const_ptr(ptr: *const u8) -> Self {
         Opnd::UImm(ptr as u64)
     }
+
+    pub fn unwrap_reg(&self) -> Reg {
+        match self {
+            Opnd::Reg(reg) => *reg,
+            _ => unreachable!("trying to unwrap {:?} into reg", self)
+        }
+    }
 }
 
 impl From<usize> for Opnd {
@@ -264,8 +288,14 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L288
         // one.
         let insn_idx = self.insns.len();
         for opnd in &opnds {
-            if let Opnd::InsnOut(idx) = opnd {
-                self.live_ranges[*idx] = insn_idx;
+            match opnd {
+                Opnd::InsnOut(idx) => {
+                    self.live_ranges[*idx] = insn_idx;
+                }
+                Opnd::Mem( Mem { base: MemBase::InsnOut(idx), .. }) => {
+                    self.live_ranges[*idx] = insn_idx;
+                }
+                _ => {}
             }
         }
 
@@ -483,22 +513,26 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L513
             // spans more than one instruction. In that case, return the
             // allocated register to the pool.
             for opnd in &opnds {
-                if let Opnd::InsnOut(idx) = opnd {
-                    // Since we have an InsnOut, we know it spans more that one
-                    // instruction.
-                    let start_index = *idx;
-                    assert!(start_index < index);
-
-                    // We're going to check if this is the last instruction that
-                    // uses this operand. If it is, we can return the allocated
-                    // register to the pool.
-                    if live_ranges[start_index] == index {
-                        if let Opnd::Reg(reg) = asm.insns[start_index].out {
-                            dealloc_reg(&mut pool, &regs, &reg);
-                        } else {
-                            unreachable!("no register allocated for insn");
+                match opnd {
+                    Opnd::InsnOut(idx) | Opnd::Mem( Mem { base: MemBase::InsnOut(idx), .. }) => {
+                        // Since we have an InsnOut, we know it spans more that one
+                        // instruction.
+                        let start_index = *idx;
+                        assert!(start_index < index);
+
+                        // We're going to check if this is the last instruction that
+                        // uses this operand. If it is, we can return the allocated
+                        // register to the pool.
+                        if live_ranges[start_index] == index {
+                            if let Opnd::Reg(reg) = asm.insns[start_index].out {
+                                dealloc_reg(&mut pool, &regs, &reg);
+                            } else {
+                                unreachable!("no register allocated for insn");
+                            }
                         }
                     }
+
+                    _ => {}
                 }
             }
 
@@ -541,7 +575,15 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L575
             // Replace InsnOut operands by their corresponding register
             let reg_opnds = opnds.into_iter().map(|opnd|
                 match opnd {
-                     Opnd::InsnOut(idx) => asm.insns[idx].out,
+                    Opnd::InsnOut(idx) => asm.insns[idx].out,
+                    Opnd::Mem(Mem { base: MemBase::InsnOut(idx), disp, num_bits }) => {
+                        let out_reg = asm.insns[idx].out.unwrap_reg();
+                        Opnd::Mem(Mem {
+                            base: MemBase::Reg(out_reg.reg_no),
+                            disp,
+                            num_bits
+                        })
+                    }
                      _ => opnd,
                 }
             ).collect();
@@ -864,6 +906,22 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L906
         asm.compile_with_regs(&mut cb, regs);
     }
 
+    // Use instruction output as base register for memory operand
+    #[test]
+    fn test_base_insn_out()
+    {
+        let (mut asm, mut cb, regs) = setup_asm(1);
+
+        // Load the pointer into a register
+        let ptr_reg = asm.load(Opnd::const_ptr(0 as *const u8));
+        let counter_opnd = Opnd::mem(64, ptr_reg, 0);
+
+        // Increment and store the updated value
+        asm.incr_counter(counter_opnd, 1.into() );
+
+        asm.compile_with_regs(&mut cb, regs);
+    }
+
     #[test]
     fn test_c_call()
     {
diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs
index daa8005088..0c23781e20 100644
--- a/yjit/src/backend/x86_64/mod.rs
+++ b/yjit/src/backend/x86_64/mod.rs
@@ -6,7 +6,7 @@ use crate::asm::{CodeBlock}; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L6
 use crate::asm::x86_64::*;
 use crate::codegen::{JITState};
 use crate::cruby::*;
-use crate::backend::ir::{Assembler, Opnd, Target, Op, Mem};
+use crate::backend::ir::{Assembler, Opnd, Target, Op, MemBase, Mem};
 
 // Use the x86 register type for this platform
 pub type Reg = X86Reg;
@@ -49,8 +49,14 @@ impl From<Opnd> for X86Opnd { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L49
             Opnd::Reg(reg) => X86Opnd::Reg(reg),
 
             // Memory operand with displacement
-            Opnd::Mem(Mem{ num_bits, base_reg, disp }) => {
-                mem_opnd(num_bits, X86Opnd::Reg(base_reg), disp)
+            Opnd::Mem(Mem{ base: MemBase::Reg(reg_no), num_bits, disp }) => {
+                let reg = X86Reg {
+                    reg_no,
+                    num_bits: 64,
+                    reg_type: RegType::GP
+                };
+
+                mem_opnd(num_bits, X86Opnd::Reg(reg), disp)
             }
 
             _ => panic!("unsupported x86 operand type")
@@ -186,7 +192,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L192
                 // Atomically increment a counter at a given memory location
                 Op::IncrCounter => {
                     assert!(matches!(insn.opnds[0], Opnd::Mem(_)));
-                    assert!(matches!(insn.opnds[0], Opnd::UImm(_)));
+                    assert!(matches!(insn.opnds[1], Opnd::UImm(_) | Opnd::Imm(_) ) );
                     write_lock_prefix(cb);
                     add(cb, insn.opnds[0].into(), insn.opnds[1].into());
                 },
-- 
cgit v1.2.1


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

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