summaryrefslogtreecommitdiff
path: root/yjit/src/asm/arm64/inst
diff options
context:
space:
mode:
Diffstat (limited to 'yjit/src/asm/arm64/inst')
-rw-r--r--yjit/src/asm/arm64/inst/breakpoint.rs55
-rw-r--r--yjit/src/asm/arm64/inst/call.rs51
-rw-r--r--yjit/src/asm/arm64/inst/logical_imm.rs37
-rw-r--r--yjit/src/asm/arm64/inst/logical_reg.rs80
-rw-r--r--yjit/src/asm/arm64/inst/mod.rs4
-rw-r--r--yjit/src/asm/arm64/inst/nop.rs44
6 files changed, 254 insertions, 17 deletions
diff --git a/yjit/src/asm/arm64/inst/breakpoint.rs b/yjit/src/asm/arm64/inst/breakpoint.rs
new file mode 100644
index 0000000000..be4920ac76
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/breakpoint.rs
@@ -0,0 +1,55 @@
+/// The struct that represents an A64 breakpoint 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 0 1 0 1 0 0 0 0 1 0 0 0 0 0 |
+/// | imm16.................................................. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Breakpoint {
+ /// The value to be captured by ESR_ELx.ISS
+ imm16: u16
+}
+
+impl Breakpoint {
+ /// BRK
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/BRK--Breakpoint-instruction-
+ pub fn brk(imm16: u16) -> Self {
+ Self { imm16 }
+ }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Branches--Exception-Generating-and-System-instructions?lang=en#control
+const FAMILY: u32 = 0b101;
+
+impl From<Breakpoint> for u32 {
+ /// Convert an instruction into a 32-bit value.
+ fn from(inst: Breakpoint) -> Self {
+ let imm16 = inst.imm16 as u32;
+
+ 0
+ | (0b11 << 30)
+ | (FAMILY << 26)
+ | (1 << 21)
+ | (imm16 << 5)
+ }
+}
+
+impl From<Breakpoint> for [u8; 4] {
+ /// Convert an instruction into a 4 byte array.
+ fn from(inst: Breakpoint) -> [u8; 4] {
+ let result: u32 = inst.into();
+ result.to_le_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_brk() {
+ let result: u32 = Breakpoint::brk(7).into();
+ assert_eq!(0xd42000e0, result);
+ }
+}
diff --git a/yjit/src/asm/arm64/inst/call.rs b/yjit/src/asm/arm64/inst/call.rs
index 6f23acf9f5..8d65359f77 100644
--- a/yjit/src/asm/arm64/inst/call.rs
+++ b/yjit/src/asm/arm64/inst/call.rs
@@ -1,22 +1,41 @@
-/// The struct that represents an A64 branch with link instruction that can be
-/// encoded.
+/// The operation to perform for this instruction.
+enum Op {
+ /// Branch directly, with a hint that this is not a subroutine call or
+ /// return.
+ Branch = 0,
+
+ /// Branch directly, with a hint that this is a subroutine call or return.
+ BranchWithLink = 1
+}
+
+/// The struct that represents an A64 branch with our without 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.................................................................................... |
+/// | 0 0 1 0 1 |
+/// | op imm26.................................................................................... |
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
///
pub struct Call {
/// The PC-relative offset to jump to (which will be multiplied by 4).
- imm26: i32
+ imm26: i32,
+
+ /// The operation to perform for this instruction.
+ op: Op
}
impl Call {
+ /// B
+ /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/B--Branch-
+ pub fn b(imm26: i32) -> Self {
+ Self { imm26, op: Op::Branch }
+ }
+
/// 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 }
+ Self { imm26, op: Op::BranchWithLink }
}
}
@@ -29,7 +48,7 @@ impl From<Call> for u32 {
let imm26 = (inst.imm26 as u32) & ((1 << 26) - 1);
0
- | (1 << 31)
+ | ((inst.op as u32) << 31)
| (FAMILY << 26)
| imm26
}
@@ -64,4 +83,22 @@ mod tests {
let result: u32 = Call::bl(-256).into();
assert_eq!(0x97ffff00, result);
}
+
+ #[test]
+ fn test_b() {
+ let result: u32 = Call::b(0).into();
+ assert_eq!(0x14000000, result);
+ }
+
+ #[test]
+ fn test_b_positive() {
+ let result: u32 = Call::b(256).into();
+ assert_eq!(0x14000100, result);
+ }
+
+ #[test]
+ fn test_b_negative() {
+ let result: u32 = Call::b(-256).into();
+ assert_eq!(0x17ffff00, result);
+ }
}
diff --git a/yjit/src/asm/arm64/inst/logical_imm.rs b/yjit/src/asm/arm64/inst/logical_imm.rs
index cc2a16cbdc..13865697f6 100644
--- a/yjit/src/asm/arm64/inst/logical_imm.rs
+++ b/yjit/src/asm/arm64/inst/logical_imm.rs
@@ -5,6 +5,9 @@ enum Opc {
/// The AND operation.
And = 0b00,
+ /// The ORR operation.
+ Orr = 0b01,
+
/// The ANDS operation.
Ands = 0b11
}
@@ -12,7 +15,7 @@ enum Opc {
/// The struct that represents an A64 bitwise immediate instruction that can be
/// encoded.
///
-/// AND/ANDS (immediate)
+/// AND/ORR/ANDS (immediate)
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
/// | 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 0 |
@@ -37,19 +40,31 @@ pub struct LogicalImm {
}
impl LogicalImm {
- /// AND (immediate)
+ /// AND (bitmask immediate)
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/AND--immediate---Bitwise-AND--immediate--?lang=en
pub fn and(rd: u8, rn: u8, imm: BitmaskImmediate, num_bits: u8) -> Self {
Self { rd, rn, imm, opc: Opc::And, sf: num_bits.into() }
}
- /// ANDS (immediate)
+ /// ANDS (bitmask immediate)
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/ANDS--immediate---Bitwise-AND--immediate---setting-flags-?lang=en
pub fn ands(rd: u8, rn: u8, imm: BitmaskImmediate, num_bits: u8) -> Self {
Self { rd, rn, imm, opc: Opc::Ands, sf: num_bits.into() }
}
- /// TST (immediate)
+ /// MOV (bitmask immediate)
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/MOV--bitmask-immediate---Move--bitmask-immediate---an-alias-of-ORR--immediate--?lang=en
+ pub fn mov(rd: u8, imm: BitmaskImmediate, num_bits: u8) -> Self {
+ Self { rd, rn: 0b11111, imm, opc: Opc::Orr, sf: num_bits.into() }
+ }
+
+ /// ORR (bitmask immediate)
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/ORR--immediate---Bitwise-OR--immediate--
+ pub fn orr(rd: u8, rn: u8, imm: BitmaskImmediate, num_bits: u8) -> Self {
+ Self { rd, rn, imm, opc: Opc::Orr, sf: num_bits.into() }
+ }
+
+ /// TST (bitmask immediate)
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/TST--immediate---Test-bits--immediate---an-alias-of-ANDS--immediate--?lang=en
pub fn tst(rn: u8, imm: BitmaskImmediate, num_bits: u8) -> Self {
Self::ands(31, rn, imm, num_bits)
@@ -101,6 +116,20 @@ mod tests {
}
#[test]
+ fn test_mov() {
+ let inst = LogicalImm::mov(0, 0x5555555555555555.try_into().unwrap(), 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xb200f3e0, result);
+ }
+
+ #[test]
+ fn test_orr() {
+ let inst = LogicalImm::orr(0, 1, 7.try_into().unwrap(), 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xb2400820, result);
+ }
+
+ #[test]
fn test_tst() {
let inst = LogicalImm::tst(1, 7.try_into().unwrap(), 64);
let result: u32 = inst.into();
diff --git a/yjit/src/asm/arm64/inst/logical_reg.rs b/yjit/src/asm/arm64/inst/logical_reg.rs
index 3feb3350ab..5d7954c587 100644
--- a/yjit/src/asm/arm64/inst/logical_reg.rs
+++ b/yjit/src/asm/arm64/inst/logical_reg.rs
@@ -1,5 +1,14 @@
use super::super::arg::Sf;
+/// Whether or not this is a NOT instruction.
+enum N {
+ /// This is not a NOT instruction.
+ No = 0,
+
+ /// This is a NOT instruction.
+ Yes = 1
+}
+
/// The type of shift to perform on the second operand register.
enum Shift {
LSL = 0b00, // logical shift left (unsigned)
@@ -13,6 +22,9 @@ enum Opc {
/// The AND operation.
And = 0b00,
+ /// The ORR operation.
+ Orr = 0b01,
+
/// The ANDS operation.
Ands = 0b11
}
@@ -20,11 +32,11 @@ enum Opc {
/// The struct that represents an A64 logical register instruction that can be
/// encoded.
///
-/// AND/ANDS (shifted register)
+/// AND/ORR/ANDS (shifted register)
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
/// | 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 0 1 0 0 |
-/// | sf opc.. shift rm.............. imm6............... rn.............. rd.............. |
+/// | 0 1 0 1 0 |
+/// | sf opc.. shift N rm.............. imm6............... rn.............. rd.............. |
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
///
pub struct LogicalReg {
@@ -40,6 +52,9 @@ pub struct LogicalReg {
/// The register number of the second operand register.
rm: u8,
+ /// Whether or not this is a NOT instruction.
+ n: N,
+
/// The type of shift to perform on the second operand register.
shift: Shift,
@@ -54,19 +69,43 @@ impl LogicalReg {
/// AND (shifted register)
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/AND--shifted-register---Bitwise-AND--shifted-register--?lang=en
pub fn and(rd: u8, rn: u8, rm: u8, num_bits: u8) -> Self {
- Self { rd, rn, imm6: 0, rm, shift: Shift::LSL, opc: Opc::And, sf: num_bits.into() }
+ Self { rd, rn, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::And, sf: num_bits.into() }
}
/// ANDS (shifted register)
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/ANDS--shifted-register---Bitwise-AND--shifted-register---setting-flags-?lang=en
pub fn ands(rd: u8, rn: u8, rm: u8, num_bits: u8) -> Self {
- Self { rd, rn, imm6: 0, rm, shift: Shift::LSL, opc: Opc::Ands, sf: num_bits.into() }
+ Self { rd, rn, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::Ands, sf: num_bits.into() }
+ }
+
+ /// MOV (register)
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/MOV--register---Move--register---an-alias-of-ORR--shifted-register--?lang=en
+ pub fn mov(rd: u8, rm: u8, num_bits: u8) -> Self {
+ Self { rd, rn: 0b11111, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::Orr, sf: num_bits.into() }
+ }
+
+ /// MVN (shifted register)
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/MVN--Bitwise-NOT--an-alias-of-ORN--shifted-register--?lang=en
+ pub fn mvn(rd: u8, rm: u8, num_bits: u8) -> Self {
+ Self { rd, rn: 0b11111, imm6: 0, rm, n: N::Yes, shift: Shift::LSL, opc: Opc::Orr, sf: num_bits.into() }
+ }
+
+ /// ORN (shifted register)
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/ORN--shifted-register---Bitwise-OR-NOT--shifted-register--
+ pub fn orn(rd: u8, rn: u8, rm: u8, num_bits: u8) -> Self {
+ Self { rd, rn, imm6: 0, rm, n: N::Yes, shift: Shift::LSL, opc: Opc::Orr, sf: num_bits.into() }
+ }
+
+ /// ORR (shifted register)
+ /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/ORR--shifted-register---Bitwise-OR--shifted-register--
+ pub fn orr(rd: u8, rn: u8, rm: u8, num_bits: u8) -> Self {
+ Self { rd, rn, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::Orr, sf: num_bits.into() }
}
/// TST (shifted register)
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/TST--shifted-register---Test--shifted-register---an-alias-of-ANDS--shifted-register--?lang=en
pub fn tst(rn: u8, rm: u8, num_bits: u8) -> Self {
- Self { rd: 31, rn, imm6: 0, rm, shift: Shift::LSL, opc: Opc::Ands, sf: num_bits.into() }
+ Self { rd: 31, rn, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::Ands, sf: num_bits.into() }
}
}
@@ -83,6 +122,7 @@ impl From<LogicalReg> for u32 {
| ((inst.opc as u32) << 29)
| (FAMILY << 25)
| ((inst.shift as u32) << 22)
+ | ((inst.n as u32) << 21)
| ((inst.rm as u32) << 16)
| (imm6 << 10)
| ((inst.rn as u32) << 5)
@@ -117,6 +157,34 @@ mod tests {
}
#[test]
+ fn test_mov() {
+ let inst = LogicalReg::mov(0, 1, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xaa0103e0, result);
+ }
+
+ #[test]
+ fn test_mvn() {
+ let inst = LogicalReg::mvn(0, 1, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xaa2103e0, result);
+ }
+
+ #[test]
+ fn test_orn() {
+ let inst = LogicalReg::orn(0, 1, 2, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xaa220020, result);
+ }
+
+ #[test]
+ fn test_orr() {
+ let inst = LogicalReg::orr(0, 1, 2, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xaa020020, result);
+ }
+
+ #[test]
fn test_tst() {
let inst = LogicalReg::tst(0, 1, 64);
let result: u32 = inst.into();
diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs
index 2f0e708999..ae589ca564 100644
--- a/yjit/src/asm/arm64/inst/mod.rs
+++ b/yjit/src/asm/arm64/inst/mod.rs
@@ -4,6 +4,7 @@
mod atomic;
mod branch;
mod branch_cond;
+mod breakpoint;
mod call;
mod data_imm;
mod data_reg;
@@ -11,12 +12,14 @@ mod load;
mod logical_imm;
mod logical_reg;
mod mov;
+mod nop;
mod shift_imm;
mod store;
pub use atomic::Atomic;
pub use branch::Branch;
pub use branch_cond::BranchCond;
+pub use breakpoint::Breakpoint;
pub use call::Call;
pub use data_imm::DataImm;
pub use data_reg::DataReg;
@@ -24,5 +27,6 @@ pub use load::Load;
pub use logical_imm::LogicalImm;
pub use logical_reg::LogicalReg;
pub use mov::Mov;
+pub use nop::Nop;
pub use shift_imm::ShiftImm;
pub use store::Store;
diff --git a/yjit/src/asm/arm64/inst/nop.rs b/yjit/src/asm/arm64/inst/nop.rs
new file mode 100644
index 0000000000..a99f8d34b7
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/nop.rs
@@ -0,0 +1,44 @@
+/// The struct that represents an A64 nop instruction that can be encoded.
+///
+/// NOP
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 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 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Nop;
+
+impl Nop {
+ /// NOP
+ /// https://developer.arm.com/documentation/ddi0602/2022-03/Base-Instructions/NOP--No-Operation-
+ pub fn nop() -> Self {
+ Self {}
+ }
+}
+
+impl From<Nop> for u32 {
+ /// Convert an instruction into a 32-bit value.
+ fn from(inst: Nop) -> Self {
+ 0b11010101000000110010000000011111
+ }
+}
+
+impl From<Nop> for [u8; 4] {
+ /// Convert an instruction into a 4 byte array.
+ fn from(inst: Nop) -> [u8; 4] {
+ let result: u32 = inst.into();
+ result.to_le_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_nop() {
+ let inst = Nop::nop();
+ let result: u32 = inst.into();
+ assert_eq!(0xd503201f, result);
+ }
+}