Dampen quadratic behavior in check_cssa().

Use a dominator tree pre-order to speed up the dominance checks and only
check for interference with the nearest dominating predecessor in a
virtual register.

This makes the CSSA verification about 2x as fast.
This commit is contained in:
Jakob Stoklund Olesen
2018-01-22 10:48:14 -08:00
parent 91343f208d
commit c6bb7afa07

View File

@@ -1,7 +1,7 @@
//! Verify conventional SSA form. //! Verify conventional SSA form.
use dbg::DisplayList; use dbg::DisplayList;
use dominator_tree::DominatorTree; use dominator_tree::{DominatorTree, DominatorTreePreorder};
use flowgraph::ControlFlowGraph; use flowgraph::ControlFlowGraph;
use ir::{Function, ExpandedProgramPoint}; use ir::{Function, ExpandedProgramPoint};
use regalloc::liveness::Liveness; use regalloc::liveness::Liveness;
@@ -31,12 +31,17 @@ pub fn verify_cssa(
virtregs: &VirtRegs, virtregs: &VirtRegs,
) -> Result { ) -> Result {
let _tt = timing::verify_cssa(); let _tt = timing::verify_cssa();
let mut preorder = DominatorTreePreorder::new();
preorder.compute(domtree, &func.layout);
let verifier = CssaVerifier { let verifier = CssaVerifier {
func, func,
cfg, cfg,
domtree, domtree,
virtregs, virtregs,
liveness, liveness,
preorder,
}; };
verifier.check_virtregs()?; verifier.check_virtregs()?;
verifier.check_cssa()?; verifier.check_cssa()?;
@@ -49,6 +54,7 @@ struct CssaVerifier<'a> {
domtree: &'a DominatorTree, domtree: &'a DominatorTree,
virtregs: &'a VirtRegs, virtregs: &'a VirtRegs,
liveness: &'a Liveness, liveness: &'a Liveness,
preorder: DominatorTreePreorder,
} }
impl<'a> CssaVerifier<'a> { impl<'a> CssaVerifier<'a> {
@@ -72,6 +78,7 @@ impl<'a> CssaVerifier<'a> {
let def_ebb = self.func.layout.pp_ebb(def); let def_ebb = self.func.layout.pp_ebb(def);
for &prev_val in &values[0..idx] { for &prev_val in &values[0..idx] {
let prev_def: ExpandedProgramPoint = self.func.dfg.value_def(prev_val).into(); let prev_def: ExpandedProgramPoint = self.func.dfg.value_def(prev_val).into();
let prev_ebb = self.func.layout.pp_ebb(prev_def);
if prev_def == def { if prev_def == def {
return err!( return err!(
@@ -85,7 +92,9 @@ impl<'a> CssaVerifier<'a> {
} }
// Enforce topological ordering of defs in the virtual register. // Enforce topological ordering of defs in the virtual register.
if self.domtree.dominates(def, prev_def, &self.func.layout) { if self.preorder.dominates(def_ebb, prev_ebb) &&
self.domtree.dominates(def, prev_def, &self.func.layout)
{
return err!( return err!(
val, val,
"Value in {} = {} def dominates previous {}", "Value in {} = {} def dominates previous {}",
@@ -94,18 +103,30 @@ impl<'a> CssaVerifier<'a> {
prev_val prev_val
); );
} }
}
// Knowing that values are in topo order, we can check for interference this // Knowing that values are in topo order, we can check for interference this
// way. // way.
let ctx = self.liveness.context(&self.func.layout); // We only have to check against the nearest dominating value.
if self.liveness[prev_val].overlaps_def(def, def_ebb, ctx) { for &prev_val in values[0..idx].iter().rev() {
return err!( let prev_def: ExpandedProgramPoint = self.func.dfg.value_def(prev_val).into();
val, let prev_ebb = self.func.layout.pp_ebb(prev_def);
"Value def in {} = {} interferes with {}",
vreg, if self.preorder.dominates(prev_ebb, def_ebb) &&
DisplayList(values), self.domtree.dominates(prev_def, def, &self.func.layout)
prev_val {
); let ctx = self.liveness.context(&self.func.layout);
if self.liveness[prev_val].overlaps_def(def, def_ebb, ctx) {
return err!(
val,
"Value def in {} = {} interferes with {}",
vreg,
DisplayList(values),
prev_val
);
} else {
break;
}
} }
} }
} }