From a538d101675b0adf1195bffe3c1efc67705d0ddf Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Tue, 1 Nov 2022 20:43:47 -0700 Subject: [PATCH] big refactor --- src/backend/lower.rs | 76 +++++-------- src/cfg/domtree.rs | 47 ++++---- src/cfg/mod.rs | 61 ++++++----- src/cfg/postorder.rs | 17 ++- src/entity.rs | 152 ++++++++++++++++++++++++++ src/frontend.rs | 130 +++++++++++------------ src/ir.rs | 196 ++++++++++------------------------ src/lib.rs | 2 +- src/op_traits.rs | 60 +++++------ src/ops.rs | 247 ++++++++++++++++++++++++++++++------------- src/use_count.rs | 77 -------------- 11 files changed, 561 insertions(+), 504 deletions(-) create mode 100644 src/entity.rs delete mode 100644 src/use_count.rs diff --git a/src/backend/lower.rs b/src/backend/lower.rs index 8025146..309b75b 100644 --- a/src/backend/lower.rs +++ b/src/backend/lower.rs @@ -1,4 +1,6 @@ +/* use crate::backend::binaryen; +use crate::entity::EntityRef; use crate::ir::*; use crate::Operator; use fxhash::FxHashMap; @@ -14,9 +16,9 @@ pub(crate) fn generate_body( let mut ctx = ElabCtx::new(body, into_mod); // For each block, generate an expr. - let mut block_exprs: FxHashMap = FxHashMap::default(); - for block in body.blocks() { - let exprs = body[block] + let mut block_exprs: FxHashMap = FxHashMap::default(); + for (block_id, block) in body.blocks.entries() { + let exprs = block .insts .iter() .flat_map(|&inst| { @@ -24,61 +26,32 @@ pub(crate) fn generate_body( ctx.elaborate_value(into_mod, inst) }) .collect::>(); - 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 // relooper/stackifier support built into Binaryen. let mut relooper = binaryen::Relooper::new(into_mod); let mut entry = None; - let mut relooper_blocks: FxHashMap = FxHashMap::default(); + let mut relooper_blocks: FxHashMap = FxHashMap::default(); for (block_id, block_expr) in block_exprs {} 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) } #[derive(Clone, Debug)] struct ElabCtx<'a> { body: &'a FunctionBody, - op_result_locals: FxHashMap<(Value, usize), LocalId>, - block_param_locals: FxHashMap<(BlockId, usize), LocalId>, + op_result_locals: FxHashMap<(Value, usize), Local>, + block_param_locals: FxHashMap<(Block, usize), Local>, new_locals: Vec, } impl<'a> ElabCtx<'a> { fn new(body: &'a FunctionBody, into_mod: &mut binaryen::Module) -> ElabCtx<'a> { - // Create locals for each blockparam. - 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 + todo!() } fn elaborate_value( @@ -86,9 +59,10 @@ impl<'a> ElabCtx<'a> { into_mod: &binaryen::Module, value: Value, ) -> Option { + /* let value = self.body.resolve_alias(value); - match &self.body[value] { + match &self.body.values[value] { &ValueDef::Operator(op, ref args, ref tys) => { // Get expressions for each arg. let args = args.iter().map(|&arg| self.get_val_local(arg)); @@ -113,11 +87,13 @@ impl<'a> ElabCtx<'a> { } _ => None, } + */ + todo!() } - fn get_val_local(&self, value: Value) -> LocalId { - match &self.body[value] { - &ValueDef::Arg(idx, _) => idx as LocalId, + fn get_val_local(&self, value: Value) -> Local { + match &self.body.values[value] { + &ValueDef::Arg(idx, _) => Local::new(idx), &ValueDef::BlockParam(block, idx, _) => { self.block_param_locals.get(&(block, idx)).copied().unwrap() } @@ -130,8 +106,8 @@ impl<'a> ElabCtx<'a> { } } - fn new_local(&mut self, ty: Type) -> LocalId { - let index = (self.body.locals.len() + self.new_locals.len()) as LocalId; + fn new_local(&mut self, ty: Type) -> Local { + let index = Local::new(self.body.locals.len() + self.new_locals.len()); self.new_locals.push(ty); index } @@ -145,19 +121,18 @@ impl<'a> ElabCtx<'a> { todo!() } - fn local_ty(&self, local: LocalId) -> Type { - let index = local as usize; + fn local_ty(&self, local: Local) -> Type { self.body .locals - .get(index) + .get(local) .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( module: &Module, - sig: SignatureId, + sig: Signature, body: &FunctionBody, into_mod: &mut binaryen::Module, body_expr: binaryen::Expression, @@ -170,10 +145,11 @@ pub(crate) fn create_new_func( sig.params.iter().copied(), sig.returns.iter().copied(), body.locals - .iter() + .values() .copied() .skip(body.n_params) .chain(new_locals.into_iter()), body_expr, ); } +*/ diff --git a/src/cfg/domtree.rs b/src/cfg/domtree.rs index 8736973..8d38dd1 100644 --- a/src/cfg/domtree.rs +++ b/src/cfg/domtree.rs @@ -12,18 +12,19 @@ // TR-06-33870 // 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 fn merge_sets( - idom: &[BlockId], // map from BlockId to BlockId - block_to_rpo: &[Option], - mut node1: BlockId, - mut node2: BlockId, -) -> BlockId { + idom: &PerEntity, // map from Block to Block + block_to_rpo: &PerEntity>, + mut node1: Block, + mut node2: Block, +) -> Block { while node1 != node2 { - if node1 == INVALID_BLOCK || node2 == INVALID_BLOCK { - return INVALID_BLOCK; + if node1.is_invalid() || node2.is_invalid() { + return Block::invalid(); } let rpo1 = block_to_rpo[node1].unwrap(); let rpo2 = block_to_rpo[node2].unwrap(); @@ -37,22 +38,20 @@ fn merge_sets( node1 } -pub fn calculate<'a, PredFn: Fn(BlockId) -> &'a [BlockId]>( - num_blocks: usize, +pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>( preds: PredFn, - post_ord: &[BlockId], - start: BlockId, -) -> Vec { + post_ord: &[Block], + start: Block, +) -> PerEntity { // We have post_ord, which is the postorder sequence. // Compute maps from RPO to block number and vice-versa. - let mut block_to_rpo = vec![None; num_blocks]; - block_to_rpo.resize(num_blocks, None); + let mut block_to_rpo: PerEntity> = PerEntity::default(); for (i, rpo_block) in post_ord.iter().rev().enumerate() { block_to_rpo[*rpo_block] = Some(i as u32); } - let mut idom = vec![INVALID_BLOCK; num_blocks]; + let mut idom: PerEntity = PerEntity::default(); // The start node must have itself as a parent. idom[start] = start; @@ -64,7 +63,7 @@ pub fn calculate<'a, PredFn: Fn(BlockId) -> &'a [BlockId]>( for &node in post_ord.iter().rev() { let rponum = block_to_rpo[node].unwrap(); - let mut parent = INVALID_BLOCK; + let mut parent = Block::invalid(); for &pred in preds(node).iter() { let pred_rpo = match block_to_rpo[pred] { 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() { if pred == parent { continue; } - if idom[pred] == INVALID_BLOCK { + if idom[pred] == Block::invalid() { 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; 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"; // this allows the loop in `dominates` to terminate. - idom[start] = INVALID_BLOCK; + idom[start] = Block::invalid(); idom } -pub fn dominates(idom: &[BlockId], a: BlockId, mut b: BlockId) -> bool { +pub fn dominates(idom: &PerEntity, a: Block, mut b: Block) -> bool { loop { if a == b { return true; } - if b == INVALID_BLOCK { + if b.is_invalid() { return false; } b = idom[b]; diff --git a/src/cfg/mod.rs b/src/cfg/mod.rs index 0c3d7b2..59c9aa0 100644 --- a/src/cfg/mod.rs +++ b/src/cfg/mod.rs @@ -3,7 +3,8 @@ // Borrowed from regalloc2's cfg.rs, which is also Apache-2.0 with // LLVM exception. -use crate::ir::{BlockId, FunctionBody, Terminator}; +use crate::entity::PerEntity; +use crate::ir::{Block, FunctionBody, Terminator}; use smallvec::SmallVec; pub mod domtree; @@ -11,53 +12,55 @@ pub mod postorder; #[derive(Clone, Debug)] pub struct CFGInfo { + /// Entry block. + pub entry: Block, /// Predecessors for each block. - pub block_preds: Vec>, + pub block_preds: PerEntity>, /// Successors for each block. - pub block_succs: Vec>, + pub block_succs: PerEntity>, /// Blocks that end in return. - pub return_blocks: Vec, + pub return_blocks: Vec, /// Postorder traversal of blocks. - pub postorder: Vec, + pub postorder: Vec, /// Position of each block in postorder, if reachable. - pub postorder_pos: Vec>, + pub postorder_pos: PerEntity>, /// Domtree parents, indexed by block. - pub domtree: Vec, + pub domtree: PerEntity, } impl CFGInfo { pub fn new(f: &FunctionBody) -> CFGInfo { - let mut block_preds = vec![SmallVec::new(); f.blocks.len()]; - let mut block_succs = vec![SmallVec::new(); f.blocks.len()]; - for block in 0..f.blocks.len() { - f.blocks[block].terminator.visit_successors(|succ| { + let mut block_preds: PerEntity> = PerEntity::default(); + let mut block_succs: PerEntity> = PerEntity::default(); + for (block, block_def) in f.blocks.entries() { + block_def.terminator.visit_successors(|succ| { block_preds[succ].push(block); block_succs[block].push(succ); }); } let mut return_blocks = vec![]; - for block in 0..f.blocks.len() { - if let Terminator::Return { .. } = &f.blocks[block].terminator { - return_blocks.push(block); + for (block_id, block) in f.blocks.entries() { + if let Terminator::Return { .. } = &block.terminator { + 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() { postorder_pos[*block] = Some(i); } let domtree = domtree::calculate( - f.blocks.len(), |block| &&block_preds[block], &postorder[..], - 0, + f.entry, ); CFGInfo { + entry: f.entry, block_preds, block_succs, return_blocks, @@ -67,37 +70,33 @@ impl CFGInfo { } } - pub fn len(&self) -> usize { - self.block_succs.len() + pub fn dominates(&self, a: Block, b: Block) -> bool { + domtree::dominates(&self.domtree, a, b) } - pub fn dominates(&self, a: BlockId, b: BlockId) -> bool { - domtree::dominates(&self.domtree[..], a, b) - } - - pub fn succs(&self, block: BlockId) -> &[BlockId] { + pub fn succs(&self, block: Block) -> &[Block] { &self.block_succs[block] } - pub fn preds(&self, block: BlockId) -> &[BlockId] { + pub fn preds(&self, block: Block) -> &[Block] { &self.block_preds[block] } - pub fn pred_count_with_entry(&self, block: BlockId) -> usize { - let is_entry = block == 0; + pub fn pred_count_with_entry(&self, block: Block) -> usize { + let is_entry = block == self.entry; 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(); self.succs(block).len() + if is_return { 1 } else { 0 } } - pub fn rpo(&self) -> Vec { + pub fn rpo(&self) -> Vec { self.postorder.iter().cloned().rev().collect() } - pub fn rpo_pos(&self, block: BlockId) -> Option { + pub fn rpo_pos(&self, block: Block) -> Option { self.postorder_pos[block].map(|fwd_pos| self.postorder.len() - 1 - fwd_pos) } } diff --git a/src/cfg/postorder.rs b/src/cfg/postorder.rs index 755aea6..0256cbf 100644 --- a/src/cfg/postorder.rs +++ b/src/cfg/postorder.rs @@ -3,24 +3,23 @@ // Borrowed from regalloc2's postorder.rs, which is also Apache-2.0 // with LLVM-exception. -use crate::ir::BlockId; +use crate::entity::PerEntity; +use crate::ir::Block; use smallvec::{smallvec, SmallVec}; -pub fn calculate<'a, SuccFn: Fn(BlockId) -> &'a [BlockId]>( - num_blocks: usize, - entry: BlockId, +pub fn calculate<'a, SuccFn: Fn(Block) -> &'a [Block]>( + entry: Block, succ_blocks: SuccFn, -) -> Vec { +) -> Vec { let mut ret = vec![]; // State: visited-block map, and explicit DFS stack. - let mut visited = vec![]; - visited.resize(num_blocks, false); + let mut visited: PerEntity = PerEntity::default(); #[derive(Debug)] struct State<'a> { - block: BlockId, - succs: &'a [BlockId], + block: Block, + succs: &'a [Block], next_succ: usize, } let mut stack: SmallVec<[State; 64]> = smallvec![]; diff --git a/src/entity.rs b/src/entity.rs new file mode 100644 index 0000000..aceadac --- /dev/null +++ b/src/entity.rs @@ -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 for $name { + fn from(val: u32) -> Self { + ::new(val as usize) + } + } + + impl std::default::Default for $name { + fn default() -> Self { + ::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(Vec, PhantomData); + +impl std::default::Default for EntityVec { + fn default() -> Self { + Self(vec![], PhantomData) + } +} + +impl EntityVec { + 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 { + (0..self.0.len()).map(|index| Idx::new(index)) + } + + pub fn values(&self) -> impl Iterator { + self.0.iter() + } + + pub fn values_mut(&mut self) -> impl Iterator { + self.0.iter_mut() + } + + pub fn entries(&self) -> impl Iterator { + self.0 + .iter() + .enumerate() + .map(|(index, t)| (Idx::new(index), t)) + } + + pub fn entries_mut(&mut self) -> impl Iterator { + 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 Index for EntityVec { + type Output = T; + fn index(&self, idx: Idx) -> &T { + &self.0[idx.index()] + } +} + +impl IndexMut for EntityVec { + fn index_mut(&mut self, idx: Idx) -> &mut T { + &mut self.0[idx.index()] + } +} + +#[derive(Clone, Debug, Default)] +pub struct PerEntity(Vec, PhantomData, T); + +impl Index for PerEntity { + type Output = T; + fn index(&self, idx: Idx) -> &T { + self.0.get(idx.index()).unwrap_or(&self.2) + } +} + +impl IndexMut for PerEntity { + 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()] + } +} diff --git a/src/frontend.rs b/src/frontend.rs index 6612116..4a6d18d 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -2,14 +2,14 @@ #![allow(dead_code)] -use std::convert::TryFrom; - +use crate::entity::EntityRef; use crate::ir::*; use crate::op_traits::{op_inputs, op_outputs}; use crate::ops::Operator; use anyhow::{bail, Result}; use fxhash::{FxHashMap, FxHashSet}; use log::trace; +use std::convert::TryFrom; use wasmparser::{ Ieee32, Ieee64, ImportSectionEntryType, Parser, Payload, Type, TypeDef, TypeOrFuncType, }; @@ -45,7 +45,7 @@ fn handle_payload<'a>( for _ in 0..reader.get_count() { match reader.read()?.ty { 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; } ImportSectionEntryType::Global(ty) => { @@ -72,12 +72,12 @@ fn handle_payload<'a>( } Payload::FunctionSection(mut reader) => { 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())); } } Payload::CodeSectionEntry(body) => { - let func_idx = *next_func; + let func_idx = Func::new(*next_func); *next_func += 1; let my_sig = module.func(func_idx).sig(); @@ -94,7 +94,7 @@ fn handle_payload<'a>( fn parse_body<'a>( module: &'a Module, - my_sig: SignatureId, + my_sig: Signature, body: wasmparser::FunctionBody, ) -> Result { let mut ret: FunctionBody = FunctionBody::default(); @@ -123,11 +123,12 @@ fn parse_body<'a>( ); let mut builder = FunctionBodyBuilder::new(module, my_sig, &mut ret); - builder.locals.seal_block_preds(0, &mut builder.body); - builder.locals.start_block(0); + let entry = Block::new(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() { - 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)); trace!("defining local {} to value {}", local_idx, value); builder.locals.declare(local_idx, arg_ty); @@ -135,9 +136,9 @@ fn parse_body<'a>( } let n_args = module.signature(my_sig).params.len(); - for (offset, local_ty) in locals.into_iter().enumerate() { - let local_idx = (n_args + offset) as u32; - builder.locals.declare(local_idx, local_ty); + for (offset, local_ty) in locals.values().enumerate() { + let local_idx = Local::new(n_args + offset); + builder.locals.declare(local_idx, *local_ty); } let ops = body.get_operators_reader()?; @@ -150,12 +151,12 @@ fn parse_body<'a>( 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); - assert!(builder.locals.is_sealed(block)); + debug_assert!(builder.locals.is_sealed(block)); } - for value in &builder.body.values { - assert!(!matches!(value, &ValueDef::Placeholder(_))); + for value in builder.body.values.values() { + debug_assert!(!matches!(value, &ValueDef::Placeholder(_))); } trace!("Final function body:{:?}", ret); @@ -166,26 +167,26 @@ fn parse_body<'a>( #[derive(Debug, Clone, Default)] struct LocalTracker { /// Types of locals, as declared. - types: FxHashMap, + types: FxHashMap, /// The current block. - cur_block: Option, + cur_block: Option, /// Is the given block sealed? - block_sealed: FxHashSet, + block_sealed: FxHashSet, /// The local-to-value mapping at the start of a block. - block_start: FxHashMap>, + block_start: FxHashMap>, /// The local-to-value mapping at the end of a block. - block_end: FxHashMap>, - in_cur_block: FxHashMap, - incomplete_phis: FxHashMap>, + block_end: FxHashMap>, + in_cur_block: FxHashMap, + incomplete_phis: FxHashMap>, } 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(); assert!(!was_present); } - pub fn start_block(&mut self, block: BlockId) { + pub fn start_block(&mut self, block: Block) { self.finish_block(); log::trace!("start_block: block {}", block); self.cur_block = Some(block); @@ -200,7 +201,7 @@ impl LocalTracker { 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); let not_sealed = self.block_sealed.insert(block); 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) } - 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); self.in_cur_block.insert(local, value); } - fn get_in_block( - &mut self, - body: &mut FunctionBody, - at_block: BlockId, - local: LocalId, - ) -> Value { + fn get_in_block(&mut self, body: &mut FunctionBody, at_block: Block, local: Local) -> Value { 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 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 { - assert!((local as usize) < body.locals.len()); self.get_in_block(body, block, local) } else { - let ty = body.locals[local as usize]; + let ty = body.locals[local]; self.create_default_value(body, ty) } } @@ -322,8 +317,8 @@ impl LocalTracker { fn compute_blockparam( &mut self, body: &mut FunctionBody, - block: BlockId, - local: LocalId, + block: Block, + local: Local, value: Value, ) { log::trace!( @@ -400,10 +395,10 @@ impl LocalTracker { #[derive(Debug)] struct FunctionBodyBuilder<'a, 'b> { module: &'b Module<'a>, - my_sig: SignatureId, + my_sig: Signature, body: &'b mut FunctionBody, locals: LocalTracker, - cur_block: Option, + cur_block: Option, ctrl_stack: Vec, op_stack: Vec<(Type, Value)>, } @@ -412,28 +407,28 @@ struct FunctionBodyBuilder<'a, 'b> { enum Frame { Block { start_depth: usize, - out: BlockId, + out: Block, params: Vec, results: Vec, }, Loop { start_depth: usize, - header: BlockId, - out: BlockId, + header: Block, + out: Block, params: Vec, results: Vec, }, If { start_depth: usize, - out: BlockId, - el: BlockId, + out: Block, + el: Block, param_values: Vec<(Type, Value)>, params: Vec, results: Vec, }, Else { start_depth: usize, - out: BlockId, + out: Block, params: Vec, results: Vec, }, @@ -458,7 +453,7 @@ impl Frame { } } - fn br_target(&self) -> BlockId { + fn br_target(&self) -> Block { match self { Frame::Block { out, .. } => *out, Frame::Loop { header, .. } => *header, @@ -466,7 +461,7 @@ impl Frame { } } - fn out(&self) -> BlockId { + fn out(&self) -> Block { match self { Frame::Block { out, .. } | Frame::Loop { out, .. } @@ -495,15 +490,15 @@ impl Frame { } impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { - fn new(module: &'b Module<'a>, my_sig: SignatureId, body: &'b mut FunctionBody) -> Self { - body.blocks.push(Block::default()); + fn new(module: &'b Module<'a>, my_sig: Signature, body: &'b mut FunctionBody) -> Self { + body.blocks.push(BlockDef::default()); let mut ret = Self { module, my_sig, body, ctrl_stack: vec![], op_stack: vec![], - cur_block: Some(0), + cur_block: Some(Block::new(0)), locals: LocalTracker::default(), }; @@ -559,22 +554,25 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { } wasmparser::Operator::LocalGet { local_index } => { - let ty = self.body.locals[*local_index as usize]; - let value = self.locals.get(&mut self.body, *local_index); + let local_index = Local::from(*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)); } wasmparser::Operator::LocalSet { local_index } => { + let local_index = Local::from(*local_index); let (_, value) = self.op_stack.pop().unwrap(); if self.cur_block.is_some() { - self.locals.set(*local_index, value); + self.locals.set(local_index, value); } } wasmparser::Operator::LocalTee { local_index } => { + let local_index = Local::from(*local_index); let (_ty, value) = *self.op_stack.last().unwrap(); 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(()) } - 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); for &ty in tys { self.body.add_blockparam(block, ty); @@ -1010,7 +1008,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]), TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]), 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.returns.clone()), @@ -1023,7 +1021,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { &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!( "emit_branch: cur_block {:?} target {} args {:?}", self.cur_block, @@ -1045,9 +1043,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { fn emit_cond_branch( &mut self, cond: Value, - if_true: BlockId, + if_true: Block, if_true_args: &[Value], - if_false: BlockId, + if_false: Block, if_false_args: &[Value], ) { log::trace!( @@ -1083,8 +1081,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { fn emit_br_table( &mut self, index: Value, - default_target: BlockId, - indexed_targets: &[BlockId], + default_target: Block, + indexed_targets: &[Block], args: &[Value], ) { log::trace!( @@ -1151,11 +1149,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { let inputs = op_inputs( self.module, self.my_sig, - &self.body.locals[..], + &self.body.locals, &self.op_stack[..], &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!( "emit into block {:?}: op {:?} inputs {:?}", diff --git a/src/ir.rs b/src/ir.rs index 0d455a7..badb1a0 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -1,21 +1,22 @@ //! Intermediate representation for Wasm. -use crate::{backend, backend::binaryen}; +use crate::entity; +use crate::entity::{EntityRef, EntityVec}; use crate::{frontend, Operator}; use anyhow::Result; use fxhash::FxHashSet; -use wasmparser::{FuncType, Type}; +use wasmparser::FuncType; -pub type SignatureId = usize; -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 use wasmparser::Type; -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)] pub struct Module<'a> { @@ -25,7 +26,7 @@ pub struct Module<'a> { globals: Vec, tables: Vec, - dirty_funcs: FxHashSet, + dirty_funcs: FxHashSet, } impl<'a> Module<'a> { @@ -37,21 +38,21 @@ impl<'a> Module<'a> { } impl<'a> Module<'a> { - pub fn func<'b>(&'b self, id: FuncId) -> &'b FuncDecl { - &self.funcs[id] + pub fn func<'b>(&'b self, id: Func) -> &'b FuncDecl { + &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); - &mut self.funcs[id] + &mut self.funcs[id.index()] } - pub fn signature<'b>(&'b self, id: SignatureId) -> &'b FuncType { - &self.signatures[id] + pub fn signature<'b>(&'b self, id: Signature) -> &'b FuncType { + &self.signatures[id.index()] } - pub fn global_ty(&self, id: GlobalId) -> Type { - self.globals[id as usize] + pub fn global_ty(&self, id: Global) -> Type { + self.globals[id.index()] } - pub fn table_ty(&self, id: TableId) -> Type { - self.tables[id as usize] + pub fn table_ty(&self, id: Table) -> Type { + self.tables[id.index()] } pub(crate) fn frontend_add_signature(&mut self, ty: FuncType) { @@ -70,12 +71,12 @@ impl<'a> Module<'a> { #[derive(Clone, Debug)] pub enum FuncDecl { - Import(SignatureId), - Body(SignatureId, FunctionBody), + Import(Signature), + Body(Signature, FunctionBody), } impl FuncDecl { - pub fn sig(&self) -> SignatureId { + pub fn sig(&self) -> Signature { match self { FuncDecl::Import(sig) => *sig, FuncDecl::Body(sig, ..) => *sig, @@ -105,23 +106,23 @@ pub struct FunctionBody { /// Return types of the function. pub rets: Vec, /// Local types, *including* args. - pub locals: Vec, - /// Block bodies, indexed by `BlockId`. - pub blocks: Vec, + pub locals: EntityVec, + /// Entry block. + pub entry: Block, + /// Block bodies. + pub blocks: EntityVec, /// Value definitions, indexed by `Value`. - pub values: Vec, + pub values: EntityVec, } impl FunctionBody { - pub fn add_block(&mut self) -> BlockId { - let id = self.blocks.len(); - self.blocks.push(Block::default()); - self.blocks[id].id = id; + pub fn add_block(&mut self) -> Block { + let id = self.blocks.push(BlockDef::default()); log::trace!("add_block: block {}", 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 pred_pos = self.blocks[to].preds.len(); self.blocks[from].succs.push(to); @@ -133,10 +134,7 @@ impl FunctionBody { pub fn add_value(&mut self, value: ValueDef) -> Value { log::trace!("add_value: def {:?}", value); - let id = Value(self.values.len() as u32); - log::trace!(" -> value {:?}", id); - self.values.push(value.clone()); - id + self.values.push(value) } pub fn set_alias(&mut self, value: Value, to: Value) { @@ -147,13 +145,13 @@ impl FunctionBody { if to == value { 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 { let mut result = value; loop { - if let &ValueDef::Alias(to) = &self.values[result.index()] { + if let &ValueDef::Alias(to) = &self.values[result] { result = to; } else { break; @@ -168,7 +166,7 @@ impl FunctionBody { 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 value = self.add_value(ValueDef::BlockParam(block, index, ty)); self.blocks[block].params.push((ty, value)); @@ -179,121 +177,65 @@ impl FunctionBody { 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 ty = match &self.values[value.index()] { + let ty = match &self.values[value] { &ValueDef::Placeholder(ty) => ty, _ => unreachable!(), }; 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 { let to = self.resolve_alias(value); // 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 { - self.values[value.index()] = ValueDef::Alias(to); + self.values[value] = ValueDef::Alias(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); } - pub fn end_block(&mut self, block: BlockId, terminator: Terminator) { + pub fn end_block(&mut self, block: Block, terminator: Terminator) { terminator.visit_successors(|succ| { self.add_edge(block, succ); }); self.blocks[block].terminator = terminator; } - pub fn add_local(&mut self, ty: Type) -> LocalId { - let id = self.locals.len() as LocalId; - self.locals.push(ty); - id - } - - pub fn values<'a>(&'a self) -> impl Iterator + 'a { - self.values - .iter() - .enumerate() - .map(|(idx, value_def)| (Value(idx as u32), value_def)) - } - - pub fn blocks(&self) -> impl Iterator { - (0..self.blocks.len()).into_iter() - } -} - -impl std::ops::Index for FunctionBody { - type Output = ValueDef; - fn index(&self, index: Value) -> &ValueDef { - &self.values[index.0 as usize] - } -} -impl std::ops::IndexMut for FunctionBody { - fn index_mut(&mut self, index: Value) -> &mut ValueDef { - &mut self.values[index.0 as usize] - } -} -impl std::ops::Index for FunctionBody { - type Output = Block; - fn index(&self, index: BlockId) -> &Block { - &self.blocks[index] - } -} -impl std::ops::IndexMut for FunctionBody { - fn index_mut(&mut self, index: BlockId) -> &mut Block { - &mut self.blocks[index] + pub fn add_local(&mut self, ty: Type) -> Local { + self.locals.push(ty) } } #[derive(Clone, Debug, Default)] -pub struct Block { - pub id: BlockId, - /// Side-effecting values from the sea-of-nodes that are computed, in order. +pub struct BlockDef { + /// Instructions in this block. pub insts: Vec, /// Terminator: branch or return. pub terminator: Terminator, /// Successor blocks. - pub succs: Vec, + pub succs: Vec, /// For each successor block, our index in its `preds` array. pub pos_in_succ_pred: Vec, /// Predecessor blocks. - pub preds: Vec, + pub preds: Vec, /// For each predecessor block, our index in its `succs` array. pub pos_in_pred_succ: Vec, /// Type and Value for each blockparam. 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)] pub enum ValueDef { Arg(usize, Type), - BlockParam(BlockId, usize, Type), + BlockParam(Block, usize, Type), Operator(Operator, Vec, Vec), PickOutput(Value, usize, Type), Alias(Value), @@ -334,7 +276,7 @@ impl ValueDef { #[derive(Clone, Debug)] pub struct BlockTarget { - pub block: BlockId, + pub block: Block, pub args: Vec, } @@ -476,7 +418,7 @@ impl Terminator { } } - pub fn visit_successors(&self, mut f: F) { + pub fn visit_successors(&self, mut f: F) { self.visit_targets(|target| f(target.block)); } @@ -523,32 +465,6 @@ impl<'a> Module<'a> { } pub fn to_wasm_bytes(&self) -> Result> { - let mut binaryen_module = binaryen::Module::read(self.orig_bytes)?; - 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() + todo!() } } diff --git a/src/lib.rs b/src/lib.rs index 16be75e..4eb29c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,11 @@ pub use wasmparser; mod backend; mod cfg; +mod entity; mod frontend; mod ir; mod op_traits; mod ops; -mod use_count; pub use ir::*; pub use ops::Operator; diff --git a/src/op_traits.rs b/src/op_traits.rs index 51f3c28..9ec18c9 100644 --- a/src/op_traits.rs +++ b/src/op_traits.rs @@ -1,14 +1,15 @@ //! 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 anyhow::Result; use wasmparser::Type; pub fn op_inputs( module: &Module, - my_sig: SignatureId, - my_locals: &[Type], + my_sig: Signature, + my_locals: &EntityVec, op_stack: &[(Type, Value)], op: &Operator, ) -> Result> { @@ -19,15 +20,15 @@ pub fn op_inputs( let sig = module.func(function_index).sig(); Ok(Vec::from(module.signature(sig).params.clone())) } - &Operator::CallIndirect { index, .. } => { - let mut params = module.signature(index).params.to_vec(); + &Operator::CallIndirect { sig_index, .. } => { + let mut params = module.signature(sig_index).params.to_vec(); params.push(Type::I32); Ok(params) } &Operator::Return => Ok(Vec::from(module.signature(my_sig).returns.clone())), &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![]), @@ -216,7 +217,7 @@ pub fn op_inputs( Operator::I32ReinterpretF32 => Ok(vec![Type::F32]), Operator::I64ReinterpretF64 => Ok(vec![Type::F64]), 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::TableSize { .. } => Ok(vec![]), Operator::MemorySize { .. } => Ok(vec![]), @@ -226,7 +227,7 @@ pub fn op_inputs( pub fn op_outputs( module: &Module, - my_locals: &[Type], + my_locals: &EntityVec, op_stack: &[(Type, Value)], op: &Operator, ) -> Result> { @@ -237,13 +238,13 @@ pub fn op_outputs( let sig = module.func(function_index).sig(); Ok(Vec::from(module.signature(sig).returns.clone())) } - &Operator::CallIndirect { index, .. } => { - Ok(Vec::from(module.signature(index).returns.clone())) + &Operator::CallIndirect { sig_index, .. } => { + Ok(Vec::from(module.signature(sig_index).returns.clone())) } &Operator::Return => Ok(vec![]), &Operator::LocalSet { .. } => Ok(vec![]), &Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => { - Ok(vec![my_locals[local_index as usize]]) + Ok(vec![my_locals[local_index]]) } &Operator::Select => { @@ -425,7 +426,7 @@ pub fn op_outputs( Operator::F64ReinterpretI64 => Ok(vec![Type::F64]), Operator::I32ReinterpretF32 => Ok(vec![Type::I32]), 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::TableGrow { .. } => Ok(vec![]), Operator::TableSize { .. } => Ok(vec![Type::I32]), @@ -439,12 +440,12 @@ pub enum SideEffect { Trap, ReadMem, WriteMem, - ReadGlobal(usize), - WriteGlobal(usize), - ReadTable(usize), - WriteTable(usize), - ReadLocal(usize), - WriteLocal(usize), + ReadGlobal(Global), + WriteGlobal(Global), + ReadTable(Table), + WriteTable(Table), + ReadLocal(Local), + WriteLocal(Local), Return, All, } @@ -459,17 +460,16 @@ pub fn op_effects(op: &Operator) -> Result> { &Operator::Call { .. } => Ok(vec![All]), &Operator::CallIndirect { .. } => Ok(vec![All]), &Operator::Return => Ok(vec![Return]), - &Operator::LocalSet { local_index, .. } => Ok(vec![WriteLocal(local_index as usize)]), - &Operator::LocalGet { local_index, .. } => Ok(vec![ReadLocal(local_index as usize)]), - &Operator::LocalTee { local_index, .. } => Ok(vec![ - ReadLocal(local_index as usize), - WriteLocal(local_index as usize), - ]), + &Operator::LocalSet { local_index, .. } => Ok(vec![WriteLocal(local_index)]), + &Operator::LocalGet { local_index, .. } => Ok(vec![ReadLocal(local_index)]), + &Operator::LocalTee { local_index, .. } => { + Ok(vec![ReadLocal(local_index), WriteLocal(local_index)]) + } &Operator::Select => Ok(vec![]), &Operator::TypedSelect { .. } => Ok(vec![]), - &Operator::GlobalGet { global_index, .. } => Ok(vec![ReadGlobal(global_index as usize)]), - &Operator::GlobalSet { global_index, .. } => Ok(vec![WriteGlobal(global_index as usize)]), + &Operator::GlobalGet { global_index, .. } => Ok(vec![ReadGlobal(global_index)]), + &Operator::GlobalSet { global_index, .. } => Ok(vec![WriteGlobal(global_index)]), Operator::I32Load { .. } | Operator::I32Load8S { .. } @@ -642,10 +642,10 @@ pub fn op_effects(op: &Operator) -> Result> { Operator::F64ReinterpretI64 => Ok(vec![]), Operator::I32ReinterpretF32 => Ok(vec![]), Operator::I64ReinterpretF64 => Ok(vec![]), - Operator::TableGet { table, .. } => Ok(vec![ReadTable(*table as usize), Trap]), - Operator::TableSet { table, .. } => Ok(vec![WriteTable(*table as usize), Trap]), - Operator::TableGrow { table, .. } => Ok(vec![WriteTable(*table as usize), Trap]), - Operator::TableSize { table, .. } => Ok(vec![ReadTable(*table as usize)]), + Operator::TableGet { table_index, .. } => Ok(vec![ReadTable(*table_index), Trap]), + Operator::TableSet { table_index, .. } => Ok(vec![WriteTable(*table_index), Trap]), + Operator::TableGrow { table_index, .. } => Ok(vec![WriteTable(*table_index), Trap]), + Operator::TableSize { table_index, .. } => Ok(vec![ReadTable(*table_index)]), Operator::MemorySize { .. } => Ok(vec![ReadMem]), Operator::MemoryGrow { .. } => Ok(vec![WriteMem, Trap]), } diff --git a/src/ops.rs b/src/ops.rs index a2bb73c..701159e 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -2,13 +2,13 @@ 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)] -pub struct Memory { +pub struct MemoryArg { pub align: u8, pub offset: u64, - pub memory: MemoryId, + pub memory: Memory, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -16,46 +16,117 @@ pub enum Operator { Unreachable, Nop, - Call { function_index: FuncId }, - CallIndirect { index: FuncId, table_index: TableId }, + Call { + function_index: Func, + }, + CallIndirect { + sig_index: Signature, + table_index: Table, + }, Return, - LocalSet { local_index: LocalId }, - LocalTee { local_index: LocalId }, - LocalGet { local_index: LocalId }, + LocalSet { + local_index: Local, + }, + LocalTee { + local_index: Local, + }, + LocalGet { + local_index: Local, + }, Select, - TypedSelect { ty: Type }, - GlobalGet { global_index: GlobalId }, - GlobalSet { global_index: GlobalId }, + TypedSelect { + ty: Type, + }, + GlobalGet { + global_index: Global, + }, + GlobalSet { + global_index: Global, + }, - I32Load { memory: Memory }, - I64Load { memory: Memory }, - F32Load { memory: Memory }, - F64Load { memory: Memory }, - I32Load8S { memory: Memory }, - I32Load8U { memory: Memory }, - I32Load16S { memory: Memory }, - I32Load16U { memory: Memory }, - I64Load8S { memory: Memory }, - I64Load8U { memory: Memory }, - I64Load16S { memory: Memory }, - I64Load16U { memory: Memory }, - I64Load32S { memory: Memory }, - I64Load32U { memory: Memory }, + I32Load { + memory: MemoryArg, + }, + I64Load { + memory: MemoryArg, + }, + F32Load { + memory: MemoryArg, + }, + F64Load { + memory: MemoryArg, + }, + I32Load8S { + 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 }, - I64Store { memory: Memory }, - F32Store { memory: Memory }, - F64Store { memory: Memory }, - I32Store8 { memory: Memory }, - I32Store16 { memory: Memory }, - I64Store8 { memory: Memory }, - I64Store16 { memory: Memory }, - I64Store32 { memory: Memory }, + I32Store { + memory: MemoryArg, + }, + I64Store { + memory: MemoryArg, + }, + F32Store { + memory: MemoryArg, + }, + F64Store { + memory: MemoryArg, + }, + I32Store8 { + memory: MemoryArg, + }, + I32Store16 { + memory: MemoryArg, + }, + I64Store8 { + memory: MemoryArg, + }, + I64Store16 { + memory: MemoryArg, + }, + I64Store32 { + memory: MemoryArg, + }, - I32Const { value: i32 }, - I64Const { value: i64 }, - F32Const { value: Ieee32 }, - F64Const { value: Ieee64 }, + I32Const { + value: i32, + }, + I64Const { + value: i64, + }, + F32Const { + value: Ieee32, + }, + F64Const { + value: Ieee64, + }, I32Eqz, I32Eq, @@ -206,12 +277,24 @@ pub enum Operator { F64ReinterpretI64, I32ReinterpretF32, I64ReinterpretF64, - TableGet { table: TableId }, - TableSet { table: TableId }, - TableGrow { table: TableId }, - TableSize { table: TableId }, - MemorySize { mem: MemoryId }, - MemoryGrow { mem: MemoryId }, + TableGet { + table_index: Table, + }, + TableSet { + table_index: Table, + }, + 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 { @@ -222,32 +305,32 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator { &wasmparser::Operator::Unreachable => Ok(Operator::Unreachable), &wasmparser::Operator::Nop => Ok(Operator::Nop), &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::LocalSet { local_index } => { - Ok(Operator::LocalSet { local_index }) - } - &wasmparser::Operator::LocalTee { local_index } => { - Ok(Operator::LocalTee { local_index }) - } - &wasmparser::Operator::LocalGet { local_index } => { - Ok(Operator::LocalGet { local_index }) - } + &wasmparser::Operator::LocalSet { local_index } => Ok(Operator::LocalSet { + local_index: Local::from(local_index), + }), + &wasmparser::Operator::LocalTee { local_index } => Ok(Operator::LocalTee { + local_index: Local::from(local_index), + }), + &wasmparser::Operator::LocalGet { local_index } => Ok(Operator::LocalGet { + local_index: Local::from(local_index), + }), &wasmparser::Operator::Select => Ok(Operator::Select), &wasmparser::Operator::TypedSelect { ty } => Ok(Operator::TypedSelect { ty }), - &wasmparser::Operator::GlobalGet { global_index } => { - Ok(Operator::GlobalGet { global_index }) - } - &wasmparser::Operator::GlobalSet { global_index } => { - Ok(Operator::GlobalSet { global_index }) - } + &wasmparser::Operator::GlobalGet { global_index } => Ok(Operator::GlobalGet { + global_index: Global::from(global_index), + }), + &wasmparser::Operator::GlobalSet { global_index } => Ok(Operator::GlobalSet { + global_index: Global::from(global_index), + }), &wasmparser::Operator::I32Load { memarg } => Ok(Operator::I32Load { 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::I32ReinterpretF32 => Ok(Operator::I32ReinterpretF32), &wasmparser::Operator::I64ReinterpretF64 => Ok(Operator::I64ReinterpretF64), - &wasmparser::Operator::TableGet { table } => Ok(Operator::TableGet { table }), - &wasmparser::Operator::TableSet { table } => Ok(Operator::TableSet { table }), - &wasmparser::Operator::TableGrow { table } => Ok(Operator::TableGrow { table }), - &wasmparser::Operator::TableSize { table } => Ok(Operator::TableSize { table }), - &wasmparser::Operator::MemorySize { mem, .. } => Ok(Operator::MemorySize { mem }), - &wasmparser::Operator::MemoryGrow { mem, .. } => Ok(Operator::MemoryGrow { mem }), + &wasmparser::Operator::TableGet { table } => Ok(Operator::TableGet { + table_index: Table::from(table), + }), + &wasmparser::Operator::TableSet { table } => Ok(Operator::TableSet { + table_index: Table::from(table), + }), + &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(()), } } } -impl std::convert::From for Memory { - fn from(value: MemoryImmediate) -> Memory { - Memory { +impl std::convert::From for MemoryArg { + fn from(value: MemoryImmediate) -> MemoryArg { + MemoryArg { align: value.align, offset: value.offset, - memory: value.memory as MemoryId, + memory: Memory::from(value.memory), } } } diff --git a/src/use_count.rs b/src/use_count.rs deleted file mode 100644 index 4cb6d68..0000000 --- a/src/use_count.rs +++ /dev/null @@ -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, - pub(crate) use_count: Vec, -} - -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; - } -}