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.
|
//! 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user