Recompute the dominator tree on demand.
The legalizer can invalidate the dominator tree, but we don't actually need a dominator tree during legalization, so defer the construction of the domtree. - Add an "invalid" state to the dominator tree along with clear() and is_valid() methods to test it. - Invalidate the dominator tree as part of legalization. - Ensure that a valid dominator tree exists before the passes that need it. Together these features add up to a manual invalidation mechanism for the dominator tree.
This commit is contained in:
@@ -63,7 +63,7 @@ impl Context {
|
||||
///
|
||||
/// Returns the size of the function's code.
|
||||
pub fn compile(&mut self, isa: &TargetIsa) -> Result<CodeOffset, CtonError> {
|
||||
self.flowgraph();
|
||||
self.cfg.compute(&self.func);
|
||||
self.verify_if(isa)?;
|
||||
|
||||
self.legalize(isa)?;
|
||||
@@ -103,6 +103,8 @@ impl Context {
|
||||
|
||||
/// Run the legalizer for `isa` on the function.
|
||||
pub fn legalize(&mut self, isa: &TargetIsa) -> CtonResult {
|
||||
// Legalization invalidates the domtree by mutating the CFG.
|
||||
self.domtree.clear();
|
||||
legalize_function(&mut self.func, &mut self.cfg, isa);
|
||||
self.verify_if(isa)
|
||||
}
|
||||
@@ -113,6 +115,13 @@ impl Context {
|
||||
self.domtree.compute(&self.func, &self.cfg);
|
||||
}
|
||||
|
||||
/// Ensure that a valid domtree exists.
|
||||
pub fn ensure_domtree(&mut self) {
|
||||
if !self.domtree.is_valid() {
|
||||
self.domtree.compute(&self.func, &self.cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform simple GVN on the function.
|
||||
pub fn simple_gvn(&mut self) -> CtonResult {
|
||||
do_simple_gvn(&mut self.func, &mut self.cfg);
|
||||
@@ -123,6 +132,7 @@ impl Context {
|
||||
|
||||
/// Perform LICM on the function.
|
||||
pub fn licm(&mut self) -> CtonResult {
|
||||
self.ensure_domtree();
|
||||
do_licm(&mut self.func,
|
||||
&mut self.cfg,
|
||||
&mut self.domtree,
|
||||
@@ -132,6 +142,7 @@ impl Context {
|
||||
|
||||
/// Run the register allocator.
|
||||
pub fn regalloc(&mut self, isa: &TargetIsa) -> CtonResult {
|
||||
self.ensure_domtree();
|
||||
self.regalloc
|
||||
.run(isa, &mut self.func, &self.cfg, &self.domtree)
|
||||
}
|
||||
|
||||
@@ -205,14 +205,30 @@ impl DominatorTree {
|
||||
self.compute_domtree(func, cfg);
|
||||
}
|
||||
|
||||
/// Clear the data structures used to represent the dominator tree. This will leave the tree in
|
||||
/// a state where `is_valid()` returns false.
|
||||
pub fn clear(&mut self) {
|
||||
self.nodes.clear();
|
||||
self.postorder.clear();
|
||||
assert!(self.stack.is_empty());
|
||||
}
|
||||
|
||||
/// Check if the dominator tree is in a valid state.
|
||||
///
|
||||
/// Note that this doesn't perform any kind of validity checks. It simply checks if the
|
||||
/// `compute()` method has been called since the last `clear()`. It does not check that the
|
||||
/// dominator tree is consistent
|
||||
/// with the CFG>
|
||||
pub fn is_valid(&self) -> bool {
|
||||
!self.nodes.is_empty()
|
||||
}
|
||||
|
||||
/// Reset all internal data structures and compute a post-order for `cfg`.
|
||||
///
|
||||
/// This leaves `rpo_number == 1` for all reachable EBBs, 0 for unreachable ones.
|
||||
fn compute_postorder(&mut self, func: &Function, cfg: &ControlFlowGraph) {
|
||||
self.nodes.clear();
|
||||
self.clear();
|
||||
self.nodes.resize(func.dfg.num_ebbs());
|
||||
self.postorder.clear();
|
||||
assert!(self.stack.is_empty());
|
||||
|
||||
// During this algorithm only, use `rpo_number` to hold the following state:
|
||||
//
|
||||
|
||||
@@ -134,7 +134,9 @@ pub fn verify_context(func: &Function,
|
||||
-> Result {
|
||||
let verifier = Verifier::new(func, isa);
|
||||
verifier.cfg_integrity(cfg)?;
|
||||
if domtree.is_valid() {
|
||||
verifier.domtree_integrity(domtree)?;
|
||||
}
|
||||
verifier.run()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user