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:
Jakob Stoklund Olesen
2018-01-24 13:44:51 -08:00
parent 416b21c18d
commit d56ce9e8bf
2 changed files with 24 additions and 12 deletions

View File

@@ -138,7 +138,7 @@ impl DominatorTree {
/// Find the last instruction in `a` that dominates `b`. /// Find the last instruction in `a` that dominates `b`.
/// If no instructions in `a` dominate `b`, return `None`. /// 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 where
B: Into<ExpandedProgramPoint>, B: Into<ExpandedProgramPoint>,
{ {

View File

@@ -779,21 +779,33 @@ impl DomForest {
// not necessarily mean that `top.def` dominates `node.def`, though. The `top.def` // 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 // program point may be below the last branch in `top.ebb` that dominates
// `node.def`. // `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 // 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 // will be on the stack. We just need to find the last stack entry that actually
// dominates. // dominates.
// let mut last_dom = node.def;
// TODO: This search could be more efficient if we had access to for &n in self.stack.iter().rev().skip(1) {
// `domtree.last_dominator()`. Each call to `dominates()` here ends up walking up // If the node is defined at the EBB header, it does in fact dominate
// the dominator tree starting from `node.ebb`. // everything else pushed on the stack.
let last_dom = self.stack[0..self.stack.len() - 1].iter().rposition(|n| { let def_inst = match n.def {
domtree.dominates(n.def, node.def, &func.layout) ExpandedProgramPoint::Ebb(_) => return Some(n),
}); ExpandedProgramPoint::Inst(i) => i,
};
// If there is a dominating parent value, return it for interference checking. // We need to find the last program point in `n.ebb` to dominate `node.def`.
return last_dom.map(|pos| self.stack[pos]); 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;
} }
} }