wasm region generation and target resolution

This commit is contained in:
Chris Fallin 2021-12-17 01:07:37 -08:00
parent 693c691b59
commit 65e47c8a32
2 changed files with 139 additions and 18 deletions

View file

@ -4,7 +4,7 @@
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use crate::{cfg::CFGInfo, BlockId}; use crate::{cfg::CFGInfo, BlockId, FunctionBody};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Node { pub enum Node {
@ -137,13 +137,47 @@ impl LoopNest {
} }
} }
fn compute_forward_edge_targets(cfg: &CFGInfo) -> FxHashSet<BlockId> { fn compute_linear_block_pos(cfg: &CFGInfo, nest: &LoopNest) -> Vec<Option<usize>> {
let mut next = 0;
let mut positions = vec![None; cfg.len()];
for node in &nest.nodes {
compute_linear_block_pos_for_node(node, &mut next, &mut positions);
}
positions
}
fn compute_linear_block_pos_for_node(
node: &Node,
next: &mut usize,
positions: &mut Vec<Option<usize>>,
) {
match node {
&Node::Loop(_, ref subnodes) => {
for subnode in subnodes {
compute_linear_block_pos_for_node(subnode, next, positions);
}
}
&Node::Leaf(block) => {
let linear_index = *next;
*next += 1;
positions[block] = Some(linear_index);
}
}
}
fn compute_forward_edge_targets(
cfg: &CFGInfo,
linear_block_pos: &[Option<usize>],
) -> FxHashSet<BlockId> {
let mut ret = FxHashSet::default(); let mut ret = FxHashSet::default();
for (block_rpo, &block) in cfg.postorder.iter().rev().enumerate() { for block in 0..cfg.len() {
if linear_block_pos[block].is_none() {
continue;
}
let block_pos = linear_block_pos[block].unwrap();
for &succ in &cfg.block_succs[block] { for &succ in &cfg.block_succs[block] {
let succ_po = cfg.postorder_pos[succ].unwrap(); let succ_pos = linear_block_pos[succ].unwrap();
let succ_rpo = cfg.postorder.len() - 1 - succ_po; if succ_pos > block_pos + 1 {
if succ_rpo > block_rpo {
ret.insert(succ); ret.insert(succ);
} }
} }
@ -176,7 +210,8 @@ impl WasmRegion {
assert!(!loop_nest.nodes.is_empty()); assert!(!loop_nest.nodes.is_empty());
assert!(loop_nest.nodes[0].header() == 0); assert!(loop_nest.nodes[0].header() == 0);
let forward_targets = compute_forward_edge_targets(cfg); let linear_pos = compute_linear_block_pos(cfg, loop_nest);
let forward_targets = compute_forward_edge_targets(cfg, &linear_pos);
log::trace!( log::trace!(
"WasmRegion::compute: forward_targets = {:?}", "WasmRegion::compute: forward_targets = {:?}",
forward_targets forward_targets
@ -241,26 +276,111 @@ impl WasmRegion {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BlockOrder { pub struct BlockOrder {
pub blocks: Vec<BlockOrderEntry>, pub entries: Vec<BlockOrderEntry>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum BlockOrderEntry { pub enum BlockOrderEntry {
StartBlock, StartBlock(Vec<wasmparser::Type>),
EndBlock, StartLoop(Vec<wasmparser::Type>),
StartLoop, End,
EndLoop, BasicBlock(BlockId, Vec<BlockOrderTarget>),
Block(BlockId, Vec<BlockOrderTarget>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BlockOrderTarget { pub struct BlockOrderTarget {
pub target: BlockId, pub target: BlockId,
pub relative_branch: usize, /// `None` means fallthrough.
pub relative_branch: Option<usize>,
} }
impl BlockOrder { impl BlockOrder {
pub fn compute(cfg: &CFGInfo, wasm_region: &WasmRegion) -> BlockOrder { pub fn compute(f: &FunctionBody, cfg: &CFGInfo, wasm_region: &WasmRegion) -> BlockOrder {
todo!() let mut target_stack = vec![];
let mut entries = vec![];
Self::generate_region(f, cfg, &mut target_stack, &mut entries, wasm_region, None);
log::trace!("entries: {:?}", entries);
BlockOrder { entries }
}
fn generate_region(
f: &FunctionBody,
cfg: &CFGInfo,
target_stack: &mut Vec<BlockId>,
entries: &mut Vec<BlockOrderEntry>,
region: &WasmRegion,
fallthrough: Option<BlockId>,
) {
log::trace!(
"BlockOrder::generate_region: stack {:?} region {:?} fallthrough {:?}",
target_stack,
region,
fallthrough,
);
match region {
&WasmRegion::Block(header, _, ref subregions, ..)
| &WasmRegion::Loop(header, ref subregions) => {
let (target, is_loop) = match region {
&WasmRegion::Block(_, out, ..) => {
assert!(out.is_some() || target_stack.is_empty());
(out, false)
}
&WasmRegion::Loop(header, ..) => (Some(header), true),
_ => unreachable!(),
};
if let Some(target) = target {
target_stack.push(target);
}
let params = f.blocks[header].params.clone();
if is_loop {
entries.push(BlockOrderEntry::StartLoop(params));
} else {
entries.push(BlockOrderEntry::StartBlock(params));
}
for i in 0..subregions.len() {
let subregion = &subregions[i];
let fallthrough = if i == subregions.len() - 1 {
fallthrough
} else {
Some(subregions[i + 1].header())
};
Self::generate_region(f, cfg, target_stack, entries, subregion, fallthrough);
}
entries.push(BlockOrderEntry::End);
if target.is_some() {
target_stack.pop();
}
}
&WasmRegion::Leaf(block) => {
let mut targets = vec![];
for &succ in &cfg.block_succs[block] {
log::trace!(
"BlockOrder::generate_region: looking for succ {} in stack {:?} fallthrough {:?}",
succ,
target_stack,
fallthrough,
);
let relative_branch = if Some(succ) == fallthrough {
None
} else {
let pos = target_stack
.iter()
.position(|entry| *entry == succ)
.expect("Malformed Wasm structured control flow");
Some(target_stack.len() - 1 - pos)
};
targets.push(BlockOrderTarget {
target: succ,
relative_branch,
});
}
entries.push(BlockOrderEntry::BasicBlock(block, targets));
}
}
log::trace!("BlockOrder::generate_region: done with region {:?}", region);
} }
} }

View file

@ -4,7 +4,7 @@ use std::collections::hash_map::Entry;
use crate::{ use crate::{
cfg::{ cfg::{
structured::{LoopNest, WasmRegion}, structured::{BlockOrder, LoopNest, WasmRegion},
CFGInfo, CFGInfo,
}, },
frontend, Operator, frontend, Operator,
@ -484,7 +484,8 @@ impl<'a> Module<'a> {
&FuncDecl::Body(_, ref body) => { &FuncDecl::Body(_, ref body) => {
let cfg = CFGInfo::new(body); let cfg = CFGInfo::new(body);
let loopnest = LoopNest::compute(&cfg); let loopnest = LoopNest::compute(&cfg);
let _regions = WasmRegion::compute(&cfg, &loopnest); let regions = WasmRegion::compute(&cfg, &loopnest);
let _blockorder = BlockOrder::compute(body, &cfg, &regions);
} }
_ => {} _ => {}
} }