Skip to content

Commit 3d515f6

Browse files
committed
[ADT] Actually mutate the iterator VisitStack.back().second, not its copy.
Summary: Before the change, *Opt never actually gets updated by the end of toNext(), so for every next time the loop has to start over from child_begin(). This bug doesn't affect the correctness, since Visited prevents it from re-entering the same node again; but it's slow. Reviewers: dberris, dblaikie, dannyb Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D23649 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@279482 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0fd3c95 commit 3d515f6

File tree

5 files changed

+312
-229
lines changed

5 files changed

+312
-229
lines changed

include/llvm/ADT/DepthFirstIterator.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ class df_iterator
107107
if (!Opt)
108108
Opt.emplace(GT::child_begin(Node));
109109

110-
for (NodeRef Next : make_range(*Opt, GT::child_end(Node))) {
110+
// Notice that we directly mutate *Opt here, so that
111+
// VisitStack.back().second actually gets updated as the iterator
112+
// increases.
113+
while (*Opt != GT::child_end(Node)) {
114+
NodeRef Next = *(*Opt)++;
111115
// Has our next sibling been visited?
112116
if (this->Visited.insert(Next).second) {
113117
// No, do it now.

unittests/ADT/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(ADTSources
1313
DeltaAlgorithmTest.cpp
1414
DenseMapTest.cpp
1515
DenseSetTest.cpp
16+
DepthFirstIteratorTest.cpp
1617
FoldingSet.cpp
1718
FunctionRefTest.cpp
1819
HashingTest.cpp
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//=== llvm/unittest/ADT/DepthFirstIteratorTest.cpp - DFS iterator tests ---===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "TestGraph.h"
11+
#include "llvm/ADT/DepthFirstIterator.h"
12+
#include "gtest/gtest.h"
13+
14+
using namespace llvm;
15+
16+
namespace llvm {
17+
18+
template <typename T> struct CountedSet {
19+
typedef typename SmallPtrSet<T, 4>::iterator iterator;
20+
21+
SmallPtrSet<T, 4> S;
22+
int InsertVisited = 0;
23+
24+
std::pair<iterator, bool> insert(const T &Item) {
25+
InsertVisited++;
26+
return S.insert(Item);
27+
}
28+
29+
size_t count(const T &Item) const { return S.count(Item); }
30+
};
31+
32+
template <typename T> class df_iterator_storage<CountedSet<T>, true> {
33+
public:
34+
df_iterator_storage(CountedSet<T> &VSet) : Visited(VSet) {}
35+
36+
CountedSet<T> &Visited;
37+
};
38+
39+
TEST(DepthFirstIteratorTest, ActuallyUpdateIterator) {
40+
typedef CountedSet<Graph<3>::NodeType *> StorageT;
41+
typedef df_iterator<Graph<3>, StorageT, true> DFIter;
42+
43+
Graph<3> G;
44+
G.AddEdge(0, 1);
45+
G.AddEdge(0, 2);
46+
StorageT S;
47+
for (auto N : make_range(DFIter::begin(G, S), DFIter::end(G, S)))
48+
(void)N;
49+
50+
EXPECT_EQ(3, S.InsertVisited);
51+
}
52+
}

unittests/ADT/SCCIteratorTest.cpp

Lines changed: 1 addition & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -8,241 +8,14 @@
88
//===----------------------------------------------------------------------===//
99

1010
#include "llvm/ADT/SCCIterator.h"
11-
#include "llvm/ADT/GraphTraits.h"
1211
#include "gtest/gtest.h"
12+
#include "TestGraph.h"
1313
#include <limits.h>
1414

1515
using namespace llvm;
1616

1717
namespace llvm {
1818

19-
/// Graph<N> - A graph with N nodes. Note that N can be at most 8.
20-
template <unsigned N>
21-
class Graph {
22-
private:
23-
// Disable copying.
24-
Graph(const Graph&);
25-
Graph& operator=(const Graph&);
26-
27-
static void ValidateIndex(unsigned Idx) {
28-
assert(Idx < N && "Invalid node index!");
29-
}
30-
public:
31-
32-
/// NodeSubset - A subset of the graph's nodes.
33-
class NodeSubset {
34-
typedef unsigned char BitVector; // Where the limitation N <= 8 comes from.
35-
BitVector Elements;
36-
NodeSubset(BitVector e) : Elements(e) {}
37-
public:
38-
/// NodeSubset - Default constructor, creates an empty subset.
39-
NodeSubset() : Elements(0) {
40-
assert(N <= sizeof(BitVector)*CHAR_BIT && "Graph too big!");
41-
}
42-
43-
/// Comparison operators.
44-
bool operator==(const NodeSubset &other) const {
45-
return other.Elements == this->Elements;
46-
}
47-
bool operator!=(const NodeSubset &other) const {
48-
return !(*this == other);
49-
}
50-
51-
/// AddNode - Add the node with the given index to the subset.
52-
void AddNode(unsigned Idx) {
53-
ValidateIndex(Idx);
54-
Elements |= 1U << Idx;
55-
}
56-
57-
/// DeleteNode - Remove the node with the given index from the subset.
58-
void DeleteNode(unsigned Idx) {
59-
ValidateIndex(Idx);
60-
Elements &= ~(1U << Idx);
61-
}
62-
63-
/// count - Return true if the node with the given index is in the subset.
64-
bool count(unsigned Idx) {
65-
ValidateIndex(Idx);
66-
return (Elements & (1U << Idx)) != 0;
67-
}
68-
69-
/// isEmpty - Return true if this is the empty set.
70-
bool isEmpty() const {
71-
return Elements == 0;
72-
}
73-
74-
/// isSubsetOf - Return true if this set is a subset of the given one.
75-
bool isSubsetOf(const NodeSubset &other) const {
76-
return (this->Elements | other.Elements) == other.Elements;
77-
}
78-
79-
/// Complement - Return the complement of this subset.
80-
NodeSubset Complement() const {
81-
return ~(unsigned)this->Elements & ((1U << N) - 1);
82-
}
83-
84-
/// Join - Return the union of this subset and the given one.
85-
NodeSubset Join(const NodeSubset &other) const {
86-
return this->Elements | other.Elements;
87-
}
88-
89-
/// Meet - Return the intersection of this subset and the given one.
90-
NodeSubset Meet(const NodeSubset &other) const {
91-
return this->Elements & other.Elements;
92-
}
93-
};
94-
95-
/// NodeType - Node index and set of children of the node.
96-
typedef std::pair<unsigned, NodeSubset> NodeType;
97-
98-
private:
99-
/// Nodes - The list of nodes for this graph.
100-
NodeType Nodes[N];
101-
public:
102-
103-
/// Graph - Default constructor. Creates an empty graph.
104-
Graph() {
105-
// Let each node know which node it is. This allows us to find the start of
106-
// the Nodes array given a pointer to any element of it.
107-
for (unsigned i = 0; i != N; ++i)
108-
Nodes[i].first = i;
109-
}
110-
111-
/// AddEdge - Add an edge from the node with index FromIdx to the node with
112-
/// index ToIdx.
113-
void AddEdge(unsigned FromIdx, unsigned ToIdx) {
114-
ValidateIndex(FromIdx);
115-
Nodes[FromIdx].second.AddNode(ToIdx);
116-
}
117-
118-
/// DeleteEdge - Remove the edge (if any) from the node with index FromIdx to
119-
/// the node with index ToIdx.
120-
void DeleteEdge(unsigned FromIdx, unsigned ToIdx) {
121-
ValidateIndex(FromIdx);
122-
Nodes[FromIdx].second.DeleteNode(ToIdx);
123-
}
124-
125-
/// AccessNode - Get a pointer to the node with the given index.
126-
NodeType *AccessNode(unsigned Idx) const {
127-
ValidateIndex(Idx);
128-
// The constant cast is needed when working with GraphTraits, which insists
129-
// on taking a constant Graph.
130-
return const_cast<NodeType *>(&Nodes[Idx]);
131-
}
132-
133-
/// NodesReachableFrom - Return the set of all nodes reachable from the given
134-
/// node.
135-
NodeSubset NodesReachableFrom(unsigned Idx) const {
136-
// This algorithm doesn't scale, but that doesn't matter given the small
137-
// size of our graphs.
138-
NodeSubset Reachable;
139-
140-
// The initial node is reachable.
141-
Reachable.AddNode(Idx);
142-
do {
143-
NodeSubset Previous(Reachable);
144-
145-
// Add in all nodes which are children of a reachable node.
146-
for (unsigned i = 0; i != N; ++i)
147-
if (Previous.count(i))
148-
Reachable = Reachable.Join(Nodes[i].second);
149-
150-
// If nothing changed then we have found all reachable nodes.
151-
if (Reachable == Previous)
152-
return Reachable;
153-
154-
// Rinse and repeat.
155-
} while (1);
156-
}
157-
158-
/// ChildIterator - Visit all children of a node.
159-
class ChildIterator {
160-
friend class Graph;
161-
162-
/// FirstNode - Pointer to first node in the graph's Nodes array.
163-
NodeType *FirstNode;
164-
/// Children - Set of nodes which are children of this one and that haven't
165-
/// yet been visited.
166-
NodeSubset Children;
167-
168-
ChildIterator(); // Disable default constructor.
169-
protected:
170-
ChildIterator(NodeType *F, NodeSubset C) : FirstNode(F), Children(C) {}
171-
172-
public:
173-
/// ChildIterator - Copy constructor.
174-
ChildIterator(const ChildIterator& other) : FirstNode(other.FirstNode),
175-
Children(other.Children) {}
176-
177-
/// Comparison operators.
178-
bool operator==(const ChildIterator &other) const {
179-
return other.FirstNode == this->FirstNode &&
180-
other.Children == this->Children;
181-
}
182-
bool operator!=(const ChildIterator &other) const {
183-
return !(*this == other);
184-
}
185-
186-
/// Prefix increment operator.
187-
ChildIterator& operator++() {
188-
// Find the next unvisited child node.
189-
for (unsigned i = 0; i != N; ++i)
190-
if (Children.count(i)) {
191-
// Remove that child - it has been visited. This is the increment!
192-
Children.DeleteNode(i);
193-
return *this;
194-
}
195-
assert(false && "Incrementing end iterator!");
196-
return *this; // Avoid compiler warnings.
197-
}
198-
199-
/// Postfix increment operator.
200-
ChildIterator operator++(int) {
201-
ChildIterator Result(*this);
202-
++(*this);
203-
return Result;
204-
}
205-
206-
/// Dereference operator.
207-
NodeType *operator*() {
208-
// Find the next unvisited child node.
209-
for (unsigned i = 0; i != N; ++i)
210-
if (Children.count(i))
211-
// Return a pointer to it.
212-
return FirstNode + i;
213-
assert(false && "Dereferencing end iterator!");
214-
return nullptr; // Avoid compiler warning.
215-
}
216-
};
217-
218-
/// child_begin - Return an iterator pointing to the first child of the given
219-
/// node.
220-
static ChildIterator child_begin(NodeType *Parent) {
221-
return ChildIterator(Parent - Parent->first, Parent->second);
222-
}
223-
224-
/// child_end - Return the end iterator for children of the given node.
225-
static ChildIterator child_end(NodeType *Parent) {
226-
return ChildIterator(Parent - Parent->first, NodeSubset());
227-
}
228-
};
229-
230-
template <unsigned N>
231-
struct GraphTraits<Graph<N> > {
232-
typedef typename Graph<N>::NodeType *NodeRef;
233-
typedef typename Graph<N>::ChildIterator ChildIteratorType;
234-
235-
static inline NodeRef getEntryNode(const Graph<N> &G) {
236-
return G.AccessNode(0);
237-
}
238-
static inline ChildIteratorType child_begin(NodeRef Node) {
239-
return Graph<N>::child_begin(Node);
240-
}
241-
static inline ChildIteratorType child_end(NodeRef Node) {
242-
return Graph<N>::child_end(Node);
243-
}
244-
};
245-
24619
TEST(SCCIteratorTest, AllSmallGraphs) {
24720
// Test SCC computation against every graph with NUM_NODES nodes or less.
24821
// Since SCC considers every node to have an implicit self-edge, we only

0 commit comments

Comments
 (0)