mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
TBZ and TBNZ for AArch64 (https://github.com/Shopify/ruby/pull/434)
This commit is contained in:
parent
c2e9253893
commit
29e0713a12
Notes:
git
2022-08-30 01:10:08 +09:00
3 changed files with 171 additions and 0 deletions
|
@ -22,6 +22,7 @@ mod reg_pair;
|
||||||
mod sbfm;
|
mod sbfm;
|
||||||
mod shift_imm;
|
mod shift_imm;
|
||||||
mod sys_reg;
|
mod sys_reg;
|
||||||
|
mod test_bit;
|
||||||
|
|
||||||
pub use atomic::Atomic;
|
pub use atomic::Atomic;
|
||||||
pub use branch::Branch;
|
pub use branch::Branch;
|
||||||
|
@ -44,3 +45,4 @@ pub use reg_pair::RegisterPair;
|
||||||
pub use sbfm::SBFM;
|
pub use sbfm::SBFM;
|
||||||
pub use shift_imm::ShiftImm;
|
pub use shift_imm::ShiftImm;
|
||||||
pub use sys_reg::SysReg;
|
pub use sys_reg::SysReg;
|
||||||
|
pub use test_bit::TestBit;
|
||||||
|
|
135
yjit/src/asm/arm64/inst/test_bit.rs
Normal file
135
yjit/src/asm/arm64/inst/test_bit.rs
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/// The upper bit of the bit number to test.
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum B5 {
|
||||||
|
/// When the bit number is below 32.
|
||||||
|
B532 = 0,
|
||||||
|
|
||||||
|
/// When the bit number is equal to or above 32.
|
||||||
|
B564 = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A convenience function so that we can convert the bit number directly into a
|
||||||
|
/// B5 variant.
|
||||||
|
impl From<u8> for B5 {
|
||||||
|
fn from(bit_num: u8) -> Self {
|
||||||
|
match bit_num {
|
||||||
|
0..=31 => B5::B532,
|
||||||
|
32..=63 => B5::B564,
|
||||||
|
_ => panic!("Invalid bit number: {}", bit_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The operation to perform for this instruction.
|
||||||
|
enum Op {
|
||||||
|
/// The test bit zero operation.
|
||||||
|
TBZ = 0,
|
||||||
|
|
||||||
|
/// The test bit not zero operation.
|
||||||
|
TBNZ = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The struct that represents an A64 test bit instruction that can be encoded.
|
||||||
|
///
|
||||||
|
/// TBNZ/TBZ
|
||||||
|
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
|
||||||
|
/// | 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 0 1 1 |
|
||||||
|
/// | b5 op b40............. imm14.......................................... rt.............. |
|
||||||
|
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
|
||||||
|
///
|
||||||
|
pub struct TestBit {
|
||||||
|
/// The number of the register to test.
|
||||||
|
rt: u8,
|
||||||
|
|
||||||
|
/// The PC-relative offset to the target instruction in term of number of
|
||||||
|
/// instructions.
|
||||||
|
imm14: i16,
|
||||||
|
|
||||||
|
/// The lower 5 bits of the bit number to be tested.
|
||||||
|
b40: u8,
|
||||||
|
|
||||||
|
/// The operation to perform for this instruction.
|
||||||
|
op: Op,
|
||||||
|
|
||||||
|
/// The upper bit of the bit number to test.
|
||||||
|
b5: B5
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestBit {
|
||||||
|
/// TBNZ
|
||||||
|
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/TBNZ--Test-bit-and-Branch-if-Nonzero-?lang=en
|
||||||
|
pub fn tbnz(rt: u8, bit_num: u8, offset: i16) -> Self {
|
||||||
|
Self { rt, imm14: offset, b40: bit_num & 0b11111, op: Op::TBNZ, b5: bit_num.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TBZ
|
||||||
|
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/TBZ--Test-bit-and-Branch-if-Zero-?lang=en
|
||||||
|
pub fn tbz(rt: u8, bit_num: u8, offset: i16) -> Self {
|
||||||
|
Self { rt, imm14: offset, b40: bit_num & 0b11111, op: Op::TBZ, b5: bit_num.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Branches--Exception-Generating-and-System-instructions?lang=en
|
||||||
|
const FAMILY: u32 = 0b11011;
|
||||||
|
|
||||||
|
impl From<TestBit> for u32 {
|
||||||
|
/// Convert an instruction into a 32-bit value.
|
||||||
|
fn from(inst: TestBit) -> Self {
|
||||||
|
let b40 = (inst.b40 & 0b11111) as u32;
|
||||||
|
let mut imm14 = (inst.imm14 & ((1 << 13) - 1)) as u32;
|
||||||
|
|
||||||
|
if inst.imm14 < 0 {
|
||||||
|
imm14 |= (1 << 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
| ((inst.b5 as u32) << 31)
|
||||||
|
| (FAMILY << 25)
|
||||||
|
| ((inst.op as u32) << 24)
|
||||||
|
| (b40 << 19)
|
||||||
|
| (imm14 << 5)
|
||||||
|
| inst.rt as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TestBit> for [u8; 4] {
|
||||||
|
/// Convert an instruction into a 4 byte array.
|
||||||
|
fn from(inst: TestBit) -> [u8; 4] {
|
||||||
|
let result: u32 = inst.into();
|
||||||
|
result.to_le_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tbnz() {
|
||||||
|
let inst = TestBit::tbnz(0, 0, 0);
|
||||||
|
let result: u32 = inst.into();
|
||||||
|
assert_eq!(0x37000000, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tbnz_negative() {
|
||||||
|
let inst = TestBit::tbnz(0, 0, -1);
|
||||||
|
let result: u32 = inst.into();
|
||||||
|
assert_eq!(0x3707ffe0, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tbz() {
|
||||||
|
let inst = TestBit::tbz(0, 0, 0);
|
||||||
|
let result: u32 = inst.into();
|
||||||
|
assert_eq!(0x36000000, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tbz_negative() {
|
||||||
|
let inst = TestBit::tbz(0, 0, -1);
|
||||||
|
let result: u32 = inst.into();
|
||||||
|
assert_eq!(0x3607ffe0, result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -934,6 +934,30 @@ pub fn ret(cb: &mut CodeBlock, rn: A64Opnd) {
|
||||||
cb.write_bytes(&bytes);
|
cb.write_bytes(&bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TBNZ - test bit and branch if not zero
|
||||||
|
pub fn tbnz(cb: &mut CodeBlock, rt: A64Opnd, bit_num: A64Opnd, offset: A64Opnd) {
|
||||||
|
let bytes: [u8; 4] = match (rt, bit_num, offset) {
|
||||||
|
(A64Opnd::Reg(rt), A64Opnd::UImm(bit_num), A64Opnd::Imm(offset)) => {
|
||||||
|
TestBit::tbnz(rt.reg_no, bit_num.try_into().unwrap(), offset.try_into().unwrap()).into()
|
||||||
|
},
|
||||||
|
_ => panic!("Invalid operand combination to tbnz instruction.")
|
||||||
|
};
|
||||||
|
|
||||||
|
cb.write_bytes(&bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TBZ - test bit and branch if zero
|
||||||
|
pub fn tbz(cb: &mut CodeBlock, rt: A64Opnd, bit_num: A64Opnd, offset: A64Opnd) {
|
||||||
|
let bytes: [u8; 4] = match (rt, bit_num, offset) {
|
||||||
|
(A64Opnd::Reg(rt), A64Opnd::UImm(bit_num), A64Opnd::Imm(offset)) => {
|
||||||
|
TestBit::tbz(rt.reg_no, bit_num.try_into().unwrap(), offset.try_into().unwrap()).into()
|
||||||
|
},
|
||||||
|
_ => panic!("Invalid operand combination to tbz instruction.")
|
||||||
|
};
|
||||||
|
|
||||||
|
cb.write_bytes(&bytes);
|
||||||
|
}
|
||||||
|
|
||||||
/// TST - test the bits of a register against a mask, then update flags
|
/// TST - test the bits of a register against a mask, then update flags
|
||||||
pub fn tst(cb: &mut CodeBlock, rn: A64Opnd, rm: A64Opnd) {
|
pub fn tst(cb: &mut CodeBlock, rn: A64Opnd, rm: A64Opnd) {
|
||||||
let bytes: [u8; 4] = match (rn, rm) {
|
let bytes: [u8; 4] = match (rn, rm) {
|
||||||
|
@ -1393,6 +1417,16 @@ mod tests {
|
||||||
check_bytes("6a7d4093", |cb| sxtw(cb, X10, W11));
|
check_bytes("6a7d4093", |cb| sxtw(cb, X10, W11));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tbnz() {
|
||||||
|
check_bytes("4a005037", |cb| tbnz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tbz() {
|
||||||
|
check_bytes("4a005036", |cb| tbz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2)));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tst_register() {
|
fn test_tst_register() {
|
||||||
check_bytes("1f0001ea", |cb| tst(cb, X0, X1));
|
check_bytes("1f0001ea", |cb| tst(cb, X0, X1));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue