Skip to content

Commit 1379999

Browse files
authored
[EquivalenceClasses] Use DenseMap instead of std::set. (NFC) (#134264)
Replace the std::set with DenseMap, which removes the requirement for an ordering predicate. This also requires to allocate the ECValue objects separately. This patch uses a BumpPtrAllocator. Follow-up to #134075. Compile-time impact is mostly neutral or slightly positive: https://llvm-compile-time-tracker.com/compare.php?from=ee4e8197fa67dd1ed6e9470e00708e7feeaacd97&to=242e6a8e42889eebfc0bb5d433a4de7dd9e224a7&stat=instructions:u
1 parent cd54cb0 commit 1379999

File tree

4 files changed

+29
-81
lines changed

4 files changed

+29
-81
lines changed

llvm/include/llvm/ADT/EquivalenceClasses.h

+24-42
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
#ifndef LLVM_ADT_EQUIVALENCECLASSES_H
1616
#define LLVM_ADT_EQUIVALENCECLASSES_H
1717

18+
#include "llvm/ADT/DenseMap.h"
1819
#include "llvm/ADT/SmallVector.h"
1920
#include "llvm/ADT/iterator_range.h"
21+
#include "llvm/Support/Allocator.h"
2022
#include <cassert>
2123
#include <cstddef>
2224
#include <cstdint>
2325
#include <iterator>
24-
#include <set>
2526

2627
namespace llvm {
2728

@@ -33,8 +34,7 @@ namespace llvm {
3334
///
3435
/// This implementation is an efficient implementation that only stores one copy
3536
/// of the element being indexed per entry in the set, and allows any arbitrary
36-
/// type to be indexed (as long as it can be ordered with operator< or a
37-
/// comparator is provided).
37+
/// type to be indexed (as long as it can be implements DenseMapInfo).
3838
///
3939
/// Here is a simple example using integers:
4040
///
@@ -58,18 +58,17 @@ namespace llvm {
5858
/// 4
5959
/// 5 1 2
6060
///
61-
template <class ElemTy, class Compare = std::less<ElemTy>>
62-
class EquivalenceClasses {
61+
template <class ElemTy> class EquivalenceClasses {
6362
/// ECValue - The EquivalenceClasses data structure is just a set of these.
6463
/// Each of these represents a relation for a value. First it stores the
65-
/// value itself, which provides the ordering that the set queries. Next, it
66-
/// provides a "next pointer", which is used to enumerate all of the elements
67-
/// in the unioned set. Finally, it defines either a "end of list pointer" or
68-
/// "leader pointer" depending on whether the value itself is a leader. A
69-
/// "leader pointer" points to the node that is the leader for this element,
70-
/// if the node is not a leader. A "end of list pointer" points to the last
71-
/// node in the list of members of this list. Whether or not a node is a
72-
/// leader is determined by a bit stolen from one of the pointers.
64+
/// value itself. Next, it provides a "next pointer", which is used to
65+
/// enumerate all of the elements in the unioned set. Finally, it defines
66+
/// either a "end of list pointer" or "leader pointer" depending on whether
67+
/// the value itself is a leader. A "leader pointer" points to the node that
68+
/// is the leader for this element, if the node is not a leader. A "end of
69+
/// list pointer" points to the last node in the list of members of this list.
70+
/// Whether or not a node is a leader is determined by a bit stolen from one
71+
/// of the pointers.
7372
class ECValue {
7473
friend class EquivalenceClasses;
7574

@@ -113,36 +112,15 @@ class EquivalenceClasses {
113112
}
114113
};
115114

116-
/// A wrapper of the comparator, to be passed to the set.
117-
struct ECValueComparator {
118-
using is_transparent = void;
119-
120-
ECValueComparator() : compare(Compare()) {}
121-
122-
bool operator()(const ECValue &lhs, const ECValue &rhs) const {
123-
return compare(lhs.Data, rhs.Data);
124-
}
125-
126-
template <typename T>
127-
bool operator()(const T &lhs, const ECValue &rhs) const {
128-
return compare(lhs, rhs.Data);
129-
}
130-
131-
template <typename T>
132-
bool operator()(const ECValue &lhs, const T &rhs) const {
133-
return compare(lhs.Data, rhs);
134-
}
135-
136-
const Compare compare;
137-
};
138-
139115
/// TheMapping - This implicitly provides a mapping from ElemTy values to the
140116
/// ECValues, it just keeps the key as part of the value.
141-
std::set<ECValue, ECValueComparator> TheMapping;
117+
DenseMap<ElemTy, ECValue *> TheMapping;
142118

143119
/// List of all members, used to provide a determinstic iteration order.
144120
SmallVector<const ECValue *> Members;
145121

122+
mutable BumpPtrAllocator ECValueAllocator;
123+
146124
public:
147125
EquivalenceClasses() = default;
148126
EquivalenceClasses(const EquivalenceClasses &RHS) {
@@ -232,10 +210,14 @@ class EquivalenceClasses {
232210
/// insert - Insert a new value into the union/find set, ignoring the request
233211
/// if the value already exists.
234212
const ECValue &insert(const ElemTy &Data) {
235-
auto I = TheMapping.insert(ECValue(Data));
236-
if (I.second)
237-
Members.push_back(&*I.first);
238-
return *I.first;
213+
auto I = TheMapping.insert({Data, nullptr});
214+
if (!I.second)
215+
return *I.first->second;
216+
217+
auto *ECV = new (ECValueAllocator) ECValue(Data);
218+
I.first->second = ECV;
219+
Members.push_back(ECV);
220+
return *ECV;
239221
}
240222

241223
/// findLeader - Given a value in the set, return a member iterator for the
@@ -246,7 +228,7 @@ class EquivalenceClasses {
246228
auto I = TheMapping.find(V);
247229
if (I == TheMapping.end())
248230
return member_iterator(nullptr);
249-
return findLeader(*I);
231+
return findLeader(*I->second);
250232
}
251233
member_iterator findLeader(const ECValue &ECV) const {
252234
return member_iterator(ECV.getLeader());

llvm/lib/Transforms/Vectorize/VectorCombine.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "llvm/Transforms/Utils/LoopUtils.h"
3434
#include <numeric>
3535
#include <queue>
36+
#include <set>
3637

3738
#define DEBUG_TYPE "vector-combine"
3839
#include "llvm/Transforms/Utils/InstructionWorklist.h"

llvm/unittests/ADT/EquivalenceClassesTest.cpp

-26
Original file line numberDiff line numberDiff line change
@@ -109,30 +109,4 @@ TYPED_TEST_P(ParameterizedTest, MultipleSets) {
109109
EXPECT_FALSE(EqClasses.isEquivalent(i, j));
110110
}
111111

112-
namespace {
113-
// A dummy struct for testing EquivalenceClasses with a comparator.
114-
struct TestStruct {
115-
TestStruct(int value) : value(value) {}
116-
117-
bool operator==(const TestStruct &other) const {
118-
return value == other.value;
119-
}
120-
121-
int value;
122-
};
123-
// Comparator to be used in test case.
124-
struct TestStructComparator {
125-
bool operator()(const TestStruct &lhs, const TestStruct &rhs) const {
126-
return lhs.value < rhs.value;
127-
}
128-
};
129-
} // namespace
130-
131-
REGISTER_TYPED_TEST_SUITE_P(ParameterizedTest, MultipleSets);
132-
using ParamTypes =
133-
testing::Types<EquivalenceClasses<int>,
134-
EquivalenceClasses<TestStruct, TestStructComparator>>;
135-
INSTANTIATE_TYPED_TEST_SUITE_P(EquivalenceClassesTest, ParameterizedTest,
136-
ParamTypes, );
137-
138112
} // llvm

mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h

+4-13
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,8 @@ class OneShotAnalysisState : public AnalysisState {
224224
}
225225

226226
private:
227-
/// llvm::EquivalenceClasses wants comparable elements. This comparator uses
228-
/// pointer comparison on the defining op. This is a poor man's comparison
229-
/// but it's not like UnionFind needs ordering anyway.
230-
struct ValueComparator {
231-
bool operator()(const Value &lhs, const Value &rhs) const {
232-
return lhs.getImpl() < rhs.getImpl();
233-
}
234-
};
235-
236-
using EquivalenceClassRangeType = llvm::iterator_range<
237-
llvm::EquivalenceClasses<Value, ValueComparator>::member_iterator>;
227+
using EquivalenceClassRangeType =
228+
llvm::iterator_range<llvm::EquivalenceClasses<Value>::member_iterator>;
238229
/// Check that aliasInfo for `v` exists and return a reference to it.
239230
EquivalenceClassRangeType getAliases(Value v) const;
240231

@@ -249,15 +240,15 @@ class OneShotAnalysisState : public AnalysisState {
249240
/// value may alias with one of multiple other values. The concrete aliasing
250241
/// value may not even be known at compile time. All such values are
251242
/// considered to be aliases.
252-
llvm::EquivalenceClasses<Value, ValueComparator> aliasInfo;
243+
llvm::EquivalenceClasses<Value> aliasInfo;
253244

254245
/// Auxiliary structure to store all the equivalent buffer classes. Equivalent
255246
/// buffer information is "must be" conservative: Only if two values are
256247
/// guaranteed to be equivalent at runtime, they said to be equivalent. It is
257248
/// possible that, in the presence of branches, it cannot be determined
258249
/// statically if two values are equivalent. In that case, the values are
259250
/// considered to be not equivalent.
260-
llvm::EquivalenceClasses<Value, ValueComparator> equivalentInfo;
251+
llvm::EquivalenceClasses<Value> equivalentInfo;
261252

262253
// Bufferization statistics.
263254
int64_t statNumTensorOutOfPlace = 0;

0 commit comments

Comments
 (0)