use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use strum_macros::IntoStaticStr;
#[repr(C, u8)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Const {
Bool(bool),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
F32(f32),
F64(f64),
}
impl Eq for Const {}
impl Hash for Const {
fn hash<H: Hasher>(&self, state: &mut H) {
let tag = unsafe { *(self as *const Self as *const u8) };
tag.hash(state);
match *self {
Const::Bool(v) => v.hash(state),
Const::I8(v) => v.hash(state),
Const::I16(v) => v.hash(state),
Const::I32(v) => v.hash(state),
Const::I64(v) => v.hash(state),
Const::I128(v) => v.hash(state),
Const::F32(v) => v.to_bits().hash(state),
Const::F64(v) => v.to_bits().hash(state),
}
}
}
pub trait OpCode:
From<usize> + Into<usize> + Copy + Clone + Debug + PartialEq + Eq + Hash + 'static
{
fn name(&self) -> &'static str;
fn ctrl_op(&self) -> Option<CtrlOp>;
fn is_effect_phi(&self) -> bool;
fn is_param(&self) -> bool;
fn is_move(&self) -> bool;
fn has_output(&self) -> bool;
fn is_phi(&self) -> bool {
self.ctrl_op() == Some(CtrlOp::Phi)
}
fn is_label_or_terminal(&self) -> bool {
self.ctrl_op()
.map(|op| op.is_label_or_terminal())
.unwrap_or(false)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr)]
#[repr(u8)]
pub enum BaseOp {
Start,
Param,
Region,
EffectPhi,
Phi,
Branch,
Jump,
BrTable,
Return,
DebugBreak,
Const,
Neg,
Not,
And,
Xor,
Or,
Shl,
ShrS,
ShrU,
Rotl,
Rotr,
Add,
Sub,
Mul,
DivS,
DivU,
RemS,
RemU,
Clz,
Ctz,
Popcnt,
FAdd,
FDiv,
FSqrt,
FRound,
FCeil,
FFloor,
FTrunc,
FAbs,
FCopysign,
SExt,
ZExt,
ITruncU,
CvtF2SI,
CvtF2UI,
CvtSI2F,
CvtUI2F,
CvtF2F,
Bitcast,
Wrap,
Eq,
Ne,
LtS,
LtU,
LeS,
LeU,
GtS,
GtU,
GeS,
GeU,
LtF,
LeF,
IsNan,
GtF,
GeF,
Call,
CallIndirect,
Move,
Load,
Store,
}
impl From<usize> for BaseOp {
fn from(v: usize) -> Self {
unsafe { std::mem::transmute(v as u8) }
}
}
impl Into<usize> for BaseOp {
fn into(self) -> usize {
self as usize
}
}
impl OpCode for BaseOp {
fn name(&self) -> &'static str {
self.into()
}
fn ctrl_op(&self) -> Option<CtrlOp> {
match self {
BaseOp::Phi => Some(CtrlOp::Phi),
BaseOp::Start => Some(CtrlOp::Start),
BaseOp::Region => Some(CtrlOp::Region),
BaseOp::Branch => Some(CtrlOp::Branch),
BaseOp::BrTable => Some(CtrlOp::BrTable),
BaseOp::Jump => Some(CtrlOp::Jump),
BaseOp::Return => Some(CtrlOp::Return),
_ => None,
}
}
fn is_param(&self) -> bool {
*self == Self::Param
}
fn is_move(&self) -> bool {
*self == Self::Move
}
fn is_effect_phi(&self) -> bool {
*self == BaseOp::EffectPhi
}
fn has_output(&self) -> bool {
match self {
BaseOp::Start
| BaseOp::Region
| BaseOp::EffectPhi
| BaseOp::Branch
| BaseOp::BrTable
| BaseOp::Jump
| BaseOp::Return
| BaseOp::DebugBreak
| BaseOp::Store => false,
_ => true,
}
}
}
#[derive(Debug, Clone, PartialEq, Hash)]
#[repr(u8)]
pub enum CtrlOp {
Start,
Region,
Phi,
Branch,
BrTable,
Jump,
Return,
}
impl CtrlOp {
pub fn is_label(&self) -> bool {
*self == CtrlOp::Start || *self == CtrlOp::Region
}
pub fn is_terminal(&self) -> bool {
*self == CtrlOp::Jump
|| *self == CtrlOp::Return
|| *self == CtrlOp::Branch
|| *self == CtrlOp::BrTable
}
pub fn is_label_or_terminal(&self) -> bool {
self.is_label() || self.is_terminal()
}
}