use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u32)]
pub enum Opcode {
Ret = 1,
Br = 2,
Switch = 3,
IndirectBr = 4,
Invoke = 5,
CallBr = 6,
Resume = 7,
CatchSwitch = 8,
CatchRet = 9,
CleanupRet = 10,
Unreachable = 11,
Add = 12,
FAdd = 13,
Sub = 14,
FSub = 15,
Mul = 16,
FMul = 17,
UDiv = 18,
SDiv = 19,
FDiv = 20,
URem = 21,
SRem = 22,
FRem = 23,
Shl = 24,
LShr = 25,
AShr = 26,
And = 27,
Or = 28,
Xor = 29,
Alloca = 30,
Load = 31,
Store = 32,
GetElementPtr = 33,
Fence = 34,
CmpXchg = 35,
AtomicRMW = 36,
Trunc = 37,
ZExt = 38,
SExt = 39,
FPToUI = 40,
FPToSI = 41,
UIToFP = 42,
SIToFP = 43,
FPTrunc = 44,
FPExt = 45,
PtrToInt = 46,
IntToPtr = 47,
BitCast = 48,
AddrSpaceCast = 49,
ICmp = 50,
FCmp = 51,
Phi = 52,
Call = 53,
Select = 54,
UserOp1 = 55,
UserOp2 = 56,
VAArg = 57,
ExtractElement = 58,
InsertElement = 59,
ShuffleVector = 60,
ExtractValue = 61,
InsertValue = 62,
LandingPad = 63,
Freeze = 64,
CatchPad = 65, CleanupPad = 66,
}
impl Opcode {
pub fn is_terminator(&self) -> bool {
matches!(
self,
Opcode::Ret
| Opcode::Br
| Opcode::Switch
| Opcode::IndirectBr
| Opcode::Invoke
| Opcode::CallBr
| Opcode::Resume
| Opcode::CatchSwitch
| Opcode::CatchRet
| Opcode::CleanupRet
| Opcode::Unreachable
)
}
pub fn is_binary(&self) -> bool {
matches!(
self,
Opcode::Add
| Opcode::FAdd
| Opcode::Sub
| Opcode::FSub
| Opcode::Mul
| Opcode::FMul
| Opcode::UDiv
| Opcode::SDiv
| Opcode::FDiv
| Opcode::URem
| Opcode::SRem
| Opcode::FRem
| Opcode::Shl
| Opcode::LShr
| Opcode::AShr
| Opcode::And
| Opcode::Or
| Opcode::Xor
)
}
pub fn is_cast(&self) -> bool {
matches!(
self,
Opcode::Trunc
| Opcode::ZExt
| Opcode::SExt
| Opcode::FPToUI
| Opcode::FPToSI
| Opcode::UIToFP
| Opcode::SIToFP
| Opcode::FPTrunc
| Opcode::FPExt
| Opcode::PtrToInt
| Opcode::IntToPtr
| Opcode::BitCast
| Opcode::AddrSpaceCast
)
}
pub fn is_memory(&self) -> bool {
matches!(
self,
Opcode::Alloca
| Opcode::Load
| Opcode::Store
| Opcode::GetElementPtr
| Opcode::Fence
| Opcode::CmpXchg
| Opcode::AtomicRMW
)
}
pub fn is_float(&self) -> bool {
matches!(
self,
Opcode::FAdd
| Opcode::FSub
| Opcode::FMul
| Opcode::FDiv
| Opcode::FRem
| Opcode::FPTrunc
| Opcode::FPExt
| Opcode::FPToUI
| Opcode::FPToSI
| Opcode::UIToFP
| Opcode::SIToFP
| Opcode::FCmp
)
}
pub fn is_compare(&self) -> bool {
matches!(self, Opcode::ICmp | Opcode::FCmp)
}
pub fn operand_count(&self) -> usize {
match self {
Opcode::Ret => 1,
Opcode::Br => 1,
Opcode::Switch => 2,
Opcode::IndirectBr => 1,
Opcode::Invoke => 3,
Opcode::CallBr => 3,
Opcode::Resume => 1,
Opcode::CatchSwitch => 1,
Opcode::CatchRet => 1,
Opcode::CleanupRet => 1,
Opcode::Unreachable => 0,
Opcode::Alloca => 1,
Opcode::Load => 1,
Opcode::Store => 2,
Opcode::GetElementPtr => 2,
Opcode::Fence => 1,
Opcode::CmpXchg => 4,
Opcode::AtomicRMW => 3,
Opcode::Phi => 1,
Opcode::Call => 1,
Opcode::Select => 3,
Opcode::VAArg => 1,
Opcode::ExtractElement => 2,
Opcode::InsertElement => 3,
Opcode::ShuffleVector => 3,
Opcode::ExtractValue => 2,
Opcode::InsertValue => 3,
Opcode::LandingPad => 1,
Opcode::Freeze => 1,
_ => 2, }
}
pub fn name(&self) -> &'static str {
match self {
Opcode::Ret => "ret",
Opcode::Br => "br",
Opcode::Switch => "switch",
Opcode::IndirectBr => "indirectbr",
Opcode::Invoke => "invoke",
Opcode::CallBr => "callbr",
Opcode::Resume => "resume",
Opcode::CatchPad => "catchpad",
Opcode::CleanupPad => "cleanuppad",
Opcode::CatchSwitch => "catchswitch",
Opcode::CatchRet => "catchret",
Opcode::CleanupRet => "cleanupret",
Opcode::Unreachable => "unreachable",
Opcode::Add => "add",
Opcode::FAdd => "fadd",
Opcode::Sub => "sub",
Opcode::FSub => "fsub",
Opcode::Mul => "mul",
Opcode::FMul => "fmul",
Opcode::UDiv => "udiv",
Opcode::SDiv => "sdiv",
Opcode::FDiv => "fdiv",
Opcode::URem => "urem",
Opcode::SRem => "srem",
Opcode::FRem => "frem",
Opcode::Shl => "shl",
Opcode::LShr => "lshr",
Opcode::AShr => "ashr",
Opcode::And => "and",
Opcode::Or => "or",
Opcode::Xor => "xor",
Opcode::Alloca => "alloca",
Opcode::Load => "load",
Opcode::Store => "store",
Opcode::GetElementPtr => "getelementptr",
Opcode::Fence => "fence",
Opcode::CmpXchg => "cmpxchg",
Opcode::AtomicRMW => "atomicrmw",
Opcode::Trunc => "trunc",
Opcode::ZExt => "zext",
Opcode::SExt => "sext",
Opcode::FPToUI => "fptoui",
Opcode::FPToSI => "fptosi",
Opcode::UIToFP => "uitofp",
Opcode::SIToFP => "sitofp",
Opcode::FPTrunc => "fptrunc",
Opcode::FPExt => "fpext",
Opcode::PtrToInt => "ptrtoint",
Opcode::IntToPtr => "inttoptr",
Opcode::BitCast => "bitcast",
Opcode::AddrSpaceCast => "addrspacecast",
Opcode::ICmp => "icmp",
Opcode::FCmp => "fcmp",
Opcode::Phi => "phi",
Opcode::Call => "call",
Opcode::Select => "select",
Opcode::VAArg => "va_arg",
Opcode::ExtractElement => "extractelement",
Opcode::InsertElement => "insertelement",
Opcode::ShuffleVector => "shufflevector",
Opcode::ExtractValue => "extractvalue",
Opcode::InsertValue => "insertvalue",
Opcode::LandingPad => "landingpad",
Opcode::Freeze => "freeze",
Opcode::UserOp1 => "userop1",
Opcode::UserOp2 => "userop2",
}
}
}
impl fmt::Display for Opcode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ICmpPred {
Eq,
Ne,
Ugt,
Uge,
Ult,
Ule,
Sgt,
Sge,
Slt,
Sle,
}
impl ICmpPred {
pub fn as_str(&self) -> &'static str {
match self {
ICmpPred::Eq => "eq",
ICmpPred::Ne => "ne",
ICmpPred::Ugt => "ugt",
ICmpPred::Uge => "uge",
ICmpPred::Ult => "ult",
ICmpPred::Ule => "ule",
ICmpPred::Sgt => "sgt",
ICmpPred::Sge => "sge",
ICmpPred::Slt => "slt",
ICmpPred::Sle => "sle",
}
}
pub fn is_signed(&self) -> bool {
matches!(
self,
ICmpPred::Sgt | ICmpPred::Sge | ICmpPred::Slt | ICmpPred::Sle
)
}
pub fn is_unsigned(&self) -> bool {
matches!(
self,
ICmpPred::Ugt | ICmpPred::Uge | ICmpPred::Ult | ICmpPred::Ule
)
}
pub fn swap(&self) -> ICmpPred {
match self {
ICmpPred::Eq => ICmpPred::Eq,
ICmpPred::Ne => ICmpPred::Ne,
ICmpPred::Ugt => ICmpPred::Ult,
ICmpPred::Uge => ICmpPred::Ule,
ICmpPred::Ult => ICmpPred::Ugt,
ICmpPred::Ule => ICmpPred::Uge,
ICmpPred::Sgt => ICmpPred::Slt,
ICmpPred::Sge => ICmpPred::Sle,
ICmpPred::Slt => ICmpPred::Sgt,
ICmpPred::Sle => ICmpPred::Sge,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FCmpPred {
False,
Oeq,
Ogt,
Oge,
Olt,
Ole,
One,
Ord,
Uno,
Ueq,
Ugt,
Uge,
Ult,
Ule,
Une,
True,
}
impl FCmpPred {
pub fn as_str(&self) -> &'static str {
match self {
FCmpPred::False => "false",
FCmpPred::Oeq => "oeq",
FCmpPred::Ogt => "ogt",
FCmpPred::Oge => "oge",
FCmpPred::Olt => "olt",
FCmpPred::Ole => "ole",
FCmpPred::One => "one",
FCmpPred::Ord => "ord",
FCmpPred::Uno => "uno",
FCmpPred::Ueq => "ueq",
FCmpPred::Ugt => "ugt",
FCmpPred::Uge => "uge",
FCmpPred::Ult => "ult",
FCmpPred::Ule => "ule",
FCmpPred::Une => "une",
FCmpPred::True => "true",
}
}
pub fn is_ordered(&self) -> bool {
matches!(
self,
FCmpPred::Oeq
| FCmpPred::Ogt
| FCmpPred::Oge
| FCmpPred::Olt
| FCmpPred::Ole
| FCmpPred::One
| FCmpPred::Ord
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_count() {
assert!(Opcode::Ret as u32 <= 64);
}
#[test]
fn test_terminator() {
assert!(Opcode::Ret.is_terminator());
assert!(!Opcode::Add.is_terminator());
}
#[test]
fn test_binary() {
assert!(Opcode::Add.is_binary());
assert!(!Opcode::Load.is_binary());
}
#[test]
fn test_cast() {
assert!(Opcode::ZExt.is_cast());
assert!(!Opcode::Add.is_cast());
}
#[test]
fn test_float() {
assert!(Opcode::FAdd.is_float());
assert!(!Opcode::Add.is_float());
}
#[test]
fn test_names() {
assert_eq!(Opcode::Add.name(), "add");
assert_eq!(Opcode::Ret.name(), "ret");
}
#[test]
fn test_icmp_swap() {
assert_eq!(ICmpPred::Sgt.swap(), ICmpPred::Slt);
}
#[test]
fn test_fcmp_ordered() {
assert!(FCmpPred::Oeq.is_ordered());
assert!(!FCmpPred::Uno.is_ordered());
}
}
impl Opcode {
pub fn as_u32(&self) -> u32 { *self as u32 }
pub fn as_mnemonic(&self) -> &'static str { self.name() }
pub fn is_binary_op(&self) -> bool { self.is_binary() }
pub fn is_memory_op(&self) -> bool { self.is_memory() }
}
impl fmt::Display for ICmpPred {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.as_str()) }
}
impl fmt::Display for FCmpPred {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.as_str()) }
}