This commit is contained in:
Chris Fallin 2022-11-21 17:37:32 -08:00
parent 2fc5440fa3
commit 8a234ddccb
No known key found for this signature in database
GPG key ID: 31649E4FE65EB465
2 changed files with 384 additions and 92 deletions

View file

@ -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::<Vec<_>>();
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::<Vec<_>>();
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;

View file

@ -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<Type>, 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<Block, binaryen::Expression> = 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::<Vec<_>>();
// 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<binaryen::Expression>,
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 {