pub mod convert;
pub mod lower;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Reg(pub u32);
impl fmt::Display for Reg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "v{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Label(pub String);
impl Label {
pub fn new(name: impl Into<String>) -> Self {
Self(name.into())
}
}
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone)]
pub enum LIROp {
Call(String),
Return,
Halt,
Branch {
cond: Reg,
if_true: Label,
if_false: Label,
},
Jump(Label),
LabelDef(Label),
FnStart(String),
FnEnd,
Entry(String),
Comment(String),
Asm { lines: Vec<String> },
LoadImm(Reg, u64),
Move(Reg, Reg),
Add(Reg, Reg, Reg),
Mul(Reg, Reg, Reg),
Eq(Reg, Reg, Reg),
Lt(Reg, Reg, Reg),
And(Reg, Reg, Reg),
Or(Reg, Reg, Reg),
Xor(Reg, Reg, Reg),
DivMod {
dst_quot: Reg,
dst_rem: Reg,
src1: Reg,
src2: Reg,
},
Shl(Reg, Reg, Reg),
Shr(Reg, Reg, Reg),
Invert(Reg, Reg),
Split { dst_hi: Reg, dst_lo: Reg, src: Reg },
Log2(Reg, Reg),
Pow(Reg, Reg, Reg),
PopCount(Reg, Reg),
ReadIo { dst: Reg, count: u32 },
WriteIo { src: Reg, count: u32 },
Hint { dst: Reg, count: u32 },
Load { dst: Reg, base: Reg, offset: i32 },
Store { src: Reg, base: Reg, offset: i32 },
LoadMulti { dst: Reg, base: Reg, width: u32 },
StoreMulti { src: Reg, base: Reg, width: u32 },
Assert { src: Reg, count: u32 },
Hash { dst: Reg, src: Reg, count: u32 },
Reveal {
name: String,
tag: u64,
src: Reg,
field_count: u32,
},
Seal {
name: String,
tag: u64,
src: Reg,
field_count: u32,
},
RamRead { dst: Reg, key: Reg, width: u32 },
RamWrite { key: Reg, src: Reg, width: u32 },
SpongeInit(Reg),
SpongeAbsorb { state: Reg, src: Reg },
SpongeSqueeze { dst: Reg, state: Reg },
SpongeLoad { state: Reg, addr: Reg },
MerkleStep { dst: Reg, node: Reg, sibling: Reg },
MerkleLoad { dst: Reg, node: Reg, addr: Reg },
ExtMul(Reg, Reg, Reg),
ExtInvert(Reg, Reg),
FoldExt { dst: Reg, src1: Reg, src2: Reg },
FoldBase { dst: Reg, src1: Reg, src2: Reg },
ProofBlock { program_hash: String },
ProofBlockEnd,
}
impl fmt::Display for LIROp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LIROp::Call(label) => write!(f, "call {}", label),
LIROp::Return => write!(f, "ret"),
LIROp::Halt => write!(f, "halt"),
LIROp::Branch {
cond,
if_true,
if_false,
} => {
write!(f, "br {}, {}, {}", cond, if_true, if_false)
}
LIROp::Jump(label) => write!(f, "jmp {}", label),
LIROp::LabelDef(label) => write!(f, "{}:", label),
LIROp::FnStart(name) => write!(f, "fn {}:", name),
LIROp::FnEnd => write!(f, "fn_end"),
LIROp::Entry(main) => write!(f, "entry {}", main),
LIROp::Comment(text) => write!(f, "// {}", text),
LIROp::Asm { lines } => write!(f, "asm({} lines)", lines.len()),
LIROp::LoadImm(dst, val) => write!(f, "li {}, {}", dst, val),
LIROp::Move(dst, src) => write!(f, "mv {}, {}", dst, src),
LIROp::Add(d, a, b) => write!(f, "add {}, {}, {}", d, a, b),
LIROp::Mul(d, a, b) => write!(f, "mul {}, {}, {}", d, a, b),
LIROp::Eq(d, a, b) => write!(f, "eq {}, {}, {}", d, a, b),
LIROp::Lt(d, a, b) => write!(f, "lt {}, {}, {}", d, a, b),
LIROp::And(d, a, b) => write!(f, "and {}, {}, {}", d, a, b),
LIROp::Or(d, a, b) => write!(f, "or {}, {}, {}", d, a, b),
LIROp::Xor(d, a, b) => write!(f, "xor {}, {}, {}", d, a, b),
LIROp::DivMod {
dst_quot,
dst_rem,
src1,
src2,
} => {
write!(f, "divmod {}, {}, {}, {}", dst_quot, dst_rem, src1, src2)
}
LIROp::Shl(d, a, b) => write!(f, "shl {}, {}, {}", d, a, b),
LIROp::Shr(d, a, b) => write!(f, "shr {}, {}, {}", d, a, b),
LIROp::Invert(d, s) => write!(f, "inv {}, {}", d, s),
LIROp::Split {
dst_hi,
dst_lo,
src,
} => {
write!(f, "split {}, {}, {}", dst_hi, dst_lo, src)
}
LIROp::Log2(d, s) => write!(f, "log2 {}, {}", d, s),
LIROp::Pow(d, b, e) => write!(f, "pow {}, {}, {}", d, b, e),
LIROp::PopCount(d, s) => write!(f, "popcnt {}, {}", d, s),
LIROp::ReadIo { dst, count } => write!(f, "read_io {}, {}", dst, count),
LIROp::WriteIo { src, count } => write!(f, "write_io {}, {}", src, count),
LIROp::Hint { dst, count } => write!(f, "hint {}, {}", dst, count),
LIROp::Load { dst, base, offset } => {
write!(f, "ld {}, [{}+{}]", dst, base, offset)
}
LIROp::Store { src, base, offset } => {
write!(f, "st {}, [{}+{}]", src, base, offset)
}
LIROp::LoadMulti { dst, base, width } => {
write!(f, "ldm {}, [{}], {}", dst, base, width)
}
LIROp::StoreMulti { src, base, width } => {
write!(f, "stm {}, [{}], {}", src, base, width)
}
LIROp::Assert { src, count } => {
write!(f, "assert {}, {}", src, count)
}
LIROp::Hash { dst, src, count } => {
write!(f, "hash {}, {}, {}", dst, src, count)
}
LIROp::Reveal {
name,
src,
field_count,
..
} => {
write!(f, "reveal {}({}, {})", name, src, field_count)
}
LIROp::Seal {
name,
src,
field_count,
..
} => {
write!(f, "seal {}({}, {})", name, src, field_count)
}
LIROp::RamRead { dst, key, width } => {
write!(f, "ram_read {}, {}, {}", dst, key, width)
}
LIROp::RamWrite { key, src, width } => {
write!(f, "ram_write {}, {}, {}", key, src, width)
}
LIROp::SpongeInit(d) => write!(f, "sponge_init {}", d),
LIROp::SpongeAbsorb { state, src } => {
write!(f, "sponge_absorb {}, {}", state, src)
}
LIROp::SpongeSqueeze { dst, state } => {
write!(f, "sponge_squeeze {}, {}", dst, state)
}
LIROp::SpongeLoad { state, addr } => {
write!(f, "sponge_load {}, {}", state, addr)
}
LIROp::MerkleStep { dst, node, sibling } => {
write!(f, "merkle_step {}, {}, {}", dst, node, sibling)
}
LIROp::MerkleLoad { dst, node, addr } => {
write!(f, "merkle_load {}, {}, {}", dst, node, addr)
}
LIROp::ExtMul(d, a, b) => write!(f, "ext_mul {}, {}, {}", d, a, b),
LIROp::ExtInvert(d, s) => write!(f, "ext_inv {}, {}", d, s),
LIROp::FoldExt { dst, src1, src2 } => {
write!(f, "fold_ext {}, {}, {}", dst, src1, src2)
}
LIROp::FoldBase { dst, src1, src2 } => {
write!(f, "fold_base {}, {}, {}", dst, src1, src2)
}
LIROp::ProofBlock { program_hash } => {
write!(f, "proof_block {}", program_hash)
}
LIROp::ProofBlockEnd => write!(f, "proof_block_end"),
}
}
}
#[cfg(test)]
mod tests;