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

ruby-changes:73187

From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 00:59:55 +0900 (JST)
Subject: [ruby-changes:73187] 160e29b9e5 (master): Port print_str to new backend (https://github.com/Shopify/ruby/pull/318)

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

From 160e29b9e5c9419e3275d4bd6de09c9c4f242602 Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Fri, 15 Jul 2022 13:25:26 -0400
Subject: Port print_str to new backend
 (https://github.com/Shopify/ruby/pull/318)

* ADR and ADRP for AArch64

* Implement Op::Jbe on X86

* Lera instruction

* Op::BakeString

* LeaPC -> LeaLabel

* Port print_str to the new backend

* Port print_value to the new backend

* Port print_ptr to the new backend

* Write null-terminators in Op::BakeString

* Fix up rebase issues on print-str port

* Add back in panic for X86 backend for unsupported instructions being lowered

* Fix target architecture
---
 yjit/src/asm/arm64/inst/mod.rs    |   2 +
 yjit/src/asm/arm64/inst/pc_rel.rs | 107 ++++++++++++++++++++++++++++++++++++++
 yjit/src/asm/arm64/mod.rs         |  42 +++++++++++++++
 yjit/src/backend/arm64/mod.rs     |  75 +++++++++++++++++++++-----
 yjit/src/backend/ir.rs            |  62 ++++++++++++++++------
 yjit/src/backend/tests.rs         |   8 +++
 yjit/src/backend/x86_64/mod.rs    |  53 ++++++++++++++++---
 yjit/src/codegen.rs               |   4 +-
 yjit/src/utils.rs                 |  89 +++++++++----------------------
 9 files changed, 339 insertions(+), 103 deletions(-)
 create mode 100644 yjit/src/asm/arm64/inst/pc_rel.rs

diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs
index 9dfc923f53..752ee64aa3 100644
--- a/yjit/src/asm/arm64/inst/mod.rs
+++ b/yjit/src/asm/arm64/inst/mod.rs
@@ -14,6 +14,7 @@ mod logical_imm; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L14
 mod logical_reg;
 mod mov;
 mod nop;
+mod pc_rel;
 mod shift_imm;
 mod store;
 mod sys_reg;
@@ -31,6 +32,7 @@ pub use logical_imm::LogicalImm; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L32
 pub use logical_reg::LogicalReg;
 pub use mov::Mov;
 pub use nop::Nop;
+pub use pc_rel::PCRelative;
 pub use shift_imm::ShiftImm;
 pub use store::Store;
 pub use sys_reg::SysReg;
diff --git a/yjit/src/asm/arm64/inst/pc_rel.rs b/yjit/src/asm/arm64/inst/pc_rel.rs
new file mode 100644
index 0000000000..fa330cb9d6
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/pc_rel.rs
@@ -0,0 +1,107 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/pc_rel.rs#L1
+/// Which operation to perform for the PC-relative instruction.
+enum Op {
+    /// Form a PC-relative address.
+    ADR = 0,
+
+    /// Form a PC-relative address to a 4KB page.
+    ADRP = 1
+}
+
+/// The struct that represents an A64 PC-relative address instruction that can
+/// be encoded.
+///
+/// ADR
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 |
+/// |           1    0  0  0  0                                                                                     |
+/// | op immlo                    immhi........................................................... rd.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct PCRelative {
+    /// The number for the general-purpose register to load the address into.
+    rd: u8,
+
+    /// The number of bytes to add to the PC to form the address.
+    imm: i32,
+
+    /// Which operation to perform for this instruction.
+    op: Op
+}
+
+impl PCRelative {
+    /// ADR
+    /// https://developer.arm.com/documentation/ddi0602/2022-03/Base-Instructions/ADR--Form-PC-relative-address-
+    pub fn adr(rd: u8, imm: i32) -> Self {
+        Self { rd, imm, op: Op::ADR }
+    }
+
+    /// ADRP
+    /// https://developer.arm.com/documentation/ddi0602/2022-03/Base-Instructions/ADRP--Form-PC-relative-address-to-4KB-page-
+    pub fn adrp(rd: u8, imm: i32) -> Self {
+        Self { rd, imm: imm >> 12, op: Op::ADRP }
+    }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Data-Processing----Immediate?lang=en
+const FAMILY: u32 = 0b1000;
+
+impl From<PCRelative> for u32 {
+    /// Convert an instruction into a 32-bit value.
+    fn from(inst: PCRelative) -> Self {
+        let immlo = (inst.imm & 0b11) as u32;
+        let mut immhi = ((inst.imm >> 2) & ((1 << 18) - 1)) as u32;
+
+        // Toggle the sign bit if necessary.
+        if inst.imm < 0 {
+            immhi |= (1 << 18);
+        }
+
+        0
+        | ((inst.op as u32) << 31)
+        | (immlo << 29)
+        | (FAMILY << 25)
+        | (immhi << 5)
+        | inst.rd as u32
+    }
+}
+
+impl From<PCRelative> for [u8; 4] {
+    /// Convert an instruction into a 4 byte array.
+    fn from(inst: PCRelative) -> [u8; 4] {
+        let result: u32 = inst.into();
+        result.to_le_bytes()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_adr_positive() {
+        let inst = PCRelative::adr(0, 5);
+        let result: u32 = inst.into();
+        assert_eq!(0x30000020, result);
+    }
+
+    #[test]
+    fn test_adr_negative() {
+        let inst = PCRelative::adr(0, -5);
+        let result: u32 = inst.into();
+        assert_eq!(0x70ffffc0, result);
+    }
+
+    #[test]
+    fn test_adrp_positive() {
+        let inst = PCRelative::adrp(0, 0x4000);
+        let result: u32 = inst.into();
+        assert_eq!(0x90000020, result);
+    }
+
+    #[test]
+    fn test_adrp_negative() {
+        let inst = PCRelative::adrp(0, -0x4000);
+        let result: u32 = inst.into();
+        assert_eq!(0x90ffffe0, result);
+    }
+}
diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs
index 7adc1a2745..ca69b33d9e 100644
--- a/yjit/src/asm/arm64/mod.rs
+++ b/yjit/src/asm/arm64/mod.rs
@@ -94,6 +94,38 @@ pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L94
     cb.write_bytes(&bytes);
 }
 
+/// ADR - form a PC-relative address and load it into a register
+pub fn adr(cb: &mut CodeBlock, rd: A64Opnd, imm: A64Opnd) {
+    let bytes: [u8; 4] = match (rd, imm) {
+        (A64Opnd::Reg(rd), A64Opnd::Imm(imm)) => {
+            assert!(rd.num_bits == 64, "The destination register must be 64 bits.");
+            assert!(imm_fits_bits(imm, 21), "The immediate operand must be 21 bits or less.");
+
+            PCRelative::adr(rd.reg_no, imm as i32).into()
+        },
+        _ => panic!("Invalid operand combination to adr instruction."),
+    };
+
+    cb.write_bytes(&bytes);
+}
+
+/// ADRP - form a PC-relative address to a 4KB page and load it into a register.
+/// This is effectively the same as ADR except that the immediate must be a
+/// multiple of 4KB.
+pub fn adrp(cb: &mut CodeBlock, rd: A64Opnd, imm: A64Opnd) {
+    let bytes: [u8; 4] = match (rd, imm) {
+        (A64Opnd::Reg(rd), A64Opnd::Imm(imm)) => {
+            assert!(rd.num_bits == 64, "The destination register must be 64 bits.");
+            assert!(imm_fits_bits(imm, 32), "The immediate operand must be 32 bits or less.");
+
+            PCRelative::adrp(rd.reg_no, imm as i32).into()
+        },
+        _ => panic!("Invalid operand combination to adr instruction."),
+    };
+
+    cb.write_bytes(&bytes);
+}
+
 /// AND - and rn and rm, put the result in rd, don't update flags
 pub fn and(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
     let bytes: [u8; 4] = match (rd, rn, rm) {
@@ -628,6 +660,16 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L660
         check_bytes("201c00f1", |cb| adds(cb, X0, X1, A64Opnd::new_imm(-7)));
     }
 
+    #[test]
+    fn test_adr() {
+        check_bytes("aa000010", |cb| adr(cb, X10, A64Opnd::new_imm(20)));
+    }
+
+    #[test]
+    fn test_adrp() {
+        check_bytes("4a000090", |cb| adrp(cb, X10, A64Opnd::new_imm(0x8000)));
+    }
+
     #[test]
     fn test_and_register() {
         check_bytes("2000028a", |cb| and(cb, X0, X1, X2));
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs
index 22998b1ab5..153237a9b1 100644
--- a/yjit/src/backend/arm64/mod.rs
+++ b/yjit/src/backend/arm64/mod.rs
@@ -58,6 +58,9 @@ impl From<Opnd> for A64Opnd { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L58
 
 impl Assembler
 {
+    // A special scratch register for intermediate processing.
+    const SCRATCH0: A64Opnd = A64Opnd::Reg(X22_REG);
+
     /// Get the list of registers from which we will allocate on this platform
     /// These are caller-saved registers
     /// Note: we intentionally exclude C_RET_REG (X0) from this list
@@ -78,7 +81,7 @@ 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
     {
-        self.forward_pass(|asm, index, op, opnds, target| {
+        self.forward_pass(|asm, index, op, opnds, target, text| {
             // Load all Value operands into registers that aren't already a part
             // of Load instructions.
             let opnds = match op {
@@ -100,15 +103,15 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L103
                         (Opnd::Mem(_), Opnd::Mem(_)) => {
                             let opnd0 = asm.load(opnds[0]);
                             let opnd1 = asm.load(opnds[1]);
-                            asm.push_insn(op, vec![opnd0, opnd1], target);
+                            asm.push_insn(op, vec![opnd0, opnd1], target, text);
                         },
                         (mem_opnd @ Opnd::Mem(_), other_opnd) |
                         (other_opnd, mem_opnd @ Opnd::Mem(_)) => {
                             let opnd0 = asm.load(mem_opnd);
-                            asm.push_insn(op, vec![opnd0, other_opnd], target);
+                            asm.push_insn(op, vec![opnd0, other_opnd], target, text);
                         },
              (... truncated)

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

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