// // findLoops // // Find loops and build loop forest using Havlak's algorithm, which // is derived from Tarjan. Variable names and step numbering has // been chosen to be identical to the nomenclature in Havlak's // paper (which, in turn, is similar to the one used by Tarjan). // public void findLoops() { if (cfg.getStartBasicBlock() == null) { return; } long startMillis = CurrentTimeMillis(); int size = cfg.getNumNodes(); nonBackPreds.Clear(); backPreds.Clear(); number.Clear(); if (size > maxSize) { header = new int[size]; type = new BasicBlockClass[size]; last = new int[size]; nodes = new UnionFindNode[size]; maxSize = size; } /* * List<Set<Integer>> nonBackPreds = new ArrayList<Set<Integer>>(); * List<List<Integer>> backPreds = new ArrayList<List<Integer>>(); * * Map<BasicBlock, Integer> number = new HashMap<BasicBlock, Integer>(); * int[] header = new int[size]; * BasicBlockClass[] type = new BasicBlockClass[size]; * int[] last = new int[size]; * UnionFindNode[] nodes = new UnionFindNode[size]; */ for (int i = 0; i < size; ++i) { //nonBackPreds.Add(freeListSet.Count == 0 ? new HashSet<int>() : freeListSet.RemoveFirst().Clear()); if (freeListList.Count == 0) { nonBackPreds.Add(new HashSet <int>()); } else { var node = freeListSet.First; freeListSet.RemoveFirst(); node.Value.Clear(); nonBackPreds.Add(node.Value); } //backPreds.Add(freeListList.Count == 0 ? new List<int>() : freeListList.RemoveFirst().Clear()); if (freeListList.Count == 0) { backPreds.Add(new List <int>()); } else { var node = freeListList.First; freeListList.RemoveFirst(); node.Value.Clear(); backPreds.Add(node.Value); } nodes[i] = new UnionFindNode(); } // Step a: // - initialize all nodes as unvisited. // - depth-first traversal and numbering. // - unreached BB's are marked as dead. // foreach (var bbIter in cfg.getBasicBlocks().values()) { number.Add(bbIter, UNVISITED); } doDFS(cfg.getStartBasicBlock(), 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; type[w] = BasicBlockClass.BB_NONHEADER; BasicBlock nodeW = nodes[w].getBb(); if (nodeW == null) { type[w] = BasicBlockClass.BB_DEAD; continue; // dead BB } if (nodeW.getNumPred() > 0) { int len1 = nodeW.getInEdges().size(); for (int i = 0; i < len1; i++) { // for (BasicBlock nodeV : nodeW.getInEdges()) { BasicBlock nodeV = nodeW.getInEdges().get(i); int v = number[nodeV]; if (v == UNVISITED) { continue; // dead node } if (isAncestor(w, v, last)) { backPreds[w].Add(v); } else { nonBackPreds[w].Add(v); } } } } // 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 LinkedList <UnionFindNode> nodePool = new LinkedList <UnionFindNode>(); BasicBlock nodeW = nodes[w].getBb(); if (nodeW == null) { continue; // dead BB } // Step d: int len = backPreds[w].Count; for (int i = 0; i < len; i++) { int v = backPreds[w][i]; // for (int v : backPreds.get(w)) { if (v != w) { nodePool.AddLast(nodes[v].findSet()); } else { type[w] = BasicBlockClass.BB_SELF; } } // Copy nodePool to workList. // LinkedList <UnionFindNode> workList = new LinkedList <UnionFindNode>(); foreach (var niter in nodePool) { workList.AddLast(niter); } if (nodePool.Count != 0) { type[w] = BasicBlockClass.BB_REDUCIBLE; } // work the list... // while (workList.Count != 0) // while (!workList.isEmpty()) { LinkedListNode <UnionFindNode> x = workList.First; workList.RemoveFirst(); // 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. // int nonBackSize = nonBackPreds[x.Value.getDfsNumber()].Count; if (nonBackSize > MAXNONBACKPREDS) { return; } HashSet <int> curr = nonBackPreds[x.Value.getDfsNumber()]; foreach (var iter in curr) { UnionFindNode y = nodes[iter]; UnionFindNode ydash = y.findSet(); if (!isAncestor(w, ydash.getDfsNumber(), last)) { type[w] = BasicBlockClass.BB_IRREDUCIBLE; nonBackPreds[w].Add(ydash.getDfsNumber()); } else { if (ydash.getDfsNumber() != w) { if (!nodePool.Contains(ydash)) { workList.AddLast(ydash); nodePool.AddLast(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) || (type[w] == BasicBlockClass.BB_SELF)) { SimpleLoop loop = lsg.createNewLoop(); loop.setHeader(nodeW); loop.setIsReducible(type[w] != BasicBlockClass.BB_IRREDUCIBLE); // At this point, one can set attributes to the loop, such as: // // the bottom node: // iter = backPreds[w].begin(); // loop bottom is: nodes[iter].node); // // the number of backedges: // backPreds[w].size() // // whether this loop is reducible: // type[w] != BasicBlockClass.BB_IRREDUCIBLE // nodes[w].setLoop(loop); foreach (var node in nodePool) { // Add nodes to loop descriptor. header[node.getDfsNumber()] = w; node.union(nodes[w]); // Nested loops are not added, but linked together. if (node.getLoop() != null) { node.getLoop().setParent(loop); } else { loop.addNode(node.getBb()); } } lsg.addLoop(loop); } // nodePool.size } // Step c long totalMillis = CurrentTimeMillis() - startMillis; if (totalMillis > maxMillis) { maxMillis = totalMillis; } if (totalMillis < minMillis) { minMillis = totalMillis; } for (int i = 0; i < size; ++i) { freeListSet.AddLast(nonBackPreds[i]); // Add() in Java LinkedList adds to the end freeListList.AddLast(backPreds[i]); nodes[i] = new UnionFindNode(); } } // findLoops