diff options
Diffstat (limited to 'yjit/src/asm/arm64/inst')
| -rw-r--r-- | yjit/src/asm/arm64/inst/breakpoint.rs | 55 | ||||
| -rw-r--r-- | yjit/src/asm/arm64/inst/call.rs | 51 | ||||
| -rw-r--r-- | yjit/src/asm/arm64/inst/logical_imm.rs | 37 | ||||
| -rw-r--r-- | yjit/src/asm/arm64/inst/logical_reg.rs | 80 | ||||
| -rw-r--r-- | yjit/src/asm/arm64/inst/mod.rs | 4 | ||||
| -rw-r--r-- | yjit/src/asm/arm64/inst/nop.rs | 44 |
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); + } +} |
