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:
@@ -5,6 +5,7 @@
|
||||
//! on to memory allocations between function compilations.
|
||||
|
||||
use cfg::ControlFlowGraph;
|
||||
use dominator_tree::DominatorTree;
|
||||
use ir::Function;
|
||||
|
||||
/// Persistent data structures and compilation pipeline.
|
||||
@@ -14,6 +15,9 @@ pub struct Context {
|
||||
|
||||
/// The control flow graph of `func`.
|
||||
pub cfg: ControlFlowGraph,
|
||||
|
||||
/// Dominator tree for `func`.
|
||||
pub domtree: DominatorTree,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -25,6 +29,13 @@ impl Context {
|
||||
Context {
|
||||
func: Function::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,10 +119,24 @@ 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
|
||||
/// "Simple, Fast Dominator Algorithm."
|
||||
pub fn new(func: &Function, cfg: &ControlFlowGraph) -> DominatorTree {
|
||||
let mut domtree = DominatorTree { nodes: EntityMap::with_capacity(func.dfg.num_ebbs()) };
|
||||
pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) {
|
||||
self.nodes.clear();
|
||||
self.nodes.resize(func.dfg.num_ebbs());
|
||||
|
||||
// We'll be iterating over a reverse post-order of the CFG.
|
||||
// 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.
|
||||
let entry_block = match postorder.pop() {
|
||||
Some(ebb) => ebb,
|
||||
None => return domtree,
|
||||
None => return,
|
||||
};
|
||||
assert_eq!(Some(entry_block), func.layout.entry_block());
|
||||
|
||||
// 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() {
|
||||
// Update the current node and give it an RPO number.
|
||||
// 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
|
||||
// least one predecessor that has previously been visited during this RPO.
|
||||
domtree.nodes[ebb] = DomNode {
|
||||
idom: domtree.compute_idom(ebb, cfg, &func.layout).into(),
|
||||
self.nodes[ebb] = DomNode {
|
||||
idom: self.compute_idom(ebb, cfg, &func.layout).into(),
|
||||
rpo_number: rpo_idx as u32 + 2,
|
||||
}
|
||||
}
|
||||
@@ -162,15 +176,13 @@ impl DominatorTree {
|
||||
while changed {
|
||||
changed = false;
|
||||
for &ebb in postorder.iter().rev() {
|
||||
let idom = domtree.compute_idom(ebb, cfg, &func.layout).into();
|
||||
if domtree.nodes[ebb].idom != idom {
|
||||
domtree.nodes[ebb].idom = idom;
|
||||
let idom = self.compute_idom(ebb, cfg, &func.layout).into();
|
||||
if self.nodes[ebb].idom != idom {
|
||||
self.nodes[ebb].idom = idom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
domtree
|
||||
}
|
||||
|
||||
// Compute the immediate dominator for `ebb` using the current `idom` states for the reachable
|
||||
@@ -204,7 +216,7 @@ mod test {
|
||||
fn empty() {
|
||||
let func = Function::new();
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -239,7 +251,7 @@ mod test {
|
||||
}
|
||||
|
||||
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!(dt.idom(ebb3), None);
|
||||
|
||||
@@ -41,7 +41,7 @@ impl SubTest for TestDomtree {
|
||||
fn run(&self, func: Cow<Function>, context: &Context) -> Result<()> {
|
||||
let func = func.borrow();
|
||||
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.
|
||||
let mut expected = HashMap::new();
|
||||
|
||||
Reference in New Issue
Block a user