WIP.
This commit is contained in:
parent
91a2c11f67
commit
c2db0ad4b9
|
@ -1,5 +1,7 @@
|
|||
//! Binaryen bindings.
|
||||
|
||||
use crate::entity::EntityRef;
|
||||
use crate::ir;
|
||||
use anyhow::{bail, Result};
|
||||
use lazy_static::lazy_static;
|
||||
use libc::{c_char, c_void};
|
||||
|
@ -118,14 +120,14 @@ impl Function {
|
|||
|
||||
pub fn create(
|
||||
module: &mut Module,
|
||||
params: impl Iterator<Item = wasmparser::Type>,
|
||||
results: impl Iterator<Item = wasmparser::Type>,
|
||||
locals: impl Iterator<Item = wasmparser::Type>,
|
||||
params: impl Iterator<Item = ir::Type>,
|
||||
results: impl Iterator<Item = ir::Type>,
|
||||
locals: impl Iterator<Item = ir::Type>,
|
||||
body: Expression,
|
||||
) -> Function {
|
||||
let params = tys_to_binaryen(params);
|
||||
let results = tys_to_binaryen(results);
|
||||
let locals: Vec<BinaryenType> = locals.map(|ty| Type::from(ty).to_kind()).collect();
|
||||
let locals: Vec<BinaryenType> = locals.map(|ty| Type::from(ty).to_binaryen()).collect();
|
||||
let ptr = unsafe {
|
||||
BinaryenAddFunc(
|
||||
module.0,
|
||||
|
@ -140,8 +142,8 @@ 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
|
||||
pub fn add_local(&mut self, ty: ir::Type) -> usize {
|
||||
(unsafe { BinaryenFunctionAddVar(self.1, Type::from(ty).to_binaryen()) }) as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +266,7 @@ pub enum Type {
|
|||
}
|
||||
|
||||
impl Type {
|
||||
fn from_kind(kind: BinaryenType) -> Option<Type> {
|
||||
fn from_binaryen(kind: BinaryenType) -> Option<Type> {
|
||||
let tys = &*TYPE_IDS;
|
||||
if kind == tys.none_t {
|
||||
Some(Type::None)
|
||||
|
@ -281,7 +283,7 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_kind(&self) -> BinaryenType {
|
||||
pub(crate) fn to_binaryen(&self) -> BinaryenType {
|
||||
let tys = &*TYPE_IDS;
|
||||
match self {
|
||||
&Type::None => tys.none_t,
|
||||
|
@ -294,21 +296,21 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<wasmparser::Type> for Type {
|
||||
fn from(ty: wasmparser::Type) -> Self {
|
||||
impl From<ir::Type> for Type {
|
||||
fn from(ty: ir::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,
|
||||
ir::Type::I32 => Type::I32,
|
||||
ir::Type::I64 => Type::I64,
|
||||
ir::Type::F32 => Type::F32,
|
||||
ir::Type::F64 => Type::F64,
|
||||
ir::Type::V128 => Type::V128,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tys_to_binaryen(tys: impl Iterator<Item = wasmparser::Type>) -> BinaryenType {
|
||||
let tys: Vec<BinaryenType> = tys.map(|ty| Type::from(ty).to_kind()).collect();
|
||||
pub fn tys_to_binaryen(tys: impl Iterator<Item = ir::Type>) -> BinaryenType {
|
||||
let tys: Vec<BinaryenType> = tys.map(|ty| Type::from(ty).to_binaryen()).collect();
|
||||
unsafe { BinaryenTypeCreate(tys.as_ptr(), tys.len() as BinaryenIndex) }
|
||||
}
|
||||
|
||||
|
@ -322,7 +324,7 @@ fn name_to_string(name: *const c_char) -> Option<String> {
|
|||
|
||||
impl Expression {
|
||||
pub fn ty(&self) -> Type {
|
||||
Type::from_kind(unsafe { BinaryenExpressionGetType(self.1) }).unwrap()
|
||||
Type::from_binaryen(unsafe { BinaryenExpressionGetType(self.1) }).unwrap()
|
||||
}
|
||||
|
||||
pub fn deep_clone(&self) -> Self {
|
||||
|
@ -345,6 +347,44 @@ impl Expression {
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn block_append_child(&mut self, child: Expression) {
|
||||
unsafe {
|
||||
BinaryenBlockAppendChild(self.1, child.1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unreachable(module: &Module) -> Expression {
|
||||
Expression(module.0, unsafe { BinaryenUnreachable(module.0) })
|
||||
}
|
||||
|
||||
pub fn local_get(module: &Module, local: ir::Local, ty: ir::Type) -> Expression {
|
||||
let local = local.index() as BinaryenIndex;
|
||||
let ty = Type::from(ty).to_binaryen();
|
||||
let expr = unsafe { BinaryenLocalGet(module.0, local, ty) };
|
||||
Expression(module.0, expr)
|
||||
}
|
||||
|
||||
pub fn local_set(module: &Module, local: ir::Local, value: Expression) -> Expression {
|
||||
let local = local.index() as BinaryenIndex;
|
||||
let expr = unsafe { BinaryenLocalSet(module.0, local, value.1) };
|
||||
Expression(module.0, expr)
|
||||
}
|
||||
|
||||
pub fn ret(module: &Module, values: &[Expression]) -> Expression {
|
||||
let expr = if values.len() == 0 {
|
||||
unsafe { BinaryenReturn(module.0, std::ptr::null()) }
|
||||
} else if values.len() == 1 {
|
||||
unsafe { BinaryenReturn(module.0, values[0].1) }
|
||||
} else {
|
||||
let exprs = values.iter().map(|e| e.1).collect::<Vec<_>>();
|
||||
let tuple = unsafe {
|
||||
BinaryenTupleMake(module.0, exprs.as_ptr(), exprs.len() as BinaryenIndex)
|
||||
};
|
||||
unsafe { BinaryenReturn(module.0, tuple) }
|
||||
};
|
||||
Expression(module.0, expr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
@ -387,13 +427,13 @@ lazy_static! {
|
|||
}
|
||||
|
||||
impl UnaryOp {
|
||||
fn from_kind(kind: u32) -> UnaryOp {
|
||||
fn from_binaryen(kind: u32) -> UnaryOp {
|
||||
UnaryOp::Other(kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
fn from_kind(kind: u32) -> BinaryOp {
|
||||
fn from_binaryen(kind: u32) -> BinaryOp {
|
||||
let ids = &*OP_IDS;
|
||||
if kind == ids.i32_add {
|
||||
BinaryOp::I32Add
|
||||
|
@ -447,9 +487,6 @@ pub struct Relooper(BinaryenModule, BinaryenRelooper);
|
|||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct RelooperBlock(BinaryenRelooperBlock);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct RelooperBlockWithSwitch(BinaryenRelooperBlock);
|
||||
|
||||
impl Relooper {
|
||||
pub fn new(module: &Module) -> Relooper {
|
||||
let ptr = unsafe { RelooperCreate(module.0) };
|
||||
|
@ -467,12 +504,8 @@ impl Relooper {
|
|||
RelooperBlock(unsafe { RelooperAddBlock(self.1, expr.1) })
|
||||
}
|
||||
|
||||
pub fn add_block_with_switch(
|
||||
&mut self,
|
||||
expr: Expression,
|
||||
sel: Expression,
|
||||
) -> RelooperBlockWithSwitch {
|
||||
RelooperBlockWithSwitch(unsafe { RelooperAddBlockWithSwitch(self.1, expr.1, sel.1) })
|
||||
pub fn add_block_with_switch(&mut self, expr: Expression, sel: Expression) -> RelooperBlock {
|
||||
RelooperBlock(unsafe { RelooperAddBlockWithSwitch(self.1, expr.1, sel.1) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,9 +521,7 @@ impl RelooperBlock {
|
|||
RelooperAddBranch(self.0, to.0, std::ptr::null(), edge.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelooperBlockWithSwitch {
|
||||
pub fn switch(&self, to: RelooperBlock, edge: Expression, indices: &[BinaryenIndex]) {
|
||||
unsafe {
|
||||
RelooperAddBranchForSwitch(
|
||||
|
@ -548,6 +579,10 @@ extern "C" {
|
|||
fn BinaryenBlockGetNumChildren(ptr: BinaryenExpression) -> u32;
|
||||
fn BinaryenBlockGetChildAt(ptr: BinaryenExpression, index: u32) -> BinaryenExpression;
|
||||
fn BinaryenBlockGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||
fn BinaryenBlockAppendChild(
|
||||
ptr: BinaryenExpression,
|
||||
child: BinaryenExpression,
|
||||
) -> BinaryenIndex;
|
||||
|
||||
fn BinaryenLoopGetBody(ptr: BinaryenExpression) -> BinaryenExpression;
|
||||
fn BinaryenLoopGetName(ptr: BinaryenExpression) -> *const c_char;
|
||||
|
@ -654,6 +689,12 @@ extern "C" {
|
|||
fn BinaryenShrSInt32() -> u32;
|
||||
|
||||
fn BinaryenConst(module: BinaryenModule, lit: BinaryenLiteral) -> BinaryenExpression;
|
||||
fn BinaryenUnreachable(module: BinaryenModule) -> BinaryenExpression;
|
||||
fn BinaryenLocalGet(
|
||||
module: BinaryenModule,
|
||||
local: BinaryenIndex,
|
||||
ty: BinaryenType,
|
||||
) -> BinaryenExpression;
|
||||
fn BinaryenLocalSet(
|
||||
module: BinaryenModule,
|
||||
index: u32,
|
||||
|
@ -666,6 +707,12 @@ extern "C" {
|
|||
n_children: BinaryenIndex,
|
||||
ty: BinaryenType,
|
||||
) -> BinaryenExpression;
|
||||
fn BinaryenTupleMake(
|
||||
module: BinaryenModule,
|
||||
operands: *const BinaryenExpression,
|
||||
n_operands: BinaryenIndex,
|
||||
) -> BinaryenExpression;
|
||||
fn BinaryenReturn(module: BinaryenModule, expr: BinaryenExpression) -> BinaryenExpression;
|
||||
|
||||
fn BinaryenAddFunc(
|
||||
module: BinaryenModule,
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
/*
|
||||
use crate::backend::binaryen;
|
||||
use crate::entity::EntityRef;
|
||||
use crate::ir::*;
|
||||
use crate::Operator;
|
||||
use fxhash::FxHashMap;
|
||||
use wasmparser::Type;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Creates a body expression for a function. Returns that expression,
|
||||
/// and new locals (as their types) that were created as temporaries
|
||||
|
@ -16,36 +15,133 @@ pub(crate) fn generate_body(
|
|||
let mut ctx = ElabCtx::new(body, into_mod);
|
||||
|
||||
// For each block, generate an expr.
|
||||
let mut block_exprs: FxHashMap<Block, binaryen::Expression> = FxHashMap::default();
|
||||
let mut block_exprs: BTreeMap<Block, binaryen::Expression> = BTreeMap::default();
|
||||
for (block_id, block) in body.blocks.entries() {
|
||||
let exprs = block
|
||||
.insts
|
||||
.iter()
|
||||
.flat_map(|&inst| {
|
||||
let inst = body.resolve_alias(inst);
|
||||
ctx.elaborate_value(into_mod, inst)
|
||||
})
|
||||
.collect::<Vec<binaryen::Expression>>();
|
||||
let mut exprs = vec![];
|
||||
for (i, (ty, _param)) in block.params.iter().enumerate() {
|
||||
let val = binaryen::Expression::local_get(
|
||||
into_mod,
|
||||
*ctx.block_param_next_locals.get(&(block_id, i)).unwrap(),
|
||||
*ty,
|
||||
);
|
||||
let set = binaryen::Expression::local_set(
|
||||
into_mod,
|
||||
*ctx.block_param_locals.get(&(block_id, i)).unwrap(),
|
||||
val,
|
||||
);
|
||||
exprs.push(set);
|
||||
}
|
||||
for &inst in &block.insts {
|
||||
let inst = body.resolve_alias(inst);
|
||||
if let Some(expr) = ctx.elaborate_value(into_mod, inst) {
|
||||
exprs.push(expr);
|
||||
}
|
||||
}
|
||||
block_exprs.insert(block_id, binaryen::Expression::block(into_mod, &exprs[..]));
|
||||
}
|
||||
|
||||
// Combine blocks into a single body expression, using the
|
||||
// relooper/stackifier support built into Binaryen.
|
||||
let mut relooper = binaryen::Relooper::new(into_mod);
|
||||
let mut entry = None;
|
||||
let mut relooper_blocks: FxHashMap<Block, binaryen::RelooperBlock> = FxHashMap::default();
|
||||
for (block_id, block_expr) in block_exprs {}
|
||||
|
||||
// Create the blocks.
|
||||
let mut relooper_blocks: FxHashMap<Block, (binaryen::Expression, binaryen::RelooperBlock)> =
|
||||
FxHashMap::default();
|
||||
for (block_id, block_expr) in &mut block_exprs {
|
||||
let block = match &body.blocks[*block_id].terminator {
|
||||
&Terminator::Select { value, .. } => {
|
||||
let sel = ctx.get_val(value, into_mod);
|
||||
relooper.add_block_with_switch(block_expr.clone(), sel)
|
||||
}
|
||||
_ => relooper.add_block(block_expr.clone()),
|
||||
};
|
||||
relooper_blocks.insert(*block_id, (block_expr.clone(), block));
|
||||
}
|
||||
|
||||
// Add edges.
|
||||
for &block_id in block_exprs.keys() {
|
||||
let (mut block_expr, block) = relooper_blocks.get(&block_id).unwrap().clone();
|
||||
match &body.blocks[block_id].terminator {
|
||||
&Terminator::Br { ref target } => {
|
||||
let (target_block, edge) = build_ssa_edge(&ctx, target, &relooper_blocks, into_mod);
|
||||
block.branch(target_block, edge);
|
||||
}
|
||||
&Terminator::CondBr {
|
||||
cond,
|
||||
ref if_true,
|
||||
ref if_false,
|
||||
} => {
|
||||
let (true_block, true_edge) =
|
||||
build_ssa_edge(&ctx, if_true, &relooper_blocks, into_mod);
|
||||
let (false_block, false_edge) =
|
||||
build_ssa_edge(&ctx, if_false, &relooper_blocks, into_mod);
|
||||
let cond = ctx.get_val(cond, into_mod);
|
||||
block.cond_branch(true_block, cond, true_edge);
|
||||
block.branch(false_block, false_edge);
|
||||
}
|
||||
&Terminator::Select {
|
||||
value: _,
|
||||
ref targets,
|
||||
ref default,
|
||||
} => {
|
||||
for (i, target) in targets.iter().enumerate() {
|
||||
let (target_block, edge) =
|
||||
build_ssa_edge(&ctx, target, &relooper_blocks, into_mod);
|
||||
block.switch(target_block, edge, &[i as u32]);
|
||||
}
|
||||
let (target_block, edge) =
|
||||
build_ssa_edge(&ctx, default, &relooper_blocks, into_mod);
|
||||
block.switch(target_block, edge, &[]);
|
||||
}
|
||||
&Terminator::Return { ref values } => {
|
||||
let values = values
|
||||
.iter()
|
||||
.map(|value| ctx.get_val(*value, into_mod))
|
||||
.collect::<Vec<_>>();
|
||||
block_expr.block_append_child(binaryen::Expression::ret(into_mod, &values[..]));
|
||||
}
|
||||
&Terminator::Unreachable | &Terminator::None => {
|
||||
block_expr.block_append_child(binaryen::Expression::unreachable(into_mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let index_var = ctx.new_local(Type::I32);
|
||||
let expr = relooper.construct(entry.unwrap(), index_var.index());
|
||||
let entry = relooper_blocks.get(&ctx.body.entry).unwrap().1.clone();
|
||||
let expr = relooper.construct(entry, index_var.index());
|
||||
(ctx.new_locals, expr)
|
||||
}
|
||||
|
||||
fn build_ssa_edge(
|
||||
ctx: &ElabCtx<'_>,
|
||||
target: &BlockTarget,
|
||||
blocks: &FxHashMap<Block, (binaryen::Expression, binaryen::RelooperBlock)>,
|
||||
into_mod: &mut binaryen::Module,
|
||||
) -> (binaryen::RelooperBlock, binaryen::Expression) {
|
||||
// Copy all block args to the "next" locals. Build an edge block
|
||||
// with these get-set pairs.
|
||||
let mut sets = vec![];
|
||||
for (i, arg) in target.args.iter().enumerate() {
|
||||
let value = ctx.get_val(*arg, into_mod);
|
||||
let set = binaryen::Expression::local_set(
|
||||
into_mod,
|
||||
*ctx.block_param_next_locals.get(&(target.block, i)).unwrap(),
|
||||
value,
|
||||
);
|
||||
sets.push(set);
|
||||
}
|
||||
|
||||
let edge_block = binaryen::Expression::block(into_mod, &sets[..]);
|
||||
let block = blocks.get(&target.block).unwrap().1.clone();
|
||||
(block, edge_block)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ElabCtx<'a> {
|
||||
body: &'a FunctionBody,
|
||||
op_result_locals: FxHashMap<(Value, usize), Local>,
|
||||
block_param_locals: FxHashMap<(Block, usize), Local>,
|
||||
block_param_next_locals: FxHashMap<(Block, usize), Local>,
|
||||
new_locals: Vec<Type>,
|
||||
}
|
||||
|
||||
|
@ -93,7 +189,6 @@ impl<'a> ElabCtx<'a> {
|
|||
|
||||
fn get_val_local(&self, value: Value) -> Local {
|
||||
match &self.body.values[value] {
|
||||
&ValueDef::Arg(idx, _) => Local::new(idx),
|
||||
&ValueDef::BlockParam(block, idx, _) => {
|
||||
self.block_param_locals.get(&(block, idx)).copied().unwrap()
|
||||
}
|
||||
|
@ -102,10 +197,15 @@ impl<'a> ElabCtx<'a> {
|
|||
self.op_result_locals.get(&(value, idx)).copied().unwrap()
|
||||
}
|
||||
&ValueDef::Alias(val) => self.get_val_local(val),
|
||||
&ValueDef::Placeholder(_) => unreachable!(),
|
||||
&ValueDef::Placeholder(_) | &ValueDef::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_val(&self, value: Value, into_mod: &mut binaryen::Module) -> binaryen::Expression {
|
||||
let local = self.get_val_local(value);
|
||||
binaryen::Expression::local_get(into_mod, local, self.body.values[value].ty().unwrap())
|
||||
}
|
||||
|
||||
fn new_local(&mut self, ty: Type) -> Local {
|
||||
let index = Local::new(self.body.locals.len() + self.new_locals.len());
|
||||
self.new_locals.push(ty);
|
||||
|
@ -152,4 +252,3 @@ pub(crate) fn create_new_func(
|
|||
body_expr,
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,17 @@ pub enum ValueDef {
|
|||
}
|
||||
|
||||
impl ValueDef {
|
||||
pub fn ty(&self) -> Option<Type> {
|
||||
match self {
|
||||
&ValueDef::BlockParam(_, _, ty) => Some(ty),
|
||||
&ValueDef::Operator(_, _, ref tys) if tys.len() == 0 => None,
|
||||
&ValueDef::Operator(_, _, ref tys) if tys.len() == 1 => Some(tys[0]),
|
||||
&ValueDef::PickOutput(_, _, ty) => Some(ty),
|
||||
&ValueDef::Placeholder(ty) => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_uses<F: FnMut(Value)>(&self, mut f: F) {
|
||||
match self {
|
||||
&ValueDef::BlockParam { .. } => {}
|
||||
|
|
Loading…
Reference in a new issue