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

ruby-changes:73318

From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:10:22 +0900 (JST)
Subject: [ruby-changes:73318] 44c6bcff1d (master): LDRH and STRH for AArch64 (https://github.com/Shopify/ruby/pull/438)

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

From 44c6bcff1d068a2a5d191f602efc99a28e94dbc1 Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Thu, 25 Aug 2022 21:19:26 -0400
Subject: LDRH and STRH for AArch64 (https://github.com/Shopify/ruby/pull/438)

---
 yjit/src/asm/arm64/inst/halfword_imm.rs | 176 ++++++++++++++++++++++++++++++++
 yjit/src/asm/arm64/inst/mod.rs          |   2 +
 yjit/src/asm/arm64/mod.rs               | 120 ++++++++++++++++++++++
 3 files changed, 298 insertions(+)
 create mode 100644 yjit/src/asm/arm64/inst/halfword_imm.rs

diff --git a/yjit/src/asm/arm64/inst/halfword_imm.rs b/yjit/src/asm/arm64/inst/halfword_imm.rs
new file mode 100644
index 0000000000..675e33d4a8
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/halfword_imm.rs
@@ -0,0 +1,176 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/halfword_imm.rs#L1
+/// Whether this is a load or a store.
+enum Op {
+    Load = 1,
+    Store = 0
+}
+
+/// The type of indexing to perform for this instruction.
+enum Index {
+    /// No indexing.
+    None = 0b00,
+
+    /// Mutate the register after the read.
+    PostIndex = 0b01,
+
+    /// Mutate the register before the read.
+    PreIndex = 0b11
+}
+
+/// The struct that represents an A64 halfword instruction that can be encoded.
+///
+/// LDRH/STRH
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 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 |
+/// |  0  1  1  1    1  0  0  1    0                                                                                |
+/// |                                op imm12.................................... rn.............. rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+/// LDRH (pre-index/post-index)
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 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 |
+/// |  0  1  1  1    1  0  0  0    0     0                                                                          |
+/// |                                op    imm9..........................   index rn.............. rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct HalfwordImm {
+    /// The number of the 32-bit register to be loaded.
+    rt: u8,
+
+    /// The number of the 64-bit base register to calculate the memory address.
+    rn: u8,
+
+    /// The type of indexing to perform for this instruction.
+    index: Index,
+
+    /// The immediate offset from the base register.
+    imm: i16,
+
+    /// The operation to perform.
+    op: Op
+}
+
+impl HalfwordImm {
+    /// LDRH
+    /// https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/LDRH--immediate---Load-Register-Halfword--immediate--
+    pub fn ldrh(rt: u8, rn: u8, imm12: i16) -> Self {
+        Self { rt, rn, index: Index::None, imm: imm12, op: Op::Load }
+    }
+
+    /// LDRH (pre-index)
+    /// https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/LDRH--immediate---Load-Register-Halfword--immediate--
+    pub fn ldrh_pre(rt: u8, rn: u8, imm9: i16) -> Self {
+        Self { rt, rn, index: Index::PreIndex, imm: imm9, op: Op::Load }
+    }
+
+    /// LDRH (post-index)
+    /// https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/LDRH--immediate---Load-Register-Halfword--immediate--
+    pub fn ldrh_post(rt: u8, rn: u8, imm9: i16) -> Self {
+        Self { rt, rn, index: Index::PostIndex, imm: imm9, op: Op::Load }
+    }
+
+    /// STRH
+    /// https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/STRH--immediate---Store-Register-Halfword--immediate--
+    pub fn strh(rt: u8, rn: u8, imm12: i16) -> Self {
+        Self { rt, rn, index: Index::None, imm: imm12, op: Op::Store }
+    }
+
+    /// STRH (pre-index)
+    /// https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/STRH--immediate---Store-Register-Halfword--immediate--
+    pub fn strh_pre(rt: u8, rn: u8, imm9: i16) -> Self {
+        Self { rt, rn, index: Index::PreIndex, imm: imm9, op: Op::Store }
+    }
+
+    /// STRH (post-index)
+    /// https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/STRH--immediate---Store-Register-Halfword--immediate--
+    pub fn strh_post(rt: u8, rn: u8, imm9: i16) -> Self {
+        Self { rt, rn, index: Index::PostIndex, imm: imm9, op: Op::Store }
+    }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Loads-and-Stores?lang=en
+const FAMILY: u32 = 0b111100;
+
+impl From<HalfwordImm> for u32 {
+    /// Convert an instruction into a 32-bit value.
+    fn from(inst: HalfwordImm) -> Self {
+        let (mut opc, imm) = match inst.index {
+            Index::None => {
+                let mut imm12 = ((inst.imm / 2) as u32) & ((1 << 12) - 1);
+                (0b100, imm12)
+            },
+            Index::PreIndex | Index::PostIndex => {
+                let mut imm9 = (inst.imm as u32) & ((1 << 9) - 1);
+                (0b000, (imm9 << 2) | (inst.index as u32))
+            }
+        };
+
+        0
+        | (FAMILY << 25)
+        | ((opc | (inst.op as u32)) << 22)
+        | (imm << 10)
+        | ((inst.rn as u32) << 5)
+        | (inst.rt as u32)
+    }
+}
+
+impl From<HalfwordImm> for [u8; 4] {
+    /// Convert an instruction into a 4 byte array.
+    fn from(inst: HalfwordImm) -> [u8; 4] {
+        let result: u32 = inst.into();
+        result.to_le_bytes()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_ldrh() {
+        let inst = HalfwordImm::ldrh(0, 1, 8);
+        let result: u32 = inst.into();
+        assert_eq!(0x79401020, result);
+    }
+
+    #[test]
+    fn test_ldrh_pre() {
+        let inst = HalfwordImm::ldrh_pre(0, 1, 16);
+        let result: u32 = inst.into();
+        assert_eq!(0x78410c20, result);
+    }
+
+    #[test]
+    fn test_ldrh_post() {
+        let inst = HalfwordImm::ldrh_post(0, 1, 24);
+        let result: u32 = inst.into();
+        assert_eq!(0x78418420, result);
+    }
+
+    #[test]
+    fn test_ldrh_post_negative() {
+        let inst = HalfwordImm::ldrh_post(0, 1, -24);
+        let result: u32 = inst.into();
+        assert_eq!(0x785e8420, result);
+    }
+
+    #[test]
+    fn test_strh() {
+        let inst = HalfwordImm::strh(0, 1, 0);
+        let result: u32 = inst.into();
+        assert_eq!(0x79000020, result);
+    }
+
+    #[test]
+    fn test_strh_pre() {
+        let inst = HalfwordImm::strh_pre(0, 1, 0);
+        let result: u32 = inst.into();
+        assert_eq!(0x78000c20, result);
+    }
+
+    #[test]
+    fn test_strh_post() {
+        let inst = HalfwordImm::strh_post(0, 1, 0);
+        let result: u32 = inst.into();
+        assert_eq!(0x78000420, result);
+    }
+}
diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs
index ab41464013..f4c27a5102 100644
--- a/yjit/src/asm/arm64/inst/mod.rs
+++ b/yjit/src/asm/arm64/inst/mod.rs
@@ -9,6 +9,7 @@ mod call; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L9
 mod conditional;
 mod data_imm;
 mod data_reg;
+mod halfword_imm;
 mod load_literal;
 mod load_register;
 mod load_store;
@@ -30,6 +31,7 @@ pub use call::Call; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L31
 pub use conditional::Conditional;
 pub use data_imm::DataImm;
 pub use data_reg::DataReg;
+pub use halfword_imm::HalfwordImm;
 pub use load_literal::LoadLiteral;
 pub use load_register::LoadRegister;
 pub use load_store::LoadStore;
diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs
index fb07498ce2..cf898d2b5a 100644
--- a/yjit/src/asm/arm64/mod.rs
+++ b/yjit/src/asm/arm64/mod.rs
@@ -423,6 +423,51 @@ pub fn ldr_literal(cb: &mut CodeBlock, rt: A64Opnd, rn: i32) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L423
     cb.write_bytes(&bytes);
 }
 
+/// LDRH - load a halfword from memory
+pub fn ldrh(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
+    let bytes: [u8; 4] = match (rt, rn) {
+        (A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => {
+            assert_eq!(rt.num_bits, 32, "Expected to be loading a halfword");
+            assert!(imm_fits_bits(rn.disp.into(), 12), "The displacement must be 12 bits or less.");
+
+            HalfwordImm::ldrh(rt.reg_no, rn.base_reg_no, rn.disp as i16).into()
+        },
+        _ => panic!("Invalid operand combination to ldrh instruction.")
+    };
+
+    cb.write_bytes(&bytes);
+}
+
+/// LDRH (pre-index) - load a halfword from memory, update the base pointer before loading it
+pub fn ldrh_pre(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
+    let bytes: [u8; 4] = match (rt, rn) {
+        (A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => {
+            assert_eq!(rt.num_bits, 32, "Expected to be loading a halfword");
+            assert!(imm_fits_bits(rn.disp.into(), 9), "The displacement must be 9 bits or less.");
+
+            HalfwordImm::ldrh_pre(rt.reg_no, rn.base_reg_no, rn.disp as i16).into()
+        },
+        _ => panic!("Invalid operand combination to ldrh instruction.")
+    };
+
+    cb.write_bytes(&bytes);
+}
+
+/// LDRH (post-index) - load a halfword from memory, update the base pointer after loading it
+pub fn ldrh_post(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
+    let bytes: [u8; 4] = match (rt, rn) {
+        (A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => {
+            assert_eq!(rt.num_bits, 32, "Expected to be loading a halfword");
+            assert!(imm_fits_bits(rn.disp.into(), 9), "The displacement must be 9 bits or less.");
+
+            HalfwordImm::ldrh_post(rt.reg_no, rn.base_reg_no, rn.disp as i16).into( (... truncated)

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

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