Пример #1
0
            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());
            }