Add an unreachable code elimination pass.

The register allocator doesn't even try to compile unreachable EBBs, so
any values defined in such blocks won't be assigned registers.

Since the dominator tree already has determined which EBBs are
reachable, we should just eliminate any unreachable blocks instead o
trying to do something with the dead code.

Not that this is not a "dead code elimination" pass which would also
remove individual instructions whose results are not used.
This commit is contained in:
Jakob Stoklund Olesen
2017-10-09 15:24:15 -07:00
parent 6aeeaebbd3
commit 90ed698e83
5 changed files with 126 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ use legalize_function;
use regalloc;
use result::{CtonError, CtonResult};
use settings::{FlagsOrIsa, OptLevel};
use unreachable_code::eliminate_unreachable_code;
use verifier;
use simple_gvn::do_simple_gvn;
use licm::do_licm;
@@ -75,6 +76,7 @@ impl Context {
self.simple_gvn(isa)?;
}
self.compute_domtree();
self.eliminate_unreachable_code(isa)?;
self.regalloc(isa)?;
self.prologue_epilogue(isa)?;
self.relax_branches(isa)
@@ -159,6 +161,15 @@ impl Context {
self.verify_if(fisa)
}
/// Perform unreachable code elimination.
pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CtonResult
where
FOI: Into<FlagsOrIsa<'a>>,
{
eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
self.verify_if(fisa)
}
/// Run the register allocator.
pub fn regalloc(&mut self, isa: &TargetIsa) -> CtonResult {
self.regalloc.run(

View File

@@ -360,6 +360,32 @@ impl Layout {
self.assign_ebb_seq(ebb);
}
/// Remove `ebb` from the layout.
pub fn remove_ebb(&mut self, ebb: Ebb) {
assert!(self.is_ebb_inserted(ebb), "EBB not in the layout");
assert!(self.first_inst(ebb).is_none(), "EBB must be empty.");
// Clear the `ebb` node and extract links.
let prev;
let next;
{
let n = &mut self.ebbs[ebb];
prev = n.prev;
next = n.next;
n.prev = None.into();
n.next = None.into();
}
// Fix up links to `ebb`.
match prev.expand() {
None => self.first_ebb = next.expand(),
Some(p) => self.ebbs[p].next = next,
}
match next.expand() {
None => self.last_ebb = prev.expand(),
Some(n) => self.ebbs[n].prev = prev,
}
}
/// Return an iterator over all EBBs in layout order.
pub fn ebbs<'f>(&'f self) -> Ebbs<'f> {
Ebbs {

View File

@@ -42,4 +42,5 @@ mod scoped_hash_map;
mod simple_gvn;
mod stack_layout;
mod topo_order;
mod unreachable_code;
mod write;

View File

@@ -0,0 +1,43 @@
//! Unreachable code elimination.
use cursor::{Cursor, FuncCursor};
use dominator_tree::DominatorTree;
use flowgraph::ControlFlowGraph;
use ir;
/// Eliminate unreachable code.
///
/// This pass deletes whole EBBs that can't be reached from the entry block. It does not delete
/// individual instructions whose results are unused.
///
/// The reachability analysis is performed by the dominator tree analysis.
pub fn eliminate_unreachable_code(
func: &mut ir::Function,
cfg: &mut ControlFlowGraph,
domtree: &DominatorTree,
) {
let mut pos = FuncCursor::new(func);
while let Some(ebb) = pos.next_ebb() {
if domtree.is_reachable(ebb) {
continue;
}
dbg!("Eliminating unreachable {}", ebb);
// Move the cursor out of the way and make sure the next lop iteration goes to the right
// EBB.
pos.prev_ebb();
// Remove all instructions from `ebb`.
while let Some(inst) = pos.func.layout.first_inst(ebb) {
dbg!(" - {}", pos.func.dfg.display_inst(inst, None));
pos.func.layout.remove_inst(inst);
}
// Once the EBB is completely empty, we can update the CFG which removes it from any
// predecessor lists.
cfg.recompute_ebb(pos.func, ebb);
// Finally, remove the EBB from the layout.
pos.func.layout.remove_ebb(ebb);
}
}