Example #1
0
        //
        // 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