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