big refactor

This commit is contained in:
Chris Fallin 2022-11-01 20:43:47 -07:00
parent 1da150823d
commit a538d10167
11 changed files with 561 additions and 504 deletions

View file

@ -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,
); );
} }
*/

View file

@ -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];

View file

@ -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)
} }
} }

View file

@ -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
View 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()]
}
}

View file

@ -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
View file

@ -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()
} }
} }

View file

@ -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;

View file

@ -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]),
} }

View file

@ -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),
} }
} }
} }

View file

@ -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;
}
}