//! Intermediate representation for Wasm. use crate::{frontend, localssa::LocalSSATransform}; use anyhow::Result; use wasmparser::{FuncType, Operator, Type}; pub type SignatureId = usize; pub type FuncId = usize; pub type BlockId = usize; pub type InstId = usize; pub type ValueId = usize; pub const NO_VALUE: ValueId = usize::MAX; #[derive(Clone, Debug, Default)] pub struct Module<'a> { pub funcs: Vec>, pub signatures: Vec, pub globals: Vec, pub tables: Vec, } #[derive(Clone, Debug)] pub enum FuncDecl<'a> { Import(SignatureId), Body(SignatureId, FunctionBody<'a>), } impl<'a> FuncDecl<'a> { pub fn sig(&self) -> SignatureId { match self { FuncDecl::Import(sig) => *sig, FuncDecl::Body(sig, ..) => *sig, } } } #[derive(Clone, Debug, Default)] pub struct FunctionBody<'a> { pub locals: Vec, pub blocks: Vec>, pub values: Vec, } #[derive(Clone, Debug)] pub struct ValueDef { pub kind: ValueKind, pub ty: Type, } #[derive(Clone, Debug)] pub enum ValueKind { BlockParam(BlockId, usize), Inst(BlockId, InstId), } #[derive(Clone, Debug, Default)] pub struct Block<'a> { pub params: Vec, pub insts: Vec>, pub terminator: Terminator<'a>, } #[derive(Clone, Debug)] pub struct Inst<'a> { pub operator: Operator<'a>, pub outputs: Vec, pub inputs: Vec>, } #[derive(Clone, Debug)] pub enum Operand<'a> { /// An SSA value. Value(ValueId), /// Tree-ified instructions for Wasm emission. Sub(Box>), /// Undef values are produced when code is unreachable and thus /// removed/never executed. Undef, } impl<'a> Operand<'a> { pub fn value(value: ValueId) -> Self { if value == NO_VALUE { Operand::Undef } else { Operand::Value(value) } } } #[derive(Clone, Debug)] pub struct BlockTarget<'a> { pub block: BlockId, pub args: Vec>, } #[derive(Clone, Debug)] pub enum Terminator<'a> { Br { target: BlockTarget<'a>, }, CondBr { cond: Operand<'a>, if_true: BlockTarget<'a>, if_false: BlockTarget<'a>, }, Select { value: Operand<'a>, targets: Vec>, default: BlockTarget<'a>, }, Return { values: Vec>, }, None, } impl<'a> std::default::Default for Terminator<'a> { fn default() -> Self { Terminator::None } } impl<'a> Module<'a> { pub fn from_wasm_bytes(bytes: &'a [u8]) -> Result { let mut module = frontend::wasm_to_ir(bytes)?; for func in &mut module.funcs { match func { &mut FuncDecl::Body(_, ref mut body) => { let ssa_transform = LocalSSATransform::new(&body); // TODO } _ => {} } } Ok(module) } } impl<'a> Terminator<'a> { pub fn successors(&self) -> Vec { match self { Terminator::Return { .. } => vec![], Terminator::Br { target, .. } => vec![target.block], Terminator::CondBr { if_true, if_false, .. } => vec![if_true.block, if_false.block], Terminator::Select { ref targets, default, .. } => { let mut ret = targets .iter() .map(|target| target.block) .collect::>(); ret.push(default.block); ret } Terminator::None => vec![], } } }