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:
@@ -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(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -42,4 +42,5 @@ mod scoped_hash_map;
|
||||
mod simple_gvn;
|
||||
mod stack_layout;
|
||||
mod topo_order;
|
||||
mod unreachable_code;
|
||||
mod write;
|
||||
|
||||
43
lib/cretonne/src/unreachable_code.rs
Normal file
43
lib/cretonne/src/unreachable_code.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user