diff --git a/src/frontend.rs b/src/frontend.rs index 1a7a591..5027a39 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -1,11 +1,14 @@ //! Frontend: convert Wasm to IR. +#![allow(dead_code)] + use crate::ir::*; +use crate::op_traits::{op_inputs, op_outputs}; use anyhow::anyhow; -use anyhow::Result; +use anyhow::{bail, Result}; use log::trace; use std::collections::VecDeque; -use wasmparser::{ImportSectionEntryType, Operator, Parser, Payload, TypeDef}; +use wasmparser::{FuncType, ImportSectionEntryType, Operator, Parser, Payload, Type, TypeDef}; pub fn wasm_to_ir(bytes: &[u8]) -> Result { let mut module = Module::default(); @@ -56,7 +59,7 @@ fn handle_payload<'a>( let sig = func_sigs .pop_front() .ok_or_else(|| anyhow!("mismatched func section and code section sizes"))?; - let body = parse_body(body)?; + let body = parse_body(&module, body)?; module.funcs.push(FuncDecl::Body(sig as SignatureId, body)); } _ => {} @@ -65,7 +68,7 @@ fn handle_payload<'a>( Ok(()) } -fn parse_body(body: wasmparser::FunctionBody) -> Result { +fn parse_body(module: &Module, body: wasmparser::FunctionBody) -> Result { let mut ret = FunctionBody::default(); let mut locals = body.get_locals_reader()?; for _ in 0..locals.get_count() { @@ -75,7 +78,7 @@ fn parse_body(body: wasmparser::FunctionBody) -> Result { } } - let mut builder = FunctionBodyBuilder::new(&mut ret); + let mut builder = FunctionBodyBuilder::new(&module.signatures[..], &mut ret); let ops = body.get_operators_reader()?; for op in ops.into_iter() { let op = op?; @@ -87,19 +90,87 @@ fn parse_body(body: wasmparser::FunctionBody) -> Result { #[derive(Debug)] struct FunctionBodyBuilder<'a> { + signatures: &'a [FuncType], body: &'a mut FunctionBody, + cur_block: BlockId, + ctrl_stack: Vec, + op_stack: Vec, +} + +#[derive(Debug)] +enum Frame { + Block { + out: Block, + params: Vec, + results: Vec, + }, + Loop { + top: Block, + out: Block, + params: Vec, + results: Vec, + }, + If { + out: Block, + el: Block, + params: Vec, + results: Vec, + }, + Else { + out: Block, + params: Vec, + results: Vec, + }, } impl<'a> FunctionBodyBuilder<'a> { - fn new(body: &'a mut FunctionBody) -> Self { - Self { body } + fn new(signatures: &'a [FuncType], body: &'a mut FunctionBody) -> Self { + body.blocks.push(Block::default()); + Self { + signatures, + body, + ctrl_stack: vec![], + op_stack: vec![], + cur_block: 0, + } } fn handle_op(&mut self, op: Operator<'_>) -> Result<()> { match op { - _ => {} + Operator::Unreachable => self.emit(Operator::Unreachable, vec![], vec![])?, + _ => bail!("Unsupported operator: {:?}", op), } Ok(()) } + + fn emit( + &mut self, + op: Operator<'static>, + outputs: Vec, + inputs: Vec, + ) -> Result<()> { + let block = self.cur_block; + let inst = self.body.blocks[block].insts.len() as InstId; + + for input in op_inputs(self.signatures, &op)?.into_iter().rev() { + assert_eq!(self.body.values[self.op_stack.pop().unwrap()].ty, input); + } + for output in op_outputs(self.signatures, &op)?.into_iter() { + let val = self.body.values.len() as ValueId; + self.body.values.push(ValueDef { + kind: ValueKind::Inst(block, inst), + ty: output, + }); + self.op_stack.push(val); + } + + self.body.blocks[self.cur_block].insts.push(Inst { + operator: op, + outputs, + inputs, + }); + + Ok(()) + } } diff --git a/src/ir.rs b/src/ir.rs index 696bee1..fcf2a09 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -36,7 +36,7 @@ pub struct ValueDef { #[derive(Clone, Debug)] pub enum ValueKind { BlockParam(Block), - Inst(Block, Inst), + Inst(BlockId, InstId), } #[derive(Clone, Debug, Default)] @@ -56,4 +56,5 @@ pub struct Inst { pub enum Operand { Value(ValueId), Sub(Box), + Local(usize), // eliminated during local2ssa pass } diff --git a/src/lib.rs b/src/lib.rs index 7a84d4b..ebcc7de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,3 +7,4 @@ pub use wasmparser; pub mod frontend; pub mod ir; +pub mod op_traits; diff --git a/src/op_traits.rs b/src/op_traits.rs new file mode 100644 index 0000000..c0ae001 --- /dev/null +++ b/src/op_traits.rs @@ -0,0 +1,18 @@ +//! Metadata on operators. + +use anyhow::{bail, Result}; +use wasmparser::{FuncType, Operator, Type}; + +pub fn op_inputs(_sigs: &[FuncType], op: &Operator<'_>) -> Result> { + match op { + &Operator::Unreachable | &Operator::Nop => Ok(vec![]), + _ => bail!("Unknown operator in op_inputs(): {:?}", op), + } +} + +pub fn op_outputs(_sigs: &[FuncType], op: &Operator<'_>) -> Result> { + match op { + &Operator::Unreachable | &Operator::Nop => Ok(vec![]), + _ => bail!("Unknown operator in op_outputs(): {:?}", op), + } +}