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

ruby-changes:73181

From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 00:59:51 +0900 (JST)
Subject: [ruby-changes:73181] 159566fef9 (master): Op::CPushAll and Op::CPopAll (https://github.com/Shopify/ruby/pull/317)

https://git.ruby-lang.org/ruby.git/commit/?id=159566fef9

From 159566fef91b010d8e236151bdbc77993f77c15f Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Thu, 14 Jul 2022 11:10:58 -0400
Subject: Op::CPushAll and Op::CPopAll
 (https://github.com/Shopify/ruby/pull/317)

Instructions for pushing all caller-save registers and the flags so that
we can implement dump_insns.
---
 yjit/src/asm/arm64/opnd.rs     | 30 ++++++++++-------
 yjit/src/backend/arm64/mod.rs  | 73 ++++++++++++++++++++++++++++++++++++------
 yjit/src/backend/ir.rs         |  7 ++++
 yjit/src/backend/x86_64/mod.rs | 27 ++++++++++++++++
 4 files changed, 116 insertions(+), 21 deletions(-)

diff --git a/yjit/src/asm/arm64/opnd.rs b/yjit/src/asm/arm64/opnd.rs
index 1738f0985c..e1f95979a9 100644
--- a/yjit/src/asm/arm64/opnd.rs
+++ b/yjit/src/asm/arm64/opnd.rs
@@ -88,6 +88,7 @@ impl A64Opnd { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/opnd.rs#L88
     }
 }
 
+// argument registers
 pub const X0_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 0 };
 pub const X1_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 1 };
 pub const X2_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 2 };
@@ -95,15 +96,20 @@ pub const X3_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 3 }; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/opnd.rs#L96
 pub const X4_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 4 };
 pub const X5_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 5 };
 
+// caller-save registers
 pub const X9_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 9 };
 pub const X10_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 10 };
 pub const X11_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 11 };
 pub const X12_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 12 };
 pub const X13_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 13 };
+pub const X14_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 14 };
+pub const X15_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 15 };
 
-pub const X24_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 24 };
-pub const X25_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 25 };
-pub const X26_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 26 };
+// callee-save registers
+pub const X19_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 19 };
+pub const X20_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 20 };
+pub const X21_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 21 };
+pub const X22_REG: A64Reg = A64Reg { num_bits: 64, reg_no: 22 };
 
 // 64-bit registers
 pub const X0: A64Opnd = A64Opnd::Reg(X0_REG);
@@ -120,19 +126,19 @@ pub const X10: A64Opnd = A64Opnd::Reg(X10_REG); https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/opnd.rs#L126
 pub const X11: A64Opnd = A64Opnd::Reg(X11_REG);
 pub const X12: A64Opnd = A64Opnd::Reg(X12_REG);
 pub const X13: A64Opnd = A64Opnd::Reg(X13_REG);
-pub const X14: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 14 });
-pub const X15: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 15 });
+pub const X14: A64Opnd = A64Opnd::Reg(X14_REG);
+pub const X15: A64Opnd = A64Opnd::Reg(X15_REG);
 pub const X16: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 16 });
 pub const X17: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 17 });
 pub const X18: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 18 });
-pub const X19: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 19 });
-pub const X20: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 20 });
-pub const X21: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 21 });
-pub const X22: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 22 });
+pub const X19: A64Opnd = A64Opnd::Reg(X19_REG);
+pub const X20: A64Opnd = A64Opnd::Reg(X20_REG);
+pub const X21: A64Opnd = A64Opnd::Reg(X21_REG);
+pub const X22: A64Opnd = A64Opnd::Reg(X22_REG);
 pub const X23: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 23 });
-pub const X24: A64Opnd = A64Opnd::Reg(X24_REG);
-pub const X25: A64Opnd = A64Opnd::Reg(X25_REG);
-pub const X26: A64Opnd = A64Opnd::Reg(X26_REG);
+pub const X24: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 24 });
+pub const X25: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 25 });
+pub const X26: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 26 });
 pub const X27: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 27 });
 pub const X28: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 28 });
 pub const X29: A64Opnd = A64Opnd::Reg(A64Reg { num_bits: 64, reg_no: 29 });
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs
index f6429dbcea..a208eb6316 100644
--- a/yjit/src/backend/arm64/mod.rs
+++ b/yjit/src/backend/arm64/mod.rs
@@ -13,9 +13,9 @@ use crate::virtualmem::CodePtr; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L13
 pub type Reg = A64Reg;
 
 // Callee-saved registers
-pub const _CFP: Opnd = Opnd::Reg(X24_REG);
-pub const _EC: Opnd = Opnd::Reg(X25_REG);
-pub const _SP: Opnd = Opnd::Reg(X26_REG);
+pub const _CFP: Opnd = Opnd::Reg(X19_REG);
+pub const _EC: Opnd = Opnd::Reg(X20_REG);
+pub const _SP: Opnd = Opnd::Reg(X21_REG);
 
 // C argument registers on this platform
 pub const _C_ARG_OPNDS: [Opnd; 6] = [
@@ -59,11 +59,15 @@ impl From<Opnd> for A64Opnd { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L59
 impl Assembler
 {
     /// Get the list of registers from which we can allocate on this platform
-    pub fn get_alloc_regs() -> Vec<Reg>
-    {
+    pub fn get_alloc_regs() -> Vec<Reg> {
         vec![C_RET_REG, X12_REG]
     }
 
+    /// Get a list of all of the caller-save registers
+    pub fn get_caller_save_regs() -> Vec<Reg> {
+        vec![X9_REG, X10_REG, X11_REG, X12_REG, X13_REG, X14_REG, X15_REG]
+    }
+
     /// Split platform-specific instructions
     /// The transformations done here are meant to make our lives simpler in later
     /// stages of the compilation pipeline.
@@ -340,11 +344,28 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L344
             };
         }
 
+        /// Emit a push instruction for the given operand by adding to the stack
+        /// pointer and then storing the given value.
+        fn emit_push(cb: &mut CodeBlock, opnd: A64Opnd) {
+            add(cb, C_SP_REG, C_SP_REG, C_SP_STEP);
+            stur(cb, opnd, A64Opnd::new_mem(64, C_SP_REG, 0));
+        }
+
+        /// Emit a pop instruction into the given operand by loading the value
+        /// and then subtracting from the stack pointer.
+        fn emit_pop(cb: &mut CodeBlock, opnd: A64Opnd) {
+            ldur(cb, opnd, A64Opnd::new_mem(64, C_SP_REG, 0));
+            sub(cb, C_SP_REG, C_SP_REG, C_SP_STEP);
+        }
+
         // dbg!(&self.insns);
 
         // List of GC offsets
         let mut gc_offsets: Vec<u32> = Vec::new();
 
+        // A special scratch register for loading/storing system registers.
+        let mut sys_scratch = A64Opnd::Reg(X22_REG);
+
         // For each instruction
         for insn in &self.insns {
             match insn.op {
@@ -429,12 +450,30 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L450
                     };
                 },
                 Op::CPush => {
-                    add(cb, C_SP_REG, C_SP_REG, C_SP_STEP);
-                    stur(cb, insn.opnds[0].into(), A64Opnd::new_mem(64, C_SP_REG, 0));
+                    emit_push(cb, insn.opnds[0].into());
+                },
+                Op::CPushAll => {
+                    let regs = Assembler::get_caller_save_regs();
+
+                    for reg in regs {
+                        emit_push(cb, A64Opnd::Reg(reg));
+                    }
+
+                    mrs(cb, sys_scratch, SystemRegister::NZCV);
+                    emit_push(cb, sys_scratch);
                 },
                 Op::CPop => {
-                    ldur(cb, insn.opnds[0].into(), A64Opnd::new_mem(64, C_SP_REG, 0));
-                    sub(cb, C_SP_REG, C_SP_REG, C_SP_STEP);
+                    emit_pop(cb, insn.opnds[0].into());
+                },
+                Op::CPopAll => {
+                    let regs = Assembler::get_caller_save_regs();
+
+                    msr(cb, SystemRegister::NZCV, sys_scratch);
+                    emit_pop(cb, sys_scratch);
+
+                    for reg in regs.into_iter().rev() {
+                        emit_pop(cb, A64Opnd::Reg(reg));
+                    }
                 },
                 Op::CCall => {
                     let src_addr = cb.get_write_ptr().into_i64() + 4;
@@ -570,4 +609,20 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L609
         let insns = cb.get_ptr(0).raw_ptr() as *const u32;
         assert_eq!(0x8b010003, unsafe { *insns });
     }
+
+    #[test]
+    fn test_emit_cpush_all() {
+        let (mut asm, mut cb) = setup_asm();
+
+        asm.cpush_all();
+        asm.compile_with_num_regs(&mut cb, 0);
+    }
+
+    #[test]
+    fn test_emit_cpop_all() {
+        let (mut asm, mut cb) = setup_asm();
+
+        asm.cpop_all();
+        asm.compile_with_num_regs(&mut cb, 0);
+    }
 }
diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index 5758d72d43..dbc6464a9c 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -97,6 +97,11 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L97
     CPush,
     CPop,
 
+    // Push and pop all of the caller-save registers and the flags to/from the C
+    // stack
+    CPushAll,
+    CPopAll,
+
     // C function call with N arguments (variadic)
     CCall,
 
@@ -804,6 +809,8 @@ def_push_2_opnd!(and, Op::And); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L809
 def_push_1_opnd!(not, Op::Not);
 def_push_1_opnd_no_out!(cpush, Op::CPush);
 def_push_1_opnd_no_out!(cpop, Op::CPop);
+def_push_0_opnd_no_out!(cpush_all, Op::CPushAll);
+def_push_0_opnd_no_out!(cpop_all, Op::CPopAll);
 def_push_1_opnd_no_out!(cret, Op::CRet);
 def_push_1_opnd!(load, Op::Load);
 def_push_1_opnd!(lea, Op::Lea);
diff  (... truncated)

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

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