use std::fmt;
use super::*;
use crate::ir::variable::SsaVarId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CmpKind {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
impl CmpKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Eq => "eq",
Self::Ne => "ne",
Self::Lt => "lt",
Self::Le => "le",
Self::Gt => "gt",
Self::Ge => "ge",
}
}
}
impl fmt::Display for CmpKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Eq => write!(f, "=="),
Self::Ne => write!(f, "!="),
Self::Lt => write!(f, "<"),
Self::Le => write!(f, "<="),
Self::Gt => write!(f, ">"),
Self::Ge => write!(f, ">="),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Signedness {
Signed,
Unsigned,
}
impl Signedness {
#[must_use]
pub const fn from_unsigned(unsigned: bool) -> Self {
if unsigned {
Self::Unsigned
} else {
Self::Signed
}
}
#[must_use]
pub const fn is_unsigned(self) -> bool {
matches!(self, Self::Unsigned)
}
}
impl fmt::Display for Signedness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Signed => write!(f, "signed"),
Self::Unsigned => write!(f, "unsigned"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum FenceKind {
Full,
Acquire,
Release,
AcqRel,
SeqCst,
}
impl fmt::Display for FenceKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Full => write!(f, "full"),
Self::Acquire => write!(f, "acquire"),
Self::Release => write!(f, "release"),
Self::AcqRel => write!(f, "acqrel"),
Self::SeqCst => write!(f, "seqcst"),
}
}
}
impl FenceKind {
#[must_use]
pub const fn ordering(self) -> AtomicOrdering {
match self {
Self::Full | Self::SeqCst => AtomicOrdering::SeqCst,
Self::Acquire => AtomicOrdering::Acquire,
Self::Release => AtomicOrdering::Release,
Self::AcqRel => AtomicOrdering::AcqRel,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AtomicOrdering {
Relaxed,
Acquire,
Release,
AcqRel,
SeqCst,
}
impl fmt::Display for AtomicOrdering {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Relaxed => write!(f, "relaxed"),
Self::Acquire => write!(f, "acquire"),
Self::Release => write!(f, "release"),
Self::AcqRel => write!(f, "acqrel"),
Self::SeqCst => write!(f, "seqcst"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AtomicAccessWidth {
Bits8,
Bits16,
Bits32,
Bits64,
Bits128,
Pointer,
}
impl AtomicAccessWidth {
#[must_use]
pub const fn bits(self) -> Option<u32> {
match self {
Self::Bits8 => Some(8),
Self::Bits16 => Some(16),
Self::Bits32 => Some(32),
Self::Bits64 => Some(64),
Self::Bits128 => Some(128),
Self::Pointer => None,
}
}
}
impl fmt::Display for AtomicAccessWidth {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Bits8 => write!(f, "i8"),
Self::Bits16 => write!(f, "i16"),
Self::Bits32 => write!(f, "i32"),
Self::Bits64 => write!(f, "i64"),
Self::Bits128 => write!(f, "i128"),
Self::Pointer => write!(f, "ptr"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AtomicRmwOp {
Xchg,
Add,
Sub,
And,
Or,
Xor,
Min,
Max,
AndNot,
MinU,
MaxU,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OperandRole {
Def,
FlagsDef,
Use,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SsaOpClass {
Synthetic,
Scalar,
Boolean,
Flags,
Vector,
Memory,
Atomic,
Call,
Control,
NativeOpaque,
NativeIntrinsic,
WideArithmetic,
Prefix,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SsaSimilarityClass {
Synthetic,
Constant,
Arithmetic,
Bitwise,
ShiftRotate,
Compare,
Boolean,
Select,
Conversion,
TypeFlow,
MemoryRead,
MemoryWrite,
MemoryReadWrite,
Allocation,
Atomic,
Fence,
Call,
Control,
Vector,
Flags,
WideArithmetic,
NativeOpaque,
Prefix,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SsaFeatureToken {
pub opcode: &'static str,
pub op_class: SsaOpClass,
pub similarity_class: SsaSimilarityClass,
pub effect_kind: SsaEffectKind,
pub def_count: usize,
pub use_count: usize,
pub may_throw: bool,
}
impl fmt::Display for SsaFeatureToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"op={};class={:?};sim={:?};effect={:?};defs={};uses={};throw={}",
self.opcode,
self.op_class,
self.similarity_class,
self.effect_kind,
self.def_count,
self.use_count,
self.may_throw
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NativeInstructionMetadata {
pub architecture: Option<String>,
pub address: Option<u64>,
pub raw_bytes: Vec<u8>,
}
impl NativeInstructionMetadata {
#[must_use]
pub fn new(architecture: Option<String>, address: Option<u64>, raw_bytes: Vec<u8>) -> Self {
Self {
architecture,
address,
raw_bytes,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NativeOpaqueData {
pub mnemonic: String,
pub metadata: Option<NativeInstructionMetadata>,
pub outputs: Vec<SsaVarId>,
pub inputs: Vec<SsaVarId>,
pub clobbers: Vec<NativeClobber>,
pub effects: SsaEffects,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NativeIntrinsicId {
Cpuid,
Rdtsc,
Rdtscp,
Rdmsr,
Wrmsr,
Rdpmc,
Xgetbv,
Xsetbv,
SystemCall,
SystemReturn,
BitDeposit,
BitExtract,
Crc32,
RandomNumber,
RandomSeed,
PointerAuth(PacKind),
Hypervisor,
Privileged,
ControlRegister,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PacKind {
Sign,
Authenticate,
Strip,
GenericMac,
}
impl fmt::Display for PacKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
Self::Sign => "sign",
Self::Authenticate => "auth",
Self::Strip => "strip",
Self::GenericMac => "genmac",
};
f.write_str(name)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KindedVecData<K> {
pub kind: K,
pub outputs: Vec<SsaVarId>,
pub inputs: Vec<SsaVarId>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VecImm8Data {
pub imm8: u8,
pub outputs: Vec<SsaVarId>,
pub inputs: Vec<SsaVarId>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NativeKindedData<K> {
pub kind: K,
pub mnemonic: String,
pub metadata: Option<NativeInstructionMetadata>,
pub outputs: Vec<SsaVarId>,
pub inputs: Vec<SsaVarId>,
pub clobbers: Vec<NativeClobber>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
pub enum TranscendentalKind {
Sin,
Cos,
SinCos,
Tan,
Atan,
Exp2m1,
Ylog2,
Ylog2p1,
Rem,
Rem1,
Scale,
Extract,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
pub enum FpuControlKind {
LoadControlWord,
StoreControlWord,
StoreStatusWord,
LoadEnvironment,
StoreEnvironment,
Save,
Restore,
SaveExtended,
RestoreExtended,
ClearExceptions,
DecrementStackTop,
IncrementStackTop,
FreeRegister,
NoOp,
Wait,
Initialize,
EmptyMmxState,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NativeIntrinsicData {
pub id: NativeIntrinsicId,
pub mnemonic: String,
pub metadata: Option<NativeInstructionMetadata>,
pub outputs: Vec<SsaVarId>,
pub inputs: Vec<SsaVarId>,
pub clobbers: Vec<NativeClobber>,
pub effects: SsaEffects,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SysRegNamespace {
X86Msr,
X86Xcr,
X86ControlReg,
X86DebugReg,
Arm64System,
RiscvCsr,
MipsCop0,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SystemOpKind {
CpuId,
Timestamp {
aux: bool,
},
ReadSysReg {
namespace: SysRegNamespace,
},
WriteSysReg {
namespace: SysRegNamespace,
},
ReadPerfCounter,
SystemCall,
SystemReturn,
Trap {
vector: Option<u8>,
},
InterruptReturn,
CacheMaintenance,
TlbMaintenance,
Barrier,
Privileged,
Hypervisor,
HardwareEngine,
Transaction(SystemTransactionKind),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SystemTransactionKind {
Start,
Commit,
Cancel,
Test,
}
impl SystemOpKind {
#[must_use]
pub const fn effects(self) -> SsaEffects {
match self {
Self::CpuId
| Self::Timestamp { .. }
| Self::ReadSysReg { .. }
| Self::ReadPerfCounter => SsaEffects::new(SsaEffectKind::Read, false),
Self::WriteSysReg { .. }
| Self::Privileged
| Self::CacheMaintenance
| Self::TlbMaintenance
| Self::HardwareEngine
| Self::Transaction(_) => SsaEffects::new(SsaEffectKind::Write, false),
Self::Barrier => {
SsaEffects::new(SsaEffectKind::Fence, false).fence_ordering(AtomicOrdering::SeqCst)
}
Self::SystemCall | Self::SystemReturn | Self::Hypervisor | Self::Trap { .. } => {
SsaEffects::new(SsaEffectKind::Call, true).with_control(ControlEffect::Call)
}
Self::InterruptReturn => {
SsaEffects::new(SsaEffectKind::Call, false).with_control(ControlEffect::Call)
}
}
}
#[must_use]
pub const fn kind_str(self) -> &'static str {
match self {
Self::CpuId => "system.cpuid",
Self::Timestamp { .. } => "system.timestamp",
Self::ReadSysReg { .. } => "system.sysreg.read",
Self::WriteSysReg { .. } => "system.sysreg.write",
Self::ReadPerfCounter => "system.perfcounter",
Self::SystemCall => "system.syscall",
Self::SystemReturn => "system.sysreturn",
Self::Trap { .. } => "system.trap",
Self::InterruptReturn => "system.iret",
Self::CacheMaintenance => "system.cache",
Self::TlbMaintenance => "system.tlb",
Self::Barrier => "system.barrier",
Self::Privileged => "system.privileged",
Self::Hypervisor => "system.hypervisor",
Self::HardwareEngine => "system.hwengine",
Self::Transaction(SystemTransactionKind::Start) => "system.txn.start",
Self::Transaction(SystemTransactionKind::Commit) => "system.txn.commit",
Self::Transaction(SystemTransactionKind::Cancel) => "system.txn.cancel",
Self::Transaction(SystemTransactionKind::Test) => "system.txn.test",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ComputeKind {
BitDeposit,
BitExtract,
Checksum,
Random {
from_entropy: bool,
},
PointerAuth(PacKind),
MipsDspAccumulate,
}
impl ComputeKind {
#[must_use]
pub const fn effects(self) -> SsaEffects {
match self {
Self::BitDeposit
| Self::BitExtract
| Self::Checksum
| Self::PointerAuth(_)
| Self::MipsDspAccumulate => SsaEffects::new(SsaEffectKind::Pure, false),
Self::Random { .. } => SsaEffects::new(SsaEffectKind::Read, false),
}
}
#[must_use]
pub const fn kind_str(self) -> &'static str {
match self {
Self::BitDeposit => "compute.pdep",
Self::BitExtract => "compute.pext",
Self::Checksum => "compute.crc32",
Self::Random {
from_entropy: false,
} => "compute.rdrand",
Self::Random { from_entropy: true } => "compute.rdseed",
Self::PointerAuth(_) => "compute.pac",
Self::MipsDspAccumulate => "compute.mips_dsp_acc",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
pub enum BcdAdjustKind {
DecimalAddAdjust,
DecimalSubAdjust,
AsciiAddAdjust,
AsciiSubAdjust,
AsciiMulAdjust,
AsciiDivAdjust,
}
impl BcdAdjustKind {
#[must_use]
pub const fn effects(self) -> SsaEffects {
SsaEffects::new(SsaEffectKind::Pure, false)
}
#[must_use]
pub const fn kind_str(self) -> &'static str {
match self {
Self::DecimalAddAdjust => "bcd.daa",
Self::DecimalSubAdjust => "bcd.das",
Self::AsciiAddAdjust => "bcd.aaa",
Self::AsciiSubAdjust => "bcd.aas",
Self::AsciiMulAdjust => "bcd.aam",
Self::AsciiDivAdjust => "bcd.aad",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BcdAdjustData {
pub kind: BcdAdjustKind,
pub base: u8,
pub mnemonic: String,
pub metadata: Option<NativeInstructionMetadata>,
pub outputs: Vec<SsaVarId>,
pub inputs: Vec<SsaVarId>,
pub clobbers: Vec<NativeClobber>,
}