//! This library provides structures and enums for describing
//! AArch64 (ARMv8) instructions.

#![no_std]

pub mod defn;

#[cfg(feature = "std")]
pub mod deser;

#[cfg(feature = "std")]
mod test;

#[cfg(feature = "std")]
extern crate std;

use bitflags::bitflags;
use serde::Deserialize;
use serde::Serialize;
use strum_macros::EnumIter;

#[cfg(feature = "std")]
use strum::IntoEnumIterator;
use strum_macros::IntoStaticStr;

/// The AArch64 instruction classes.
#[allow(non_camel_case_types)]
#[derive(
    Debug, PartialEq, Eq, Clone, Copy, Hash, EnumIter, Serialize, Deserialize, IntoStaticStr,
)]
pub enum InsnClass {
    AARCH64_MISC,
    ADDSUB_CARRY,
    ADDSUB_EXT,
    ADDSUB_IMM,
    ADDSUB_SHIFT,
    ASIMDALL,
    ASIMDDIFF,
    ASIMDELEM,
    ASIMDEXT,
    ASIMDIMM,
    ASIMDINS,
    ASIMDMISC,
    ASIMDPERM,
    ASIMDSAME,
    ASIMDSHF,
    ASIMDTBL,
    ASISDDIFF,
    ASISDELEM,
    ASISDLSE,
    ASISDLSEP,
    ASISDLSO,
    ASISDLSOP,
    ASISDMISC,
    ASISDONE,
    ASISDPAIR,
    ASISDSAME,
    ASISDSHF,
    BFLOAT16,
    BITFIELD,
    BRANCH_IMM,
    BRANCH_REG,
    COMPBRANCH,
    CONDBRANCH,
    CONDCMP_IMM,
    CONDCMP_REG,
    CONDSEL,
    CRYPTOAES,
    CRYPTOSHA2,
    CRYPTOSHA3,
    CRYPTOSM3,
    CRYPTOSM4,
    CSSC,
    DOTPRODUCT,
    DP_1SRC,
    DP_2SRC,
    DP_3SRC,
    EXCEPTION,
    EXTRACT,
    FLOAT2FIX,
    FLOAT2INT,
    FLOATCCMP,
    FLOATCMP,
    FLOATDP1,
    FLOATDP2,
    FLOATDP3,
    FLOATIMM,
    FLOATSEL,
    GCS,
    IC_SYSTEM,
    LDST_IMM10,
    LDST_IMM9,
    LDST_POS,
    LDST_REGOFF,
    LDST_UNPRIV,
    LDST_UNSCALED,
    LDSTEXCL,
    LDSTNAPAIR_OFFS,
    LDSTPAIR_INDEXED,
    LDSTPAIR_OFF,
    LOADLIT,
    LOG_IMM,
    LOG_SHIFT,
    LSE_ATOMIC,
    LSE128_ATOMIC,
    MOVEWIDE,
    PCRELADDR,
    RCPC3,
    SME_FP_SD,
    SME_INT_SD,
    SME_LDR,
    SME_MISC,
    SME_MOV,
    SME_PSEL,
    SME_SHIFT,
    SME_SIZE_12_BHS,
    SME_SIZE_12_HS,
    SME_SIZE_22_HSD,
    SME_SIZE_22,
    SME_START,
    SME_STOP,
    SME_STR,
    SME_SZ_23,
    SME2_MOV,
    SME2_MOVAZ,
    SVE_CPY,
    SVE_INDEX,
    SVE_INDEX1,
    SVE_LIMM,
    SVE_MISC,
    SVE_MOVPRFX,
    SVE_PRED_ZM,
    SVE_SHIFT_PRED,
    SVE_SHIFT_TSZ_BHSD,
    SVE_SHIFT_TSZ_HSD,
    SVE_SHIFT_UNPRED,
    SVE_SIZE_13,
    SVE_SIZE_BH,
    SVE_SIZE_BHS,
    SVE_SIZE_BHSD,
    SVE_SIZE_HSD,
    SVE_SIZE_HSD2,
    SVE_SIZE_SD,
    SVE_SIZE_SD2,
    SVE_SIZE_TSZ_BHS,
    SVE2_URQVS,
    TESTBRANCH,
    THE,
}

#[cfg(feature = "std")]
impl std::str::FromStr for InsnClass {
    type Err = std::string::String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let s = s.to_uppercase();
        let s = s.as_str();
        match s {
            "AARCH64_MISC" => Ok(InsnClass::AARCH64_MISC),
            "ADDSUB_CARRY" => Ok(InsnClass::ADDSUB_CARRY),
            "ADDSUB_EXT" => Ok(InsnClass::ADDSUB_EXT),
            "ADDSUB_IMM" => Ok(InsnClass::ADDSUB_IMM),
            "ADDSUB_SHIFT" => Ok(InsnClass::ADDSUB_SHIFT),
            "ASIMDALL" => Ok(InsnClass::ASIMDALL),
            "ASIMDDIFF" => Ok(InsnClass::ASIMDDIFF),
            "ASIMDELEM" => Ok(InsnClass::ASIMDELEM),
            "ASIMDEXT" => Ok(InsnClass::ASIMDEXT),
            "ASIMDIMM" => Ok(InsnClass::ASIMDIMM),
            "ASIMDINS" => Ok(InsnClass::ASIMDINS),
            "ASIMDMISC" => Ok(InsnClass::ASIMDMISC),
            "ASIMDPERM" => Ok(InsnClass::ASIMDPERM),
            "ASIMDSAME" => Ok(InsnClass::ASIMDSAME),
            "ASIMDSHF" => Ok(InsnClass::ASIMDSHF),
            "ASIMDTBL" => Ok(InsnClass::ASIMDTBL),
            "ASISDDIFF" => Ok(InsnClass::ASISDDIFF),
            "ASISDELEM" => Ok(InsnClass::ASISDELEM),
            "ASISDLSE" => Ok(InsnClass::ASISDLSE),
            "ASISDLSEP" => Ok(InsnClass::ASISDLSEP),
            "ASISDLSO" => Ok(InsnClass::ASISDLSO),
            "ASISDLSOP" => Ok(InsnClass::ASISDLSOP),
            "ASISDMISC" => Ok(InsnClass::ASISDMISC),
            "ASISDONE" => Ok(InsnClass::ASISDONE),
            "ASISDPAIR" => Ok(InsnClass::ASISDPAIR),
            "ASISDSAME" => Ok(InsnClass::ASISDSAME),
            "ASISDSHF" => Ok(InsnClass::ASISDSHF),
            "BFLOAT16" => Ok(InsnClass::BFLOAT16),
            "BITFIELD" => Ok(InsnClass::BITFIELD),
            "BRANCH_IMM" => Ok(InsnClass::BRANCH_IMM),
            "BRANCH_REG" => Ok(InsnClass::BRANCH_REG),
            "COMPBRANCH" => Ok(InsnClass::COMPBRANCH),
            "CONDBRANCH" => Ok(InsnClass::CONDBRANCH),
            "CONDCMP_IMM" => Ok(InsnClass::CONDCMP_IMM),
            "CONDCMP_REG" => Ok(InsnClass::CONDCMP_REG),
            "CONDSEL" => Ok(InsnClass::CONDSEL),
            "CRYPTOAES" => Ok(InsnClass::CRYPTOAES),
            "CRYPTOSHA2" => Ok(InsnClass::CRYPTOSHA2),
            "CRYPTOSHA3" => Ok(InsnClass::CRYPTOSHA3),
            "CRYPTOSM3" => Ok(InsnClass::CRYPTOSM3),
            "CRYPTOSM4" => Ok(InsnClass::CRYPTOSM4),
            "CSSC" => Ok(InsnClass::CSSC),
            "DOTPRODUCT" => Ok(InsnClass::DOTPRODUCT),
            "DP_1SRC" => Ok(InsnClass::DP_1SRC),
            "DP_2SRC" => Ok(InsnClass::DP_2SRC),
            "DP_3SRC" => Ok(InsnClass::DP_3SRC),
            "EXCEPTION" => Ok(InsnClass::EXCEPTION),
            "EXTRACT" => Ok(InsnClass::EXTRACT),
            "FLOAT2FIX" => Ok(InsnClass::FLOAT2FIX),
            "FLOAT2INT" => Ok(InsnClass::FLOAT2INT),
            "FLOATCCMP" => Ok(InsnClass::FLOATCCMP),
            "FLOATCMP" => Ok(InsnClass::FLOATCMP),
            "FLOATDP1" => Ok(InsnClass::FLOATDP1),
            "FLOATDP2" => Ok(InsnClass::FLOATDP2),
            "FLOATDP3" => Ok(InsnClass::FLOATDP3),
            "FLOATIMM" => Ok(InsnClass::FLOATIMM),
            "FLOATSEL" => Ok(InsnClass::FLOATSEL),
            "GCS" => Ok(InsnClass::GCS),
            "IC_SYSTEM" => Ok(InsnClass::IC_SYSTEM),
            "LDST_IMM10" => Ok(InsnClass::LDST_IMM10),
            "LDST_IMM9" => Ok(InsnClass::LDST_IMM9),
            "LDST_POS" => Ok(InsnClass::LDST_POS),
            "LDST_REGOFF" => Ok(InsnClass::LDST_REGOFF),
            "LDST_UNPRIV" => Ok(InsnClass::LDST_UNPRIV),
            "LDST_UNSCALED" => Ok(InsnClass::LDST_UNSCALED),
            "LDSTEXCL" => Ok(InsnClass::LDSTEXCL),
            "LDSTNAPAIR_OFFS" => Ok(InsnClass::LDSTNAPAIR_OFFS),
            "LDSTPAIR_INDEXED" => Ok(InsnClass::LDSTPAIR_INDEXED),
            "LDSTPAIR_OFF" => Ok(InsnClass::LDSTPAIR_OFF),
            "LOADLIT" => Ok(InsnClass::LOADLIT),
            "LOG_IMM" => Ok(InsnClass::LOG_IMM),
            "LOG_SHIFT" => Ok(InsnClass::LOG_SHIFT),
            "LSE_ATOMIC" => Ok(InsnClass::LSE_ATOMIC),
            "LSE128_ATOMIC" => Ok(InsnClass::LSE128_ATOMIC),
            "MOVEWIDE" => Ok(InsnClass::MOVEWIDE),
            "PCRELADDR" => Ok(InsnClass::PCRELADDR),
            "RCPC3" => Ok(InsnClass::RCPC3),
            "SME_FP_SD" => Ok(InsnClass::SME_FP_SD),
            "SME_INT_SD" => Ok(InsnClass::SME_INT_SD),
            "SME_LDR" => Ok(InsnClass::SME_LDR),
            "SME_MISC" => Ok(InsnClass::SME_MISC),
            "SME_MOV" => Ok(InsnClass::SME_MOV),
            "SME_PSEL" => Ok(InsnClass::SME_PSEL),
            "SME_SHIFT" => Ok(InsnClass::SME_SHIFT),
            "SME_SIZE_12_BHS" => Ok(InsnClass::SME_SIZE_12_BHS),
            "SME_SIZE_12_HS" => Ok(InsnClass::SME_SIZE_12_HS),
            "SME_SIZE_22_HSD" => Ok(InsnClass::SME_SIZE_22_HSD),
            "SME_SIZE_22" => Ok(InsnClass::SME_SIZE_22),
            "SME_START" => Ok(InsnClass::SME_START),
            "SME_STOP" => Ok(InsnClass::SME_STOP),
            "SME_STR" => Ok(InsnClass::SME_STR),
            "SME_SZ_23" => Ok(InsnClass::SME_SZ_23),
            "SME2_MOV" => Ok(InsnClass::SME2_MOV),
            "SME2_MOVAZ" => Ok(InsnClass::SME2_MOVAZ),
            "SVE_CPY" => Ok(InsnClass::SVE_CPY),
            "SVE_INDEX" => Ok(InsnClass::SVE_INDEX),
            "SVE_INDEX1" => Ok(InsnClass::SVE_INDEX1),
            "SVE_LIMM" => Ok(InsnClass::SVE_LIMM),
            "SVE_MISC" => Ok(InsnClass::SVE_MISC),
            "SVE_MOVPRFX" => Ok(InsnClass::SVE_MOVPRFX),
            "SVE_PRED_ZM" => Ok(InsnClass::SVE_PRED_ZM),
            "SVE_SHIFT_PRED" => Ok(InsnClass::SVE_SHIFT_PRED),
            "SVE_SHIFT_TSZ_BHSD" => Ok(InsnClass::SVE_SHIFT_TSZ_BHSD),
            "SVE_SHIFT_TSZ_HSD" => Ok(InsnClass::SVE_SHIFT_TSZ_HSD),
            "SVE_SHIFT_UNPRED" => Ok(InsnClass::SVE_SHIFT_UNPRED),
            "SVE_SIZE_13" => Ok(InsnClass::SVE_SIZE_13),
            "SVE_SIZE_BH" => Ok(InsnClass::SVE_SIZE_BH),
            "SVE_SIZE_BHS" => Ok(InsnClass::SVE_SIZE_BHS),
            "SVE_SIZE_BHSD" => Ok(InsnClass::SVE_SIZE_BHSD),
            "SVE_SIZE_HSD" => Ok(InsnClass::SVE_SIZE_HSD),
            "SVE_SIZE_HSD2" => Ok(InsnClass::SVE_SIZE_HSD2),
            "SVE_SIZE_SD" => Ok(InsnClass::SVE_SIZE_SD),
            "SVE_SIZE_SD2" => Ok(InsnClass::SVE_SIZE_SD2),
            "SVE_SIZE_TSZ_BHS" => Ok(InsnClass::SVE_SIZE_TSZ_BHS),
            "SVE2_URQVS" => Ok(InsnClass::SVE2_URQVS),
            "TESTBRANCH" => Ok(InsnClass::TESTBRANCH),
            "THE" => Ok(InsnClass::THE),

            _ => {
                let mut names = std::vec::Vec::new();
                for i in InsnClass::iter() {
                    names.push(i);
                }
                Err(std::format!("expected a subset of {names:?}"))
            }
        }
    }
}

impl core::fmt::Display for InsnClass {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// The AArch64 instruction feature sets.
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, EnumIter, Serialize, Deserialize)]
#[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
pub enum InsnFeatureSet {
    AES,
    B16B16,
    BFLOAT16,
    BFLOAT16_SVE,
    CHK,
    COMPNUM,
    CRC,
    CSSC,
    D128,
    D128_THE,
    DOTPROD,
    F32MM_SVE,
    F64MM_SVE,
    FLAGM,
    FLAGMANIP,
    FP,
    FP_16_V8_2A,
    FP_F16,
    FRINTTS,
    GCS,
    HBC,
    I8MM,
    I8MM_SVE,
    ITE,
    JSCVT,
    LOR,
    LS64,
    LSE,
    LSE128,
    MEMTAG,
    MOPS,
    MOPS_MEMTAG,
    PAC,
    PREDRES,
    PREDRES2,
    RCPC,
    RCPC2,
    RCPC3,
    RDMA,
    SB,
    SHA2,
    SHA3,
    SIMD,
    SIMD_F16,
    SM4,
    SME,
    SME2,
    SME2P1,
    SME2_F64F64,
    SME2_I16I64,
    SME_F64F64,
    SME_I16I64,
    SVE,
    SVE2,
    SVE2AES,
    SVE2BITPERM,
    SVE2P1,
    SVE2SHA3,
    SVE2SM4,
    THE,
    TME,
    V8,
    V8R,
    WFXT,
    XS,
}

#[cfg(feature = "std")]
impl std::str::FromStr for InsnFeatureSet {
    type Err = std::string::String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let s = s.to_uppercase();
        let s = s.as_str();
        match s {
            "AES" => Ok(InsnFeatureSet::AES),
            "B16B16" => Ok(InsnFeatureSet::B16B16),
            "BFLOAT16" => Ok(InsnFeatureSet::BFLOAT16),
            "BFLOAT16_SVE" => Ok(InsnFeatureSet::BFLOAT16_SVE),
            "CHK" => Ok(InsnFeatureSet::CHK),
            "COMPNUM" => Ok(InsnFeatureSet::COMPNUM),
            "CRC" => Ok(InsnFeatureSet::CRC),
            "CSSC" => Ok(InsnFeatureSet::CSSC),
            "D128" => Ok(InsnFeatureSet::D128),
            "D128_THE" => Ok(InsnFeatureSet::D128_THE),
            "DOTPROD" => Ok(InsnFeatureSet::DOTPROD),
            "F32MM_SVE" => Ok(InsnFeatureSet::F32MM_SVE),
            "F64MM_SVE" => Ok(InsnFeatureSet::F64MM_SVE),
            "FLAGM" => Ok(InsnFeatureSet::FLAGM),
            "FLAGMANIP" => Ok(InsnFeatureSet::FLAGMANIP),
            "FP" => Ok(InsnFeatureSet::FP),
            "FP_16_V8_2A" => Ok(InsnFeatureSet::FP_16_V8_2A),
            "FP_F16" => Ok(InsnFeatureSet::FP_F16),
            "FRINTTS" => Ok(InsnFeatureSet::FRINTTS),
            "GCS" => Ok(InsnFeatureSet::GCS),
            "HBC" => Ok(InsnFeatureSet::HBC),
            "I8MM" => Ok(InsnFeatureSet::I8MM),
            "I8MM_SVE" => Ok(InsnFeatureSet::I8MM_SVE),
            "ITE" => Ok(InsnFeatureSet::ITE),
            "JSCVT" => Ok(InsnFeatureSet::JSCVT),
            "LOR" => Ok(InsnFeatureSet::LOR),
            "LS64" => Ok(InsnFeatureSet::LS64),
            "LSE" => Ok(InsnFeatureSet::LSE),
            "LSE128" => Ok(InsnFeatureSet::LSE128),
            "MEMTAG" => Ok(InsnFeatureSet::MEMTAG),
            "MOPS" => Ok(InsnFeatureSet::MOPS),
            "MOPS_MEMTAG" => Ok(InsnFeatureSet::MOPS_MEMTAG),
            "PAC" => Ok(InsnFeatureSet::PAC),
            "PREDRES" => Ok(InsnFeatureSet::PREDRES),
            "PREDRES2" => Ok(InsnFeatureSet::PREDRES2),
            "RCPC" => Ok(InsnFeatureSet::RCPC),
            "RCPC2" => Ok(InsnFeatureSet::RCPC2),
            "RCPC3" => Ok(InsnFeatureSet::RCPC3),
            "RDMA" => Ok(InsnFeatureSet::RDMA),
            "SB" => Ok(InsnFeatureSet::SB),
            "SHA2" => Ok(InsnFeatureSet::SHA2),
            "SHA3" => Ok(InsnFeatureSet::SHA3),
            "SIMD" => Ok(InsnFeatureSet::SIMD),
            "SIMD_F16" => Ok(InsnFeatureSet::SIMD_F16),
            "SM4" => Ok(InsnFeatureSet::SM4),
            "SME" => Ok(InsnFeatureSet::SME),
            "SME2" => Ok(InsnFeatureSet::SME2),
            "SME2P1" => Ok(InsnFeatureSet::SME2P1),
            "SME2_F64F64" => Ok(InsnFeatureSet::SME2_F64F64),
            "SME2_I16I64" => Ok(InsnFeatureSet::SME2_I16I64),
            "SME_F64F64" => Ok(InsnFeatureSet::SME_F64F64),
            "SME_I16I64" => Ok(InsnFeatureSet::SME_I16I64),
            "SVE" => Ok(InsnFeatureSet::SVE),
            "SVE2" => Ok(InsnFeatureSet::SVE2),
            "SVE2AES" => Ok(InsnFeatureSet::SVE2AES),
            "SVE2BITPERM" => Ok(InsnFeatureSet::SVE2BITPERM),
            "SVE2P1" => Ok(InsnFeatureSet::SVE2P1),
            "SVE2SHA3" => Ok(InsnFeatureSet::SVE2SHA3),
            "SVE2SM4" => Ok(InsnFeatureSet::SVE2SM4),
            "THE" => Ok(InsnFeatureSet::THE),
            "TME" => Ok(InsnFeatureSet::TME),
            "V8" => Ok(InsnFeatureSet::V8),
            "V8R" => Ok(InsnFeatureSet::V8R),
            "WFXT" => Ok(InsnFeatureSet::WFXT),
            "XS" => Ok(InsnFeatureSet::XS),

            _ => {
                let mut names = std::vec::Vec::new();
                for i in InsnFeatureSet::iter() {
                    names.push(i);
                }
                Err(std::format!("expected a subset of {names:?}"))
            }
        }
    }
}

impl core::fmt::Display for InsnFeatureSet {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "{:?}", self)
    }
}

bitflags! {
    /// The AArch64 instruction flags.
    #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, Serialize, Deserialize)]
    pub struct InsnFlags : u64 {
        const HAS_ADVSIMD_SCALAR_SIZE = 1 << 0;
        const HAS_ADVSIMV_GPRSIZE_IN_Q = 1 << 1;
        const HAS_ADVSIMV_VEC_IN_Q = 1 << 2;
        const HAS_ALIAS = 1 << 3;
        const HAS_FPTYPE_FIELD = 1 << 4;
        const HAS_LDS_SIZE_IN_BIT_22 = 1 << 5;
        const HAS_LSE_SZ_FIELD = 1 << 6;
        const HAS_NARROW = 1 << 7;
        const HAS_N_FIELD = 1 << 8;
        const HAS_OPCODE_DEPENDENT_FIELD_1 = 1 << 9;
        const HAS_OPCODE_DEPENDENT_FIELD_2 = 1 << 10;
        const HAS_OPCODE_DEPENDENT_FIELD_3 = 1 << 11;
        const HAS_OPCODE_DEPENDENT_FIELD_4 = 1 << 12;
        const HAS_OPCODE_DEPENDENT_FIELD_5 = 1 << 13;
        const HAS_OPCODE_DEPENDENT_FIELD_6 = 1 << 14;
        const HAS_OPCODE_DEPENDENT_FIELD_7 = 1 << 15;
        const HAS_RCPC3_SIZE = 1 << 16;
        const HAS_SF_FIELD = 1 << 17;
        const HAS_SIZE = 1 << 18;
        const HAS_SIZEQ_FIELD = 1 << 19;
        const HAS_SPEC_DECODE_RULES = 1 << 20;
        const IS_ALIAS = 1 << 21;
        const IS_COND = 1 << 22;
        const IS_SYS_READ = 1 << 23;
        const IS_SYS_WRITE = 1 << 24;
        const RESTRICTED_NEXT_INSN_SET = 1 << 25;
    }
}

impl InsnFlags {
    pub const fn const_from_bits(b: u64) -> InsnFlags {
        // TODO: waiting for Option<T>::unwrap_or_else to be const
        unsafe { core::mem::transmute(b) }
    }
}

/// The AArch64 instruction operand kinds.
#[derive(
    Debug, PartialEq, Eq, Copy, Clone, Hash, EnumIter, Serialize, Deserialize, IntoStaticStr,
)]
#[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
pub enum InsnOperandKind {
    ADDR_ADRP,
    ADDR_OFFSET,
    ADDR_PCREL14,
    ADDR_PCREL19,
    ADDR_PCREL21,
    ADDR_PCREL26,
    ADDR_REGOFF,
    ADDR_SIMM10,
    ADDR_SIMM11,
    ADDR_SIMM13,
    ADDR_SIMM7,
    ADDR_SIMM9,
    ADDR_SIMPLE,
    ADDR_UIMM12,
    AIMM,
    BARRIER_DSB_NXS,
    BARRIER_GCSB,
    BARRIER_ISB,
    BARRIER_PSB,
    BARRIER,
    BIT_NUM,
    BTI_TARGET,
    CCMP_IMM,
    COND,
    COND1,
    CRm,
    CRn,
    CSSC_SIMM8,
    CSSC_UIMM8,
    Ed,
    Em,
    Em16,
    En,
    EXCEPTION,
    Fa,
    FBITS,
    Fd,
    Fm,
    Fn,
    FPIMM,
    FPIMM0,
    Ft,
    Ft2,
    HALF,
    IDX,
    IMM_2,
    IMM_MOV,
    IMM_ROT1,
    IMM_ROT2,
    IMM_ROT3,
    IMM_VLSL,
    IMM_VLSR,
    IMM,
    IMM0,
    IMMR,
    IMMS,
    LEt,
    LIMM,
    LSE128_Rt,
    LSE128_Rt2,
    LVn,
    LVt_AL,
    LVt,
    MASK,
    MOPS_ADDR_Rd,
    MOPS_ADDR_Rs,
    MOPS_WB_Rn,
    NZCV,
    PAIRREG_OR_XZR,
    PAIRREG,
    PRFOP,
    PSTATEFIELD,
    Ra,
    RCPC3_ADDR_OFFSET,
    RCPC3_ADDR_OPT_POSTIND,
    RCPC3_ADDR_OPT_PREIND_WB,
    RCPC3_ADDR_POSTIND,
    RCPC3_ADDR_PREIND_WB,
    Rd_SP,
    Rd,
    Rm_EXT,
    Rm_SFT,
    Rm_SP,
    Rm,
    Rn_SP,
    Rn,
    RPRFMOP,
    Rs,
    Rt_LS64,
    Rt_SP,
    Rt_SYS,
    Rt,
    Rt2,
    Sd,
    SHLL_IMM,
    SIMD_ADDR_POST,
    SIMD_ADDR_SIMPLE,
    SIMD_FPIMM,
    SIMD_IMM_SFT,
    SIMD_IMM,
    SIMM5,
    Sm,
    SME_ADDR_RI_U4xVL,
    SME_list_of_64bit_tiles,
    SME_Pdx2,
    SME_PdxN,
    SME_Pm,
    SME_PNd3,
    SME_PNg3,
    SME_PNn,
    SME_PNn3_INDEX1,
    SME_PNn3_INDEX2,
    SME_PnT_Wm_imm,
    SME_SHRIMM4,
    SME_SHRIMM5,
    SME_SM_ZA,
    SME_VLxN_10,
    SME_VLxN_13,
    SME_ZA_array_off1x4,
    SME_ZA_array_off2x2,
    SME_ZA_array_off2x4,
    SME_ZA_array_off3_0,
    SME_ZA_array_off3_5,
    SME_ZA_array_off3x2,
    SME_ZA_array_off4,
    SME_ZA_array_vrsb_1,
    SME_ZA_array_vrsb_2,
    SME_ZA_array_vrsd_1,
    SME_ZA_array_vrsd_2,
    SME_ZA_array_vrsh_1,
    SME_ZA_array_vrsh_2,
    SME_ZA_array_vrss_1,
    SME_ZA_array_vrss_2,
    SME_ZA_HV_idx_dest,
    SME_ZA_HV_idx_destxN,
    SME_ZA_HV_idx_ldstr,
    SME_ZA_HV_idx_src,
    SME_ZA_HV_idx_srcxN,
    SME_ZAda_2b,
    SME_ZAda_3b,
    SME_Zdnx2,
    SME_Zdnx4,
    SME_Zm_INDEX1,
    SME_Zm_INDEX2,
    SME_Zm_INDEX3_1,
    SME_Zm_INDEX3_10,
    SME_Zm_INDEX3_2,
    SME_Zm_INDEX4_1,
    SME_Zm_INDEX4_10,
    SME_Zm,
    SME_Zmx2,
    SME_Zmx4,
    SME_Zn_INDEX1_16,
    SME_Zn_INDEX2_15,
    SME_Zn_INDEX2_16,
    SME_Zn_INDEX3_14,
    SME_Zn_INDEX3_15,
    SME_Zn_INDEX4_14,
    SME_Znx2,
    SME_Znx4,
    SME_ZT0_INDEX,
    SME_ZT0_LIST,
    SME_ZT0,
    SME_Zt2,
    SME_Zt3,
    SME_Zt4,
    SME_Ztx2_STRIDED,
    SME_Ztx4_STRIDED,
    Sn,
    SVE_ADDR_R,
    SVE_ADDR_RI_S4x16,
    SVE_ADDR_RI_S4x2xVL,
    SVE_ADDR_RI_S4x32,
    SVE_ADDR_RI_S4x3xVL,
    SVE_ADDR_RI_S4x4xVL,
    SVE_ADDR_RI_S4xVL,
    SVE_ADDR_RI_S6xVL,
    SVE_ADDR_RI_S9xVL,
    SVE_ADDR_RI_U6,
    SVE_ADDR_RI_U6x2,
    SVE_ADDR_RI_U6x4,
    SVE_ADDR_RI_U6x8,
    SVE_ADDR_RR_LSL1,
    SVE_ADDR_RR_LSL2,
    SVE_ADDR_RR_LSL3,
    SVE_ADDR_RR_LSL4,
    SVE_ADDR_RR,
    SVE_ADDR_RX_LSL1,
    SVE_ADDR_RX_LSL2,
    SVE_ADDR_RX_LSL3,
    SVE_ADDR_RX,
    SVE_ADDR_RZ_LSL1,
    SVE_ADDR_RZ_LSL2,
    SVE_ADDR_RZ_LSL3,
    SVE_ADDR_RZ_XTW_14,
    SVE_ADDR_RZ_XTW_22,
    SVE_ADDR_RZ_XTW1_14,
    SVE_ADDR_RZ_XTW1_22,
    SVE_ADDR_RZ_XTW2_14,
    SVE_ADDR_RZ_XTW2_22,
    SVE_ADDR_RZ_XTW3_14,
    SVE_ADDR_RZ_XTW3_22,
    SVE_ADDR_RZ,
    SVE_ADDR_ZI_U5,
    SVE_ADDR_ZI_U5x2,
    SVE_ADDR_ZI_U5x4,
    SVE_ADDR_ZI_U5x8,
    SVE_ADDR_ZX,
    SVE_ADDR_ZZ_LSL,
    SVE_ADDR_ZZ_SXTW,
    SVE_ADDR_ZZ_UXTW,
    SVE_AIMM,
    SVE_ASIMM,
    SVE_FPIMM8,
    SVE_I1_HALF_ONE,
    SVE_I1_HALF_TWO,
    SVE_I1_ZERO_ONE,
    SVE_IMM_ROT1,
    SVE_IMM_ROT2,
    SVE_IMM_ROT3,
    SVE_INV_LIMM,
    SVE_LIMM_MOV,
    SVE_LIMM,
    SVE_PATTERN_SCALED,
    SVE_PATTERN,
    SVE_Pd,
    SVE_Pg3,
    SVE_Pg4_10,
    SVE_Pg4_16,
    SVE_Pg4_5,
    SVE_Pm,
    SVE_Pn,
    SVE_PNd,
    SVE_PNg4_10,
    SVE_PNn,
    SVE_PNt,
    SVE_PRFOP,
    SVE_Pt,
    SVE_Rm,
    SVE_Rn_SP,
    SVE_SHLIMM_PRED,
    SVE_SHLIMM_UNPRED_22,
    SVE_SHLIMM_UNPRED,
    SVE_SHRIMM_PRED,
    SVE_SHRIMM_UNPRED_22,
    SVE_SHRIMM_UNPRED,
    SVE_SIMM5,
    SVE_SIMM5B,
    SVE_SIMM6,
    SVE_SIMM8,
    SVE_UIMM3,
    SVE_UIMM7,
    SVE_UIMM8_53,
    SVE_UIMM8,
    SVE_Vd,
    SVE_Vm,
    SVE_Vn,
    SVE_VZn,
    SVE_Za_16,
    SVE_Za_5,
    SVE_Zd,
    SVE_Zm_16,
    SVE_Zm_5,
    SVE_Zm_imm4,
    SVE_Zm3_11_INDEX,
    SVE_Zm3_19_INDEX,
    SVE_Zm3_22_INDEX,
    SVE_Zm3_INDEX,
    SVE_Zm4_11_INDEX,
    SVE_Zm4_INDEX,
    SVE_Zn_5_INDEX,
    SVE_Zn_INDEX,
    SVE_Zn,
    SVE_ZnxN,
    SVE_Zt,
    SVE_ZtxN,
    SYSREG_AT,
    SYSREG_DC,
    SYSREG_IC,
    SYSREG_SR,
    SYSREG_TLBI,
    SYSREG_TLBIP,
    SYSREG,
    SYSREG128,
    TME_UIMM16,
    UIMM10,
    UIMM3_OP1,
    UIMM3_OP2,
    UIMM4_ADDG,
    UIMM4,
    UIMM7,
    UNDEFINED,
    Va,
    Vd,
    VdD1,
    Vm,
    Vn,
    VnD1,
    WIDTH,
    X16,
}

/// The AArch64 instruction operand classes.
#[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
#[derive(
    Debug, PartialEq, Eq, Clone, Copy, Hash, EnumIter, Serialize, Deserialize, IntoStaticStr,
)]
pub enum InsnOperandClass {
    ADDRESS,
    COND,
    FP_REG,
    IMMEDIATE,
    INT_REG,
    MODIFIED_REG,
    PRED_REG,
    SIMD_ELEMENT,
    SIMD_REG,
    SIMD_REGLIST,
    SISD_REG,
    SVE_REG,
    SVE_REGLIST,
    SYSTEM,
    ZA_ACCESS,
}

/// The AArch64 instruction operand qualifiers.
#[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, EnumIter, Serialize, Deserialize)]
pub enum InsnOperandQualifier {
    imm_0_15,
    imm_0_31,
    imm_0_63,
    imm_0_7,
    imm_1_32,
    imm_1_64,
    imm_tag,
    LSL,
    MSL,
    P_M,
    P_Z,
    S_2H,
    S_4B,
    S_B,
    S_D,
    S_H,
    S_Q,
    S_S,
    V_16B,
    V_1D,
    V_1Q,
    V_2D,
    V_2H,
    V_2S,
    V_4H,
    V_4S,
    V_8B,
    V_8H,
    W,
    WSP,
    X,
    SP,
}

/// The AArch64 instruction bit fields.
#[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, EnumIter, Serialize, Deserialize)]
pub enum InsnBitField {
    b40,
    b5,
    cond,
    CRm,
    CRn,
    CSSC_imm8,
    imm1_0,
    imm1_10,
    imm1_15,
    imm1_16,
    imm1_2,
    imm1_8,
    imm12,
    imm14,
    imm16_0,
    imm16_5,
    imm19,
    imm2_0,
    imm2_1,
    imm2_10,
    imm2_12,
    imm2_15,
    imm2_16,
    imm2_19,
    imm2_8,
    imm26,
    imm3_0,
    imm3_10,
    imm3_12,
    imm3_14,
    imm3_15,
    imm3_5,
    imm4_0,
    imm4_10,
    imm4_11,
    imm4_14,
    imm4_5,
    imm5,
    imm6_10,
    imm6_15,
    imm7,
    imm8,
    imm9,
    immhi,
    immlo,
    immr,
    imms,
    index,
    index2,
    LSE128_Rt,
    LSE128_Rt2,
    N,
    nzcv,
    off2,
    off3,
    ol,
    op1,
    op2,
    opc2,
    Ra,
    Rd,
    Rm,
    Rn,
    rotate1,
    rotate2,
    rotate3,
    Rs,
    Rt,
    Rt2,
    S_imm10,
    scale,
    shift,
    SME_i1,
    SME_Pdx2,
    SME_Pm,
    SME_PNd3,
    SME_PNn3,
    SME_Q,
    SME_Rm,
    SME_Rv,
    SME_size_22,
    SME_tszh,
    SME_tszl,
    SME_V,
    SME_VL_10,
    SME_VL_13,
    SME_ZAda_2b,
    SME_ZAda_3b,
    SME_Zdn2,
    SME_Zdn4,
    SME_zero_mask,
    SME_Zm,
    SME_Zm2,
    SME_Zm4,
    SME_Zn2,
    SME_Zn4,
    SME_Zt2,
    SME_Zt3,
    SME_ZtT,
    SVE_i1,
    SVE_i2h,
    SVE_i3h,
    SVE_i3h2,
    SVE_i3l,
    SVE_imm3,
    SVE_imm4,
    SVE_imm5,
    SVE_imm5b,
    SVE_imm7,
    SVE_imm8,
    SVE_imm9,
    SVE_immr,
    SVE_imms,
    SVE_N,
    SVE_pattern,
    SVE_Pd,
    SVE_Pg3,
    SVE_Pg4_10,
    SVE_Pg4_16,
    SVE_Pg4_5,
    SVE_Pm,
    SVE_Pn,
    SVE_prfop,
    SVE_Pt,
    SVE_Rm,
    SVE_Rn,
    SVE_rot1,
    SVE_rot2,
    SVE_rot3,
    SVE_sz,
    SVE_tsz,
    SVE_tszh,
    SVE_tszl_19,
    SVE_Vd,
    SVE_Vm,
    SVE_Vn,
    SVE_xs_14,
    SVE_xs_22,
    SVE_Za_16,
    SVE_Za_5,
    SVE_Zd,
    SVE_Zm_16,
    SVE_Zm_5,
    SVE_Zn,
    SVE_Zt,
    ZAn_1,
    ZAn_2,
    ZAn_3,
    ZAn,
}

/// The AArch64 instruction bit field specification.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct BitfieldSpec {
    pub bitfield: InsnBitField,
    pub lsb: u8,
    pub width: u8,
}
