use super::arm_instr_info::ArmOpcode;
#[cfg(test)]
use super::arm_mc_encoder::ArmCond;
use crate::codegen::{MachineInstr, MachineOperand, PhysReg};
const OP_ADD: u32 = ArmOpcode::ADD as u32;
const OP_SUB: u32 = ArmOpcode::SUB as u32;
const _OP_MUL: u32 = ArmOpcode::MUL as u32;
const OP_SDIV: u32 = ArmOpcode::SDIV as u32;
const OP_UDIV: u32 = ArmOpcode::UDIV as u32;
const OP_AND: u32 = ArmOpcode::AND as u32;
const OP_ORR: u32 = ArmOpcode::ORR as u32;
const OP_EOR: u32 = ArmOpcode::EOR as u32;
const OP_ADDS: u32 = ArmOpcode::ADDS as u32;
const OP_SUBS: u32 = ArmOpcode::SUBS as u32;
const OP_MADD: u32 = ArmOpcode::MADD as u32;
const OP_MSUB: u32 = ArmOpcode::MSUB as u32;
const OP_MOV: u32 = ArmOpcode::MOV as u32;
const OP_MOVZ: u32 = ArmOpcode::MOVZ as u32;
const OP_MOVK: u32 = ArmOpcode::MOVK as u32;
const OP_MOVN: u32 = ArmOpcode::MOVN as u32;
const OP_LDR: u32 = ArmOpcode::LDR as u32;
const OP_STR: u32 = ArmOpcode::STR as u32;
const OP_LDP: u32 = ArmOpcode::LDP as u32;
const OP_STP: u32 = ArmOpcode::STP as u32;
const OP_B: u32 = ArmOpcode::B as u32;
const OP_BL: u32 = ArmOpcode::BL as u32;
const OP_BR: u32 = ArmOpcode::BR as u32;
const OP_BLR: u32 = ArmOpcode::BLR as u32;
const OP_RET: u32 = ArmOpcode::RET as u32;
const OP_CBZ: u32 = ArmOpcode::CBZ as u32;
const OP_CBNZ: u32 = ArmOpcode::CBNZ as u32;
const OP_B_COND: u32 = ArmOpcode::B_COND as u32;
const OP_CMP: u32 = ArmOpcode::CMP as u32;
const OP_CSEL: u32 = ArmOpcode::CSEL as u32;
const OP_BFM: u32 = ArmOpcode::BFM as u32;
const OP_SBFM: u32 = ArmOpcode::SBFM as u32;
const OP_UBFM: u32 = ArmOpcode::UBFM as u32;
const OP_NOP: u32 = ArmOpcode::NOP as u32;
const OP_ARM_ADD: u32 = ArmOpcode::ARM_ADD as u32;
const OP_ARM_SUB: u32 = ArmOpcode::ARM_SUB as u32;
const OP_ARM_MOV: u32 = ArmOpcode::ARM_MOV as u32;
const OP_ARM_AND: u32 = ArmOpcode::ARM_AND as u32;
const OP_ARM_ORR: u32 = ArmOpcode::ARM_ORR as u32;
const OP_ARM_EOR: u32 = ArmOpcode::ARM_EOR as u32;
const OP_ARM_CMP: u32 = ArmOpcode::ARM_CMP as u32;
const OP_ARM_B: u32 = ArmOpcode::ARM_B as u32;
const OP_ARM_BL: u32 = ArmOpcode::ARM_BL as u32;
const OP_ARM_LDR: u32 = ArmOpcode::ARM_LDR as u32;
const OP_ARM_STR: u32 = ArmOpcode::ARM_STR as u32;
const _OP_ARM_PUSH: u32 = ArmOpcode::ARM_PUSH as u32;
const _OP_ARM_POP: u32 = ArmOpcode::ARM_POP as u32;
const _OP_INVALID: u32 = ArmOpcode::INVALID as u32;
const OP_SVC: u32 = ArmOpcode::SVC as u32;
const OP_HVC: u32 = ArmOpcode::HVC as u32;
const OP_SMC: u32 = ArmOpcode::SMC as u32;
const OP_BRK: u32 = ArmOpcode::BRK as u32;
const OP_MSR: u32 = ArmOpcode::MSR as u32;
const OP_MRS: u32 = ArmOpcode::MRS as u32;
const OP_SYS: u32 = ArmOpcode::SYS as u32;
const OP_SYSL: u32 = ArmOpcode::SYSL as u32;
const OP_ADR: u32 = ArmOpcode::ADR as u32;
const OP_ADRP: u32 = ArmOpcode::ADRP as u32;
const OP_TBNZ: u32 = ArmOpcode::TBNZ as u32;
const OP_TBZ: u32 = ArmOpcode::TBZ as u32;
const OP_LDRB: u32 = ArmOpcode::LDRB as u32;
const OP_LDRH: u32 = ArmOpcode::LDRH as u32;
const OP_LDRSB: u32 = ArmOpcode::LDRSB as u32;
const OP_LDRSH: u32 = ArmOpcode::LDRSH as u32;
const OP_LDRSW: u32 = ArmOpcode::LDRSW as u32;
const OP_STRB: u32 = ArmOpcode::STRB as u32;
const OP_STRH: u32 = ArmOpcode::STRH as u32;
const OP_LDUR: u32 = ArmOpcode::LDUR as u32;
const OP_STUR: u32 = ArmOpcode::STUR as u32;
const OP_PRFM: u32 = ArmOpcode::PRFM as u32;
const OP_CLREX: u32 = ArmOpcode::CLREX_A64 as u32;
const OP_DMB: u32 = ArmOpcode::DMB as u32;
const OP_DSB: u32 = ArmOpcode::DSB as u32;
const OP_ISB: u32 = ArmOpcode::ISB as u32;
const OP_CCMN: u32 = ArmOpcode::CCMN as u32;
const OP_CCMP: u32 = ArmOpcode::CCMP as u32;
const OP_RBIT: u32 = ArmOpcode::RBIT as u32;
const OP_REV: u32 = ArmOpcode::REV as u32;
const OP_REV16: u32 = ArmOpcode::REV16 as u32;
const OP_REV32: u32 = ArmOpcode::REV32 as u32;
const OP_CLZ: u32 = ArmOpcode::CLZ as u32;
const OP_CLS: u32 = ArmOpcode::CLS as u32;
const OP_BIC: u32 = ArmOpcode::BIC as u32;
const OP_UBFX: u32 = ArmOpcode::UBFX as u32;
const OP_SBFX: u32 = ArmOpcode::SBFX as u32;
const OP_EXTR: u32 = ArmOpcode::EXTR as u32;
const OP_FADD: u32 = ArmOpcode::FADD as u32;
const OP_FSUB: u32 = ArmOpcode::FSUB as u32;
const OP_FMUL: u32 = ArmOpcode::FMUL as u32;
const OP_FDIV: u32 = ArmOpcode::FDIV as u32;
const OP_FNEG: u32 = ArmOpcode::FNEG as u32;
const OP_FABS: u32 = ArmOpcode::FABS as u32;
const OP_FSQRT: u32 = ArmOpcode::FSQRT as u32;
const OP_FMOV: u32 = ArmOpcode::FMOV as u32;
const OP_FCVT: u32 = ArmOpcode::FCVT as u32;
const OP_FCVTZS: u32 = ArmOpcode::FCVTZS as u32;
const OP_FCVTZU: u32 = ArmOpcode::FCVTZU as u32;
const OP_SCVTF: u32 = ArmOpcode::SCVTF as u32;
const OP_UCVTF: u32 = ArmOpcode::UCVTF as u32;
const OP_FCMP: u32 = ArmOpcode::FCMP as u32;
const OP_FCSEL: u32 = ArmOpcode::FCSEL as u32;
const OP_FMIN: u32 = ArmOpcode::FMIN as u32;
const OP_FMAX: u32 = ArmOpcode::FMAX as u32;
const OP_FRINTN: u32 = ArmOpcode::FRINTN as u32;
const OP_FRINTZ: u32 = ArmOpcode::FRINTZ as u32;
const OP_FRINTM: u32 = ArmOpcode::FRINTM as u32;
const OP_FRINTP: u32 = ArmOpcode::FRINTP as u32;
const OP_FRINTA: u32 = ArmOpcode::FRINTA as u32;
const OP_FRINTX: u32 = ArmOpcode::FRINTX as u32;
const OP_FRINTI: u32 = ArmOpcode::FRINTI as u32;
const OP_FCCMP: u32 = ArmOpcode::FCCMP as u32;
const OP_FADDP: u32 = ArmOpcode::FADDP as u32;
const OP_DUP: u32 = ArmOpcode::DUP as u32;
const OP_AND_V: u32 = ArmOpcode::AND_V as u32;
const OP_ORR_V: u32 = ArmOpcode::ORR_V as u32;
const OP_EOR_V: u32 = ArmOpcode::EOR_V as u32;
const OP_BIC_V: u32 = ArmOpcode::BIC_V as u32;
const OP_ADD_V: u32 = ArmOpcode::ADD_V as u32;
const OP_SUB_V: u32 = ArmOpcode::SUB_V as u32;
const OP_MUL_V: u32 = ArmOpcode::MUL_V as u32;
const OP_MLA_V: u32 = ArmOpcode::MLA_V as u32;
const OP_MLS_V: u32 = ArmOpcode::MLS_V as u32;
const OP_BSL: u32 = ArmOpcode::BSL as u32;
const OP_BIT: u32 = ArmOpcode::BIT as u32;
const OP_BIF: u32 = ArmOpcode::BIF as u32;
const OP_SSHL: u32 = ArmOpcode::SSHL as u32;
const OP_USHL: u32 = ArmOpcode::USHL as u32;
const OP_CMEQ: u32 = ArmOpcode::CMEQ as u32;
const OP_CMGT: u32 = ArmOpcode::CMGT as u32;
const OP_CMGE: u32 = ArmOpcode::CMGE as u32;
const OP_CMHI: u32 = ArmOpcode::CMHI as u32;
const OP_CMHS: u32 = ArmOpcode::CMHS as u32;
const OP_CMTST: u32 = ArmOpcode::CMTST as u32;
const OP_XTN: u32 = ArmOpcode::XTN as u32;
const OP_SQXTN: u32 = ArmOpcode::SQXTN as u32;
const OP_UQXTN: u32 = ArmOpcode::UQXTN as u32;
const OP_SCVTF_V: u32 = ArmOpcode::SCVTF_V as u32;
const OP_UCVTF_V: u32 = ArmOpcode::UCVTF_V as u32;
const OP_FCVTZS_V: u32 = ArmOpcode::FCVTZS_V as u32;
const OP_FCVTZU_V: u32 = ArmOpcode::FCVTZU_V as u32;
const OP_EXT: u32 = ArmOpcode::EXT as u32;
const OP_TBL: u32 = ArmOpcode::TBL as u32;
const OP_TBX: u32 = ArmOpcode::TBX as u32;
const OP_ZIP1: u32 = ArmOpcode::ZIP1 as u32;
const OP_ZIP2: u32 = ArmOpcode::ZIP2 as u32;
const OP_UZP1: u32 = ArmOpcode::UZP1 as u32;
const OP_UZP2: u32 = ArmOpcode::UZP2 as u32;
const OP_TRN1: u32 = ArmOpcode::TRN1 as u32;
const OP_TRN2: u32 = ArmOpcode::TRN2 as u32;
const OP_REV64: u32 = ArmOpcode::REV64 as u32;
const OP_REV32_V: u32 = ArmOpcode::REV32_V as u32;
const OP_REV16_V: u32 = ArmOpcode::REV16_V as u32;
const OP_SADDLP: u32 = ArmOpcode::SADDLP as u32;
const OP_UADDLP: u32 = ArmOpcode::UADDLP as u32;
const OP_SMAXV: u32 = ArmOpcode::SMAXV as u32;
const OP_UMAXV: u32 = ArmOpcode::UMAXV as u32;
const OP_SMINV: u32 = ArmOpcode::SMINV as u32;
const OP_UMINV: u32 = ArmOpcode::UMINV as u32;
const OP_FMAXV: u32 = ArmOpcode::FMAXV as u32;
const OP_FMINV: u32 = ArmOpcode::FMINV as u32;
const OP_SADDLV: u32 = ArmOpcode::SADDLV as u32;
const OP_UADDLV: u32 = ArmOpcode::UADDLV as u32;
const OP_MOVI: u32 = ArmOpcode::MOVI as u32;
const OP_LD2: u32 = ArmOpcode::LD2 as u32;
const OP_LD3: u32 = ArmOpcode::LD3 as u32;
const OP_LD4: u32 = ArmOpcode::LD4 as u32;
const OP_ST2: u32 = ArmOpcode::ST2 as u32;
const OP_ST3: u32 = ArmOpcode::ST3 as u32;
const OP_ST4: u32 = ArmOpcode::ST4 as u32;
pub struct ArmMCDecoder {
pub is_64bit: bool,
}
impl ArmMCDecoder {
pub fn new(is_64bit: bool) -> Self {
Self { is_64bit }
}
pub fn decode_instruction(&self, bytes: &[u8], offset: usize) -> Option<(MachineInstr, usize)> {
if offset + 4 > bytes.len() {
return None;
}
let word = u32::from_le_bytes([
bytes[offset],
bytes[offset + 1],
bytes[offset + 2],
bytes[offset + 3],
]);
if self.is_64bit {
self.decode_aarch64(word).map(|mi| (mi, 4))
} else {
self.decode_arm32(word).map(|mi| (mi, 4))
}
}
pub fn decode_aarch64(&self, insn: u32) -> Option<MachineInstr> {
if (insn & 0xFFFFF000) == 0xD5032000 {
return self.decode_nop_hint(insn);
}
if (insn & 0xFFFFFC00) == 0xD65F0000 {
return self.decode_ret(insn);
}
if (insn & 0xFFFFFC00) == 0xD61F0000 {
return self.decode_br_blr(insn);
}
if (insn >> 26) & 0x3F == 0x05 {
return self.decode_b_bl(insn);
}
if (insn >> 26) & 0x3F == 0x25 {
return self.decode_b_bl(insn);
}
if ((insn >> 24) & 0xFE) == 0x54 {
return self.decode_b_cond(insn);
}
if ((insn >> 24) & 0x7F) == 0x34 {
return self.decode_cbz_cbnz(insn);
}
if insn >> 24 == 0xB5 {
return self.decode_cbz_cbnz(insn);
}
if ((insn >> 22) & 0x3FF) == 0x294 || (insn >> 22) & 0x3FF == 0x2D4 {
let fixed = (insn >> 22) & 0xFF;
if fixed == 0xA5 || fixed == 0xA4 {
return self.decode_ldp_stp(insn);
}
}
let pair_fixed = (insn >> 22) & 0xFF;
if pair_fixed == 0xA5 || pair_fixed == 0xA4 {
let opc = (insn >> 30) & 0x3;
if opc == 0b10 || opc == 0b11 {
return self.decode_ldp_stp(insn);
}
}
let ls_fixed = (insn >> 22) & 0xFF; if ls_fixed == 0xE5 || ls_fixed == 0xE4 {
return self.decode_ldr_str_imm(insn);
}
if ((insn >> 23) & 0x1FF) == 0x110 || ((insn >> 23) & 0x1FF) == 0x111 {
let opc = (insn >> 24) & 0x1F;
if opc == 0x11 || opc == 0x10 {
return self.decode_add_sub_imm(insn);
}
}
let dp_imm_op = (insn >> 24) & 0x1F;
if dp_imm_op == 0x11 {
return self.decode_add_sub_imm(insn);
}
if ((insn >> 24) & 0x1F) == 0x0B {
return self.decode_add_sub_reg(insn);
}
if ((insn >> 24) & 0x1F) == 0x0A {
return self.decode_logical_reg(insn);
}
if ((insn >> 23) & 0x3F) == 0x25 {
let opc = (insn >> 29) & 0x3;
match opc {
0b10 => return self.decode_movz_movk(insn), 0b11 => return self.decode_movz_movk(insn), 0b00 => return self.decode_movz_movk(insn), _ => {}
}
}
if ((insn >> 21) & 0x7FF) == 0x354 {
let opc21 = (insn >> 21) & 0xFF;
if opc21 == 0xD4 || opc21 == 0x54 {
return self.decode_csel(insn);
}
}
let csel_fixed = (insn >> 21) & 0xFF;
if csel_fixed == 0xD4 {
let sub_opc = (insn >> 10) & 0x3;
if sub_opc == 0 {
return self.decode_csel(insn);
}
}
let dp2 = (insn >> 21) & 0xFF; if dp2 == 0xD6 {
let sub = (insn >> 10) & 0x3F;
if sub == 0b000010 || sub == 0b000011 {
return self.decode_sdiv_udiv(insn);
}
}
if ((insn >> 24) & 0x1F) == 0x1B {
let sub_opc = (insn >> 21) & 0x7;
if sub_opc == 0 {
return self.decode_madd_msub(insn);
}
}
if ((insn >> 23) & 0x3F) == 0x26 {
return self.decode_bfm(insn);
}
if (insn >> 21) == 0x6A0 {
let opc = insn & 0x1F;
match opc {
1 => return self.decode_svc(insn),
2 => return self.decode_svc(insn), 3 => return self.decode_svc(insn), _ => {}
}
}
if ((insn >> 21) & 0x7FF) == 0x6A1 {
if (insn & 0x1F) == 0 {
return self.decode_brk(insn);
}
}
if ((insn >> 22) & 0x3FF) == 0x354 {
let opc0 = (insn >> 19) & 0x1;
if opc0 == 0 {
return self.decode_msr(insn);
} else {
return self.decode_mrs(insn);
}
}
if ((insn >> 22) & 0x3FF) == 0x352 || ((insn >> 22) & 0x3FF) == 0x353 {
return self.decode_sys(insn);
}
if (insn & 0xFFFFF000) == 0xD5033000 {
return self.decode_barrier(insn);
}
if ((insn >> 24) & 0x9F) == 0x10 {
return self.decode_adr_adrp(insn);
}
if ((insn >> 24) & 0x7F) == 0x36 || ((insn >> 24) & 0x7F) == 0x37 {
return self.decode_tbz_tbnz(insn);
}
if ((insn >> 22) & 0x3F) == 0x38 {
let opc = (insn >> 22) & 0x3;
if opc == 0 || opc == 1 {
return self.decode_ldrb_strb(insn);
}
}
if ((insn >> 22) & 0x3F) == 0x78 {
let opc = (insn >> 22) & 0x3;
if opc == 0 || opc == 1 {
return self.decode_ldrh_strh(insn);
}
}
if ((insn >> 22) & 0xFF) == 0xE2 || ((insn >> 22) & 0xFF) == 0xE0 {
return self.decode_ldur_stur(insn);
}
if ((insn >> 21) & 0x7FF) == 0x352 {
return self.decode_ccmp_ccmn(insn);
}
if ((insn >> 21) & 0x7FF) == 0x35B {
return self.decode_one_source(insn);
}
if ((insn >> 24) & 0x1F) == 0x0F {
if ((insn >> 28) & 0xF) == 0x0 || ((insn >> 28) & 0xF) == 0x4 {
let opcode = (insn >> 10) & 0x3F;
let op2 = (insn >> 12) & 0xF;
if op2 == 0b0000 && opcode == 0b10000 {
return self.decode_fmov(insn);
}
if op2 == 0b0100 {
return self.decode_fp_two_reg(insn);
}
if opcode >= 0b001000 && opcode <= 0b111111 {
return self.decode_fp_three_reg(insn);
}
if ((insn >> 21) & 1) == 1 && op2 == 0x0 {
return self.decode_fcvt_int_fp(insn);
}
if (op2 == 0b1100 && (opcode & 0b11) == 0b11) {
return self.decode_fcsel(insn);
}
}
}
if ((insn >> 24) & 0x1F) == 0x0E {
let u = (insn >> 29) & 1;
let opcode = (insn >> 10) & 0x3F;
if matches!(opcode, 0b100001 | 0b100111 | 0b100101 | 0b000111) {
return self.decode_simd_three_same(insn);
}
if matches!(opcode, 0b100011 | 0b001101 | 0b001111) {
return self.decode_simd_cmp(insn);
}
if opcode == 0b010101 {
return self.decode_simd_shift(insn);
}
if matches!(
opcode,
0b001110 | 0b001111 | 0b000110 | 0b000111 | 0b001010 | 0b001011
) {
return self.decode_simd_permute(insn);
}
let op2 = (insn >> 12) & 0x1F;
if matches!(op2, 0b11011 | 0b00111 | 0b01101 | 0b01111) {
return self.decode_simd_across(insn);
}
}
if ((insn >> 22) & 0x1FF) == 0x170 || ((insn >> 22) & 0x1FF) == 0x370 {
return self.decode_ext(insn);
}
if ((insn >> 24) & 0x3F) == 0x0C {
return self.decode_simd_ldst_single(insn);
}
if (insn >> 24) == 0xC1 {
return self.decode_sme2_multi_vector(insn);
}
if (insn >> 24) == 0x81 {
return self.decode_sme2_outer_product(insn);
}
if (insn >> 24) == 0xC5 {
return self.decode_sme2_mv_ldst(insn);
}
None
}
pub fn decode_add_sub_imm(&self, insn: u32) -> Option<MachineInstr> {
let sf = (insn >> 31) & 1;
let op = (insn >> 30) & 1;
let s = (insn >> 29) & 1;
let sh = (insn >> 22) & 3;
let imm12 = (insn >> 10) & 0xFFF;
let rn = (insn >> 5) & 0x1F;
let rd = insn & 0x1F;
let imm_val = if sh == 0 {
imm12 as i64
} else {
(imm12 << 12) as i64
};
let opcode = if s != 0 {
if op == 0 {
OP_ADDS
} else {
OP_SUBS
}
} else {
if op == 0 {
OP_ADD
} else {
OP_SUB
}
};
if rd == 31 && s != 0 {
return self.decode_cmp_imm(insn, rn as u8, imm_val);
}
let rn_phys = self.reg_field_to_phys(rd as u8, sf != 0); let rn_src = self.reg_field_to_phys(rn as u8, sf != 0);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_src as u32));
mi.operands.push(MachineOperand::Imm(imm_val));
Some(mi)
}
fn decode_cmp_imm(&self, _insn: u32, rn: u8, imm: i64) -> Option<MachineInstr> {
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(OP_CMP);
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::Imm(imm));
Some(mi)
}
pub fn decode_add_sub_reg(&self, insn: u32) -> Option<MachineInstr> {
let sf = (insn >> 31) & 1;
let op = (insn >> 30) & 1;
let s = (insn >> 29) & 1;
let rm = ((insn >> 16) & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rd = (insn & 0x1F) as u8;
let opcode = if s != 0 {
if op == 0 {
OP_ADDS
} else {
OP_SUBS
}
} else {
if op == 0 {
OP_ADD
} else {
OP_SUB
}
};
if rd == 31 && s != 0 {
return self.decode_cmp_reg(insn, rn, rm);
}
let rd_phys = self.reg_field_to_phys(rd, sf != 0);
let rn_phys = self.reg_field_to_phys(rn, sf != 0);
let rm_phys = self.reg_field_to_phys(rm, sf != 0);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
Some(mi)
}
fn decode_cmp_reg(&self, _insn: u32, rn: u8, rm: u8) -> Option<MachineInstr> {
let rn_phys = self.reg_field_to_phys(rn, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let mut mi = MachineInstr::new(OP_CMP);
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
Some(mi)
}
fn decode_logical_reg(&self, insn: u32) -> Option<MachineInstr> {
let opc = (insn >> 29) & 0x3;
let rm = ((insn >> 16) & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rd = (insn & 0x1F) as u8;
let opcode = match opc {
0b00 => OP_AND,
0b01 => OP_ORR,
0b10 => OP_EOR,
_ => return None,
};
if rn == 31 && opc == 0b01 {
return self.decode_mov_reg(insn, rd, rm);
}
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
Some(mi)
}
fn decode_mov_reg(&self, _insn: u32, rd: u8, rm: u8) -> Option<MachineInstr> {
let rd_phys = self.reg_field_to_phys(rd, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let mut mi = MachineInstr::new(OP_MOV);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
Some(mi)
}
pub fn decode_movz_movk(&self, insn: u32) -> Option<MachineInstr> {
let opc = (insn >> 29) & 0x3;
let hw = (insn >> 21) & 0x3;
let imm16 = (insn >> 5) & 0xFFFF;
let rd = (insn & 0x1F) as u8;
let opcode = match opc {
0b10 => OP_MOVZ,
0b11 => OP_MOVK,
0b00 => OP_MOVN,
_ => return None,
};
let shift = (hw * 16) as i64;
let rd_phys = self.reg_field_to_phys(rd, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::Imm(imm16 as i64));
mi.operands.push(MachineOperand::Imm(shift));
Some(mi)
}
pub fn decode_ldr_str_imm(&self, insn: u32) -> Option<MachineInstr> {
let size = (insn >> 30) & 0x3;
let is_load = ((insn >> 22) & 1) == 1;
let imm9 = (insn >> 12) & 0x1FF;
let rn = ((insn >> 5) & 0x1F) as u8;
let rt = (insn & 0x1F) as u8;
let opcode = if is_load { OP_LDR } else { OP_STR };
let scale = 1 << size; let imm_val = (imm9 * scale) as i64;
let rt_phys = self.reg_field_to_phys(rt, size == 3); let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rt_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::Imm(imm_val));
Some(mi)
}
pub fn decode_ldp_stp(&self, insn: u32) -> Option<MachineInstr> {
let opc = (insn >> 30) & 0x3;
let is_store = opc == 0b11;
let imm7 = ((insn >> 15) & 0x7F) as i32;
let rt2 = ((insn >> 10) & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rt = (insn & 0x1F) as u8;
let opcode = if is_store { OP_STP } else { OP_LDP };
let imm_val = (imm7 as i64) * 8;
let rt_phys = self.reg_field_to_phys(rt, true);
let rt2_phys = self.reg_field_to_phys(rt2, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rt_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rt2_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::Imm(imm_val));
Some(mi)
}
pub fn decode_b_bl(&self, insn: u32) -> Option<MachineInstr> {
let op = (insn >> 31) & 1;
let imm26 = insn & 0x3FFFFFF;
let opcode = if op == 1 { OP_BL } else { OP_B };
let offset = if (imm26 & 0x2000000) != 0 {
(imm26 | 0xFC000000) as i32
} else {
imm26 as i32
};
let byte_offset = (offset as i64) * 4;
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::Imm(byte_offset));
Some(mi)
}
fn decode_b_cond(&self, insn: u32) -> Option<MachineInstr> {
let imm19_raw = (insn >> 5) & 0x7FFFF;
let cond = (insn & 0xF) as u8;
let offset = if (imm19_raw & 0x40000) != 0 {
(imm19_raw | 0xFFF80000) as i32
} else {
imm19_raw as i32
};
let byte_offset = (offset as i64) * 4;
let mut mi = MachineInstr::new(OP_B_COND);
mi.operands.push(MachineOperand::Imm(cond as i64));
mi.operands.push(MachineOperand::Imm(byte_offset));
Some(mi)
}
pub fn decode_cbz_cbnz(&self, insn: u32) -> Option<MachineInstr> {
let is_cbz = ((insn >> 24) & 1) == 0;
let imm19_raw = (insn >> 5) & 0x7FFFF;
let rt = (insn & 0x1F) as u8;
let opcode = if is_cbz { OP_CBZ } else { OP_CBNZ };
let offset = if (imm19_raw & 0x40000) != 0 {
(imm19_raw | 0xFFF80000) as i32
} else {
imm19_raw as i32
};
let byte_offset = (offset as i64) * 4;
let rt_phys = self.reg_field_to_phys(rt, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rt_phys as u32));
mi.operands.push(MachineOperand::Imm(byte_offset));
Some(mi)
}
pub fn decode_ret(&self, insn: u32) -> Option<MachineInstr> {
let rn = ((insn >> 5) & 0x1F) as u8;
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(OP_RET);
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
Some(mi)
}
fn decode_br_blr(&self, insn: u32) -> Option<MachineInstr> {
let is_call = ((insn >> 21) & 1) == 1; let rn = ((insn >> 5) & 0x1F) as u8;
let opcode = if is_call { OP_BLR } else { OP_BR };
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
Some(mi)
}
pub fn decode_nop_hint(&self, insn: u32) -> Option<MachineInstr> {
if insn == 0xD503201F {
Some(MachineInstr::new(OP_NOP))
} else {
Some(MachineInstr::new(OP_NOP))
}
}
pub fn decode_sdiv_udiv(&self, insn: u32) -> Option<MachineInstr> {
let rm = ((insn >> 16) & 0x1F) as u8;
let opcode_field = (insn >> 10) & 0x3F;
let rn = ((insn >> 5) & 0x1F) as u8;
let rd = (insn & 0x1F) as u8;
let opcode = match opcode_field {
0b000010 => OP_UDIV,
0b000011 => OP_SDIV,
_ => return None,
};
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
Some(mi)
}
fn decode_madd_msub(&self, insn: u32) -> Option<MachineInstr> {
let rm = ((insn >> 16) & 0x1F) as u8;
let is_msub = ((insn >> 15) & 1) == 1;
let ra = ((insn >> 10) & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rd = (insn & 0x1F) as u8;
let opcode = if is_msub { OP_MSUB } else { OP_MADD };
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let ra_phys = self.reg_field_to_phys(ra, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
mi.operands.push(MachineOperand::PhysReg(ra_phys as u32));
Some(mi)
}
pub fn decode_csel(&self, insn: u32) -> Option<MachineInstr> {
let rm = ((insn >> 16) & 0x1F) as u8;
let cond = ((insn >> 12) & 0xF) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rd = (insn & 0x1F) as u8;
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let mut mi = MachineInstr::new(OP_CSEL);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
mi.operands.push(MachineOperand::Imm(cond as i64));
Some(mi)
}
fn decode_bfm(&self, insn: u32) -> Option<MachineInstr> {
let opc = (insn >> 29) & 0x3;
let immr = (insn >> 16) & 0x3F;
let imms = (insn >> 10) & 0x3F;
let rn = ((insn >> 5) & 0x1F) as u8;
let rd = (insn & 0x1F) as u8;
let opcode = match opc {
0b01 => OP_BFM,
0b00 => OP_SBFM,
0b10 => OP_UBFM,
_ => return None,
};
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::Imm(immr as i64));
mi.operands.push(MachineOperand::Imm(imms as i64));
Some(mi)
}
pub fn decode_arm32(&self, insn: u32) -> Option<MachineInstr> {
let cond = (insn >> 28) & 0xF;
if cond != 0xE && cond != 0x0 {
return None; }
let op_type = (insn >> 26) & 0x3;
if op_type == 0b00 {
return self.decode_arm32_data_proc(insn);
}
if op_type == 0b01 {
let l_bit = (insn >> 20) & 1;
if l_bit == 1 {
return self.decode_arm32_ldr(insn);
} else {
return self.decode_arm32_str(insn);
}
}
if op_type == 0b10 {
return self.decode_arm32_b_bl(insn);
}
None
}
fn decode_arm32_data_proc(&self, insn: u32) -> Option<MachineInstr> {
let opcode_field = (insn >> 21) & 0xF;
let s_bit = (insn >> 20) & 1;
let rn = ((insn >> 16) & 0xF) as u8;
let rd = ((insn >> 12) & 0xF) as u8;
let opcode = match (opcode_field, s_bit) {
(0b0100, 0) => OP_ARM_ADD,
(0b0010, 0) => OP_ARM_SUB,
(0b1101, 0) => OP_ARM_MOV,
(0b0000, 0) => OP_ARM_AND,
(0b1100, 0) => OP_ARM_ORR,
(0b0001, 0) => OP_ARM_EOR,
(0b1010, 1) => OP_ARM_CMP,
_ => return None,
};
let mut mi = MachineInstr::new(opcode);
let rd_phys = self.arm32_reg_field_to_phys(rd);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
if opcode != OP_ARM_MOV && opcode != OP_ARM_CMP {
let rn_phys = self.arm32_reg_field_to_phys(rn);
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
}
if opcode == OP_ARM_CMP {
let rm = (insn & 0xF) as u8;
let rm_phys = self.arm32_reg_field_to_phys(rm);
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
} else if opcode == OP_ARM_MOV {
let rm = (insn & 0xF) as u8;
let rm_phys = self.arm32_reg_field_to_phys(rm);
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
} else {
let rm = (insn & 0xF) as u8;
let rm_phys = self.arm32_reg_field_to_phys(rm);
mi.operands.push(MachineOperand::PhysReg(rm_phys as u32));
}
Some(mi)
}
fn decode_arm32_ldr(&self, insn: u32) -> Option<MachineInstr> {
let rn = ((insn >> 16) & 0xF) as u8;
let rd = ((insn >> 12) & 0xF) as u8;
let imm12 = insn & 0xFFF;
let rd_phys = self.arm32_reg_field_to_phys(rd);
let rn_phys = self.arm32_reg_field_to_phys(rn);
let mut mi = MachineInstr::new(OP_ARM_LDR);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::Imm(imm12 as i64));
Some(mi)
}
fn decode_arm32_str(&self, insn: u32) -> Option<MachineInstr> {
let rn = ((insn >> 16) & 0xF) as u8;
let rd = ((insn >> 12) & 0xF) as u8;
let imm12 = insn & 0xFFF;
let rd_phys = self.arm32_reg_field_to_phys(rd);
let rn_phys = self.arm32_reg_field_to_phys(rn);
let mut mi = MachineInstr::new(OP_ARM_STR);
mi.operands.push(MachineOperand::PhysReg(rd_phys as u32));
mi.operands.push(MachineOperand::PhysReg(rn_phys as u32));
mi.operands.push(MachineOperand::Imm(imm12 as i64));
Some(mi)
}
fn decode_arm32_b_bl(&self, insn: u32) -> Option<MachineInstr> {
let l_bit = (insn >> 24) & 1;
let imm24 = insn & 0xFFFFFF;
let opcode = if l_bit == 1 { OP_ARM_BL } else { OP_ARM_B };
let offset = if (imm24 & 0x800000) != 0 {
(imm24 | 0xFF000000) as i32
} else {
imm24 as i32
};
let byte_offset = (offset as i64) * 4;
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::Imm(byte_offset));
Some(mi)
}
fn decode_svc(&self, insn: u32) -> Option<MachineInstr> {
let imm16 = ((insn >> 5) & 0xFFFF) as i64;
let mut mi = MachineInstr::new(OP_SVC);
mi.operands.push(MachineOperand::Imm(imm16));
Some(mi)
}
fn decode_brk(&self, insn: u32) -> Option<MachineInstr> {
let imm16 = ((insn >> 5) & 0xFFFF) as i64;
let mut mi = MachineInstr::new(OP_BRK);
mi.operands.push(MachineOperand::Imm(imm16));
Some(mi)
}
fn decode_msr(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let op0 = ((insn >> 19) & 0x3) as u32;
let op1 = ((insn >> 16) & 0x7) as u32;
let crn = ((insn >> 12) & 0xF) as u32;
let crm = ((insn >> 8) & 0xF) as u32;
let op2 = ((insn >> 5) & 0x7) as u32;
let sr = ((op0 << 14) | (op1 << 11) | (crn << 7) | (crm << 3) | op2) as i64;
let rt_phys = self.reg_field_to_phys(rt, true);
let mut mi = MachineInstr::new(OP_MSR);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(sr));
Some(mi)
}
fn decode_mrs(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let op0 = ((insn >> 19) & 0x3) as u32;
let op1 = ((insn >> 16) & 0x7) as u32;
let crn = ((insn >> 12) & 0xF) as u32;
let crm = ((insn >> 8) & 0xF) as u32;
let op2 = ((insn >> 5) & 0x7) as u32;
let sr = ((op0 << 14) | (op1 << 11) | (crn << 7) | (crm << 3) | op2) as i64;
let rt_phys = self.reg_field_to_phys(rt, true);
let mut mi = MachineInstr::new(OP_MRS);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(sr));
Some(mi)
}
fn decode_sys(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let op1 = ((insn >> 16) & 0x7) as u32;
let crn = ((insn >> 12) & 0xF) as u32;
let crm = ((insn >> 8) & 0xF) as u32;
let op2 = ((insn >> 5) & 0x7) as u32;
let sr = ((op1 << 14) | (crn << 10) | (crm << 6) | (op2 << 3)) as i64;
let rt_phys = self.reg_field_to_phys(rt, true);
let mut mi = MachineInstr::new(OP_SYS);
mi.operands.push(MachineOperand::Imm(sr));
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
Some(mi)
}
fn decode_adr_adrp(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let immlo = (insn >> 29) & 0x3;
let immhi = (insn >> 5) & 0x7FFFF;
let imm21 = ((immhi << 2) | immlo) as i64;
let sf = (insn >> 31) & 1;
let op = if sf == 1 { OP_ADRP } else { OP_ADR };
let rd_phys = self.reg_field_to_phys(rd, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(imm21));
Some(mi)
}
fn decode_tbz_tbnz(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let b5 = (insn >> 19) & 0x1F;
let b40 = (insn >> 31) & 1;
let bit = (b40 << 5) | b5;
let imm14 = ((insn >> 5) & 0x3FFF) as i64;
let op = if (insn >> 24) & 1 == 1 {
OP_TBNZ
} else {
OP_TBZ
};
let rt_phys = self.reg_field_to_phys(rt, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(bit as i64));
mi.operands.push(MachineOperand::Imm(imm14));
Some(mi)
}
fn decode_ldrb_strb(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let imm12 = ((insn >> 10) & 0xFFF) as i64;
let opc = (insn >> 22) & 0x3;
let op = if opc == 0 { OP_STRB } else { OP_LDRB };
let rt_phys = self.reg_field_to_phys(rt, false);
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(imm12));
Some(mi)
}
fn decode_ldrh_strh(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let imm12 = ((insn >> 10) & 0xFFF) as i64;
let opc = (insn >> 22) & 0x3;
let op = if opc == 0 { OP_STRH } else { OP_LDRH };
let rt_phys = self.reg_field_to_phys(rt, false);
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(imm12));
Some(mi)
}
fn decode_ldur_stur(&self, insn: u32) -> Option<MachineInstr> {
let rt = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let simm9 = ((insn as i32) >> 12) & 0x1FF;
let size = (insn >> 30) & 0x3;
let v = (insn >> 26) & 1;
let opc = (insn >> 22) & 0x3;
let op = if opc == 0 { OP_STUR } else { OP_LDUR };
let is_64bit = size >= 0b11;
let rt_phys = self.reg_field_to_phys(rt, is_64bit);
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(simm9 as i64));
Some(mi)
}
fn decode_barrier(&self, insn: u32) -> Option<MachineInstr> {
let crm = ((insn >> 8) & 0xF) as i64;
let opc = (insn >> 5) & 0x7;
let op = match opc {
0x3 => OP_DMB,
0x4 => OP_DSB,
0x6 => OP_ISB,
_ => return None,
};
let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::Imm(crm));
Some(mi)
}
fn decode_ccmp_ccmn(&self, insn: u32) -> Option<MachineInstr> {
let rn = (insn & 0x1F) as u8;
let imm5 = ((insn >> 16) & 0x1F) as i64;
let nzcv = (insn & 0xF) as i64;
let cond = ((insn >> 12) & 0xF) as i64;
let opc = (insn >> 30) & 1;
let op = if opc == 0 { OP_CCMN } else { OP_CCMP };
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(imm5));
mi.operands.push(MachineOperand::Imm(nzcv));
mi.operands.push(MachineOperand::Imm(cond));
Some(mi)
}
fn decode_one_source(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let opcode = (insn >> 10) & 0x3F;
let sf = (insn >> 31) & 1;
let is_64bit = sf == 1;
let op = match opcode {
0b000000 => OP_RBIT,
0b000001 => OP_REV16,
0b000010 => {
if is_64bit {
OP_REV32
} else {
OP_REV
}
}
0b000011 => OP_REV,
0b000100 => OP_CLZ,
0b000101 => OP_CLS,
_ => return None,
};
let rd_phys = self.reg_field_to_phys(rd, is_64bit);
let rn_phys = self.reg_field_to_phys(rn, is_64bit);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
Some(mi)
}
fn decode_ubfx_sbfx(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let immr = ((insn >> 16) & 0x3F) as i64;
let imms = ((insn >> 10) & 0x3F) as i64;
let opc = (insn >> 29) & 0x3;
let lsb = immr;
let width = imms - lsb + 1;
let op = if opc == 0 { OP_SBFX } else { OP_UBFX };
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(lsb));
mi.operands.push(MachineOperand::Imm(width));
Some(mi)
}
fn decode_extr(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let lsb = ((insn >> 10) & 0x3F) as i64;
let rd_phys = self.reg_field_to_phys(rd, true);
let rn_phys = self.reg_field_to_phys(rn, true);
let rm_phys = self.reg_field_to_phys(rm, true);
let mut mi = MachineInstr::new(OP_EXTR);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(lsb));
Some(mi)
}
fn get_simd_phys_reg(&self, field: u8, size: u32) -> u16 {
match size {
0 => 2300 + field as u16,
1 => 2320 + field as u16,
2 => 2340 + field as u16,
3 => 2360 + field as u16,
_ => 2360 + field as u16,
}
}
fn get_simd_q_reg(&self, field: u8) -> u16 {
2380 + field as u16
}
fn decode_fp_two_reg(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let sz = (insn >> 22) & 0x3;
let opcode = (insn >> 12) & 0x3F;
let op = match opcode {
0b010000 => OP_FNEG,
0b011000 => OP_FABS,
0b011100 => OP_FSQRT,
0b010100 => OP_FCVT,
0b001100 => OP_FRINTN,
0b001101 => OP_FRINTP,
0b001110 => OP_FRINTM,
0b001111 => OP_FRINTZ,
0b001000 => OP_FRINTA,
0b001001 => OP_FRINTX,
0b001010 => OP_FRINTI,
_ => return None,
};
let rd_phys = self.get_simd_phys_reg(rd, sz);
let rn_phys = self.get_simd_phys_reg(rn, sz);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
Some(mi)
}
fn decode_fp_three_reg(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let sz = (insn >> 22) & 0x3;
let opcode = (insn >> 10) & 0x3F;
let op = match opcode {
0b001010 => OP_FADD,
0b001110 => OP_FSUB,
0b000010 => OP_FMUL,
0b000110 => OP_FDIV,
0b001000 => OP_FCMP,
0b001001 => OP_FCMP, 0b010110 => OP_FMIN,
0b011010 => OP_FMAX,
_ => return None,
};
let rd_phys = self.get_simd_phys_reg(rd, sz);
let rn_phys = self.get_simd_phys_reg(rn, sz);
let rm_phys = self.get_simd_phys_reg(rm, sz);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
Some(mi)
}
fn decode_fmov(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let sz = (insn >> 22) & 0x3;
let rd_phys = self.get_simd_phys_reg(rd, sz);
let rn_phys = self.get_simd_phys_reg(rn, sz);
let mut mi = MachineInstr::new(OP_FMOV);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
Some(mi)
}
fn decode_fcsel(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let cond = ((insn >> 12) & 0xF) as i64;
let sz = (insn >> 22) & 0x3;
let rd_phys = self.get_simd_phys_reg(rd, sz);
let rn_phys = self.get_simd_phys_reg(rn, sz);
let rm_phys = self.get_simd_phys_reg(rm, sz);
let mut mi = MachineInstr::new(OP_FCSEL);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(cond));
Some(mi)
}
fn decode_fcvt_int_fp(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let sz = (insn >> 22) & 0x3;
let opcode = (insn >> 16) & 0x7;
let op = match opcode {
0b000 => OP_FCVTZS,
0b001 => OP_FCVTZU,
0b010 => OP_SCVTF,
0b011 => OP_UCVTF,
_ => return None,
};
let rd_phys = self.get_simd_phys_reg(rd, sz);
let rn_phys = self.get_simd_phys_reg(rn, sz);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
Some(mi)
}
fn get_vec_size(&self, insn: u32) -> (u32, u32) {
let q = (insn >> 30) & 1;
let size = (insn >> 22) & 0x3;
(q, size)
}
fn decode_simd_three_same(&self, insn: u32) -> Option<MachineInstr> {
let (q, size) = self.get_vec_size(insn);
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let u = (insn >> 29) & 1;
let opcode = (insn >> 10) & 0x3F;
let op = match (u, opcode) {
(0, 0b100001) => OP_ADD_V,
(1, 0b100001) => OP_SUB_V,
(0, 0b100111) => OP_MUL_V,
(0, 0b100101) => OP_MLA_V,
(1, 0b100101) => OP_MLS_V,
(0, 0b000111) => OP_AND_V,
(1, 0b000111) => OP_EOR_V,
_ => return None,
};
let rd_phys = if q == 1 {
self.get_simd_q_reg(rd)
} else {
self.get_simd_phys_reg(rd, size)
};
let rn_phys = if q == 1 {
self.get_simd_q_reg(rn)
} else {
self.get_simd_phys_reg(rn, size)
};
let rm_phys = if q == 1 {
self.get_simd_q_reg(rm)
} else {
self.get_simd_phys_reg(rm, size)
};
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
Some(mi)
}
fn decode_simd_cmp(&self, insn: u32) -> Option<MachineInstr> {
let (q, size) = self.get_vec_size(insn);
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let u = (insn >> 29) & 1;
let opcode = (insn >> 10) & 0x3F;
let op = match (u, opcode) {
(1, 0b100011) => OP_CMEQ,
(0, 0b001101) => OP_CMGT,
(0, 0b001111) => OP_CMGE,
(1, 0b001101) => OP_CMHI,
(1, 0b001111) => OP_CMHS,
(0, 0b100011) => OP_CMTST,
_ => return None,
};
let rd_phys = if q == 1 {
self.get_simd_q_reg(rd)
} else {
self.get_simd_phys_reg(rd, size)
};
let rn_phys = if q == 1 {
self.get_simd_q_reg(rn)
} else {
self.get_simd_phys_reg(rn, size)
};
let rm_phys = if q == 1 {
self.get_simd_q_reg(rm)
} else {
self.get_simd_phys_reg(rm, size)
};
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
Some(mi)
}
fn decode_simd_shift(&self, insn: u32) -> Option<MachineInstr> {
let (q, size) = self.get_vec_size(insn);
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let shift = ((insn >> 16) & 0x3F) as i64;
let u = (insn >> 29) & 1;
let op = if u == 0 { OP_SSHL } else { OP_USHL };
let rd_phys = if q == 1 {
self.get_simd_q_reg(rd)
} else {
self.get_simd_phys_reg(rd, size)
};
let rn_phys = if q == 1 {
self.get_simd_q_reg(rn)
} else {
self.get_simd_phys_reg(rn, size)
};
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(shift));
Some(mi)
}
fn decode_simd_across(&self, insn: u32) -> Option<MachineInstr> {
let (q, size) = self.get_vec_size(insn);
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let u = (insn >> 29) & 1;
let opcode = (insn >> 12) & 0x1F;
let op = match (u, opcode) {
(0, 0b11011) => OP_ADD_V, (0, 0b00111) if size != 3 => OP_SADDLV,
(1, 0b00111) if size != 3 => OP_UADDLV,
(0, 0b01101) => OP_SMAXV,
(1, 0b01101) => OP_UMAXV,
(0, 0b01111) => OP_SMINV,
(1, 0b01111) => OP_UMINV,
_ => return None,
};
let rd_phys = self.get_simd_phys_reg(rd, size);
let rn_phys = if q == 1 {
self.get_simd_q_reg(rn)
} else {
self.get_simd_phys_reg(rn, size)
};
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
Some(mi)
}
fn decode_simd_permute(&self, insn: u32) -> Option<MachineInstr> {
let (q, size) = self.get_vec_size(insn);
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let opcode = (insn >> 10) & 0x3F;
let op = match opcode {
0b001110 => OP_ZIP1,
0b001111 => OP_ZIP2,
0b000110 => OP_UZP1,
0b000111 => OP_UZP2,
0b001010 => OP_TRN1,
0b001011 => OP_TRN2,
_ => return None,
};
let rd_phys = if q == 1 {
self.get_simd_q_reg(rd)
} else {
self.get_simd_phys_reg(rd, size)
};
let rn_phys = if q == 1 {
self.get_simd_q_reg(rn)
} else {
self.get_simd_phys_reg(rn, size)
};
let rm_phys = if q == 1 {
self.get_simd_q_reg(rm)
} else {
self.get_simd_phys_reg(rm, size)
};
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
Some(mi)
}
fn decode_ext(&self, insn: u32) -> Option<MachineInstr> {
let q = (insn >> 30) & 1;
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let index = ((insn >> 11) & 0xF) as i64;
let rd_phys = if q == 1 {
self.get_simd_q_reg(rd)
} else {
self.get_simd_phys_reg(rd, 3)
};
let rn_phys = if q == 1 {
self.get_simd_q_reg(rn)
} else {
self.get_simd_phys_reg(rn, 3)
};
let rm_phys = if q == 1 {
self.get_simd_q_reg(rm)
} else {
self.get_simd_phys_reg(rm, 3)
};
let mut mi = MachineInstr::new(OP_EXT);
mi.operands
.push(MachineOperand::PhysReg(rd_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rm_phys as PhysReg));
mi.operands.push(MachineOperand::Imm(index));
Some(mi)
}
fn decode_simd_ldst_single(&self, insn: u32) -> Option<MachineInstr> {
let q = (insn >> 30) & 1;
let l = (insn >> 22) & 1;
let size = (insn >> 10) & 0x3;
let rt = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let opcode = (insn >> 13) & 0x7;
let num_regs = (insn >> 12) & 0xF;
let is_store = l == 0;
let op = match (is_store, num_regs) {
(false, 0b0111) => OP_LDR, (false, 0b1010) => OP_LD2,
(false, 0b0110) => OP_LD3,
(false, 0b0010) => OP_LD4,
(true, 0b0111) => OP_STR, (true, 0b1010) => OP_ST2,
(true, 0b0110) => OP_ST3,
(true, 0b0010) => OP_ST4,
_ => return None,
};
let rt_phys = if q == 1 {
self.get_simd_q_reg(rt)
} else {
self.get_simd_phys_reg(rt, size)
};
let rn_phys = self.reg_field_to_phys(rn, true);
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(rt_phys as PhysReg));
mi.operands
.push(MachineOperand::PhysReg(rn_phys as PhysReg));
Some(mi)
}
fn reg_field_to_phys(&self, field: u8, is_64bit: bool) -> u32 {
if field == 31 {
if is_64bit {
2032 } else {
2072 }
} else if is_64bit {
2000 + field as u32 } else {
2040 + field as u32 }
}
fn arm32_reg_field_to_phys(&self, field: u8) -> u16 {
if field <= 15 {
2100 + field as u16 } else {
2100 }
}
fn decode_sve_pred_logical(&self, insn: u32) -> Option<MachineInstr> {
let opc = (insn >> 22) & 0x3;
let pd = (insn & 0xF) as u8;
let pn = ((insn >> 5) & 0xF) as u8;
let pm = ((insn >> 16) & 0xF) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let op = match opc {
0 => OP_AND,
1 => OP_ORR,
2 => OP_EOR,
_ => return None,
};
let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2400 + pd as u32)); mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pn as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pm as u32));
Some(mi)
}
fn decode_sve_ptrue(&self, insn: u32) -> Option<MachineInstr> {
let pd = (insn & 0xF) as u8;
let pattern = ((insn >> 5) & 0x1F) as u8;
let mut mi = MachineInstr::new(OP_NOP); mi.operands.push(MachineOperand::PhysReg(2400 + pd as u32));
mi.operands.push(MachineOperand::Imm(pattern as i64));
Some(mi)
}
fn decode_sve_pfirst_pnext(&self, insn: u32) -> Option<MachineInstr> {
let pd = (insn & 0xF) as u8;
let pn = ((insn >> 5) & 0xF) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let is_next = (insn >> 13) & 1;
let op = if is_next != 0 { OP_MUL_V } else { OP_ADD_V }; let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2400 + pd as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pn as u32));
Some(mi)
}
fn decode_sve_add_sub_z(&self, insn: u32) -> Option<MachineInstr> {
let zd = (insn & 0x1F) as u8;
let zn = ((insn >> 5) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let is_sub = (insn >> 13) & 1;
let op = if is_sub != 0 { OP_SUB } else { OP_ADD };
let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2200 + zd as u32)); mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zn as u32));
Some(mi)
}
fn decode_sve_mul_z(&self, insn: u32) -> Option<MachineInstr> {
let zd = (insn & 0x1F) as u8;
let zn = ((insn >> 5) & 0x1F) as u8;
let zm = ((insn >> 16) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let is_mla = (insn >> 11) & 1;
let is_mls = (insn >> 13) & 1;
let op = if is_mls != 0 {
OP_MLS_V
} else if is_mla != 0 {
OP_MLA_V
} else {
OP_MUL_V
};
let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2200 + zd as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zn as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zm as u32));
Some(mi)
}
fn decode_sve_fadd_z(&self, insn: u32) -> Option<MachineInstr> {
let zd = (insn & 0x1F) as u8;
let zn = ((insn >> 5) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let is_sub = (insn >> 13) & 1;
let op = if is_sub != 0 { OP_FSUB } else { OP_FADD };
let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2200 + zd as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zn as u32));
Some(mi)
}
fn decode_sve_fmul_z(&self, insn: u32) -> Option<MachineInstr> {
let zd = (insn & 0x1F) as u8;
let zn = ((insn >> 5) & 0x1F) as u8;
let zm = ((insn >> 16) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let is_div = (insn >> 11) & 1;
let op = if is_div != 0 { OP_FDIV } else { OP_FMUL };
let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2200 + zd as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zn as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zm as u32));
Some(mi)
}
fn decode_sve_ld1b_z(&self, insn: u32) -> Option<MachineInstr> {
let zt = (insn & 0x1F) as u8;
let xn = ((insn >> 5) & 0x1F) as u8;
let xm = ((insn >> 16) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let mut mi = MachineInstr::new(OP_LDR);
mi.operands.push(MachineOperand::PhysReg(2200 + zt as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xn, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xm, true)));
Some(mi)
}
fn decode_sve_st1b_z(&self, insn: u32) -> Option<MachineInstr> {
let zt = (insn & 0x1F) as u8;
let xn = ((insn >> 5) & 0x1F) as u8;
let xm = ((insn >> 16) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let mut mi = MachineInstr::new(OP_STR);
mi.operands.push(MachineOperand::PhysReg(2200 + zt as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xn, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xm, true)));
Some(mi)
}
fn decode_sve_ld1w_gather(&self, insn: u32) -> Option<MachineInstr> {
let zt = (insn & 0x1F) as u8;
let zn = ((insn >> 5) & 0x1F) as u8;
let zm = ((insn >> 16) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let mut mi = MachineInstr::new(OP_LDR);
mi.operands.push(MachineOperand::PhysReg(2200 + zt as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zn as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zm as u32));
Some(mi)
}
fn decode_sve_st1w_scatter(&self, insn: u32) -> Option<MachineInstr> {
let zt = (insn & 0x1F) as u8;
let zn = ((insn >> 5) & 0x1F) as u8;
let zm = ((insn >> 16) & 0x1F) as u8;
let pg = ((insn >> 10) & 0xF) as u8;
let mut mi = MachineInstr::new(OP_STR);
mi.operands.push(MachineOperand::PhysReg(2200 + zt as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pg as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zn as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zm as u32));
Some(mi)
}
fn decode_sme_addha(&self, insn: u32) -> Option<MachineInstr> {
let zdn = (insn & 0x1F) as u8;
let pm = ((insn >> 5) & 0xF) as u8;
let pn = ((insn >> 10) & 0xF) as u8;
let zm = ((insn >> 16) & 0x1F) as u8;
let mut mi = MachineInstr::new(OP_MADD);
mi.operands.push(MachineOperand::PhysReg(2200 + zdn as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pm as u32));
mi.operands.push(MachineOperand::PhysReg(2400 + pn as u32));
mi.operands.push(MachineOperand::PhysReg(2200 + zm as u32));
Some(mi)
}
fn decode_sme_ldr_str_za(&self, insn: u32) -> Option<MachineInstr> {
let is_store = (insn >> 23) & 1;
let rn = ((insn >> 5) & 0x1F) as u8;
let op = if is_store != 0 { OP_STR } else { OP_LDR };
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rn, true)));
Some(mi)
}
fn decode_sme_mova_za_z(&self, insn: u32) -> Option<MachineInstr> {
let z = (insn & 0x1F) as u8;
let slice = ((insn >> 5) & 0x7) as u8;
let to_za = (insn >> 22) & 1;
let op = if to_za != 0 { OP_STR } else { OP_LDR }; let mut mi = MachineInstr::new(op);
mi.operands.push(MachineOperand::PhysReg(2200 + z as u32));
mi.operands.push(MachineOperand::Imm(slice as i64));
Some(mi)
}
fn decode_mte_stg_ldg(&self, insn: u32) -> Option<MachineInstr> {
let xt = ((insn >> 10) & 0x1F) as u8;
let xn = (insn & 0x1F) as u8;
let opc = (insn >> 22) & 0x3;
let op = match opc {
0b11 => OP_LDR, 0b01 => OP_STR, 0b10 => OP_STP, _ => OP_STR,
};
let mut mi = MachineInstr::new(op);
let xt_phys = self.reg_field_to_phys(xt, true);
let xn_phys = self.reg_field_to_phys(xn, true);
mi.operands.push(MachineOperand::PhysReg(xt_phys));
mi.operands.push(MachineOperand::PhysReg(xn_phys));
let s9_4 = ((insn >> 16) & 0x3F) as i64;
let s3_0 = ((insn >> 8) & 0x7) as i64 | (((insn >> 14) & 1) << 3) as i64;
let simm = ((s9_4 << 4) | s3_0) as i64;
mi.operands.push(MachineOperand::Imm(simm));
Some(mi)
}
fn decode_mte_irg(&self, insn: u32) -> Option<MachineInstr> {
let xd = (insn & 0x1F) as u8;
let xn = ((insn >> 5) & 0x1F) as u8;
let xm = ((insn >> 16) & 0x1F) as u8;
let mut mi = MachineInstr::new(OP_ORR); mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xd, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xn, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xm, true)));
Some(mi)
}
fn decode_mte_addg_subg(&self, insn: u32) -> Option<MachineInstr> {
let xd = (insn & 0x1F) as u8;
let xn = ((insn >> 5) & 0x1F) as u8;
let uimm6 = ((insn >> 16) & 0x3F) as i64;
let uimm4 = ((insn >> 10) & 0xF) as i64;
let is_sub = (insn >> 22) & 1;
let op = if is_sub != 0 { OP_SUB } else { OP_ADD };
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xd, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xn, true)));
mi.operands.push(MachineOperand::Imm((uimm6 << 4) | uimm4));
Some(mi)
}
fn decode_mte_gmi(&self, insn: u32) -> Option<MachineInstr> {
let xd = (insn & 0x1F) as u8;
let xn = ((insn >> 5) & 0x1F) as u8;
let xm = ((insn >> 16) & 0x1F) as u8;
let mut mi = MachineInstr::new(OP_BFM);
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xd, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xn, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(xm, true)));
Some(mi)
}
fn decode_pac(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let key_b = (insn >> 10) & 1;
let data_key = (insn >> 12) & 1;
let op = if data_key != 0 { OP_AND } else { OP_ORR };
let mut mi = MachineInstr::new(op);
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rd, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rn, true)));
mi.operands.push(MachineOperand::Imm(
(key_b as i64) | ((data_key as i64) << 1),
));
Some(mi)
}
fn decode_aut(&self, insn: u32) -> Option<MachineInstr> {
let mut mi = self.decode_pac(insn)?;
mi.opcode = OP_EOR; Some(mi)
}
fn decode_pacga(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let rm = ((insn >> 16) & 0x1F) as u8;
let mut mi = MachineInstr::new(OP_EOR);
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rd, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rn, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rm, true)));
Some(mi)
}
fn decode_xpac(&self, insn: u32) -> Option<MachineInstr> {
let rd = (insn & 0x1F) as u8;
let rn = ((insn >> 5) & 0x1F) as u8;
let mut mi = MachineInstr::new(OP_MOV);
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rd, true)));
mi.operands
.push(MachineOperand::PhysReg(self.reg_field_to_phys(rn, true)));
Some(mi)
}
fn decode_sme2_multi_vector(&self, insn: u32) -> Option<MachineInstr> {
let op2 = (insn >> 22) & 0x3;
let op3 = (insn >> 20) & 0x3;
let zm = (insn >> 16) & 0x1F;
let zn = (insn >> 5) & 0x1F;
let zd = insn & 0x1F;
let bit23 = (insn >> 23) & 1;
match (op2, bit23, op3) {
(0b01, 0, _) => {
let mut mi = MachineInstr::new(OP_ADD);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
mi.operands.push(MachineOperand::PhysReg(zm));
Some(mi)
}
(0b01, 1, _) => {
let mut mi = MachineInstr::new(OP_SUB);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
mi.operands.push(MachineOperand::PhysReg(zm));
Some(mi)
}
(0b10, 0, _) => {
let mut mi = MachineInstr::new(OP_MADD);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
mi.operands.push(MachineOperand::PhysReg(zm));
Some(mi)
}
(0b11, _, _) => {
let mut mi = MachineInstr::new(OP_MOV);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::Imm(0));
Some(mi)
}
(0b01, _, _) if ((insn >> 15) & 1) == 1 => {
let mut mi = MachineInstr::new(OP_MOV);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
Some(mi)
}
_ => None,
}
}
fn decode_sme2_outer_product(&self, insn: u32) -> Option<MachineInstr> {
let op2 = (insn >> 22) & 0x3;
let zm = (insn >> 16) & 0x1F;
let pm = (insn >> 19) & 0xF;
let zn = (insn >> 5) & 0x1F;
let zd = insn & 0x1F;
let opcode = match op2 {
0b00 => OP_MADD, 0b01 => OP_ADD, 0b10 => OP_SUB, 0b11 => OP_FMUL, _ => return None,
};
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
mi.operands.push(MachineOperand::PhysReg(zm));
Some(mi)
}
fn decode_sme2_mv_ldst(&self, insn: u32) -> Option<MachineInstr> {
let is_load = ((insn >> 22) & 1) == 0;
let zt = insn & 0x1F;
let xn = (insn >> 5) & 0x1F;
let imm_field = (insn >> 17) & 0x7;
let opcode = if is_load { OP_LDR } else { OP_STR };
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(zt));
mi.operands.push(MachineOperand::PhysReg(xn));
mi.operands
.push(MachineOperand::Imm((imm_field as i64) << 3));
Some(mi)
}
fn decode_sme2_psel(&self, insn: u32) -> Option<MachineInstr> {
let pd = ((insn >> 5) & 0xF) as u8;
let pn = ((insn >> 19) & 0xF) as u8;
let pm = ((insn >> 14) & 0xF) as u8;
let mut mi = MachineInstr::new(OP_MOV);
mi.operands.push(MachineOperand::PhysReg(pd as u32));
mi.operands.push(MachineOperand::PhysReg(pn as u32));
mi.operands.push(MachineOperand::PhysReg(pm as u32));
Some(mi)
}
fn decode_sme2_revd(&self, insn: u32) -> Option<MachineInstr> {
let zd = insn & 0x1F;
let zm = (insn >> 5) & 0x1F;
let pn = (insn >> 19) & 0xF;
let mut mi = MachineInstr::new(OP_REV);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zm));
Some(mi)
}
fn decode_sme2_sclamp(&self, insn: u32) -> Option<MachineInstr> {
let zd = insn & 0x1F;
let zn = (insn >> 16) & 0x1F;
let zm = (insn >> 5) & 0x1F;
let mut mi = MachineInstr::new(OP_ADD);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
mi.operands.push(MachineOperand::PhysReg(zm));
Some(mi)
}
fn decode_sme2_fp8_convert(&self, insn: u32) -> Option<MachineInstr> {
let is_bf16 = ((insn >> 15) & 1) == 0;
let is_down = ((insn >> 14) & 1) == 1;
let zd = insn & 0x1F;
let zn = (insn >> 5) & 0x1F;
let opcode = if is_bf16 { OP_FMOV } else { OP_FCVT };
let mut mi = MachineInstr::new(opcode);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
if is_down {
mi.operands.push(MachineOperand::Imm(1));
}
Some(mi)
}
fn decode_sme2_f2cvt(&self, insn: u32) -> Option<MachineInstr> {
let zd = insn & 0x1F;
let zn = (insn >> 5) & 0x1F;
let mut mi = MachineInstr::new(OP_FCVT);
mi.operands.push(MachineOperand::PhysReg(zd));
mi.operands.push(MachineOperand::PhysReg(zn));
Some(mi)
}
}
#[cfg(test)]
mod tests {
use super::super::arm_mc_encoder::ArmMCEncoder;
use super::*;
fn roundtrip_aarch64(_opcode: u32, enc_word: u32) -> Option<MachineInstr> {
let dec = ArmMCDecoder::new(true);
dec.decode_aarch64(enc_word)
}
fn encode_to_word(enc: &ArmMCEncoder, mi: &MachineInstr) -> u32 {
let bytes = enc.encode_instruction(mi);
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
}
#[test]
fn test_decode_nop() {
let dec = ArmMCDecoder::new(true);
let mi = dec.decode_aarch64(0xD503201F);
assert!(mi.is_some());
assert_eq!(mi.unwrap().opcode, OP_NOP);
}
#[test]
fn test_nop_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mi = MachineInstr::new(OP_NOP);
let word = encode_to_word(&enc, &mi);
assert_eq!(word, 0xD503201F);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_NOP);
}
#[test]
fn test_decode_add_imm() {
let dec = ArmMCDecoder::new(true);
let mi = dec.decode_aarch64(0x9100A820);
assert!(mi.is_some());
let mi = mi.unwrap();
assert_eq!(mi.opcode, OP_ADD);
assert_eq!(mi.operands.len(), 3);
if let MachineOperand::PhysReg(r) = mi.operands[0] {
assert_eq!(r, 2000);
}
if let MachineOperand::Imm(v) = mi.operands[2] {
assert_eq!(v, 42);
}
}
#[test]
fn test_add_imm_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_ADD);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::Imm(42));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_ADD);
}
#[test]
fn test_sub_imm_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_SUB);
mi.operands.push(MachineOperand::PhysReg(2005 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2003 as PhysReg)); mi.operands.push(MachineOperand::Imm(16));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_SUB);
if let MachineOperand::PhysReg(r) = decoded.operands[0] {
assert_eq!(r, 2005);
}
if let MachineOperand::Imm(v) = decoded.operands[2] {
assert_eq!(v, 16);
}
}
#[test]
fn test_add_reg_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_ADD);
mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2003 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2004 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_ADD);
}
#[test]
fn test_movz_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_MOVZ);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::Imm(42));
mi.operands.push(MachineOperand::Imm(0));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_MOVZ);
let has_imm42 = decoded
.operands
.iter()
.any(|op| matches!(op, MachineOperand::Imm(42)));
assert!(has_imm42);
}
#[test]
fn test_movk_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_MOVK);
mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::Imm(0xABCD));
mi.operands.push(MachineOperand::Imm(16)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_MOVK);
let has_imm = decoded
.operands
.iter()
.any(|op| matches!(op, MachineOperand::Imm(0xABCD)));
assert!(has_imm);
}
#[test]
fn test_ret_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_RET);
mi.operands.push(MachineOperand::PhysReg(2030 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_RET);
}
#[test]
fn test_cmp_imm_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_CMP);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::Imm(0));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_CMP);
}
#[test]
fn test_cmp_reg_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_CMP);
mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_CMP);
}
#[test]
fn test_ldr_imm_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_LDR);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::Imm(8));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_LDR);
}
#[test]
fn test_str_imm_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_STR);
mi.operands.push(MachineOperand::PhysReg(2005 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2031 as PhysReg)); mi.operands.push(MachineOperand::Imm(16));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_STR);
}
#[test]
fn test_ldp_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_LDP);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); mi.operands.push(MachineOperand::Imm(0));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_LDP);
}
#[test]
fn test_sdiv_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_SDIV);
mi.operands.push(MachineOperand::PhysReg(2003 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2004 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2005 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_SDIV);
}
#[test]
fn test_udiv_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_UDIV);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_UDIV);
}
#[test]
fn test_madd_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_MADD);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2003 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_MADD);
}
#[test]
fn test_msub_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_MSUB);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2003 as PhysReg));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_MSUB);
}
#[test]
fn test_adds_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_ADDS);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_ADDS);
}
#[test]
fn test_subs_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_SUBS);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_SUBS);
}
#[test]
fn test_csel_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_CSEL);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg)); mi.operands.push(MachineOperand::Imm(ArmCond::EQ as i64));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_CSEL);
let has_cond = decoded.operands.iter().any(|op| {
matches!(op, MachineOperand::Imm(0)) });
assert!(has_cond);
}
#[test]
fn test_cbz_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_CBZ);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::Imm(16)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_CBZ);
}
#[test]
fn test_bfm_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_BFM);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg)); mi.operands.push(MachineOperand::Imm(0));
mi.operands.push(MachineOperand::Imm(7));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
let decoded = decoded.unwrap();
assert_eq!(decoded.opcode, OP_BFM);
}
#[test]
fn test_arm32_mov_roundtrip() {
let enc = ArmMCEncoder::new(false);
let mut mi = MachineInstr::new(OP_ARM_MOV);
mi.operands.push(MachineOperand::PhysReg(2101 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2102 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(false);
let decoded = dec.decode_arm32(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_ARM_MOV);
}
#[test]
fn test_arm32_add_roundtrip() {
let enc = ArmMCEncoder::new(false);
let mut mi = MachineInstr::new(OP_ARM_ADD);
mi.operands.push(MachineOperand::PhysReg(2100 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2101 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2102 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(false);
let decoded = dec.decode_arm32(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_ARM_ADD);
}
#[test]
fn test_decode_instruction_bytes() {
let dec = ArmMCDecoder::new(true);
let bytes = vec![0x1F, 0x20, 0x03, 0xD5];
let result = dec.decode_instruction(&bytes, 0);
assert!(result.is_some());
let (mi, consumed) = result.unwrap();
assert_eq!(consumed, 4);
assert_eq!(mi.opcode, OP_NOP);
}
#[test]
fn test_decode_instruction_out_of_bounds() {
let dec = ArmMCDecoder::new(true);
let bytes = vec![0x1F, 0x20]; let result = dec.decode_instruction(&bytes, 0);
assert!(result.is_none());
}
#[test]
fn test_decode_instruction_with_offset() {
let dec = ArmMCDecoder::new(true);
let bytes = vec![
0x00, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x03, 0xD5, ];
let result = dec.decode_instruction(&bytes, 4);
assert!(result.is_some());
let (mi, _) = result.unwrap();
assert_eq!(mi.opcode, OP_NOP);
}
#[test]
fn test_and_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_AND);
mi.operands.push(MachineOperand::PhysReg(2000 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2001 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2002 as PhysReg));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_AND);
}
#[test]
fn test_eor_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_EOR);
mi.operands.push(MachineOperand::PhysReg(2005 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2006 as PhysReg));
mi.operands.push(MachineOperand::PhysReg(2007 as PhysReg));
let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_EOR);
}
#[test]
fn test_mov_reg_roundtrip() {
let enc = ArmMCEncoder::new(true);
let mut mi = MachineInstr::new(OP_MOV);
mi.operands.push(MachineOperand::PhysReg(2003 as PhysReg)); mi.operands.push(MachineOperand::PhysReg(2004 as PhysReg)); let word = encode_to_word(&enc, &mi);
let dec = ArmMCDecoder::new(true);
let decoded = dec.decode_aarch64(word);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().opcode, OP_MOV);
}
#[test]
fn test_decode_unknown_instruction() {
let dec = ArmMCDecoder::new(true);
let result = dec.decode_aarch64(0x00000000);
assert!(result.is_none());
}
}