llvm.org GIT mirror llvm / 5fe9171
Generic graph iterator to enumerate the SCCs of a graph in linear time using Tarjan's DFS algorithm. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4531 91177308-0d34-0410-b5e6-96231b3b80d8 Vikram S. Adve 17 years ago
2 changed file(s) with 442 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===-- Support/TarjanSCCIterator.h -Generic Tarjan SCC iterator -*- C++ -*--=//
1 //
2 // This builds on the Support/GraphTraits.h file to find the strongly
3 // connected components (SCCs) of a graph in O(N+E) time using
4 // Tarjan's DFS algorithm.
5 //
6 // The SCC iterator has the important property that if a node in SCC S1
7 // has an edge to a node in SCC S2, then it visits S1 *after* S2.
8 //
9 // To visit S1 *before* S2, use the TarjanSCCIterator on the Inverse graph.
10 // (NOTE: This requires some simple wrappers and is not supported yet.)
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_SUPPORT_TARJANSCC_ITERATOR_H
14 #define LLVM_SUPPORT_TARJANSCC_ITERATOR_H
15
16 #include "Support/GraphTraits.h"
17 #include
18 #include
19 #include
20 #include
21 #include
22
23
24 //--------------------------------------------------------------------------
25 // class SCC : A simple representation of an SCC in a generic Graph.
26 //--------------------------------------------------------------------------
27
28 template >
29 struct SCC: public std::vector {
30
31 typedef typename GT::NodeType NodeType;
32 typedef typename GT::ChildIteratorType ChildItTy;
33
34 typedef std::vector super;
35 typedef typename super::iterator iterator;
36 typedef typename super::const_iterator const_iterator;
37 typedef typename super::reverse_iterator reverse_iterator;
38 typedef typename super::const_reverse_iterator const_reverse_iterator;
39
40 // HasLoop() -- Test if this SCC has a loop. If it has more than one
41 // node, this is trivially true. If not, it may still contain a loop
42 // if the node has an edge back to itself.
43 bool HasLoop() const {
44 if (size() > 1) return true;
45 NodeType* N = front();
46 for (ChildItTy CI=GT::child_begin(N), CE=GT::child_end(N); CI != CE; ++CI)
47 if (*CI == N)
48 return true;
49 return false;
50 }
51 };
52
53 //--------------------------------------------------------------------------
54 // class TarjanSCC_iterator: Enumerate the SCCs of a directed graph, in
55 // reverse topological order of the SCC DAG.
56 //--------------------------------------------------------------------------
57
58 const unsigned long MAXLONG = (1 << (8 * sizeof(unsigned long) - 1));
59
60 namespace {
61 Statistic<> NumSCCs("NumSCCs", "Number of Strongly Connected Components");
62 Statistic<> MaxSCCSize("MaxSCCSize", "Size of largest Strongly Connected Component");
63 }
64
65 template >
66 class TarjanSCC_iterator : public forward_iterator, ptrdiff_t>
67 {
68 typedef SCC SccTy;
69 typedef forward_iterator super;
70 typedef typename super::reference reference;
71 typedef typename super::pointer pointer;
72 typedef typename GT::NodeType NodeType;
73 typedef typename GT::ChildIteratorType ChildItTy;
74
75 // The visit counters used to detect when a complete SCC is on the stack.
76 // visitNum is the global counter.
77 // nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
78 unsigned long visitNum;
79 std::map nodeVisitNumbers;
80
81 // SCCNodeStack - Stack holding nodes of the SCC.
82 std::stack SCCNodeStack;
83
84 // CurrentSCC - The current SCC, retrieved using operator*().
85 SccTy CurrentSCC;
86
87 // VisitStack - Used to maintain the ordering. Top = current block
88 // First element is basic block pointer, second is the 'next child' to visit
89 std::stack > VisitStack;
90
91 // MinVistNumStack - Stack holding the "min" values for each node in the DFS.
92 // This is used to track the minimum uplink values for all children of
93 // the corresponding node on the VisitStack.
94 std::stack MinVisitNumStack;
95
96 // A single "visit" within the non-recursive DFS traversal.
97 void DFSVisitOne(NodeType* N) {
98 ++visitNum; // Global counter for the visit order
99 nodeVisitNumbers[N] = visitNum;
100 SCCNodeStack.push(N);
101 MinVisitNumStack.push(visitNum);
102 VisitStack.push(make_pair(N, GT::child_begin(N)));
103 DEBUG(std::cerr << "TarjanSCC: Node " << N <<
104 " : visitNum = " << visitNum << "\n");
105 }
106
107 // The stack-based DFS traversal; defined below.
108 void DFSVisitChildren() {
109 assert(!VisitStack.empty());
110 while (VisitStack.top().second != GT::child_end(VisitStack.top().first))
111 { // TOS has at least one more child so continue DFS
112 NodeType *childN = *VisitStack.top().second++;
113 if (nodeVisitNumbers.find(childN) == nodeVisitNumbers.end())
114 { // this node has never been seen
115 DFSVisitOne(childN);
116 }
117 else
118 {
119 unsigned long childNum = nodeVisitNumbers[childN];
120 if (MinVisitNumStack.top() > childNum)
121 MinVisitNumStack.top() = childNum;
122 }
123 }
124 }
125
126 // Compute the next SCC using the DFS traversal.
127 void GetNextSCC() {
128 assert(VisitStack.size() == MinVisitNumStack.size());
129 CurrentSCC.clear(); // Prepare to compute the next SCC
130 while (! VisitStack.empty())
131 {
132 DFSVisitChildren();
133
134 assert(VisitStack.top().second==GT::child_end(VisitStack.top().first));
135 NodeType* visitingN = VisitStack.top().first;
136 unsigned long minVisitNum = MinVisitNumStack.top();
137 VisitStack.pop();
138 MinVisitNumStack.pop();
139 if (! MinVisitNumStack.empty() && MinVisitNumStack.top() > minVisitNum)
140 MinVisitNumStack.top() = minVisitNum;
141
142 DEBUG(std::cerr << "TarjanSCC: Popped node " << visitingN <<
143 " : minVisitNum = " << minVisitNum << "; Node visit num = " <<
144 nodeVisitNumbers[visitingN] << "\n");
145
146 if (minVisitNum == nodeVisitNumbers[visitingN])
147 { // A full SCC is on the SCCNodeStack! It includes all nodes below
148 // visitingN on the stack. Copy those nodes to CurrentSCC,
149 // reset their minVisit values, and return (this suspends
150 // the DFS traversal till the next ++).
151 do {
152 CurrentSCC.push_back(SCCNodeStack.top());
153 SCCNodeStack.pop();
154 nodeVisitNumbers[CurrentSCC.back()] = MAXLONG;
155 } while (CurrentSCC.back() != visitingN);
156
157 ++NumSCCs;
158 if (CurrentSCC.size() > MaxSCCSize) MaxSCCSize = CurrentSCC.size();
159
160 return;
161 }
162 }
163 }
164
165 inline TarjanSCC_iterator(NodeType *entryN) : visitNum(0) {
166 DFSVisitOne(entryN);
167 GetNextSCC();
168 }
169 inline TarjanSCC_iterator() { /* End is when DFS stack is empty */ }
170
171 public:
172 typedef TarjanSCC_iterator _Self;
173
174 // Provide static "constructors"...
175 static inline _Self begin(GraphT& G) { return _Self(GT::getEntryNode(G)); }
176 static inline _Self end (GraphT& G) { return _Self(); }
177
178 // Direct loop termination test (I.fini() is more efficient than I == end())
179 inline bool fini() const {
180 return VisitStack.empty();
181 }
182
183 inline bool operator==(const _Self& x) const {
184 return VisitStack == x.VisitStack;
185 }
186 inline bool operator!=(const _Self& x) const { return !operator==(x); }
187
188 // Iterator traversal: forward iteration only
189 inline _Self& operator++() { // Preincrement
190 GetNextSCC();
191 return *this;
192 }
193 inline _Self operator++(int) { // Postincrement
194 _Self tmp = *this; ++*this; return tmp;
195 }
196
197 // Retrieve a pointer to the current SCC. Returns NULL when done.
198 inline const SccTy* operator*() const {
199 assert(!CurrentSCC.empty() || fini());
200 return CurrentSCC.empty()? NULL : &CurrentSCC;
201 }
202 inline SccTy* operator*() {
203 assert(!CurrentSCC.empty() || fini());
204 return CurrentSCC.empty()? NULL : &CurrentSCC;
205 }
206 };
207
208
209 // Global constructor for the Tarjan SCC iterator. Use *I == NULL or I.fini()
210 // to test termination efficiently, instead of I == the "end" iterator.
211 template
212 TarjanSCC_iterator tarj_begin(T G)
213 {
214 return TarjanSCC_iterator::begin(G);
215 }
216
217
218 //===----------------------------------------------------------------------===//
219
220 #endif
0 //===-- Support/TarjanSCCIterator.h -Generic Tarjan SCC iterator -*- C++ -*--=//
1 //
2 // This builds on the Support/GraphTraits.h file to find the strongly
3 // connected components (SCCs) of a graph in O(N+E) time using
4 // Tarjan's DFS algorithm.
5 //
6 // The SCC iterator has the important property that if a node in SCC S1
7 // has an edge to a node in SCC S2, then it visits S1 *after* S2.
8 //
9 // To visit S1 *before* S2, use the TarjanSCCIterator on the Inverse graph.
10 // (NOTE: This requires some simple wrappers and is not supported yet.)
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_SUPPORT_TARJANSCC_ITERATOR_H
14 #define LLVM_SUPPORT_TARJANSCC_ITERATOR_H
15
16 #include "Support/GraphTraits.h"
17 #include
18 #include
19 #include
20 #include
21 #include
22
23
24 //--------------------------------------------------------------------------
25 // class SCC : A simple representation of an SCC in a generic Graph.
26 //--------------------------------------------------------------------------
27
28 template >
29 struct SCC: public std::vector {
30
31 typedef typename GT::NodeType NodeType;
32 typedef typename GT::ChildIteratorType ChildItTy;
33
34 typedef std::vector super;
35 typedef typename super::iterator iterator;
36 typedef typename super::const_iterator const_iterator;
37 typedef typename super::reverse_iterator reverse_iterator;
38 typedef typename super::const_reverse_iterator const_reverse_iterator;
39
40 // HasLoop() -- Test if this SCC has a loop. If it has more than one
41 // node, this is trivially true. If not, it may still contain a loop
42 // if the node has an edge back to itself.
43 bool HasLoop() const {
44 if (size() > 1) return true;
45 NodeType* N = front();
46 for (ChildItTy CI=GT::child_begin(N), CE=GT::child_end(N); CI != CE; ++CI)
47 if (*CI == N)
48 return true;
49 return false;
50 }
51 };
52
53 //--------------------------------------------------------------------------
54 // class TarjanSCC_iterator: Enumerate the SCCs of a directed graph, in
55 // reverse topological order of the SCC DAG.
56 //--------------------------------------------------------------------------
57
58 const unsigned long MAXLONG = (1 << (8 * sizeof(unsigned long) - 1));
59
60 namespace {
61 Statistic<> NumSCCs("NumSCCs", "Number of Strongly Connected Components");
62 Statistic<> MaxSCCSize("MaxSCCSize", "Size of largest Strongly Connected Component");
63 }
64
65 template >
66 class TarjanSCC_iterator : public forward_iterator, ptrdiff_t>
67 {
68 typedef SCC SccTy;
69 typedef forward_iterator super;
70 typedef typename super::reference reference;
71 typedef typename super::pointer pointer;
72 typedef typename GT::NodeType NodeType;
73 typedef typename GT::ChildIteratorType ChildItTy;
74
75 // The visit counters used to detect when a complete SCC is on the stack.
76 // visitNum is the global counter.
77 // nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
78 unsigned long visitNum;
79 std::map nodeVisitNumbers;
80
81 // SCCNodeStack - Stack holding nodes of the SCC.
82 std::stack SCCNodeStack;
83
84 // CurrentSCC - The current SCC, retrieved using operator*().
85 SccTy CurrentSCC;
86
87 // VisitStack - Used to maintain the ordering. Top = current block
88 // First element is basic block pointer, second is the 'next child' to visit
89 std::stack > VisitStack;
90
91 // MinVistNumStack - Stack holding the "min" values for each node in the DFS.
92 // This is used to track the minimum uplink values for all children of
93 // the corresponding node on the VisitStack.
94 std::stack MinVisitNumStack;
95
96 // A single "visit" within the non-recursive DFS traversal.
97 void DFSVisitOne(NodeType* N) {
98 ++visitNum; // Global counter for the visit order
99 nodeVisitNumbers[N] = visitNum;
100 SCCNodeStack.push(N);
101 MinVisitNumStack.push(visitNum);
102 VisitStack.push(make_pair(N, GT::child_begin(N)));
103 DEBUG(std::cerr << "TarjanSCC: Node " << N <<
104 " : visitNum = " << visitNum << "\n");
105 }
106
107 // The stack-based DFS traversal; defined below.
108 void DFSVisitChildren() {
109 assert(!VisitStack.empty());
110 while (VisitStack.top().second != GT::child_end(VisitStack.top().first))
111 { // TOS has at least one more child so continue DFS
112 NodeType *childN = *VisitStack.top().second++;
113 if (nodeVisitNumbers.find(childN) == nodeVisitNumbers.end())
114 { // this node has never been seen
115 DFSVisitOne(childN);
116 }
117 else
118 {
119 unsigned long childNum = nodeVisitNumbers[childN];
120 if (MinVisitNumStack.top() > childNum)
121 MinVisitNumStack.top() = childNum;
122 }
123 }
124 }
125
126 // Compute the next SCC using the DFS traversal.
127 void GetNextSCC() {
128 assert(VisitStack.size() == MinVisitNumStack.size());
129 CurrentSCC.clear(); // Prepare to compute the next SCC
130 while (! VisitStack.empty())
131 {
132 DFSVisitChildren();
133
134 assert(VisitStack.top().second==GT::child_end(VisitStack.top().first));
135 NodeType* visitingN = VisitStack.top().first;
136 unsigned long minVisitNum = MinVisitNumStack.top();
137 VisitStack.pop();
138 MinVisitNumStack.pop();
139 if (! MinVisitNumStack.empty() && MinVisitNumStack.top() > minVisitNum)
140 MinVisitNumStack.top() = minVisitNum;
141
142 DEBUG(std::cerr << "TarjanSCC: Popped node " << visitingN <<
143 " : minVisitNum = " << minVisitNum << "; Node visit num = " <<
144 nodeVisitNumbers[visitingN] << "\n");
145
146 if (minVisitNum == nodeVisitNumbers[visitingN])
147 { // A full SCC is on the SCCNodeStack! It includes all nodes below
148 // visitingN on the stack. Copy those nodes to CurrentSCC,
149 // reset their minVisit values, and return (this suspends
150 // the DFS traversal till the next ++).
151 do {
152 CurrentSCC.push_back(SCCNodeStack.top());
153 SCCNodeStack.pop();
154 nodeVisitNumbers[CurrentSCC.back()] = MAXLONG;
155 } while (CurrentSCC.back() != visitingN);
156
157 ++NumSCCs;
158 if (CurrentSCC.size() > MaxSCCSize) MaxSCCSize = CurrentSCC.size();
159
160 return;
161 }
162 }
163 }
164
165 inline TarjanSCC_iterator(NodeType *entryN) : visitNum(0) {
166 DFSVisitOne(entryN);
167 GetNextSCC();
168 }
169 inline TarjanSCC_iterator() { /* End is when DFS stack is empty */ }
170
171 public:
172 typedef TarjanSCC_iterator _Self;
173
174 // Provide static "constructors"...
175 static inline _Self begin(GraphT& G) { return _Self(GT::getEntryNode(G)); }
176 static inline _Self end (GraphT& G) { return _Self(); }
177
178 // Direct loop termination test (I.fini() is more efficient than I == end())
179 inline bool fini() const {
180 return VisitStack.empty();
181 }
182
183 inline bool operator==(const _Self& x) const {
184 return VisitStack == x.VisitStack;
185 }
186 inline bool operator!=(const _Self& x) const { return !operator==(x); }
187
188 // Iterator traversal: forward iteration only
189 inline _Self& operator++() { // Preincrement
190 GetNextSCC();
191 return *this;
192 }
193 inline _Self operator++(int) { // Postincrement
194 _Self tmp = *this; ++*this; return tmp;
195 }
196
197 // Retrieve a pointer to the current SCC. Returns NULL when done.
198 inline const SccTy* operator*() const {
199 assert(!CurrentSCC.empty() || fini());
200 return CurrentSCC.empty()? NULL : &CurrentSCC;
201 }
202 inline SccTy* operator*() {
203 assert(!CurrentSCC.empty() || fini());
204 return CurrentSCC.empty()? NULL : &CurrentSCC;
205 }
206 };
207
208
209 // Global constructor for the Tarjan SCC iterator. Use *I == NULL or I.fini()
210 // to test termination efficiently, instead of I == the "end" iterator.
211 template
212 TarjanSCC_iterator tarj_begin(T G)
213 {
214 return TarjanSCC_iterator::begin(G);
215 }
216
217
218 //===----------------------------------------------------------------------===//
219
220 #endif