pub type VReg = u32;
pub type Label = u32;
#[derive(Debug, Clone)]
pub enum Ir {
Add(VReg, VReg, VReg),
Sub(VReg, VReg, VReg),
Mul(VReg, VReg, VReg),
Div(VReg, VReg, VReg),
Mod(VReg, VReg, VReg),
AddSat(VReg, VReg, VReg),
SubSat(VReg, VReg, VReg),
And(VReg, VReg, VReg),
Or(VReg, VReg, VReg),
Xor(VReg, VReg, VReg),
Not(VReg, VReg),
Shl(VReg, VReg, u8),
Shr(VReg, VReg, u8),
Eq(VReg, VReg, VReg),
Ne(VReg, VReg, VReg),
Lt(VReg, VReg, VReg),
Lte(VReg, VReg, VReg),
Gt(VReg, VReg, VReg),
Gte(VReg, VReg, VReg),
IsZero(VReg, VReg),
Label(Label),
Jump(Label),
JumpIf(VReg, Label),
JumpIfNot(VReg, Label),
Call(Label),
Return,
Halt,
Trap(u16),
LoadConst(VReg, Vec<u8>),
LoadConstIndex(VReg, Vec<u8>),
LoadImm8(VReg, u8),
LoadImm64(VReg, u64),
Mov(VReg, VReg),
SLoad(VReg, VReg),
SStore(VReg, VReg),
SDelete(VReg),
GetCaller(VReg),
GetOwner(VReg),
GetCellId(VReg),
GetHeight(VReg),
GetTimestamp(VReg),
GetValue(VReg),
GetCalldataLen(VReg),
GetCalldata(VReg, VReg),
SetReturn(VReg, VReg),
SetReturnReg(VReg, VReg),
EmitLog(VReg, VReg),
EmitLogReg(VReg, VReg, VReg),
CallCell(VReg, VReg, VReg, VReg),
BufReset,
BufWriteConst(Vec<u8>),
BufWriteReg(VReg),
BufCallCell(VReg, VReg),
BufSetReturn,
Hash32(VReg, VReg),
Hash32Const(VReg, Vec<u8>),
RequireOwner,
RequireCaller(VReg),
RequireEq(VReg, VReg),
RequireNe(VReg, VReg),
RequireLt(VReg, VReg),
RequireNonZero(VReg),
RequireGas(u64),
TokenBalance(VReg, VReg, VReg),
TokenTransfer(VReg, VReg, VReg, VReg),
TokenMint(VReg, VReg, VReg),
TokenBurn(VReg, VReg, VReg),
TokenFreeze(VReg, VReg),
TokenThaw(VReg, VReg),
AccordRequest(VReg, VReg, VReg, VReg),
AccordRead(VReg, VReg),
}
impl Ir {
pub fn def(&self) -> Option<VReg> {
match self {
Ir::Add(d, _, _)
| Ir::Sub(d, _, _)
| Ir::Mul(d, _, _)
| Ir::Div(d, _, _)
| Ir::Mod(d, _, _)
| Ir::AddSat(d, _, _)
| Ir::SubSat(d, _, _)
| Ir::And(d, _, _)
| Ir::Or(d, _, _)
| Ir::Xor(d, _, _)
| Ir::Not(d, _)
| Ir::Shl(d, _, _)
| Ir::Shr(d, _, _)
| Ir::Eq(d, _, _)
| Ir::Ne(d, _, _)
| Ir::Lt(d, _, _)
| Ir::Lte(d, _, _)
| Ir::Gt(d, _, _)
| Ir::Gte(d, _, _)
| Ir::IsZero(d, _)
| Ir::LoadConst(d, _)
| Ir::LoadConstIndex(d, _)
| Ir::LoadImm8(d, _)
| Ir::LoadImm64(d, _)
| Ir::Mov(d, _)
| Ir::SLoad(d, _)
| Ir::GetCaller(d)
| Ir::GetOwner(d)
| Ir::GetCellId(d)
| Ir::GetHeight(d)
| Ir::GetTimestamp(d)
| Ir::GetValue(d)
| Ir::GetCalldataLen(d)
| Ir::GetCalldata(d, _)
| Ir::Hash32(d, _)
| Ir::Hash32Const(d, _)
| Ir::TokenBalance(d, _, _)
| Ir::AccordRequest(d, _, _, _)
| Ir::AccordRead(d, _) => {
if *d != 0 {
Some(*d)
} else {
None
}
}
_ => None,
}
}
pub fn uses(&self) -> Vec<VReg> {
let mut v = Vec::new();
let mut push = |r: VReg| {
if r != 0 {
v.push(r);
}
};
match self {
Ir::Add(_, a, b)
| Ir::Sub(_, a, b)
| Ir::Mul(_, a, b)
| Ir::Div(_, a, b)
| Ir::Mod(_, a, b)
| Ir::AddSat(_, a, b)
| Ir::SubSat(_, a, b)
| Ir::And(_, a, b)
| Ir::Or(_, a, b)
| Ir::Xor(_, a, b)
| Ir::Eq(_, a, b)
| Ir::Ne(_, a, b)
| Ir::Lt(_, a, b)
| Ir::Lte(_, a, b)
| Ir::Gt(_, a, b)
| Ir::Gte(_, a, b) => {
push(*a);
push(*b);
}
Ir::Not(_, a)
| Ir::IsZero(_, a)
| Ir::Shl(_, a, _)
| Ir::Shr(_, a, _)
| Ir::Mov(_, a)
| Ir::SLoad(_, a)
| Ir::SDelete(a)
| Ir::GetCalldata(_, a)
| Ir::Hash32(_, a)
| Ir::RequireCaller(a)
| Ir::RequireNonZero(a) => {
push(*a);
}
Ir::SStore(k, v2)
| Ir::RequireEq(k, v2)
| Ir::RequireNe(k, v2)
| Ir::RequireLt(k, v2)
| Ir::SetReturn(k, v2)
| Ir::SetReturnReg(k, v2)
| Ir::EmitLog(k, v2)
| Ir::TokenFreeze(k, v2)
| Ir::TokenThaw(k, v2) => {
push(*k);
push(*v2);
}
Ir::EmitLogReg(t, d, l) => {
push(*t);
push(*d);
push(*l);
}
Ir::JumpIf(c, _) | Ir::JumpIfNot(c, _) => {
push(*c);
}
Ir::TokenBalance(_, t, a) | Ir::TokenMint(_, t, a) | Ir::TokenBurn(_, t, a) => {
push(*t);
push(*a);
}
Ir::TokenTransfer(tok, f, t, a) => {
push(*tok);
push(*f);
push(*t);
push(*a);
}
Ir::AccordRequest(_, url, meth, body) => {
push(*url);
push(*meth);
push(*body);
}
Ir::AccordRead(_, req) => {
push(*req);
}
Ir::CallCell(cell, cd, len, val) => {
push(*cell);
push(*cd);
push(*len);
push(*val);
}
Ir::BufWriteReg(src) => {
push(*src);
}
Ir::BufCallCell(cell, val) => {
push(*cell);
push(*val);
}
_ => {}
}
v
}
}