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

ruby-changes:73138

From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 00:55:20 +0900 (JST)
Subject: [ruby-changes:73138] c10e018e1c (master): LDADDAL, STUR, BL (https://github.com/Shopify/ruby/pull/299)

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

From c10e018e1c2dd3351af1f40f9b20ea23cfeace36 Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Mon, 13 Jun 2022 17:16:33 -0400
Subject: LDADDAL, STUR, BL (https://github.com/Shopify/ruby/pull/299)

* LDADDAL instruction

* STUR

* BL instruction

* Remove num_bits from imm and uimm

* Tests for imm_fits_bits and uimm_fits_bits

* Reorder arguments to LDADDAL
---
 yjit/src/asm/arm64/inst/atomic.rs |  86 ++++++++++++++++++++++++
 yjit/src/asm/arm64/inst/call.rs   |  67 +++++++++++++++++++
 yjit/src/asm/arm64/inst/mod.rs    | 137 +++++++++++++++++++++++++++++++++-----
 yjit/src/asm/arm64/inst/store.rs  | 105 +++++++++++++++++++++++++++++
 yjit/src/asm/arm64/opnd.rs        |  42 ++----------
 5 files changed, 384 insertions(+), 53 deletions(-)
 create mode 100644 yjit/src/asm/arm64/inst/atomic.rs
 create mode 100644 yjit/src/asm/arm64/inst/call.rs
 create mode 100644 yjit/src/asm/arm64/inst/store.rs

diff --git a/yjit/src/asm/arm64/inst/atomic.rs b/yjit/src/asm/arm64/inst/atomic.rs
new file mode 100644
index 0000000000..5ce497209c
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/atomic.rs
@@ -0,0 +1,86 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/atomic.rs#L1
+/// The size of the register operands to this instruction.
+enum Size {
+    /// Using 32-bit registers.
+    Size32 = 0b10,
+
+    /// Using 64-bit registers.
+    Size64 = 0b11
+}
+
+/// A convenience function so that we can convert the number of bits of an
+/// register operand directly into a Size enum variant.
+impl From<u8> for Size {
+    fn from(num_bits: u8) -> Self {
+        match num_bits {
+            64 => Size::Size64,
+            32 => Size::Size32,
+            _ => panic!("Invalid number of bits: {}", num_bits)
+        }
+    }
+}
+
+/// The struct that represents an A64 atomic instruction that can be encoded.
+///
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 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  1    1  0  0  0    1  1  1                     0  0  0  0    0  0                                   |
+/// | size                                 rs..............                       rn.............. rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Atomic {
+    /// The register holding the value to be loaded.
+    rt: u8,
+
+    /// The base register.
+    rn: u8,
+
+    /// The register holding the data value to be operated on.
+    rs: u8,
+
+    /// The size of the registers used in this instruction.
+    size: Size
+}
+
+impl Atomic {
+    /// LDADDAL
+    /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDADD--LDADDA--LDADDAL--LDADDL--Atomic-add-on-word-or-doubleword-in-memory-?lang=en
+    pub fn ldaddal(rs: u8, rt: u8, rn: u8, num_bits: u8) -> Self {
+        Self { rt, rn, rs, size: num_bits.into() }
+    }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Loads-and-Stores?lang=en
+const FAMILY: u32 = 0b0100;
+
+impl From<Atomic> for u32 {
+    /// Convert an instruction into a 32-bit value.
+    fn from(inst: Atomic) -> Self {
+        0
+        | ((inst.size as u32) << 30)
+        | (0b11 << 28)
+        | (FAMILY << 25)
+        | (0b111 << 21)
+        | ((inst.rs as u32) << 16)
+        | ((inst.rn as u32) << 5)
+        | (inst.rt as u32)
+    }
+}
+
+impl From<Atomic> for [u8; 4] {
+    /// Convert an instruction into a 4 byte array.
+    fn from(inst: Atomic) -> [u8; 4] {
+        let result: u32 = inst.into();
+        result.to_le_bytes()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_ldaddal() {
+        let result: u32 = Atomic::ldaddal(20, 21, 22, 64).into();
+        assert_eq!(0xf8f402d5, result);
+    }
+}
diff --git a/yjit/src/asm/arm64/inst/call.rs b/yjit/src/asm/arm64/inst/call.rs
new file mode 100644
index 0000000000..6f23acf9f5
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/call.rs
@@ -0,0 +1,67 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/call.rs#L1
+/// The struct that represents an A64 branch with link instruction that can be
+/// encoded.
+///
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 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  1    0  1                                                                                           |
+/// |                     imm26.................................................................................... |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Call {
+    /// The PC-relative offset to jump to (which will be multiplied by 4).
+    imm26: i32
+}
+
+impl Call {
+    /// BL
+    /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/BL--Branch-with-Link-?lang=en
+    pub fn bl(imm26: i32) -> Self {
+        Self { imm26 }
+    }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Branches--Exception-Generating-and-System-instructions?lang=en
+const FAMILY: u32 = 0b101;
+
+impl From<Call> for u32 {
+    /// Convert an instruction into a 32-bit value.
+    fn from(inst: Call) -> Self {
+        let imm26 = (inst.imm26 as u32) & ((1 << 26) - 1);
+
+        0
+        | (1 << 31)
+        | (FAMILY << 26)
+        | imm26
+    }
+}
+
+impl From<Call> for [u8; 4] {
+    /// Convert an instruction into a 4 byte array.
+    fn from(inst: Call) -> [u8; 4] {
+        let result: u32 = inst.into();
+        result.to_le_bytes()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_bl() {
+        let result: u32 = Call::bl(0).into();
+        assert_eq!(0x94000000, result);
+    }
+
+    #[test]
+    fn test_bl_positive() {
+        let result: u32 = Call::bl(256).into();
+        assert_eq!(0x94000100, result);
+    }
+
+    #[test]
+    fn test_bl_negative() {
+        let result: u32 = Call::bl(-256).into();
+        assert_eq!(0x97ffff00, result);
+    }
+}
diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs
index eec9d116b2..c96e9328ff 100644
--- a/yjit/src/asm/arm64/inst/mod.rs
+++ b/yjit/src/asm/arm64/inst/mod.rs
@@ -1,19 +1,42 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L1
+mod atomic;
 mod branch;
+mod call;
 mod data_imm;
 mod data_reg;
 mod load;
 mod mov;
 mod sf;
+mod store;
 
+use core::num;
+
+use atomic::Atomic;
 use branch::Branch;
+use call::Call;
 use data_imm::DataImm;
 use data_reg::DataReg;
 use load::Load;
 use mov::Mov;
+use store::Store;
 
-use crate::asm::{CodeBlock, imm_num_bits};
+use crate::asm::CodeBlock;
 use super::opnd::*;
 
+/// Checks that a signed value fits within the specified number of bits.
+const fn imm_fits_bits(imm: i64, num_bits: u8) -> bool {
+    let minimum = if num_bits == 64 { i64::MIN } else { -2_i64.pow((num_bits as u32) - 1) };
+    let maximum = if num_bits == 64 { i64::MAX } else { 2_i64.pow((num_bits as u32) - 1) - 1 };
+
+    imm >= minimum && imm <= maximum
+}
+
+/// Checks that an unsigned value fits within the specified number of bits.
+const fn uimm_fits_bits(uimm: u64, num_bits: u8) -> bool {
+    let maximum = if num_bits == 64 { u64::MAX } else { 2_u64.pow(num_bits as u32) - 1 };
+
+    uimm <= maximum
+}
+
 /// ADD - add rn and rm, put the result in rd, don't update flags
 pub fn add(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
     let bytes: [u8; 4] = match (rd, rn, rm) {
@@ -27,9 +50,9 @@ pub fn add(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L50
         },
         (A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
             assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size.");
-            assert!(imm12.num_bits <= 12, "The immediate operand must be 12 bits or less.");
+            assert!(uimm_fits_bits(imm12, 12), "The immediate operand must be 12 bits or less.");
 
-            DataImm::add(rd.reg_no, rn.reg_no, imm12.value as u16, rd.num_bits).into()
+            DataImm::add(rd.reg_no, rn.reg_no, imm12 as u16, rd.num_bits).into()
         },
         _ => panic!("Invalid operand combination to add instruction."),
     };
@@ -50,9 +73,9 @@ pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L73
         },
         (A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
             assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size.");
-            assert!(imm12.num_bits <= 12, "The immediate operand must be 12 bits or less.");
+            assert!(uimm_fits_bits(imm12, 12), "The immediate operand must be 12 bits or less.");
 
-            DataImm::adds(rd.reg_no, rn.reg_no, imm12.value as u16, rd.num_bits).into()
+            DataImm::adds(rd.reg_no, rn.reg_no, imm12 as u16, rd.num_bits).into()
         },
         _ => panic!("Invalid operand combination to adds instruction."),
     };
@@ -60,6 +83,20 @@ pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L83
     cb.write_bytes(&bytes);
 }
 
+/// BL - branch with link (offset is number of instructions to jump)
+pub fn bl(cb: &mut CodeBlock, imm26: A64Opnd) {
+    let bytes: [u8; 4] = match imm26 {
+        A64Opnd::Imm(imm26) => {
+            assert!(imm_fits_bits(imm26, 26), "The immediate operand must be 26 bits or less.");
+
+            Call::bl(imm26 as i32).into()
+     (... truncated)

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

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