MLIR 22.0.0git
TypeDetail.h
Go to the documentation of this file.
1//===- TypeDetail.h - Details of MLIR LLVM dialect types --------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains implementation details, such as storage structures, of
10// MLIR LLVM dialect types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef DIALECT_LLVMIR_IR_TYPEDETAIL_H
15#define DIALECT_LLVMIR_IR_TYPEDETAIL_H
16
18#include "mlir/IR/TypeSupport.h"
19#include "mlir/IR/Types.h"
20
21#include "llvm/ADT/Bitfields.h"
22#include "llvm/ADT/PointerIntPair.h"
23
24namespace mlir {
25namespace LLVM {
26namespace detail {
27
28//===----------------------------------------------------------------------===//
29// LLVMStructTypeStorage.
30//===----------------------------------------------------------------------===//
31
32/// Type storage for LLVM structure types.
33///
34/// Structures are uniqued using:
35/// - a bit indicating whether a struct is literal or identified;
36/// - for identified structs, in addition to the bit:
37/// - a string identifier;
38/// - for literal structs, in addition to the bit:
39/// - a list of contained types;
40/// - a bit indicating whether the literal struct is packed.
41///
42/// Identified structures only have a mutable component consisting of:
43/// - a list of contained types;
44/// - a bit indicating whether the identified struct is packed;
45/// - a bit indicating whether the identified struct is intentionally opaque;
46/// - a bit indicating whether the identified struct has been initialized.
47/// Uninitialized structs are considered opaque by the user, and can be mutated.
48/// Initialized and still opaque structs cannot be mutated.
49///
50/// The struct storage consists of:
51/// - immutable part:
52/// - a pointer to the first element of the key (character for identified
53/// structs, type for literal structs);
54/// - the number of elements in the key packed together with bits indicating
55/// whether a type is literal or identified, and the packedness bit for
56/// literal structs only;
57/// - mutable part:
58/// - a pointer to the first contained type for identified structs only;
59/// - the number of contained types packed together with bits of the mutable
60/// component, for identified structs only.
62public:
63 /// Construction/uniquing key class for LLVM dialect structure storage. Note
64 /// that this is a transient helper data structure that is NOT stored.
65 /// Therefore, it intentionally avoids bit manipulation and type erasure in
66 /// pointers to make manipulation more straightforward. Not all elements of
67 /// the key participate in uniquing, but all elements participate in
68 /// construction.
69 class Key {
70 public:
71 /// Constructs a key for an identified struct.
72 Key(StringRef name, bool opaque, ArrayRef<Type> types = {})
73 : types(types), name(name), identified(true), packed(false),
74 opaque(opaque) {}
75 /// Constructs a key for a literal struct.
76 Key(ArrayRef<Type> types, bool packed)
77 : types(types), identified(false), packed(packed), opaque(false) {}
78
79 /// Checks a specific property of the struct.
80 bool isIdentified() const { return identified; }
81 bool isPacked() const {
82 assert(!isIdentified() &&
83 "'packed' bit is not part of the key for identified structs");
84 return packed;
85 }
86 bool isOpaque() const {
87 assert(isIdentified() &&
88 "'opaque' bit is meaningless on literal structs");
89 return opaque;
90 }
91
92 /// Returns the identifier of a key for identified structs.
93 StringRef getIdentifier() const {
94 assert(isIdentified() &&
95 "non-identified struct key cannot have an identifier");
96 return name;
97 }
98
99 /// Returns the list of type contained in the key of a literal struct.
101 assert(!isIdentified() &&
102 "identified struct key cannot have a type list");
103 return types;
104 }
105
106 /// Returns the list of type contained in an identified struct.
108 assert(isIdentified() &&
109 "requested struct body on a non-identified struct");
110 return types;
111 }
112
113 /// Returns the hash value of the key. This combines various flags into a
114 /// single value: the identified flag sets the first bit, and the packedness
115 /// flag sets the second bit. Opacity bit is only used for construction and
116 /// does not participate in uniquing.
117 llvm::hash_code hashValue() const {
118 constexpr static unsigned kIdentifiedHashFlag = 1;
119 constexpr static unsigned kPackedHashFlag = 2;
120
121 unsigned flags = 0;
122 if (isIdentified()) {
123 flags |= kIdentifiedHashFlag;
124 return llvm::hash_combine(flags, getIdentifier());
125 }
126 if (isPacked())
127 flags |= kPackedHashFlag;
128 return llvm::hash_combine(flags, getTypeList());
129 }
130
131 /// Compares two keys.
132 bool operator==(const Key &other) const {
133 if (isIdentified())
134 return other.isIdentified() && other.getIdentifier() == getIdentifier();
135
136 return !other.isIdentified() && other.isPacked() == isPacked() &&
137 other.getTypeList() == getTypeList();
138 }
139
140 /// Copies dynamically-sized components of the key into the given allocator.
142 if (isIdentified())
143 return Key(allocator.copyInto(name), opaque);
144 return Key(allocator.copyInto(types), packed);
145 }
146
147 private:
148 ArrayRef<Type> types;
149 StringRef name;
150 bool identified;
151 bool packed;
152 bool opaque;
153 };
154 using KeyTy = Key;
155
156 /// Returns the string identifier of an identified struct.
157 StringRef getIdentifier() const {
158 assert(isIdentified() && "requested identifier on a non-identified struct");
159 return StringRef(static_cast<const char *>(keyPtr), keySize());
160 }
161
162 /// Returns the list of types (partially) identifying a literal struct.
164 // If this triggers, use getIdentifiedStructBody() instead.
165 assert(!isIdentified() && "requested typelist on an identified struct");
166 return ArrayRef<Type>(static_cast<const Type *>(keyPtr), keySize());
167 }
168
169 /// Returns the list of types contained in an identified struct.
171 // If this triggers, use getTypeList() instead.
172 assert(isIdentified() &&
173 "requested struct body on a non-identified struct");
174 return ArrayRef<Type>(identifiedBodyArray, identifiedBodySize());
175 }
176
177 /// Checks whether the struct is identified.
178 bool isIdentified() const {
179 return llvm::Bitfield::get<KeyFlagIdentified>(keySizeAndFlags);
180 }
181
182 /// Checks whether the struct is packed (both literal and identified structs).
183 bool isPacked() const {
184 return isIdentified() ? llvm::Bitfield::get<MutableFlagPacked>(
185 identifiedBodySizeAndFlags)
186 : llvm::Bitfield::get<KeyFlagPacked>(keySizeAndFlags);
187 }
188
189 /// Checks whether a struct is marked as intentionally opaque (an
190 /// uninitialized struct is also considered opaque by the user, call
191 /// isInitialized to check that).
192 bool isOpaque() const {
193 return llvm::Bitfield::get<MutableFlagOpaque>(identifiedBodySizeAndFlags);
194 }
195
196 /// Checks whether an identified struct has been explicitly initialized either
197 /// by setting its body or by marking it as intentionally opaque.
198 bool isInitialized() const {
199 return llvm::Bitfield::get<MutableFlagInitialized>(
200 identifiedBodySizeAndFlags);
201 }
202
203 /// Constructs the storage from the given key. This sets up the uniquing key
204 /// components and optionally the mutable component if they construction key
205 /// has the relevant information. In the latter case, the struct is considered
206 /// as initialized and can no longer be mutated.
208 if (!key.isIdentified()) {
209 ArrayRef<Type> types = key.getTypeList();
210 keyPtr = static_cast<const void *>(types.data());
211 setKeySize(types.size());
212 llvm::Bitfield::set<KeyFlagPacked>(keySizeAndFlags, key.isPacked());
213 return;
214 }
215
216 StringRef name = key.getIdentifier();
217 keyPtr = static_cast<const void *>(name.data());
218 setKeySize(name.size());
219 llvm::Bitfield::set<KeyFlagIdentified>(keySizeAndFlags, true);
220
221 // If the struct is being constructed directly as opaque, mark it as
222 // initialized.
223 llvm::Bitfield::set<MutableFlagInitialized>(identifiedBodySizeAndFlags,
224 key.isOpaque());
225 llvm::Bitfield::set<MutableFlagOpaque>(identifiedBodySizeAndFlags,
226 key.isOpaque());
227 }
228
229 /// Hook into the type uniquing infrastructure.
230 bool operator==(const KeyTy &other) const { return getAsKey() == other; };
231 static llvm::hash_code hashKey(const KeyTy &key) { return key.hashValue(); }
233 const KeyTy &key) {
234 return new (allocator.allocate<LLVMStructTypeStorage>())
236 }
237
238 /// Sets the body of an identified struct. If the struct is already
239 /// initialized, succeeds only if the body is equal to the current body. Fails
240 /// if the struct is marked as intentionally opaque. The struct will be marked
241 /// as initialized as a result of this operation and can no longer be changed.
242 LogicalResult mutate(TypeStorageAllocator &allocator, ArrayRef<Type> body,
243 bool packed) {
244 if (!isIdentified())
245 return failure();
246 if (isInitialized())
247 return success(!isOpaque() && body == getIdentifiedStructBody() &&
248 packed == isPacked());
249
250 llvm::Bitfield::set<MutableFlagInitialized>(identifiedBodySizeAndFlags,
251 true);
252 llvm::Bitfield::set<MutableFlagPacked>(identifiedBodySizeAndFlags, packed);
253
254 ArrayRef<Type> typesInAllocator = allocator.copyInto(body);
255 identifiedBodyArray = typesInAllocator.data();
256 setIdentifiedBodySize(typesInAllocator.size());
257
258 return success();
259 }
260
261 /// Returns the key for the current storage.
262 Key getAsKey() const {
263 if (isIdentified())
265 return Key(getTypeList(), isPacked());
266 }
267
268private:
269 /// Returns the number of elements in the key.
270 unsigned keySize() const {
271 return llvm::Bitfield::get<KeySize>(keySizeAndFlags);
272 }
273
274 /// Sets the number of elements in the key.
275 void setKeySize(unsigned value) {
276 llvm::Bitfield::set<KeySize>(keySizeAndFlags, value);
277 }
278
279 /// Returns the number of types contained in an identified struct.
280 unsigned identifiedBodySize() const {
281 return llvm::Bitfield::get<MutableSize>(identifiedBodySizeAndFlags);
282 }
283 /// Sets the number of types contained in an identified struct.
284 void setIdentifiedBodySize(unsigned value) {
285 llvm::Bitfield::set<MutableSize>(identifiedBodySizeAndFlags, value);
286 }
287
288 /// Bitfield elements for `keyAndSizeFlags`:
289 /// - bit 0: identified key flag;
290 /// - bit 1: packed key flag;
291 /// - bits 2..bitwidth(unsigned): size of the key.
292 using KeyFlagIdentified =
293 llvm::Bitfield::Element<bool, /*Offset=*/0, /*Size=*/1>;
294 using KeyFlagPacked = llvm::Bitfield::Element<bool, /*Offset=*/1, /*Size=*/1>;
295 using KeySize =
296 llvm::Bitfield::Element<unsigned, /*Offset=*/2,
297 std::numeric_limits<unsigned>::digits - 2>;
298
299 /// Bitfield elements for `identifiedBodySizeAndFlags`:
300 /// - bit 0: opaque flag;
301 /// - bit 1: packed mutable flag;
302 /// - bit 2: initialized flag;
303 /// - bits 3..bitwidth(unsigned): size of the identified body.
304 using MutableFlagOpaque =
305 llvm::Bitfield::Element<bool, /*Offset=*/0, /*Size=*/1>;
306 using MutableFlagPacked =
307 llvm::Bitfield::Element<bool, /*Offset=*/1, /*Size=*/1>;
308 using MutableFlagInitialized =
309 llvm::Bitfield::Element<bool, /*Offset=*/2, /*Size=*/1>;
310 using MutableSize =
311 llvm::Bitfield::Element<unsigned, /*Offset=*/3,
312 std::numeric_limits<unsigned>::digits - 3>;
313
314 /// Pointer to the first element of the uniquing key.
315 // Note: cannot use PointerUnion because bump-ptr allocator does not guarantee
316 // address alignment.
317 const void *keyPtr = nullptr;
318
319 /// Pointer to the first type contained in an identified struct.
320 const Type *identifiedBodyArray = nullptr;
321
322 /// Size of the uniquing key combined with identified/literal and
323 /// packedness bits. Must only be used through the Key* bitfields.
324 unsigned keySizeAndFlags = 0;
325
326 /// Number of the types contained in an identified struct combined with
327 /// mutable flags. Must only be used through the Mutable* bitfields.
328 unsigned identifiedBodySizeAndFlags = 0;
329};
330} // end namespace detail
331} // end namespace LLVM
332
333/// Allow walking and replacing the subelements of a LLVMStructTypeStorage key.
334template <>
335struct AttrTypeSubElementHandler<LLVM::detail::LLVMStructTypeStorage::Key> {
338 if (param.isIdentified())
339 walker.walkRange(param.getIdentifiedStructBody());
340 else
341 walker.walkRange(param.getTypeList());
342 }
343 static FailureOr<LLVM::detail::LLVMStructTypeStorage::Key>
346 TypeSubElementReplacements &typeRepls) {
347 // TODO: It's not clear how we support replacing sub-elements of mutable
348 // types.
349 if (param.isIdentified())
350 return failure();
351
353 typeRepls.take_front(param.getTypeList().size()), param.isPacked());
354 }
355};
356
357namespace LLVM {
358namespace detail {
359//===----------------------------------------------------------------------===//
360// LLVMTypeAndSizeStorage.
361//===----------------------------------------------------------------------===//
362
363/// Common storage used for LLVM dialect types that need an element type and a
364/// number: arrays, fixed and scalable vectors. The actual semantics of the
365/// type is defined by its kind.
367 using KeyTy = std::tuple<Type, unsigned>;
368
370 : elementType(std::get<0>(key)), numElements(std::get<1>(key)) {}
371
373 const KeyTy &key) {
374 return new (allocator.allocate<LLVMTypeAndSizeStorage>())
376 }
377
378 bool operator==(const KeyTy &key) const {
379 return std::make_tuple(elementType, numElements) == key;
380 }
381
383 unsigned numElements;
384};
385
386} // namespace detail
387} // namespace LLVM
388} // namespace mlir
389
390#endif // DIALECT_LLVMIR_IR_TYPEDETAIL_H
return success()
true
Given two iterators into the same block, return "true" if a is before `b.
false
Parses a map_entries map type from a string format back into its numeric value.
void walkRange(RangeT &&elements)
Walk a range of attributes or types.
ArrayRef< T > take_front(unsigned n)
Take the first N replacements as an ArrayRef, dropping them from this replacement list.
Construction/uniquing key class for LLVM dialect structure storage.
Definition TypeDetail.h:69
Key(StringRef name, bool opaque, ArrayRef< Type > types={})
Constructs a key for an identified struct.
Definition TypeDetail.h:72
ArrayRef< Type > getTypeList() const
Returns the list of type contained in the key of a literal struct.
Definition TypeDetail.h:100
bool isIdentified() const
Checks a specific property of the struct.
Definition TypeDetail.h:80
llvm::hash_code hashValue() const
Returns the hash value of the key.
Definition TypeDetail.h:117
StringRef getIdentifier() const
Returns the identifier of a key for identified structs.
Definition TypeDetail.h:93
bool operator==(const Key &other) const
Compares two keys.
Definition TypeDetail.h:132
Key copyIntoAllocator(TypeStorageAllocator &allocator) const
Copies dynamically-sized components of the key into the given allocator.
Definition TypeDetail.h:141
Key(ArrayRef< Type > types, bool packed)
Constructs a key for a literal struct.
Definition TypeDetail.h:76
ArrayRef< Type > getIdentifiedStructBody() const
Returns the list of type contained in an identified struct.
Definition TypeDetail.h:107
ArrayRef< T > copyInto(ArrayRef< T > elements)
Copy the specified array of elements into memory managed by our bump pointer allocator.
T * allocate()
Allocate an instance of the provided type.
TypeStorage()
This constructor is used by derived classes as part of the TypeUniquer.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
Include the generated interface declarations.
StorageUniquer::StorageAllocator TypeStorageAllocator
This is a utility allocator used to allocate memory for instances of derived Types.
AttrTypeSubElementReplacements< Attribute > AttrSubElementReplacements
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
AttrTypeSubElementReplacements< Type > TypeSubElementReplacements
static void walk(const LLVM::detail::LLVMStructTypeStorage::Key &param, AttrTypeImmediateSubElementWalker &walker)
Definition TypeDetail.h:336
static FailureOr< LLVM::detail::LLVMStructTypeStorage::Key > replace(const LLVM::detail::LLVMStructTypeStorage::Key &param, AttrSubElementReplacements &attrRepls, TypeSubElementReplacements &typeRepls)
Definition TypeDetail.h:344
This class provides support for interacting with the SubElementInterfaces for different types of para...
StringRef getIdentifier() const
Returns the string identifier of an identified struct.
Definition TypeDetail.h:157
LogicalResult mutate(TypeStorageAllocator &allocator, ArrayRef< Type > body, bool packed)
Sets the body of an identified struct.
Definition TypeDetail.h:242
static LLVMStructTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition TypeDetail.h:232
static llvm::hash_code hashKey(const KeyTy &key)
Definition TypeDetail.h:231
Key getAsKey() const
Returns the key for the current storage.
Definition TypeDetail.h:262
bool operator==(const KeyTy &other) const
Hook into the type uniquing infrastructure.
Definition TypeDetail.h:230
LLVMStructTypeStorage(const KeyTy &key)
Constructs the storage from the given key.
Definition TypeDetail.h:207
bool isIdentified() const
Checks whether the struct is identified.
Definition TypeDetail.h:178
ArrayRef< Type > getTypeList() const
Returns the list of types (partially) identifying a literal struct.
Definition TypeDetail.h:163
ArrayRef< Type > getIdentifiedStructBody() const
Returns the list of types contained in an identified struct.
Definition TypeDetail.h:170
bool isInitialized() const
Checks whether an identified struct has been explicitly initialized either by setting its body or by ...
Definition TypeDetail.h:198
bool isOpaque() const
Checks whether a struct is marked as intentionally opaque (an uninitialized struct is also considered...
Definition TypeDetail.h:192
bool isPacked() const
Checks whether the struct is packed (both literal and identified structs).
Definition TypeDetail.h:183
std::tuple< Type, unsigned > KeyTy
Definition TypeDetail.h:367
bool operator==(const KeyTy &key) const
Definition TypeDetail.h:378
static LLVMTypeAndSizeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition TypeDetail.h:372