big refactor
This commit is contained in:
parent
1da150823d
commit
a538d10167
|
@ -1,4 +1,6 @@
|
||||||
|
/*
|
||||||
use crate::backend::binaryen;
|
use crate::backend::binaryen;
|
||||||
|
use crate::entity::EntityRef;
|
||||||
use crate::ir::*;
|
use crate::ir::*;
|
||||||
use crate::Operator;
|
use crate::Operator;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
|
@ -14,9 +16,9 @@ pub(crate) fn generate_body(
|
||||||
let mut ctx = ElabCtx::new(body, into_mod);
|
let mut ctx = ElabCtx::new(body, into_mod);
|
||||||
|
|
||||||
// For each block, generate an expr.
|
// For each block, generate an expr.
|
||||||
let mut block_exprs: FxHashMap<BlockId, binaryen::Expression> = FxHashMap::default();
|
let mut block_exprs: FxHashMap<Block, binaryen::Expression> = FxHashMap::default();
|
||||||
for block in body.blocks() {
|
for (block_id, block) in body.blocks.entries() {
|
||||||
let exprs = body[block]
|
let exprs = block
|
||||||
.insts
|
.insts
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|&inst| {
|
.flat_map(|&inst| {
|
||||||
|
@ -24,61 +26,32 @@ pub(crate) fn generate_body(
|
||||||
ctx.elaborate_value(into_mod, inst)
|
ctx.elaborate_value(into_mod, inst)
|
||||||
})
|
})
|
||||||
.collect::<Vec<binaryen::Expression>>();
|
.collect::<Vec<binaryen::Expression>>();
|
||||||
block_exprs.insert(block, binaryen::Expression::block(into_mod, &exprs[..]));
|
block_exprs.insert(block_id, binaryen::Expression::block(into_mod, &exprs[..]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine blocks into a single body expression, using the
|
// Combine blocks into a single body expression, using the
|
||||||
// relooper/stackifier support built into Binaryen.
|
// relooper/stackifier support built into Binaryen.
|
||||||
let mut relooper = binaryen::Relooper::new(into_mod);
|
let mut relooper = binaryen::Relooper::new(into_mod);
|
||||||
let mut entry = None;
|
let mut entry = None;
|
||||||
let mut relooper_blocks: FxHashMap<BlockId, binaryen::RelooperBlock> = FxHashMap::default();
|
let mut relooper_blocks: FxHashMap<Block, binaryen::RelooperBlock> = FxHashMap::default();
|
||||||
for (block_id, block_expr) in block_exprs {}
|
for (block_id, block_expr) in block_exprs {}
|
||||||
|
|
||||||
let index_var = ctx.new_local(Type::I32);
|
let index_var = ctx.new_local(Type::I32);
|
||||||
let expr = relooper.construct(entry.unwrap(), index_var as usize);
|
let expr = relooper.construct(entry.unwrap(), index_var.index());
|
||||||
(ctx.new_locals, expr)
|
(ctx.new_locals, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct ElabCtx<'a> {
|
struct ElabCtx<'a> {
|
||||||
body: &'a FunctionBody,
|
body: &'a FunctionBody,
|
||||||
op_result_locals: FxHashMap<(Value, usize), LocalId>,
|
op_result_locals: FxHashMap<(Value, usize), Local>,
|
||||||
block_param_locals: FxHashMap<(BlockId, usize), LocalId>,
|
block_param_locals: FxHashMap<(Block, usize), Local>,
|
||||||
new_locals: Vec<Type>,
|
new_locals: Vec<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ElabCtx<'a> {
|
impl<'a> ElabCtx<'a> {
|
||||||
fn new(body: &'a FunctionBody, into_mod: &mut binaryen::Module) -> ElabCtx<'a> {
|
fn new(body: &'a FunctionBody, into_mod: &mut binaryen::Module) -> ElabCtx<'a> {
|
||||||
// Create locals for each blockparam.
|
todo!()
|
||||||
let mut this = ElabCtx {
|
|
||||||
body,
|
|
||||||
op_result_locals: FxHashMap::default(),
|
|
||||||
block_param_locals: FxHashMap::default(),
|
|
||||||
new_locals: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
for block in body.blocks() {
|
|
||||||
for &(ty, param) in &body[block].params {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create locals for each Operator value and each blockparam.
|
|
||||||
for (value, def) in body.values() {
|
|
||||||
match def {
|
|
||||||
&ValueDef::Operator(_, _, ref tys) => {
|
|
||||||
for (i, ty) in tys.iter().copied().enumerate() {
|
|
||||||
let local = this.new_local(ty);
|
|
||||||
this.op_result_locals.insert((value, i), local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&ValueDef::BlockParam(block, index, ty) => {
|
|
||||||
let local = this.new_local(ty);
|
|
||||||
this.block_param_locals.insert((block, index), local);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn elaborate_value(
|
fn elaborate_value(
|
||||||
|
@ -86,9 +59,10 @@ impl<'a> ElabCtx<'a> {
|
||||||
into_mod: &binaryen::Module,
|
into_mod: &binaryen::Module,
|
||||||
value: Value,
|
value: Value,
|
||||||
) -> Option<binaryen::Expression> {
|
) -> Option<binaryen::Expression> {
|
||||||
|
/*
|
||||||
let value = self.body.resolve_alias(value);
|
let value = self.body.resolve_alias(value);
|
||||||
|
|
||||||
match &self.body[value] {
|
match &self.body.values[value] {
|
||||||
&ValueDef::Operator(op, ref args, ref tys) => {
|
&ValueDef::Operator(op, ref args, ref tys) => {
|
||||||
// Get expressions for each arg.
|
// Get expressions for each arg.
|
||||||
let args = args.iter().map(|&arg| self.get_val_local(arg));
|
let args = args.iter().map(|&arg| self.get_val_local(arg));
|
||||||
|
@ -113,11 +87,13 @@ impl<'a> ElabCtx<'a> {
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_val_local(&self, value: Value) -> LocalId {
|
fn get_val_local(&self, value: Value) -> Local {
|
||||||
match &self.body[value] {
|
match &self.body.values[value] {
|
||||||
&ValueDef::Arg(idx, _) => idx as LocalId,
|
&ValueDef::Arg(idx, _) => Local::new(idx),
|
||||||
&ValueDef::BlockParam(block, idx, _) => {
|
&ValueDef::BlockParam(block, idx, _) => {
|
||||||
self.block_param_locals.get(&(block, idx)).copied().unwrap()
|
self.block_param_locals.get(&(block, idx)).copied().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -130,8 +106,8 @@ impl<'a> ElabCtx<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_local(&mut self, ty: Type) -> LocalId {
|
fn new_local(&mut self, ty: Type) -> Local {
|
||||||
let index = (self.body.locals.len() + self.new_locals.len()) as LocalId;
|
let index = Local::new(self.body.locals.len() + self.new_locals.len());
|
||||||
self.new_locals.push(ty);
|
self.new_locals.push(ty);
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
@ -145,19 +121,18 @@ impl<'a> ElabCtx<'a> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_ty(&self, local: LocalId) -> Type {
|
fn local_ty(&self, local: Local) -> Type {
|
||||||
let index = local as usize;
|
|
||||||
self.body
|
self.body
|
||||||
.locals
|
.locals
|
||||||
.get(index)
|
.get(local)
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or_else(|| self.new_locals[index - self.body.locals.len()])
|
.unwrap_or_else(|| self.new_locals[local.index() - self.body.locals.len()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_new_func(
|
pub(crate) fn create_new_func(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
sig: SignatureId,
|
sig: Signature,
|
||||||
body: &FunctionBody,
|
body: &FunctionBody,
|
||||||
into_mod: &mut binaryen::Module,
|
into_mod: &mut binaryen::Module,
|
||||||
body_expr: binaryen::Expression,
|
body_expr: binaryen::Expression,
|
||||||
|
@ -170,10 +145,11 @@ pub(crate) fn create_new_func(
|
||||||
sig.params.iter().copied(),
|
sig.params.iter().copied(),
|
||||||
sig.returns.iter().copied(),
|
sig.returns.iter().copied(),
|
||||||
body.locals
|
body.locals
|
||||||
.iter()
|
.values()
|
||||||
.copied()
|
.copied()
|
||||||
.skip(body.n_params)
|
.skip(body.n_params)
|
||||||
.chain(new_locals.into_iter()),
|
.chain(new_locals.into_iter()),
|
||||||
body_expr,
|
body_expr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -12,18 +12,19 @@
|
||||||
// TR-06-33870
|
// TR-06-33870
|
||||||
// https://www.cs.rice.edu/~keith/EMBED/dom.pdf
|
// https://www.cs.rice.edu/~keith/EMBED/dom.pdf
|
||||||
|
|
||||||
use crate::ir::{BlockId, INVALID_BLOCK};
|
use crate::entity::{EntityRef, PerEntity};
|
||||||
|
use crate::ir::Block;
|
||||||
|
|
||||||
// Helper
|
// Helper
|
||||||
fn merge_sets(
|
fn merge_sets(
|
||||||
idom: &[BlockId], // map from BlockId to BlockId
|
idom: &PerEntity<Block, Block>, // map from Block to Block
|
||||||
block_to_rpo: &[Option<u32>],
|
block_to_rpo: &PerEntity<Block, Option<u32>>,
|
||||||
mut node1: BlockId,
|
mut node1: Block,
|
||||||
mut node2: BlockId,
|
mut node2: Block,
|
||||||
) -> BlockId {
|
) -> Block {
|
||||||
while node1 != node2 {
|
while node1 != node2 {
|
||||||
if node1 == INVALID_BLOCK || node2 == INVALID_BLOCK {
|
if node1.is_invalid() || node2.is_invalid() {
|
||||||
return INVALID_BLOCK;
|
return Block::invalid();
|
||||||
}
|
}
|
||||||
let rpo1 = block_to_rpo[node1].unwrap();
|
let rpo1 = block_to_rpo[node1].unwrap();
|
||||||
let rpo2 = block_to_rpo[node2].unwrap();
|
let rpo2 = block_to_rpo[node2].unwrap();
|
||||||
|
@ -37,22 +38,20 @@ fn merge_sets(
|
||||||
node1
|
node1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate<'a, PredFn: Fn(BlockId) -> &'a [BlockId]>(
|
pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
|
||||||
num_blocks: usize,
|
|
||||||
preds: PredFn,
|
preds: PredFn,
|
||||||
post_ord: &[BlockId],
|
post_ord: &[Block],
|
||||||
start: BlockId,
|
start: Block,
|
||||||
) -> Vec<BlockId> {
|
) -> PerEntity<Block, Block> {
|
||||||
// We have post_ord, which is the postorder sequence.
|
// We have post_ord, which is the postorder sequence.
|
||||||
|
|
||||||
// Compute maps from RPO to block number and vice-versa.
|
// Compute maps from RPO to block number and vice-versa.
|
||||||
let mut block_to_rpo = vec![None; num_blocks];
|
let mut block_to_rpo: PerEntity<Block, Option<u32>> = PerEntity::default();
|
||||||
block_to_rpo.resize(num_blocks, None);
|
|
||||||
for (i, rpo_block) in post_ord.iter().rev().enumerate() {
|
for (i, rpo_block) in post_ord.iter().rev().enumerate() {
|
||||||
block_to_rpo[*rpo_block] = Some(i as u32);
|
block_to_rpo[*rpo_block] = Some(i as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut idom = vec![INVALID_BLOCK; num_blocks];
|
let mut idom: PerEntity<Block, Block> = PerEntity::default();
|
||||||
|
|
||||||
// The start node must have itself as a parent.
|
// The start node must have itself as a parent.
|
||||||
idom[start] = start;
|
idom[start] = start;
|
||||||
|
@ -64,7 +63,7 @@ pub fn calculate<'a, PredFn: Fn(BlockId) -> &'a [BlockId]>(
|
||||||
for &node in post_ord.iter().rev() {
|
for &node in post_ord.iter().rev() {
|
||||||
let rponum = block_to_rpo[node].unwrap();
|
let rponum = block_to_rpo[node].unwrap();
|
||||||
|
|
||||||
let mut parent = INVALID_BLOCK;
|
let mut parent = Block::invalid();
|
||||||
for &pred in preds(node).iter() {
|
for &pred in preds(node).iter() {
|
||||||
let pred_rpo = match block_to_rpo[pred] {
|
let pred_rpo = match block_to_rpo[pred] {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
|
@ -79,19 +78,19 @@ pub fn calculate<'a, PredFn: Fn(BlockId) -> &'a [BlockId]>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent != INVALID_BLOCK {
|
if parent != Block::invalid() {
|
||||||
for &pred in preds(node).iter() {
|
for &pred in preds(node).iter() {
|
||||||
if pred == parent {
|
if pred == parent {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if idom[pred] == INVALID_BLOCK {
|
if idom[pred] == Block::invalid() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
parent = merge_sets(&idom, &block_to_rpo[..], parent, pred);
|
parent = merge_sets(&idom, &block_to_rpo, parent, pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent != INVALID_BLOCK && parent != idom[node] {
|
if parent != Block::invalid() && parent != idom[node] {
|
||||||
idom[node] = parent;
|
idom[node] = parent;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -100,17 +99,17 @@ pub fn calculate<'a, PredFn: Fn(BlockId) -> &'a [BlockId]>(
|
||||||
|
|
||||||
// Now set the start node's dominator-tree parent to "invalid";
|
// Now set the start node's dominator-tree parent to "invalid";
|
||||||
// this allows the loop in `dominates` to terminate.
|
// this allows the loop in `dominates` to terminate.
|
||||||
idom[start] = INVALID_BLOCK;
|
idom[start] = Block::invalid();
|
||||||
|
|
||||||
idom
|
idom
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dominates(idom: &[BlockId], a: BlockId, mut b: BlockId) -> bool {
|
pub fn dominates(idom: &PerEntity<Block, Block>, a: Block, mut b: Block) -> bool {
|
||||||
loop {
|
loop {
|
||||||
if a == b {
|
if a == b {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if b == INVALID_BLOCK {
|
if b.is_invalid() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
b = idom[b];
|
b = idom[b];
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
// Borrowed from regalloc2's cfg.rs, which is also Apache-2.0 with
|
// Borrowed from regalloc2's cfg.rs, which is also Apache-2.0 with
|
||||||
// LLVM exception.
|
// LLVM exception.
|
||||||
|
|
||||||
use crate::ir::{BlockId, FunctionBody, Terminator};
|
use crate::entity::PerEntity;
|
||||||
|
use crate::ir::{Block, FunctionBody, Terminator};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
pub mod domtree;
|
pub mod domtree;
|
||||||
|
@ -11,53 +12,55 @@ pub mod postorder;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CFGInfo {
|
pub struct CFGInfo {
|
||||||
|
/// Entry block.
|
||||||
|
pub entry: Block,
|
||||||
/// Predecessors for each block.
|
/// Predecessors for each block.
|
||||||
pub block_preds: Vec</* BlockId, */ SmallVec<[BlockId; 4]>>,
|
pub block_preds: PerEntity<Block, SmallVec<[Block; 4]>>,
|
||||||
/// Successors for each block.
|
/// Successors for each block.
|
||||||
pub block_succs: Vec</* BlockId, */ SmallVec<[BlockId; 4]>>,
|
pub block_succs: PerEntity<Block, SmallVec<[Block; 4]>>,
|
||||||
/// Blocks that end in return.
|
/// Blocks that end in return.
|
||||||
pub return_blocks: Vec<BlockId>,
|
pub return_blocks: Vec<Block>,
|
||||||
/// Postorder traversal of blocks.
|
/// Postorder traversal of blocks.
|
||||||
pub postorder: Vec<BlockId>,
|
pub postorder: Vec<Block>,
|
||||||
/// Position of each block in postorder, if reachable.
|
/// Position of each block in postorder, if reachable.
|
||||||
pub postorder_pos: Vec</* BlockId, */ Option<usize>>,
|
pub postorder_pos: PerEntity<Block, Option<usize>>,
|
||||||
/// Domtree parents, indexed by block.
|
/// Domtree parents, indexed by block.
|
||||||
pub domtree: Vec<BlockId>,
|
pub domtree: PerEntity<Block, Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CFGInfo {
|
impl CFGInfo {
|
||||||
pub fn new(f: &FunctionBody) -> CFGInfo {
|
pub fn new(f: &FunctionBody) -> CFGInfo {
|
||||||
let mut block_preds = vec![SmallVec::new(); f.blocks.len()];
|
let mut block_preds: PerEntity<Block, SmallVec<[Block; 4]>> = PerEntity::default();
|
||||||
let mut block_succs = vec![SmallVec::new(); f.blocks.len()];
|
let mut block_succs: PerEntity<Block, SmallVec<[Block; 4]>> = PerEntity::default();
|
||||||
for block in 0..f.blocks.len() {
|
for (block, block_def) in f.blocks.entries() {
|
||||||
f.blocks[block].terminator.visit_successors(|succ| {
|
block_def.terminator.visit_successors(|succ| {
|
||||||
block_preds[succ].push(block);
|
block_preds[succ].push(block);
|
||||||
block_succs[block].push(succ);
|
block_succs[block].push(succ);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut return_blocks = vec![];
|
let mut return_blocks = vec![];
|
||||||
for block in 0..f.blocks.len() {
|
for (block_id, block) in f.blocks.entries() {
|
||||||
if let Terminator::Return { .. } = &f.blocks[block].terminator {
|
if let Terminator::Return { .. } = &block.terminator {
|
||||||
return_blocks.push(block);
|
return_blocks.push(block_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let postorder = postorder::calculate(f.blocks.len(), 0, |block| &block_succs[block]);
|
let postorder = postorder::calculate(f.entry, |block| &block_succs[block]);
|
||||||
|
|
||||||
let mut postorder_pos = vec![None; f.blocks.len()];
|
let mut postorder_pos = PerEntity::default();
|
||||||
for (i, block) in postorder.iter().enumerate() {
|
for (i, block) in postorder.iter().enumerate() {
|
||||||
postorder_pos[*block] = Some(i);
|
postorder_pos[*block] = Some(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
let domtree = domtree::calculate(
|
let domtree = domtree::calculate(
|
||||||
f.blocks.len(),
|
|
||||||
|block| &&block_preds[block],
|
|block| &&block_preds[block],
|
||||||
&postorder[..],
|
&postorder[..],
|
||||||
0,
|
f.entry,
|
||||||
);
|
);
|
||||||
|
|
||||||
CFGInfo {
|
CFGInfo {
|
||||||
|
entry: f.entry,
|
||||||
block_preds,
|
block_preds,
|
||||||
block_succs,
|
block_succs,
|
||||||
return_blocks,
|
return_blocks,
|
||||||
|
@ -67,37 +70,33 @@ impl CFGInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn dominates(&self, a: Block, b: Block) -> bool {
|
||||||
self.block_succs.len()
|
domtree::dominates(&self.domtree, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dominates(&self, a: BlockId, b: BlockId) -> bool {
|
pub fn succs(&self, block: Block) -> &[Block] {
|
||||||
domtree::dominates(&self.domtree[..], a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn succs(&self, block: BlockId) -> &[BlockId] {
|
|
||||||
&self.block_succs[block]
|
&self.block_succs[block]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preds(&self, block: BlockId) -> &[BlockId] {
|
pub fn preds(&self, block: Block) -> &[Block] {
|
||||||
&self.block_preds[block]
|
&self.block_preds[block]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pred_count_with_entry(&self, block: BlockId) -> usize {
|
pub fn pred_count_with_entry(&self, block: Block) -> usize {
|
||||||
let is_entry = block == 0;
|
let is_entry = block == self.entry;
|
||||||
self.preds(block).len() + if is_entry { 1 } else { 0 }
|
self.preds(block).len() + if is_entry { 1 } else { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn succ_count_with_return(&self, block: BlockId) -> usize {
|
pub fn succ_count_with_return(&self, block: Block) -> usize {
|
||||||
let is_return = self.return_blocks.binary_search(&block).is_ok();
|
let is_return = self.return_blocks.binary_search(&block).is_ok();
|
||||||
self.succs(block).len() + if is_return { 1 } else { 0 }
|
self.succs(block).len() + if is_return { 1 } else { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rpo(&self) -> Vec<BlockId> {
|
pub fn rpo(&self) -> Vec<Block> {
|
||||||
self.postorder.iter().cloned().rev().collect()
|
self.postorder.iter().cloned().rev().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rpo_pos(&self, block: BlockId) -> Option<usize> {
|
pub fn rpo_pos(&self, block: Block) -> Option<usize> {
|
||||||
self.postorder_pos[block].map(|fwd_pos| self.postorder.len() - 1 - fwd_pos)
|
self.postorder_pos[block].map(|fwd_pos| self.postorder.len() - 1 - fwd_pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,24 +3,23 @@
|
||||||
// Borrowed from regalloc2's postorder.rs, which is also Apache-2.0
|
// Borrowed from regalloc2's postorder.rs, which is also Apache-2.0
|
||||||
// with LLVM-exception.
|
// with LLVM-exception.
|
||||||
|
|
||||||
use crate::ir::BlockId;
|
use crate::entity::PerEntity;
|
||||||
|
use crate::ir::Block;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
pub fn calculate<'a, SuccFn: Fn(BlockId) -> &'a [BlockId]>(
|
pub fn calculate<'a, SuccFn: Fn(Block) -> &'a [Block]>(
|
||||||
num_blocks: usize,
|
entry: Block,
|
||||||
entry: BlockId,
|
|
||||||
succ_blocks: SuccFn,
|
succ_blocks: SuccFn,
|
||||||
) -> Vec<BlockId> {
|
) -> Vec<Block> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
|
|
||||||
// State: visited-block map, and explicit DFS stack.
|
// State: visited-block map, and explicit DFS stack.
|
||||||
let mut visited = vec![];
|
let mut visited: PerEntity<Block, bool> = PerEntity::default();
|
||||||
visited.resize(num_blocks, false);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct State<'a> {
|
struct State<'a> {
|
||||||
block: BlockId,
|
block: Block,
|
||||||
succs: &'a [BlockId],
|
succs: &'a [Block],
|
||||||
next_succ: usize,
|
next_succ: usize,
|
||||||
}
|
}
|
||||||
let mut stack: SmallVec<[State; 64]> = smallvec![];
|
let mut stack: SmallVec<[State; 64]> = smallvec![];
|
||||||
|
|
152
src/entity.rs
Normal file
152
src/entity.rs
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
//! Type-safe indices and indexed containers.
|
||||||
|
|
||||||
|
use std::default::Default;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
pub trait EntityRef: Clone + Copy + PartialEq + Eq + PartialOrd + Ord + Hash {
|
||||||
|
fn new(value: usize) -> Self;
|
||||||
|
fn index(self) -> usize;
|
||||||
|
fn invalid() -> Self;
|
||||||
|
fn is_valid(self) -> bool {
|
||||||
|
self != Self::invalid()
|
||||||
|
}
|
||||||
|
fn is_invalid(self) -> bool {
|
||||||
|
self == Self::invalid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! entity {
|
||||||
|
($name:tt, $prefix:tt) => {
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct $name(u32);
|
||||||
|
|
||||||
|
impl crate::entity::EntityRef for $name {
|
||||||
|
fn new(value: usize) -> Self {
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
let value = u32::try_from(value).unwrap();
|
||||||
|
debug_assert!(value != u32::MAX);
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
fn index(self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
fn invalid() -> Self {
|
||||||
|
Self(u32::MAX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<u32> for $name {
|
||||||
|
fn from(val: u32) -> Self {
|
||||||
|
<Self as crate::entity::EntityRef>::new(val as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::default::Default for $name {
|
||||||
|
fn default() -> Self {
|
||||||
|
<Self as crate::entity::EntityRef>::invalid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for $name {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{}{}", $prefix, self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for $name {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{}{}", $prefix, self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct EntityVec<Idx: EntityRef, T: Clone + Debug>(Vec<T>, PhantomData<Idx>);
|
||||||
|
|
||||||
|
impl<Idx: EntityRef, T: Clone + Debug> std::default::Default for EntityVec<Idx, T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(vec![], PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Idx: EntityRef, T: Clone + Debug> EntityVec<Idx, T> {
|
||||||
|
pub fn push(&mut self, t: T) -> Idx {
|
||||||
|
let idx = Idx::new(self.0.len());
|
||||||
|
self.0.push(t);
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = Idx> {
|
||||||
|
(0..self.0.len()).map(|index| Idx::new(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn values(&self) -> impl Iterator<Item = &T> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||||
|
self.0.iter_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entries(&self) -> impl Iterator<Item = (Idx, &T)> {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, t)| (Idx::new(index), t))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entries_mut(&mut self) -> impl Iterator<Item = (Idx, &mut T)> {
|
||||||
|
self.0
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, t)| (Idx::new(index), t))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, idx: Idx) -> Option<&T> {
|
||||||
|
self.0.get(idx.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, idx: Idx) -> Option<&mut T> {
|
||||||
|
self.0.get_mut(idx.index())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Idx: EntityRef, T: Clone + Debug> Index<Idx> for EntityVec<Idx, T> {
|
||||||
|
type Output = T;
|
||||||
|
fn index(&self, idx: Idx) -> &T {
|
||||||
|
&self.0[idx.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Idx: EntityRef, T: Clone + Debug> IndexMut<Idx> for EntityVec<Idx, T> {
|
||||||
|
fn index_mut(&mut self, idx: Idx) -> &mut T {
|
||||||
|
&mut self.0[idx.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct PerEntity<Idx: EntityRef, T: Clone + Debug + Default>(Vec<T>, PhantomData<Idx>, T);
|
||||||
|
|
||||||
|
impl<Idx: EntityRef, T: Clone + Debug + Default> Index<Idx> for PerEntity<Idx, T> {
|
||||||
|
type Output = T;
|
||||||
|
fn index(&self, idx: Idx) -> &T {
|
||||||
|
self.0.get(idx.index()).unwrap_or(&self.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Idx: EntityRef, T: Clone + Debug + Default> IndexMut<Idx> for PerEntity<Idx, T> {
|
||||||
|
fn index_mut(&mut self, idx: Idx) -> &mut T {
|
||||||
|
if idx.index() >= self.0.len() {
|
||||||
|
self.0.resize(idx.index() + 1, T::default());
|
||||||
|
}
|
||||||
|
&mut self.0[idx.index()]
|
||||||
|
}
|
||||||
|
}
|
130
src/frontend.rs
130
src/frontend.rs
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use crate::entity::EntityRef;
|
||||||
|
|
||||||
use crate::ir::*;
|
use crate::ir::*;
|
||||||
use crate::op_traits::{op_inputs, op_outputs};
|
use crate::op_traits::{op_inputs, op_outputs};
|
||||||
use crate::ops::Operator;
|
use crate::ops::Operator;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use fxhash::{FxHashMap, FxHashSet};
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
Ieee32, Ieee64, ImportSectionEntryType, Parser, Payload, Type, TypeDef, TypeOrFuncType,
|
Ieee32, Ieee64, ImportSectionEntryType, Parser, Payload, Type, TypeDef, TypeOrFuncType,
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@ fn handle_payload<'a>(
|
||||||
for _ in 0..reader.get_count() {
|
for _ in 0..reader.get_count() {
|
||||||
match reader.read()?.ty {
|
match reader.read()?.ty {
|
||||||
ImportSectionEntryType::Function(sig_idx) => {
|
ImportSectionEntryType::Function(sig_idx) => {
|
||||||
module.frontend_add_func(FuncDecl::Import(sig_idx as SignatureId));
|
module.frontend_add_func(FuncDecl::Import(Signature::from(sig_idx)));
|
||||||
*next_func += 1;
|
*next_func += 1;
|
||||||
}
|
}
|
||||||
ImportSectionEntryType::Global(ty) => {
|
ImportSectionEntryType::Global(ty) => {
|
||||||
|
@ -72,12 +72,12 @@ fn handle_payload<'a>(
|
||||||
}
|
}
|
||||||
Payload::FunctionSection(mut reader) => {
|
Payload::FunctionSection(mut reader) => {
|
||||||
for _ in 0..reader.get_count() {
|
for _ in 0..reader.get_count() {
|
||||||
let sig_idx = reader.read()? as SignatureId;
|
let sig_idx = Signature::from(reader.read()?);
|
||||||
module.frontend_add_func(FuncDecl::Body(sig_idx, FunctionBody::default()));
|
module.frontend_add_func(FuncDecl::Body(sig_idx, FunctionBody::default()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Payload::CodeSectionEntry(body) => {
|
Payload::CodeSectionEntry(body) => {
|
||||||
let func_idx = *next_func;
|
let func_idx = Func::new(*next_func);
|
||||||
*next_func += 1;
|
*next_func += 1;
|
||||||
|
|
||||||
let my_sig = module.func(func_idx).sig();
|
let my_sig = module.func(func_idx).sig();
|
||||||
|
@ -94,7 +94,7 @@ fn handle_payload<'a>(
|
||||||
|
|
||||||
fn parse_body<'a>(
|
fn parse_body<'a>(
|
||||||
module: &'a Module,
|
module: &'a Module,
|
||||||
my_sig: SignatureId,
|
my_sig: Signature,
|
||||||
body: wasmparser::FunctionBody,
|
body: wasmparser::FunctionBody,
|
||||||
) -> Result<FunctionBody> {
|
) -> Result<FunctionBody> {
|
||||||
let mut ret: FunctionBody = FunctionBody::default();
|
let mut ret: FunctionBody = FunctionBody::default();
|
||||||
|
@ -123,11 +123,12 @@ fn parse_body<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut builder = FunctionBodyBuilder::new(module, my_sig, &mut ret);
|
let mut builder = FunctionBodyBuilder::new(module, my_sig, &mut ret);
|
||||||
builder.locals.seal_block_preds(0, &mut builder.body);
|
let entry = Block::new(0);
|
||||||
builder.locals.start_block(0);
|
builder.locals.seal_block_preds(entry, &mut builder.body);
|
||||||
|
builder.locals.start_block(entry);
|
||||||
|
|
||||||
for (arg_idx, &arg_ty) in module.signature(my_sig).params.iter().enumerate() {
|
for (arg_idx, &arg_ty) in module.signature(my_sig).params.iter().enumerate() {
|
||||||
let local_idx = arg_idx as LocalId;
|
let local_idx = Local::new(arg_idx);
|
||||||
let value = builder.body.add_value(ValueDef::Arg(arg_idx, arg_ty));
|
let value = builder.body.add_value(ValueDef::Arg(arg_idx, arg_ty));
|
||||||
trace!("defining local {} to value {}", local_idx, value);
|
trace!("defining local {} to value {}", local_idx, value);
|
||||||
builder.locals.declare(local_idx, arg_ty);
|
builder.locals.declare(local_idx, arg_ty);
|
||||||
|
@ -135,9 +136,9 @@ fn parse_body<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let n_args = module.signature(my_sig).params.len();
|
let n_args = module.signature(my_sig).params.len();
|
||||||
for (offset, local_ty) in locals.into_iter().enumerate() {
|
for (offset, local_ty) in locals.values().enumerate() {
|
||||||
let local_idx = (n_args + offset) as u32;
|
let local_idx = Local::new(n_args + offset);
|
||||||
builder.locals.declare(local_idx, local_ty);
|
builder.locals.declare(local_idx, *local_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ops = body.get_operators_reader()?;
|
let ops = body.get_operators_reader()?;
|
||||||
|
@ -150,12 +151,12 @@ fn parse_body<'a>(
|
||||||
builder.handle_op(wasmparser::Operator::Return)?;
|
builder.handle_op(wasmparser::Operator::Return)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for block in 0..builder.body.blocks.len() {
|
for block in builder.body.blocks.iter() {
|
||||||
log::trace!("checking if block is sealed: {}", block);
|
log::trace!("checking if block is sealed: {}", block);
|
||||||
assert!(builder.locals.is_sealed(block));
|
debug_assert!(builder.locals.is_sealed(block));
|
||||||
}
|
}
|
||||||
for value in &builder.body.values {
|
for value in builder.body.values.values() {
|
||||||
assert!(!matches!(value, &ValueDef::Placeholder(_)));
|
debug_assert!(!matches!(value, &ValueDef::Placeholder(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Final function body:{:?}", ret);
|
trace!("Final function body:{:?}", ret);
|
||||||
|
@ -166,26 +167,26 @@ fn parse_body<'a>(
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
struct LocalTracker {
|
struct LocalTracker {
|
||||||
/// Types of locals, as declared.
|
/// Types of locals, as declared.
|
||||||
types: FxHashMap<LocalId, Type>,
|
types: FxHashMap<Local, Type>,
|
||||||
/// The current block.
|
/// The current block.
|
||||||
cur_block: Option<BlockId>,
|
cur_block: Option<Block>,
|
||||||
/// Is the given block sealed?
|
/// Is the given block sealed?
|
||||||
block_sealed: FxHashSet<BlockId>,
|
block_sealed: FxHashSet<Block>,
|
||||||
/// The local-to-value mapping at the start of a block.
|
/// The local-to-value mapping at the start of a block.
|
||||||
block_start: FxHashMap<BlockId, FxHashMap<LocalId, Value>>,
|
block_start: FxHashMap<Block, FxHashMap<Local, Value>>,
|
||||||
/// The local-to-value mapping at the end of a block.
|
/// The local-to-value mapping at the end of a block.
|
||||||
block_end: FxHashMap<BlockId, FxHashMap<LocalId, Value>>,
|
block_end: FxHashMap<Block, FxHashMap<Local, Value>>,
|
||||||
in_cur_block: FxHashMap<LocalId, Value>,
|
in_cur_block: FxHashMap<Local, Value>,
|
||||||
incomplete_phis: FxHashMap<BlockId, Vec<(LocalId, Value)>>,
|
incomplete_phis: FxHashMap<Block, Vec<(Local, Value)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalTracker {
|
impl LocalTracker {
|
||||||
pub fn declare(&mut self, local: LocalId, ty: Type) {
|
pub fn declare(&mut self, local: Local, ty: Type) {
|
||||||
let was_present = self.types.insert(local, ty).is_some();
|
let was_present = self.types.insert(local, ty).is_some();
|
||||||
assert!(!was_present);
|
assert!(!was_present);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_block(&mut self, block: BlockId) {
|
pub fn start_block(&mut self, block: Block) {
|
||||||
self.finish_block();
|
self.finish_block();
|
||||||
log::trace!("start_block: block {}", block);
|
log::trace!("start_block: block {}", block);
|
||||||
self.cur_block = Some(block);
|
self.cur_block = Some(block);
|
||||||
|
@ -200,7 +201,7 @@ impl LocalTracker {
|
||||||
self.cur_block = None;
|
self.cur_block = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seal_block_preds(&mut self, block: BlockId, body: &mut FunctionBody) {
|
pub fn seal_block_preds(&mut self, block: Block, body: &mut FunctionBody) {
|
||||||
log::trace!("seal_block_preds: block {}", block);
|
log::trace!("seal_block_preds: block {}", block);
|
||||||
let not_sealed = self.block_sealed.insert(block);
|
let not_sealed = self.block_sealed.insert(block);
|
||||||
assert!(not_sealed);
|
assert!(not_sealed);
|
||||||
|
@ -213,23 +214,18 @@ impl LocalTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_sealed(&self, block: BlockId) -> bool {
|
fn is_sealed(&self, block: Block) -> bool {
|
||||||
self.block_sealed.contains(&block)
|
self.block_sealed.contains(&block)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, local: LocalId, value: Value) {
|
pub fn set(&mut self, local: Local, value: Value) {
|
||||||
log::trace!("set: local {} value {:?}", local, value);
|
log::trace!("set: local {} value {:?}", local, value);
|
||||||
self.in_cur_block.insert(local, value);
|
self.in_cur_block.insert(local, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_in_block(
|
fn get_in_block(&mut self, body: &mut FunctionBody, at_block: Block, local: Local) -> Value {
|
||||||
&mut self,
|
|
||||||
body: &mut FunctionBody,
|
|
||||||
at_block: BlockId,
|
|
||||||
local: LocalId,
|
|
||||||
) -> Value {
|
|
||||||
log::trace!("get_in_block: at_block {} local {}", at_block, local);
|
log::trace!("get_in_block: at_block {} local {}", at_block, local);
|
||||||
let ty = body.locals[local as usize];
|
let ty = body.locals[local];
|
||||||
|
|
||||||
if self.cur_block == Some(at_block) {
|
if self.cur_block == Some(at_block) {
|
||||||
if let Some(&value) = self.in_cur_block.get(&local) {
|
if let Some(&value) = self.in_cur_block.get(&local) {
|
||||||
|
@ -279,12 +275,11 @@ impl LocalTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, body: &mut FunctionBody, local: LocalId) -> Value {
|
pub fn get(&mut self, body: &mut FunctionBody, local: Local) -> Value {
|
||||||
if let Some(block) = self.cur_block {
|
if let Some(block) = self.cur_block {
|
||||||
assert!((local as usize) < body.locals.len());
|
|
||||||
self.get_in_block(body, block, local)
|
self.get_in_block(body, block, local)
|
||||||
} else {
|
} else {
|
||||||
let ty = body.locals[local as usize];
|
let ty = body.locals[local];
|
||||||
self.create_default_value(body, ty)
|
self.create_default_value(body, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,8 +317,8 @@ impl LocalTracker {
|
||||||
fn compute_blockparam(
|
fn compute_blockparam(
|
||||||
&mut self,
|
&mut self,
|
||||||
body: &mut FunctionBody,
|
body: &mut FunctionBody,
|
||||||
block: BlockId,
|
block: Block,
|
||||||
local: LocalId,
|
local: Local,
|
||||||
value: Value,
|
value: Value,
|
||||||
) {
|
) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
|
@ -400,10 +395,10 @@ impl LocalTracker {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FunctionBodyBuilder<'a, 'b> {
|
struct FunctionBodyBuilder<'a, 'b> {
|
||||||
module: &'b Module<'a>,
|
module: &'b Module<'a>,
|
||||||
my_sig: SignatureId,
|
my_sig: Signature,
|
||||||
body: &'b mut FunctionBody,
|
body: &'b mut FunctionBody,
|
||||||
locals: LocalTracker,
|
locals: LocalTracker,
|
||||||
cur_block: Option<BlockId>,
|
cur_block: Option<Block>,
|
||||||
ctrl_stack: Vec<Frame>,
|
ctrl_stack: Vec<Frame>,
|
||||||
op_stack: Vec<(Type, Value)>,
|
op_stack: Vec<(Type, Value)>,
|
||||||
}
|
}
|
||||||
|
@ -412,28 +407,28 @@ struct FunctionBodyBuilder<'a, 'b> {
|
||||||
enum Frame {
|
enum Frame {
|
||||||
Block {
|
Block {
|
||||||
start_depth: usize,
|
start_depth: usize,
|
||||||
out: BlockId,
|
out: Block,
|
||||||
params: Vec<Type>,
|
params: Vec<Type>,
|
||||||
results: Vec<Type>,
|
results: Vec<Type>,
|
||||||
},
|
},
|
||||||
Loop {
|
Loop {
|
||||||
start_depth: usize,
|
start_depth: usize,
|
||||||
header: BlockId,
|
header: Block,
|
||||||
out: BlockId,
|
out: Block,
|
||||||
params: Vec<Type>,
|
params: Vec<Type>,
|
||||||
results: Vec<Type>,
|
results: Vec<Type>,
|
||||||
},
|
},
|
||||||
If {
|
If {
|
||||||
start_depth: usize,
|
start_depth: usize,
|
||||||
out: BlockId,
|
out: Block,
|
||||||
el: BlockId,
|
el: Block,
|
||||||
param_values: Vec<(Type, Value)>,
|
param_values: Vec<(Type, Value)>,
|
||||||
params: Vec<Type>,
|
params: Vec<Type>,
|
||||||
results: Vec<Type>,
|
results: Vec<Type>,
|
||||||
},
|
},
|
||||||
Else {
|
Else {
|
||||||
start_depth: usize,
|
start_depth: usize,
|
||||||
out: BlockId,
|
out: Block,
|
||||||
params: Vec<Type>,
|
params: Vec<Type>,
|
||||||
results: Vec<Type>,
|
results: Vec<Type>,
|
||||||
},
|
},
|
||||||
|
@ -458,7 +453,7 @@ impl Frame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn br_target(&self) -> BlockId {
|
fn br_target(&self) -> Block {
|
||||||
match self {
|
match self {
|
||||||
Frame::Block { out, .. } => *out,
|
Frame::Block { out, .. } => *out,
|
||||||
Frame::Loop { header, .. } => *header,
|
Frame::Loop { header, .. } => *header,
|
||||||
|
@ -466,7 +461,7 @@ impl Frame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn out(&self) -> BlockId {
|
fn out(&self) -> Block {
|
||||||
match self {
|
match self {
|
||||||
Frame::Block { out, .. }
|
Frame::Block { out, .. }
|
||||||
| Frame::Loop { out, .. }
|
| Frame::Loop { out, .. }
|
||||||
|
@ -495,15 +490,15 @@ impl Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
fn new(module: &'b Module<'a>, my_sig: SignatureId, body: &'b mut FunctionBody) -> Self {
|
fn new(module: &'b Module<'a>, my_sig: Signature, body: &'b mut FunctionBody) -> Self {
|
||||||
body.blocks.push(Block::default());
|
body.blocks.push(BlockDef::default());
|
||||||
let mut ret = Self {
|
let mut ret = Self {
|
||||||
module,
|
module,
|
||||||
my_sig,
|
my_sig,
|
||||||
body,
|
body,
|
||||||
ctrl_stack: vec![],
|
ctrl_stack: vec![],
|
||||||
op_stack: vec![],
|
op_stack: vec![],
|
||||||
cur_block: Some(0),
|
cur_block: Some(Block::new(0)),
|
||||||
locals: LocalTracker::default(),
|
locals: LocalTracker::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -559,22 +554,25 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::LocalGet { local_index } => {
|
wasmparser::Operator::LocalGet { local_index } => {
|
||||||
let ty = self.body.locals[*local_index as usize];
|
let local_index = Local::from(*local_index);
|
||||||
let value = self.locals.get(&mut self.body, *local_index);
|
let ty = self.body.locals[local_index];
|
||||||
|
let value = self.locals.get(&mut self.body, local_index);
|
||||||
self.op_stack.push((ty, value));
|
self.op_stack.push((ty, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::LocalSet { local_index } => {
|
wasmparser::Operator::LocalSet { local_index } => {
|
||||||
|
let local_index = Local::from(*local_index);
|
||||||
let (_, value) = self.op_stack.pop().unwrap();
|
let (_, value) = self.op_stack.pop().unwrap();
|
||||||
if self.cur_block.is_some() {
|
if self.cur_block.is_some() {
|
||||||
self.locals.set(*local_index, value);
|
self.locals.set(local_index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::LocalTee { local_index } => {
|
wasmparser::Operator::LocalTee { local_index } => {
|
||||||
|
let local_index = Local::from(*local_index);
|
||||||
let (_ty, value) = *self.op_stack.last().unwrap();
|
let (_ty, value) = *self.op_stack.last().unwrap();
|
||||||
if self.cur_block.is_some() {
|
if self.cur_block.is_some() {
|
||||||
self.locals.set(*local_index, value);
|
self.locals.set(local_index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,7 +996,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_block_params(&mut self, block: BlockId, tys: &[Type]) {
|
fn add_block_params(&mut self, block: Block, tys: &[Type]) {
|
||||||
log::trace!("add_block_params: block {} tys {:?}", block, tys);
|
log::trace!("add_block_params: block {} tys {:?}", block, tys);
|
||||||
for &ty in tys {
|
for &ty in tys {
|
||||||
self.body.add_blockparam(block, ty);
|
self.body.add_blockparam(block, ty);
|
||||||
|
@ -1010,7 +1008,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
|
TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
|
||||||
TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]),
|
TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]),
|
||||||
TypeOrFuncType::FuncType(sig_idx) => {
|
TypeOrFuncType::FuncType(sig_idx) => {
|
||||||
let sig = &self.module.signature(sig_idx as SignatureId);
|
let sig = &self.module.signature(Signature::from(sig_idx));
|
||||||
(
|
(
|
||||||
Vec::from(sig.params.clone()),
|
Vec::from(sig.params.clone()),
|
||||||
Vec::from(sig.returns.clone()),
|
Vec::from(sig.returns.clone()),
|
||||||
|
@ -1023,7 +1021,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
&self.ctrl_stack[self.ctrl_stack.len() - 1 - relative_depth as usize]
|
&self.ctrl_stack[self.ctrl_stack.len() - 1 - relative_depth as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_branch(&mut self, target: BlockId, args: &[Value]) {
|
fn emit_branch(&mut self, target: Block, args: &[Value]) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"emit_branch: cur_block {:?} target {} args {:?}",
|
"emit_branch: cur_block {:?} target {} args {:?}",
|
||||||
self.cur_block,
|
self.cur_block,
|
||||||
|
@ -1045,9 +1043,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
fn emit_cond_branch(
|
fn emit_cond_branch(
|
||||||
&mut self,
|
&mut self,
|
||||||
cond: Value,
|
cond: Value,
|
||||||
if_true: BlockId,
|
if_true: Block,
|
||||||
if_true_args: &[Value],
|
if_true_args: &[Value],
|
||||||
if_false: BlockId,
|
if_false: Block,
|
||||||
if_false_args: &[Value],
|
if_false_args: &[Value],
|
||||||
) {
|
) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
|
@ -1083,8 +1081,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
fn emit_br_table(
|
fn emit_br_table(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: Value,
|
index: Value,
|
||||||
default_target: BlockId,
|
default_target: Block,
|
||||||
indexed_targets: &[BlockId],
|
indexed_targets: &[Block],
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
) {
|
) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
|
@ -1151,11 +1149,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
let inputs = op_inputs(
|
let inputs = op_inputs(
|
||||||
self.module,
|
self.module,
|
||||||
self.my_sig,
|
self.my_sig,
|
||||||
&self.body.locals[..],
|
&self.body.locals,
|
||||||
&self.op_stack[..],
|
&self.op_stack[..],
|
||||||
&op,
|
&op,
|
||||||
)?;
|
)?;
|
||||||
let outputs = op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)?;
|
let outputs = op_outputs(self.module, &self.body.locals, &self.op_stack[..], &op)?;
|
||||||
|
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"emit into block {:?}: op {:?} inputs {:?}",
|
"emit into block {:?}: op {:?} inputs {:?}",
|
||||||
|
|
196
src/ir.rs
196
src/ir.rs
|
@ -1,21 +1,22 @@
|
||||||
//! Intermediate representation for Wasm.
|
//! Intermediate representation for Wasm.
|
||||||
|
|
||||||
use crate::{backend, backend::binaryen};
|
use crate::entity;
|
||||||
|
use crate::entity::{EntityRef, EntityVec};
|
||||||
use crate::{frontend, Operator};
|
use crate::{frontend, Operator};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use fxhash::FxHashSet;
|
use fxhash::FxHashSet;
|
||||||
use wasmparser::{FuncType, Type};
|
use wasmparser::FuncType;
|
||||||
|
|
||||||
pub type SignatureId = usize;
|
pub use wasmparser::Type;
|
||||||
pub type FuncId = usize;
|
|
||||||
pub type BlockId = usize;
|
|
||||||
pub type InstId = usize;
|
|
||||||
pub type LocalId = u32;
|
|
||||||
pub type GlobalId = u32;
|
|
||||||
pub type TableId = u32;
|
|
||||||
pub type MemoryId = u32;
|
|
||||||
|
|
||||||
pub const INVALID_BLOCK: BlockId = usize::MAX;
|
entity!(Signature, "sig");
|
||||||
|
entity!(Func, "func");
|
||||||
|
entity!(Block, "block");
|
||||||
|
entity!(Local, "local");
|
||||||
|
entity!(Global, "global");
|
||||||
|
entity!(Table, "table");
|
||||||
|
entity!(Memory, "memory");
|
||||||
|
entity!(Value, "value");
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Module<'a> {
|
pub struct Module<'a> {
|
||||||
|
@ -25,7 +26,7 @@ pub struct Module<'a> {
|
||||||
globals: Vec<Type>,
|
globals: Vec<Type>,
|
||||||
tables: Vec<Type>,
|
tables: Vec<Type>,
|
||||||
|
|
||||||
dirty_funcs: FxHashSet<FuncId>,
|
dirty_funcs: FxHashSet<Func>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Module<'a> {
|
impl<'a> Module<'a> {
|
||||||
|
@ -37,21 +38,21 @@ impl<'a> Module<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Module<'a> {
|
impl<'a> Module<'a> {
|
||||||
pub fn func<'b>(&'b self, id: FuncId) -> &'b FuncDecl {
|
pub fn func<'b>(&'b self, id: Func) -> &'b FuncDecl {
|
||||||
&self.funcs[id]
|
&self.funcs[id.index()]
|
||||||
}
|
}
|
||||||
pub fn func_mut<'b>(&'b mut self, id: FuncId) -> &'b mut FuncDecl {
|
pub fn func_mut<'b>(&'b mut self, id: Func) -> &'b mut FuncDecl {
|
||||||
self.dirty_funcs.insert(id);
|
self.dirty_funcs.insert(id);
|
||||||
&mut self.funcs[id]
|
&mut self.funcs[id.index()]
|
||||||
}
|
}
|
||||||
pub fn signature<'b>(&'b self, id: SignatureId) -> &'b FuncType {
|
pub fn signature<'b>(&'b self, id: Signature) -> &'b FuncType {
|
||||||
&self.signatures[id]
|
&self.signatures[id.index()]
|
||||||
}
|
}
|
||||||
pub fn global_ty(&self, id: GlobalId) -> Type {
|
pub fn global_ty(&self, id: Global) -> Type {
|
||||||
self.globals[id as usize]
|
self.globals[id.index()]
|
||||||
}
|
}
|
||||||
pub fn table_ty(&self, id: TableId) -> Type {
|
pub fn table_ty(&self, id: Table) -> Type {
|
||||||
self.tables[id as usize]
|
self.tables[id.index()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn frontend_add_signature(&mut self, ty: FuncType) {
|
pub(crate) fn frontend_add_signature(&mut self, ty: FuncType) {
|
||||||
|
@ -70,12 +71,12 @@ impl<'a> Module<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum FuncDecl {
|
pub enum FuncDecl {
|
||||||
Import(SignatureId),
|
Import(Signature),
|
||||||
Body(SignatureId, FunctionBody),
|
Body(Signature, FunctionBody),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncDecl {
|
impl FuncDecl {
|
||||||
pub fn sig(&self) -> SignatureId {
|
pub fn sig(&self) -> Signature {
|
||||||
match self {
|
match self {
|
||||||
FuncDecl::Import(sig) => *sig,
|
FuncDecl::Import(sig) => *sig,
|
||||||
FuncDecl::Body(sig, ..) => *sig,
|
FuncDecl::Body(sig, ..) => *sig,
|
||||||
|
@ -105,23 +106,23 @@ pub struct FunctionBody {
|
||||||
/// Return types of the function.
|
/// Return types of the function.
|
||||||
pub rets: Vec<Type>,
|
pub rets: Vec<Type>,
|
||||||
/// Local types, *including* args.
|
/// Local types, *including* args.
|
||||||
pub locals: Vec<Type>,
|
pub locals: EntityVec<Local, Type>,
|
||||||
/// Block bodies, indexed by `BlockId`.
|
/// Entry block.
|
||||||
pub blocks: Vec<Block>,
|
pub entry: Block,
|
||||||
|
/// Block bodies.
|
||||||
|
pub blocks: EntityVec<Block, BlockDef>,
|
||||||
/// Value definitions, indexed by `Value`.
|
/// Value definitions, indexed by `Value`.
|
||||||
pub values: Vec<ValueDef>,
|
pub values: EntityVec<Value, ValueDef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionBody {
|
impl FunctionBody {
|
||||||
pub fn add_block(&mut self) -> BlockId {
|
pub fn add_block(&mut self) -> Block {
|
||||||
let id = self.blocks.len();
|
let id = self.blocks.push(BlockDef::default());
|
||||||
self.blocks.push(Block::default());
|
|
||||||
self.blocks[id].id = id;
|
|
||||||
log::trace!("add_block: block {}", id);
|
log::trace!("add_block: block {}", id);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_edge(&mut self, from: BlockId, to: BlockId) {
|
pub fn add_edge(&mut self, from: Block, to: Block) {
|
||||||
let succ_pos = self.blocks[from].succs.len();
|
let succ_pos = self.blocks[from].succs.len();
|
||||||
let pred_pos = self.blocks[to].preds.len();
|
let pred_pos = self.blocks[to].preds.len();
|
||||||
self.blocks[from].succs.push(to);
|
self.blocks[from].succs.push(to);
|
||||||
|
@ -133,10 +134,7 @@ impl FunctionBody {
|
||||||
|
|
||||||
pub fn add_value(&mut self, value: ValueDef) -> Value {
|
pub fn add_value(&mut self, value: ValueDef) -> Value {
|
||||||
log::trace!("add_value: def {:?}", value);
|
log::trace!("add_value: def {:?}", value);
|
||||||
let id = Value(self.values.len() as u32);
|
self.values.push(value)
|
||||||
log::trace!(" -> value {:?}", id);
|
|
||||||
self.values.push(value.clone());
|
|
||||||
id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_alias(&mut self, value: Value, to: Value) {
|
pub fn set_alias(&mut self, value: Value, to: Value) {
|
||||||
|
@ -147,13 +145,13 @@ impl FunctionBody {
|
||||||
if to == value {
|
if to == value {
|
||||||
panic!("Cannot create an alias cycle");
|
panic!("Cannot create an alias cycle");
|
||||||
}
|
}
|
||||||
self.values[value.index()] = ValueDef::Alias(to);
|
self.values[value] = ValueDef::Alias(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_alias(&self, value: Value) -> Value {
|
pub fn resolve_alias(&self, value: Value) -> Value {
|
||||||
let mut result = value;
|
let mut result = value;
|
||||||
loop {
|
loop {
|
||||||
if let &ValueDef::Alias(to) = &self.values[result.index()] {
|
if let &ValueDef::Alias(to) = &self.values[result] {
|
||||||
result = to;
|
result = to;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -168,7 +166,7 @@ impl FunctionBody {
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_blockparam(&mut self, block: BlockId, ty: Type) -> Value {
|
pub fn add_blockparam(&mut self, block: Block, ty: Type) -> Value {
|
||||||
let index = self.blocks[block].params.len();
|
let index = self.blocks[block].params.len();
|
||||||
let value = self.add_value(ValueDef::BlockParam(block, index, ty));
|
let value = self.add_value(ValueDef::BlockParam(block, index, ty));
|
||||||
self.blocks[block].params.push((ty, value));
|
self.blocks[block].params.push((ty, value));
|
||||||
|
@ -179,121 +177,65 @@ impl FunctionBody {
|
||||||
self.add_mutable_inst(ValueDef::Placeholder(ty))
|
self.add_mutable_inst(ValueDef::Placeholder(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_placeholder_with_blockparam(&mut self, block: BlockId, value: Value) {
|
pub fn replace_placeholder_with_blockparam(&mut self, block: Block, value: Value) {
|
||||||
let index = self.blocks[block].params.len();
|
let index = self.blocks[block].params.len();
|
||||||
let ty = match &self.values[value.index()] {
|
let ty = match &self.values[value] {
|
||||||
&ValueDef::Placeholder(ty) => ty,
|
&ValueDef::Placeholder(ty) => ty,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.blocks[block].params.push((ty, value));
|
self.blocks[block].params.push((ty, value));
|
||||||
self.values[value.index()] = ValueDef::BlockParam(block, index, ty);
|
self.values[value] = ValueDef::BlockParam(block, index, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_and_update_alias(&mut self, value: Value) -> Value {
|
pub fn resolve_and_update_alias(&mut self, value: Value) -> Value {
|
||||||
let to = self.resolve_alias(value);
|
let to = self.resolve_alias(value);
|
||||||
// Short-circuit the chain, union-find-style.
|
// Short-circuit the chain, union-find-style.
|
||||||
if let &ValueDef::Alias(orig_to) = &self.values[value.index()] {
|
if let &ValueDef::Alias(orig_to) = &self.values[value] {
|
||||||
if orig_to != to {
|
if orig_to != to {
|
||||||
self.values[value.index()] = ValueDef::Alias(to);
|
self.values[value] = ValueDef::Alias(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
to
|
to
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_to_block(&mut self, block: BlockId, value: Value) {
|
pub fn append_to_block(&mut self, block: Block, value: Value) {
|
||||||
self.blocks[block].insts.push(value);
|
self.blocks[block].insts.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_block(&mut self, block: BlockId, terminator: Terminator) {
|
pub fn end_block(&mut self, block: Block, terminator: Terminator) {
|
||||||
terminator.visit_successors(|succ| {
|
terminator.visit_successors(|succ| {
|
||||||
self.add_edge(block, succ);
|
self.add_edge(block, succ);
|
||||||
});
|
});
|
||||||
self.blocks[block].terminator = terminator;
|
self.blocks[block].terminator = terminator;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_local(&mut self, ty: Type) -> LocalId {
|
pub fn add_local(&mut self, ty: Type) -> Local {
|
||||||
let id = self.locals.len() as LocalId;
|
self.locals.push(ty)
|
||||||
self.locals.push(ty);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn values<'a>(&'a self) -> impl Iterator<Item = (Value, &'a ValueDef)> + 'a {
|
|
||||||
self.values
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, value_def)| (Value(idx as u32), value_def))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocks(&self) -> impl Iterator<Item = BlockId> {
|
|
||||||
(0..self.blocks.len()).into_iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Index<Value> for FunctionBody {
|
|
||||||
type Output = ValueDef;
|
|
||||||
fn index(&self, index: Value) -> &ValueDef {
|
|
||||||
&self.values[index.0 as usize]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::ops::IndexMut<Value> for FunctionBody {
|
|
||||||
fn index_mut(&mut self, index: Value) -> &mut ValueDef {
|
|
||||||
&mut self.values[index.0 as usize]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::ops::Index<BlockId> for FunctionBody {
|
|
||||||
type Output = Block;
|
|
||||||
fn index(&self, index: BlockId) -> &Block {
|
|
||||||
&self.blocks[index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::ops::IndexMut<BlockId> for FunctionBody {
|
|
||||||
fn index_mut(&mut self, index: BlockId) -> &mut Block {
|
|
||||||
&mut self.blocks[index]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Block {
|
pub struct BlockDef {
|
||||||
pub id: BlockId,
|
/// Instructions in this block.
|
||||||
/// Side-effecting values from the sea-of-nodes that are computed, in order.
|
|
||||||
pub insts: Vec<Value>,
|
pub insts: Vec<Value>,
|
||||||
/// Terminator: branch or return.
|
/// Terminator: branch or return.
|
||||||
pub terminator: Terminator,
|
pub terminator: Terminator,
|
||||||
/// Successor blocks.
|
/// Successor blocks.
|
||||||
pub succs: Vec<BlockId>,
|
pub succs: Vec<Block>,
|
||||||
/// For each successor block, our index in its `preds` array.
|
/// For each successor block, our index in its `preds` array.
|
||||||
pub pos_in_succ_pred: Vec<usize>,
|
pub pos_in_succ_pred: Vec<usize>,
|
||||||
/// Predecessor blocks.
|
/// Predecessor blocks.
|
||||||
pub preds: Vec<BlockId>,
|
pub preds: Vec<Block>,
|
||||||
/// For each predecessor block, our index in its `succs` array.
|
/// For each predecessor block, our index in its `succs` array.
|
||||||
pub pos_in_pred_succ: Vec<usize>,
|
pub pos_in_pred_succ: Vec<usize>,
|
||||||
/// Type and Value for each blockparam.
|
/// Type and Value for each blockparam.
|
||||||
pub params: Vec<(Type, Value)>,
|
pub params: Vec<(Type, Value)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct Value(u32);
|
|
||||||
|
|
||||||
impl std::fmt::Display for Value {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(f, "v{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
|
||||||
pub fn index(self) -> usize {
|
|
||||||
self.0 as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_index(value: usize) -> Value {
|
|
||||||
Self(value as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ValueDef {
|
pub enum ValueDef {
|
||||||
Arg(usize, Type),
|
Arg(usize, Type),
|
||||||
BlockParam(BlockId, usize, Type),
|
BlockParam(Block, usize, Type),
|
||||||
Operator(Operator, Vec<Value>, Vec<Type>),
|
Operator(Operator, Vec<Value>, Vec<Type>),
|
||||||
PickOutput(Value, usize, Type),
|
PickOutput(Value, usize, Type),
|
||||||
Alias(Value),
|
Alias(Value),
|
||||||
|
@ -334,7 +276,7 @@ impl ValueDef {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BlockTarget {
|
pub struct BlockTarget {
|
||||||
pub block: BlockId,
|
pub block: Block,
|
||||||
pub args: Vec<Value>,
|
pub args: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +418,7 @@ impl Terminator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visit_successors<F: FnMut(BlockId)>(&self, mut f: F) {
|
pub fn visit_successors<F: FnMut(Block)>(&self, mut f: F) {
|
||||||
self.visit_targets(|target| f(target.block));
|
self.visit_targets(|target| f(target.block));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,32 +465,6 @@ impl<'a> Module<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_wasm_bytes(&self) -> Result<Vec<u8>> {
|
pub fn to_wasm_bytes(&self) -> Result<Vec<u8>> {
|
||||||
let mut binaryen_module = binaryen::Module::read(self.orig_bytes)?;
|
todo!()
|
||||||
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 (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 (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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binaryen_module.write()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@ pub use wasmparser;
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
mod cfg;
|
mod cfg;
|
||||||
|
mod entity;
|
||||||
mod frontend;
|
mod frontend;
|
||||||
mod ir;
|
mod ir;
|
||||||
mod op_traits;
|
mod op_traits;
|
||||||
mod ops;
|
mod ops;
|
||||||
mod use_count;
|
|
||||||
|
|
||||||
pub use ir::*;
|
pub use ir::*;
|
||||||
pub use ops::Operator;
|
pub use ops::Operator;
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
//! Metadata on operators.
|
//! Metadata on operators.
|
||||||
|
|
||||||
use crate::ir::{Module, SignatureId, Value};
|
use crate::entity::EntityVec;
|
||||||
|
use crate::ir::{Global, Local, Module, Signature, Table, Value};
|
||||||
use crate::Operator;
|
use crate::Operator;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use wasmparser::Type;
|
use wasmparser::Type;
|
||||||
|
|
||||||
pub fn op_inputs(
|
pub fn op_inputs(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
my_sig: SignatureId,
|
my_sig: Signature,
|
||||||
my_locals: &[Type],
|
my_locals: &EntityVec<Local, Type>,
|
||||||
op_stack: &[(Type, Value)],
|
op_stack: &[(Type, Value)],
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
) -> Result<Vec<Type>> {
|
) -> Result<Vec<Type>> {
|
||||||
|
@ -19,15 +20,15 @@ pub fn op_inputs(
|
||||||
let sig = module.func(function_index).sig();
|
let sig = module.func(function_index).sig();
|
||||||
Ok(Vec::from(module.signature(sig).params.clone()))
|
Ok(Vec::from(module.signature(sig).params.clone()))
|
||||||
}
|
}
|
||||||
&Operator::CallIndirect { index, .. } => {
|
&Operator::CallIndirect { sig_index, .. } => {
|
||||||
let mut params = module.signature(index).params.to_vec();
|
let mut params = module.signature(sig_index).params.to_vec();
|
||||||
params.push(Type::I32);
|
params.push(Type::I32);
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
&Operator::Return => Ok(Vec::from(module.signature(my_sig).returns.clone())),
|
&Operator::Return => Ok(Vec::from(module.signature(my_sig).returns.clone())),
|
||||||
|
|
||||||
&Operator::LocalSet { local_index } | &Operator::LocalTee { local_index } => {
|
&Operator::LocalSet { local_index } | &Operator::LocalTee { local_index } => {
|
||||||
Ok(vec![my_locals[local_index as usize]])
|
Ok(vec![my_locals[local_index]])
|
||||||
}
|
}
|
||||||
&Operator::LocalGet { .. } => Ok(vec![]),
|
&Operator::LocalGet { .. } => Ok(vec![]),
|
||||||
|
|
||||||
|
@ -216,7 +217,7 @@ pub fn op_inputs(
|
||||||
Operator::I32ReinterpretF32 => Ok(vec![Type::F32]),
|
Operator::I32ReinterpretF32 => Ok(vec![Type::F32]),
|
||||||
Operator::I64ReinterpretF64 => Ok(vec![Type::F64]),
|
Operator::I64ReinterpretF64 => Ok(vec![Type::F64]),
|
||||||
Operator::TableGet { .. } => Ok(vec![Type::I32]),
|
Operator::TableGet { .. } => Ok(vec![Type::I32]),
|
||||||
Operator::TableSet { table } => Ok(vec![Type::I32, module.table_ty(*table)]),
|
Operator::TableSet { table_index } => Ok(vec![Type::I32, module.table_ty(*table_index)]),
|
||||||
Operator::TableGrow { .. } => Ok(vec![Type::I32]),
|
Operator::TableGrow { .. } => Ok(vec![Type::I32]),
|
||||||
Operator::TableSize { .. } => Ok(vec![]),
|
Operator::TableSize { .. } => Ok(vec![]),
|
||||||
Operator::MemorySize { .. } => Ok(vec![]),
|
Operator::MemorySize { .. } => Ok(vec![]),
|
||||||
|
@ -226,7 +227,7 @@ pub fn op_inputs(
|
||||||
|
|
||||||
pub fn op_outputs(
|
pub fn op_outputs(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
my_locals: &[Type],
|
my_locals: &EntityVec<Local, Type>,
|
||||||
op_stack: &[(Type, Value)],
|
op_stack: &[(Type, Value)],
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
) -> Result<Vec<Type>> {
|
) -> Result<Vec<Type>> {
|
||||||
|
@ -237,13 +238,13 @@ pub fn op_outputs(
|
||||||
let sig = module.func(function_index).sig();
|
let sig = module.func(function_index).sig();
|
||||||
Ok(Vec::from(module.signature(sig).returns.clone()))
|
Ok(Vec::from(module.signature(sig).returns.clone()))
|
||||||
}
|
}
|
||||||
&Operator::CallIndirect { index, .. } => {
|
&Operator::CallIndirect { sig_index, .. } => {
|
||||||
Ok(Vec::from(module.signature(index).returns.clone()))
|
Ok(Vec::from(module.signature(sig_index).returns.clone()))
|
||||||
}
|
}
|
||||||
&Operator::Return => Ok(vec![]),
|
&Operator::Return => Ok(vec![]),
|
||||||
&Operator::LocalSet { .. } => Ok(vec![]),
|
&Operator::LocalSet { .. } => Ok(vec![]),
|
||||||
&Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => {
|
&Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => {
|
||||||
Ok(vec![my_locals[local_index as usize]])
|
Ok(vec![my_locals[local_index]])
|
||||||
}
|
}
|
||||||
|
|
||||||
&Operator::Select => {
|
&Operator::Select => {
|
||||||
|
@ -425,7 +426,7 @@ pub fn op_outputs(
|
||||||
Operator::F64ReinterpretI64 => Ok(vec![Type::F64]),
|
Operator::F64ReinterpretI64 => Ok(vec![Type::F64]),
|
||||||
Operator::I32ReinterpretF32 => Ok(vec![Type::I32]),
|
Operator::I32ReinterpretF32 => Ok(vec![Type::I32]),
|
||||||
Operator::I64ReinterpretF64 => Ok(vec![Type::I64]),
|
Operator::I64ReinterpretF64 => Ok(vec![Type::I64]),
|
||||||
Operator::TableGet { table } => Ok(vec![module.table_ty(*table)]),
|
Operator::TableGet { table_index } => Ok(vec![module.table_ty(*table_index)]),
|
||||||
Operator::TableSet { .. } => Ok(vec![]),
|
Operator::TableSet { .. } => Ok(vec![]),
|
||||||
Operator::TableGrow { .. } => Ok(vec![]),
|
Operator::TableGrow { .. } => Ok(vec![]),
|
||||||
Operator::TableSize { .. } => Ok(vec![Type::I32]),
|
Operator::TableSize { .. } => Ok(vec![Type::I32]),
|
||||||
|
@ -439,12 +440,12 @@ pub enum SideEffect {
|
||||||
Trap,
|
Trap,
|
||||||
ReadMem,
|
ReadMem,
|
||||||
WriteMem,
|
WriteMem,
|
||||||
ReadGlobal(usize),
|
ReadGlobal(Global),
|
||||||
WriteGlobal(usize),
|
WriteGlobal(Global),
|
||||||
ReadTable(usize),
|
ReadTable(Table),
|
||||||
WriteTable(usize),
|
WriteTable(Table),
|
||||||
ReadLocal(usize),
|
ReadLocal(Local),
|
||||||
WriteLocal(usize),
|
WriteLocal(Local),
|
||||||
Return,
|
Return,
|
||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
@ -459,17 +460,16 @@ pub fn op_effects(op: &Operator) -> Result<Vec<SideEffect>> {
|
||||||
&Operator::Call { .. } => Ok(vec![All]),
|
&Operator::Call { .. } => Ok(vec![All]),
|
||||||
&Operator::CallIndirect { .. } => Ok(vec![All]),
|
&Operator::CallIndirect { .. } => Ok(vec![All]),
|
||||||
&Operator::Return => Ok(vec![Return]),
|
&Operator::Return => Ok(vec![Return]),
|
||||||
&Operator::LocalSet { local_index, .. } => Ok(vec![WriteLocal(local_index as usize)]),
|
&Operator::LocalSet { local_index, .. } => Ok(vec![WriteLocal(local_index)]),
|
||||||
&Operator::LocalGet { local_index, .. } => Ok(vec![ReadLocal(local_index as usize)]),
|
&Operator::LocalGet { local_index, .. } => Ok(vec![ReadLocal(local_index)]),
|
||||||
&Operator::LocalTee { local_index, .. } => Ok(vec![
|
&Operator::LocalTee { local_index, .. } => {
|
||||||
ReadLocal(local_index as usize),
|
Ok(vec![ReadLocal(local_index), WriteLocal(local_index)])
|
||||||
WriteLocal(local_index as usize),
|
}
|
||||||
]),
|
|
||||||
|
|
||||||
&Operator::Select => Ok(vec![]),
|
&Operator::Select => Ok(vec![]),
|
||||||
&Operator::TypedSelect { .. } => Ok(vec![]),
|
&Operator::TypedSelect { .. } => Ok(vec![]),
|
||||||
&Operator::GlobalGet { global_index, .. } => Ok(vec![ReadGlobal(global_index as usize)]),
|
&Operator::GlobalGet { global_index, .. } => Ok(vec![ReadGlobal(global_index)]),
|
||||||
&Operator::GlobalSet { global_index, .. } => Ok(vec![WriteGlobal(global_index as usize)]),
|
&Operator::GlobalSet { global_index, .. } => Ok(vec![WriteGlobal(global_index)]),
|
||||||
|
|
||||||
Operator::I32Load { .. }
|
Operator::I32Load { .. }
|
||||||
| Operator::I32Load8S { .. }
|
| Operator::I32Load8S { .. }
|
||||||
|
@ -642,10 +642,10 @@ pub fn op_effects(op: &Operator) -> Result<Vec<SideEffect>> {
|
||||||
Operator::F64ReinterpretI64 => Ok(vec![]),
|
Operator::F64ReinterpretI64 => Ok(vec![]),
|
||||||
Operator::I32ReinterpretF32 => Ok(vec![]),
|
Operator::I32ReinterpretF32 => Ok(vec![]),
|
||||||
Operator::I64ReinterpretF64 => Ok(vec![]),
|
Operator::I64ReinterpretF64 => Ok(vec![]),
|
||||||
Operator::TableGet { table, .. } => Ok(vec![ReadTable(*table as usize), Trap]),
|
Operator::TableGet { table_index, .. } => Ok(vec![ReadTable(*table_index), Trap]),
|
||||||
Operator::TableSet { table, .. } => Ok(vec![WriteTable(*table as usize), Trap]),
|
Operator::TableSet { table_index, .. } => Ok(vec![WriteTable(*table_index), Trap]),
|
||||||
Operator::TableGrow { table, .. } => Ok(vec![WriteTable(*table as usize), Trap]),
|
Operator::TableGrow { table_index, .. } => Ok(vec![WriteTable(*table_index), Trap]),
|
||||||
Operator::TableSize { table, .. } => Ok(vec![ReadTable(*table as usize)]),
|
Operator::TableSize { table_index, .. } => Ok(vec![ReadTable(*table_index)]),
|
||||||
Operator::MemorySize { .. } => Ok(vec![ReadMem]),
|
Operator::MemorySize { .. } => Ok(vec![ReadMem]),
|
||||||
Operator::MemoryGrow { .. } => Ok(vec![WriteMem, Trap]),
|
Operator::MemoryGrow { .. } => Ok(vec![WriteMem, Trap]),
|
||||||
}
|
}
|
||||||
|
|
247
src/ops.rs
247
src/ops.rs
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
use wasmparser::{Ieee32, Ieee64, MemoryImmediate, Type};
|
use wasmparser::{Ieee32, Ieee64, MemoryImmediate, Type};
|
||||||
|
|
||||||
use crate::{FuncId, GlobalId, LocalId, MemoryId, TableId};
|
use crate::{Func, Global, Local, Memory, Signature, Table};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Memory {
|
pub struct MemoryArg {
|
||||||
pub align: u8,
|
pub align: u8,
|
||||||
pub offset: u64,
|
pub offset: u64,
|
||||||
pub memory: MemoryId,
|
pub memory: Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
@ -16,46 +16,117 @@ pub enum Operator {
|
||||||
Unreachable,
|
Unreachable,
|
||||||
Nop,
|
Nop,
|
||||||
|
|
||||||
Call { function_index: FuncId },
|
Call {
|
||||||
CallIndirect { index: FuncId, table_index: TableId },
|
function_index: Func,
|
||||||
|
},
|
||||||
|
CallIndirect {
|
||||||
|
sig_index: Signature,
|
||||||
|
table_index: Table,
|
||||||
|
},
|
||||||
Return,
|
Return,
|
||||||
LocalSet { local_index: LocalId },
|
LocalSet {
|
||||||
LocalTee { local_index: LocalId },
|
local_index: Local,
|
||||||
LocalGet { local_index: LocalId },
|
},
|
||||||
|
LocalTee {
|
||||||
|
local_index: Local,
|
||||||
|
},
|
||||||
|
LocalGet {
|
||||||
|
local_index: Local,
|
||||||
|
},
|
||||||
Select,
|
Select,
|
||||||
TypedSelect { ty: Type },
|
TypedSelect {
|
||||||
GlobalGet { global_index: GlobalId },
|
ty: Type,
|
||||||
GlobalSet { global_index: GlobalId },
|
},
|
||||||
|
GlobalGet {
|
||||||
|
global_index: Global,
|
||||||
|
},
|
||||||
|
GlobalSet {
|
||||||
|
global_index: Global,
|
||||||
|
},
|
||||||
|
|
||||||
I32Load { memory: Memory },
|
I32Load {
|
||||||
I64Load { memory: Memory },
|
memory: MemoryArg,
|
||||||
F32Load { memory: Memory },
|
},
|
||||||
F64Load { memory: Memory },
|
I64Load {
|
||||||
I32Load8S { memory: Memory },
|
memory: MemoryArg,
|
||||||
I32Load8U { memory: Memory },
|
},
|
||||||
I32Load16S { memory: Memory },
|
F32Load {
|
||||||
I32Load16U { memory: Memory },
|
memory: MemoryArg,
|
||||||
I64Load8S { memory: Memory },
|
},
|
||||||
I64Load8U { memory: Memory },
|
F64Load {
|
||||||
I64Load16S { memory: Memory },
|
memory: MemoryArg,
|
||||||
I64Load16U { memory: Memory },
|
},
|
||||||
I64Load32S { memory: Memory },
|
I32Load8S {
|
||||||
I64Load32U { memory: Memory },
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I32Load8U {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I32Load16S {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I32Load16U {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Load8S {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Load8U {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Load16S {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Load16U {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Load32S {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Load32U {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
|
||||||
I32Store { memory: Memory },
|
I32Store {
|
||||||
I64Store { memory: Memory },
|
memory: MemoryArg,
|
||||||
F32Store { memory: Memory },
|
},
|
||||||
F64Store { memory: Memory },
|
I64Store {
|
||||||
I32Store8 { memory: Memory },
|
memory: MemoryArg,
|
||||||
I32Store16 { memory: Memory },
|
},
|
||||||
I64Store8 { memory: Memory },
|
F32Store {
|
||||||
I64Store16 { memory: Memory },
|
memory: MemoryArg,
|
||||||
I64Store32 { memory: Memory },
|
},
|
||||||
|
F64Store {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I32Store8 {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I32Store16 {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Store8 {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Store16 {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
I64Store32 {
|
||||||
|
memory: MemoryArg,
|
||||||
|
},
|
||||||
|
|
||||||
I32Const { value: i32 },
|
I32Const {
|
||||||
I64Const { value: i64 },
|
value: i32,
|
||||||
F32Const { value: Ieee32 },
|
},
|
||||||
F64Const { value: Ieee64 },
|
I64Const {
|
||||||
|
value: i64,
|
||||||
|
},
|
||||||
|
F32Const {
|
||||||
|
value: Ieee32,
|
||||||
|
},
|
||||||
|
F64Const {
|
||||||
|
value: Ieee64,
|
||||||
|
},
|
||||||
|
|
||||||
I32Eqz,
|
I32Eqz,
|
||||||
I32Eq,
|
I32Eq,
|
||||||
|
@ -206,12 +277,24 @@ pub enum Operator {
|
||||||
F64ReinterpretI64,
|
F64ReinterpretI64,
|
||||||
I32ReinterpretF32,
|
I32ReinterpretF32,
|
||||||
I64ReinterpretF64,
|
I64ReinterpretF64,
|
||||||
TableGet { table: TableId },
|
TableGet {
|
||||||
TableSet { table: TableId },
|
table_index: Table,
|
||||||
TableGrow { table: TableId },
|
},
|
||||||
TableSize { table: TableId },
|
TableSet {
|
||||||
MemorySize { mem: MemoryId },
|
table_index: Table,
|
||||||
MemoryGrow { mem: MemoryId },
|
},
|
||||||
|
TableGrow {
|
||||||
|
table_index: Table,
|
||||||
|
},
|
||||||
|
TableSize {
|
||||||
|
table_index: Table,
|
||||||
|
},
|
||||||
|
MemorySize {
|
||||||
|
mem: Memory,
|
||||||
|
},
|
||||||
|
MemoryGrow {
|
||||||
|
mem: Memory,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||||
|
@ -222,32 +305,32 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||||
&wasmparser::Operator::Unreachable => Ok(Operator::Unreachable),
|
&wasmparser::Operator::Unreachable => Ok(Operator::Unreachable),
|
||||||
&wasmparser::Operator::Nop => Ok(Operator::Nop),
|
&wasmparser::Operator::Nop => Ok(Operator::Nop),
|
||||||
&wasmparser::Operator::Call { function_index } => Ok(Operator::Call {
|
&wasmparser::Operator::Call { function_index } => Ok(Operator::Call {
|
||||||
function_index: function_index as usize,
|
function_index: Func::from(function_index),
|
||||||
|
}),
|
||||||
|
&wasmparser::Operator::CallIndirect {
|
||||||
|
index, table_index, ..
|
||||||
|
} => Ok(Operator::CallIndirect {
|
||||||
|
sig_index: Signature::from(index),
|
||||||
|
table_index: Table::from(table_index),
|
||||||
}),
|
}),
|
||||||
&wasmparser::Operator::CallIndirect { index, table_index } => {
|
|
||||||
Ok(Operator::CallIndirect {
|
|
||||||
index: index as usize,
|
|
||||||
table_index,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
&wasmparser::Operator::Return => Ok(Operator::Return),
|
&wasmparser::Operator::Return => Ok(Operator::Return),
|
||||||
&wasmparser::Operator::LocalSet { local_index } => {
|
&wasmparser::Operator::LocalSet { local_index } => Ok(Operator::LocalSet {
|
||||||
Ok(Operator::LocalSet { local_index })
|
local_index: Local::from(local_index),
|
||||||
}
|
}),
|
||||||
&wasmparser::Operator::LocalTee { local_index } => {
|
&wasmparser::Operator::LocalTee { local_index } => Ok(Operator::LocalTee {
|
||||||
Ok(Operator::LocalTee { local_index })
|
local_index: Local::from(local_index),
|
||||||
}
|
}),
|
||||||
&wasmparser::Operator::LocalGet { local_index } => {
|
&wasmparser::Operator::LocalGet { local_index } => Ok(Operator::LocalGet {
|
||||||
Ok(Operator::LocalGet { local_index })
|
local_index: Local::from(local_index),
|
||||||
}
|
}),
|
||||||
&wasmparser::Operator::Select => Ok(Operator::Select),
|
&wasmparser::Operator::Select => Ok(Operator::Select),
|
||||||
&wasmparser::Operator::TypedSelect { ty } => Ok(Operator::TypedSelect { ty }),
|
&wasmparser::Operator::TypedSelect { ty } => Ok(Operator::TypedSelect { ty }),
|
||||||
&wasmparser::Operator::GlobalGet { global_index } => {
|
&wasmparser::Operator::GlobalGet { global_index } => Ok(Operator::GlobalGet {
|
||||||
Ok(Operator::GlobalGet { global_index })
|
global_index: Global::from(global_index),
|
||||||
}
|
}),
|
||||||
&wasmparser::Operator::GlobalSet { global_index } => {
|
&wasmparser::Operator::GlobalSet { global_index } => Ok(Operator::GlobalSet {
|
||||||
Ok(Operator::GlobalSet { global_index })
|
global_index: Global::from(global_index),
|
||||||
}
|
}),
|
||||||
&wasmparser::Operator::I32Load { memarg } => Ok(Operator::I32Load {
|
&wasmparser::Operator::I32Load { memarg } => Ok(Operator::I32Load {
|
||||||
memory: memarg.into(),
|
memory: memarg.into(),
|
||||||
}),
|
}),
|
||||||
|
@ -457,23 +540,35 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||||
&wasmparser::Operator::F64ReinterpretI64 => Ok(Operator::F64ReinterpretI64),
|
&wasmparser::Operator::F64ReinterpretI64 => Ok(Operator::F64ReinterpretI64),
|
||||||
&wasmparser::Operator::I32ReinterpretF32 => Ok(Operator::I32ReinterpretF32),
|
&wasmparser::Operator::I32ReinterpretF32 => Ok(Operator::I32ReinterpretF32),
|
||||||
&wasmparser::Operator::I64ReinterpretF64 => Ok(Operator::I64ReinterpretF64),
|
&wasmparser::Operator::I64ReinterpretF64 => Ok(Operator::I64ReinterpretF64),
|
||||||
&wasmparser::Operator::TableGet { table } => Ok(Operator::TableGet { table }),
|
&wasmparser::Operator::TableGet { table } => Ok(Operator::TableGet {
|
||||||
&wasmparser::Operator::TableSet { table } => Ok(Operator::TableSet { table }),
|
table_index: Table::from(table),
|
||||||
&wasmparser::Operator::TableGrow { table } => Ok(Operator::TableGrow { table }),
|
}),
|
||||||
&wasmparser::Operator::TableSize { table } => Ok(Operator::TableSize { table }),
|
&wasmparser::Operator::TableSet { table } => Ok(Operator::TableSet {
|
||||||
&wasmparser::Operator::MemorySize { mem, .. } => Ok(Operator::MemorySize { mem }),
|
table_index: Table::from(table),
|
||||||
&wasmparser::Operator::MemoryGrow { mem, .. } => Ok(Operator::MemoryGrow { mem }),
|
}),
|
||||||
|
&wasmparser::Operator::TableGrow { table } => Ok(Operator::TableGrow {
|
||||||
|
table_index: Table::from(table),
|
||||||
|
}),
|
||||||
|
&wasmparser::Operator::TableSize { table } => Ok(Operator::TableSize {
|
||||||
|
table_index: Table::from(table),
|
||||||
|
}),
|
||||||
|
&wasmparser::Operator::MemorySize { mem, .. } => Ok(Operator::MemorySize {
|
||||||
|
mem: Memory::from(mem),
|
||||||
|
}),
|
||||||
|
&wasmparser::Operator::MemoryGrow { mem, .. } => Ok(Operator::MemoryGrow {
|
||||||
|
mem: Memory::from(mem),
|
||||||
|
}),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<MemoryImmediate> for Memory {
|
impl std::convert::From<MemoryImmediate> for MemoryArg {
|
||||||
fn from(value: MemoryImmediate) -> Memory {
|
fn from(value: MemoryImmediate) -> MemoryArg {
|
||||||
Memory {
|
MemoryArg {
|
||||||
align: value.align,
|
align: value.align,
|
||||||
offset: value.offset,
|
offset: value.offset,
|
||||||
memory: value.memory as MemoryId,
|
memory: Memory::from(value.memory),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
//! Use-count analysis.
|
|
||||||
|
|
||||||
use crate::{FunctionBody, Value, ValueDef};
|
|
||||||
use fxhash::FxHashSet;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct UseCountAnalysis {
|
|
||||||
pub(crate) toplevel: FxHashSet<Value>,
|
|
||||||
pub(crate) use_count: Vec</* Value, */ usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UseCountAnalysis {
|
|
||||||
pub(crate) fn compute(f: &FunctionBody) -> UseCountAnalysis {
|
|
||||||
let n_values = f.values.len();
|
|
||||||
let mut counts = UseCountAnalysis {
|
|
||||||
use_count: vec![0; n_values],
|
|
||||||
toplevel: FxHashSet::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut workqueue = VecDeque::new();
|
|
||||||
let mut workqueue_set = FxHashSet::default();
|
|
||||||
for block in 0..f.blocks.len() {
|
|
||||||
for &value in &f.blocks[block].insts {
|
|
||||||
let value = f.resolve_alias(value);
|
|
||||||
counts.add(value);
|
|
||||||
if workqueue_set.insert(value) {
|
|
||||||
workqueue.push_back(value);
|
|
||||||
}
|
|
||||||
counts.toplevel.insert(value);
|
|
||||||
}
|
|
||||||
f.blocks[block].terminator.visit_uses(|value| {
|
|
||||||
let value = f.resolve_alias(value);
|
|
||||||
counts.add(value);
|
|
||||||
if workqueue_set.insert(value) {
|
|
||||||
workqueue.push_back(value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
while let Some(value) = workqueue.pop_front() {
|
|
||||||
workqueue_set.remove(&value);
|
|
||||||
match &f.values[value.index()] {
|
|
||||||
&ValueDef::Alias(..) | &ValueDef::Arg(..) | &ValueDef::BlockParam(..) => {}
|
|
||||||
&ValueDef::Operator(_op, ref args, _) => {
|
|
||||||
for &arg in args {
|
|
||||||
let arg = f.resolve_alias(arg);
|
|
||||||
counts.add(arg);
|
|
||||||
if counts.use_count[arg.index()] == 1 {
|
|
||||||
if workqueue_set.insert(arg) {
|
|
||||||
workqueue.push_back(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&ValueDef::PickOutput(value, _, _) => {
|
|
||||||
let value = f.resolve_alias(value);
|
|
||||||
counts.add(value);
|
|
||||||
if counts.use_count[value.index()] == 1 {
|
|
||||||
if workqueue_set.insert(value) {
|
|
||||||
workqueue.push_back(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&ValueDef::Placeholder(_) => {
|
|
||||||
panic!("Unresolved placeholder for value {}", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
counts
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add(&mut self, value: Value) {
|
|
||||||
self.use_count[value.index()] += 1;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue