use crate::{
event::EventId,
frontend::{
Pointer,
VAddr,
},
riscv::register::{
CsrRegister,
FpRegister,
GpRegister,
},
};
#[derive(Debug, Clone, Hash)]
pub enum ArithmeticBehavior {
Wrapping,
Saturating(bool),
Checked(bool),
}
impl Default for ArithmeticBehavior {
fn default() -> Self {
Self::Wrapping
}
}
#[derive(Debug, Clone, Hash)]
pub enum Comparison {
Equal,
NotEqual,
Less(bool),
LessEqual(bool),
}
#[derive(Debug, Clone, Hash)]
pub enum Register {
Gp(GpRegister),
Fp(FpRegister),
Csr(CsrRegister),
}
impl Register {
pub fn is_gp(&self) -> bool {
matches!(self, Self::Gp(_))
}
pub fn is_fp(&self) -> bool {
matches!(self, Self::Fp(_))
}
pub fn is_csr(&self) -> bool {
matches!(self, Self::Csr(_))
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum VarType {
Number,
Float32,
Float64,
}
#[derive(Debug, Copy, Clone, Hash)]
pub struct Var {
id: u32,
typ: VarType,
}
impl Var {
pub(crate) fn new(id: usize, typ: VarType) -> Self {
Self {
id: id as u32,
typ,
}
}
pub fn id(&self) -> usize {
self.id as usize
}
pub fn vartype(&self) -> VarType {
self.typ
}
#[inline]
pub fn is_number(&self) -> bool {
matches!(&self.typ, VarType::Number)
}
#[inline]
pub fn is_float32(&self) -> bool {
matches!(&self.typ, VarType::Float32)
}
#[inline]
pub fn is_float64(&self) -> bool {
matches!(&self.typ, VarType::Float64)
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Hash)]
pub enum Half {
Lower,
Upper,
}
#[derive(Debug, Clone, Hash)]
pub enum Signedness {
Signed,
Unsigned,
Mixed,
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Hash)]
pub enum Op {
NextInstruction {
vaddr: VAddr,
},
LoadVirtAddr { dst: Var, vaddr: VAddr },
StoreRegister { reg: Register, var: Var },
LoadImmediate { dst: Var, imm: u64 },
Jump { dst: Var },
LoadRegister { var: Var, reg: Register },
Add { dst: Var, src1: Var, src2: Var, behavior: ArithmeticBehavior },
Compare { dst: Var, lhs: Var, rhs: Var, comp: Comparison },
Branch { dst: Var, cond: Var },
LoadMemory { dst: Var, addr: Var, size: usize },
SignExtend { dst: Var, src: Var, size: usize },
StoreMemory { addr: Var, src: Var, size: usize },
Xor { dst: Var, src1: Var, src2: Var },
Or { dst: Var, src1: Var, src2: Var },
And { dst: Var, src1: Var, src2: Var },
Sub { dst: Var, lhs: Var, rhs: Var },
ShiftLeft { dst: Var, src: Var, amount: Var },
ShiftRight { dst: Var, src: Var, amount: Var, arithmetic: bool },
Nop,
PushEventArgs { args: Vec<Var> },
FireEvent { event: EventId },
CollectEventReturns { vars: Vec<Var> },
ZeroExtend { dst: Var, src: Var, size: usize },
Invert { dst: Var, src: Var },
Min { dst: Var, src1: Var, src2: Var, signs: Signedness },
Max { dst: Var, src1: Var, src2: Var, signs: Signedness },
NaNBox { dst: Var, src: Var },
ReinterpretAsFloat32 { dst: Var, src: Var },
ReinterpretAsFloat64 { dst: Var, src: Var },
MultiplyAdd { dst: Var, src1: Var, src2: Var, src3: Var },
NaNUnbox { dst: Var, src: Var },
ConvertNaN { dst: Var, src: Var },
Negate { dst: Var, src: Var },
Multiply { dst: Var, src1: Var, src2: Var, half: Half, signs: Signedness },
Divide { dst: Var, src1: Var, src2: Var, signs: Signedness },
Sqrt { dst: Var, src: Var },
ReinterpretAsInteger { dst: Var, src: Var },
Classify { dst: Var, src: Var },
ConvertToInteger32 { dst: Var, src: Var, sign: Signedness },
Round { dst: Var, src: Var, rm: Var },
ConvertToFloat32 { dst: Var, src: Var, sign: Signedness },
ConvertToFloat64 { dst: Var, src: Var, sign: Signedness },
ConvertToInteger64 { dst: Var, src: Var, sign: Signedness },
Remainder { dst: Var, src1: Var, src2: Var, signs: Signedness },
Copy { dst: Var, src: Var },
LoadPointer { dst: Var, pointer: Pointer },
}
impl Op {
pub fn is_terminator(&self) -> bool {
matches!(self, Op::Branch { .. } | Op::Jump { .. } | Op::FireEvent { .. })
}
pub fn output_variables(&self) -> Vec<Var> {
let mut ret = Vec::new();
match self {
Op::LoadVirtAddr {
dst,
..
} => ret.push(*dst),
Op::LoadImmediate {
dst,
..
} => ret.push(*dst),
Op::Add {
dst,
..
} => ret.push(*dst),
Op::Compare {
dst,
..
} => ret.push(*dst),
Op::LoadMemory {
dst,
..
} => ret.push(*dst),
Op::SignExtend {
dst,
..
} => ret.push(*dst),
Op::Xor {
dst,
..
} => ret.push(*dst),
Op::Or {
dst,
..
} => ret.push(*dst),
Op::And {
dst,
..
} => ret.push(*dst),
Op::Sub {
dst,
..
} => ret.push(*dst),
Op::ShiftLeft {
dst,
..
} => ret.push(*dst),
Op::ShiftRight {
dst,
..
} => ret.push(*dst),
Op::CollectEventReturns {
vars,
} => ret.clone_from(vars),
Op::ZeroExtend {
dst,
..
} => ret.push(*dst),
Op::Invert {
dst,
..
} => ret.push(*dst),
Op::Min {
dst,
..
} => ret.push(*dst),
Op::Max {
dst,
..
} => ret.push(*dst),
Op::NaNBox {
dst,
..
} => ret.push(*dst),
Op::ReinterpretAsFloat32 {
dst,
..
} => ret.push(*dst),
Op::ReinterpretAsFloat64 {
dst,
..
} => ret.push(*dst),
Op::MultiplyAdd {
dst,
..
} => ret.push(*dst),
Op::NaNUnbox {
dst,
..
} => ret.push(*dst),
Op::ConvertNaN {
dst,
..
} => ret.push(*dst),
Op::Negate {
dst,
..
} => ret.push(*dst),
Op::Multiply {
dst,
..
} => ret.push(*dst),
Op::Divide {
dst,
..
} => ret.push(*dst),
Op::Sqrt {
dst,
..
} => ret.push(*dst),
Op::ReinterpretAsInteger {
dst,
..
} => ret.push(*dst),
Op::Classify {
dst,
..
} => ret.push(*dst),
Op::ConvertToInteger32 {
dst,
..
} => ret.push(*dst),
Op::Round {
dst,
..
} => ret.push(*dst),
Op::ConvertToFloat32 {
dst,
..
} => ret.push(*dst),
Op::ConvertToFloat64 {
dst,
..
} => ret.push(*dst),
Op::ConvertToInteger64 {
dst,
..
} => ret.push(*dst),
Op::Remainder {
dst,
..
} => ret.push(*dst),
Op::StoreRegister {
..
} => {},
Op::Nop => {},
Op::PushEventArgs {
..
} => {},
Op::FireEvent {
..
} => {},
Op::StoreMemory {
..
} => {},
Op::Branch {
..
} => {},
Op::Jump {
..
} => {},
Op::NextInstruction {
..
} => {},
Op::LoadRegister {
var,
..
} => ret.push(*var),
Op::Copy {
dst,
..
} => ret.push(*dst),
Op::LoadPointer {
dst,
..
} => ret.push(*dst),
}
ret
}
pub fn input_variables(&self) -> Vec<Var> {
let mut ret = Vec::new();
match self {
Op::NextInstruction {
..
} => {},
Op::LoadVirtAddr {
..
} => {},
Op::StoreRegister {
var,
..
} => ret.push(*var),
Op::LoadImmediate {
..
} => {},
Op::Jump {
dst,
} => ret.push(*dst),
Op::LoadRegister {
..
} => {},
Op::Remainder {
src1,
src2,
..
}
| Op::Multiply {
src1,
src2,
..
}
| Op::Divide {
src1,
src2,
..
}
| Op::Min {
src1,
src2,
..
}
| Op::Max {
src1,
src2,
..
}
| Op::Xor {
src1,
src2,
..
}
| Op::Or {
src1,
src2,
..
}
| Op::And {
src1,
src2,
..
}
| Op::Add {
src1,
src2,
..
} => {
ret.push(*src1);
ret.push(*src2);
},
Op::ConvertToFloat32 {
src,
..
}
| Op::ConvertToFloat64 {
src,
..
}
| Op::ConvertToInteger64 {
src,
..
}
| Op::SignExtend {
src,
..
}
| Op::ZeroExtend {
src,
..
}
| Op::Invert {
src,
..
}
| Op::NaNBox {
src,
..
}
| Op::ReinterpretAsFloat32 {
src,
..
}
| Op::ReinterpretAsFloat64 {
src,
..
}
| Op::NaNUnbox {
src,
..
}
| Op::ConvertNaN {
src,
..
}
| Op::Negate {
src,
..
}
| Op::Sqrt {
src,
..
}
| Op::ReinterpretAsInteger {
src,
..
}
| Op::Classify {
src,
..
}
| Op::ConvertToInteger32 {
src,
..
} => ret.push(*src),
Op::Compare {
lhs,
rhs,
..
}
| Op::Sub {
lhs,
rhs,
..
} => {
ret.push(*lhs);
ret.push(*rhs);
},
Op::ShiftLeft {
src,
amount,
..
}
| Op::ShiftRight {
src,
amount,
..
} => {
ret.push(*src);
ret.push(*amount);
},
Op::Branch {
dst,
cond,
} => {
ret.push(*dst);
ret.push(*cond);
},
Op::LoadMemory {
addr,
..
} => ret.push(*addr),
Op::StoreMemory {
addr,
src,
..
} => {
ret.push(*addr);
ret.push(*src);
},
Op::Nop => {},
Op::PushEventArgs {
args,
} => ret.clone_from(args),
Op::FireEvent {
..
} => {},
Op::CollectEventReturns {
..
} => {},
Op::MultiplyAdd {
src1,
src2,
src3,
..
} => {
ret.push(*src1);
ret.push(*src2);
ret.push(*src3);
},
Op::Round {
src,
rm,
..
} => {
ret.push(*src);
ret.push(*rm);
},
Op::Copy {
src,
..
} => ret.push(*src),
Op::LoadPointer {
..
} => {},
}
ret
}
pub fn input_register(&self) -> Option<Register> {
match self {
Op::LoadRegister {
reg,
..
} => Some(reg.clone()),
_ => None,
}
}
pub fn output_register(&self) -> Option<Register> {
match self {
Op::StoreRegister {
reg,
..
} => Some(reg.clone()),
_ => None,
}
}
}