diff --git a/src/frontend.rs b/src/frontend.rs index 5027a39..3a8221c 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -4,28 +4,26 @@ use crate::ir::*; use crate::op_traits::{op_inputs, op_outputs}; -use anyhow::anyhow; use anyhow::{bail, Result}; use log::trace; -use std::collections::VecDeque; -use wasmparser::{FuncType, ImportSectionEntryType, Operator, Parser, Payload, Type, TypeDef}; +use wasmparser::{ImportSectionEntryType, Operator, Parser, Payload, Type, TypeDef}; -pub fn wasm_to_ir(bytes: &[u8]) -> Result { +pub fn wasm_to_ir<'a>(bytes: &'a [u8]) -> Result> { let mut module = Module::default(); let parser = Parser::new(0); - let mut sigs = VecDeque::new(); + let mut next_func = 0; for payload in parser.parse_all(bytes) { let payload = payload?; - handle_payload(&mut module, payload, &mut sigs)?; + handle_payload(&mut module, payload, &mut next_func)?; } Ok(module) } fn handle_payload<'a>( - module: &mut Module, + module: &mut Module<'a>, payload: Payload<'a>, - func_sigs: &mut VecDeque, + next_func: &mut usize, ) -> Result<()> { trace!("Wasm parser item: {:?}", payload); match payload { @@ -45,6 +43,7 @@ fn handle_payload<'a>( match reader.read()?.ty { ImportSectionEntryType::Function(sig_idx) => { module.funcs.push(FuncDecl::Import(sig_idx as SignatureId)); + *next_func += 1; } _ => {} } @@ -52,15 +51,25 @@ fn handle_payload<'a>( } Payload::FunctionSection(mut reader) => { for _ in 0..reader.get_count() { - func_sigs.push_back(reader.read()? as SignatureId); + let sig_idx = reader.read()? as SignatureId; + module + .funcs + .push(FuncDecl::Body(sig_idx, FunctionBody::default())); } } Payload::CodeSectionEntry(body) => { - let sig = func_sigs - .pop_front() - .ok_or_else(|| anyhow!("mismatched func section and code section sizes"))?; - let body = parse_body(&module, body)?; - module.funcs.push(FuncDecl::Body(sig as SignatureId, body)); + let func_idx = *next_func; + *next_func += 1; + + let my_sig = module.funcs[func_idx].sig(); + let body = parse_body(&module, my_sig, body)?; + + match &mut module.funcs[func_idx] { + &mut FuncDecl::Body(_, ref mut existing_body) => { + *existing_body = body; + } + _ => unreachable!(), + } } _ => {} } @@ -68,8 +77,12 @@ fn handle_payload<'a>( Ok(()) } -fn parse_body(module: &Module, body: wasmparser::FunctionBody) -> Result { - let mut ret = FunctionBody::default(); +fn parse_body<'a, 'b>( + module: &'b Module<'a>, + my_sig: SignatureId, + body: wasmparser::FunctionBody<'a>, +) -> Result> { + let mut ret: FunctionBody<'a> = FunctionBody::default(); let mut locals = body.get_locals_reader()?; for _ in 0..locals.get_count() { let (count, ty) = locals.read()?; @@ -78,7 +91,7 @@ fn parse_body(module: &Module, body: wasmparser::FunctionBody) -> Result Result { - signatures: &'a [FuncType], - body: &'a mut FunctionBody, +struct FunctionBodyBuilder<'a, 'b> { + module: &'b Module<'a>, + my_sig: SignatureId, + body: &'b mut FunctionBody<'a>, cur_block: BlockId, ctrl_stack: Vec, op_stack: Vec, @@ -100,34 +114,35 @@ struct FunctionBodyBuilder<'a> { #[derive(Debug)] enum Frame { Block { - out: Block, + out: BlockId, params: Vec, results: Vec, }, Loop { - top: Block, - out: Block, + top: BlockId, + out: BlockId, params: Vec, results: Vec, }, If { - out: Block, - el: Block, + out: BlockId, + el: BlockId, params: Vec, results: Vec, }, Else { - out: Block, + out: BlockId, params: Vec, results: Vec, }, } -impl<'a> FunctionBodyBuilder<'a> { - fn new(signatures: &'a [FuncType], body: &'a mut FunctionBody) -> Self { +impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { + fn new(module: &'b Module<'a>, my_sig: SignatureId, body: &'b mut FunctionBody<'a>) -> Self { body.blocks.push(Block::default()); Self { - signatures, + module, + my_sig, body, ctrl_stack: vec![], op_stack: vec![], @@ -135,29 +150,47 @@ impl<'a> FunctionBodyBuilder<'a> { } } - fn handle_op(&mut self, op: Operator<'_>) -> Result<()> { + fn handle_op(&mut self, op: Operator<'a>) -> Result<()> { match op { - Operator::Unreachable => self.emit(Operator::Unreachable, vec![], vec![])?, + Operator::Unreachable + | Operator::Call { .. } + | Operator::LocalGet { .. } + | Operator::LocalSet { .. } + | Operator::LocalTee { .. } => self.emit(op.clone())?, + + Operator::End => { + if self.ctrl_stack.is_empty() { + self.emit(Operator::Return)?; + } else { + bail!("Unsupported End"); + } + } + _ => bail!("Unsupported operator: {:?}", op), } Ok(()) } - fn emit( - &mut self, - op: Operator<'static>, - outputs: Vec, - inputs: Vec, - ) -> Result<()> { + fn emit(&mut self, op: Operator<'a>) -> 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); + let mut inputs = vec![]; + for input in op_inputs(self.module, self.my_sig, &self.body.locals[..], &op)? + .into_iter() + .rev() + { + let stack_top = self.op_stack.pop().unwrap(); + assert_eq!(self.body.values[stack_top].ty, input); + inputs.push(Operand::Value(stack_top)); } - for output in op_outputs(self.signatures, &op)?.into_iter() { + inputs.reverse(); + + let mut outputs = vec![]; + for output in op_outputs(self.module, &self.body.locals[..], &op)?.into_iter() { let val = self.body.values.len() as ValueId; + outputs.push(val); self.body.values.push(ValueDef { kind: ValueKind::Inst(block, inst), ty: output, diff --git a/src/ir.rs b/src/ir.rs index fcf2a09..c0f18bd 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -9,21 +9,30 @@ pub type InstId = usize; pub type ValueId = usize; #[derive(Clone, Debug, Default)] -pub struct Module { - pub funcs: Vec, +pub struct Module<'a> { + pub funcs: Vec>, pub signatures: Vec, } #[derive(Clone, Debug)] -pub enum FuncDecl { +pub enum FuncDecl<'a> { Import(SignatureId), - Body(SignatureId, FunctionBody), + 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 { +pub struct FunctionBody<'a> { pub locals: Vec, - pub blocks: Vec, + pub blocks: Vec>, pub values: Vec, } @@ -35,26 +44,25 @@ pub struct ValueDef { #[derive(Clone, Debug)] pub enum ValueKind { - BlockParam(Block), + BlockParam(BlockId, usize), Inst(BlockId, InstId), } #[derive(Clone, Debug, Default)] -pub struct Block { +pub struct Block<'a> { pub params: Vec, - pub insts: Vec, + pub insts: Vec>, } #[derive(Clone, Debug)] -pub struct Inst { - pub operator: Operator<'static>, +pub struct Inst<'a> { + pub operator: Operator<'a>, pub outputs: Vec, - pub inputs: Vec, + pub inputs: Vec>, } #[derive(Clone, Debug)] -pub enum Operand { +pub enum Operand<'a> { Value(ValueId), - Sub(Box), - Local(usize), // eliminated during local2ssa pass + Sub(Box>), } diff --git a/src/op_traits.rs b/src/op_traits.rs index c0ae001..c0930bd 100644 --- a/src/op_traits.rs +++ b/src/op_traits.rs @@ -1,18 +1,45 @@ //! Metadata on operators. +use crate::ir::{Module, SignatureId}; use anyhow::{bail, Result}; -use wasmparser::{FuncType, Operator, Type}; +use wasmparser::{Operator, Type}; -pub fn op_inputs(_sigs: &[FuncType], op: &Operator<'_>) -> Result> { +pub fn op_inputs( + module: &Module, + my_sig: SignatureId, + my_locals: &[Type], + op: &Operator<'_>, +) -> Result> { match op { &Operator::Unreachable | &Operator::Nop => Ok(vec![]), + + &Operator::Call { function_index } => { + let sig = module.funcs[function_index as usize].sig(); + Ok(Vec::from(module.signatures[sig].params.clone())) + } + &Operator::Return => Ok(Vec::from(module.signatures[my_sig].returns.clone())), + + &Operator::LocalSet { local_index } | &Operator::LocalTee { local_index } => { + Ok(vec![my_locals[local_index as usize]]) + } + &Operator::LocalGet { .. } => Ok(vec![]), + _ => bail!("Unknown operator in op_inputs(): {:?}", op), } } -pub fn op_outputs(_sigs: &[FuncType], op: &Operator<'_>) -> Result> { +pub fn op_outputs(module: &Module, my_locals: &[Type], op: &Operator<'_>) -> Result> { match op { &Operator::Unreachable | &Operator::Nop => Ok(vec![]), + + &Operator::Call { function_index } => { + let sig = module.funcs[function_index as usize].sig(); + Ok(Vec::from(module.signatures[sig].returns.clone())) + } + &Operator::Return => Ok(vec![]), + &Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]), + &Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]), + _ => bail!("Unknown operator in op_outputs(): {:?}", op), } }