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