big refactor
This commit is contained in:
parent
1da150823d
commit
a538d10167
|
@ -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<BlockId, binaryen::Expression> = FxHashMap::default();
|
||||
for block in body.blocks() {
|
||||
let exprs = body[block]
|
||||
let mut block_exprs: FxHashMap<Block, binaryen::Expression> = 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::<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
|
||||
// relooper/stackifier support built into Binaryen.
|
||||
let mut relooper = binaryen::Relooper::new(into_mod);
|
||||
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 {}
|
||||
|
||||
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<Type>,
|
||||
}
|
||||
|
||||
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<binaryen::Expression> {
|
||||
/*
|
||||
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,
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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<u32>],
|
||||
mut node1: BlockId,
|
||||
mut node2: BlockId,
|
||||
) -> BlockId {
|
||||
idom: &PerEntity<Block, Block>, // map from Block to Block
|
||||
block_to_rpo: &PerEntity<Block, Option<u32>>,
|
||||
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<BlockId> {
|
||||
post_ord: &[Block],
|
||||
start: Block,
|
||||
) -> PerEntity<Block, Block> {
|
||||
// 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<Block, Option<u32>> = 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<Block, Block> = 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<Block, Block>, 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];
|
||||
|
|
|
@ -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</* BlockId, */ SmallVec<[BlockId; 4]>>,
|
||||
pub block_preds: PerEntity<Block, SmallVec<[Block; 4]>>,
|
||||
/// 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.
|
||||
pub return_blocks: Vec<BlockId>,
|
||||
pub return_blocks: Vec<Block>,
|
||||
/// Postorder traversal of blocks.
|
||||
pub postorder: Vec<BlockId>,
|
||||
pub postorder: Vec<Block>,
|
||||
/// 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.
|
||||
pub domtree: Vec<BlockId>,
|
||||
pub domtree: PerEntity<Block, Block>,
|
||||
}
|
||||
|
||||
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<Block, SmallVec<[Block; 4]>> = PerEntity::default();
|
||||
let mut block_succs: PerEntity<Block, SmallVec<[Block; 4]>> = 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<BlockId> {
|
||||
pub fn rpo(&self) -> Vec<Block> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<BlockId> {
|
||||
) -> Vec<Block> {
|
||||
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<Block, bool> = 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![];
|
||||
|
|
152
src/entity.rs
Normal file
152
src/entity.rs
Normal file
|
@ -0,0 +1,152 @@
|
|||
//! Type-safe indices and indexed containers.
|
||||
|
||||
use std::default::Default;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
pub trait EntityRef: Clone + Copy + PartialEq + Eq + PartialOrd + Ord + Hash {
|
||||
fn new(value: usize) -> Self;
|
||||
fn index(self) -> usize;
|
||||
fn invalid() -> Self;
|
||||
fn is_valid(self) -> bool {
|
||||
self != Self::invalid()
|
||||
}
|
||||
fn is_invalid(self) -> bool {
|
||||
self == Self::invalid()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! entity {
|
||||
($name:tt, $prefix:tt) => {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct $name(u32);
|
||||
|
||||
impl crate::entity::EntityRef for $name {
|
||||
fn new(value: usize) -> Self {
|
||||
use std::convert::TryFrom;
|
||||
let value = u32::try_from(value).unwrap();
|
||||
debug_assert!(value != u32::MAX);
|
||||
Self(value)
|
||||
}
|
||||
fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
fn invalid() -> Self {
|
||||
Self(u32::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<u32> for $name {
|
||||
fn from(val: u32) -> Self {
|
||||
<Self as crate::entity::EntityRef>::new(val as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for $name {
|
||||
fn default() -> Self {
|
||||
<Self as crate::entity::EntityRef>::invalid()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}{}", $prefix, self.0)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}{}", $prefix, self.0)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EntityVec<Idx: EntityRef, T: Clone + Debug>(Vec<T>, PhantomData<Idx>);
|
||||
|
||||
impl<Idx: EntityRef, T: Clone + Debug> std::default::Default for EntityVec<Idx, T> {
|
||||
fn default() -> Self {
|
||||
Self(vec![], PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: EntityRef, T: Clone + Debug> EntityVec<Idx, T> {
|
||||
pub fn push(&mut self, t: T) -> Idx {
|
||||
let idx = Idx::new(self.0.len());
|
||||
self.0.push(t);
|
||||
idx
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = Idx> {
|
||||
(0..self.0.len()).map(|index| Idx::new(index))
|
||||
}
|
||||
|
||||
pub fn values(&self) -> impl Iterator<Item = &T> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||
self.0.iter_mut()
|
||||
}
|
||||
|
||||
pub fn entries(&self) -> impl Iterator<Item = (Idx, &T)> {
|
||||
self.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, t)| (Idx::new(index), t))
|
||||
}
|
||||
|
||||
pub fn entries_mut(&mut self) -> impl Iterator<Item = (Idx, &mut T)> {
|
||||
self.0
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.map(|(index, t)| (Idx::new(index), t))
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: Idx) -> Option<&T> {
|
||||
self.0.get(idx.index())
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, idx: Idx) -> Option<&mut T> {
|
||||
self.0.get_mut(idx.index())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: EntityRef, T: Clone + Debug> Index<Idx> for EntityVec<Idx, T> {
|
||||
type Output = T;
|
||||
fn index(&self, idx: Idx) -> &T {
|
||||
&self.0[idx.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: EntityRef, T: Clone + Debug> IndexMut<Idx> for EntityVec<Idx, T> {
|
||||
fn index_mut(&mut self, idx: Idx) -> &mut T {
|
||||
&mut self.0[idx.index()]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PerEntity<Idx: EntityRef, T: Clone + Debug + Default>(Vec<T>, PhantomData<Idx>, T);
|
||||
|
||||
impl<Idx: EntityRef, T: Clone + Debug + Default> Index<Idx> for PerEntity<Idx, T> {
|
||||
type Output = T;
|
||||
fn index(&self, idx: Idx) -> &T {
|
||||
self.0.get(idx.index()).unwrap_or(&self.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: EntityRef, T: Clone + Debug + Default> IndexMut<Idx> for PerEntity<Idx, T> {
|
||||
fn index_mut(&mut self, idx: Idx) -> &mut T {
|
||||
if idx.index() >= self.0.len() {
|
||||
self.0.resize(idx.index() + 1, T::default());
|
||||
}
|
||||
&mut self.0[idx.index()]
|
||||
}
|
||||
}
|
130
src/frontend.rs
130
src/frontend.rs
|
@ -2,14 +2,14 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
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<FunctionBody> {
|
||||
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<LocalId, Type>,
|
||||
types: FxHashMap<Local, Type>,
|
||||
/// The current block.
|
||||
cur_block: Option<BlockId>,
|
||||
cur_block: Option<Block>,
|
||||
/// Is the given block sealed?
|
||||
block_sealed: FxHashSet<BlockId>,
|
||||
block_sealed: FxHashSet<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.
|
||||
block_end: FxHashMap<BlockId, FxHashMap<LocalId, Value>>,
|
||||
in_cur_block: FxHashMap<LocalId, Value>,
|
||||
incomplete_phis: FxHashMap<BlockId, Vec<(LocalId, Value)>>,
|
||||
block_end: FxHashMap<Block, FxHashMap<Local, Value>>,
|
||||
in_cur_block: FxHashMap<Local, Value>,
|
||||
incomplete_phis: FxHashMap<Block, Vec<(Local, Value)>>,
|
||||
}
|
||||
|
||||
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<BlockId>,
|
||||
cur_block: Option<Block>,
|
||||
ctrl_stack: Vec<Frame>,
|
||||
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<Type>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
Loop {
|
||||
start_depth: usize,
|
||||
header: BlockId,
|
||||
out: BlockId,
|
||||
header: Block,
|
||||
out: Block,
|
||||
params: Vec<Type>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
If {
|
||||
start_depth: usize,
|
||||
out: BlockId,
|
||||
el: BlockId,
|
||||
out: Block,
|
||||
el: Block,
|
||||
param_values: Vec<(Type, Value)>,
|
||||
params: Vec<Type>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
Else {
|
||||
start_depth: usize,
|
||||
out: BlockId,
|
||||
out: Block,
|
||||
params: Vec<Type>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
|
@ -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 {:?}",
|
||||
|
|
196
src/ir.rs
196
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<Type>,
|
||||
tables: Vec<Type>,
|
||||
|
||||
dirty_funcs: FxHashSet<FuncId>,
|
||||
dirty_funcs: FxHashSet<Func>,
|
||||
}
|
||||
|
||||
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<Type>,
|
||||
/// Local types, *including* args.
|
||||
pub locals: Vec<Type>,
|
||||
/// Block bodies, indexed by `BlockId`.
|
||||
pub blocks: Vec<Block>,
|
||||
pub locals: EntityVec<Local, Type>,
|
||||
/// Entry block.
|
||||
pub entry: Block,
|
||||
/// Block bodies.
|
||||
pub blocks: EntityVec<Block, BlockDef>,
|
||||
/// Value definitions, indexed by `Value`.
|
||||
pub values: Vec<ValueDef>,
|
||||
pub values: EntityVec<Value, ValueDef>,
|
||||
}
|
||||
|
||||
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<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]
|
||||
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<Value>,
|
||||
/// Terminator: branch or return.
|
||||
pub terminator: Terminator,
|
||||
/// Successor blocks.
|
||||
pub succs: Vec<BlockId>,
|
||||
pub succs: Vec<Block>,
|
||||
/// For each successor block, our index in its `preds` array.
|
||||
pub pos_in_succ_pred: Vec<usize>,
|
||||
/// Predecessor blocks.
|
||||
pub preds: Vec<BlockId>,
|
||||
pub preds: Vec<Block>,
|
||||
/// For each predecessor block, our index in its `succs` array.
|
||||
pub pos_in_pred_succ: Vec<usize>,
|
||||
/// 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<Value>, Vec<Type>),
|
||||
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<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));
|
||||
}
|
||||
|
||||
|
@ -523,32 +465,6 @@ impl<'a> Module<'a> {
|
|||
}
|
||||
|
||||
pub fn to_wasm_bytes(&self) -> Result<Vec<u8>> {
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Local, Type>,
|
||||
op_stack: &[(Type, Value)],
|
||||
op: &Operator,
|
||||
) -> Result<Vec<Type>> {
|
||||
|
@ -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<Local, Type>,
|
||||
op_stack: &[(Type, Value)],
|
||||
op: &Operator,
|
||||
) -> Result<Vec<Type>> {
|
||||
|
@ -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<Vec<SideEffect>> {
|
|||
&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<Vec<SideEffect>> {
|
|||
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]),
|
||||
}
|
||||
|
|
247
src/ops.rs
247
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<MemoryImmediate> for Memory {
|
||||
fn from(value: MemoryImmediate) -> Memory {
|
||||
Memory {
|
||||
impl std::convert::From<MemoryImmediate> for MemoryArg {
|
||||
fn from(value: MemoryImmediate) -> MemoryArg {
|
||||
MemoryArg {
|
||||
align: value.align,
|
||||
offset: value.offset,
|
||||
memory: value.memory as MemoryId,
|
||||
memory: Memory::from(value.memory),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
//! Use-count analysis.
|
||||
|
||||
use crate::{FunctionBody, Value, ValueDef};
|
||||
use fxhash::FxHashSet;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UseCountAnalysis {
|
||||
pub(crate) toplevel: FxHashSet<Value>,
|
||||
pub(crate) use_count: Vec</* Value, */ usize>,
|
||||
}
|
||||
|
||||
impl UseCountAnalysis {
|
||||
pub(crate) fn compute(f: &FunctionBody) -> UseCountAnalysis {
|
||||
let n_values = f.values.len();
|
||||
let mut counts = UseCountAnalysis {
|
||||
use_count: vec![0; n_values],
|
||||
toplevel: FxHashSet::default(),
|
||||
};
|
||||
|
||||
let mut workqueue = VecDeque::new();
|
||||
let mut workqueue_set = FxHashSet::default();
|
||||
for block in 0..f.blocks.len() {
|
||||
for &value in &f.blocks[block].insts {
|
||||
let value = f.resolve_alias(value);
|
||||
counts.add(value);
|
||||
if workqueue_set.insert(value) {
|
||||
workqueue.push_back(value);
|
||||
}
|
||||
counts.toplevel.insert(value);
|
||||
}
|
||||
f.blocks[block].terminator.visit_uses(|value| {
|
||||
let value = f.resolve_alias(value);
|
||||
counts.add(value);
|
||||
if workqueue_set.insert(value) {
|
||||
workqueue.push_back(value);
|
||||
}
|
||||
});
|
||||
|
||||
while let Some(value) = workqueue.pop_front() {
|
||||
workqueue_set.remove(&value);
|
||||
match &f.values[value.index()] {
|
||||
&ValueDef::Alias(..) | &ValueDef::Arg(..) | &ValueDef::BlockParam(..) => {}
|
||||
&ValueDef::Operator(_op, ref args, _) => {
|
||||
for &arg in args {
|
||||
let arg = f.resolve_alias(arg);
|
||||
counts.add(arg);
|
||||
if counts.use_count[arg.index()] == 1 {
|
||||
if workqueue_set.insert(arg) {
|
||||
workqueue.push_back(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&ValueDef::PickOutput(value, _, _) => {
|
||||
let value = f.resolve_alias(value);
|
||||
counts.add(value);
|
||||
if counts.use_count[value.index()] == 1 {
|
||||
if workqueue_set.insert(value) {
|
||||
workqueue.push_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
&ValueDef::Placeholder(_) => {
|
||||
panic!("Unresolved placeholder for value {}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
counts
|
||||
}
|
||||
|
||||
fn add(&mut self, value: Value) {
|
||||
self.use_count[value.index()] += 1;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue