Skip to content

Commit d222b69

Browse files
committed
[MLIR][Presburger] Add Identifier class to store identifiers and their type
This patch adds a new class Identifier to store identifiers in PresburgerSpace and their types. Identifiers were added earlier and were stored as a void pointer, and their type in the form of mlir::TypeId in PresburgerSpace. To get an identifier, a user of PresburgerSpace needed to know the type of identifiers. This was a problem for users of PresburgerSpace like IntegerRelation, which want to work on identifiers without knowing their type. The Identifier class allows users like IntegerRelation to work on identifiers without knowing their type, and also exposes an easier way to work with Identifiers. Reviewed By: arjunp Differential Revision: https://reviews.llvm.org/D146909
1 parent 5f667a5 commit d222b69

File tree

3 files changed

+335
-137
lines changed

3 files changed

+335
-137
lines changed

mlir/include/mlir/Analysis/Presburger/PresburgerSpace.h

Lines changed: 128 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,90 @@ namespace presburger {
2828
/// as relations with zero domain vars.
2929
enum class VarKind { Symbol, Local, Domain, Range, SetDim = Range };
3030

31+
/// An Identifier stores a pointer to an object, such as a Value or an
32+
/// Operation. Identifiers are intended to be attached to a variable in a
33+
/// PresburgerSpace and can be used to check if two variables correspond to the
34+
/// same object.
35+
///
36+
/// Take for example the following code:
37+
///
38+
/// for i = 0 to 100
39+
/// for j = 0 to 100
40+
/// S0: A[j] = 0
41+
/// for k = 0 to 100
42+
/// S1: A[k] = 1
43+
///
44+
/// If we represent the space of iteration variables surrounding S0, S1 we have:
45+
/// space(S0): {d0, d1}
46+
/// space(S1): {d0, d1}
47+
///
48+
/// Since the variables are in different spaces, without an identifier, there
49+
/// is no way to distinguish if the variables in the two spaces correspond to
50+
/// different SSA values in the program. So, we attach an Identifier
51+
/// corresponding to the loop iteration variable to them. Now,
52+
///
53+
/// space(S0) = {d0(id = i), d1(id = j)}
54+
/// space(S1) = {d0(id = i), d1(id = k)}.
55+
///
56+
/// Using the identifier, we can check that the first iteration variable in
57+
/// both the spaces correspond to the same variable in the program, while they
58+
/// are different for second iteration variable.
59+
///
60+
/// The equality of Identifiers is checked by comparing the stored pointers.
61+
/// Checking equality asserts that the type of the equal identifiers is same.
62+
/// Identifiers storing null pointers are treated as having no attachment and
63+
/// are considered unequal to any other identifier, including other identifiers
64+
/// with no attachments.
65+
///
66+
/// The type of the pointer stored must have an `llvm::PointerLikeTypeTraits`
67+
/// specialization.
68+
class Identifier {
69+
public:
70+
Identifier() = default;
71+
72+
// Create an identifier from a pointer.
73+
template <typename T>
74+
explicit Identifier(T value)
75+
: value(llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(value)) {
76+
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
77+
idType = TypeID::get<T>();
78+
#endif
79+
}
80+
81+
/// Get the value of the identifier casted to type `T`. `T` here should match
82+
/// the type of the identifier used to create it.
83+
template <typename T>
84+
T getValue() const {
85+
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
86+
assert(TypeID::get<T>() == idType &&
87+
"Identifier was initialized with a different type than the one used "
88+
"to retrieve it.");
89+
#endif
90+
return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(value);
91+
}
92+
93+
bool hasValue() const { return value != nullptr; }
94+
95+
/// Check if the two identifiers are equal. Null identifiers are considered
96+
/// not equal. Asserts if two identifiers are equal but their types are not.
97+
bool isEqual(const Identifier &other) const;
98+
99+
bool operator==(const Identifier &other) const { return isEqual(other); }
100+
bool operator!=(const Identifier &other) const { return !isEqual(other); }
101+
102+
void print(llvm::raw_ostream &os) const;
103+
void dump() const;
104+
105+
private:
106+
/// The value of the identifier.
107+
void *value = nullptr;
108+
109+
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
110+
/// TypeID of the identifiers in space. This should be used in asserts only.
111+
TypeID idType = TypeID::get<void>();
112+
#endif
113+
};
114+
31115
/// PresburgerSpace is the space of all possible values of a tuple of integer
32116
/// valued variables/variables. Each variable has one of the three types:
33117
///
@@ -66,14 +150,12 @@ enum class VarKind { Symbol, Local, Domain, Range, SetDim = Range };
66150
/// other than Locals are equal. Equality of two spaces implies that number of
67151
/// variables of each kind are equal.
68152
///
69-
/// PresburgerSpace optionally also supports attaching some information to each
70-
/// variable in space, called "identifier" of that variable. `resetIds<IdType>`
71-
/// is used to enable/reset these identifiers. All identifiers must be of the
72-
/// same type, `IdType`. `IdType` must have a `llvm::PointerLikeTypeTraits`
73-
/// specialization available and should be supported via `mlir::TypeID`.
74-
///
75-
/// These identifiers can be used to check if two variables in two different
76-
/// spaces are actually same variable.
153+
/// PresburgerSpace optionally also supports attaching an Identifier with each
154+
/// non-local variable in the space. This is disabled by default. `resetIds` is
155+
/// used to enable/reset these identifiers. The user can identify each variable
156+
/// in the space as corresponding to some Identifier. Some example use cases
157+
/// are described in the `Identifier` documentation above. The type attached to
158+
/// the Identifier can be different for different variables in the space.
77159
class PresburgerSpace {
78160
public:
79161
static PresburgerSpace getRelationSpace(unsigned numDomain = 0,
@@ -142,6 +224,20 @@ class PresburgerSpace {
142224
/// varLimit). The range is relative to the kind of variable.
143225
void removeVarRange(VarKind kind, unsigned varStart, unsigned varLimit);
144226

227+
/// Converts variables of the specified kind in the column range [srcPos,
228+
/// srcPos + num) to variables of the specified kind at position dstPos. The
229+
/// ranges are relative to the kind of variable.
230+
///
231+
/// srcKind and dstKind must be different.
232+
void convertVarKind(VarKind srcKind, unsigned srcPos, unsigned num,
233+
VarKind dstKind, unsigned dstPos);
234+
235+
/// Changes the partition between dimensions and symbols. Depending on the new
236+
/// symbol count, either a chunk of dimensional variables immediately before
237+
/// the split become symbols, or some of the symbols immediately after the
238+
/// split become dimensions.
239+
void setVarSymbolSeperation(unsigned newSymbolCount);
240+
145241
/// Swaps the posA^th variable of kindA and posB^th variable of kindB.
146242
void swapVar(VarKind kindA, VarKind kindB, unsigned posA, unsigned posB);
147243

@@ -154,77 +250,29 @@ class PresburgerSpace {
154250
/// locals).
155251
bool isEqual(const PresburgerSpace &other) const;
156252

157-
/// Changes the partition between dimensions and symbols. Depending on the new
158-
/// symbol count, either a chunk of dimensional variables immediately before
159-
/// the split become symbols, or some of the symbols immediately after the
160-
/// split become dimensions.
161-
void setVarSymbolSeperation(unsigned newSymbolCount);
162-
163-
void print(llvm::raw_ostream &os) const;
164-
void dump() const;
165-
166-
//===--------------------------------------------------------------------===//
167-
// Identifier Interactions
168-
//===--------------------------------------------------------------------===//
169-
170-
/// Set the identifier for `i^th` variable to `id`. `T` here should match the
171-
/// type used to enable identifiers.
172-
template <typename T>
173-
void setId(VarKind kind, unsigned i, T id) {
174-
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
175-
assert(TypeID::get<T>() == idType && "Type mismatch");
176-
#endif
177-
atId(kind, i) = llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(id);
178-
}
179-
180-
/// Get the identifier for `i^th` variable casted to type `T`. `T` here
181-
/// should match the type used to enable identifiers.
182-
template <typename T>
183-
T getId(VarKind kind, unsigned i) const {
184-
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
185-
assert(TypeID::get<T>() == idType && "Type mismatch");
186-
#endif
187-
return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(atId(kind, i));
253+
/// Get the identifier of the specified variable.
254+
Identifier &getId(VarKind kind, unsigned pos) {
255+
assert(kind != VarKind::Local && "Local variables have no identifiers");
256+
return identifiers[getVarKindOffset(kind) + pos];
188257
}
189-
190-
/// Check if the i^th variable of the specified kind has a non-null
191-
/// identifier.
192-
bool hasId(VarKind kind, unsigned i) const {
193-
return atId(kind, i) != nullptr;
258+
Identifier getId(VarKind kind, unsigned pos) const {
259+
assert(kind != VarKind::Local && "Local variables have no identifiers");
260+
return identifiers[getVarKindOffset(kind) + pos];
194261
}
195262

196-
/// Check if the spaces are compatible, as well as have the same identifiers
197-
/// for each variable.
198-
bool isAligned(const PresburgerSpace &other) const;
199-
/// Check if the number of variables of the specified kind match, and have
200-
/// same identifiers with the other space.
201-
bool isAligned(const PresburgerSpace &other, VarKind kind) const;
202-
203-
/// Find the variable of the specified kind with identifier `id`.
204-
/// Returns PresburgerSpace::kIdNotFound if identifier is not found.
205-
template <typename T>
206-
unsigned findId(VarKind kind, T id) const {
207-
unsigned i = 0;
208-
for (unsigned e = getNumVarKind(kind); i < e; ++i)
209-
if (hasId(kind, i) && getId<T>(kind, i) == id)
210-
return i;
211-
return kIdNotFound;
263+
ArrayRef<Identifier> getIds(VarKind kind) const {
264+
assert(kind != VarKind::Local && "Local variables have no identifiers");
265+
return {identifiers.data() + getVarKindOffset(kind), getNumVarKind(kind)};
212266
}
213-
static const unsigned kIdNotFound = UINT_MAX;
214267

215268
/// Returns if identifiers are being used.
216269
bool isUsingIds() const { return usingIds; }
217270

218271
/// Reset the stored identifiers in the space. Enables `usingIds` if it was
219272
/// `false` before.
220-
template <typename T>
221273
void resetIds() {
222274
identifiers.clear();
223275
identifiers.resize(getNumDimAndSymbolVars());
224-
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
225-
idType = TypeID::get<T>();
226-
#endif
227-
228276
usingIds = true;
229277
}
230278

@@ -234,26 +282,23 @@ class PresburgerSpace {
234282
usingIds = false;
235283
}
236284

285+
/// Check if the spaces are compatible, and the non-local variables having
286+
/// same identifiers are in the same positions. If the space is not using
287+
/// Identifiers, this check is same as isCompatible.
288+
bool isAligned(const PresburgerSpace &other) const;
289+
/// Same as above but only check the specified VarKind. Useful to check if
290+
/// the symbols in two spaces are aligned.
291+
bool isAligned(const PresburgerSpace &other, VarKind kind) const;
292+
293+
void print(llvm::raw_ostream &os) const;
294+
void dump() const;
295+
237296
protected:
238-
PresburgerSpace(unsigned numDomain = 0, unsigned numRange = 0,
239-
unsigned numSymbols = 0, unsigned numLocals = 0)
297+
PresburgerSpace(unsigned numDomain, unsigned numRange, unsigned numSymbols,
298+
unsigned numLocals)
240299
: numDomain(numDomain), numRange(numRange), numSymbols(numSymbols),
241300
numLocals(numLocals) {}
242301

243-
void *&atId(VarKind kind, unsigned i) {
244-
assert(usingIds && "Cannot access identifiers when `usingIds` is false.");
245-
assert(kind != VarKind::Local &&
246-
"Local variables cannot have identifiers.");
247-
return identifiers[getVarKindOffset(kind) + i];
248-
}
249-
250-
void *atId(VarKind kind, unsigned i) const {
251-
assert(usingIds && "Cannot access identifiers when `usingIds` is false.");
252-
assert(kind != VarKind::Local &&
253-
"Local variables cannot have identifiers.");
254-
return identifiers[getVarKindOffset(kind) + i];
255-
}
256-
257302
private:
258303
// Number of variables corresponding to domain variables.
259304
unsigned numDomain;
@@ -272,13 +317,8 @@ class PresburgerSpace {
272317
/// Stores whether or not identifiers are being used in this space.
273318
bool usingIds = false;
274319

275-
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
276-
/// TypeID of the identifiers in space. This should be used in asserts only.
277-
TypeID idType;
278-
#endif
279-
280320
/// Stores an identifier for each non-local variable as a `void` pointer.
281-
SmallVector<void *, 0> identifiers;
321+
SmallVector<Identifier, 0> identifiers;
282322
};
283323

284324
} // namespace presburger

0 commit comments

Comments
 (0)