Optimize DomForest::push_node().
The dominator tree pre-order is defined at the EBB granularity, but we are looking for dominating nodes at the instruction level. This means that we sometimes need to look higher up the DomForest stack for a dominating node, using DominatorTree::dominates() instead of DominatorTreePreorder::dominates(). Each dominance check involves the domtree.last_dominator() function scanning up the dominator tree, starting from the new node that was pushed. We can eliminate this duplicate work by exposing the last_dominator() function to push_node(). As we are searching through nodes on the stack, maintain a last_dom program point representing the previous return value from last_dominator(). This way, we're only scanning the dominator tree once.
This commit is contained in:
@@ -138,7 +138,7 @@ impl DominatorTree {
|
||||
|
||||
/// Find the last instruction in `a` that dominates `b`.
|
||||
/// If no instructions in `a` dominate `b`, return `None`.
|
||||
fn last_dominator<B>(&self, a: Ebb, b: B, layout: &Layout) -> Option<Inst>
|
||||
pub fn last_dominator<B>(&self, a: Ebb, b: B, layout: &Layout) -> Option<Inst>
|
||||
where
|
||||
B: Into<ExpandedProgramPoint>,
|
||||
{
|
||||
|
||||
@@ -779,21 +779,33 @@ impl DomForest {
|
||||
// not necessarily mean that `top.def` dominates `node.def`, though. The `top.def`
|
||||
// program point may be below the last branch in `top.ebb` that dominates
|
||||
// `node.def`.
|
||||
debug_assert!(domtree.dominates(top.ebb, node.def, &func.layout));
|
||||
|
||||
//
|
||||
// We do know, though, that if there is a nearest value dominating `node.def`, it
|
||||
// will be on the stack. We just need to find the last stack entry that actually
|
||||
// dominates.
|
||||
//
|
||||
// TODO: This search could be more efficient if we had access to
|
||||
// `domtree.last_dominator()`. Each call to `dominates()` here ends up walking up
|
||||
// the dominator tree starting from `node.ebb`.
|
||||
let last_dom = self.stack[0..self.stack.len() - 1].iter().rposition(|n| {
|
||||
domtree.dominates(n.def, node.def, &func.layout)
|
||||
});
|
||||
let mut last_dom = node.def;
|
||||
for &n in self.stack.iter().rev().skip(1) {
|
||||
// If the node is defined at the EBB header, it does in fact dominate
|
||||
// everything else pushed on the stack.
|
||||
let def_inst = match n.def {
|
||||
ExpandedProgramPoint::Ebb(_) => return Some(n),
|
||||
ExpandedProgramPoint::Inst(i) => i,
|
||||
};
|
||||
|
||||
// If there is a dominating parent value, return it for interference checking.
|
||||
return last_dom.map(|pos| self.stack[pos]);
|
||||
// We need to find the last program point in `n.ebb` to dominate `node.def`.
|
||||
last_dom = match domtree.last_dominator(n.ebb, last_dom, &func.layout) {
|
||||
None => n.ebb.into(),
|
||||
Some(inst) => {
|
||||
if func.layout.cmp(def_inst, inst) != cmp::Ordering::Greater {
|
||||
return Some(n);
|
||||
}
|
||||
inst.into()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// No real dominator found on the stack.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user