diff --git a/src/backend/binaryen.rs b/src/backend/binaryen.rs index 0af8cc6..ebc31e8 100644 --- a/src/backend/binaryen.rs +++ b/src/backend/binaryen.rs @@ -125,7 +125,7 @@ impl Function { ) -> Function { let params = tys_to_binaryen(params); let results = tys_to_binaryen(results); - let locals: Vec = locals.map(|&ty| Type::from(ty).to_kind()).collect(); + let locals: Vec = locals.map(|ty| Type::from(ty).to_kind()).collect(); let ptr = unsafe { BinaryenAddFunc( module.0, @@ -139,6 +139,10 @@ impl Function { }; Function(module.0, ptr) } + + pub fn add_local(&mut self, ty: wasmparser::Type) -> usize { + (unsafe { BinaryenFunctionAddVar(self.1, Type::from(ty).to_kind()) }) as usize + } } impl Export { @@ -224,12 +228,12 @@ lazy_static! { } struct TypeIds { - none_t: u32, - i32_t: u32, - i64_t: u32, - f32_t: u32, - f64_t: u32, - v128_t: u32, + none_t: BinaryenType, + i32_t: BinaryenType, + i64_t: BinaryenType, + f32_t: BinaryenType, + f64_t: BinaryenType, + v128_t: BinaryenType, } impl TypeIds { @@ -260,7 +264,7 @@ pub enum Type { } impl Type { - fn from_kind(kind: u32) -> Option { + fn from_kind(kind: BinaryenType) -> Option { let tys = &*TYPE_IDS; if kind == tys.none_t { Some(Type::None) @@ -304,7 +308,7 @@ impl From for Type { } pub fn tys_to_binaryen(tys: impl Iterator) -> BinaryenType { - let tys: Vec = tys.map(|&ty| Type::from(ty).to_kind()).collect(); + let tys: Vec = tys.map(|ty| Type::from(ty).to_kind()).collect(); unsafe { BinaryenTypeCreate(tys.as_ptr(), tys.len() as BinaryenIndex) } } @@ -450,6 +454,7 @@ extern "C" { fn BinaryenFunctionGetBody(ptr: BinaryenFunction) -> BinaryenExpression; fn BinaryenFunctionSetBody(ptr: BinaryenFunction, body: BinaryenExpression); fn BinaryenFunctionGetName(ptr: BinaryenFunction) -> *const c_char; + fn BinaryenFunctionAddVar(ptr: BinaryenFunction, ty: BinaryenType) -> BinaryenIndex; fn BinaryenGetExport(ptr: BinaryenModule, name: *const c_char) -> BinaryenExport; fn BinaryenGetNumExports(ptr: BinaryenModule) -> u32; fn BinaryenGetExportByIndex(ptr: BinaryenModule, index: u32) -> BinaryenExport; @@ -459,7 +464,7 @@ extern "C" { fn BinaryenExternalFunction() -> u32; fn BinaryenExpressionGetId(ptr: BinaryenExpression) -> u32; - fn BinaryenExpressionGetType(ptr: BinaryenExpression) -> u32; + fn BinaryenExpressionGetType(ptr: BinaryenExpression) -> BinaryenType; fn BinaryenExpressionCopy( ptr: BinaryenExpression, module: BinaryenModule, diff --git a/src/backend/lower.rs b/src/backend/lower.rs index 5faec60..73d4873 100644 --- a/src/backend/lower.rs +++ b/src/backend/lower.rs @@ -1,14 +1,18 @@ use crate::backend::binaryen; use crate::ir::*; use fxhash::FxHashMap; +use wasmparser::Type; +/// Creates a body expression for a function. Returns that expression, +/// and new locals (as their types) that were created as temporaries +/// and need to be appended to `body.locals`. pub(crate) fn generate_body( body: &FunctionBody, into_mod: &mut binaryen::Module, -) -> binaryen::Expression { +) -> (Vec, binaryen::Expression) { // For each block, generate an expr. let mut block_exprs: FxHashMap = FxHashMap::default(); - let mut ctx = ElabCtx::default(); + let mut ctx = ElabCtx::new(body, into_mod); for block in body.blocks() { let exprs = body[block] .insts @@ -24,22 +28,33 @@ pub(crate) fn generate_body( todo!() } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] struct ElabCtx { value_to_expr: FxHashMap, - block_params: FxHashMap, - args: FxHashMap, + block_params: FxHashMap<(Block, usize), LocalId>, + new_locals: Vec, } impl ElabCtx { - fn for_func(module: &Module, func: FuncId) -> ElabCtx { - let sig = module.func(func).sig(); - let sig = module.signature(sig); - let body = module.func(func).body().unwrap(); + fn new(body: &FunctionBody, into_mod: &mut binaryen::Module) -> ElabCtx { + // Create locals for each blockparam. + let mut block_params = FxHashMap::default(); + let mut next_local = body.locals.len() as LocalId; + let mut new_locals = vec![]; + for block in body.blocks() { + for &(ty, param) in &body[block].params { + let new_local = next_local; + next_local += 1; + block_params.insert((ty, param), new_local); + new_locals.push(ty); + } + } - let mut ctx = ElabCtx::default(); - - // TODO + ElabCtx { + value_to_expr: FxHashMap::default(), + block_params, + new_locals, + } } } @@ -73,6 +88,7 @@ pub(crate) fn create_new_func( body: &FunctionBody, into_mod: &mut binaryen::Module, body_expr: binaryen::Expression, + new_locals: Vec, ) { // Create param types. let sig = module.signature(sig); @@ -80,7 +96,11 @@ pub(crate) fn create_new_func( into_mod, sig.params.iter().copied(), sig.returns.iter().copied(), - body.locals.iter().copied(), + body.locals + .iter() + .copied() + .skip(body.n_params) + .chain(new_locals.into_iter()), body_expr, ); } diff --git a/src/ir.rs b/src/ir.rs index 0d3e654..7a3d8d0 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -99,14 +99,20 @@ impl FuncDecl { #[derive(Clone, Debug, Default)] pub struct FunctionBody { + /// How many parameters the function has. (Their types are the + /// first `n_params` values in `locals`.) pub n_params: usize, + /// Return types of the function. pub rets: Vec, + /// Local types, *including* args. pub locals: Vec, + /// Block bodies, indexed by `BlockId`. pub blocks: Vec, + /// Value definitions, indexed by `Value`. pub values: Vec, - /// A single value can have multiple types if multi-value (e.g. a - /// call). - pub types: Vec>, + /// Types, indexed by `Value`. A single value can have multiple + /// types if multi-value (e.g. a call). + pub types: Vec>, } impl FunctionBody { @@ -524,13 +530,25 @@ impl<'a> Module<'a> { for new_func_idx in self.funcs.len()..binaryen_module.num_funcs() { let sig = self.func(new_func_idx).sig(); let body = self.func(new_func_idx).body().unwrap(); - let binaryen_expr = backend::lower::generate_body(body, &mut binaryen_module); - backend::lower::create_new_func(self, sig, body, &mut binaryen_module, binaryen_expr); + let (new_locals, binaryen_expr) = + backend::lower::generate_body(body, &mut binaryen_module); + backend::lower::create_new_func( + self, + sig, + body, + &mut binaryen_module, + binaryen_expr, + new_locals, + ); } for &func in &self.dirty_funcs { if let Some(body) = self.func(func).body() { let mut binaryen_func = binaryen_module.func(func); - let binaryen_expr = backend::lower::generate_body(body, &mut binaryen_module); + let (new_locals, binaryen_expr) = + backend::lower::generate_body(body, &mut binaryen_module); + for ty in new_locals { + binaryen_func.add_local(ty); + } binaryen_func.set_body(binaryen_expr); } }