public int FindLoops() { BasicBlock startNode = cfg.StartNode; if (startNode == null) { return(0); } int size = cfg.GetNumNodes(); // init var non_back_preds = new List <Dictionary <int, bool> >(); var back_preds = new List <List <int> >(); var header = new List <int>(); var types = new List <int>(); var last = new List <int>(); var nodes = new List <UnionFindNode>(); var number = new Dictionary <BasicBlock, int>(); for (int i = 0; i < size; ++i) { non_back_preds.Add(new Dictionary <int, bool>()); back_preds.Add(new List <int>()); header.Add(0); types.Add(0); last.Add(0); nodes.Add(new UnionFindNode()); } // Step a: // - initialize all nodes as unvisited. // - depth-first traversal and numbering. // - unreached BB's are marked as dead. foreach (var pair in cfg.BasicBlockMap) { number[pair.Value] = UNVISITED; } DSF(startNode, nodes, number, last, 0); // Step b: // - iterate over all nodes. // A backedge comes from a descendant in the DFS tree, and non-backedges // from non-descendants (following Tarjan). // - check incoming edges 'v' and add them to either // - the list of backedges (backPreds) or // - the list of non-backedges (nonBackPreds) for (int w = 0; w < size; ++w) { header[w] = 0; types[w] = BB_NONHEADER; var nodeW = nodes[w].BB; if (nodeW != null) { foreach (var nodeV in nodeW.InEdges) { var v = number[nodeV]; if (v != UNVISITED) { if (IsAncestor(w, v, last)) { back_preds[w].Add(v); } else { non_back_preds[w][v] = true; } } } } else { types[w] = BB_DEAD; } } // Start node is root of all other loops. header[0] = 0; // Step c: // The outer loop, unchanged from Tarjan. It does nothing except // for those nodes which are the destinations of backedges. // For a header node w, we chase backward from the sources of the // backedges adding nodes to the set P, representing the body of // the loop headed by w. // By running through the nodes in reverse of the DFST preorder, // we ensure that inner loop headers will be processed before the // headers for surrounding loops. for (int w = size - 1; w >= 0; --w) { // this is 'P' in Havlak's paper var nodePool = new List <UnionFindNode>(); var nodeW = nodes[w].BB; if (nodeW != null) // dead BB { // Step d: foreach (var v in back_preds[w]) { if (v != w) { nodePool.Add(nodes[v].FindSet()); } else { types[w] = BB_SELF; } } var workList = new List <UnionFindNode>(nodePool); if (nodePool.Count != 0) { types[w] = BB_REDUCIBLE; } while (workList.Count > 0) { var x = workList[0]; workList.RemoveAt(0); // Step e: // Step e represents the main difference from Tarjan's method. // Chasing upwards from the sources of a node w's backedges. If // there is a node y' that is not a descendant of w, w is marked // the header of an irreducible loop, there is another entry // into this loop that avoids w. // The algorithm has degenerated. Break and // return in this case. var nonBackSize = non_back_preds[x.DfsNumber].Count; if (nonBackSize > MAXNONBACKPREDS) { return(0); } foreach (var iter in non_back_preds[x.DfsNumber]) { var y = nodes[iter.Key]; var ydash = y.FindSet(); if (!IsAncestor(w, ydash.DfsNumber, last)) { types[w] = BB_IRREDUCIBLE; int dsfnum = ydash.DfsNumber; non_back_preds[w][dsfnum] = true; } else { if (ydash.DfsNumber != w && !nodePool.Contains(ydash)) { workList.Add(ydash); nodePool.Add(ydash); } } } } // Collapse/Unionize nodes in a SCC to a single node // For every SCC found, create a loop descriptor and link it in. if ((nodePool.Count > 0) || (types[w] == BB_SELF)) { var loop = lsg.CreateNewLoop(); loop.SetHeader(nodeW); loop.IsReducible = (types[w] != BB_IRREDUCIBLE); nodes[w].Loop = loop; foreach (var node in nodePool) { // Add nodes to loop descriptor. header[node.DfsNumber] = w; node.UnionParent(nodes[w]); if (node.Loop != null) { node.Loop.SetParent(loop); } else { loop.AddNode(node.BB); } } lsg.AddLoop(loop); } } } return(lsg.GetNumLoops()); }