Skip to content

Commit fb6feb8

Browse files
authored
[ADT] Restore handwritten vector find in SmallSet (#110254)
This patch restores handwritten linear searches instead of the use of std::find. After PR #109412, a performance regression was observed that's caused by the use of std::find for linear searches. The exact cause wasn't pinpointed, but, at the time of writing, the most likely culprit is the forced loop unrolling in the definition of libstdc++'s std::find. Presumably this is done to optimise for larger containers. However for the case of small containers such as SmallVector, this actually hurts performance.
1 parent f3ebf22 commit fb6feb8

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

llvm/include/llvm/ADT/SmallSet.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class SmallSet {
193193
bool erase(const T &V) {
194194
if (!isSmall())
195195
return Set.erase(V);
196-
auto I = std::find(Vector.begin(), Vector.end(), V);
196+
auto I = vfind(V);
197197
if (I != Vector.end()) {
198198
Vector.erase(I);
199199
return true;
@@ -221,7 +221,7 @@ class SmallSet {
221221
/// Check if the SmallSet contains the given element.
222222
bool contains(const T &V) const {
223223
if (isSmall())
224-
return std::find(Vector.begin(), Vector.end(), V) != Vector.end();
224+
return vfind(V) != Vector.end();
225225
return Set.find(V) != Set.end();
226226
}
227227

@@ -237,20 +237,28 @@ class SmallSet {
237237
return {const_iterator(I), Inserted};
238238
}
239239

240-
auto I = std::find(Vector.begin(), Vector.end(), V);
240+
auto I = vfind(V);
241241
if (I != Vector.end()) // Don't reinsert if it already exists.
242242
return {const_iterator(I), false};
243243
if (Vector.size() < N) {
244244
Vector.push_back(std::forward<ArgType>(V));
245245
return {const_iterator(std::prev(Vector.end())), true};
246246
}
247-
248247
// Otherwise, grow from vector to set.
249248
Set.insert(std::make_move_iterator(Vector.begin()),
250249
std::make_move_iterator(Vector.end()));
251250
Vector.clear();
252251
return {const_iterator(Set.insert(std::forward<ArgType>(V)).first), true};
253252
}
253+
254+
// Handwritten linear search. The use of std::find might hurt performance as
255+
// its implementation may be optimized for larger containers.
256+
typename SmallVector<T, N>::const_iterator vfind(const T &V) const {
257+
for (auto I = Vector.begin(), E = Vector.end(); I != E; ++I)
258+
if (*I == V)
259+
return I;
260+
return Vector.end();
261+
}
254262
};
255263

256264
/// If this set is of pointer values, transparently switch over to using

0 commit comments

Comments
 (0)