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

ruby-changes:73212

From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:02:57 +0900 (JST)
Subject: [ruby-changes:73212] 70e117d512 (master): Fixes (https://github.com/Shopify/ruby/pull/336)

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

From 70e117d512636465d8dc2094b22dd6535602050a Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Thu, 21 Jul 2022 16:25:21 -0400
Subject: Fixes (https://github.com/Shopify/ruby/pull/336)

* Fix bitmask encoding to u32

* Fix splitting for Op::And to account for bitmask immediate
---
 yjit/src/asm/arm64/arg/bitmask_imm.rs |  9 +++-
 yjit/src/backend/arm64/mod.rs         | 98 +++++++++++++++++++----------------
 2 files changed, 61 insertions(+), 46 deletions(-)

diff --git a/yjit/src/asm/arm64/arg/bitmask_imm.rs b/yjit/src/asm/arm64/arg/bitmask_imm.rs
index 847b735eaa..220a7d697e 100644
--- a/yjit/src/asm/arm64/arg/bitmask_imm.rs
+++ b/yjit/src/asm/arm64/arg/bitmask_imm.rs
@@ -136,7 +136,7 @@ impl From<BitmaskImmediate> for u32 { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/arg/bitmask_imm.rs#L136
     fn from(bitmask: BitmaskImmediate) -> Self {
         0
         | (((bitmask.n as u32) & 1) << 12)
-        | (bitmask.immr << 6) as u32
+        | ((bitmask.immr as u32) << 6)
         | bitmask.imms as u32
     }
 }
@@ -152,6 +152,13 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/arg/bitmask_imm.rs#L152
         });
     }
 
+    #[test]
+    fn test_negative() {
+        let bitmask: BitmaskImmediate = (-9_i64 as u64).try_into().unwrap();
+        let encoded: u32 = bitmask.into();
+        assert_eq!(7998, encoded);
+    }
+
     #[test]
     fn test_size_2_minimum() {
         let bitmask = BitmaskImmediate::try_from(0x5555555555555555);
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs
index b1f4d63d0f..d3db3877dc 100644
--- a/yjit/src/backend/arm64/mod.rs
+++ b/yjit/src/backend/arm64/mod.rs
@@ -81,6 +81,30 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L81
     /// have no memory operands.
     fn arm64_split(mut self) -> Assembler
     {
+        fn load_bitmask_immediate(asm: &mut Assembler, opnd: Opnd) -> Opnd {
+            match opnd {
+                Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd,
+                Opnd::Mem(_) => asm.load(opnd),
+                Opnd::Imm(imm) => {
+                    if imm <= 0 {
+                        asm.load(opnd)
+                    } else if BitmaskImmediate::try_from(imm as u64).is_ok() {
+                        Opnd::UImm(imm as u64)
+                    } else {
+                        asm.load(opnd)
+                    }
+                },
+                Opnd::UImm(uimm) => {
+                    if BitmaskImmediate::try_from(uimm).is_ok() {
+                        opnd
+                    } else {
+                        asm.load(opnd)
+                    }
+                },
+                Opnd::None | Opnd::Value(_) => unreachable!()
+            }
+        }
+
         self.forward_pass(|asm, index, op, opnds, target, text, pos_marker| {
             // Load all Value operands into registers that aren't already a part
             // of Load instructions.
@@ -96,7 +120,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L120
             };
 
             match op {
-                Op::Add | Op::And | Op::Sub => {
+                Op::Add | Op::Sub => {
                     // Check if one of the operands is a register. If it is,
                     // then we'll make that the first operand.
                     match (opnds[0], opnds[1]) {
@@ -115,6 +139,23 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L139
                         }
                     }
                 },
+                Op::And => {
+                    match (opnds[0], opnds[1]) {
+                        (Opnd::Reg(_), Opnd::Reg(_)) => {
+                            asm.and(opnds[0], opnds[1]);
+                        },
+                        (reg_opnd @ Opnd::Reg(_), other_opnd) |
+                        (other_opnd, reg_opnd @ Opnd::Reg(_)) => {
+                            let opnd1 = load_bitmask_immediate(asm, other_opnd);
+                            asm.and(reg_opnd, opnd1);
+                        },
+                        _ => {
+                            let opnd0 = asm.load(opnds[0]);
+                            let opnd1 = load_bitmask_immediate(asm, opnds[1]);
+                            asm.and(opnd0, opnd1);
+                        }
+                    }
+                },
                 Op::CCall => {
                     assert!(opnds.len() < C_ARG_REGS.len());
 
@@ -188,29 +229,16 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L229
                     };
                 },
                 Op::Mov => {
-                    // The value that is being moved must be either a register
-                    // or an immediate that can be encoded as a bitmask
-                    // immediate. Otherwise, we'll need to split the move into
-                    // multiple instructions.
-                    let value = match opnds[1] {
-                        Opnd::Reg(_) | Opnd::InsnOut { .. } => opnds[1],
-                        Opnd::Mem(_) | Opnd::Imm(_) => asm.load(opnds[1]),
-                        Opnd::UImm(uimm) => {
-                            if let Ok(encoded) = BitmaskImmediate::try_from(uimm) {
-                                if let Opnd::Mem(_) = opnds[0] {
-                                    // If the first operand is a memory operand,
-                                    // we're going to transform this into a
-                                    // store instruction, so we'll need to load
-                                    // this anyway.
-                                    asm.load(opnds[1])
-                                } else {
-                                    opnds[1]
-                                }
-                            } else {
-                                asm.load(opnds[1])
-                            }
-                        },
-                        _ => unreachable!()
+                    let value = match (opnds[0], opnds[1]) {
+                        // If the first operand is a memory operand, we're going
+                        // to transform this into a store instruction, so we'll
+                        // need to load this anyway.
+                        (Opnd::Mem(_), Opnd::UImm(_)) => asm.load(opnds[1]),
+                        // The value that is being moved must be either a
+                        // register or an immediate that can be encoded as a
+                        // bitmask immediate. Otherwise, we'll need to split the
+                        // move into multiple instructions.
+                        _ => load_bitmask_immediate(asm, opnds[1])
                     };
 
                     // If we're attempting to load into a memory operand, then
@@ -253,27 +281,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L281
                     // unsigned immediate that can be encoded as a bitmask
                     // immediate. If it's not one of those, we'll need to load
                     // it first.
-                    let opnd1 = match opnds[1] {
-                        Opnd::Reg(_) | Opnd::InsnOut { .. } => opnds[1],
-                        Opnd::Mem(_) => asm.load(opnds[1]),
-                        Opnd::Imm(imm) => {
-                            if imm <= 0 {
-                                asm.load(opnds[1])
-                            } else if BitmaskImmediate::try_from(imm as u64).is_ok() {
-                                Opnd::UImm(imm as u64)
-                            } else {
-                                asm.load(opnds[1])
-                            }
-                        },
-                        Opnd::UImm(uimm) => {
-                            if BitmaskImmediate::try_from(uimm).is_ok() {
-                                opnds[1]
-                            } else {
-                                asm.load(opnds[1])
-                            }
-                        },
-                        Opnd::None | Opnd::Value(_) => unreachable!()
-                    };
+                    let opnd1 = load_bitmask_immediate(asm, opnds[1]);
 
                     asm.test(opnd0, opnd1);
                 },
-- 
cgit v1.2.1


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

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