Browse Source

Property validate exit points determined using post-dominance.

pull/887/head
Daniel Grunwald 8 years ago
parent
commit
cd993ad074
  1. 49
      ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs

49
ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs

@ -293,22 +293,63 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -293,22 +293,63 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
commonAncestor = Dominance.FindCommonDominator(commonAncestor, revNode);
}
}
// All paths from within the loop to a reachable exit run through 'commonAncestor'.
// However, this doesn't mean that 'commonAncestor' is valid as an exit point.
// We walk up the post-dominator tree until we've got a valid exit point:
ControlFlowNode exitPoint;
while (commonAncestor.UserIndex >= 0) {
exitPoint = cfg[commonAncestor.UserIndex];
Debug.Assert(exitPoint.Visited == naturalLoop.Contains(exitPoint));
if (exitPoint.Visited) {
commonAncestor = commonAncestor.ImmediateDominator;
continue;
} else {
// It's possible that 'commonAncestor' is itself part of the natural loop.
// If so, it's not a valid exit point.
if (!exitPoint.Visited && ValidateExitPoint(loopHead, exitPoint)) {
// we found an exit point
return exitPoint;
}
commonAncestor = commonAncestor.ImmediateDominator;
}
// least common post-dominator is the artificial exit node
return null;
}
}
/// <summary>
/// Validates an exit point.
///
/// An exit point is invalid iff there is a node reachable from the exit point that
/// is dominated by the loop head, but not by the exit point.
/// (i.e. this method returns false iff the exit point's dominance frontier contains
/// a node dominated by the loop head. but we implement this the slow way because
/// we don't have dominance frontiers precomputed)
/// </summary>
/// <remarks>
/// We need this because it's possible that there's a return block (thus reverse-unreachable node ignored by post-dominance)
/// that is reachable both directly from the loop, and from the exit point.
/// </remarks>
bool ValidateExitPoint(ControlFlowNode loopHead, ControlFlowNode exitPoint)
{
var cfg = context.ControlFlowGraph;
return IsValid(exitPoint);
bool IsValid(ControlFlowNode node)
{
if (!cfg.HasReachableExit(node)) {
// Optimization: if the dominance frontier is empty, we don't need
// to check every node.
return true;
}
foreach (var succ in node.Successors) {
if (loopHead.Dominates(succ) && !exitPoint.Dominates(succ))
return false;
}
foreach (var child in node.DominatorTreeChildren) {
if (!IsValid(child))
return false;
}
return true;
}
}
/// <summary>
/// Pick exit point by picking any node that has no reachable exits.
///

Loading…
Cancel
Save