Make the DominatorTree reusable.

Add a compute() method which can recompute a dominator tree for
different functions.

Add a dominator tree data to the cretonne::Context.
This commit is contained in:
Jakob Stoklund Olesen
2017-02-17 13:09:41 -08:00
parent 77a7ad88f4
commit 85fa68023c
3 changed files with 37 additions and 14 deletions

View File

@@ -41,7 +41,7 @@ impl SubTest for TestDomtree {
fn run(&self, func: Cow<Function>, context: &Context) -> Result<()> { fn run(&self, func: Cow<Function>, context: &Context) -> Result<()> {
let func = func.borrow(); let func = func.borrow();
let cfg = ControlFlowGraph::with_function(func); let cfg = ControlFlowGraph::with_function(func);
let domtree = DominatorTree::new(func, &cfg); let domtree = DominatorTree::with_function(func, &cfg);
// Build an expected domtree from the source annotations. // Build an expected domtree from the source annotations.
let mut expected = HashMap::new(); let mut expected = HashMap::new();

View File

@@ -5,6 +5,7 @@
//! on to memory allocations between function compilations. //! on to memory allocations between function compilations.
use cfg::ControlFlowGraph; use cfg::ControlFlowGraph;
use dominator_tree::DominatorTree;
use ir::Function; use ir::Function;
/// Persistent data structures and compilation pipeline. /// Persistent data structures and compilation pipeline.
@@ -14,6 +15,9 @@ pub struct Context {
/// The control flow graph of `func`. /// The control flow graph of `func`.
pub cfg: ControlFlowGraph, pub cfg: ControlFlowGraph,
/// Dominator tree for `func`.
pub domtree: DominatorTree,
} }
impl Context { impl Context {
@@ -25,6 +29,13 @@ impl Context {
Context { Context {
func: Function::new(), func: Function::new(),
cfg: ControlFlowGraph::new(), cfg: ControlFlowGraph::new(),
domtree: DominatorTree::new(),
} }
} }
/// Recompute the control flow graph and dominator tree.
pub fn flowgraph(&mut self) {
self.cfg.compute(&self.func);
self.domtree.compute(&self.func, &self.cfg);
}
} }

View File

@@ -119,10 +119,24 @@ impl DominatorTree {
} }
impl DominatorTree { impl DominatorTree {
/// Allocate a new blank dominator tree. Use `compute` to compute the dominator tree for a
/// function.
pub fn new() -> DominatorTree {
DominatorTree { nodes: EntityMap::new() }
}
/// Allocate and compute a dominator tree.
pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> DominatorTree {
let mut domtree = DominatorTree::new();
domtree.compute(func, cfg);
domtree
}
/// Build a dominator tree from a control flow graph using Keith D. Cooper's /// Build a dominator tree from a control flow graph using Keith D. Cooper's
/// "Simple, Fast Dominator Algorithm." /// "Simple, Fast Dominator Algorithm."
pub fn new(func: &Function, cfg: &ControlFlowGraph) -> DominatorTree { pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) {
let mut domtree = DominatorTree { nodes: EntityMap::with_capacity(func.dfg.num_ebbs()) }; self.nodes.clear();
self.nodes.resize(func.dfg.num_ebbs());
// We'll be iterating over a reverse post-order of the CFG. // We'll be iterating over a reverse post-order of the CFG.
// This vector only contains reachable EBBs. // This vector only contains reachable EBBs.
@@ -132,12 +146,12 @@ impl DominatorTree {
// The last block visited in a post-order traversal must be the entry block. // The last block visited in a post-order traversal must be the entry block.
let entry_block = match postorder.pop() { let entry_block = match postorder.pop() {
Some(ebb) => ebb, Some(ebb) => ebb,
None => return domtree, None => return,
}; };
assert_eq!(Some(entry_block), func.layout.entry_block()); assert_eq!(Some(entry_block), func.layout.entry_block());
// Do a first pass where we assign RPO numbers to all reachable nodes. // Do a first pass where we assign RPO numbers to all reachable nodes.
domtree.nodes[entry_block].rpo_number = 1; self.nodes[entry_block].rpo_number = 1;
for (rpo_idx, &ebb) in postorder.iter().rev().enumerate() { for (rpo_idx, &ebb) in postorder.iter().rev().enumerate() {
// Update the current node and give it an RPO number. // Update the current node and give it an RPO number.
// The entry block got 1, the rest start at 2. // The entry block got 1, the rest start at 2.
@@ -148,8 +162,8 @@ impl DominatorTree {
// //
// Due to the nature of the post-order traversal, every node we visit will have at // Due to the nature of the post-order traversal, every node we visit will have at
// least one predecessor that has previously been visited during this RPO. // least one predecessor that has previously been visited during this RPO.
domtree.nodes[ebb] = DomNode { self.nodes[ebb] = DomNode {
idom: domtree.compute_idom(ebb, cfg, &func.layout).into(), idom: self.compute_idom(ebb, cfg, &func.layout).into(),
rpo_number: rpo_idx as u32 + 2, rpo_number: rpo_idx as u32 + 2,
} }
} }
@@ -162,15 +176,13 @@ impl DominatorTree {
while changed { while changed {
changed = false; changed = false;
for &ebb in postorder.iter().rev() { for &ebb in postorder.iter().rev() {
let idom = domtree.compute_idom(ebb, cfg, &func.layout).into(); let idom = self.compute_idom(ebb, cfg, &func.layout).into();
if domtree.nodes[ebb].idom != idom { if self.nodes[ebb].idom != idom {
domtree.nodes[ebb].idom = idom; self.nodes[ebb].idom = idom;
changed = true; changed = true;
} }
} }
} }
domtree
} }
// Compute the immediate dominator for `ebb` using the current `idom` states for the reachable // Compute the immediate dominator for `ebb` using the current `idom` states for the reachable
@@ -204,7 +216,7 @@ mod test {
fn empty() { fn empty() {
let func = Function::new(); let func = Function::new();
let cfg = ControlFlowGraph::with_function(&func); let cfg = ControlFlowGraph::with_function(&func);
let dtree = DominatorTree::new(&func, &cfg); let dtree = DominatorTree::with_function(&func, &cfg);
assert_eq!(0, dtree.nodes.keys().count()); assert_eq!(0, dtree.nodes.keys().count());
} }
@@ -239,7 +251,7 @@ mod test {
} }
let cfg = ControlFlowGraph::with_function(&func); let cfg = ControlFlowGraph::with_function(&func);
let dt = DominatorTree::new(&func, &cfg); let dt = DominatorTree::with_function(&func, &cfg);
assert_eq!(func.layout.entry_block().unwrap(), ebb3); assert_eq!(func.layout.entry_block().unwrap(), ebb3);
assert_eq!(dt.idom(ebb3), None); assert_eq!(dt.idom(ebb3), None);