public static CfgLoop GetLoopInformation(ControlFlowGraph graph, List <int> nodes) { if (nodes == null) { throw new ArgumentNullException(nameof(nodes)); } if (nodes.Count == 0) { throw new ArgumentException("Empty loop provided to GetLoopInformation", nameof(nodes)); } var body = new List <LoopPart>(); var header = new LoopPart(nodes[0], true); var exits = new HashSet <int>(); // Determine if header can break out of the loop foreach (int child in graph.Children(nodes[0])) { if (nodes.Contains(child)) { continue; } CfgEdge edgeLabel = graph.GetEdgeLabel(nodes[0], child); if (edgeLabel == CfgEdge.LoopSuccessor) // Loop successor pseudo-edges don't count for break-detection { continue; } header = new LoopPart(header.Index, true, Break: true, Negated: edgeLabel == CfgEdge.True); exits.Add(child); } for (int i = 1; i < nodes.Count; i++) { var node = nodes[i]; bool isContinue = false; bool isBreak = false; bool isTail = true; bool negated = false; foreach (int child in graph.Children(node)) { // Func<string> vis = () => ToVis().AddPointer("i", node).AddPointer("child", child).ToString(); // For VS Code debug visualisation if (child == header.Index) // Jump to header = possible continue { isContinue = true; } else if (nodes.Contains(child)) { isTail = false; } else { negated = graph.GetEdgeLabel(node, child) == CfgEdge.False; isBreak = true; exits.Add(child); } } bool hasOutsideEntry = Enumerable.Any(graph.Parents(node), x => !nodes.Contains(x)); body.Add(new LoopPart(node, false, isTail, isBreak, isContinue, hasOutsideEntry, negated)); } var postDom = graph.GetPostDominatorTree(); int?mainExit = postDom.ImmediateDominator(header.Index); while (mainExit.HasValue && body.Any(x => !postDom.Dominates(mainExit.Value, x.Index))) { mainExit = postDom.ImmediateDominator(mainExit.Value); } if (body.Count(x => x.Tail) > 1) // Only allow one tail, pick one of the nodes with the longest path from the header. { var longestPaths = new Dictionary <int, int>(); for (int i = 0; i < body.Count; i++) { var part = body[i]; if (!part.Tail) { continue; } var paths = graph.GetAllReachingPaths(header.Index, part.Index); longestPaths[i] = paths.Select(x => x.Count).Max(); } var longestDistance = longestPaths.Values.Max(); var winner = longestPaths.First(x => x.Value == longestDistance).Key; foreach (var kvp in longestPaths) { if (kvp.Key == winner) { continue; } var part = body[kvp.Key]; body[kvp.Key] = new LoopPart(part.Index, part.Header, false, part.Break, part.Continue, part.OutsideEntry, part.Negated); } } return(new CfgLoop(header, body.ToImmutableList(), exits.ToImmutableList(), mainExit)); }