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

ruby-changes:73133

From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:55:19 +0900 (JST)
Subject: [ruby-changes:73133] d75c346c1c (master): Port gen_leave_exit(), add support for labels to backend

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

From d75c346c1cb5d67fd4c6582274a3ff4f1450af15 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Thu, 9 Jun 2022 15:40:27 -0400
Subject: Port gen_leave_exit(), add support for labels to backend

---
 yjit/src/asm/mod.rs            |  6 +---
 yjit/src/backend/ir.rs         | 68 ++++++++++++++++++++++++++++++++++--------
 yjit/src/backend/x86_64/mod.rs | 47 +++++++++++++++++++++--------
 yjit/src/codegen.rs            | 38 ++++++++++-------------
 4 files changed, 106 insertions(+), 53 deletions(-)

diff --git a/yjit/src/asm/mod.rs b/yjit/src/asm/mod.rs
index 751f9fce0b..9f518398b7 100644
--- a/yjit/src/asm/mod.rs
+++ b/yjit/src/asm/mod.rs
@@ -214,16 +214,12 @@ impl CodeBlock { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L214
 
     /// Write a label at the current address
     pub fn write_label(&mut self, label_idx: usize) {
-        // TODO: make sure that label_idx is valid
-        // TODO: add an asseer here
-
         self.label_addrs[label_idx] = self.write_pos;
     }
 
     // Add a label reference at the current write position
     pub fn label_ref(&mut self, label_idx: usize) {
-        // TODO: make sure that label_idx is valid
-        // TODO: add an asseer here
+        assert!(label_idx < self.label_addrs.len());
 
         // Keep track of the reference
         self.label_refs.push(LabelRef {
diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index 514ac4a67e..63bf85f3a0 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -256,6 +256,13 @@ impl Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L256
     }
 }
 
+impl From<VALUE> for Opnd {
+    fn from(value: VALUE) -> Self {
+        let VALUE(uimm) = value;
+        Opnd::UImm(uimm as u64)
+    }
+}
+
 /// NOTE: this is useful during the port but can probably be removed once
 /// Context returns ir::Opnd instead of X86Opnd
 ///
@@ -290,13 +297,22 @@ impl From<X86Opnd> for Opnd { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L297
 
 /// Branch target (something that we can jump to)
 /// for branch instructions
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum Target
 {
     CodePtr(CodePtr),   // Pointer to a piece of YJIT-generated code (e.g. side-exit)
     FunPtr(*const u8),  // Pointer to a C function
-    LabelName(String),  // A label without an index in the output
-    LabelIdx(usize),    // A label that has been indexed
+    Label(usize),       // A label within the generated code
+}
+
+impl Target
+{
+    pub fn unwrap_label_idx(&self) -> usize {
+        match self {
+            Target::Label(idx) => *idx,
+            _ => unreachable!()
+        }
+    }
 }
 
 /// YJIT IR instruction
@@ -332,6 +348,9 @@ pub struct Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L348
     /// Parallel vec with insns
     /// Index of the last insn using the output of this insn
     pub(super) live_ranges: Vec<usize>,
+
+    /// Names of labels
+    pub(super) label_names: Vec<String>,
 }
 
 impl Assembler
@@ -340,6 +359,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L359
         Assembler {
             insns: Vec::default(),
             live_ranges: Vec::default(),
+            label_names: Vec::default(),
         }
     }
 
@@ -387,30 +407,42 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L407
         self.live_ranges.push(self.insns.len());
     }
 
+    /// Create a new label instance that we can jump to
+    pub fn new_label(&mut self, name: &str) -> Target
+    {
+        let label_idx = self.label_names.len();
+        dbg!(label_idx);
+
+        self.label_names.push(name.to_string());
+        Target::Label(label_idx)
+    }
+
     /// Add a label at the current position
-    pub fn label(&mut self, name: &str) -> Target
+    pub fn write_label(&mut self, label: Target)
     {
-        let insn_idx = self.insns.len();
+        assert!(label.unwrap_label_idx() < self.label_names.len());
 
         let insn = Insn {
             op: Op::Label,
-            text: Some(name.to_owned()),
+            text: None,
             opnds: vec![],
             out: Opnd::None,
-            target: None,
+            target: Some(label),
             pos: None
         };
         self.insns.push(insn);
         self.live_ranges.push(self.insns.len());
-
-        Target::LabelIdx(insn_idx)
     }
 
     /// Transform input instructions, consumes the input assembler
     pub(super) fn transform_insns<F>(mut self, mut map_insn: F) -> Assembler
         where F: FnMut(&mut Assembler, usize, Op, Vec<Opnd>, Option<Target>)
     {
-        let mut asm = Assembler::new();
+        let mut asm = Assembler {
+            insns: Vec::default(),
+            live_ranges: Vec::default(),
+            label_names: self.label_names,
+        };
 
         // indices maps from the old instruction index to the new instruction
         // index.
@@ -435,9 +467,6 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L467
                 Op::Comment => {
                     asm.comment(insn.text.unwrap().as_str());
                 },
-                Op::Label => {
-                    asm.label(insn.text.unwrap().as_str());
-                },
                 _ => {
                     map_insn(&mut asm, index, insn.op, opnds, insn.target);
                 }
@@ -931,4 +960,17 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L960
 
         asm.compile_with_regs(&mut cb, regs);
     }
+
+    #[test]
+    fn test_jcc_label()
+    {
+        let (mut asm, mut cb, regs) = setup_asm(1);
+
+        let label = asm.new_label("foo");
+        asm.cmp(EC, EC);
+        asm.je(label);
+        asm.write_label(label);
+
+        asm.compile_with_regs(&mut cb, regs);
+    }
 }
diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs
index a40bc2a980..467a347b01 100644
--- a/yjit/src/backend/x86_64/mod.rs
+++ b/yjit/src/backend/x86_64/mod.rs
@@ -107,11 +107,12 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L107
                     }
                 },
 
-                Op::Label => {},
+                // Write the label at the current position
+                Op::Label => {
+                    cb.write_label(insn.target.unwrap().unwrap_label_idx());
+                },
 
                 Op::Add => {
-                    // FIXME: this fails because insn.out is none sometimes
-                    //assert_eq!(insn.out, insn.opnds[0]);
                     add(cb, insn.opnds[0].into(), insn.opnds[1].into())
                 },
 
@@ -160,14 +161,23 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L161
                     ret(cb);
                 }
 
+                // Compare
+                Op::Cmp => test(cb, insn.opnds[0].into(), insn.opnds[1].into()),
+
                 // Test and set flags
                 Op::Test => test(cb, insn.opnds[0].into(), insn.opnds[1].into()),
 
-                /*
-                Cmp,
-                Jnz,
-                Jbe,
-                */
+                Op::Je => {
+                    match insn.target.unwrap() {
+                        Target::Label(idx) => {
+
+                            dbg!(idx);
+                            je_label(cb, idx);
+
+                        },
+                        _ => unimplemented!()
+                    }
+                }
 
                 _ => panic!("unsupported instruction passed to x86 backend: {:?}", insn.op)
             };
@@ -179,10 +189,21 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L189
     /// Optimize and compile the stored instructions
     pub fn compile_with_regs(self, cb: &mut CodeBlock, regs: Vec<Reg>) -> Vec<u32>
     {
-        self
-        .x86_split()
-        .split_loads()
-        .alloc_regs(regs)
-        .x86_emit(cb)
+        let mut asm = self.x86_split();
+        let mut asm = asm.split_loads();
+        let mut asm = asm.alloc_regs(regs);
+
+        // Create label instances in the code block
+        for (idx, name) in asm.label_names.iter().enumerate() {
+            dbg!("creating label, idx={}", idx);
+            let label_idx = cb.new_label(name.to_string());
+            assert!(label_idx == idx);
+        }
+
+        let gc_offsets = asm.x86_emit(cb);
+
+        cb.link_labels();
+
+        gc_offsets
     }
 }
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index be051c39a6..01c0b7ee85 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -535,8 +535,9 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L535
     // Note, gen_leave() fully reconstructs interpreter state and leaves the
     // return value in RAX before coming here.
 
+    // FIXME
     // Every exit to the interpreter should be counted
-    gen_counter_incr!(ocb, leave_interp_return);
+    //gen_counter_incr!(ocb, leave_interp_return);
 
     pop(ocb, REG_SP);
     pop(ocb, REG_EC);
@@ -552,31 +553,28 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L553
 // This is to handle the situation of optional parameters.
 // When a function with optional parameters is called, the entry
 // PC for the method isn't necessarily 0.
-fn gen_pc_guard(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) {
-    let pc_opnd = mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_PC);
+fn gen_pc_guard(asm: &mut Assembler, iseq: IseqPtr, insn_idx: u32) {
+    let pc_opnd = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC);
     let expected_pc = unsafe { rb_iseq_pc_at_idx(iseq, insn_idx) };
-    let expected_pc_opnd = const_ptr_opnd(expected_pc as *const u8);
+    let expected_pc_opnd = Opnd::const_ptr(ex (... truncated)

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

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