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

ruby-changes:73370

From: Kevin <ko1@a...>
Date: Fri, 2 Sep 2022 11:14:45 +0900 (JST)
Subject: [ruby-changes:73370] 9b48edd932 (master): Allow comparing against 64-bit immediates on x86 (#6314)

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

From 9b48edd9322e7e0f6453303a62a83caad40a9fed Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Thu, 1 Sep 2022 22:14:23 -0400
Subject: Allow comparing against 64-bit immediates on x86 (#6314)

---
 yjit/src/backend/x86_64/mod.rs | 266 +++++++++++++++++++++++++++++++++--------
 1 file changed, 215 insertions(+), 51 deletions(-)

diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs
index bda7dc4c06..4e230822f1 100644
--- a/yjit/src/backend/x86_64/mod.rs
+++ b/yjit/src/backend/x86_64/mod.rs
@@ -103,42 +103,6 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L103
     /// Split IR instructions for the x86 platform
     fn x86_split(mut self) -> Assembler
     {
-        fn split_arithmetic_opnds(asm: &mut Assembler, live_ranges: &Vec<usize>, index: usize, unmapped_opnds: &Vec<Opnd>, left: &Opnd, right: &Opnd) -> (Opnd, Opnd) {
-            match (unmapped_opnds[0], unmapped_opnds[1]) {
-                (Opnd::Mem(_), Opnd::Mem(_)) => {
-                    (asm.load(*left), asm.load(*right))
-                },
-                (Opnd::Mem(_), Opnd::UImm(value)) => {
-                    // 32-bit values will be sign-extended
-                    if imm_num_bits(value as i64) > 32 {
-                        (asm.load(*left), asm.load(*right))
-                    } else {
-                        (asm.load(*left), *right)
-                    }
-                },
-                (Opnd::Mem(_), Opnd::Imm(value)) => {
-                    if imm_num_bits(value) > 32 {
-                        (asm.load(*left), asm.load(*right))
-                    } else {
-                        (asm.load(*left), *right)
-                    }
-                },
-                // Instruction output whose live range spans beyond this instruction
-                (Opnd::InsnOut { idx, .. }, _) => {
-                    if live_ranges[idx] > index {
-                        (asm.load(*left), *right)
-                    } else {
-                        (*left, *right)
-                    }
-                },
-                // We have to load memory operands to avoid corrupting them
-                (Opnd::Mem(_) | Opnd::Reg(_), _) => {
-                    (asm.load(*left), *right)
-                },
-                _ => (*left, *right)
-            }
-        }
-
         let live_ranges: Vec<usize> = take(&mut self.live_ranges);
         let mut asm = Assembler::new_with_label_names(take(&mut self.label_names));
         let mut iterator = self.into_draining_iter();
@@ -194,20 +158,36 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L158
                 Insn::And { left, right, out } |
                 Insn::Or { left, right, out } |
                 Insn::Xor { left, right, out } => {
-                    let (split_left, split_right) = split_arithmetic_opnds(&mut asm, &live_ranges, index, &unmapped_opnds, left, right);
+                    match (unmapped_opnds[0], unmapped_opnds[1]) {
+                        (Opnd::Mem(_), Opnd::Mem(_)) => {
+                            *left = asm.load(*left);
+                            *right = asm.load(*right);
+                        },
+                        (Opnd::Mem(_), Opnd::UImm(_) | Opnd::Imm(_)) => {
+                            *left = asm.load(*left);
+                        },
+                        // Instruction output whose live range spans beyond this instruction
+                        (Opnd::InsnOut { idx, .. }, _) => {
+                            if live_ranges[idx] > index {
+                                *left = asm.load(*left);
+                            }
+                        },
+                        // We have to load memory operands to avoid corrupting them
+                        (Opnd::Mem(_) | Opnd::Reg(_), _) => {
+                            *left = asm.load(*left);
+                        },
+                        _ => {}
+                    };
 
-                    *left = split_left;
-                    *right = split_right;
                     *out = asm.next_opnd_out(Opnd::match_num_bits(&[*left, *right]));
-
                     asm.push_insn(insn);
                 },
                 Insn::Cmp { left, right } |
                 Insn::Test { left, right } => {
-                    let (split_left, split_right) = split_arithmetic_opnds(&mut asm, &live_ranges, index, &unmapped_opnds, left, right);
-
-                    *left = split_left;
-                    *right = split_right;
+                    if let (Opnd::Mem(_), Opnd::Mem(_)) = (&left, &right) {
+                        let loaded = asm.load(*right);
+                        *right = loaded;
+                    }
 
                     asm.push_insn(insn);
                 },
@@ -329,6 +309,34 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L309
     /// Emit platform-specific machine code
     pub fn x86_emit(&mut self, cb: &mut CodeBlock) -> Vec<u32>
     {
+        /// For some instructions, we want to be able to lower a 64-bit operand
+        /// without requiring more registers to be available in the register
+        /// allocator. So we just use the SCRATCH0 register temporarily to hold
+        /// the value before we immediately use it.
+        fn emit_64bit_immediate(cb: &mut CodeBlock, opnd: &Opnd) -> X86Opnd {
+            match opnd {
+                Opnd::Imm(value) => {
+                    // 32-bit values will be sign-extended
+                    if imm_num_bits(*value) > 32 {
+                        mov(cb, Assembler::SCRATCH0, opnd.into());
+                        Assembler::SCRATCH0
+                    } else {
+                        opnd.into()
+                    }
+                },
+                Opnd::UImm(value) => {
+                    // 32-bit values will be sign-extended
+                    if imm_num_bits(*value as i64) > 32 {
+                        mov(cb, Assembler::SCRATCH0, opnd.into());
+                        Assembler::SCRATCH0
+                    } else {
+                        opnd.into()
+                    }
+                },
+                _ => opnd.into()
+            }
+        }
+
         //dbg!(&self.insns);
 
         // List of GC offsets
@@ -365,26 +373,31 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L373
                 },
 
                 Insn::Add { left, right, .. } => {
-                    add(cb, left.into(), right.into())
+                    let opnd1 = emit_64bit_immediate(cb, right);
+                    add(cb, left.into(), opnd1);
                 },
 
                 Insn::FrameSetup => {},
                 Insn::FrameTeardown => {},
 
                 Insn::Sub { left, right, .. } => {
-                    sub(cb, left.into(), right.into())
+                    let opnd1 = emit_64bit_immediate(cb, right);
+                    sub(cb, left.into(), opnd1);
                 },
 
                 Insn::And { left, right, .. } => {
-                    and(cb, left.into(), right.into())
+                    let opnd1 = emit_64bit_immediate(cb, right);
+                    and(cb, left.into(), opnd1);
                 },
 
                 Insn::Or { left, right, .. } => {
-                    or(cb, left.into(), right.into());
+                    let opnd1 = emit_64bit_immediate(cb, right);
+                    or(cb, left.into(), opnd1);
                 },
 
                 Insn::Xor { left, right, .. } => {
-                    xor(cb, left.into(), right.into());
+                    let opnd1 = emit_64bit_immediate(cb, right);
+                    xor(cb, left.into(), opnd1);
                 },
 
                 Insn::Not { opnd, .. } => {
@@ -501,12 +514,14 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L514
 
                 // Compare
                 Insn::Cmp { left, right } => {
-                    cmp(cb, left.into(), right.into());
+                    let emitted = emit_64bit_immediate(cb, right);
+                    cmp(cb, left.into(), emitted);
                 }
 
                 // Test and set flags
                 Insn::Test { left, right } => {
-                    test(cb, left.into(), right.into());
+                    let emitted = emit_64bit_immediate(cb, right);
+                    test(cb, left.into(), emitted);
                 }
 
                 Insn::JmpOpnd(opnd) => {
@@ -660,3 +675,152 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L675
         gc_offsets
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn setup_asm() -> (Assembler, CodeBlock) {
+        (Assembler::new(), CodeBlock::new_dummy(1024))
+    }
+
+    #[test]
+    fn test_emit_add_lt_32_bits() {
+        let (mut asm, mut cb) = setup_asm();
+
+        asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF));
+        asm.compile_with_num_regs(&mut cb, 1);
+
+        assert_eq!(format!("{:x}", cb), "4889c04881c0ff000000");
+    }
+
+    #[test]
+    fn test_emit_add_gt_32_bits() {
+        let (mut asm, mut cb) = setup_asm();
+
+        asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF));
+        asm.compile_with_num_regs(&mut cb, 1);
+
+        assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c01d8");
+    }
+
+    #[test]
+    fn test_emit_and_lt_32_bits() {
+        let (mut asm, mut cb) = setup_asm();
+
+        asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF));
+        asm.compile_with_num_regs(&mut cb, 1);
+
+        assert_eq!(format!("{:x}", cb), "4889c04881e0ff000000");
+    }
+
+    #[test]
+    fn test_emit_and_gt_32_bits() {
+        let (mut asm, mut cb) = setup_asm();
+
+        asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF));
+        asm.compile_with_num_regs(&mut cb, 1);
+
+        assert_eq!(format!("{:x}", cb), "4889c0 (... truncated)

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

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