use alloc::boxed::Box;
#[allow(unused_imports)]
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use crate::error::Span;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Arch {
X86,
X86_64,
Arm,
Thumb,
Aarch64,
Rv32,
Rv64,
}
impl fmt::Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Arch::X86 => write!(f, "x86"),
Arch::X86_64 => write!(f, "x86_64"),
Arch::Arm => write!(f, "ARM"),
Arch::Thumb => write!(f, "Thumb"),
Arch::Aarch64 => write!(f, "AArch64"),
Arch::Rv32 => write!(f, "RV32"),
Arch::Rv64 => write!(f, "RV64"),
}
}
}
impl Arch {
#[must_use]
pub fn to_arch_name(self) -> crate::error::ArchName {
match self {
Arch::X86 => crate::error::ArchName::X86,
Arch::X86_64 => crate::error::ArchName::X86_64,
Arch::Arm => crate::error::ArchName::Arm,
Arch::Thumb => crate::error::ArchName::Thumb,
Arch::Aarch64 => crate::error::ArchName::Aarch64,
Arch::Rv32 => crate::error::ArchName::Rv32,
Arch::Rv64 => crate::error::ArchName::Rv64,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Syntax {
Intel,
Att,
Ual,
RiscV,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OptLevel {
None,
#[default]
Size,
Aggressive,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Register {
Rax,
Rcx,
Rdx,
Rbx,
Rsp,
Rbp,
Rsi,
Rdi,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
Eax,
Ecx,
Edx,
Ebx,
Esp,
Ebp,
Esi,
Edi,
R8d,
R9d,
R10d,
R11d,
R12d,
R13d,
R14d,
R15d,
Ax,
Cx,
Dx,
Bx,
Sp,
Bp,
Si,
Di,
R8w,
R9w,
R10w,
R11w,
R12w,
R13w,
R14w,
R15w,
Al,
Cl,
Dl,
Bl,
Spl,
Bpl,
Sil,
Dil,
Ah,
Ch,
Dh,
Bh,
R8b,
R9b,
R10b,
R11b,
R12b,
R13b,
R14b,
R15b,
Rip,
Eip,
Cs,
Ds,
Es,
Fs,
Gs,
Ss,
Xmm0,
Xmm1,
Xmm2,
Xmm3,
Xmm4,
Xmm5,
Xmm6,
Xmm7,
Xmm8,
Xmm9,
Xmm10,
Xmm11,
Xmm12,
Xmm13,
Xmm14,
Xmm15,
Ymm0,
Ymm1,
Ymm2,
Ymm3,
Ymm4,
Ymm5,
Ymm6,
Ymm7,
Ymm8,
Ymm9,
Ymm10,
Ymm11,
Ymm12,
Ymm13,
Ymm14,
Ymm15,
Zmm0,
Zmm1,
Zmm2,
Zmm3,
Zmm4,
Zmm5,
Zmm6,
Zmm7,
Zmm8,
Zmm9,
Zmm10,
Zmm11,
Zmm12,
Zmm13,
Zmm14,
Zmm15,
Zmm16,
Zmm17,
Zmm18,
Zmm19,
Zmm20,
Zmm21,
Zmm22,
Zmm23,
Zmm24,
Zmm25,
Zmm26,
Zmm27,
Zmm28,
Zmm29,
Zmm30,
Zmm31,
K0,
K1,
K2,
K3,
K4,
K5,
K6,
K7,
ArmR0,
ArmR1,
ArmR2,
ArmR3,
ArmR4,
ArmR5,
ArmR6,
ArmR7,
ArmR8,
ArmR9,
ArmR10,
ArmR11,
ArmR12,
ArmSp,
ArmLr,
ArmPc,
ArmCpsr,
A64X0,
A64X1,
A64X2,
A64X3,
A64X4,
A64X5,
A64X6,
A64X7,
A64X8,
A64X9,
A64X10,
A64X11,
A64X12,
A64X13,
A64X14,
A64X15,
A64X16,
A64X17,
A64X18,
A64X19,
A64X20,
A64X21,
A64X22,
A64X23,
A64X24,
A64X25,
A64X26,
A64X27,
A64X28,
A64X29,
A64X30,
A64Sp,
A64Xzr,
A64W0,
A64W1,
A64W2,
A64W3,
A64W4,
A64W5,
A64W6,
A64W7,
A64W8,
A64W9,
A64W10,
A64W11,
A64W12,
A64W13,
A64W14,
A64W15,
A64W16,
A64W17,
A64W18,
A64W19,
A64W20,
A64W21,
A64W22,
A64W23,
A64W24,
A64W25,
A64W26,
A64W27,
A64W28,
A64W29,
A64W30,
A64Wzr,
A64Wsp,
A64V0,
A64V1,
A64V2,
A64V3,
A64V4,
A64V5,
A64V6,
A64V7,
A64V8,
A64V9,
A64V10,
A64V11,
A64V12,
A64V13,
A64V14,
A64V15,
A64V16,
A64V17,
A64V18,
A64V19,
A64V20,
A64V21,
A64V22,
A64V23,
A64V24,
A64V25,
A64V26,
A64V27,
A64V28,
A64V29,
A64V30,
A64V31,
A64Q0,
A64Q1,
A64Q2,
A64Q3,
A64Q4,
A64Q5,
A64Q6,
A64Q7,
A64Q8,
A64Q9,
A64Q10,
A64Q11,
A64Q12,
A64Q13,
A64Q14,
A64Q15,
A64Q16,
A64Q17,
A64Q18,
A64Q19,
A64Q20,
A64Q21,
A64Q22,
A64Q23,
A64Q24,
A64Q25,
A64Q26,
A64Q27,
A64Q28,
A64Q29,
A64Q30,
A64Q31,
A64D0,
A64D1,
A64D2,
A64D3,
A64D4,
A64D5,
A64D6,
A64D7,
A64D8,
A64D9,
A64D10,
A64D11,
A64D12,
A64D13,
A64D14,
A64D15,
A64D16,
A64D17,
A64D18,
A64D19,
A64D20,
A64D21,
A64D22,
A64D23,
A64D24,
A64D25,
A64D26,
A64D27,
A64D28,
A64D29,
A64D30,
A64D31,
A64S0,
A64S1,
A64S2,
A64S3,
A64S4,
A64S5,
A64S6,
A64S7,
A64S8,
A64S9,
A64S10,
A64S11,
A64S12,
A64S13,
A64S14,
A64S15,
A64S16,
A64S17,
A64S18,
A64S19,
A64S20,
A64S21,
A64S22,
A64S23,
A64S24,
A64S25,
A64S26,
A64S27,
A64S28,
A64S29,
A64S30,
A64S31,
A64H0,
A64H1,
A64H2,
A64H3,
A64H4,
A64H5,
A64H6,
A64H7,
A64H8,
A64H9,
A64H10,
A64H11,
A64H12,
A64H13,
A64H14,
A64H15,
A64H16,
A64H17,
A64H18,
A64H19,
A64H20,
A64H21,
A64H22,
A64H23,
A64H24,
A64H25,
A64H26,
A64H27,
A64H28,
A64H29,
A64H30,
A64H31,
A64B0,
A64B1,
A64B2,
A64B3,
A64B4,
A64B5,
A64B6,
A64B7,
A64B8,
A64B9,
A64B10,
A64B11,
A64B12,
A64B13,
A64B14,
A64B15,
A64B16,
A64B17,
A64B18,
A64B19,
A64B20,
A64B21,
A64B22,
A64B23,
A64B24,
A64B25,
A64B26,
A64B27,
A64B28,
A64B29,
A64B30,
A64B31,
A64Z0,
A64Z1,
A64Z2,
A64Z3,
A64Z4,
A64Z5,
A64Z6,
A64Z7,
A64Z8,
A64Z9,
A64Z10,
A64Z11,
A64Z12,
A64Z13,
A64Z14,
A64Z15,
A64Z16,
A64Z17,
A64Z18,
A64Z19,
A64Z20,
A64Z21,
A64Z22,
A64Z23,
A64Z24,
A64Z25,
A64Z26,
A64Z27,
A64Z28,
A64Z29,
A64Z30,
A64Z31,
A64P0,
A64P1,
A64P2,
A64P3,
A64P4,
A64P5,
A64P6,
A64P7,
A64P8,
A64P9,
A64P10,
A64P11,
A64P12,
A64P13,
A64P14,
A64P15,
RvX0,
RvX1,
RvX2,
RvX3,
RvX4,
RvX5,
RvX6,
RvX7,
RvX8,
RvX9,
RvX10,
RvX11,
RvX12,
RvX13,
RvX14,
RvX15,
RvX16,
RvX17,
RvX18,
RvX19,
RvX20,
RvX21,
RvX22,
RvX23,
RvX24,
RvX25,
RvX26,
RvX27,
RvX28,
RvX29,
RvX30,
RvX31,
RvF0,
RvF1,
RvF2,
RvF3,
RvF4,
RvF5,
RvF6,
RvF7,
RvF8,
RvF9,
RvF10,
RvF11,
RvF12,
RvF13,
RvF14,
RvF15,
RvF16,
RvF17,
RvF18,
RvF19,
RvF20,
RvF21,
RvF22,
RvF23,
RvF24,
RvF25,
RvF26,
RvF27,
RvF28,
RvF29,
RvF30,
RvF31,
RvV0,
RvV1,
RvV2,
RvV3,
RvV4,
RvV5,
RvV6,
RvV7,
RvV8,
RvV9,
RvV10,
RvV11,
RvV12,
RvV13,
RvV14,
RvV15,
RvV16,
RvV17,
RvV18,
RvV19,
RvV20,
RvV21,
RvV22,
RvV23,
RvV24,
RvV25,
RvV26,
RvV27,
RvV28,
RvV29,
RvV30,
RvV31,
}
impl Register {
pub fn base_code(self) -> u8 {
use Register::*;
match self {
Rax | Eax | Ax | Al | R8 | R8d | R8w | R8b | Xmm0 | Xmm8 | Ymm0 | Ymm8 | Zmm0
| Zmm8 | Zmm16 | Zmm24 | K0 => 0,
Rcx | Ecx | Cx | Cl | R9 | R9d | R9w | R9b | Xmm1 | Xmm9 | Ymm1 | Ymm9 | Zmm1
| Zmm9 | Zmm17 | Zmm25 | K1 => 1,
Rdx | Edx | Dx | Dl | R10 | R10d | R10w | R10b | Xmm2 | Xmm10 | Ymm2 | Ymm10 | Zmm2
| Zmm10 | Zmm18 | Zmm26 | K2 => 2,
Rbx | Ebx | Bx | Bl | R11 | R11d | R11w | R11b | Xmm3 | Xmm11 | Ymm3 | Ymm11 | Zmm3
| Zmm11 | Zmm19 | Zmm27 | K3 => 3,
Rsp | Esp | Sp | Spl | Ah | R12 | R12d | R12w | R12b | Xmm4 | Xmm12 | Ymm4 | Ymm12
| Zmm4 | Zmm12 | Zmm20 | Zmm28 | K4 => 4,
Rbp | Ebp | Bp | Bpl | Ch | R13 | R13d | R13w | R13b | Xmm5 | Xmm13 | Ymm5 | Ymm13
| Zmm5 | Zmm13 | Zmm21 | Zmm29 | K5 => 5,
Rsi | Esi | Si | Sil | Dh | R14 | R14d | R14w | R14b | Xmm6 | Xmm14 | Ymm6 | Ymm14
| Zmm6 | Zmm14 | Zmm22 | Zmm30 | K6 => 6,
Rdi | Edi | Di | Dil | Bh | R15 | R15d | R15w | R15b | Xmm7 | Xmm15 | Ymm7 | Ymm15
| Zmm7 | Zmm15 | Zmm23 | Zmm31 | K7 => 7,
Rip | Eip => 5, Cs => 1,
Ds => 3,
Es => 0,
Fs => 4,
Gs => 5,
Ss => 2,
_ => 0,
}
}
pub fn is_extended(self) -> bool {
use Register::*;
matches!(
self,
R8 | R9
| R10
| R11
| R12
| R13
| R14
| R15
| R8d
| R9d
| R10d
| R11d
| R12d
| R13d
| R14d
| R15d
| R8w
| R9w
| R10w
| R11w
| R12w
| R13w
| R14w
| R15w
| R8b
| R9b
| R10b
| R11b
| R12b
| R13b
| R14b
| R15b
| Xmm8
| Xmm9
| Xmm10
| Xmm11
| Xmm12
| Xmm13
| Xmm14
| Xmm15
| Ymm8
| Ymm9
| Ymm10
| Ymm11
| Ymm12
| Ymm13
| Ymm14
| Ymm15
| Zmm8
| Zmm9
| Zmm10
| Zmm11
| Zmm12
| Zmm13
| Zmm14
| Zmm15
| Zmm24
| Zmm25
| Zmm26
| Zmm27
| Zmm28
| Zmm29
| Zmm30
| Zmm31
)
}
pub fn is_evex_extended(self) -> bool {
use Register::*;
matches!(
self,
Zmm16
| Zmm17
| Zmm18
| Zmm19
| Zmm20
| Zmm21
| Zmm22
| Zmm23
| Zmm24
| Zmm25
| Zmm26
| Zmm27
| Zmm28
| Zmm29
| Zmm30
| Zmm31
)
}
pub fn size_bits(self) -> u16 {
use Register::*;
match self {
Rax | Rcx | Rdx | Rbx | Rsp | Rbp | Rsi | Rdi | R8 | R9 | R10 | R11 | R12 | R13
| R14 | R15 | Rip => 64,
Eax | Ecx | Edx | Ebx | Esp | Ebp | Esi | Edi | R8d | R9d | R10d | R11d | R12d
| R13d | R14d | R15d | Eip => 32,
Ax | Cx | Dx | Bx | Sp | Bp | Si | Di | R8w | R9w | R10w | R11w | R12w | R13w
| R14w | R15w => 16,
Al | Cl | Dl | Bl | Spl | Bpl | Sil | Dil | Ah | Ch | Dh | Bh | R8b | R9b | R10b
| R11b | R12b | R13b | R14b | R15b => 8,
Cs | Ds | Es | Fs | Gs | Ss => 16,
Xmm0 | Xmm1 | Xmm2 | Xmm3 | Xmm4 | Xmm5 | Xmm6 | Xmm7 | Xmm8 | Xmm9 | Xmm10 | Xmm11
| Xmm12 | Xmm13 | Xmm14 | Xmm15 => 128,
Ymm0 | Ymm1 | Ymm2 | Ymm3 | Ymm4 | Ymm5 | Ymm6 | Ymm7 | Ymm8 | Ymm9 | Ymm10 | Ymm11
| Ymm12 | Ymm13 | Ymm14 | Ymm15 => 256,
Zmm0 | Zmm1 | Zmm2 | Zmm3 | Zmm4 | Zmm5 | Zmm6 | Zmm7 | Zmm8 | Zmm9 | Zmm10 | Zmm11
| Zmm12 | Zmm13 | Zmm14 | Zmm15 | Zmm16 | Zmm17 | Zmm18 | Zmm19 | Zmm20 | Zmm21
| Zmm22 | Zmm23 | Zmm24 | Zmm25 | Zmm26 | Zmm27 | Zmm28 | Zmm29 | Zmm30 | Zmm31 => 512,
K0 | K1 | K2 | K3 | K4 | K5 | K6 | K7 => 64,
ArmR0 | ArmR1 | ArmR2 | ArmR3 | ArmR4 | ArmR5 | ArmR6 | ArmR7 | ArmR8 | ArmR9
| ArmR10 | ArmR11 | ArmR12 | ArmSp | ArmLr | ArmPc | ArmCpsr => 32,
A64X0 | A64X1 | A64X2 | A64X3 | A64X4 | A64X5 | A64X6 | A64X7 | A64X8 | A64X9
| A64X10 | A64X11 | A64X12 | A64X13 | A64X14 | A64X15 | A64X16 | A64X17 | A64X18
| A64X19 | A64X20 | A64X21 | A64X22 | A64X23 | A64X24 | A64X25 | A64X26 | A64X27
| A64X28 | A64X29 | A64X30 | A64Sp | A64Xzr => 64,
A64W0 | A64W1 | A64W2 | A64W3 | A64W4 | A64W5 | A64W6 | A64W7 | A64W8 | A64W9
| A64W10 | A64W11 | A64W12 | A64W13 | A64W14 | A64W15 | A64W16 | A64W17 | A64W18
| A64W19 | A64W20 | A64W21 | A64W22 | A64W23 | A64W24 | A64W25 | A64W26 | A64W27
| A64W28 | A64W29 | A64W30 | A64Wzr | A64Wsp => 32,
A64V0 | A64V1 | A64V2 | A64V3 | A64V4 | A64V5 | A64V6 | A64V7 | A64V8 | A64V9
| A64V10 | A64V11 | A64V12 | A64V13 | A64V14 | A64V15 | A64V16 | A64V17 | A64V18
| A64V19 | A64V20 | A64V21 | A64V22 | A64V23 | A64V24 | A64V25 | A64V26 | A64V27
| A64V28 | A64V29 | A64V30 | A64V31 | A64Q0 | A64Q1 | A64Q2 | A64Q3 | A64Q4 | A64Q5
| A64Q6 | A64Q7 | A64Q8 | A64Q9 | A64Q10 | A64Q11 | A64Q12 | A64Q13 | A64Q14
| A64Q15 | A64Q16 | A64Q17 | A64Q18 | A64Q19 | A64Q20 | A64Q21 | A64Q22 | A64Q23
| A64Q24 | A64Q25 | A64Q26 | A64Q27 | A64Q28 | A64Q29 | A64Q30 | A64Q31 => 128,
A64D0 | A64D1 | A64D2 | A64D3 | A64D4 | A64D5 | A64D6 | A64D7 | A64D8 | A64D9
| A64D10 | A64D11 | A64D12 | A64D13 | A64D14 | A64D15 | A64D16 | A64D17 | A64D18
| A64D19 | A64D20 | A64D21 | A64D22 | A64D23 | A64D24 | A64D25 | A64D26 | A64D27
| A64D28 | A64D29 | A64D30 | A64D31 => 64,
A64S0 | A64S1 | A64S2 | A64S3 | A64S4 | A64S5 | A64S6 | A64S7 | A64S8 | A64S9
| A64S10 | A64S11 | A64S12 | A64S13 | A64S14 | A64S15 | A64S16 | A64S17 | A64S18
| A64S19 | A64S20 | A64S21 | A64S22 | A64S23 | A64S24 | A64S25 | A64S26 | A64S27
| A64S28 | A64S29 | A64S30 | A64S31 => 32,
A64H0 | A64H1 | A64H2 | A64H3 | A64H4 | A64H5 | A64H6 | A64H7 | A64H8 | A64H9
| A64H10 | A64H11 | A64H12 | A64H13 | A64H14 | A64H15 | A64H16 | A64H17 | A64H18
| A64H19 | A64H20 | A64H21 | A64H22 | A64H23 | A64H24 | A64H25 | A64H26 | A64H27
| A64H28 | A64H29 | A64H30 | A64H31 => 16,
A64B0 | A64B1 | A64B2 | A64B3 | A64B4 | A64B5 | A64B6 | A64B7 | A64B8 | A64B9
| A64B10 | A64B11 | A64B12 | A64B13 | A64B14 | A64B15 | A64B16 | A64B17 | A64B18
| A64B19 | A64B20 | A64B21 | A64B22 | A64B23 | A64B24 | A64B25 | A64B26 | A64B27
| A64B28 | A64B29 | A64B30 | A64B31 => 8,
A64Z0 | A64Z1 | A64Z2 | A64Z3 | A64Z4 | A64Z5 | A64Z6 | A64Z7 | A64Z8 | A64Z9
| A64Z10 | A64Z11 | A64Z12 | A64Z13 | A64Z14 | A64Z15 | A64Z16 | A64Z17 | A64Z18
| A64Z19 | A64Z20 | A64Z21 | A64Z22 | A64Z23 | A64Z24 | A64Z25 | A64Z26 | A64Z27
| A64Z28 | A64Z29 | A64Z30 | A64Z31 => 0,
A64P0 | A64P1 | A64P2 | A64P3 | A64P4 | A64P5 | A64P6 | A64P7 | A64P8 | A64P9
| A64P10 | A64P11 | A64P12 | A64P13 | A64P14 | A64P15 => 0,
RvX0 | RvX1 | RvX2 | RvX3 | RvX4 | RvX5 | RvX6 | RvX7 | RvX8 | RvX9 | RvX10 | RvX11
| RvX12 | RvX13 | RvX14 | RvX15 | RvX16 | RvX17 | RvX18 | RvX19 | RvX20 | RvX21
| RvX22 | RvX23 | RvX24 | RvX25 | RvX26 | RvX27 | RvX28 | RvX29 | RvX30 | RvX31 => 0,
RvF0 | RvF1 | RvF2 | RvF3 | RvF4 | RvF5 | RvF6 | RvF7 | RvF8 | RvF9 | RvF10 | RvF11
| RvF12 | RvF13 | RvF14 | RvF15 | RvF16 | RvF17 | RvF18 | RvF19 | RvF20 | RvF21
| RvF22 | RvF23 | RvF24 | RvF25 | RvF26 | RvF27 | RvF28 | RvF29 | RvF30 | RvF31 => 0,
RvV0 | RvV1 | RvV2 | RvV3 | RvV4 | RvV5 | RvV6 | RvV7 | RvV8 | RvV9 | RvV10 | RvV11
| RvV12 | RvV13 | RvV14 | RvV15 | RvV16 | RvV17 | RvV18 | RvV19 | RvV20 | RvV21
| RvV22 | RvV23 | RvV24 | RvV25 | RvV26 | RvV27 | RvV28 | RvV29 | RvV30 | RvV31 => 0,
}
}
pub fn requires_rex_for_byte(self) -> bool {
use Register::*;
matches!(self, Spl | Bpl | Sil | Dil)
}
pub fn is_high_byte(self) -> bool {
use Register::*;
matches!(self, Ah | Ch | Dh | Bh)
}
#[must_use]
pub fn is_xmm(self) -> bool {
use Register::*;
matches!(
self,
Xmm0 | Xmm1
| Xmm2
| Xmm3
| Xmm4
| Xmm5
| Xmm6
| Xmm7
| Xmm8
| Xmm9
| Xmm10
| Xmm11
| Xmm12
| Xmm13
| Xmm14
| Xmm15
)
}
#[must_use]
pub fn is_ymm(self) -> bool {
use Register::*;
matches!(
self,
Ymm0 | Ymm1
| Ymm2
| Ymm3
| Ymm4
| Ymm5
| Ymm6
| Ymm7
| Ymm8
| Ymm9
| Ymm10
| Ymm11
| Ymm12
| Ymm13
| Ymm14
| Ymm15
)
}
#[must_use]
pub fn is_zmm(self) -> bool {
use Register::*;
matches!(
self,
Zmm0 | Zmm1
| Zmm2
| Zmm3
| Zmm4
| Zmm5
| Zmm6
| Zmm7
| Zmm8
| Zmm9
| Zmm10
| Zmm11
| Zmm12
| Zmm13
| Zmm14
| Zmm15
| Zmm16
| Zmm17
| Zmm18
| Zmm19
| Zmm20
| Zmm21
| Zmm22
| Zmm23
| Zmm24
| Zmm25
| Zmm26
| Zmm27
| Zmm28
| Zmm29
| Zmm30
| Zmm31
)
}
#[must_use]
pub fn is_opmask(self) -> bool {
use Register::*;
matches!(self, K0 | K1 | K2 | K3 | K4 | K5 | K6 | K7)
}
#[must_use]
pub fn is_vector(self) -> bool {
self.is_xmm() || self.is_ymm() || self.is_zmm()
}
#[must_use]
pub fn to_32bit(self) -> Option<Register> {
use Register::*;
match self {
Rax | Eax => Some(Eax),
Rcx | Ecx => Some(Ecx),
Rdx | Edx => Some(Edx),
Rbx | Ebx => Some(Ebx),
Rsp | Esp => Some(Esp),
Rbp | Ebp => Some(Ebp),
Rsi | Esi => Some(Esi),
Rdi | Edi => Some(Edi),
R8 | R8d => Some(R8d),
R9 | R9d => Some(R9d),
R10 | R10d => Some(R10d),
R11 | R11d => Some(R11d),
R12 | R12d => Some(R12d),
R13 | R13d => Some(R13d),
R14 | R14d => Some(R14d),
R15 | R15d => Some(R15d),
_ => None,
}
}
#[must_use]
pub fn is_arm(self) -> bool {
use Register::*;
matches!(
self,
ArmR0
| ArmR1
| ArmR2
| ArmR3
| ArmR4
| ArmR5
| ArmR6
| ArmR7
| ArmR8
| ArmR9
| ArmR10
| ArmR11
| ArmR12
| ArmSp
| ArmLr
| ArmPc
| ArmCpsr
)
}
#[must_use]
pub fn arm_reg_num(self) -> u8 {
use Register::*;
match self {
ArmR0 => 0,
ArmR1 => 1,
ArmR2 => 2,
ArmR3 => 3,
ArmR4 => 4,
ArmR5 => 5,
ArmR6 => 6,
ArmR7 => 7,
ArmR8 => 8,
ArmR9 => 9,
ArmR10 => 10,
ArmR11 => 11,
ArmR12 => 12,
ArmSp => 13,
ArmLr => 14,
ArmPc => 15,
_ => 0,
}
}
#[must_use]
pub fn is_a64_sp(self) -> bool {
matches!(self, Register::A64Sp | Register::A64Wsp)
}
#[must_use]
pub fn from_arm_reg_num(n: u8) -> Option<Self> {
use Register::*;
Some(match n {
0 => ArmR0,
1 => ArmR1,
2 => ArmR2,
3 => ArmR3,
4 => ArmR4,
5 => ArmR5,
6 => ArmR6,
7 => ArmR7,
8 => ArmR8,
9 => ArmR9,
10 => ArmR10,
11 => ArmR11,
12 => ArmR12,
13 => ArmSp,
14 => ArmLr,
15 => ArmPc,
_ => return None,
})
}
#[must_use]
pub fn is_aarch64(self) -> bool {
use Register::*;
matches!(
self,
A64X0
| A64X1
| A64X2
| A64X3
| A64X4
| A64X5
| A64X6
| A64X7
| A64X8
| A64X9
| A64X10
| A64X11
| A64X12
| A64X13
| A64X14
| A64X15
| A64X16
| A64X17
| A64X18
| A64X19
| A64X20
| A64X21
| A64X22
| A64X23
| A64X24
| A64X25
| A64X26
| A64X27
| A64X28
| A64X29
| A64X30
| A64Sp
| A64Xzr
| A64W0
| A64W1
| A64W2
| A64W3
| A64W4
| A64W5
| A64W6
| A64W7
| A64W8
| A64W9
| A64W10
| A64W11
| A64W12
| A64W13
| A64W14
| A64W15
| A64W16
| A64W17
| A64W18
| A64W19
| A64W20
| A64W21
| A64W22
| A64W23
| A64W24
| A64W25
| A64W26
| A64W27
| A64W28
| A64W29
| A64W30
| A64Wzr
| A64Wsp
| A64V0
| A64V1
| A64V2
| A64V3
| A64V4
| A64V5
| A64V6
| A64V7
| A64V8
| A64V9
| A64V10
| A64V11
| A64V12
| A64V13
| A64V14
| A64V15
| A64V16
| A64V17
| A64V18
| A64V19
| A64V20
| A64V21
| A64V22
| A64V23
| A64V24
| A64V25
| A64V26
| A64V27
| A64V28
| A64V29
| A64V30
| A64V31
| A64Q0
| A64Q1
| A64Q2
| A64Q3
| A64Q4
| A64Q5
| A64Q6
| A64Q7
| A64Q8
| A64Q9
| A64Q10
| A64Q11
| A64Q12
| A64Q13
| A64Q14
| A64Q15
| A64Q16
| A64Q17
| A64Q18
| A64Q19
| A64Q20
| A64Q21
| A64Q22
| A64Q23
| A64Q24
| A64Q25
| A64Q26
| A64Q27
| A64Q28
| A64Q29
| A64Q30
| A64Q31
| A64D0
| A64D1
| A64D2
| A64D3
| A64D4
| A64D5
| A64D6
| A64D7
| A64D8
| A64D9
| A64D10
| A64D11
| A64D12
| A64D13
| A64D14
| A64D15
| A64D16
| A64D17
| A64D18
| A64D19
| A64D20
| A64D21
| A64D22
| A64D23
| A64D24
| A64D25
| A64D26
| A64D27
| A64D28
| A64D29
| A64D30
| A64D31
| A64S0
| A64S1
| A64S2
| A64S3
| A64S4
| A64S5
| A64S6
| A64S7
| A64S8
| A64S9
| A64S10
| A64S11
| A64S12
| A64S13
| A64S14
| A64S15
| A64S16
| A64S17
| A64S18
| A64S19
| A64S20
| A64S21
| A64S22
| A64S23
| A64S24
| A64S25
| A64S26
| A64S27
| A64S28
| A64S29
| A64S30
| A64S31
| A64H0
| A64H1
| A64H2
| A64H3
| A64H4
| A64H5
| A64H6
| A64H7
| A64H8
| A64H9
| A64H10
| A64H11
| A64H12
| A64H13
| A64H14
| A64H15
| A64H16
| A64H17
| A64H18
| A64H19
| A64H20
| A64H21
| A64H22
| A64H23
| A64H24
| A64H25
| A64H26
| A64H27
| A64H28
| A64H29
| A64H30
| A64H31
| A64B0
| A64B1
| A64B2
| A64B3
| A64B4
| A64B5
| A64B6
| A64B7
| A64B8
| A64B9
| A64B10
| A64B11
| A64B12
| A64B13
| A64B14
| A64B15
| A64B16
| A64B17
| A64B18
| A64B19
| A64B20
| A64B21
| A64B22
| A64B23
| A64B24
| A64B25
| A64B26
| A64B27
| A64B28
| A64B29
| A64B30
| A64B31
| A64Z0
| A64Z1
| A64Z2
| A64Z3
| A64Z4
| A64Z5
| A64Z6
| A64Z7
| A64Z8
| A64Z9
| A64Z10
| A64Z11
| A64Z12
| A64Z13
| A64Z14
| A64Z15
| A64Z16
| A64Z17
| A64Z18
| A64Z19
| A64Z20
| A64Z21
| A64Z22
| A64Z23
| A64Z24
| A64Z25
| A64Z26
| A64Z27
| A64Z28
| A64Z29
| A64Z30
| A64Z31
| A64P0
| A64P1
| A64P2
| A64P3
| A64P4
| A64P5
| A64P6
| A64P7
| A64P8
| A64P9
| A64P10
| A64P11
| A64P12
| A64P13
| A64P14
| A64P15
)
}
#[must_use]
pub fn a64_reg_num(self) -> u8 {
use Register::*;
match self {
A64X0 | A64W0 => 0,
A64X1 | A64W1 => 1,
A64X2 | A64W2 => 2,
A64X3 | A64W3 => 3,
A64X4 | A64W4 => 4,
A64X5 | A64W5 => 5,
A64X6 | A64W6 => 6,
A64X7 | A64W7 => 7,
A64X8 | A64W8 => 8,
A64X9 | A64W9 => 9,
A64X10 | A64W10 => 10,
A64X11 | A64W11 => 11,
A64X12 | A64W12 => 12,
A64X13 | A64W13 => 13,
A64X14 | A64W14 => 14,
A64X15 | A64W15 => 15,
A64X16 | A64W16 => 16,
A64X17 | A64W17 => 17,
A64X18 | A64W18 => 18,
A64X19 | A64W19 => 19,
A64X20 | A64W20 => 20,
A64X21 | A64W21 => 21,
A64X22 | A64W22 => 22,
A64X23 | A64W23 => 23,
A64X24 | A64W24 => 24,
A64X25 | A64W25 => 25,
A64X26 | A64W26 => 26,
A64X27 | A64W27 => 27,
A64X28 | A64W28 => 28,
A64X29 | A64W29 => 29,
A64X30 | A64W30 => 30,
A64Sp | A64Xzr | A64Wzr | A64Wsp => 31,
A64V0 | A64Q0 | A64D0 | A64S0 | A64H0 | A64B0 => 0,
A64V1 | A64Q1 | A64D1 | A64S1 | A64H1 | A64B1 => 1,
A64V2 | A64Q2 | A64D2 | A64S2 | A64H2 | A64B2 => 2,
A64V3 | A64Q3 | A64D3 | A64S3 | A64H3 | A64B3 => 3,
A64V4 | A64Q4 | A64D4 | A64S4 | A64H4 | A64B4 => 4,
A64V5 | A64Q5 | A64D5 | A64S5 | A64H5 | A64B5 => 5,
A64V6 | A64Q6 | A64D6 | A64S6 | A64H6 | A64B6 => 6,
A64V7 | A64Q7 | A64D7 | A64S7 | A64H7 | A64B7 => 7,
A64V8 | A64Q8 | A64D8 | A64S8 | A64H8 | A64B8 => 8,
A64V9 | A64Q9 | A64D9 | A64S9 | A64H9 | A64B9 => 9,
A64V10 | A64Q10 | A64D10 | A64S10 | A64H10 | A64B10 => 10,
A64V11 | A64Q11 | A64D11 | A64S11 | A64H11 | A64B11 => 11,
A64V12 | A64Q12 | A64D12 | A64S12 | A64H12 | A64B12 => 12,
A64V13 | A64Q13 | A64D13 | A64S13 | A64H13 | A64B13 => 13,
A64V14 | A64Q14 | A64D14 | A64S14 | A64H14 | A64B14 => 14,
A64V15 | A64Q15 | A64D15 | A64S15 | A64H15 | A64B15 => 15,
A64V16 | A64Q16 | A64D16 | A64S16 | A64H16 | A64B16 => 16,
A64V17 | A64Q17 | A64D17 | A64S17 | A64H17 | A64B17 => 17,
A64V18 | A64Q18 | A64D18 | A64S18 | A64H18 | A64B18 => 18,
A64V19 | A64Q19 | A64D19 | A64S19 | A64H19 | A64B19 => 19,
A64V20 | A64Q20 | A64D20 | A64S20 | A64H20 | A64B20 => 20,
A64V21 | A64Q21 | A64D21 | A64S21 | A64H21 | A64B21 => 21,
A64V22 | A64Q22 | A64D22 | A64S22 | A64H22 | A64B22 => 22,
A64V23 | A64Q23 | A64D23 | A64S23 | A64H23 | A64B23 => 23,
A64V24 | A64Q24 | A64D24 | A64S24 | A64H24 | A64B24 => 24,
A64V25 | A64Q25 | A64D25 | A64S25 | A64H25 | A64B25 => 25,
A64V26 | A64Q26 | A64D26 | A64S26 | A64H26 | A64B26 => 26,
A64V27 | A64Q27 | A64D27 | A64S27 | A64H27 | A64B27 => 27,
A64V28 | A64Q28 | A64D28 | A64S28 | A64H28 | A64B28 => 28,
A64V29 | A64Q29 | A64D29 | A64S29 | A64H29 | A64B29 => 29,
A64V30 | A64Q30 | A64D30 | A64S30 | A64H30 | A64B30 => 30,
A64V31 | A64Q31 | A64D31 | A64S31 | A64H31 | A64B31 => 31,
A64Z0 => 0,
A64Z1 => 1,
A64Z2 => 2,
A64Z3 => 3,
A64Z4 => 4,
A64Z5 => 5,
A64Z6 => 6,
A64Z7 => 7,
A64Z8 => 8,
A64Z9 => 9,
A64Z10 => 10,
A64Z11 => 11,
A64Z12 => 12,
A64Z13 => 13,
A64Z14 => 14,
A64Z15 => 15,
A64Z16 => 16,
A64Z17 => 17,
A64Z18 => 18,
A64Z19 => 19,
A64Z20 => 20,
A64Z21 => 21,
A64Z22 => 22,
A64Z23 => 23,
A64Z24 => 24,
A64Z25 => 25,
A64Z26 => 26,
A64Z27 => 27,
A64Z28 => 28,
A64Z29 => 29,
A64Z30 => 30,
A64Z31 => 31,
_ => 0,
}
}
#[must_use]
pub fn is_a64_vector(self) -> bool {
use Register::*;
matches!(
self,
A64V0
| A64V1
| A64V2
| A64V3
| A64V4
| A64V5
| A64V6
| A64V7
| A64V8
| A64V9
| A64V10
| A64V11
| A64V12
| A64V13
| A64V14
| A64V15
| A64V16
| A64V17
| A64V18
| A64V19
| A64V20
| A64V21
| A64V22
| A64V23
| A64V24
| A64V25
| A64V26
| A64V27
| A64V28
| A64V29
| A64V30
| A64V31
)
}
#[must_use]
pub fn is_a64_simd_fp(self) -> bool {
use Register::*;
matches!(
self,
A64V0
| A64V1
| A64V2
| A64V3
| A64V4
| A64V5
| A64V6
| A64V7
| A64V8
| A64V9
| A64V10
| A64V11
| A64V12
| A64V13
| A64V14
| A64V15
| A64V16
| A64V17
| A64V18
| A64V19
| A64V20
| A64V21
| A64V22
| A64V23
| A64V24
| A64V25
| A64V26
| A64V27
| A64V28
| A64V29
| A64V30
| A64V31
| A64Q0
| A64Q1
| A64Q2
| A64Q3
| A64Q4
| A64Q5
| A64Q6
| A64Q7
| A64Q8
| A64Q9
| A64Q10
| A64Q11
| A64Q12
| A64Q13
| A64Q14
| A64Q15
| A64Q16
| A64Q17
| A64Q18
| A64Q19
| A64Q20
| A64Q21
| A64Q22
| A64Q23
| A64Q24
| A64Q25
| A64Q26
| A64Q27
| A64Q28
| A64Q29
| A64Q30
| A64Q31
| A64D0
| A64D1
| A64D2
| A64D3
| A64D4
| A64D5
| A64D6
| A64D7
| A64D8
| A64D9
| A64D10
| A64D11
| A64D12
| A64D13
| A64D14
| A64D15
| A64D16
| A64D17
| A64D18
| A64D19
| A64D20
| A64D21
| A64D22
| A64D23
| A64D24
| A64D25
| A64D26
| A64D27
| A64D28
| A64D29
| A64D30
| A64D31
| A64S0
| A64S1
| A64S2
| A64S3
| A64S4
| A64S5
| A64S6
| A64S7
| A64S8
| A64S9
| A64S10
| A64S11
| A64S12
| A64S13
| A64S14
| A64S15
| A64S16
| A64S17
| A64S18
| A64S19
| A64S20
| A64S21
| A64S22
| A64S23
| A64S24
| A64S25
| A64S26
| A64S27
| A64S28
| A64S29
| A64S30
| A64S31
| A64H0
| A64H1
| A64H2
| A64H3
| A64H4
| A64H5
| A64H6
| A64H7
| A64H8
| A64H9
| A64H10
| A64H11
| A64H12
| A64H13
| A64H14
| A64H15
| A64H16
| A64H17
| A64H18
| A64H19
| A64H20
| A64H21
| A64H22
| A64H23
| A64H24
| A64H25
| A64H26
| A64H27
| A64H28
| A64H29
| A64H30
| A64H31
| A64B0
| A64B1
| A64B2
| A64B3
| A64B4
| A64B5
| A64B6
| A64B7
| A64B8
| A64B9
| A64B10
| A64B11
| A64B12
| A64B13
| A64B14
| A64B15
| A64B16
| A64B17
| A64B18
| A64B19
| A64B20
| A64B21
| A64B22
| A64B23
| A64B24
| A64B25
| A64B26
| A64B27
| A64B28
| A64B29
| A64B30
| A64B31
)
}
#[must_use]
pub fn a64_simd_fp_bits(self) -> u32 {
use Register::*;
match self {
A64V0 | A64V1 | A64V2 | A64V3 | A64V4 | A64V5 | A64V6 | A64V7 | A64V8 | A64V9
| A64V10 | A64V11 | A64V12 | A64V13 | A64V14 | A64V15 | A64V16 | A64V17 | A64V18
| A64V19 | A64V20 | A64V21 | A64V22 | A64V23 | A64V24 | A64V25 | A64V26 | A64V27
| A64V28 | A64V29 | A64V30 | A64V31 | A64Q0 | A64Q1 | A64Q2 | A64Q3 | A64Q4 | A64Q5
| A64Q6 | A64Q7 | A64Q8 | A64Q9 | A64Q10 | A64Q11 | A64Q12 | A64Q13 | A64Q14
| A64Q15 | A64Q16 | A64Q17 | A64Q18 | A64Q19 | A64Q20 | A64Q21 | A64Q22 | A64Q23
| A64Q24 | A64Q25 | A64Q26 | A64Q27 | A64Q28 | A64Q29 | A64Q30 | A64Q31 => 128,
A64D0 | A64D1 | A64D2 | A64D3 | A64D4 | A64D5 | A64D6 | A64D7 | A64D8 | A64D9
| A64D10 | A64D11 | A64D12 | A64D13 | A64D14 | A64D15 | A64D16 | A64D17 | A64D18
| A64D19 | A64D20 | A64D21 | A64D22 | A64D23 | A64D24 | A64D25 | A64D26 | A64D27
| A64D28 | A64D29 | A64D30 | A64D31 => 64,
A64S0 | A64S1 | A64S2 | A64S3 | A64S4 | A64S5 | A64S6 | A64S7 | A64S8 | A64S9
| A64S10 | A64S11 | A64S12 | A64S13 | A64S14 | A64S15 | A64S16 | A64S17 | A64S18
| A64S19 | A64S20 | A64S21 | A64S22 | A64S23 | A64S24 | A64S25 | A64S26 | A64S27
| A64S28 | A64S29 | A64S30 | A64S31 => 32,
A64H0 | A64H1 | A64H2 | A64H3 | A64H4 | A64H5 | A64H6 | A64H7 | A64H8 | A64H9
| A64H10 | A64H11 | A64H12 | A64H13 | A64H14 | A64H15 | A64H16 | A64H17 | A64H18
| A64H19 | A64H20 | A64H21 | A64H22 | A64H23 | A64H24 | A64H25 | A64H26 | A64H27
| A64H28 | A64H29 | A64H30 | A64H31 => 16,
A64B0 | A64B1 | A64B2 | A64B3 | A64B4 | A64B5 | A64B6 | A64B7 | A64B8 | A64B9
| A64B10 | A64B11 | A64B12 | A64B13 | A64B14 | A64B15 | A64B16 | A64B17 | A64B18
| A64B19 | A64B20 | A64B21 | A64B22 | A64B23 | A64B24 | A64B25 | A64B26 | A64B27
| A64B28 | A64B29 | A64B30 | A64B31 => 8,
_ => 0,
}
}
#[must_use]
pub fn is_a64_64bit(self) -> bool {
use Register::*;
matches!(
self,
A64X0
| A64X1
| A64X2
| A64X3
| A64X4
| A64X5
| A64X6
| A64X7
| A64X8
| A64X9
| A64X10
| A64X11
| A64X12
| A64X13
| A64X14
| A64X15
| A64X16
| A64X17
| A64X18
| A64X19
| A64X20
| A64X21
| A64X22
| A64X23
| A64X24
| A64X25
| A64X26
| A64X27
| A64X28
| A64X29
| A64X30
| A64Sp
| A64Xzr
)
}
#[must_use]
pub fn is_riscv(self) -> bool {
use Register::*;
matches!(
self,
RvX0 | RvX1
| RvX2
| RvX3
| RvX4
| RvX5
| RvX6
| RvX7
| RvX8
| RvX9
| RvX10
| RvX11
| RvX12
| RvX13
| RvX14
| RvX15
| RvX16
| RvX17
| RvX18
| RvX19
| RvX20
| RvX21
| RvX22
| RvX23
| RvX24
| RvX25
| RvX26
| RvX27
| RvX28
| RvX29
| RvX30
| RvX31
)
}
#[must_use]
pub fn rv_reg_num(self) -> u8 {
use Register::*;
match self {
RvX0 => 0,
RvX1 => 1,
RvX2 => 2,
RvX3 => 3,
RvX4 => 4,
RvX5 => 5,
RvX6 => 6,
RvX7 => 7,
RvX8 => 8,
RvX9 => 9,
RvX10 => 10,
RvX11 => 11,
RvX12 => 12,
RvX13 => 13,
RvX14 => 14,
RvX15 => 15,
RvX16 => 16,
RvX17 => 17,
RvX18 => 18,
RvX19 => 19,
RvX20 => 20,
RvX21 => 21,
RvX22 => 22,
RvX23 => 23,
RvX24 => 24,
RvX25 => 25,
RvX26 => 26,
RvX27 => 27,
RvX28 => 28,
RvX29 => 29,
RvX30 => 30,
RvX31 => 31,
_ => 0,
}
}
#[must_use]
pub fn is_riscv_fp(self) -> bool {
use Register::*;
matches!(
self,
RvF0 | RvF1
| RvF2
| RvF3
| RvF4
| RvF5
| RvF6
| RvF7
| RvF8
| RvF9
| RvF10
| RvF11
| RvF12
| RvF13
| RvF14
| RvF15
| RvF16
| RvF17
| RvF18
| RvF19
| RvF20
| RvF21
| RvF22
| RvF23
| RvF24
| RvF25
| RvF26
| RvF27
| RvF28
| RvF29
| RvF30
| RvF31
)
}
#[must_use]
pub fn rv_fp_reg_num(self) -> u8 {
use Register::*;
match self {
RvF0 => 0,
RvF1 => 1,
RvF2 => 2,
RvF3 => 3,
RvF4 => 4,
RvF5 => 5,
RvF6 => 6,
RvF7 => 7,
RvF8 => 8,
RvF9 => 9,
RvF10 => 10,
RvF11 => 11,
RvF12 => 12,
RvF13 => 13,
RvF14 => 14,
RvF15 => 15,
RvF16 => 16,
RvF17 => 17,
RvF18 => 18,
RvF19 => 19,
RvF20 => 20,
RvF21 => 21,
RvF22 => 22,
RvF23 => 23,
RvF24 => 24,
RvF25 => 25,
RvF26 => 26,
RvF27 => 27,
RvF28 => 28,
RvF29 => 29,
RvF30 => 30,
RvF31 => 31,
_ => 0,
}
}
#[must_use]
pub fn is_a64_sve_z(self) -> bool {
use Register::*;
matches!(
self,
A64Z0
| A64Z1
| A64Z2
| A64Z3
| A64Z4
| A64Z5
| A64Z6
| A64Z7
| A64Z8
| A64Z9
| A64Z10
| A64Z11
| A64Z12
| A64Z13
| A64Z14
| A64Z15
| A64Z16
| A64Z17
| A64Z18
| A64Z19
| A64Z20
| A64Z21
| A64Z22
| A64Z23
| A64Z24
| A64Z25
| A64Z26
| A64Z27
| A64Z28
| A64Z29
| A64Z30
| A64Z31
)
}
#[must_use]
pub fn is_a64_sve_p(self) -> bool {
use Register::*;
matches!(
self,
A64P0
| A64P1
| A64P2
| A64P3
| A64P4
| A64P5
| A64P6
| A64P7
| A64P8
| A64P9
| A64P10
| A64P11
| A64P12
| A64P13
| A64P14
| A64P15
)
}
#[must_use]
pub fn a64_p_num(self) -> u8 {
use Register::*;
match self {
A64P0 => 0,
A64P1 => 1,
A64P2 => 2,
A64P3 => 3,
A64P4 => 4,
A64P5 => 5,
A64P6 => 6,
A64P7 => 7,
A64P8 => 8,
A64P9 => 9,
A64P10 => 10,
A64P11 => 11,
A64P12 => 12,
A64P13 => 13,
A64P14 => 14,
A64P15 => 15,
_ => 0,
}
}
#[must_use]
pub fn is_riscv_vec(self) -> bool {
use Register::*;
matches!(
self,
RvV0 | RvV1
| RvV2
| RvV3
| RvV4
| RvV5
| RvV6
| RvV7
| RvV8
| RvV9
| RvV10
| RvV11
| RvV12
| RvV13
| RvV14
| RvV15
| RvV16
| RvV17
| RvV18
| RvV19
| RvV20
| RvV21
| RvV22
| RvV23
| RvV24
| RvV25
| RvV26
| RvV27
| RvV28
| RvV29
| RvV30
| RvV31
)
}
#[must_use]
pub fn rv_vec_num(self) -> u8 {
use Register::*;
match self {
RvV0 => 0,
RvV1 => 1,
RvV2 => 2,
RvV3 => 3,
RvV4 => 4,
RvV5 => 5,
RvV6 => 6,
RvV7 => 7,
RvV8 => 8,
RvV9 => 9,
RvV10 => 10,
RvV11 => 11,
RvV12 => 12,
RvV13 => 13,
RvV14 => 14,
RvV15 => 15,
RvV16 => 16,
RvV17 => 17,
RvV18 => 18,
RvV19 => 19,
RvV20 => 20,
RvV21 => 21,
RvV22 => 22,
RvV23 => 23,
RvV24 => 24,
RvV25 => 25,
RvV26 => 26,
RvV27 => 27,
RvV28 => 28,
RvV29 => 29,
RvV30 => 30,
RvV31 => 31,
_ => 0,
}
}
}
impl fmt::Display for Register {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Write as _;
struct LowerWriter<'a, 'b>(&'a mut fmt::Formatter<'b>);
impl fmt::Write for LowerWriter<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
self.0.write_char(c.to_ascii_lowercase())?;
}
Ok(())
}
}
write!(LowerWriter(f), "{:?}", self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum VectorArrangement {
B8,
B16,
H4,
H8,
S2,
S4,
D1,
D2,
SveB,
SveH,
SveS,
SveD,
}
impl VectorArrangement {
pub fn parse(s: &str) -> Option<Self> {
let mut buf = [0u8; 4];
let len = s.len().min(4);
buf[..len].copy_from_slice(&s.as_bytes()[..len]);
buf[..len].make_ascii_lowercase();
let s = core::str::from_utf8(&buf[..len]).unwrap_or("");
match s {
"8b" => Some(VectorArrangement::B8),
"16b" => Some(VectorArrangement::B16),
"4h" => Some(VectorArrangement::H4),
"8h" => Some(VectorArrangement::H8),
"2s" => Some(VectorArrangement::S2),
"4s" => Some(VectorArrangement::S4),
"1d" => Some(VectorArrangement::D1),
"2d" => Some(VectorArrangement::D2),
"b" => Some(VectorArrangement::SveB),
"h" => Some(VectorArrangement::SveH),
"s" => Some(VectorArrangement::SveS),
"d" => Some(VectorArrangement::SveD),
_ => None,
}
}
pub fn element_bits(self) -> u32 {
match self {
VectorArrangement::B8 | VectorArrangement::B16 | VectorArrangement::SveB => 8,
VectorArrangement::H4 | VectorArrangement::H8 | VectorArrangement::SveH => 16,
VectorArrangement::S2 | VectorArrangement::S4 | VectorArrangement::SveS => 32,
VectorArrangement::D1 | VectorArrangement::D2 | VectorArrangement::SveD => 64,
}
}
pub fn total_bits(self) -> u32 {
match self {
VectorArrangement::B8
| VectorArrangement::H4
| VectorArrangement::S2
| VectorArrangement::D1 => 64,
VectorArrangement::B16
| VectorArrangement::H8
| VectorArrangement::S4
| VectorArrangement::D2 => 128,
VectorArrangement::SveB
| VectorArrangement::SveH
| VectorArrangement::SveS
| VectorArrangement::SveD => 0,
}
}
pub fn lane_count(self) -> u32 {
let total = self.total_bits();
if total == 0 {
return 0;
}
total / self.element_bits()
}
pub fn sve_size(self) -> Option<u32> {
match self {
VectorArrangement::SveB => Some(0),
VectorArrangement::SveH => Some(1),
VectorArrangement::SveS => Some(2),
VectorArrangement::SveD => Some(3),
_ => None,
}
}
}
impl fmt::Display for VectorArrangement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VectorArrangement::B8 => write!(f, "8B"),
VectorArrangement::B16 => write!(f, "16B"),
VectorArrangement::H4 => write!(f, "4H"),
VectorArrangement::H8 => write!(f, "8H"),
VectorArrangement::S2 => write!(f, "2S"),
VectorArrangement::S4 => write!(f, "4S"),
VectorArrangement::D1 => write!(f, "1D"),
VectorArrangement::D2 => write!(f, "2D"),
VectorArrangement::SveB => write!(f, "B"),
VectorArrangement::SveH => write!(f, "H"),
VectorArrangement::SveS => write!(f, "S"),
VectorArrangement::SveD => write!(f, "D"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SvePredQual {
Merging,
Zeroing,
}
impl fmt::Display for SvePredQual {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SvePredQual::Merging => write!(f, "/m"),
SvePredQual::Zeroing => write!(f, "/z"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OperandSize {
Byte,
Word,
Dword,
Qword,
Xmmword,
Ymmword,
Zmmword,
}
impl OperandSize {
pub fn bits(self) -> u16 {
match self {
OperandSize::Byte => 8,
OperandSize::Word => 16,
OperandSize::Dword => 32,
OperandSize::Qword => 64,
OperandSize::Xmmword => 128,
OperandSize::Ymmword => 256,
OperandSize::Zmmword => 512,
}
}
}
impl fmt::Display for OperandSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OperandSize::Byte => write!(f, "byte"),
OperandSize::Word => write!(f, "word"),
OperandSize::Dword => write!(f, "dword"),
OperandSize::Qword => write!(f, "qword"),
OperandSize::Xmmword => write!(f, "xmmword"),
OperandSize::Ymmword => write!(f, "ymmword"),
OperandSize::Zmmword => write!(f, "zmmword"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AddrMode {
#[default]
Offset,
PreIndex,
PostIndex,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemoryOperand {
pub size: Option<OperandSize>,
pub base: Option<Register>,
pub index: Option<Register>,
pub scale: u8,
pub disp: i64,
pub segment: Option<Register>,
pub disp_label: Option<String>,
pub addr_mode: AddrMode,
pub index_subtract: bool,
}
impl Default for MemoryOperand {
fn default() -> Self {
Self {
size: None,
base: None,
index: None,
scale: 1,
disp: 0,
segment: None,
disp_label: None,
addr_mode: AddrMode::Offset,
index_subtract: false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Expr {
Num(i128),
Label(String),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
}
impl Expr {
pub fn eval(&self) -> Option<i128> {
match self {
Expr::Num(n) => Some(*n),
Expr::Label(_) => None,
Expr::Add(l, r) => Some(l.eval()?.checked_add(r.eval()?)?),
Expr::Sub(l, r) => Some(l.eval()?.checked_sub(r.eval()?)?),
}
}
pub fn label_addend(&self) -> Option<(&str, i64)> {
let mut label: Option<&str> = None;
let mut addend: i64 = 0;
if self.collect_single_label(&mut label, &mut addend, 1) {
label.map(|l| (l, addend))
} else {
None
}
}
pub fn resolve_constants(&mut self, lookup: impl Fn(&str) -> Option<i128> + Copy) {
match self {
Expr::Label(name) => {
if let Some(val) = lookup(name) {
*self = Expr::Num(val);
}
}
Expr::Add(l, r) | Expr::Sub(l, r) => {
l.resolve_constants(lookup);
r.resolve_constants(lookup);
}
Expr::Num(_) => {}
}
}
fn collect_single_label<'a>(
&'a self,
label: &mut Option<&'a str>,
addend: &mut i64,
sign: i64,
) -> bool {
match self {
Expr::Num(n) => {
*addend = addend.wrapping_add((*n as i64).wrapping_mul(sign));
true
}
Expr::Label(name) => {
if sign != 1 || label.is_some() {
false
} else {
*label = Some(name.as_str());
true
}
}
Expr::Add(l, r) => {
l.collect_single_label(label, addend, sign)
&& r.collect_single_label(label, addend, sign)
}
Expr::Sub(l, r) => {
l.collect_single_label(label, addend, sign)
&& r.collect_single_label(label, addend, -sign)
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Operand {
Missing,
Register(Register),
Immediate(i128),
Memory(Box<MemoryOperand>),
Label(String),
Expression(Expr),
RegisterList(Vec<Register>),
LiteralPoolValue(i128),
VectorRegister(Register, VectorArrangement),
SvePredicate(Register, SvePredQual),
VectorElement(Register, ElementSize, u8),
PsrField(PsrField),
Shift(ShiftOp, ShiftAmount),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ElementSize {
B,
H,
S,
D,
}
impl ElementSize {
#[must_use]
pub fn from_lower(s: &str) -> Option<Self> {
Some(match s {
"b" => ElementSize::B,
"h" => ElementSize::H,
"s" => ElementSize::S,
"d" => ElementSize::D,
_ => return None,
})
}
#[must_use]
pub fn lane_count(self) -> u8 {
match self {
ElementSize::B => 16,
ElementSize::H => 8,
ElementSize::S => 4,
ElementSize::D => 2,
}
}
#[must_use]
pub fn imm5(self, index: u8) -> u32 {
let index = u32::from(index);
match self {
ElementSize::B => (index << 1) | 0b1,
ElementSize::H => (index << 2) | 0b10,
ElementSize::S => (index << 3) | 0b100,
ElementSize::D => (index << 4) | 0b1000,
}
}
#[must_use]
pub fn imm4(self, index: u8) -> u32 {
let index = u32::from(index);
match self {
ElementSize::B => index,
ElementSize::H => index << 1,
ElementSize::S => index << 2,
ElementSize::D => index << 3,
}
}
}
impl fmt::Display for ElementSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
ElementSize::B => "b",
ElementSize::H => "h",
ElementSize::S => "s",
ElementSize::D => "d",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PsrField {
pub saved: bool,
pub mask: u8,
}
impl PsrField {
#[must_use]
pub fn from_lower(s: &str) -> Option<Self> {
let (name, suffix) = match s.split_once('_') {
Some((n, rest)) => (n, Some(rest)),
None => (s, None),
};
let saved = match name {
"cpsr" => false,
"spsr" => true,
_ => return None,
};
let mask = match suffix {
None => 0b1001,
Some("all") => 0b1111,
Some(fields) => {
let mut m = 0u8;
for ch in fields.chars() {
m |= match ch {
'c' => 0b0001,
'x' => 0b0010,
's' => 0b0100,
'f' => 0b1000,
_ => return None,
};
}
m
}
};
Some(Self { saved, mask })
}
}
impl fmt::Display for PsrField {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(if self.saved { "spsr" } else { "cpsr" })?;
if self.mask != 0b1001 {
f.write_str("_")?;
for (bit, ch) in [(0b0001, 'c'), (0b0010, 'x'), (0b0100, 's'), (0b1000, 'f')] {
if self.mask & bit != 0 {
write!(f, "{}", ch)?;
}
}
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ShiftOp {
Lsl,
Lsr,
Asr,
Ror,
Rrx,
Msl,
Uxtb,
Uxth,
Uxtw,
Uxtx,
Sxtb,
Sxth,
Sxtw,
Sxtx,
}
impl ShiftOp {
#[must_use]
pub fn from_lower(s: &str) -> Option<Self> {
Some(match s {
"lsl" => ShiftOp::Lsl,
"lsr" => ShiftOp::Lsr,
"asr" => ShiftOp::Asr,
"ror" => ShiftOp::Ror,
"rrx" => ShiftOp::Rrx,
"msl" => ShiftOp::Msl,
"uxtb" => ShiftOp::Uxtb,
"uxth" => ShiftOp::Uxth,
"uxtw" => ShiftOp::Uxtw,
"uxtx" => ShiftOp::Uxtx,
"sxtb" => ShiftOp::Sxtb,
"sxth" => ShiftOp::Sxth,
"sxtw" => ShiftOp::Sxtw,
"sxtx" => ShiftOp::Sxtx,
_ => return None,
})
}
#[must_use]
pub fn shift_type_bits(self) -> Option<u32> {
Some(match self {
ShiftOp::Lsl => 0b00,
ShiftOp::Lsr => 0b01,
ShiftOp::Asr => 0b10,
ShiftOp::Ror | ShiftOp::Rrx => 0b11,
_ => return None,
})
}
#[must_use]
pub fn extend_option_bits(self) -> Option<u32> {
Some(match self {
ShiftOp::Uxtb => 0b000,
ShiftOp::Uxth => 0b001,
ShiftOp::Uxtw => 0b010,
ShiftOp::Uxtx => 0b011,
ShiftOp::Sxtb => 0b100,
ShiftOp::Sxth => 0b101,
ShiftOp::Sxtw => 0b110,
ShiftOp::Sxtx => 0b111,
_ => return None,
})
}
}
impl fmt::Display for ShiftOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
ShiftOp::Lsl => "lsl",
ShiftOp::Lsr => "lsr",
ShiftOp::Asr => "asr",
ShiftOp::Ror => "ror",
ShiftOp::Rrx => "rrx",
ShiftOp::Msl => "msl",
ShiftOp::Uxtb => "uxtb",
ShiftOp::Uxth => "uxth",
ShiftOp::Uxtw => "uxtw",
ShiftOp::Uxtx => "uxtx",
ShiftOp::Sxtb => "sxtb",
ShiftOp::Sxth => "sxth",
ShiftOp::Sxtw => "sxtw",
ShiftOp::Sxtx => "sxtx",
};
f.write_str(s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ShiftAmount {
Immediate(i32),
Register(Register),
None,
}
impl fmt::Display for ShiftAmount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ShiftAmount::Immediate(v) => write!(f, " #{}", v),
ShiftAmount::Register(r) => write!(f, " {}", r),
ShiftAmount::None => Ok(()),
}
}
}
impl fmt::Display for Operand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Operand::Missing => f.write_str("<none>"),
Operand::Shift(op, amount) => write!(f, "{}{}", op, amount),
Operand::PsrField(psr) => write!(f, "{}", psr),
Operand::VectorElement(r, size, idx) => write!(f, "{}.{}[{}]", r, size, idx),
Operand::Register(r) => write!(f, "{}", r),
Operand::Immediate(v) => {
if *v < 0 {
write!(f, "-0x{:X}", v.wrapping_neg())
} else {
write!(f, "0x{:X}", v)
}
}
Operand::Memory(mem) => {
if let Some(sz) = mem.size {
write!(f, "{} ptr ", sz)?;
}
write!(f, "[")?;
let mut parts = false;
if let Some(base) = mem.base {
write!(f, "{}", base)?;
parts = true;
}
if let Some(idx) = mem.index {
if parts {
write!(f, "+")?;
}
write!(f, "{}*{}", idx, mem.scale)?;
parts = true;
}
if mem.disp != 0 || !parts {
if parts && mem.disp >= 0 {
write!(f, "+")?;
}
write!(f, "0x{:X}", mem.disp)?;
}
write!(f, "]")
}
Operand::Label(name) => write!(f, "{}", name),
Operand::Expression(expr) => write!(f, "{}", expr),
Operand::RegisterList(regs) => {
write!(f, "{{")?;
for (i, r) in regs.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", r)?;
}
write!(f, "}}")
}
Operand::LiteralPoolValue(v) => write!(f, "={}", v),
Operand::VectorRegister(r, arr) => write!(f, "{}.{}", r, arr),
Operand::SvePredicate(r, qual) => write!(f, "{}{}", r, qual),
}
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expr::Num(n) => write!(f, "{}", n),
Expr::Label(name) => write!(f, "{}", name),
Expr::Add(l, r) => write!(f, "({} + {})", l, r),
Expr::Sub(l, r) => write!(f, "({} - {})", l, r),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Prefix {
Lock,
Rep,
Repne,
SegFs,
SegGs,
}
impl fmt::Display for Prefix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Prefix::Lock => write!(f, "lock"),
Prefix::Rep => write!(f, "rep"),
Prefix::Repne => write!(f, "repne"),
Prefix::SegFs => write!(f, "fs"),
Prefix::SegGs => write!(f, "gs"),
}
}
}
#[derive(Clone, Copy)]
pub struct Mnemonic {
buf: [u8; 24],
len: u8,
}
impl Mnemonic {
pub const MAX_LEN: usize = 24;
#[inline]
pub const fn new() -> Self {
Self {
buf: [0; 24],
len: 0,
}
}
#[inline]
pub fn as_str(&self) -> &str {
core::str::from_utf8(&self.buf[..self.len as usize]).unwrap_or("")
}
#[inline]
pub fn len(&self) -> usize {
self.len as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl From<&str> for Mnemonic {
#[inline]
fn from(s: &str) -> Self {
let len = s.len().min(Self::MAX_LEN);
let mut buf = [0u8; 24];
buf[..len].copy_from_slice(&s.as_bytes()[..len]);
Self {
buf,
len: len as u8,
}
}
}
impl From<String> for Mnemonic {
#[inline]
fn from(s: String) -> Self {
Self::from(s.as_str())
}
}
impl core::ops::Deref for Mnemonic {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for Mnemonic {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl Eq for Mnemonic {}
impl PartialEq<str> for Mnemonic {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<&str> for Mnemonic {
#[inline]
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<Mnemonic> for str {
#[inline]
fn eq(&self, other: &Mnemonic) -> bool {
self == other.as_str()
}
}
impl PartialEq<Mnemonic> for &str {
#[inline]
fn eq(&self, other: &Mnemonic) -> bool {
*self == other.as_str()
}
}
impl PartialEq<String> for Mnemonic {
#[inline]
fn eq(&self, other: &String) -> bool {
self.as_str() == other.as_str()
}
}
impl fmt::Debug for Mnemonic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\"{}\"", self.as_str())
}
}
impl fmt::Display for Mnemonic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Default for Mnemonic {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Mnemonic {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Mnemonic {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V;
impl<'de> serde::de::Visitor<'de> for V {
type Value = Mnemonic;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "a mnemonic string (max 24 bytes)")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Mnemonic, E> {
if v.len() > Mnemonic::MAX_LEN {
return Err(E::custom("mnemonic exceeds 24 bytes"));
}
Ok(Mnemonic::from(v))
}
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Mnemonic, E> {
self.visit_str(&v)
}
}
deserializer.deserialize_str(V)
}
}
pub struct OperandList {
items: [Operand; 6],
len: u8,
}
impl OperandList {
pub const MAX_LEN: usize = 6;
#[inline]
pub fn new() -> Self {
Self {
items: core::array::from_fn(|_| Operand::default()),
len: 0,
}
}
#[inline]
#[must_use]
pub fn try_push(&mut self, op: Operand) -> bool {
if (self.len as usize) >= Self::MAX_LEN {
return false;
}
self.items[self.len as usize] = op;
self.len += 1;
true
}
#[inline]
pub fn push(&mut self, op: Operand) {
assert!(
(self.len as usize) < Self::MAX_LEN,
"OperandList overflow: max {} operands",
Self::MAX_LEN
);
self.items[self.len as usize] = op;
self.len += 1;
}
#[inline]
pub fn len(&self) -> usize {
self.len as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn as_slice(&self) -> &[Operand] {
&self.items[..self.len as usize]
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [Operand] {
&mut self.items[..self.len as usize]
}
}
impl core::ops::Index<usize> for OperandList {
type Output = Operand;
#[inline]
fn index(&self, idx: usize) -> &Operand {
match self.items.get(idx) {
Some(op) => op,
None => &Operand::Missing,
}
}
}
impl core::ops::IndexMut<usize> for OperandList {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut Operand {
assert!(
idx < self.len as usize,
"OperandList index {idx} out of range (len {})",
self.len
);
&mut self.items[idx]
}
}
impl core::ops::Deref for OperandList {
type Target = [Operand];
#[inline]
fn deref(&self) -> &[Operand] {
self.as_slice()
}
}
impl core::ops::DerefMut for OperandList {
#[inline]
fn deref_mut(&mut self) -> &mut [Operand] {
self.as_mut_slice()
}
}
impl Clone for OperandList {
fn clone(&self) -> Self {
let mut items: [Operand; 6] = core::array::from_fn(|_| Operand::default());
for (i, op) in self.items[..self.len as usize].iter().enumerate() {
items[i] = op.clone();
}
Self {
items,
len: self.len,
}
}
}
impl PartialEq for OperandList {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl PartialEq<Vec<Operand>> for OperandList {
fn eq(&self, other: &Vec<Operand>) -> bool {
self.as_slice() == &other[..]
}
}
impl fmt::Debug for OperandList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.as_slice().iter()).finish()
}
}
impl Default for OperandList {
fn default() -> Self {
Self::new()
}
}
impl From<Vec<Operand>> for OperandList {
fn from(v: Vec<Operand>) -> Self {
assert!(
v.len() <= Self::MAX_LEN,
"OperandList: max {} operands, got {}",
Self::MAX_LEN,
v.len()
);
let mut list = Self::new();
for op in v {
list.push(op);
}
list
}
}
impl<'a> IntoIterator for &'a OperandList {
type Item = &'a Operand;
type IntoIter = core::slice::Iter<'a, Operand>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a> IntoIterator for &'a mut OperandList {
type Item = &'a mut Operand;
type IntoIter = core::slice::IterMut<'a, Operand>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for OperandList {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for op in self.as_slice() {
seq.serialize_element(op)?;
}
seq.end()
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for OperandList {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let v: Vec<Operand> = Vec::deserialize(deserializer)?;
if v.len() > Self::MAX_LEN {
return Err(serde::de::Error::custom(alloc::format!(
"too many operands: {} > {}",
v.len(),
Self::MAX_LEN
)));
}
Ok(Self::from(v))
}
}
#[derive(Clone, Copy)]
pub struct PrefixList {
items: [Prefix; 4],
len: u8,
}
impl PrefixList {
pub const MAX_LEN: usize = 4;
#[inline]
pub const fn new() -> Self {
Self {
items: [Prefix::Lock; 4], len: 0,
}
}
#[inline]
pub fn push(&mut self, p: Prefix) {
assert!(
(self.len as usize) < Self::MAX_LEN,
"PrefixList overflow: max {} prefixes",
Self::MAX_LEN
);
self.items[self.len as usize] = p;
self.len += 1;
}
#[inline]
pub fn len(&self) -> usize {
self.len as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn as_slice(&self) -> &[Prefix] {
&self.items[..self.len as usize]
}
}
impl core::ops::Deref for PrefixList {
type Target = [Prefix];
#[inline]
fn deref(&self) -> &[Prefix] {
self.as_slice()
}
}
impl PartialEq for PrefixList {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for PrefixList {}
impl PartialEq<Vec<Prefix>> for PrefixList {
fn eq(&self, other: &Vec<Prefix>) -> bool {
self.as_slice() == &other[..]
}
}
impl fmt::Debug for PrefixList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.as_slice().iter()).finish()
}
}
impl Default for PrefixList {
fn default() -> Self {
Self::new()
}
}
impl From<Vec<Prefix>> for PrefixList {
fn from(v: Vec<Prefix>) -> Self {
assert!(
v.len() <= Self::MAX_LEN,
"PrefixList: max {} prefixes, got {}",
Self::MAX_LEN,
v.len()
);
let mut list = Self::new();
for p in v {
list.push(p);
}
list
}
}
impl<'a> IntoIterator for &'a PrefixList {
type Item = &'a Prefix;
type IntoIter = core::slice::Iter<'a, Prefix>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for PrefixList {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for p in self.as_slice() {
seq.serialize_element(p)?;
}
seq.end()
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for PrefixList {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let v: Vec<Prefix> = Vec::deserialize(deserializer)?;
if v.len() > Self::MAX_LEN {
return Err(serde::de::Error::custom(alloc::format!(
"too many prefixes: {} > {}",
v.len(),
Self::MAX_LEN
)));
}
Ok(Self::from(v))
}
}
impl Default for Operand {
#[inline]
fn default() -> Self {
Operand::Missing
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Instruction {
pub mnemonic: Mnemonic,
pub operands: OperandList,
pub size_hint: Option<OperandSize>,
pub prefixes: PrefixList,
pub opmask: Option<Register>,
pub zeroing: bool,
pub broadcast: Option<BroadcastMode>,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BroadcastMode {
OneToTwo,
OneToFour,
OneToEight,
OneToSixteen,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DataSize {
Byte,
Word,
Long,
Quad,
}
impl fmt::Display for DataSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DataSize::Byte => write!(f, ".byte"),
DataSize::Word => write!(f, ".word"),
DataSize::Long => write!(f, ".long"),
DataSize::Quad => write!(f, ".quad"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DataValue {
Integer(i128),
Label(String, i64),
Bytes(Vec<u8>),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DataDecl {
pub size: DataSize,
pub values: Vec<DataValue>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AlignDirective {
pub alignment: u32,
pub fill: Option<u8>,
pub max_skip: Option<u32>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConstDef {
pub name: String,
pub value: i128,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FillDirective {
pub count: u32,
pub size: u8,
pub value: i64,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SpaceDirective {
pub size: u32,
pub fill: u8,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OrgDirective {
pub offset: u64,
pub fill: u8,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum X86Mode {
Mode16,
Mode32,
Mode64,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(clippy::large_enum_variant)] pub enum Statement {
Label(String, Span),
Instruction(Instruction),
Data(DataDecl),
Align(AlignDirective),
Const(ConstDef),
Fill(FillDirective),
Space(SpaceDirective),
Org(OrgDirective),
CodeMode(X86Mode, Span),
Ltorg(Span),
OptionRvc(bool, Span),
ThumbMode(bool, Span),
ThumbFunc(Span),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn register_size_bits() {
assert_eq!(Register::Rax.size_bits(), 64);
assert_eq!(Register::Eax.size_bits(), 32);
assert_eq!(Register::Ax.size_bits(), 16);
assert_eq!(Register::Al.size_bits(), 8);
assert_eq!(Register::R8.size_bits(), 64);
assert_eq!(Register::R8d.size_bits(), 32);
}
#[test]
fn register_base_code() {
assert_eq!(Register::Rax.base_code(), 0);
assert_eq!(Register::Rcx.base_code(), 1);
assert_eq!(Register::Rdx.base_code(), 2);
assert_eq!(Register::Rbx.base_code(), 3);
assert_eq!(Register::Rsp.base_code(), 4);
assert_eq!(Register::Rbp.base_code(), 5);
assert_eq!(Register::Rsi.base_code(), 6);
assert_eq!(Register::Rdi.base_code(), 7);
}
#[test]
fn register_is_extended() {
assert!(!Register::Rax.is_extended());
assert!(Register::R8.is_extended());
assert!(Register::R15d.is_extended());
assert!(Register::R8b.is_extended());
}
#[test]
fn register_high_byte() {
assert!(Register::Ah.is_high_byte());
assert!(Register::Ch.is_high_byte());
assert!(!Register::Al.is_high_byte());
assert!(!Register::Spl.is_high_byte());
}
#[test]
fn arch_display() {
assert_eq!(format!("{}", Arch::X86_64), "x86_64");
assert_eq!(format!("{}", Arch::Aarch64), "AArch64");
}
#[test]
fn operand_size_bits() {
assert_eq!(OperandSize::Byte.bits(), 8);
assert_eq!(OperandSize::Word.bits(), 16);
assert_eq!(OperandSize::Dword.bits(), 32);
assert_eq!(OperandSize::Qword.bits(), 64);
assert_eq!(OperandSize::Xmmword.bits(), 128);
assert_eq!(OperandSize::Ymmword.bits(), 256);
assert_eq!(OperandSize::Zmmword.bits(), 512);
}
#[test]
fn register_display() {
assert_eq!(format!("{}", Register::Rax), "rax");
assert_eq!(format!("{}", Register::R8d), "r8d");
assert_eq!(format!("{}", Register::Xmm0), "xmm0");
assert_eq!(format!("{}", Register::Ymm0), "ymm0");
assert_eq!(format!("{}", Register::Zmm0), "zmm0");
assert_eq!(format!("{}", Register::K0), "k0");
}
#[test]
fn operand_size_display() {
assert_eq!(format!("{}", OperandSize::Byte), "byte");
assert_eq!(format!("{}", OperandSize::Qword), "qword");
}
#[test]
fn data_size_display() {
assert_eq!(format!("{}", DataSize::Byte), ".byte");
assert_eq!(format!("{}", DataSize::Quad), ".quad");
}
#[test]
fn prefix_display() {
assert_eq!(format!("{}", Prefix::Lock), "lock");
assert_eq!(format!("{}", Prefix::Rep), "rep");
}
#[test]
fn operand_display() {
assert_eq!(format!("{}", Operand::Register(Register::Rax)), "rax");
assert_eq!(format!("{}", Operand::Immediate(42)), "0x2A");
assert_eq!(format!("{}", Operand::Immediate(-1)), "-0x1");
assert_eq!(format!("{}", Operand::Label(String::from("loop"))), "loop");
let mem = MemoryOperand {
base: Some(Register::Rbp),
disp: 8,
..Default::default()
};
assert_eq!(format!("{}", Operand::Memory(Box::new(mem))), "[rbp+0x8]");
let mem2 = MemoryOperand {
base: Some(Register::Rbx),
index: Some(Register::Rcx),
scale: 4,
disp: 0,
size: Some(OperandSize::Dword),
..Default::default()
};
assert_eq!(
format!("{}", Operand::Memory(Box::new(mem2))),
"dword ptr [rbx+rcx*4]"
);
}
#[test]
fn expr_display() {
let expr = Expr::Add(
Box::new(Expr::Label(String::from("foo"))),
Box::new(Expr::Num(4)),
);
assert_eq!(format!("{}", expr), "(foo + 4)");
}
#[test]
fn expr_eval_numeric() {
let e = Expr::Add(Box::new(Expr::Num(10)), Box::new(Expr::Num(20)));
assert_eq!(e.eval(), Some(30));
}
#[test]
fn expr_eval_with_label_returns_none() {
let e = Expr::Add(
Box::new(Expr::Label(String::from("x"))),
Box::new(Expr::Num(5)),
);
assert_eq!(e.eval(), None);
}
#[test]
fn expr_label_addend_add() {
let e = Expr::Add(
Box::new(Expr::Label(String::from("data"))),
Box::new(Expr::Num(8)),
);
assert_eq!(e.label_addend(), Some(("data", 8)));
}
#[test]
fn expr_label_addend_sub() {
let e = Expr::Sub(
Box::new(Expr::Label(String::from("data"))),
Box::new(Expr::Num(3)),
);
assert_eq!(e.label_addend(), Some(("data", -3)));
}
#[test]
fn expr_label_addend_plain_label() {
let e = Expr::Label(String::from("foo"));
assert_eq!(e.label_addend(), Some(("foo", 0)));
}
#[test]
fn expr_label_addend_two_labels_returns_none() {
let e = Expr::Add(
Box::new(Expr::Label(String::from("a"))),
Box::new(Expr::Label(String::from("b"))),
);
assert_eq!(e.label_addend(), None);
}
#[test]
fn expr_resolve_constants() {
let mut e = Expr::Add(
Box::new(Expr::Label(String::from("SIZE"))),
Box::new(Expr::Num(1)),
);
e.resolve_constants(|name| if name == "SIZE" { Some(10) } else { None });
assert_eq!(e.eval(), Some(11));
}
#[test]
fn expr_resolve_constants_partial() {
let mut e = Expr::Add(
Box::new(Expr::Label(String::from("SIZE"))),
Box::new(Expr::Label(String::from("unknown"))),
);
e.resolve_constants(|name| if name == "SIZE" { Some(10) } else { None });
assert_eq!(e.eval(), None);
}
}