diff --git a/src/backend/binaryen.rs b/src/backend/binaryen.rs index 74ee603..0af8cc6 100644 --- a/src/backend/binaryen.rs +++ b/src/backend/binaryen.rs @@ -115,6 +115,30 @@ impl Function { let s = unsafe { CStr::from_ptr(BinaryenFunctionGetName(self.1)) }; s.to_str().unwrap() } + + pub fn create( + module: &mut Module, + params: impl Iterator, + results: impl Iterator, + locals: impl Iterator, + body: Expression, + ) -> 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 ptr = unsafe { + BinaryenAddFunc( + module.0, + /* name = */ std::ptr::null(), + params, + results, + locals.as_ptr(), + locals.len() as BinaryenIndex, + body.1, + ) + }; + Function(module.0, ptr) + } } impl Export { @@ -205,6 +229,7 @@ struct TypeIds { i64_t: u32, f32_t: u32, f64_t: u32, + v128_t: u32, } impl TypeIds { @@ -215,6 +240,7 @@ impl TypeIds { i64_t: unsafe { BinaryenTypeInt64() }, f32_t: unsafe { BinaryenTypeFloat32() }, f64_t: unsafe { BinaryenTypeFloat64() }, + v128_t: unsafe { BinaryenTypeVec128() }, } } } @@ -230,6 +256,7 @@ pub enum Type { I64, F32, F64, + V128, } impl Type { @@ -250,7 +277,7 @@ impl Type { } } - fn to_kind(&self) -> u32 { + pub(crate) fn to_kind(&self) -> BinaryenType { let tys = &*TYPE_IDS; match self { &Type::None => tys.none_t, @@ -258,10 +285,29 @@ impl Type { &Type::I64 => tys.i64_t, &Type::F32 => tys.f32_t, &Type::F64 => tys.f64_t, + &Type::V128 => tys.v128_t, } } } +impl From for Type { + fn from(ty: wasmparser::Type) -> Self { + match ty { + wasmparser::Type::I32 => Type::I32, + wasmparser::Type::I64 => Type::I64, + wasmparser::Type::F32 => Type::F32, + wasmparser::Type::F64 => Type::F64, + wasmparser::Type::V128 => Type::V128, + _ => unimplemented!(), + } + } +} + +pub fn tys_to_binaryen(tys: impl Iterator) -> BinaryenType { + let tys: Vec = tys.map(|&ty| Type::from(ty).to_kind()).collect(); + unsafe { BinaryenTypeCreate(tys.as_ptr(), tys.len() as BinaryenIndex) } +} + fn name_to_string(name: *const c_char) -> Option { if name.is_null() { None @@ -517,11 +563,14 @@ extern "C" { fn BinaryenUnreachableId() -> u32; fn BinaryenPopId() -> u32; - fn BinaryenTypeNone() -> u32; - fn BinaryenTypeInt32() -> u32; - fn BinaryenTypeInt64() -> u32; - fn BinaryenTypeFloat32() -> u32; - fn BinaryenTypeFloat64() -> u32; + fn BinaryenTypeNone() -> BinaryenType; + fn BinaryenTypeInt32() -> BinaryenType; + fn BinaryenTypeInt64() -> BinaryenType; + fn BinaryenTypeFloat32() -> BinaryenType; + fn BinaryenTypeFloat64() -> BinaryenType; + fn BinaryenTypeVec128() -> BinaryenType; + + fn BinaryenTypeCreate(tys: *const BinaryenType, n_tys: BinaryenIndex) -> BinaryenType; fn BinaryenAddInt32() -> u32; fn BinaryenSubInt32() -> u32; @@ -543,6 +592,16 @@ extern "C" { ty: BinaryenType, ) -> BinaryenExpression; + fn BinaryenAddFunc( + module: BinaryenModule, + name: *const c_char, + params: BinaryenType, + results: BinaryenType, + vars: *const BinaryenType, + n_vars: BinaryenIndex, + body: BinaryenExpression, + ) -> BinaryenFunction; + fn BinaryenUndefined() -> BinaryenType; fn BinaryenLiteralInt32(x: i32) -> BinaryenLiteral; diff --git a/src/backend/lower.rs b/src/backend/lower.rs new file mode 100644 index 0000000..5faec60 --- /dev/null +++ b/src/backend/lower.rs @@ -0,0 +1,86 @@ +use crate::backend::binaryen; +use crate::ir::*; +use fxhash::FxHashMap; + +pub(crate) fn generate_body( + body: &FunctionBody, + into_mod: &mut binaryen::Module, +) -> binaryen::Expression { + // For each block, generate an expr. + let mut block_exprs: FxHashMap = FxHashMap::default(); + let mut ctx = ElabCtx::default(); + for block in body.blocks() { + let exprs = body[block] + .insts + .iter() + .map(|&inst| { + let inst = body.resolve_alias(inst); + elaborate_value(body, into_mod, &mut ctx, inst) + }) + .collect::>(); + block_exprs.insert(block, binaryen::Expression::block(into_mod, &exprs[..])); + } + + todo!() +} + +#[derive(Clone, Debug, Default)] +struct ElabCtx { + value_to_expr: FxHashMap, + block_params: FxHashMap, + args: FxHashMap, +} + +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(); + + let mut ctx = ElabCtx::default(); + + // TODO + } +} + +fn elaborate_value( + body: &FunctionBody, + into_mod: &binaryen::Module, + ctx: &mut ElabCtx, + value: Value, +) -> binaryen::Expression { + let value = body.resolve_alias(value); + if let Some(expr) = ctx.value_to_expr.get(&value) { + return *expr; + } + + match &body[value] { + &ValueDef::BlockParam(block, idx) => {} + &ValueDef::Arg(idx) => {} + &ValueDef::PickOutput(value, idx) => {} + &ValueDef::Operator(op, ref args) => {} + + &ValueDef::Alias(_) => unreachable!(), + &ValueDef::Placeholder => unreachable!(), + } + + todo!() +} + +pub(crate) fn create_new_func( + module: &Module, + sig: SignatureId, + body: &FunctionBody, + into_mod: &mut binaryen::Module, + body_expr: binaryen::Expression, +) { + // Create param types. + let sig = module.signature(sig); + let _func = binaryen::Function::create( + into_mod, + sig.params.iter().copied(), + sig.returns.iter().copied(), + body.locals.iter().copied(), + body_expr, + ); +} diff --git a/src/ir.rs b/src/ir.rs index ba4e476..0d3e654 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -521,6 +521,12 @@ impl<'a> Module<'a> { pub fn to_wasm_bytes(&self) -> Result> { let mut binaryen_module = binaryen::Module::read(self.orig_bytes)?; + 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); + } for &func in &self.dirty_funcs { if let Some(body) = self.func(func).body() { let mut binaryen_func = binaryen_module.func(func);