Add remove-empty-blocks pass.
This commit is contained in:
parent
b76ffd59cf
commit
c908463ee1
|
@ -94,6 +94,23 @@ impl FunctionBody {
|
||||||
log::trace!("add_edge: from {} to {}", from, to);
|
log::trace!("add_edge: from {} to {}", from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn recompute_edges(&mut self) {
|
||||||
|
for block in self.blocks.values_mut() {
|
||||||
|
block.preds.clear();
|
||||||
|
block.succs.clear();
|
||||||
|
block.pos_in_succ_pred.clear();
|
||||||
|
block.pos_in_pred_succ.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
for block in 0..self.blocks.len() {
|
||||||
|
let block = Block::new(block);
|
||||||
|
let terminator = self.blocks[block].terminator.clone();
|
||||||
|
terminator.visit_successors(|succ| {
|
||||||
|
self.add_edge(block, succ);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_value(&mut self, value: ValueDef) -> Value {
|
pub fn add_value(&mut self, value: ValueDef) -> Value {
|
||||||
log::trace!("add_value: def {:?}", value);
|
log::trace!("add_value: def {:?}", value);
|
||||||
let value = self.values.push(value);
|
let value = self.values.push(value);
|
||||||
|
|
|
@ -241,6 +241,7 @@ impl<'a> Module<'a> {
|
||||||
let cfg = crate::cfg::CFGInfo::new(body);
|
let cfg = crate::cfg::CFGInfo::new(body);
|
||||||
crate::passes::basic_opt::gvn(body, &cfg);
|
crate::passes::basic_opt::gvn(body, &cfg);
|
||||||
crate::passes::resolve_aliases::run(body);
|
crate::passes::resolve_aliases::run(body);
|
||||||
|
crate::passes::empty_blocks::run(body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
|
|
||||||
pub mod basic_opt;
|
pub mod basic_opt;
|
||||||
pub mod dom_pass;
|
pub mod dom_pass;
|
||||||
pub mod resolve_aliases;
|
pub mod empty_blocks;
|
||||||
pub mod maxssa;
|
pub mod maxssa;
|
||||||
|
pub mod resolve_aliases;
|
||||||
|
|
128
src/passes/empty_blocks.rs
Normal file
128
src/passes/empty_blocks.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
//! Pass to remove empty blocks.
|
||||||
|
|
||||||
|
use crate::entity::EntityRef;
|
||||||
|
use crate::ir::{Block, BlockTarget, FunctionBody, Terminator, Value, ValueDef};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Forwarding {
|
||||||
|
to: Block,
|
||||||
|
args: Vec<ForwardingArg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum ForwardingArg {
|
||||||
|
BlockParam(usize),
|
||||||
|
Value(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Forwarding {
|
||||||
|
fn compose(a: &Forwarding, b: &Forwarding) -> Forwarding {
|
||||||
|
// `b` should be the target of `a.to`, but we can't assert
|
||||||
|
// that here. The composed target is thus `b.to`.
|
||||||
|
let to = b.to;
|
||||||
|
|
||||||
|
// For each arg in `b.args`, evaluate, replacing any
|
||||||
|
// `BlockParam` with the corresponding value from `a.args`.
|
||||||
|
let args = b
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|&arg| match arg {
|
||||||
|
ForwardingArg::BlockParam(idx) => a.args[idx].clone(),
|
||||||
|
ForwardingArg::Value(v) => ForwardingArg::Value(v),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Forwarding { to, args }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_to_forwarding(body: &FunctionBody, block: Block) -> Option<Forwarding> {
|
||||||
|
// Must be empty except for terminator, and must have an
|
||||||
|
// unconditional-branch terminator.
|
||||||
|
if body.blocks[block].insts.len() > 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let target = match &body.blocks[block].terminator {
|
||||||
|
&Terminator::Br { ref target } => target,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If conditions met, then gather ForwardingArgs.
|
||||||
|
let args = target
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|&arg| {
|
||||||
|
let arg = body.resolve_alias(arg);
|
||||||
|
match &body.values[arg] {
|
||||||
|
&ValueDef::BlockParam(param_block, index, _) if param_block == block => {
|
||||||
|
ForwardingArg::BlockParam(index)
|
||||||
|
}
|
||||||
|
_ => ForwardingArg::Value(arg),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Some(Forwarding {
|
||||||
|
to: target.block,
|
||||||
|
args,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewrite_target(forwardings: &[Option<Forwarding>], target: &BlockTarget) -> Option<BlockTarget> {
|
||||||
|
if !forwardings[target.block.index()].is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut forwarding = Cow::Borrowed(forwardings[target.block.index()].as_ref().unwrap());
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
while forwardings[forwarding.to.index()].is_some() && seen.insert(forwarding.to.index()) {
|
||||||
|
forwarding = Cow::Owned(Forwarding::compose(
|
||||||
|
&forwarding,
|
||||||
|
forwardings[forwarding.to.index()].as_ref().unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = forwarding
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|arg| match arg {
|
||||||
|
&ForwardingArg::Value(v) => v,
|
||||||
|
&ForwardingArg::BlockParam(idx) => target.args[idx],
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Some(BlockTarget {
|
||||||
|
block: forwarding.to,
|
||||||
|
args,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(body: &mut FunctionBody) {
|
||||||
|
// Identify empty blocks, and to where they should forward.
|
||||||
|
let forwardings = body
|
||||||
|
.blocks
|
||||||
|
.iter()
|
||||||
|
.map(|block| {
|
||||||
|
if block != body.entry {
|
||||||
|
block_to_forwarding(body, block)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Rewrite every target according to a forwarding (or potentially
|
||||||
|
// a chain of composed forwardings).
|
||||||
|
for block_data in body.blocks.values_mut() {
|
||||||
|
block_data.terminator.update_targets(|target| {
|
||||||
|
if let Some(new_target) = rewrite_target(&forwardings[..], target) {
|
||||||
|
*target = new_target;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recompute preds/succs.
|
||||||
|
body.recompute_edges();
|
||||||
|
}
|
Loading…
Reference in a new issue