From 8a234ddccbe78f40239b388e5e8d7fb8f19bf512 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 21 Nov 2022 17:37:32 -0800 Subject: [PATCH] WIP. --- src/backend/binaryen.rs | 242 +++++++++++++++++++++++++--------------- src/backend/lower.rs | 234 +++++++++++++++++++++++++++++++++++++- 2 files changed, 384 insertions(+), 92 deletions(-) diff --git a/src/backend/binaryen.rs b/src/backend/binaryen.rs index 1c5a956..b771959 100644 --- a/src/backend/binaryen.rs +++ b/src/backend/binaryen.rs @@ -169,66 +169,6 @@ impl Export { } } -struct ExprIds { - nop: u32, - block: u32, - if_: u32, - loop_: u32, - break_: u32, - switch: u32, - call: u32, - call_indirect: u32, - local_get: u32, - local_set: u32, - global_get: u32, - global_set: u32, - table_get: u32, - table_set: u32, - load: u32, - store: u32, - const_: u32, - unary: u32, - binary: u32, - select: u32, - drop_: u32, - return_: u32, - unreachable: u32, -} - -impl ExprIds { - fn get() -> Self { - Self { - nop: unsafe { BinaryenNopId() }, - block: unsafe { BinaryenBlockId() }, - if_: unsafe { BinaryenIfId() }, - loop_: unsafe { BinaryenLoopId() }, - break_: unsafe { BinaryenBreakId() }, - switch: unsafe { BinaryenSwitchId() }, - call: unsafe { BinaryenCallId() }, - call_indirect: unsafe { BinaryenCallIndirectId() }, - local_get: unsafe { BinaryenLocalGetId() }, - local_set: unsafe { BinaryenLocalSetId() }, - global_get: unsafe { BinaryenGlobalGetId() }, - global_set: unsafe { BinaryenGlobalSetId() }, - table_get: unsafe { BinaryenTableGetId() }, - table_set: unsafe { BinaryenTableSetId() }, - load: unsafe { BinaryenLoadId() }, - store: unsafe { BinaryenStoreId() }, - const_: unsafe { BinaryenConstId() }, - unary: unsafe { BinaryenUnaryId() }, - binary: unsafe { BinaryenBinaryId() }, - select: unsafe { BinaryenSelectId() }, - drop_: unsafe { BinaryenDropId() }, - return_: unsafe { BinaryenReturnId() }, - unreachable: unsafe { BinaryenUnreachableId() }, - } - } -} - -lazy_static! { - static ref EXPR_IDS: ExprIds = ExprIds::get(); -} - struct TypeIds { none_t: BinaryenType, i32_t: BinaryenType, @@ -354,9 +294,68 @@ impl Expression { } } + pub fn nop(module: &Module) -> Expression { + Expression(module.0, unsafe { BinaryenNop(module.0) }) + } pub fn unreachable(module: &Module) -> Expression { Expression(module.0, unsafe { BinaryenUnreachable(module.0) }) } + pub fn call( + module: &Module, + func: ir::Func, + args: &[Expression], + tys: &[ir::Type], + ) -> Expression { + // Look up the function's name. + let func_name = unsafe { + BinaryenFunctionGetName(BinaryenGetFunctionByIndex( + module.0, + func.index() as BinaryenIndex, + )) + }; + // Create the appropriate type for return. + let ret_tuple_ty = tys_to_binaryen(tys.iter().copied()); + let args = args.iter().map(|expr| expr.1).collect::>(); + let expr = unsafe { + BinaryenCall( + module.0, + func_name, + args.as_ptr(), + args.len() as BinaryenIndex, + ret_tuple_ty, + ) + }; + Expression(module.0, expr) + } + pub fn call_indirect( + module: &Module, + table: ir::Table, + sig: &ir::SignatureData, + target: Expression, + args: &[Expression], + ) -> Expression { + let param_tuple_ty = tys_to_binaryen(sig.params.iter().copied()); + let ret_tuple_ty = tys_to_binaryen(sig.returns.iter().copied()); + let args = args.iter().map(|expr| expr.1).collect::>(); + let table_name = unsafe { + BinaryenTableGetName(BinaryenGetTableByIndex( + module.0, + table.index() as BinaryenIndex, + )) + }; + let expr = unsafe { + BinaryenCallIndirect( + module.0, + table_name, + target.1, + args.as_ptr(), + args.len() as BinaryenIndex, + param_tuple_ty, + ret_tuple_ty, + ) + }; + Expression(module.0, expr) + } pub fn local_get(module: &Module, local: ir::Local, ty: ir::Type) -> Expression { let local = local.index() as BinaryenIndex; @@ -371,6 +370,43 @@ impl Expression { Expression(module.0, expr) } + pub fn local_tee( + module: &Module, + local: ir::Local, + value: Expression, + ty: ir::Type, + ) -> Expression { + let local = local.index() as BinaryenIndex; + let ty = Type::from(ty).to_binaryen(); + let expr = unsafe { BinaryenLocalTee(module.0, local, value.1, ty) }; + Expression(module.0, expr) + } + + pub fn global_get(module: &Module, global: ir::Global, ty: ir::Type) -> Expression { + let global = global.index() as BinaryenIndex; + let ty = Type::from(ty).to_binaryen(); + let expr = unsafe { BinaryenGlobalGet(module.0, global, ty) }; + Expression(module.0, expr) + } + + pub fn global_set(module: &Module, global: ir::Global, value: Expression) -> Expression { + let global = global.index() as BinaryenIndex; + let expr = unsafe { BinaryenGlobalSet(module.0, global, value.1) }; + Expression(module.0, expr) + } + + pub fn select( + module: &Module, + cond: Expression, + if_true: Expression, + if_false: Expression, + ty: ir::Type, + ) -> Expression { + let ty = Type::from(ty).to_binaryen(); + let expr = unsafe { BinaryenSelect(module.0, cond.1, if_true.1, if_false.1, ty) }; + Expression(module.0, expr) + } + pub fn expr_drop(module: &Module, value: Expression) -> Expression { Expression(module.0, unsafe { BinaryenDrop(module.0, value.1) }) } @@ -469,6 +505,7 @@ type BinaryenExpression = *const c_void; type BinaryenExport = *const c_void; type BinaryenRelooper = *const c_void; type BinaryenRelooperBlock = *const c_void; +type BinaryenTable = *const c_void; #[repr(C)] struct BinaryenModuleAllocateAndWriteResult { @@ -567,6 +604,9 @@ extern "C" { fn BinaryenExportGetValue(ptr: BinaryenFunction) -> *const c_char; fn BinaryenExportGetKind(ptr: BinaryenFunction) -> u32; fn BinaryenExternalFunction() -> u32; + fn BinaryenGetTableByIndex(ptr: BinaryenModule, index: BinaryenIndex) -> BinaryenTable; + + fn BinaryenTableGetName(table: BinaryenTable) -> *const c_char; fn BinaryenExpressionGetId(ptr: BinaryenExpression) -> u32; fn BinaryenExpressionGetType(ptr: BinaryenExpression) -> BinaryenType; @@ -650,33 +690,6 @@ extern "C" { fn BinaryenGetMemorySegmentByteLength(module: BinaryenModule, index: u32) -> usize; fn BinaryenCopyMemorySegmentData(module: BinaryenModule, index: u32, buffer: *mut u8); - fn BinaryenNopId() -> u32; - fn BinaryenBlockId() -> u32; - fn BinaryenIfId() -> u32; - fn BinaryenLoopId() -> u32; - fn BinaryenBreakId() -> u32; - fn BinaryenSwitchId() -> u32; - fn BinaryenCallId() -> u32; - fn BinaryenCallIndirectId() -> u32; - fn BinaryenLocalGetId() -> u32; - fn BinaryenLocalSetId() -> u32; - fn BinaryenGlobalGetId() -> u32; - fn BinaryenGlobalSetId() -> u32; - fn BinaryenTableGetId() -> u32; - fn BinaryenTableSetId() -> u32; - fn BinaryenLoadId() -> u32; - fn BinaryenStoreId() -> u32; - fn BinaryenConstId() -> u32; - fn BinaryenUnaryId() -> u32; - fn BinaryenBinaryId() -> u32; - fn BinaryenSelectId() -> u32; - fn BinaryenDropId() -> u32; - fn BinaryenReturnId() -> u32; - fn BinaryenMemorySizeId() -> u32; - fn BinaryenMemoryGrowId() -> u32; - fn BinaryenUnreachableId() -> u32; - fn BinaryenPopId() -> u32; - fn BinaryenTypeNone() -> BinaryenType; fn BinaryenTypeInt32() -> BinaryenType; fn BinaryenTypeInt64() -> BinaryenType; @@ -694,6 +707,7 @@ extern "C" { fn BinaryenConst(module: BinaryenModule, lit: BinaryenLiteral) -> BinaryenExpression; fn BinaryenUnreachable(module: BinaryenModule) -> BinaryenExpression; + fn BinaryenNop(module: BinaryenModule) -> BinaryenExpression; fn BinaryenLocalGet( module: BinaryenModule, local: BinaryenIndex, @@ -701,9 +715,32 @@ extern "C" { ) -> BinaryenExpression; fn BinaryenLocalSet( module: BinaryenModule, - index: u32, + local: BinaryenIndex, value: BinaryenExpression, ) -> BinaryenExpression; + fn BinaryenLocalTee( + module: BinaryenModule, + local: BinaryenIndex, + value: BinaryenExpression, + ty: BinaryenType, + ) -> BinaryenExpression; + fn BinaryenGlobalGet( + module: BinaryenModule, + local: BinaryenIndex, + ty: BinaryenType, + ) -> BinaryenExpression; + fn BinaryenGlobalSet( + module: BinaryenModule, + local: BinaryenIndex, + value: BinaryenExpression, + ) -> BinaryenExpression; + fn BinaryenSelect( + module: BinaryenModule, + cond: BinaryenExpression, + if_true: BinaryenExpression, + if_false: BinaryenExpression, + ty: BinaryenType, + ) -> BinaryenExpression; fn BinaryenBlock( module: BinaryenModule, name: *const c_char, @@ -718,6 +755,33 @@ extern "C" { ) -> BinaryenExpression; fn BinaryenReturn(module: BinaryenModule, expr: BinaryenExpression) -> BinaryenExpression; fn BinaryenDrop(module: BinaryenModule, expr: BinaryenExpression) -> BinaryenExpression; + fn BinaryenUnary( + module: BinaryenModule, + op: BinaryenOp, + arg: BinaryenExpression, + ) -> BinaryenExpression; + fn BinaryenBinary( + module: BinaryenModule, + op: BinaryenOp, + left: BinaryenExpression, + right: BinaryenExpression, + ) -> BinaryenExpression; + fn BinaryenCall( + module: BinaryenModule, + target: *const c_char, + operands: *const BinaryenExpression, + n_operands: BinaryenIndex, + ret_type: BinaryenType, + ) -> BinaryenExpression; + fn BinaryenCallIndirect( + module: BinaryenModule, + table: *const c_char, + target: BinaryenExpression, + operands: *const BinaryenExpression, + n_operands: BinaryenIndex, + param_type: BinaryenType, + ret_type: BinaryenType, + ) -> BinaryenExpression; fn BinaryenAddFunc( module: BinaryenModule, @@ -768,3 +832,5 @@ struct BinaryenLiteral { _pad0: usize, _pad1: [u8; 16], } + +type BinaryenOp = i32; diff --git a/src/backend/lower.rs b/src/backend/lower.rs index 84ec375..81459db 100644 --- a/src/backend/lower.rs +++ b/src/backend/lower.rs @@ -9,10 +9,11 @@ use std::collections::BTreeMap; /// and new locals (as their types) that were created as temporaries /// and need to be appended to `body.locals`. pub(crate) fn generate_body( + module: &Module, body: &FunctionBody, into_mod: &mut binaryen::Module, ) -> (Vec, binaryen::Expression) { - let mut ctx = ElabCtx::new(body); + let mut ctx = ElabCtx::new(module, body); // For each block, generate an expr. let mut block_exprs: BTreeMap = BTreeMap::default(); @@ -138,6 +139,7 @@ fn build_ssa_edge( #[derive(Clone, Debug)] struct ElabCtx<'a> { + module: &'a Module<'a>, body: &'a FunctionBody, op_result_locals: FxHashMap<(Value, usize), Local>, block_param_locals: FxHashMap<(Block, usize), Local>, @@ -146,8 +148,9 @@ struct ElabCtx<'a> { } impl<'a> ElabCtx<'a> { - fn new(body: &'a FunctionBody) -> ElabCtx<'a> { + fn new(module: &'a Module<'a>, body: &'a FunctionBody) -> ElabCtx<'a> { let mut this = ElabCtx { + module, body, op_result_locals: FxHashMap::default(), block_param_locals: FxHashMap::default(), @@ -199,7 +202,7 @@ impl<'a> ElabCtx<'a> { }) .collect::>(); // Create operator. - let expr = self.create_binaryen_op(op, binaryen_args, tys); + let expr = self.create_binaryen_op(op, binaryen_args, tys, into_mod); // Set local(s) as appropriate. if tys.len() == 0 { @@ -247,8 +250,231 @@ impl<'a> ElabCtx<'a> { op: Operator, args: Vec, tys: &[Type], + into_mod: &binaryen::Module, ) -> binaryen::Expression { - todo!() + match op { + Unreachable => binaryen::Expression::unreachable(into_mod), + Nop => binaryen::Expression::nop(into_mod), + + Operator::Call { function_index } => { + binaryen::Expression::call(into_mod, function_index, &args[..], tys) + } + Operator::CallIndirect { + sig_index, + table_index, + } => binaryen::Expression::call_indirect( + into_mod, + table_index, + self.module.signature(sig_index), + args[0], + &args[1..], + ), + Operator::Return => binaryen::Expression::ret(into_mod, &args[..]), + Operator::LocalSet { local_index } => { + binaryen::Expression::local_set(into_mod, local_index, args[0]) + } + Operator::LocalTee { local_index } => { + binaryen::Expression::local_tee(into_mod, local_index, args[0], tys[0]) + } + Operator::LocalGet { local_index } => { + binaryen::Expression::local_get(into_mod, local_index, tys[0]) + } + Operator::Select | Operator::TypedSelect { .. } => { + binaryen::Expression::select(into_mod, args[0], args[1], args[2], tys[0]) + } + Operator::GlobalGet { global_index } => { + binaryen::Expression::global_get(into_mod, global_index, tys[0]) + } + Operator::GlobalSet { global_index } => { + binaryen::Expression::global_set(into_mod, global_index, args[0]) + } + + Operator::I32Load { memory } => todo!(), + Operator::I64Load { memory } => todo!(), + Operator::F32Load { memory } => todo!(), + Operator::F64Load { memory } => todo!(), + Operator::I32Load8S { memory } => todo!(), + Operator::I32Load8U { memory } => todo!(), + Operator::I32Load16S { memory } => todo!(), + Operator::I32Load16U { memory } => todo!(), + Operator::I64Load8S { memory } => todo!(), + Operator::I64Load8U { memory } => todo!(), + Operator::I64Load16S { memory } => todo!(), + Operator::I64Load16U { memory } => todo!(), + Operator::I64Load32S { memory } => todo!(), + Operator::I64Load32U { memory } => todo!(), + + Operator::I32Store { memory } => todo!(), + Operator::I64Store { memory } => todo!(), + Operator::F32Store { memory } => todo!(), + Operator::F64Store { memory } => todo!(), + Operator::I32Store8 { memory } => todo!(), + Operator::I32Store16 { memory } => todo!(), + Operator::I64Store8 { memory } => todo!(), + Operator::I64Store16 { memory } => todo!(), + Operator::I64Store32 { memory } => todo!(), + + Operator::I32Const { value } => todo!(), + Operator::I64Const { value } => todo!(), + Operator::F32Const { value } => todo!(), + Operator::F64Const { value } => todo!(), + + Operator::I32Eqz => todo!(), + Operator::I32Eq => todo!(), + Operator::I32Ne => todo!(), + Operator::I32LtS => todo!(), + Operator::I32LtU => todo!(), + Operator::I32GtS => todo!(), + Operator::I32GtU => todo!(), + Operator::I32LeS => todo!(), + Operator::I32LeU => todo!(), + Operator::I32GeS => todo!(), + Operator::I32GeU => todo!(), + + Operator::I64Eqz => todo!(), + + Operator::I64Eq => todo!(), + Operator::I64Ne => todo!(), + Operator::I64LtS => todo!(), + Operator::I64LtU => todo!(), + Operator::I64GtU => todo!(), + Operator::I64GtS => todo!(), + Operator::I64LeS => todo!(), + Operator::I64LeU => todo!(), + Operator::I64GeS => todo!(), + Operator::I64GeU => todo!(), + + Operator::F32Eq => todo!(), + Operator::F32Ne => todo!(), + Operator::F32Lt => todo!(), + Operator::F32Gt => todo!(), + Operator::F32Le => todo!(), + Operator::F32Ge => todo!(), + + Operator::F64Eq => todo!(), + Operator::F64Ne => todo!(), + Operator::F64Lt => todo!(), + Operator::F64Gt => todo!(), + Operator::F64Le => todo!(), + Operator::F64Ge => todo!(), + + Operator::I32Clz => todo!(), + Operator::I32Ctz => todo!(), + Operator::I32Popcnt => todo!(), + + Operator::I32Add => todo!(), + Operator::I32Sub => todo!(), + Operator::I32Mul => todo!(), + Operator::I32DivS => todo!(), + Operator::I32DivU => todo!(), + Operator::I32RemS => todo!(), + Operator::I32RemU => todo!(), + Operator::I32And => todo!(), + Operator::I32Or => todo!(), + Operator::I32Xor => todo!(), + Operator::I32Shl => todo!(), + Operator::I32ShrS => todo!(), + Operator::I32ShrU => todo!(), + Operator::I32Rotl => todo!(), + Operator::I32Rotr => todo!(), + + Operator::I64Clz => todo!(), + Operator::I64Ctz => todo!(), + Operator::I64Popcnt => todo!(), + + Operator::I64Add => todo!(), + Operator::I64Sub => todo!(), + Operator::I64Mul => todo!(), + Operator::I64DivS => todo!(), + Operator::I64DivU => todo!(), + Operator::I64RemS => todo!(), + Operator::I64RemU => todo!(), + Operator::I64And => todo!(), + Operator::I64Or => todo!(), + Operator::I64Xor => todo!(), + Operator::I64Shl => todo!(), + Operator::I64ShrS => todo!(), + Operator::I64ShrU => todo!(), + Operator::I64Rotl => todo!(), + Operator::I64Rotr => todo!(), + + Operator::F32Abs => todo!(), + Operator::F32Neg => todo!(), + Operator::F32Ceil => todo!(), + Operator::F32Floor => todo!(), + Operator::F32Trunc => todo!(), + Operator::F32Nearest => todo!(), + Operator::F32Sqrt => todo!(), + + Operator::F32Add => todo!(), + Operator::F32Sub => todo!(), + Operator::F32Mul => todo!(), + Operator::F32Div => todo!(), + Operator::F32Min => todo!(), + Operator::F32Max => todo!(), + Operator::F32Copysign => todo!(), + + Operator::F64Abs => todo!(), + Operator::F64Neg => todo!(), + Operator::F64Ceil => todo!(), + Operator::F64Floor => todo!(), + Operator::F64Trunc => todo!(), + Operator::F64Nearest => todo!(), + Operator::F64Sqrt => todo!(), + + Operator::F64Add => todo!(), + Operator::F64Sub => todo!(), + Operator::F64Mul => todo!(), + Operator::F64Div => todo!(), + Operator::F64Min => todo!(), + Operator::F64Max => todo!(), + Operator::F64Copysign => todo!(), + + Operator::I32WrapI64 => todo!(), + Operator::I32TruncF32S => todo!(), + Operator::I32TruncF32U => todo!(), + Operator::I32TruncF64S => todo!(), + Operator::I32TruncF64U => todo!(), + Operator::I64ExtendI32S => todo!(), + Operator::I64ExtendI32U => todo!(), + Operator::I64TruncF32S => todo!(), + Operator::I64TruncF32U => todo!(), + Operator::I64TruncF64S => todo!(), + Operator::I64TruncF64U => todo!(), + Operator::F32ConvertI32S => todo!(), + Operator::F32ConvertI32U => todo!(), + Operator::F32ConvertI64S => todo!(), + Operator::F32ConvertI64U => todo!(), + Operator::F32DemoteF64 => todo!(), + Operator::F64ConvertI32S => todo!(), + Operator::F64ConvertI32U => todo!(), + Operator::F64ConvertI64S => todo!(), + Operator::F64ConvertI64U => todo!(), + Operator::F64PromoteF32 => todo!(), + Operator::I32Extend8S => todo!(), + Operator::I32Extend16S => todo!(), + Operator::I64Extend8S => todo!(), + Operator::I64Extend16S => todo!(), + Operator::I64Extend32S => todo!(), + Operator::I32TruncSatF32S => todo!(), + Operator::I32TruncSatF32U => todo!(), + Operator::I32TruncSatF64S => todo!(), + Operator::I32TruncSatF64U => todo!(), + Operator::I64TruncSatF32S => todo!(), + Operator::I64TruncSatF32U => todo!(), + Operator::I64TruncSatF64S => todo!(), + Operator::I64TruncSatF64U => todo!(), + Operator::F32ReinterpretI32 => todo!(), + Operator::F64ReinterpretI64 => todo!(), + Operator::I32ReinterpretF32 => todo!(), + Operator::I64ReinterpretF64 => todo!(), + Operator::TableGet { table_index } => todo!(), + Operator::TableSet { table_index } => todo!(), + Operator::TableGrow { table_index } => todo!(), + Operator::TableSize { table_index } => todo!(), + Operator::MemorySize { mem } => todo!(), + Operator::MemoryGrow { mem } => todo!(), + } } fn local_ty(&self, local: Local) -> Type {