10b57cec5SDimitry Andric //===- ADT/SCCIterator.h - Strongly Connected Comp. Iter. -------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This builds on the llvm/ADT/GraphTraits.h file to find the strongly
110b57cec5SDimitry Andric /// connected components (SCCs) of a graph in O(N+E) time using Tarjan's DFS
120b57cec5SDimitry Andric /// algorithm.
130b57cec5SDimitry Andric ///
140b57cec5SDimitry Andric /// The SCC iterator has the important property that if a node in SCC S1 has an
150b57cec5SDimitry Andric /// edge to a node in SCC S2, then it visits S1 *after* S2.
160b57cec5SDimitry Andric ///
170b57cec5SDimitry Andric /// To visit S1 *before* S2, use the scc_iterator on the Inverse graph. (NOTE:
180b57cec5SDimitry Andric /// This requires some simple wrappers and is not supported yet.)
190b57cec5SDimitry Andric ///
200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #ifndef LLVM_ADT_SCCITERATOR_H
230b57cec5SDimitry Andric #define LLVM_ADT_SCCITERATOR_H
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
2606c3fb27SDimitry Andric #include "llvm/ADT/DenseSet.h"
270b57cec5SDimitry Andric #include "llvm/ADT/GraphTraits.h"
280b57cec5SDimitry Andric #include "llvm/ADT/iterator.h"
290b57cec5SDimitry Andric #include <cassert>
300b57cec5SDimitry Andric #include <cstddef>
310b57cec5SDimitry Andric #include <iterator>
324824e7fdSDimitry Andric #include <queue>
334824e7fdSDimitry Andric #include <set>
344824e7fdSDimitry Andric #include <unordered_map>
354824e7fdSDimitry Andric #include <unordered_set>
360b57cec5SDimitry Andric #include <vector>
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric namespace llvm {
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric /// Enumerate the SCCs of a directed graph in reverse topological order
410b57cec5SDimitry Andric /// of the SCC DAG.
420b57cec5SDimitry Andric ///
430b57cec5SDimitry Andric /// This is implemented using Tarjan's DFS algorithm using an internal stack to
440b57cec5SDimitry Andric /// build up a vector of nodes in a particular SCC. Note that it is a forward
450b57cec5SDimitry Andric /// iterator and thus you cannot backtrack or re-visit nodes.
460b57cec5SDimitry Andric template <class GraphT, class GT = GraphTraits<GraphT>>
470b57cec5SDimitry Andric class scc_iterator : public iterator_facade_base<
480b57cec5SDimitry Andric                          scc_iterator<GraphT, GT>, std::forward_iterator_tag,
490b57cec5SDimitry Andric                          const std::vector<typename GT::NodeRef>, ptrdiff_t> {
500b57cec5SDimitry Andric   using NodeRef = typename GT::NodeRef;
510b57cec5SDimitry Andric   using ChildItTy = typename GT::ChildIteratorType;
520b57cec5SDimitry Andric   using SccTy = std::vector<NodeRef>;
530b57cec5SDimitry Andric   using reference = typename scc_iterator::reference;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   /// Element of VisitStack during DFS.
560b57cec5SDimitry Andric   struct StackElement {
570b57cec5SDimitry Andric     NodeRef Node;         ///< The current node pointer.
580b57cec5SDimitry Andric     ChildItTy NextChild;  ///< The next child, modified inplace during DFS.
590b57cec5SDimitry Andric     unsigned MinVisited;  ///< Minimum uplink value of all children of Node.
600b57cec5SDimitry Andric 
StackElementStackElement610b57cec5SDimitry Andric     StackElement(NodeRef Node, const ChildItTy &Child, unsigned Min)
620b57cec5SDimitry Andric         : Node(Node), NextChild(Child), MinVisited(Min) {}
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric     bool operator==(const StackElement &Other) const {
650b57cec5SDimitry Andric       return Node == Other.Node &&
660b57cec5SDimitry Andric              NextChild == Other.NextChild &&
670b57cec5SDimitry Andric              MinVisited == Other.MinVisited;
680b57cec5SDimitry Andric     }
690b57cec5SDimitry Andric   };
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   /// The visit counters used to detect when a complete SCC is on the stack.
720b57cec5SDimitry Andric   /// visitNum is the global counter.
730b57cec5SDimitry Andric   ///
740b57cec5SDimitry Andric   /// nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
750b57cec5SDimitry Andric   unsigned visitNum;
760b57cec5SDimitry Andric   DenseMap<NodeRef, unsigned> nodeVisitNumbers;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   /// Stack holding nodes of the SCC.
790b57cec5SDimitry Andric   std::vector<NodeRef> SCCNodeStack;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   /// The current SCC, retrieved using operator*().
820b57cec5SDimitry Andric   SccTy CurrentSCC;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   /// DFS stack, Used to maintain the ordering.  The top contains the current
850b57cec5SDimitry Andric   /// node, the next child to visit, and the minimum uplink value of all child
860b57cec5SDimitry Andric   std::vector<StackElement> VisitStack;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   /// A single "visit" within the non-recursive DFS traversal.
890b57cec5SDimitry Andric   void DFSVisitOne(NodeRef N);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   /// The stack-based DFS traversal; defined below.
920b57cec5SDimitry Andric   void DFSVisitChildren();
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   /// Compute the next SCC using the DFS traversal.
950b57cec5SDimitry Andric   void GetNextSCC();
960b57cec5SDimitry Andric 
scc_iterator(NodeRef entryN)970b57cec5SDimitry Andric   scc_iterator(NodeRef entryN) : visitNum(0) {
980b57cec5SDimitry Andric     DFSVisitOne(entryN);
990b57cec5SDimitry Andric     GetNextSCC();
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   /// End is when the DFS stack is empty.
1030b57cec5SDimitry Andric   scc_iterator() = default;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric public:
begin(const GraphT & G)1060b57cec5SDimitry Andric   static scc_iterator begin(const GraphT &G) {
1070b57cec5SDimitry Andric     return scc_iterator(GT::getEntryNode(G));
1080b57cec5SDimitry Andric   }
end(const GraphT &)1090b57cec5SDimitry Andric   static scc_iterator end(const GraphT &) { return scc_iterator(); }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   /// Direct loop termination test which is more efficient than
1120b57cec5SDimitry Andric   /// comparison with \c end().
isAtEnd()1130b57cec5SDimitry Andric   bool isAtEnd() const {
1140b57cec5SDimitry Andric     assert(!CurrentSCC.empty() || VisitStack.empty());
1150b57cec5SDimitry Andric     return CurrentSCC.empty();
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   bool operator==(const scc_iterator &x) const {
1190b57cec5SDimitry Andric     return VisitStack == x.VisitStack && CurrentSCC == x.CurrentSCC;
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   scc_iterator &operator++() {
1230b57cec5SDimitry Andric     GetNextSCC();
1240b57cec5SDimitry Andric     return *this;
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   reference operator*() const {
1280b57cec5SDimitry Andric     assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
1290b57cec5SDimitry Andric     return CurrentSCC;
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
1325ffd83dbSDimitry Andric   /// Test if the current SCC has a cycle.
1330b57cec5SDimitry Andric   ///
1340b57cec5SDimitry Andric   /// If the SCC has more than one node, this is trivially true.  If not, it may
1355ffd83dbSDimitry Andric   /// still contain a cycle if the node has an edge back to itself.
1365ffd83dbSDimitry Andric   bool hasCycle() const;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   /// This informs the \c scc_iterator that the specified \c Old node
1390b57cec5SDimitry Andric   /// has been deleted, and \c New is to be used in its place.
ReplaceNode(NodeRef Old,NodeRef New)1400b57cec5SDimitry Andric   void ReplaceNode(NodeRef Old, NodeRef New) {
1410b57cec5SDimitry Andric     assert(nodeVisitNumbers.count(Old) && "Old not in scc_iterator?");
142480093f4SDimitry Andric     // Do the assignment in two steps, in case 'New' is not yet in the map, and
143480093f4SDimitry Andric     // inserting it causes the map to grow.
144480093f4SDimitry Andric     auto tempVal = nodeVisitNumbers[Old];
145480093f4SDimitry Andric     nodeVisitNumbers[New] = tempVal;
1460b57cec5SDimitry Andric     nodeVisitNumbers.erase(Old);
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric };
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric template <class GraphT, class GT>
DFSVisitOne(NodeRef N)1510b57cec5SDimitry Andric void scc_iterator<GraphT, GT>::DFSVisitOne(NodeRef N) {
1520b57cec5SDimitry Andric   ++visitNum;
1530b57cec5SDimitry Andric   nodeVisitNumbers[N] = visitNum;
1540b57cec5SDimitry Andric   SCCNodeStack.push_back(N);
1550b57cec5SDimitry Andric   VisitStack.push_back(StackElement(N, GT::child_begin(N), visitNum));
1560b57cec5SDimitry Andric #if 0 // Enable if needed when debugging.
1570b57cec5SDimitry Andric   dbgs() << "TarjanSCC: Node " << N <<
1580b57cec5SDimitry Andric         " : visitNum = " << visitNum << "\n";
1590b57cec5SDimitry Andric #endif
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric template <class GraphT, class GT>
DFSVisitChildren()1630b57cec5SDimitry Andric void scc_iterator<GraphT, GT>::DFSVisitChildren() {
1640b57cec5SDimitry Andric   assert(!VisitStack.empty());
1650b57cec5SDimitry Andric   while (VisitStack.back().NextChild != GT::child_end(VisitStack.back().Node)) {
1660b57cec5SDimitry Andric     // TOS has at least one more child so continue DFS
1670b57cec5SDimitry Andric     NodeRef childN = *VisitStack.back().NextChild++;
1680b57cec5SDimitry Andric     typename DenseMap<NodeRef, unsigned>::iterator Visited =
1690b57cec5SDimitry Andric         nodeVisitNumbers.find(childN);
1700b57cec5SDimitry Andric     if (Visited == nodeVisitNumbers.end()) {
1710b57cec5SDimitry Andric       // this node has never been seen.
1720b57cec5SDimitry Andric       DFSVisitOne(childN);
1730b57cec5SDimitry Andric       continue;
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     unsigned childNum = Visited->second;
1770b57cec5SDimitry Andric     if (VisitStack.back().MinVisited > childNum)
1780b57cec5SDimitry Andric       VisitStack.back().MinVisited = childNum;
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
GetNextSCC()1820b57cec5SDimitry Andric template <class GraphT, class GT> void scc_iterator<GraphT, GT>::GetNextSCC() {
1830b57cec5SDimitry Andric   CurrentSCC.clear(); // Prepare to compute the next SCC
1840b57cec5SDimitry Andric   while (!VisitStack.empty()) {
1850b57cec5SDimitry Andric     DFSVisitChildren();
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric     // Pop the leaf on top of the VisitStack.
1880b57cec5SDimitry Andric     NodeRef visitingN = VisitStack.back().Node;
1890b57cec5SDimitry Andric     unsigned minVisitNum = VisitStack.back().MinVisited;
1900b57cec5SDimitry Andric     assert(VisitStack.back().NextChild == GT::child_end(visitingN));
1910b57cec5SDimitry Andric     VisitStack.pop_back();
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     // Propagate MinVisitNum to parent so we can detect the SCC starting node.
1940b57cec5SDimitry Andric     if (!VisitStack.empty() && VisitStack.back().MinVisited > minVisitNum)
1950b57cec5SDimitry Andric       VisitStack.back().MinVisited = minVisitNum;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric #if 0 // Enable if needed when debugging.
1980b57cec5SDimitry Andric     dbgs() << "TarjanSCC: Popped node " << visitingN <<
1990b57cec5SDimitry Andric           " : minVisitNum = " << minVisitNum << "; Node visit num = " <<
2000b57cec5SDimitry Andric           nodeVisitNumbers[visitingN] << "\n";
2010b57cec5SDimitry Andric #endif
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric     if (minVisitNum != nodeVisitNumbers[visitingN])
2040b57cec5SDimitry Andric       continue;
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     // A full SCC is on the SCCNodeStack!  It includes all nodes below
2070b57cec5SDimitry Andric     // visitingN on the stack.  Copy those nodes to CurrentSCC,
2080b57cec5SDimitry Andric     // reset their minVisit values, and return (this suspends
2090b57cec5SDimitry Andric     // the DFS traversal till the next ++).
2100b57cec5SDimitry Andric     do {
2110b57cec5SDimitry Andric       CurrentSCC.push_back(SCCNodeStack.back());
2120b57cec5SDimitry Andric       SCCNodeStack.pop_back();
2130b57cec5SDimitry Andric       nodeVisitNumbers[CurrentSCC.back()] = ~0U;
2140b57cec5SDimitry Andric     } while (CurrentSCC.back() != visitingN);
2150b57cec5SDimitry Andric     return;
2160b57cec5SDimitry Andric   }
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric template <class GraphT, class GT>
hasCycle()2205ffd83dbSDimitry Andric bool scc_iterator<GraphT, GT>::hasCycle() const {
2210b57cec5SDimitry Andric     assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
2220b57cec5SDimitry Andric     if (CurrentSCC.size() > 1)
2230b57cec5SDimitry Andric       return true;
2240b57cec5SDimitry Andric     NodeRef N = CurrentSCC.front();
2250b57cec5SDimitry Andric     for (ChildItTy CI = GT::child_begin(N), CE = GT::child_end(N); CI != CE;
2260b57cec5SDimitry Andric          ++CI)
2270b57cec5SDimitry Andric       if (*CI == N)
2280b57cec5SDimitry Andric         return true;
2290b57cec5SDimitry Andric     return false;
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric /// Construct the begin iterator for a deduced graph type T.
scc_begin(const T & G)2330b57cec5SDimitry Andric template <class T> scc_iterator<T> scc_begin(const T &G) {
2340b57cec5SDimitry Andric   return scc_iterator<T>::begin(G);
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric /// Construct the end iterator for a deduced graph type T.
scc_end(const T & G)2380b57cec5SDimitry Andric template <class T> scc_iterator<T> scc_end(const T &G) {
2390b57cec5SDimitry Andric   return scc_iterator<T>::end(G);
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
2424824e7fdSDimitry Andric /// Sort the nodes of a directed SCC in the decreasing order of the edge
2434824e7fdSDimitry Andric /// weights. The instantiating GraphT type should have weighted edge type
2444824e7fdSDimitry Andric /// declared in its graph traits in order to use this iterator.
2454824e7fdSDimitry Andric ///
2464824e7fdSDimitry Andric /// This is implemented using Kruskal's minimal spanning tree algorithm followed
24706c3fb27SDimitry Andric /// by Kahn's algorithm to compute a topological order on the MST. First a
24806c3fb27SDimitry Andric /// maximum spanning tree (forest) is built based on all edges within the SCC
24906c3fb27SDimitry Andric /// collection. Then a topological walk is initiated on tree nodes that do not
25006c3fb27SDimitry Andric /// have a predecessor and then applied to all nodes of the SCC. Such order
25106c3fb27SDimitry Andric /// ensures that high-weighted edges are visited first during the traversal.
2524824e7fdSDimitry Andric template <class GraphT, class GT = GraphTraits<GraphT>>
2534824e7fdSDimitry Andric class scc_member_iterator {
2544824e7fdSDimitry Andric   using NodeType = typename GT::NodeType;
2554824e7fdSDimitry Andric   using EdgeType = typename GT::EdgeType;
2564824e7fdSDimitry Andric   using NodesType = std::vector<NodeType *>;
2574824e7fdSDimitry Andric 
2584824e7fdSDimitry Andric   // Auxilary node information used during the MST calculation.
2594824e7fdSDimitry Andric   struct NodeInfo {
2604824e7fdSDimitry Andric     NodeInfo *Group = this;
2614824e7fdSDimitry Andric     uint32_t Rank = 0;
26206c3fb27SDimitry Andric     bool Visited = false;
26306c3fb27SDimitry Andric     DenseSet<const EdgeType *> IncomingMSTEdges;
2644824e7fdSDimitry Andric   };
2654824e7fdSDimitry Andric 
2664824e7fdSDimitry Andric   // Find the root group of the node and compress the path from node to the
2674824e7fdSDimitry Andric   // root.
find(NodeInfo * Node)2684824e7fdSDimitry Andric   NodeInfo *find(NodeInfo *Node) {
2694824e7fdSDimitry Andric     if (Node->Group != Node)
2704824e7fdSDimitry Andric       Node->Group = find(Node->Group);
2714824e7fdSDimitry Andric     return Node->Group;
2724824e7fdSDimitry Andric   }
2734824e7fdSDimitry Andric 
2744824e7fdSDimitry Andric   // Union the source and target node into the same group and return true.
2754824e7fdSDimitry Andric   // Returns false if they are already in the same group.
unionGroups(const EdgeType * Edge)2764824e7fdSDimitry Andric   bool unionGroups(const EdgeType *Edge) {
2774824e7fdSDimitry Andric     NodeInfo *G1 = find(&NodeInfoMap[Edge->Source]);
2784824e7fdSDimitry Andric     NodeInfo *G2 = find(&NodeInfoMap[Edge->Target]);
2794824e7fdSDimitry Andric 
2804824e7fdSDimitry Andric     // If the edge forms a cycle, do not add it to MST
2814824e7fdSDimitry Andric     if (G1 == G2)
2824824e7fdSDimitry Andric       return false;
2834824e7fdSDimitry Andric 
2844824e7fdSDimitry Andric     // Make the smaller rank tree a direct child or the root of high rank tree.
2854824e7fdSDimitry Andric     if (G1->Rank < G1->Rank)
2864824e7fdSDimitry Andric       G1->Group = G2;
2874824e7fdSDimitry Andric     else {
2884824e7fdSDimitry Andric       G2->Group = G1;
2894824e7fdSDimitry Andric       // If the ranks are the same, increment root of one tree by one.
2904824e7fdSDimitry Andric       if (G1->Rank == G2->Rank)
2914824e7fdSDimitry Andric         G2->Rank++;
2924824e7fdSDimitry Andric     }
2934824e7fdSDimitry Andric     return true;
2944824e7fdSDimitry Andric   }
2954824e7fdSDimitry Andric 
2964824e7fdSDimitry Andric   std::unordered_map<NodeType *, NodeInfo> NodeInfoMap;
2974824e7fdSDimitry Andric   NodesType Nodes;
2984824e7fdSDimitry Andric 
2994824e7fdSDimitry Andric public:
3004824e7fdSDimitry Andric   scc_member_iterator(const NodesType &InputNodes);
3014824e7fdSDimitry Andric 
3024824e7fdSDimitry Andric   NodesType &operator*() { return Nodes; }
3034824e7fdSDimitry Andric };
3044824e7fdSDimitry Andric 
3054824e7fdSDimitry Andric template <class GraphT, class GT>
scc_member_iterator(const NodesType & InputNodes)3064824e7fdSDimitry Andric scc_member_iterator<GraphT, GT>::scc_member_iterator(
3074824e7fdSDimitry Andric     const NodesType &InputNodes) {
3084824e7fdSDimitry Andric   if (InputNodes.size() <= 1) {
3094824e7fdSDimitry Andric     Nodes = InputNodes;
3104824e7fdSDimitry Andric     return;
3114824e7fdSDimitry Andric   }
3124824e7fdSDimitry Andric 
3134824e7fdSDimitry Andric   // Initialize auxilary node information.
3144824e7fdSDimitry Andric   NodeInfoMap.clear();
3154824e7fdSDimitry Andric   for (auto *Node : InputNodes) {
3164824e7fdSDimitry Andric     // This is specifically used to construct a `NodeInfo` object in place. An
3174824e7fdSDimitry Andric     // insert operation will involve a copy construction which invalidate the
3184824e7fdSDimitry Andric     // initial value of the `Group` field which should be `this`.
3194824e7fdSDimitry Andric     (void)NodeInfoMap[Node].Group;
3204824e7fdSDimitry Andric   }
3214824e7fdSDimitry Andric 
3224824e7fdSDimitry Andric   // Sort edges by weights.
3234824e7fdSDimitry Andric   struct EdgeComparer {
3244824e7fdSDimitry Andric     bool operator()(const EdgeType *L, const EdgeType *R) const {
3254824e7fdSDimitry Andric       return L->Weight > R->Weight;
3264824e7fdSDimitry Andric     }
3274824e7fdSDimitry Andric   };
3284824e7fdSDimitry Andric 
3294824e7fdSDimitry Andric   std::multiset<const EdgeType *, EdgeComparer> SortedEdges;
3304824e7fdSDimitry Andric   for (auto *Node : InputNodes) {
3314824e7fdSDimitry Andric     for (auto &Edge : Node->Edges) {
3324824e7fdSDimitry Andric       if (NodeInfoMap.count(Edge.Target))
3334824e7fdSDimitry Andric         SortedEdges.insert(&Edge);
3344824e7fdSDimitry Andric     }
3354824e7fdSDimitry Andric   }
3364824e7fdSDimitry Andric 
3374824e7fdSDimitry Andric   // Traverse all the edges and compute the Maximum Weight Spanning Tree
3384824e7fdSDimitry Andric   // using Kruskal's algorithm.
3394824e7fdSDimitry Andric   std::unordered_set<const EdgeType *> MSTEdges;
3404824e7fdSDimitry Andric   for (auto *Edge : SortedEdges) {
3414824e7fdSDimitry Andric     if (unionGroups(Edge))
3424824e7fdSDimitry Andric       MSTEdges.insert(Edge);
3434824e7fdSDimitry Andric   }
3444824e7fdSDimitry Andric 
34506c3fb27SDimitry Andric   // Run Kahn's algorithm on MST to compute a topological traversal order.
34606c3fb27SDimitry Andric   // The algorithm starts from nodes that have no incoming edge. These nodes are
34706c3fb27SDimitry Andric   // "roots" of the MST forest. This ensures that nodes are visited before their
34806c3fb27SDimitry Andric   // descendants are, thus ensures hot edges are processed before cold edges,
34906c3fb27SDimitry Andric   // based on how MST is computed.
3504824e7fdSDimitry Andric   std::queue<NodeType *> Queue;
35106c3fb27SDimitry Andric   for (const auto *Edge : MSTEdges)
35206c3fb27SDimitry Andric     NodeInfoMap[Edge->Target].IncomingMSTEdges.insert(Edge);
35306c3fb27SDimitry Andric 
35406c3fb27SDimitry Andric   // Walk through SortedEdges to initialize the queue, instead of using NodeInfoMap
35506c3fb27SDimitry Andric   // to ensure an ordered deterministic push.
35681ad6265SDimitry Andric   for (auto *Edge : SortedEdges) {
35706c3fb27SDimitry Andric     if (!NodeInfoMap[Edge->Source].Visited &&
35806c3fb27SDimitry Andric         NodeInfoMap[Edge->Source].IncomingMSTEdges.empty()) {
35981ad6265SDimitry Andric       Queue.push(Edge->Source);
36006c3fb27SDimitry Andric       NodeInfoMap[Edge->Source].Visited = true;
36181ad6265SDimitry Andric     }
36281ad6265SDimitry Andric   }
3634824e7fdSDimitry Andric 
3644824e7fdSDimitry Andric   while (!Queue.empty()) {
3654824e7fdSDimitry Andric     auto *Node = Queue.front();
3664824e7fdSDimitry Andric     Queue.pop();
3674824e7fdSDimitry Andric     Nodes.push_back(Node);
3684824e7fdSDimitry Andric     for (auto &Edge : Node->Edges) {
36906c3fb27SDimitry Andric       NodeInfoMap[Edge.Target].IncomingMSTEdges.erase(&Edge);
37006c3fb27SDimitry Andric       if (MSTEdges.count(&Edge) &&
37106c3fb27SDimitry Andric           NodeInfoMap[Edge.Target].IncomingMSTEdges.empty()) {
3724824e7fdSDimitry Andric         Queue.push(Edge.Target);
3734824e7fdSDimitry Andric       }
3744824e7fdSDimitry Andric     }
3754824e7fdSDimitry Andric   }
3764824e7fdSDimitry Andric 
3774824e7fdSDimitry Andric   assert(InputNodes.size() == Nodes.size() && "missing nodes in MST");
3784824e7fdSDimitry Andric   std::reverse(Nodes.begin(), Nodes.end());
3794824e7fdSDimitry Andric }
3800b57cec5SDimitry Andric } // end namespace llvm
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric #endif // LLVM_ADT_SCCITERATOR_H
383