Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 1 | //===-- Support/SCCIterator.h - SCC iterator --------------------*- C++ -*-===// |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 2 | // |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 3 | // This builds on the Support/GraphTraits.h file to find the strongly connected |
| 4 | // components (SCCs) of a graph in O(N+E) time using Tarjan's DFS algorithm. |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 5 | // |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 6 | // The SCC iterator has the important property that if a node in SCC S1 has an |
| 7 | // edge to a node in SCC S2, then it visits S1 *after* S2. |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 8 | // |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 9 | // To visit S1 *before* S2, use the scc_iterator on the Inverse graph. |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 10 | // (NOTE: This requires some simple wrappers and is not supported yet.) |
Chris Lattner | 52de05c | 2003-06-22 03:08:05 +0000 | [diff] [blame] | 11 | // |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 14 | #ifndef SUPPORT_SCCITERATOR_H |
| 15 | #define SUPPORT_SCCITERATOR_H |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 16 | |
| 17 | #include "Support/GraphTraits.h" |
Chris Lattner | 52de05c | 2003-06-22 03:08:05 +0000 | [diff] [blame] | 18 | #include "Support/iterator" |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 19 | #include <vector> |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 20 | #include <map> |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 21 | |
Chris Lattner | 71e71f2 | 2003-08-31 19:55:31 +0000 | [diff] [blame] | 22 | //===----------------------------------------------------------------------===// |
| 23 | /// |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 24 | /// scc_iterator - Enumerate the SCCs of a directed graph, in |
Chris Lattner | 71e71f2 | 2003-08-31 19:55:31 +0000 | [diff] [blame] | 25 | /// reverse topological order of the SCC DAG. |
| 26 | /// |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 27 | template<class GraphT, class GT = GraphTraits<GraphT> > |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 28 | class scc_iterator |
Chris Lattner | 71e71f2 | 2003-08-31 19:55:31 +0000 | [diff] [blame] | 29 | : public forward_iterator<std::vector<typename GT::NodeType>, ptrdiff_t> { |
| 30 | typedef typename GT::NodeType NodeType; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 31 | typedef typename GT::ChildIteratorType ChildItTy; |
Chris Lattner | 71e71f2 | 2003-08-31 19:55:31 +0000 | [diff] [blame] | 32 | typedef std::vector<NodeType*> SccTy; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 33 | typedef forward_iterator<SccTy, ptrdiff_t> super; |
| 34 | typedef typename super::reference reference; |
| 35 | typedef typename super::pointer pointer; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 36 | |
| 37 | // The visit counters used to detect when a complete SCC is on the stack. |
| 38 | // visitNum is the global counter. |
| 39 | // nodeVisitNumbers are per-node visit numbers, also used as DFS flags. |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 40 | unsigned visitNum; |
| 41 | std::map<NodeType *, unsigned> nodeVisitNumbers; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 42 | |
| 43 | // SCCNodeStack - Stack holding nodes of the SCC. |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 44 | std::vector<NodeType *> SCCNodeStack; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 45 | |
| 46 | // CurrentSCC - The current SCC, retrieved using operator*(). |
| 47 | SccTy CurrentSCC; |
| 48 | |
| 49 | // VisitStack - Used to maintain the ordering. Top = current block |
| 50 | // First element is basic block pointer, second is the 'next child' to visit |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 51 | std::vector<std::pair<NodeType *, ChildItTy> > VisitStack; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 52 | |
| 53 | // MinVistNumStack - Stack holding the "min" values for each node in the DFS. |
| 54 | // This is used to track the minimum uplink values for all children of |
| 55 | // the corresponding node on the VisitStack. |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 56 | std::vector<unsigned> MinVisitNumStack; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 57 | |
| 58 | // A single "visit" within the non-recursive DFS traversal. |
| 59 | void DFSVisitOne(NodeType* N) { |
| 60 | ++visitNum; // Global counter for the visit order |
| 61 | nodeVisitNumbers[N] = visitNum; |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 62 | SCCNodeStack.push_back(N); |
| 63 | MinVisitNumStack.push_back(visitNum); |
| 64 | VisitStack.push_back(make_pair(N, GT::child_begin(N))); |
Chris Lattner | b1c0cd0 | 2003-08-31 01:45:00 +0000 | [diff] [blame] | 65 | //DEBUG(std::cerr << "TarjanSCC: Node " << N << |
| 66 | // " : visitNum = " << visitNum << "\n"); |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | // The stack-based DFS traversal; defined below. |
| 70 | void DFSVisitChildren() { |
| 71 | assert(!VisitStack.empty()); |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 72 | while (VisitStack.back().second != GT::child_end(VisitStack.back().first)) |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 73 | { // TOS has at least one more child so continue DFS |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 74 | NodeType *childN = *VisitStack.back().second++; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 75 | if (nodeVisitNumbers.find(childN) == nodeVisitNumbers.end()) |
| 76 | { // this node has never been seen |
| 77 | DFSVisitOne(childN); |
| 78 | } |
| 79 | else |
| 80 | { |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 81 | unsigned childNum = nodeVisitNumbers[childN]; |
| 82 | if (MinVisitNumStack.back() > childNum) |
| 83 | MinVisitNumStack.back() = childNum; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // Compute the next SCC using the DFS traversal. |
| 89 | void GetNextSCC() { |
| 90 | assert(VisitStack.size() == MinVisitNumStack.size()); |
| 91 | CurrentSCC.clear(); // Prepare to compute the next SCC |
| 92 | while (! VisitStack.empty()) |
| 93 | { |
| 94 | DFSVisitChildren(); |
| 95 | |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 96 | assert(VisitStack.back().second == |
| 97 | GT::child_end(VisitStack.back().first)); |
| 98 | NodeType* visitingN = VisitStack.back().first; |
| 99 | unsigned minVisitNum = MinVisitNumStack.back(); |
| 100 | VisitStack.pop_back(); |
| 101 | MinVisitNumStack.pop_back(); |
| 102 | if (! MinVisitNumStack.empty() && MinVisitNumStack.back() > minVisitNum) |
| 103 | MinVisitNumStack.back() = minVisitNum; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 104 | |
Chris Lattner | b1c0cd0 | 2003-08-31 01:45:00 +0000 | [diff] [blame] | 105 | //DEBUG(std::cerr << "TarjanSCC: Popped node " << visitingN << |
| 106 | // " : minVisitNum = " << minVisitNum << "; Node visit num = " << |
| 107 | // nodeVisitNumbers[visitingN] << "\n"); |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 108 | |
| 109 | if (minVisitNum == nodeVisitNumbers[visitingN]) |
| 110 | { // A full SCC is on the SCCNodeStack! It includes all nodes below |
| 111 | // visitingN on the stack. Copy those nodes to CurrentSCC, |
| 112 | // reset their minVisit values, and return (this suspends |
| 113 | // the DFS traversal till the next ++). |
| 114 | do { |
Chris Lattner | a74a63c | 2003-08-31 01:48:21 +0000 | [diff] [blame] | 115 | CurrentSCC.push_back(SCCNodeStack.back()); |
| 116 | SCCNodeStack.pop_back(); |
Chris Lattner | fb18559 | 2002-11-15 18:04:16 +0000 | [diff] [blame] | 117 | nodeVisitNumbers[CurrentSCC.back()] = ~0UL; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 118 | } while (CurrentSCC.back() != visitingN); |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 119 | return; |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 124 | inline scc_iterator(NodeType *entryN) : visitNum(0) { |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 125 | DFSVisitOne(entryN); |
| 126 | GetNextSCC(); |
| 127 | } |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 128 | inline scc_iterator() { /* End is when DFS stack is empty */ } |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 129 | |
| 130 | public: |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 131 | typedef scc_iterator<GraphT, GT> _Self; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 132 | |
| 133 | // Provide static "constructors"... |
| 134 | static inline _Self begin(GraphT& G) { return _Self(GT::getEntryNode(G)); } |
| 135 | static inline _Self end (GraphT& G) { return _Self(); } |
| 136 | |
| 137 | // Direct loop termination test (I.fini() is more efficient than I == end()) |
| 138 | inline bool fini() const { |
Vikram S. Adve | 80cac47 | 2002-12-06 15:02:22 +0000 | [diff] [blame] | 139 | assert(!CurrentSCC.empty() || VisitStack.empty()); |
| 140 | return CurrentSCC.empty(); |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | inline bool operator==(const _Self& x) const { |
Vikram S. Adve | 80cac47 | 2002-12-06 15:02:22 +0000 | [diff] [blame] | 144 | return VisitStack == x.VisitStack && CurrentSCC == x.CurrentSCC; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 145 | } |
| 146 | inline bool operator!=(const _Self& x) const { return !operator==(x); } |
| 147 | |
| 148 | // Iterator traversal: forward iteration only |
| 149 | inline _Self& operator++() { // Preincrement |
| 150 | GetNextSCC(); |
| 151 | return *this; |
| 152 | } |
| 153 | inline _Self operator++(int) { // Postincrement |
| 154 | _Self tmp = *this; ++*this; return tmp; |
| 155 | } |
| 156 | |
Chris Lattner | f020906 | 2003-08-31 19:34:27 +0000 | [diff] [blame] | 157 | // Retrieve a reference to the current SCC |
| 158 | inline const SccTy &operator*() const { |
| 159 | assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!"); |
| 160 | return CurrentSCC; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 161 | } |
Chris Lattner | f020906 | 2003-08-31 19:34:27 +0000 | [diff] [blame] | 162 | inline SccTy &operator*() { |
| 163 | assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!"); |
| 164 | return CurrentSCC; |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 165 | } |
Chris Lattner | 5cac4dd | 2003-08-31 19:51:22 +0000 | [diff] [blame] | 166 | |
| 167 | // hasLoop() -- Test if the current SCC has a loop. If it has more than one |
| 168 | // node, this is trivially true. If not, it may still contain a loop if the |
| 169 | // node has an edge back to itself. |
| 170 | bool hasLoop() const { |
| 171 | assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!"); |
| 172 | if (CurrentSCC.size() > 1) return true; |
| 173 | NodeType *N = CurrentSCC.front(); |
| 174 | for (ChildItTy CI = GT::child_begin(N), CE=GT::child_end(N); CI != CE; ++CI) |
| 175 | if (*CI == N) |
| 176 | return true; |
| 177 | return false; |
| 178 | } |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 179 | }; |
| 180 | |
| 181 | |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 182 | // Global constructor for the SCC iterator. |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 183 | template <class T> |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 184 | scc_iterator<T> scc_begin(T G) { |
| 185 | return scc_iterator<T>::begin(G); |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 186 | } |
| 187 | |
Chris Lattner | c0a07a4 | 2002-11-10 23:46:31 +0000 | [diff] [blame] | 188 | template <class T> |
Chris Lattner | 78a5c1a | 2003-08-31 20:01:57 +0000 | [diff] [blame] | 189 | scc_iterator<T> scc_end(T G) { |
| 190 | return scc_iterator<T>::end(G); |
Chris Lattner | c0a07a4 | 2002-11-10 23:46:31 +0000 | [diff] [blame] | 191 | } |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 192 | |
Vikram S. Adve | a9c3afb | 2002-11-04 14:15:57 +0000 | [diff] [blame] | 193 | #endif |