Skip to content

Commit a683c91

Browse files
committed
Use SetVector
1 parent 242e6a8 commit a683c91

File tree

2 files changed

+115
-73
lines changed

2 files changed

+115
-73
lines changed

llvm/include/llvm/ADT/EquivalenceClasses.h

Lines changed: 108 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
#ifndef LLVM_ADT_EQUIVALENCECLASSES_H
1616
#define LLVM_ADT_EQUIVALENCECLASSES_H
1717

18-
#include "llvm/ADT/DenseMap.h"
19-
#include "llvm/ADT/SmallVector.h"
18+
#include "llvm/ADT/SetVector.h"
2019
#include "llvm/Support/Allocator.h"
2120
#include <cassert>
2221
#include <cstddef>
@@ -58,66 +57,101 @@ namespace llvm {
5857
/// 4
5958
/// 5 1 2
6059
///
61-
template <class ElemTy> class EquivalenceClasses {
62-
/// ECValue - The EquivalenceClasses data structure is just a set of these.
63-
/// Each of these represents a relation for a value. First it stores the
64-
/// value itself, which provides the ordering that the set queries. Next, it
65-
/// provides a "next pointer", which is used to enumerate all of the elements
66-
/// in the unioned set. Finally, it defines either a "end of list pointer" or
67-
/// "leader pointer" depending on whether the value itself is a leader. A
68-
/// "leader pointer" points to the node that is the leader for this element,
69-
/// if the node is not a leader. A "end of list pointer" points to the last
70-
/// node in the list of members of this list. Whether or not a node is a
71-
/// leader is determined by a bit stolen from one of the pointers.
72-
class ECValue {
73-
friend class EquivalenceClasses;
7460

75-
mutable const ECValue *Leader, *Next;
76-
ElemTy Data;
61+
template <class ElemTy> class EquivalenceClasses;
62+
/// ECValue - The EquivalenceClasses data structure is just a set of these.
63+
/// Each of these represents a relation for a value. First it stores the
64+
/// value itself, which provides the ordering that the set queries. Next, it
65+
/// provides a "next pointer", which is used to enumerate all of the elements
66+
/// in the unioned set. Finally, it defines either a "end of list pointer" or
67+
/// "leader pointer" depending on whether the value itself is a leader. A
68+
/// "leader pointer" points to the node that is the leader for this element,
69+
/// if the node is not a leader. A "end of list pointer" points to the last
70+
/// node in the list of members of this list. Whether or not a node is a
71+
/// leader is determined by a bit stolen from one of the pointers.
72+
template <class ElemTy> class ECValue {
73+
friend class EquivalenceClasses<ElemTy>;
74+
75+
mutable const ECValue *Leader, *Next;
76+
ElemTy Data;
77+
78+
// ECValue ctor - Start out with EndOfList pointing to this node, Next is
79+
// Null, isLeader = true.
80+
ECValue(const ElemTy &Elt)
81+
: Leader(this), Next((ECValue *)(intptr_t)1), Data(Elt) {}
82+
83+
const ECValue *getLeader() const {
84+
if (isLeader())
85+
return this;
86+
if (Leader->isLeader())
87+
return Leader;
88+
// Path compression.
89+
return Leader = Leader->getLeader();
90+
}
7791

78-
// ECValue ctor - Start out with EndOfList pointing to this node, Next is
79-
// Null, isLeader = true.
80-
ECValue(const ElemTy &Elt)
81-
: Leader(this), Next((ECValue*)(intptr_t)1), Data(Elt) {}
92+
const ECValue *getEndOfList() const {
93+
assert(isLeader() && "Cannot get the end of a list for a non-leader!");
94+
return Leader;
95+
}
8296

83-
const ECValue *getLeader() const {
84-
if (isLeader()) return this;
85-
if (Leader->isLeader()) return Leader;
86-
// Path compression.
87-
return Leader = Leader->getLeader();
88-
}
97+
void setNext(const ECValue *NewNext) const {
98+
assert(getNext() == nullptr && "Already has a next pointer!");
99+
Next = (const ECValue *)((intptr_t)NewNext | (intptr_t)isLeader());
100+
}
89101

90-
const ECValue *getEndOfList() const {
91-
assert(isLeader() && "Cannot get the end of a list for a non-leader!");
92-
return Leader;
93-
}
102+
public:
103+
ECValue(const ECValue &RHS)
104+
: Leader(this), Next((ECValue *)(intptr_t)1), Data(RHS.Data) {
105+
// Only support copying of singleton nodes.
106+
essert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
107+
}
94108

95-
void setNext(const ECValue *NewNext) const {
96-
assert(getNext() == nullptr && "Already has a next pointer!");
97-
Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
98-
}
109+
bool isLeader() const { return (intptr_t)Next & 1; }
110+
const ElemTy &getData() const { return Data; }
99111

100-
public:
101-
ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
102-
Data(RHS.Data) {
103-
// Only support copying of singleton nodes.
104-
assert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
105-
}
112+
const ECValue *getNext() const {
113+
return (ECValue *)((intptr_t)Next & ~(intptr_t)1);
114+
}
115+
};
106116

107-
bool isLeader() const { return (intptr_t)Next & 1; }
108-
const ElemTy &getData() const { return Data; }
117+
template <class ElemTy> struct DenseMapInfo<ECValue<ElemTy> *> {
118+
static constexpr uintptr_t Log2MaxAlign = 12;
109119

110-
const ECValue *getNext() const {
111-
return (ECValue*)((intptr_t)Next & ~(intptr_t)1);
112-
}
113-
};
120+
static inline ECValue<ElemTy> *getEmptyKey() {
121+
uintptr_t Val = static_cast<uintptr_t>(-1);
122+
Val <<= Log2MaxAlign;
123+
return reinterpret_cast<ECValue<ElemTy> *>(Val);
124+
}
125+
126+
static inline ECValue<ElemTy> *getTombstoneKey() {
127+
uintptr_t Val = static_cast<uintptr_t>(-2);
128+
Val <<= Log2MaxAlign;
129+
return reinterpret_cast<ECValue<ElemTy> *>(Val);
130+
}
131+
132+
static unsigned getHashValue(const ECValue<ElemTy> *PtrVal) {
133+
return DenseMapInfo<ElemTy>::getHashValue(PtrVal->getData());
134+
}
114135

136+
static bool isEqual(const ECValue<ElemTy> *LHS, const ECValue<ElemTy> *RHS) {
137+
if (LHS == RHS)
138+
return true;
139+
if (LHS == getEmptyKey() && RHS != getEmptyKey())
140+
return false;
141+
if (RHS == getEmptyKey() && LHS != getEmptyKey())
142+
return false;
143+
if (LHS == getTombstoneKey() && RHS != getTombstoneKey())
144+
return false;
145+
if (RHS == getTombstoneKey() && LHS != getTombstoneKey())
146+
return false;
147+
return DenseMapInfo<ElemTy>::isEqual(LHS->getData(), RHS->getData());
148+
}
149+
};
150+
151+
template <class ElemTy> class EquivalenceClasses {
115152
/// TheMapping - This implicitly provides a mapping from ElemTy values to the
116153
/// ECValues, it just keeps the key as part of the value.
117-
DenseMap<ElemTy, ECValue *> TheMapping;
118-
119-
/// List of all members, used to provide a determinstic iteration order.
120-
SmallVector<const ECValue *> Members;
154+
SetVector<ECValue<ElemTy> *> TheMapping;
121155

122156
mutable BumpPtrAllocator ECValueAllocator;
123157

@@ -129,7 +163,6 @@ template <class ElemTy> class EquivalenceClasses {
129163

130164
EquivalenceClasses &operator=(const EquivalenceClasses &RHS) {
131165
TheMapping.clear();
132-
Members.clear();
133166
for (const auto &E : RHS)
134167
if (E->isLeader()) {
135168
member_iterator MI = RHS.member_begin(*E);
@@ -145,16 +178,16 @@ template <class ElemTy> class EquivalenceClasses {
145178
//
146179

147180
/// iterator* - Provides a way to iterate over all values in the set.
148-
using iterator = typename SmallVector<const ECValue *>::const_iterator;
181+
using iterator = typename decltype(TheMapping)::const_iterator;
149182

150-
iterator begin() const { return Members.begin(); }
151-
iterator end() const { return Members.end(); }
183+
iterator begin() const { return TheMapping.begin(); }
184+
iterator end() const { return TheMapping.end(); }
152185

153186
bool empty() const { return TheMapping.empty(); }
154187

155188
/// member_* Iterate over the members of an equivalence class.
156189
class member_iterator;
157-
member_iterator member_begin(const ECValue &ECV) const {
190+
member_iterator member_begin(const ECValue<ElemTy> &ECV) const {
158191
// Only leaders provide anything to iterate over.
159192
return member_iterator(ECV.isLeader() ? &ECV : nullptr);
160193
}
@@ -165,7 +198,8 @@ template <class ElemTy> class EquivalenceClasses {
165198

166199
/// Returns true if \p V is contained an equivalence class.
167200
bool contains(const ElemTy &V) const {
168-
return TheMapping.find(V) != TheMapping.end();
201+
ECValue<ElemTy> Tmp(V);
202+
return TheMapping.set_find(&Tmp) != TheMapping.set_end();
169203
}
170204

171205
/// getLeaderValue - Return the leader for the specified value that is in the
@@ -201,14 +235,14 @@ template <class ElemTy> class EquivalenceClasses {
201235

202236
/// insert - Insert a new value into the union/find set, ignoring the request
203237
/// if the value already exists.
204-
const ECValue &insert(const ElemTy &Data) {
205-
auto I = TheMapping.insert({Data, nullptr});
206-
if (!I.second)
207-
return *I.first->second;
208-
209-
auto *ECV = new (ECValueAllocator) ECValue(Data);
210-
I.first->second = ECV;
211-
Members.push_back(ECV);
238+
const ECValue<ElemTy> &insert(const ElemTy &Data) {
239+
ECValue<ElemTy> Tmp(Data);
240+
auto I = TheMapping.set_find(&Tmp);
241+
if (I != TheMapping.set_end())
242+
return **I;
243+
244+
auto *ECV = new (ECValueAllocator) ECValue<ElemTy>(Data);
245+
TheMapping.insert(ECV);
212246
return *ECV;
213247
}
214248

@@ -217,19 +251,20 @@ template <class ElemTy> class EquivalenceClasses {
217251
/// makes union-find "union findy". This returns an end iterator if the value
218252
/// is not in the equivalence class.
219253
member_iterator findLeader(const ElemTy &V) const {
220-
auto I = TheMapping.find(V);
221-
if (I == TheMapping.end())
254+
ECValue<ElemTy> Tmp(V);
255+
auto I = TheMapping.set_find(&Tmp);
256+
if (I == TheMapping.set_end())
222257
return member_iterator(nullptr);
223-
return findLeader(*I->second);
258+
return findLeader(**I);
224259
}
225-
member_iterator findLeader(const ECValue &ECV) const {
260+
member_iterator findLeader(const ECValue<ElemTy> &ECV) const {
226261
return member_iterator(ECV.getLeader());
227262
}
228263

229264
/// union - Merge the two equivalence sets for the specified values, inserting
230265
/// them if they do not already exist in the equivalence set.
231266
member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
232-
const ECValue &V1I = insert(V1), &V2I = insert(V2);
267+
const ECValue<ElemTy> &V1I = insert(V1), &V2I = insert(V2);
233268
return unionSets(findLeader(V1I), findLeader(V2I));
234269
}
235270
member_iterator unionSets(member_iterator L1, member_iterator L2) {
@@ -238,7 +273,7 @@ template <class ElemTy> class EquivalenceClasses {
238273

239274
// Otherwise, this is a real union operation. Set the end of the L1 list to
240275
// point to the L2 leader node.
241-
const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
276+
const ECValue<ElemTy> &L1LV = *L1.Node, &L2LV = *L2.Node;
242277
L1LV.getEndOfList()->setNext(&L2LV);
243278

244279
// Update L1LV's end of list pointer.
@@ -265,7 +300,7 @@ template <class ElemTy> class EquivalenceClasses {
265300
class member_iterator {
266301
friend class EquivalenceClasses;
267302

268-
const ECValue *Node;
303+
const ECValue<ElemTy> *Node;
269304

270305
public:
271306
using iterator_category = std::forward_iterator_tag;
@@ -276,7 +311,7 @@ template <class ElemTy> class EquivalenceClasses {
276311
using reference = value_type &;
277312

278313
explicit member_iterator() = default;
279-
explicit member_iterator(const ECValue *N) : Node(N) {}
314+
explicit member_iterator(const ECValue<ElemTy> *N) : Node(N) {}
280315

281316
reference operator*() const {
282317
assert(Node != nullptr && "Dereferencing end()!");

llvm/include/llvm/ADT/SetVector.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ class SetVector {
125125
return vector_.end();
126126
}
127127

128+
/// Get a const_iterator to the end of the SetVector.
129+
typename set_type::const_iterator set_end() const { return set_.end(); }
130+
128131
/// Get an reverse_iterator to the end of the SetVector.
129132
reverse_iterator rbegin() {
130133
return vector_.rbegin();
@@ -269,6 +272,10 @@ class SetVector {
269272
return set_.find(key) != set_.end();
270273
}
271274

275+
typename set_type::const_iterator set_find(const key_type &key) const {
276+
return set_.find(key);
277+
}
278+
272279
/// Count the number of elements of a given key in the SetVector.
273280
/// \returns 0 if the element is not in the SetVector, 1 if it is.
274281
size_type count(const key_type &key) const {

0 commit comments

Comments
 (0)