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