use std::collections::HashMap;
use super::arm_register_info::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArmOpcode {
ADD,
SUB,
MUL,
SDIV,
UDIV,
AND,
ORR,
EOR,
ORN,
BIC,
LSL,
LSR,
ASR,
ROR,
ADDS,
SUBS,
MADD,
MSUB,
SMULL,
UMULL,
SMADDL,
UMADDL,
SMSUBL,
UMSUBL,
MOV,
MOVZ,
MOVK,
MOVN,
MOVI,
ADR,
ADRP,
LDR,
STR,
LDP,
STP,
LDRB,
STRB,
LDRH,
STRH,
LDRSB,
LDRSH,
LDRSW,
LDUR,
STUR,
LDURB,
STURB,
LDURH,
STURH,
LDURSW,
LDR_LIT,
LDNP,
STNP,
LDTR,
STTR,
PRFM,
B,
BL,
BR,
BLR,
RET,
CBZ,
CBNZ,
TBZ,
TBNZ,
B_COND,
CMP,
CMN,
TST,
CSEL,
CSINC,
CSINV,
CSNEG,
CSET,
CSETM,
CCMP,
CCMN,
SBFM,
UBFM,
SBFX,
UBFX,
BFM,
BFI,
BFXIL,
SXTB,
SXTH,
SXTW,
UXTB,
UXTH,
UXTW,
EXTR,
CLZ,
CLS,
RBIT,
REV,
REV16,
REV32,
SVC,
HVC,
SMC,
BRK,
NOP,
HINT,
ISB,
DSB,
DMB,
MSR,
MRS,
SYS,
SYSL,
ADD_V,
SUB_V,
MUL_V,
MLA_V,
MLS_V,
FADD,
FSUB,
FMUL,
FDIV,
FABS,
FNEG,
FSQRT,
FCSEL,
FCMP,
FCCMP,
FCVT,
SCVTF,
UCVTF,
FCVTZS,
FCVTZU,
FCVTMU,
FCVTMS,
FCVTPS,
FCVTPU,
FCVTAS,
FCVTAU,
FMOV,
FRINTI,
FRINTZ,
FRINTP,
FRINTM,
FRINTX,
FRINTA,
FRINTN,
DUP,
INS,
SMOV,
UMOV,
EXT,
ZIP1,
ZIP2,
UZP1,
UZP2,
TRN1,
TRN2,
SHL_V,
SSHR,
USHR,
SRSHL,
URSHL,
SSRA,
USRA,
SRSRA,
URSRA,
SHADD,
UHADD,
SRHADD,
URHADD,
SHSUB,
UHSUB,
AND_V,
ORR_V,
EOR_V,
BIC_V,
ORN_V,
BSL,
BIT,
BIF,
CMEQ,
CMGE,
CMGT,
CMHI,
CMHS,
CMLE,
CMLT,
CMTST,
FCMEQ,
FCMGE,
FCMGT,
FACGE,
FACGT,
FMAX,
FMIN,
FMAXNM,
FMINNM,
FMAXP,
FMINP,
FMAXNMP,
FMINNMP,
ADDP,
SADDLP,
UADDLP,
SADDLV,
UADDLV,
FADDP,
SMAXV,
UMAXV,
SMINV,
UMINV,
FMAXV,
FMINV,
FMAXNMV,
FMINNMV,
SADDW,
UADDW,
SSUBW,
USUBW,
SMULL_V,
UMULL_V,
SQDMLAL,
SQDMLSL,
SQDMLAL_V,
SQDMLSL_V,
SQDMLAL2,
SQDMLSL2,
SQDMULL,
SQDMULL_V,
SQDMULL2,
SQRDMULH,
SQRDMLAH,
PMULL,
TBL,
TBX,
TBL_LIST,
TBX_LIST,
REV64,
REV32_V,
REV16_V,
SADDL,
UADDL,
SSUBL,
USUBL,
SABAL,
UABAL,
SABDL,
UABDL,
SABD,
UABD,
SABA,
UABA,
CNT,
NOT_V,
RBIT_V,
CLZ_V,
CLS_V,
ABS_V,
NEG_V,
SMAX,
UMAX,
SMIN,
UMIN,
SMAXP,
UMAXP,
SMINP,
UMINP,
SSHL,
USHL,
SRSHR,
URSHR,
SQADD,
UQADD,
SQSUB,
UQSUB,
SQSHL,
UQSHL,
SQSHRN,
UQSHRN,
SQRSHRN,
UQRSHRN,
SQSHLU,
SQSHRUN,
SQRSHRUN,
SHRN,
RSHRN,
SXTL,
UXTL,
SQXTN,
UQXTN,
SQXTUN,
XTN,
SHLL,
SSUBL_V,
USUBL_V,
SADDL_V,
UADDL_V,
SCVTF_V,
UCVTF_V,
FCVTZS_V,
FCVTZU_V,
FMLA,
FMLS,
FMULX,
FRECPS,
FRSQRTS,
URSQRTE,
URECPE,
FRECPE,
FRSQRTE,
ARM_ADD,
ARM_SUB,
ARM_MUL,
ARM_AND,
ARM_ORR,
ARM_EOR,
ARM_MOV,
ARM_MOVW,
ARM_MOVT,
ARM_MVN,
ARM_CMP,
ARM_CMN,
ARM_TST,
ARM_TEQ,
ARM_B,
ARM_BL,
ARM_BX,
ARM_BLX,
ARM_BLX_REG,
ARM_LDR,
ARM_STR,
ARM_LDM,
ARM_STM,
ARM_LDMIA,
ARM_STMIA,
ARM_LDMIB,
ARM_STMIB,
ARM_LDMDA,
ARM_STMDA,
ARM_LDMDB,
ARM_STMDB,
ARM_PUSH,
ARM_POP,
ARM_RSB,
ARM_RSC,
ARM_SBC,
ARM_ADC,
ARM_UXTB,
ARM_UXTH,
ARM_SXTB,
ARM_SXTH,
ARM_CLZ,
ARM_RBIT,
ARM_REV,
ARM_REV16,
ARM_REVSH,
ARM_BFC,
ARM_BFI,
ARM_SBFX,
ARM_UBFX,
ARM_PLD,
ARM_PLI,
ARM_SWP,
ARM_SWPB,
ARM_LDREX,
ARM_STREX,
ARM_STREXB,
ARM_STREXH,
ARM_STREXD,
ARM_LDREXB,
ARM_LDREXH,
ARM_LDREXD,
ARM_DMB,
ARM_DSB,
ARM_ISB,
ARM_SVC,
ARM_SMC,
ARM_HVC,
ARM_BKPT,
ARM_NOP,
ARM_MRS,
ARM_MSR,
ARM_VMOV,
ARM_VMOV_S_R,
ARM_VMOV_R_S,
ARM_VMOV_2S,
ARM_VADD,
ARM_VSUB,
ARM_VMUL,
ARM_VDIV,
ARM_VMLA,
ARM_VMLS,
ARM_VFMA,
ARM_VFMS,
ARM_VNEG,
ARM_VABS,
ARM_VSQRT,
ARM_VCMP,
ARM_VCVT,
ARM_VCVTR,
ARM_VCVT_F32_F64,
ARM_VCVT_F64_F32,
ARM_VMOVL,
ARM_VMOVN,
ARM_VMOV_IMM,
ARM_VMOV_I8,
ARM_VMOV_I16,
ARM_VMOV_I32,
ARM_VMOV_I64,
ARM_VLD1,
ARM_VLD2,
ARM_VLD3,
ARM_VLD4,
ARM_VST1,
ARM_VST2,
ARM_VST3,
ARM_VST4,
ARM_VLDR,
ARM_VSTR,
ARM_VPUSH,
ARM_VPOP,
THUMB_ADD,
THUMB_SUB,
THUMB_MOV,
THUMB_CMP,
THUMB_B,
THUMB_BL,
THUMB_BX,
THUMB_LDR,
THUMB_STR,
THUMB_PUSH,
THUMB_POP,
THUMB_CBZ,
THUMB_CBNZ,
THUMB_ADD_SP,
THUMB_SUB_SP,
THUMB_ASR,
THUMB_LSL,
THUMB_LSR,
THUMB_MUL,
THUMB_MVN,
THUMB_NEG,
THUMB_ORR,
THUMB_AND,
THUMB_EOR,
THUMB_BIC,
THUMB_SXTB,
THUMB_SXTH,
THUMB_UXTB,
THUMB_UXTH,
THUMB_REV,
THUMB_REV16,
THUMB_REVSH,
THUMB_TST,
THUMB_ADC,
THUMB_SBC,
THUMB_RSB,
LD1_ONE,
LD1_TWO,
LD1_THREE,
LD1_FOUR,
LD2,
LD3,
LD4,
LD1R,
LD2R,
LD3R,
LD4R,
ST1_ONE,
ST1_TWO,
ST1_THREE,
ST1_FOUR,
ST2,
ST3,
ST4,
PTRUE,
PTRUES,
PFALSE,
AND_P,
BIC_P,
EOR_P,
ORR_P,
ORN_P,
MOV_P,
NOT_P,
CNTP,
BRKA,
BRKB,
BRKN,
ADD_Z,
SUB_Z,
MUL_Z,
AND_Z,
ORR_Z,
EOR_Z,
BIC_Z,
ASR_Z,
LSL_Z,
LSR_Z,
SMAX_Z,
SMIN_Z,
UMAX_Z,
UMIN_Z,
ABS_Z,
NEG_Z,
INDEX_Z,
FADD_Z,
FSUB_Z,
FMUL_Z,
FDIV_Z,
FMAX_Z,
FMIN_Z,
FMAXNM_Z,
FMINNM_Z,
FABS_Z,
FNEG_Z,
FRINTA_Z,
FRINTI_Z,
FRINTM_Z,
FRINTN_Z,
FRINTP_Z,
FRINTX_Z,
FRINTZ_Z,
FRECPE_Z,
FRSQRTE_Z,
FSQRT_Z,
FMLA_Z,
FMLS_Z,
FMAD_Z,
FMSB_Z,
FNMAD_Z,
FNMSB_Z,
FCVT_Z,
FCVTZS_Z,
FCVTZU_Z,
SCVTF_Z,
UCVTF_Z,
CMPEQ_P,
CMPNE_P,
CMPGT_P,
CMPGE_P,
CMPLT_P,
CMPLE_P,
CMPHI_P,
CMPHS_P,
CMPLO_P,
CMPLS_P,
FCMEQ_P,
FCMNE_P,
FCMLT_P_F,
FCMLE_P,
FACGE_P,
FACGT_P,
LD1B_Z,
LD1H_Z,
LD1W_Z,
LD1D_Z,
ST1B_Z,
ST1H_Z,
ST1W_Z,
ST1D_Z,
LDNF1B_Z,
LDNF1H_Z,
LDNF1W_Z,
LDNF1D_Z,
LDR_Z,
STR_Z,
LD1B_GATHER_Z,
LD1H_GATHER_Z,
LD1W_GATHER_Z,
LD1D_GATHER_Z,
ST1B_SCATTER_Z,
ST1H_SCATTER_Z,
ST1W_SCATTER_Z,
ST1D_SCATTER_Z,
LD1B_GATHER_SXTW,
LD1H_GATHER_SXTW,
LD1W_GATHER_SXTW,
SMULLB_Z,
SMULLT_Z,
UMULLB_Z,
UMULLT_Z,
SMLALB_Z,
SMLALT_Z,
UMLALB_Z,
UMLALT_Z,
HISTCNT_Z,
HISTSEG_Z,
MATCH_TOP_Z,
MATCH_BOTTOM_Z,
AESE_Z,
AESD_Z,
AESMC_Z,
AESIMC_Z,
SM4E_Z,
SM4EKEY_Z,
RAX1_Z,
SHA1C_Z,
SHA1H_Z,
SHA1M_Z,
SHA1P_Z,
SHA1SU0_Z,
SHA1SU1_Z,
SHA256H2_Z,
SHA256H_Z,
SHA256SU0_Z,
SHA256SU1_Z,
SHA512H_Z,
SHA512H2_Z,
SHA512SU0_Z,
SHA512SU1_Z,
SM3PARTW1_Z,
SM3PARTW2_Z,
SM3SS1_Z,
SM3TT1A_Z,
SM3TT1B_Z,
SM3TT2A_Z,
SM3TT2B_Z,
SMSTART,
SMSTOP,
ADDA_ZA,
ADDS_ZA,
SUBS_ZA,
FMOPA_WIDE,
FMOPA_NARROW,
SMOPA_WIDE,
SMOPA_NARROW,
UMOPA_WIDE,
UMOPA_NARROW,
LDR_ZA,
STR_ZA,
MOV_ZA,
SMMLA,
USMMLA,
UMMLA,
BFMOPA,
BFMOPA_WIDE,
FMLA_ZA,
FMLS_ZA,
SME_LD1_HORIZ,
SME_ST1_HORIZ,
SME_LD1_VERT,
SME_ST1_VERT,
PACIA,
PACIB,
PACDA,
PACDB,
PACIZA,
PACIZB,
PACDZA,
PACDZB,
AUTIA,
AUTIB,
AUTDA,
AUTDB,
AUTIZA,
AUTIZB,
AUTDZA,
AUTDZB,
XPACI,
XPACD,
PACGA,
BTI,
BTI_C,
BTI_J,
BTI_JC,
BRA,
BRAB,
BRAAZ,
BRABZ,
BLRAA,
BLRAB,
BLRAAZ,
BLRABZ,
RETA,
RETAA,
RETAB,
ERETAA,
ERETAB,
IRG,
GMI,
ADDG,
SUBG,
LDG,
STG,
STZG,
ST2G,
STZ2G,
STGP,
BCAX,
EOR3,
RAX1_A64,
XAR,
CLREX_A64,
YIELD_A64,
WFE_A64,
WFI_A64,
SEV_A64,
SEVL_A64,
VTRN_8,
VTRN_16,
VTRN_32,
VZIP_8,
VZIP_16,
VZIP_32,
VUZP_8,
VUZP_16,
VUZP_32,
VEXT,
VREV64_8,
VREV64_16,
VREV64_32,
VREV32_8,
VREV32_16,
VREV16_8,
VTBL_2REG,
VTBL_3REG,
VTBL_4REG,
VTBX_2REG,
VTBX_3REG,
VTBX_4REG,
VSHL_IMM_8,
VSHL_IMM_16,
VSHL_IMM_32,
VSHL_IMM_64,
VQSHL_IMM_8,
VQSHL_IMM_16,
VQSHL_IMM_32,
VQSHL_IMM_64,
VQSHLU_IMM_8,
VQSHLU_IMM_16,
VQSHLU_IMM_32,
VQSHLU_IMM_64,
VRSHR_8,
VRSHR_16,
VRSHR_32,
VRSHR_64,
VRSRA_8,
VRSRA_16,
VRSRA_32,
VRSRA_64,
VSRI_8,
VSRI_16,
VSRI_32,
VSRI_64,
VSLI_8,
VSLI_16,
VSLI_32,
VSLI_64,
VRECPE_F32,
VRECPE_F64,
VRECPS_F32,
VRECPS_F64,
VRSQRTE_F32,
VRSQRTE_F64,
VRSQRTS_F32,
VRSQRTS_F64,
CMLA_SVE,
CADD_SVE,
SQCADD_SVE,
SQRDCMLA_SVE,
HISTCNT_SVE,
HISTSEG_SVE,
MATCH_SVE,
NMATCH_SVE,
BEXT_SVE,
BDEP_SVE,
BGRP_SVE,
FCVTNT_SVE,
FCVTLT_SVE,
FCVTX_SVE,
FCVTXNT_SVE,
RMI_GRAN_DELEGATE,
RMI_GRAN_UNDELEGATE,
RMI_DATA_CREATE,
RMI_DATA_CREATE_UNKNOWN,
RMI_DATA_DESTROY,
RMI_REC_CREATE,
RMI_REC_DESTROY,
RMI_REALM_CREATE,
RMI_REALM_DESTROY,
RMI_RTT_CREATE,
RMI_RTT_DESTROY,
RMI_RTT_INIT_RIPAS,
RMI_RTT_SET_RIPAS,
RMI_RTT_READ_ENTRY,
RMI_RTT_FOLD,
RMI_FEATURES,
RMI_VERSION,
BRB_IALL,
BRB_INJ,
GCSPUSHX,
GCSPOPX,
GCSSS1,
GCSSS2,
GCSSTR,
GCSSTTR,
THE_INVALIDATE_ALL,
THE_INVALIDATE_VA,
CHKFEAT,
LDIAPP_32,
LDIAPP_64,
STILP_32,
STILP_64,
F1CVT,
F2CVT,
BF1CVT,
LUTI2_8,
LUTI2_16,
LUTI2_32,
LUTI4_8,
LUTI4_16,
LUTI4_32,
FAMIN_32,
FAMIN_64,
FAMAX_32,
FAMAX_64,
WHILELT,
WHILELE,
WHILEGT,
WHILEGE,
WHILELS,
WHILELO,
WHILEHS,
WHILEHI,
ADDV_Z,
SMAXV_Z,
UMAXV_Z,
SMINV_Z,
UMINV_Z,
FADDV_Z,
FMAXV_Z,
FMINV_Z,
FMAXNMV_Z,
FMINNMV_Z,
TBL_Z,
ZIP1_Z,
ZIP2_Z,
UZP1_Z,
UZP2_Z,
TRN1_Z,
TRN2_Z,
REV_Z,
SUNPKLO_Z,
SUNPKHI_Z,
UUNPKLO_Z,
UUNPKHI_Z,
DUP_Z,
PTEST,
FCMGT_P,
FCMGE_P,
ZERO_ZA,
FMOPA,
FMOPS,
SMOPA,
SMOPS,
MOVA_ZA,
MOVA_ZA_TO,
SADD_Z,
SSUB_Z,
UADD_Z,
USUB_Z,
SUQADD_Z,
USQADD_Z,
SQADD_Z,
UQADD_Z,
SQSUB_Z,
UQSUB_Z,
SQRDMLAH_Z,
SQRDMLSH_Z,
MUL_I_Z,
MLA_I_Z,
MLS_I_Z,
SMLSLB_Z,
SMLSLT_Z,
UMLSLB_Z,
UMLSLT_Z,
SQDMLALB_Z,
SQDMLALT_Z,
UQDMLALB_Z,
UQDMLALT_Z,
SHRNB,
SHRNT,
SQSHRUNB,
SQSHRUNT,
UQSHRNB,
UQSHRNT,
ADDHNB,
ADDHNT,
RADDHNB,
RADDHNT,
ADDP_Z,
SMAXP_Z,
UMAXP_Z,
SMINP_Z,
UMINP_Z,
FADDP_Z,
FMAXP_Z,
FMINP_Z,
FMAXNMP_Z,
FMINNMP_Z,
BSL_Z,
BIT_Z,
BIF_Z,
MATCH_Z,
NMATCH_Z,
CMLE_Z,
TBX_Z,
EXT_Z,
FMLA_MULTI_Z,
FMLS_MULTI_Z,
SMLAL_MULTI_Z,
UMLAL_MULTI_Z,
SMLSL_MULTI_Z,
UMLSL_MULTI_Z,
LD1X2_Z,
LD1X4_Z,
ST1X2_Z,
ST1X4_Z,
LD_STRIDED_Z,
ST_STRIDED_Z,
PSEL_Z,
SCLAMP_Z,
UCLAMP_Z,
F1CVT_Z,
F2CVT_Z,
BF1CVT_Z,
FDOT_Z,
SDOT_Z,
UDOT_Z,
LD1Q_SVE,
ST1Q_SVE,
SUNPK_SVE21,
UUNPK_SVE21,
SUNPK_SVE21_2,
UUNPK_SVE21_2,
ZIPQ1_SVE21,
ZIPQ2_SVE21,
ZIPQ1_SVE21_2,
ZIPQ2_SVE21_2,
UZPQ1_SVE21,
UZPQ2_SVE21,
UZPQ1_SVE21_2,
UZPQ2_SVE21_2,
TBLQ_SVE21,
TBLQ_SVE21_2,
TBLQ_SVE21_1,
F1CVTL_SVE21,
F2CVTL_SVE21,
F1CVTL_SVE21_MULTI,
F2CVTL_SVE21_MULTI,
FRINTO_SVE21,
PTRUE_PAT,
FADD_SVE21_QUAD,
FSUB_SVE21_QUAD,
FMUL_SVE21_QUAD,
ADD_SVE21_QUAD,
SUB_SVE21_QUAD,
LSL_SVE21_QUAD,
LSR_SVE21_QUAD,
ASR_SVE21_QUAD,
AND_SVE21_QUAD,
ORR_SVE21_QUAD,
EOR_SVE21_QUAD,
FADD_SVE21_QUAD_2,
FSUB_SVE21_QUAD_2,
FMUL_SVE21_QUAD_2,
ADD_SVE21_QUAD_2,
MUL_SVE21_QUAD_2,
FADD_SVE21_FP8,
FSUB_SVE21_FP8,
FMUL_SVE21_FP8,
FDOT_SVE21,
FOP8A_SME21,
FOP8S_SME21,
BFDOT_SME21,
BFDOT_SME21_2,
FDOT_SME21_MULTI,
FADD_SME21_STREAM,
FSUB_SME21_STREAM,
FMUL_SME21_STREAM,
FMLA_SME21_STREAM,
FMLS_SME21_STREAM,
LD1W_SME21_STREAM,
ST1W_SME21_STREAM,
LDR_ZA512_SME21,
STR_ZA512_SME21,
LD1H_ZA512_SME21,
ST1H_ZA512_SME21,
LD1V_ZA512_SME21,
ST1V_ZA512_SME21,
TRN1_ZA_SME21,
TRN2_ZA_SME21,
TRN1A_ZA_SME21,
TRN2A_ZA_SME21,
FMLA_SP_SME21,
FMLA_SP_SME21_2,
FMUL_SP_SME21,
FDOT_SP_SME21,
LDR_SP_META_SME21,
LD1RQW_SP_SME21,
PK_SP_SME21,
UPK_SP_SME21,
INVALID,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArmOperandType {
GPR64,
GPR32,
FPR64,
FPR32,
FPR128,
FPR16,
FPR8,
Imm8,
Imm12,
Imm16,
Imm32,
ImmShift12,
ImmBitmask32,
ImmBitmask64,
ImmSIMD,
MemReg,
MemPostIndex,
MemPreIndex,
MemFPImm,
Label,
Cond,
RegList,
ShiftedReg,
ExtendReg,
MemRegOffset,
SysReg,
Shift,
Extend,
Predicate,
ZPR64,
ZPR32,
ZATile,
RegShift3,
RegShift4,
}
#[derive(Debug, Clone)]
pub struct ArmInstrDesc {
pub opcode: ArmOpcode,
pub mnemonic: &'static str,
pub num_operands: u8,
pub is_terminator: bool,
pub is_branch: bool,
pub is_call: bool,
pub is_return: bool,
pub is_compare: bool,
pub is_move_imm: bool,
pub has_side_effects: bool,
pub may_load: bool,
pub may_store: bool,
pub is_commutative: bool,
pub operand_types: Vec<ArmOperandType>,
pub implicit_defs: Vec<u16>,
pub implicit_uses: Vec<u16>,
pub is_aarch64: bool,
pub is_arm32: bool,
pub is_thumb: bool,
}
impl ArmInstrDesc {
fn new(opcode: ArmOpcode, mnemonic: &'static str) -> Self {
ArmInstrDesc {
opcode,
mnemonic,
num_operands: 0,
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
is_compare: false,
is_move_imm: false,
has_side_effects: false,
may_load: false,
may_store: false,
is_commutative: false,
operand_types: Vec::new(),
implicit_defs: Vec::new(),
implicit_uses: Vec::new(),
is_aarch64: false,
is_arm32: false,
is_thumb: false,
}
}
}
pub struct ArmInstrInfo {
descriptors: Vec<ArmInstrDesc>,
mnemonic_map: HashMap<String, ArmOpcode>,
}
impl ArmInstrInfo {
pub fn new() -> Self {
let mut descriptors = Vec::with_capacity(400);
let mut mnemonic_map = HashMap::with_capacity(400);
let mut register = |mut desc: ArmInstrDesc| {
let mnemonic = desc.mnemonic.to_string();
desc.num_operands = desc.operand_types.len() as u8;
mnemonic_map.entry(mnemonic).or_insert(desc.opcode);
descriptors.push(desc);
};
let arch64_data = vec![
(
"add",
ArmOpcode::ADD,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
true,
true,
),
(
"sub",
ArmOpcode::SUB,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"mul",
ArmOpcode::MUL,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
true,
),
(
"sdiv",
ArmOpcode::SDIV,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"udiv",
ArmOpcode::UDIV,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"and",
ArmOpcode::AND,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
true,
),
(
"orr",
ArmOpcode::ORR,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
true,
),
(
"eor",
ArmOpcode::EOR,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
true,
),
(
"orn",
ArmOpcode::ORN,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"bic",
ArmOpcode::BIC,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"lsl",
ArmOpcode::LSL,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"lsr",
ArmOpcode::LSR,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"asr",
ArmOpcode::ASR,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"ror",
ArmOpcode::ROR,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"adds",
ArmOpcode::ADDS,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
true,
),
(
"subs",
ArmOpcode::SUBS,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"madd",
ArmOpcode::MADD,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
(
"msub",
ArmOpcode::MSUB,
vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
],
false,
false,
),
];
for (mn, op, ops, cmp, comm) in arch64_data {
let mut desc = ArmInstrDesc::new(op, mn);
desc.operand_types = ops;
desc.is_compare = cmp;
desc.is_commutative = comm;
desc.is_aarch64 = true;
if cmp {
desc.implicit_defs.push(NZCV);
}
register(desc);
}
let mov_ops = vec![
(
"mov",
ArmOpcode::MOV,
vec![ArmOperandType::GPR64, ArmOperandType::GPR64],
true,
),
(
"movz",
ArmOpcode::MOVZ,
vec![ArmOperandType::GPR64, ArmOperandType::Imm16],
true,
),
(
"movk",
ArmOpcode::MOVK,
vec![ArmOperandType::GPR64, ArmOperandType::Imm16],
true,
),
(
"movn",
ArmOpcode::MOVN,
vec![ArmOperandType::GPR64, ArmOperandType::Imm16],
true,
),
(
"movi",
ArmOpcode::MOVI,
vec![ArmOperandType::FPR128, ArmOperandType::ImmSIMD],
true,
),
];
for (mn, op, ops, is_mov_imm) in mov_ops {
let mut desc = ArmInstrDesc::new(op, mn);
desc.operand_types = ops;
desc.is_move_imm = is_mov_imm;
desc.is_aarch64 = true;
register(desc);
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ADR, "adr");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::Label];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ADRP, "adrp");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::Label];
d.is_aarch64 = true;
d
});
let loads = [
("ldr", ArmOpcode::LDR, false),
("ldrb", ArmOpcode::LDRB, false),
("ldrh", ArmOpcode::LDRH, false),
("ldrsb", ArmOpcode::LDRSB, false),
("ldrsh", ArmOpcode::LDRSH, false),
("ldrsw", ArmOpcode::LDRSW, false),
("ldur", ArmOpcode::LDUR, false),
("ldurb", ArmOpcode::LDURB, false),
("ldurh", ArmOpcode::LDURH, false),
("ldursw", ArmOpcode::LDURSW, false),
];
for (mn, op, _) in &loads {
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::MemReg];
d.may_load = true;
d.is_aarch64 = true;
register(d);
}
let stores = [
("str", ArmOpcode::STR, false),
("strb", ArmOpcode::STRB, false),
("strh", ArmOpcode::STRH, false),
("stur", ArmOpcode::STUR, false),
("sturb", ArmOpcode::STURB, false),
("sturh", ArmOpcode::STURH, false),
];
for (mn, op, _) in &stores {
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::MemReg];
d.may_store = true;
d.is_aarch64 = true;
register(d);
}
for (mn, op, is_load) in &[
("ldp", ArmOpcode::LDP, true),
("stp", ArmOpcode::STP, false),
("ldnp", ArmOpcode::LDNP, true),
("stnp", ArmOpcode::STNP, false),
] {
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::MemReg,
];
d.may_load = *is_load;
d.may_store = !is_load;
d.is_aarch64 = true;
register(d);
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::LDR_LIT, "ldr");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::Label];
d.may_load = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::B, "b");
d.operand_types = vec![ArmOperandType::Label];
d.is_terminator = true;
d.is_branch = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::BL, "bl");
d.operand_types = vec![ArmOperandType::Label];
d.is_branch = true;
d.is_call = true;
d.has_side_effects = true;
d.implicit_defs.push(LR);
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::BR, "br");
d.operand_types = vec![ArmOperandType::GPR64];
d.is_terminator = true;
d.is_branch = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::BLR, "blr");
d.operand_types = vec![ArmOperandType::GPR64];
d.is_branch = true;
d.is_call = true;
d.has_side_effects = true;
d.implicit_defs.push(LR);
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::RET, "ret");
d.operand_types = vec![ArmOperandType::GPR64];
d.is_terminator = true;
d.is_branch = true;
d.is_return = true;
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CBZ, "cbz");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::Label];
d.is_terminator = true;
d.is_branch = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CBNZ, "cbnz");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::Label];
d.is_terminator = true;
d.is_branch = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::B_COND, "b.cond");
d.operand_types = vec![ArmOperandType::Label];
d.is_terminator = true;
d.is_branch = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CMP, "cmp");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_compare = true;
d.implicit_defs.push(NZCV);
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CMN, "cmn");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_compare = true;
d.implicit_defs.push(NZCV);
d.is_commutative = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::TST, "tst");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_compare = true;
d.implicit_defs.push(NZCV);
d.is_commutative = true;
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("csel", ArmOpcode::CSEL),
("csinc", ArmOpcode::CSINC),
("csinv", ArmOpcode::CSINV),
("csneg", ArmOpcode::CSNEG),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::Cond,
];
d.is_aarch64 = true;
d
});
}
let bitfield_ops = [
("sbfm", ArmOpcode::SBFM),
("ubfm", ArmOpcode::UBFM),
("sbfx", ArmOpcode::SBFX),
("ubfx", ArmOpcode::UBFX),
("bfm", ArmOpcode::BFM),
("bfi", ArmOpcode::BFI),
("bfxil", ArmOpcode::BFXIL),
];
for (mn, op) in &bitfield_ops {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::Imm8,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
}
let extend_ops = [
("sxtb", ArmOpcode::SXTB),
("sxth", ArmOpcode::SXTH),
("sxtw", ArmOpcode::SXTW),
("uxtb", ArmOpcode::UXTB),
("uxth", ArmOpcode::UXTH),
("uxtw", ArmOpcode::UXTW),
("clz", ArmOpcode::CLZ),
("cls", ArmOpcode::CLS),
("rbit", ArmOpcode::RBIT),
("rev", ArmOpcode::REV),
("rev16", ArmOpcode::REV16),
("rev32", ArmOpcode::REV32),
];
for (mn, op) in &extend_ops {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::EXTR, "extr");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::NOP, "nop");
d.is_aarch64 = true;
d.is_arm32 = true;
d
});
for (mn, op) in &[
("svc", ArmOpcode::SVC),
("hvc", ArmOpcode::HVC),
("smc", ArmOpcode::SMC),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::Imm16];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::BRK, "brk");
d.operand_types = vec![ArmOperandType::Imm16];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("isb", ArmOpcode::ISB),
("dsb", ArmOpcode::DSB),
("dmb", ArmOpcode::DMB),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::MSR, "msr");
d.operand_types = vec![ArmOperandType::SysReg, ArmOperandType::GPR64];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::MRS, "mrs");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::SysReg];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("add", ArmOpcode::ADD_V),
("sub", ArmOpcode::SUB_V),
("mul", ArmOpcode::MUL_V),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_commutative = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[("mla", ArmOpcode::MLA_V), ("mls", ArmOpcode::MLS_V)] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fadd", ArmOpcode::FADD),
("fsub", ArmOpcode::FSUB),
("fmul", ArmOpcode::FMUL),
("fdiv", ArmOpcode::FDIV),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::FPR64,
];
d.is_commutative = matches!(*op, ArmOpcode::FADD | ArmOpcode::FMUL);
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fabs", ArmOpcode::FABS),
("fneg", ArmOpcode::FNEG),
("fsqrt", ArmOpcode::FSQRT),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::FPR64];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FCSEL, "fcsel");
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::Cond,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FCMP, "fcmp");
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::FPR64];
d.is_compare = true;
d.implicit_defs.push(NZCV);
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("scvtf", ArmOpcode::SCVTF),
("ucvtf", ArmOpcode::UCVTF),
("fcvtzs", ArmOpcode::FCVTZS),
("fcvtzu", ArmOpcode::FCVTZU),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::GPR64];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FCVT, "fcvt");
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::FPR32];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FMOV, "fmov");
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::FPR64];
d.is_move_imm = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::DUP, "dup");
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::FPR8];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("ins", ArmOpcode::INS),
("smov", ArmOpcode::SMOV),
("umov", ArmOpcode::UMOV),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::FPR128];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::EXT, "ext");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("zip1", ArmOpcode::ZIP1),
("zip2", ArmOpcode::ZIP2),
("uzp1", ArmOpcode::UZP1),
("uzp2", ArmOpcode::UZP2),
("trn1", ArmOpcode::TRN1),
("trn2", ArmOpcode::TRN2),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("and", ArmOpcode::AND_V),
("orr", ArmOpcode::ORR_V),
("eor", ArmOpcode::EOR_V),
("bic", ArmOpcode::BIC_V),
("orn", ArmOpcode::ORN_V),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_commutative =
matches!(*op, ArmOpcode::AND_V | ArmOpcode::ORR_V | ArmOpcode::EOR_V);
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("cmeq", ArmOpcode::CMEQ),
("cmge", ArmOpcode::CMGE),
("cmgt", ArmOpcode::CMGT),
("cmhi", ArmOpcode::CMHI),
("cmhs", ArmOpcode::CMHS),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_compare = true;
d.is_aarch64 = true;
d
});
}
let arm32_data = [
("add", ArmOpcode::ARM_ADD, true, true),
("sub", ArmOpcode::ARM_SUB, false, false),
("mul", ArmOpcode::ARM_MUL, false, true),
("and", ArmOpcode::ARM_AND, false, true),
("orr", ArmOpcode::ARM_ORR, false, true),
("eor", ArmOpcode::ARM_EOR, false, true),
("rsb", ArmOpcode::ARM_RSB, false, false),
("adc", ArmOpcode::ARM_ADC, false, false),
("sbc", ArmOpcode::ARM_SBC, false, false),
];
for (mn, op, cmp, comm) in &arm32_data {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::GPR32,
ArmOperandType::GPR32,
ArmOperandType::GPR32,
];
d.is_compare = *cmp;
d.is_commutative = *comm;
d.is_arm32 = true;
if *cmp {
d.implicit_defs.push(CPSR);
}
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_MOV, "mov");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::GPR32];
d.is_move_imm = true;
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_MOVW, "movw");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::Imm16];
d.is_move_imm = true;
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_MOVT, "movt");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::Imm16];
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_MVN, "mvn");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::GPR32];
d.is_arm32 = true;
d
});
for (mn, op) in &[
("cmp", ArmOpcode::ARM_CMP),
("cmn", ArmOpcode::ARM_CMN),
("tst", ArmOpcode::ARM_TST),
("teq", ArmOpcode::ARM_TEQ),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::GPR32];
d.is_compare = true;
d.implicit_defs.push(CPSR);
d.is_commutative = matches!(
*op,
ArmOpcode::ARM_CMN | ArmOpcode::ARM_TST | ArmOpcode::ARM_TEQ
);
d.is_arm32 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_B, "b");
d.operand_types = vec![ArmOperandType::Label];
d.is_terminator = true;
d.is_branch = true;
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_BL, "bl");
d.operand_types = vec![ArmOperandType::Label];
d.is_branch = true;
d.is_call = true;
d.has_side_effects = true;
d.implicit_defs.push(LR_ARM32);
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_BX, "bx");
d.operand_types = vec![ArmOperandType::GPR32];
d.is_terminator = true;
d.is_branch = true;
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_BLX, "blx");
d.operand_types = vec![ArmOperandType::Label];
d.is_branch = true;
d.is_call = true;
d.has_side_effects = true;
d.implicit_defs.push(LR_ARM32);
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_LDR, "ldr");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::MemReg];
d.may_load = true;
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_STR, "str");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::MemReg];
d.may_store = true;
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_PUSH, "push");
d.operand_types = vec![ArmOperandType::RegList];
d.may_store = true;
d.has_side_effects = true;
d.implicit_uses.push(SP_ARM32);
d.implicit_defs.push(SP_ARM32);
d.is_arm32 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ARM_POP, "pop");
d.operand_types = vec![ArmOperandType::RegList];
d.may_load = true;
d.has_side_effects = true;
d.implicit_uses.push(SP_ARM32);
d.implicit_defs.push(SP_ARM32);
d.is_arm32 = true;
d
});
for (mn, op) in &[
("uxtb", ArmOpcode::ARM_UXTB),
("uxth", ArmOpcode::ARM_UXTH),
("sxtb", ArmOpcode::ARM_SXTB),
("sxth", ArmOpcode::ARM_SXTH),
("clz", ArmOpcode::ARM_CLZ),
("rbit", ArmOpcode::ARM_RBIT),
("rev", ArmOpcode::ARM_REV),
("rev16", ArmOpcode::ARM_REV16),
("revsh", ArmOpcode::ARM_REVSH),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::GPR32];
d.is_arm32 = true;
d
});
}
let thumb_ops = [
("add", ArmOpcode::THUMB_ADD),
("sub", ArmOpcode::THUMB_SUB),
("mov", ArmOpcode::THUMB_MOV),
("cmp", ArmOpcode::THUMB_CMP),
];
for (mn, op) in &thumb_ops {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::GPR32];
d.is_thumb = true;
if *op == ArmOpcode::THUMB_CMP {
d.is_compare = true;
d.implicit_defs.push(CPSR);
}
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_B, "b");
d.operand_types = vec![ArmOperandType::Label];
d.is_terminator = true;
d.is_branch = true;
d.is_thumb = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_BL, "bl");
d.operand_types = vec![ArmOperandType::Label];
d.is_branch = true;
d.is_call = true;
d.implicit_defs.push(LR_ARM32);
d.is_thumb = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_BX, "bx");
d.operand_types = vec![ArmOperandType::GPR32];
d.is_terminator = true;
d.is_branch = true;
d.is_thumb = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_LDR, "ldr");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::MemReg];
d.may_load = true;
d.is_thumb = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_STR, "str");
d.operand_types = vec![ArmOperandType::GPR32, ArmOperandType::MemReg];
d.may_store = true;
d.is_thumb = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_PUSH, "push");
d.operand_types = vec![ArmOperandType::RegList];
d.may_store = true;
d.is_thumb = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::THUMB_POP, "pop");
d.operand_types = vec![ArmOperandType::RegList];
d.may_load = true;
d.is_thumb = true;
d
});
for (mn, op) in &[
("ld1", ArmOpcode::LD1_ONE),
("ld1", ArmOpcode::LD1_TWO),
("ld1", ArmOpcode::LD1_THREE),
("ld1", ArmOpcode::LD1_FOUR),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::MemReg];
d.may_load = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("ld2", ArmOpcode::LD2),
("ld3", ArmOpcode::LD3),
("ld4", ArmOpcode::LD4),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::MemReg];
d.may_load = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("ld1r", ArmOpcode::LD1R),
("ld2r", ArmOpcode::LD2R),
("ld3r", ArmOpcode::LD3R),
("ld4r", ArmOpcode::LD4R),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::MemReg];
d.may_load = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("st1", ArmOpcode::ST1_ONE),
("st1", ArmOpcode::ST1_TWO),
("st1", ArmOpcode::ST1_THREE),
("st1", ArmOpcode::ST1_FOUR),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::MemReg];
d.may_store = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("st2", ArmOpcode::ST2),
("st3", ArmOpcode::ST3),
("st4", ArmOpcode::ST4),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR128, ArmOperandType::MemReg];
d.may_store = true;
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::TBL, "tbl");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::TBX, "tbx");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
for (mn, op) in &[("ptrue", ArmOpcode::PTRUE), ("ptrues", ArmOpcode::PTRUES)] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::Predicate];
d.is_aarch64 = true;
d.has_side_effects = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::PFALSE, "pfalse");
d.operand_types = vec![ArmOperandType::Predicate];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("and", ArmOpcode::AND_P),
("bic", ArmOpcode::BIC_P),
("eor", ArmOpcode::EOR_P),
("orr", ArmOpcode::ORR_P),
("orn", ArmOpcode::ORN_P),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::Predicate,
ArmOperandType::Predicate,
ArmOperandType::Predicate,
];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::MOV_P, "mov");
d.operand_types = vec![ArmOperandType::Predicate, ArmOperandType::Predicate];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::NOT_P, "not");
d.operand_types = vec![ArmOperandType::Predicate, ArmOperandType::Predicate];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CNTP, "cntp");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::Predicate,
ArmOperandType::Predicate,
];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("brka", ArmOpcode::BRKA),
("brkb", ArmOpcode::BRKB),
("brkn", ArmOpcode::BRKN),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::Predicate,
ArmOperandType::Predicate,
ArmOperandType::Predicate,
];
d.is_aarch64 = true;
d.has_side_effects = true;
d
});
}
for (mn, op) in &[
("add", ArmOpcode::ADD_Z),
("sub", ArmOpcode::SUB_Z),
("mul", ArmOpcode::MUL_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("and", ArmOpcode::AND_Z),
("orr", ArmOpcode::ORR_Z),
("eor", ArmOpcode::EOR_Z),
("bic", ArmOpcode::BIC_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("asr", ArmOpcode::ASR_Z),
("lsl", ArmOpcode::LSL_Z),
("lsr", ArmOpcode::LSR_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fadd", ArmOpcode::FADD_Z),
("fsub", ArmOpcode::FSUB_Z),
("fmul", ArmOpcode::FMUL_Z),
("fdiv", ArmOpcode::FDIV_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fmax", ArmOpcode::FMAX_Z),
("fmin", ArmOpcode::FMIN_Z),
("fmaxnm", ArmOpcode::FMAXNM_Z),
("fminnm", ArmOpcode::FMINNM_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FABS_Z, "fabs");
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FNEG_Z, "fneg");
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("frinta", ArmOpcode::FRINTA_Z),
("frinti", ArmOpcode::FRINTI_Z),
("frintm", ArmOpcode::FRINTM_Z),
("frintn", ArmOpcode::FRINTN_Z),
("frintp", ArmOpcode::FRINTP_Z),
("frintx", ArmOpcode::FRINTX_Z),
("frintz", ArmOpcode::FRINTZ_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FRECPE_Z, "frecpe");
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FRSQRTE_Z, "frsqrte");
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::FSQRT_Z, "fsqrt");
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("cmpeq", ArmOpcode::CMPEQ_P),
("cmpne", ArmOpcode::CMPNE_P),
("cmpgt", ArmOpcode::CMPGT_P),
("cmpge", ArmOpcode::CMPGE_P),
("cmplt", ArmOpcode::CMPLT_P),
("cmple", ArmOpcode::CMPLE_P),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::Predicate,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_compare = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fcmpeq", ArmOpcode::FCMEQ_P),
("fcmpne", ArmOpcode::FCMNE_P),
("fcmgt", ArmOpcode::FCMLT_P_F),
("fcmge", ArmOpcode::FCMLE_P),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::Predicate,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_compare = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("ld1b", ArmOpcode::LD1B_Z),
("ld1h", ArmOpcode::LD1H_Z),
("ld1w", ArmOpcode::LD1W_Z),
("ld1d", ArmOpcode::LD1D_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::Predicate,
ArmOperandType::MemReg,
];
d.may_load = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("st1b", ArmOpcode::ST1B_Z),
("st1h", ArmOpcode::ST1H_Z),
("st1w", ArmOpcode::ST1W_Z),
("st1d", ArmOpcode::ST1D_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::Predicate,
ArmOperandType::MemReg,
];
d.may_store = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("ld1b", ArmOpcode::LD1B_GATHER_Z),
("ld1h", ArmOpcode::LD1H_GATHER_Z),
("ld1w", ArmOpcode::LD1W_GATHER_Z),
("ld1d", ArmOpcode::LD1D_GATHER_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::Predicate,
ArmOperandType::ZPR64,
];
d.may_load = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("st1b", ArmOpcode::ST1B_SCATTER_Z),
("st1h", ArmOpcode::ST1H_SCATTER_Z),
("st1w", ArmOpcode::ST1W_SCATTER_Z),
("st1d", ArmOpcode::ST1D_SCATTER_Z),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::Predicate,
ArmOperandType::ZPR64,
];
d.may_store = true;
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::SMSTART, "smstart");
d.operand_types = vec![];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::SMSTOP, "smstop");
d.operand_types = vec![];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("adda", ArmOpcode::ADDA_ZA),
("adds", ArmOpcode::ADDS_ZA),
("subs", ArmOpcode::SUBS_ZA),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZATile,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fmopa", ArmOpcode::FMOPA_WIDE),
("fmopa", ArmOpcode::FMOPA_NARROW),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZATile,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::LDR_ZA, "ldr");
d.operand_types = vec![ArmOperandType::ZATile, ArmOperandType::MemReg];
d.may_load = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::STR_ZA, "str");
d.operand_types = vec![ArmOperandType::ZATile, ArmOperandType::MemReg];
d.may_store = true;
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("smmla", ArmOpcode::SMMLA),
("usmmla", ArmOpcode::USMMLA),
("ummla", ArmOpcode::UMMLA),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZATile,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("pacia", ArmOpcode::PACIA),
("pacib", ArmOpcode::PACIB),
("pacda", ArmOpcode::PACDA),
("pacdb", ArmOpcode::PACDB),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("autia", ArmOpcode::AUTIA),
("autib", ArmOpcode::AUTIB),
("autda", ArmOpcode::AUTDA),
("autdb", ArmOpcode::AUTDB),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::PACGA, "pacga");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::XPACI, "xpaci");
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("bti", ArmOpcode::BTI),
("bti c", ArmOpcode::BTI_C),
("bti j", ArmOpcode::BTI_J),
("bti jc", ArmOpcode::BTI_JC),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![];
d.is_terminator = true;
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[("bra", ArmOpcode::BRA), ("brab", ArmOpcode::BRAB)] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_terminator = true;
d.is_branch = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[("blraa", ArmOpcode::BLRAA), ("blrab", ArmOpcode::BLRAB)] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::GPR64];
d.is_branch = true;
d.is_call = true;
d.implicit_defs.push(LR);
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::RETAA, "retaa");
d.operand_types = vec![];
d.is_terminator = true;
d.is_branch = true;
d.is_return = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::RETAB, "retab");
d.operand_types = vec![];
d.is_terminator = true;
d.is_branch = true;
d.is_return = true;
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::IRG, "irg");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::GMI, "gmi");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::GPR64,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::ADDG, "addg");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::Imm12,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::SUBG, "subg");
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::Imm12,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("ldg", ArmOpcode::LDG),
("stg", ArmOpcode::STG),
("stzg", ArmOpcode::STZG),
("st2g", ArmOpcode::ST2G),
("stz2g", ArmOpcode::STZ2G),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64, ArmOperandType::MemReg];
d.may_load = (*op == ArmOpcode::LDG);
d.may_store = (*op != ArmOpcode::LDG);
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::BCAX, "bcax");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::EOR3, "eor3");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::RAX1_A64, "rax1");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::XAR, "xar");
d.operand_types = vec![
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::FPR128,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CLREX_A64, "clrex");
d.operand_types = vec![];
d.has_side_effects = true;
d.is_aarch64 = true;
d.is_arm32 = true;
d
});
for (mn, op) in &[
("yield", ArmOpcode::YIELD_A64),
("wfe", ArmOpcode::WFE_A64),
("wfi", ArmOpcode::WFI_A64),
("sev", ArmOpcode::SEV_A64),
("sevl", ArmOpcode::SEVL_A64),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![];
d.has_side_effects = true;
d.is_aarch64 = true;
d.is_arm32 = true;
d
});
}
for (mn, op) in &[
("vtrn.8", ArmOpcode::VTRN_8),
("vtrn.16", ArmOpcode::VTRN_16),
("vtrn.32", ArmOpcode::VTRN_32),
("vzip.8", ArmOpcode::VZIP_8),
("vzip.16", ArmOpcode::VZIP_16),
("vzip.32", ArmOpcode::VZIP_32),
("vuzp.8", ArmOpcode::VUZP_8),
("vuzp.16", ArmOpcode::VUZP_16),
("vuzp.32", ArmOpcode::VUZP_32),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::FPR64,
];
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::VEXT, "vext");
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("vrev64.8", ArmOpcode::VREV64_8),
("vrev64.16", ArmOpcode::VREV64_16),
("vrev64.32", ArmOpcode::VREV64_32),
("vrev32.8", ArmOpcode::VREV32_8),
("vrev32.16", ArmOpcode::VREV32_16),
("vrev16.8", ArmOpcode::VREV16_8),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::FPR64];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("vtbl.8", ArmOpcode::VTBL_2REG),
("vtbl.8", ArmOpcode::VTBL_3REG),
("vtbl.8", ArmOpcode::VTBL_4REG),
("vtbx.8", ArmOpcode::VTBX_2REG),
("vtbx.8", ArmOpcode::VTBX_3REG),
("vtbx.8", ArmOpcode::VTBX_4REG),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::RegList,
ArmOperandType::FPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("vshl.i8", ArmOpcode::VSHL_IMM_8),
("vshl.i16", ArmOpcode::VSHL_IMM_16),
("vshl.i32", ArmOpcode::VSHL_IMM_32),
("vshl.i64", ArmOpcode::VSHL_IMM_64),
("vqshl.s8", ArmOpcode::VQSHL_IMM_8),
("vqshl.s16", ArmOpcode::VQSHL_IMM_16),
("vqshl.s32", ArmOpcode::VQSHL_IMM_32),
("vqshl.s64", ArmOpcode::VQSHL_IMM_64),
("vqshlu.s8", ArmOpcode::VQSHLU_IMM_8),
("vqshlu.s16", ArmOpcode::VQSHLU_IMM_16),
("vqshlu.s32", ArmOpcode::VQSHLU_IMM_32),
("vqshlu.s64", ArmOpcode::VQSHLU_IMM_64),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("vrshr.s8", ArmOpcode::VRSHR_8),
("vrshr.s16", ArmOpcode::VRSHR_16),
("vrshr.s32", ArmOpcode::VRSHR_32),
("vrshr.s64", ArmOpcode::VRSHR_64),
("vrsra.s8", ArmOpcode::VRSRA_8),
("vrsra.s16", ArmOpcode::VRSRA_16),
("vrsra.s32", ArmOpcode::VRSRA_32),
("vrsra.s64", ArmOpcode::VRSRA_64),
("vsri.8", ArmOpcode::VSRI_8),
("vsri.16", ArmOpcode::VSRI_16),
("vsri.32", ArmOpcode::VSRI_32),
("vsri.64", ArmOpcode::VSRI_64),
("vsli.8", ArmOpcode::VSLI_8),
("vsli.16", ArmOpcode::VSLI_16),
("vsli.32", ArmOpcode::VSLI_32),
("vsli.64", ArmOpcode::VSLI_64),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("vrecpe.f32", ArmOpcode::VRECPE_F32),
("vrecpe.f64", ArmOpcode::VRECPE_F64),
("vrecps.f32", ArmOpcode::VRECPS_F32),
("vrecps.f64", ArmOpcode::VRECPS_F64),
("vrsqrte.f32", ArmOpcode::VRSQRTE_F32),
("vrsqrte.f64", ArmOpcode::VRSQRTE_F64),
("vrsqrts.f32", ArmOpcode::VRSQRTS_F32),
("vrsqrts.f64", ArmOpcode::VRSQRTS_F64),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR64, ArmOperandType::FPR64];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("cmla", ArmOpcode::CMLA_SVE),
("cadd", ArmOpcode::CADD_SVE),
("sqcadd", ArmOpcode::SQCADD_SVE),
("sqrdcmla", ArmOpcode::SQRDCMLA_SVE),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d.has_side_effects = false;
d
});
}
for (mn, op) in &[
("histcnt", ArmOpcode::HISTCNT_SVE),
("histseg", ArmOpcode::HISTSEG_SVE),
("match", ArmOpcode::MATCH_SVE),
("nmatch", ArmOpcode::NMATCH_SVE),
("bext", ArmOpcode::BEXT_SVE),
("bdep", ArmOpcode::BDEP_SVE),
("bgrp", ArmOpcode::BGRP_SVE),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
ArmOperandType::ZPR64,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("fcvtnt", ArmOpcode::FCVTNT_SVE),
("fcvtlt", ArmOpcode::FCVTLT_SVE),
("fcvtx", ArmOpcode::FCVTX_SVE),
("fcvtxnt", ArmOpcode::FCVTXNT_SVE),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::ZPR64, ArmOperandType::ZPR64];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("rmi_gran_delegate", ArmOpcode::RMI_GRAN_DELEGATE),
("rmi_gran_undelegate", ArmOpcode::RMI_GRAN_UNDELEGATE),
("rmi_data_create", ArmOpcode::RMI_DATA_CREATE),
(
"rmi_data_create_unknown",
ArmOpcode::RMI_DATA_CREATE_UNKNOWN,
),
("rmi_data_destroy", ArmOpcode::RMI_DATA_DESTROY),
("rmi_rec_create", ArmOpcode::RMI_REC_CREATE),
("rmi_rec_destroy", ArmOpcode::RMI_REC_DESTROY),
("rmi_realm_create", ArmOpcode::RMI_REALM_CREATE),
("rmi_realm_destroy", ArmOpcode::RMI_REALM_DESTROY),
("rmi_rtt_create", ArmOpcode::RMI_RTT_CREATE),
("rmi_rtt_destroy", ArmOpcode::RMI_RTT_DESTROY),
("rmi_rtt_init_ripas", ArmOpcode::RMI_RTT_INIT_RIPAS),
("rmi_rtt_set_ripas", ArmOpcode::RMI_RTT_SET_RIPAS),
("rmi_rtt_read_entry", ArmOpcode::RMI_RTT_READ_ENTRY),
("rmi_rtt_fold", ArmOpcode::RMI_RTT_FOLD),
("rmi_features", ArmOpcode::RMI_FEATURES),
("rmi_version", ArmOpcode::RMI_VERSION),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("brb iall", ArmOpcode::BRB_IALL),
("brb inj", ArmOpcode::BRB_INJ),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("gcspushx", ArmOpcode::GCSPUSHX),
("gcspopx", ArmOpcode::GCSPOPX),
("gcsss1", ArmOpcode::GCSSS1),
("gcsss2", ArmOpcode::GCSSS2),
("gcsstr", ArmOpcode::GCSSTR),
("gcssttr", ArmOpcode::GCSSTTR),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::GPR64];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("the_invalidate_all", ArmOpcode::THE_INVALIDATE_ALL),
("the_invalidate_va", ArmOpcode::THE_INVALIDATE_VA),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
}
register({
let mut d = ArmInstrDesc::new(ArmOpcode::CHKFEAT, "chkfeat");
d.operand_types = vec![ArmOperandType::GPR64];
d.has_side_effects = true;
d.is_aarch64 = true;
d
});
for (mn, op) in &[
("ldiapp", ArmOpcode::LDIAPP_32),
("ldiapp", ArmOpcode::LDIAPP_64),
("stilp", ArmOpcode::STILP_32),
("stilp", ArmOpcode::STILP_64),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::GPR64,
ArmOperandType::GPR64,
ArmOperandType::MemReg,
];
d.may_load = mn.starts_with("ldi");
d.may_store = mn.starts_with("st");
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("f1cvt", ArmOpcode::F1CVT),
("f2cvt", ArmOpcode::F2CVT),
("bf1cvt", ArmOpcode::BF1CVT),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![ArmOperandType::FPR32, ArmOperandType::FPR32];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("luti2.8", ArmOpcode::LUTI2_8),
("luti2.16", ArmOpcode::LUTI2_16),
("luti2.32", ArmOpcode::LUTI2_32),
("luti4.8", ArmOpcode::LUTI4_8),
("luti4.16", ArmOpcode::LUTI4_16),
("luti4.32", ArmOpcode::LUTI4_32),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::Imm8,
];
d.is_aarch64 = true;
d
});
}
for (mn, op) in &[
("famin.2s", ArmOpcode::FAMIN_32),
("famin.2d", ArmOpcode::FAMIN_64),
("famax.2s", ArmOpcode::FAMAX_32),
("famax.2d", ArmOpcode::FAMAX_64),
] {
register({
let mut d = ArmInstrDesc::new(*op, mn);
d.operand_types = vec![
ArmOperandType::FPR64,
ArmOperandType::FPR64,
ArmOperandType::FPR64,
];
d.is_aarch64 = true;
d
});
}
ArmInstrInfo {
descriptors,
mnemonic_map,
}
}
pub fn get(&self, opcode: ArmOpcode) -> Option<&ArmInstrDesc> {
self.descriptors.iter().find(|d| d.opcode == opcode)
}
pub fn get_mnemonic(&self, opcode: ArmOpcode) -> &str {
self.get(opcode).map(|d| d.mnemonic).unwrap_or("??")
}
pub fn find_by_mnemonic(&self, name: &str) -> Option<ArmOpcode> {
self.mnemonic_map.get(name).copied()
}
pub fn is_terminator(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.is_terminator).unwrap_or(false)
}
pub fn is_branch(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.is_branch).unwrap_or(false)
}
pub fn is_commutative(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.is_commutative).unwrap_or(false)
}
pub fn may_load(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.may_load).unwrap_or(false)
}
pub fn may_store(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.may_store).unwrap_or(false)
}
pub fn is_call(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.is_call).unwrap_or(false)
}
pub fn is_return(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.is_return).unwrap_or(false)
}
pub fn is_compare(&self, opcode: ArmOpcode) -> bool {
self.get(opcode).map(|d| d.is_compare).unwrap_or(false)
}
pub fn get_aarch64_opcodes(&self) -> Vec<ArmOpcode> {
self.descriptors
.iter()
.filter(|d| d.is_aarch64)
.map(|d| d.opcode)
.collect()
}
pub fn get_arm32_opcodes(&self) -> Vec<ArmOpcode> {
self.descriptors
.iter()
.filter(|d| d.is_arm32)
.map(|d| d.opcode)
.collect()
}
pub fn get_thumb_opcodes(&self) -> Vec<ArmOpcode> {
self.descriptors
.iter()
.filter(|d| d.is_thumb)
.map(|d| d.opcode)
.collect()
}
pub fn len(&self) -> usize {
self.descriptors.len()
}
pub fn is_empty(&self) -> bool {
self.descriptors.is_empty()
}
}
impl Default for ArmInstrInfo {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn info() -> ArmInstrInfo {
ArmInstrInfo::new()
}
#[test]
fn test_table_not_empty() {
let info = info();
assert!(
info.len() > 50,
"expected >50 instructions, got {}",
info.len()
);
}
#[test]
fn test_get_add() {
let info = info();
let desc = info.get(ArmOpcode::ADD).expect("ADD should exist");
assert_eq!(desc.mnemonic, "add");
assert!(!desc.is_terminator);
assert!(desc.is_commutative);
assert!(desc.is_aarch64);
}
#[test]
fn test_get_sub() {
let info = info();
let desc = info.get(ArmOpcode::SUB).expect("SUB should exist");
assert_eq!(desc.mnemonic, "sub");
assert!(!desc.is_terminator);
assert!(!desc.is_commutative);
assert!(desc.is_aarch64);
}
#[test]
fn test_get_branch_aarch64() {
let info = info();
let desc = info.get(ArmOpcode::B).expect("B should exist");
assert_eq!(desc.mnemonic, "b");
assert!(desc.is_terminator);
assert!(desc.is_branch);
assert!(!desc.is_call);
}
#[test]
fn test_get_call_aarch64() {
let info = info();
let desc = info.get(ArmOpcode::BL).expect("BL should exist");
assert_eq!(desc.mnemonic, "bl");
assert!(desc.is_call);
assert!(desc.has_side_effects);
assert!(desc.implicit_defs.contains(&LR));
}
#[test]
fn test_get_ret_aarch64() {
let info = info();
let desc = info.get(ArmOpcode::RET).expect("RET should exist");
assert_eq!(desc.mnemonic, "ret");
assert!(desc.is_terminator);
assert!(desc.is_return);
}
#[test]
fn test_get_load_store() {
let info = info();
assert!(info.may_load(ArmOpcode::LDR));
assert!(!info.may_store(ArmOpcode::LDR));
assert!(info.may_store(ArmOpcode::STR));
assert!(!info.may_load(ArmOpcode::STR));
}
#[test]
fn test_get_compare() {
let info = info();
assert!(info.is_compare(ArmOpcode::CMP));
assert!(info.is_compare(ArmOpcode::ARM_CMP));
assert!(info.is_compare(ArmOpcode::THUMB_CMP));
}
#[test]
fn test_nop() {
let info = info();
let desc = info.get(ArmOpcode::NOP).expect("NOP should exist");
assert_eq!(desc.mnemonic, "nop");
assert!(desc.is_aarch64);
assert!(desc.is_arm32);
assert_eq!(desc.num_operands, 0);
}
#[test]
fn test_get_mnemonic() {
let info = info();
assert_eq!(info.get_mnemonic(ArmOpcode::ADD), "add");
assert_eq!(info.get_mnemonic(ArmOpcode::RET), "ret");
}
#[test]
fn test_find_by_mnemonic() {
let info = info();
assert_eq!(info.find_by_mnemonic("add"), Some(ArmOpcode::ADD));
assert_eq!(info.find_by_mnemonic("bl"), Some(ArmOpcode::BL));
assert_eq!(info.find_by_mnemonic("nonexistent"), None);
}
#[test]
fn test_is_terminator() {
let info = info();
assert!(info.is_terminator(ArmOpcode::B));
assert!(info.is_terminator(ArmOpcode::RET));
assert!(info.is_terminator(ArmOpcode::BR));
assert!(!info.is_terminator(ArmOpcode::ADD));
}
#[test]
fn test_aarch64_vs_arm32_opcodes() {
let info = info();
let a64 = info.get_aarch64_opcodes();
let a32 = info.get_arm32_opcodes();
assert!(!a64.is_empty());
assert!(!a32.is_empty());
assert!(a64.contains(&ArmOpcode::NOP));
assert!(a32.contains(&ArmOpcode::NOP));
}
#[test]
fn test_thumb_opcodes() {
let info = info();
let thumb = info.get_thumb_opcodes();
assert!(!thumb.is_empty());
assert!(thumb.contains(&ArmOpcode::THUMB_ADD));
assert!(thumb.contains(&ArmOpcode::THUMB_B));
assert!(thumb.contains(&ArmOpcode::THUMB_BL));
}
#[test]
fn test_implicit_defs_for_bl() {
let info = info();
let bl = info.get(ArmOpcode::BL).unwrap();
assert!(bl.implicit_defs.contains(&LR));
let blx = info.get(ArmOpcode::ARM_BLX).unwrap();
assert!(blx.implicit_defs.contains(&LR_ARM32));
}
#[test]
fn test_commutative_ops() {
let info = info();
assert!(info.is_commutative(ArmOpcode::ADD));
assert!(info.is_commutative(ArmOpcode::ORR));
assert!(info.is_commutative(ArmOpcode::EOR));
assert!(!info.is_commutative(ArmOpcode::SUB));
assert!(!info.is_commutative(ArmOpcode::ASR));
}
#[test]
fn test_arm32_data_processing() {
let info = info();
assert!(info.get(ArmOpcode::ARM_ADD).is_some());
assert!(info.get(ArmOpcode::ARM_MUL).is_some());
assert!(info.get(ArmOpcode::ARM_CMP).is_some());
let add = info.get(ArmOpcode::ARM_ADD).unwrap();
assert_eq!(add.mnemonic, "add");
assert!(add.is_arm32);
}
#[test]
fn test_arm32_load_store() {
let info = info();
assert!(info.may_load(ArmOpcode::ARM_LDR));
assert!(info.may_store(ArmOpcode::ARM_STR));
let push = info.get(ArmOpcode::ARM_PUSH).unwrap();
assert!(push.may_store);
assert!(push.has_side_effects);
}
#[test]
fn test_neon_ops() {
let info = info();
assert!(info.get(ArmOpcode::ADD_V).is_some());
assert!(info.get(ArmOpcode::FADD).is_some());
assert!(info.get(ArmOpcode::FMUL).is_some());
assert!(info.get(ArmOpcode::DUP).is_some());
}
#[test]
fn test_operand_types() {
let info = info();
let add = info.get(ArmOpcode::ADD).unwrap();
assert_eq!(add.operand_types.len(), 3);
assert_eq!(add.operand_types[0], ArmOperandType::GPR64);
let fadd = info.get(ArmOpcode::FADD).unwrap();
assert_eq!(fadd.operand_types[0], ArmOperandType::FPR64);
}
#[test]
fn test_compare_implicit_defs_nzcv() {
let info = info();
let cmp = info.get(ArmOpcode::CMP).unwrap();
assert!(cmp.implicit_defs.contains(&NZCV));
let arm_cmp = info.get(ArmOpcode::ARM_CMP).unwrap();
assert!(arm_cmp.implicit_defs.contains(&CPSR));
}
#[test]
fn test_mov_variants() {
let info = info();
let mov = info.get(ArmOpcode::MOV).unwrap();
assert!(mov.is_move_imm);
let movz = info.get(ArmOpcode::MOVZ).unwrap();
assert!(movz.is_move_imm);
}
#[test]
fn test_find_by_mnemonic_arm32() {
let info = info();
assert_eq!(info.find_by_mnemonic("push"), Some(ArmOpcode::ARM_PUSH));
assert_eq!(info.find_by_mnemonic("pop"), Some(ArmOpcode::ARM_POP));
}
#[test]
fn test_find_by_mnemonic_thumb() {
let info = info();
assert_eq!(info.find_by_mnemonic("b"), Some(ArmOpcode::B)); }
#[test]
fn test_terminator_branch_relationship() {
let info = info();
for opcode in info.get_aarch64_opcodes() {
if info.is_terminator(opcode) {
assert!(
info.is_branch(opcode),
"terminator {:?} should also be a branch",
opcode
);
}
}
}
#[test]
fn test_call_has_side_effects() {
let info = info();
for opcode in &[ArmOpcode::BL, ArmOpcode::BLR] {
let desc = info.get(*opcode).unwrap();
assert!(
desc.has_side_effects,
"call {:?} should have side effects",
opcode
);
}
}
#[test]
fn test_load_store_mutually_exclusive() {
let info = info();
for opcode in info.get_aarch64_opcodes() {
if !matches!(opcode, ArmOpcode::NOP | ArmOpcode::INVALID) {
let may_load = info.may_load(opcode);
let may_store = info.may_store(opcode);
assert!(
!(may_load && may_store) || opcode == ArmOpcode::INVALID,
"{:?} can't both load and store",
opcode
);
}
}
}
#[test]
fn test_system_instructions() {
let info = info();
assert!(info.get(ArmOpcode::SVC).unwrap().has_side_effects);
assert!(info.get(ArmOpcode::BRK).unwrap().has_side_effects);
assert!(info.get(ArmOpcode::ISB).unwrap().has_side_effects);
assert!(info.get(ArmOpcode::MSR).unwrap().has_side_effects);
}
#[test]
fn test_pair_load_store() {
let info = info();
let ldp = info.get(ArmOpcode::LDP).unwrap();
assert!(ldp.may_load);
assert!(!ldp.may_store);
assert_eq!(ldp.operand_types.len(), 3);
let stp = info.get(ArmOpcode::STP).unwrap();
assert!(stp.may_store);
assert!(!stp.may_load);
}
#[test]
fn test_operand_count_matches() {
let info = info();
for desc in &info.descriptors {
assert_eq!(
desc.num_operands as usize,
desc.operand_types.len(),
"{}: num_operands mismatch",
desc.mnemonic
);
}
}
#[test]
fn test_default_is_valid() {
let info = ArmInstrInfo::default();
assert!(!info.is_empty());
assert!(info.get(ArmOpcode::ADD).is_some());
}
}