MLIR  17.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 
24 namespace mlir {
25 namespace LLVM {
26 namespace 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.
62 public:
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)
73  : name(name), identified(true), packed(false), opaque(opaque) {}
74  /// Constructs a key for a literal struct.
75  Key(ArrayRef<Type> types, bool packed)
76  : types(types), identified(false), packed(packed), opaque(false) {}
77 
78  /// Checks a specific property of the struct.
79  bool isIdentified() const { return identified; }
80  bool isPacked() const {
81  assert(!isIdentified() &&
82  "'packed' bit is not part of the key for identified structs");
83  return packed;
84  }
85  bool isOpaque() const {
86  assert(isIdentified() &&
87  "'opaque' bit is meaningless on literal structs");
88  return opaque;
89  }
90 
91  /// Returns the identifier of a key for identified structs.
92  StringRef getIdentifier() const {
93  assert(isIdentified() &&
94  "non-identified struct key cannot have an identifier");
95  return name;
96  }
97 
98  /// Returns the list of type contained in the key of a literal struct.
100  assert(!isIdentified() &&
101  "identified struct key cannot have a type list");
102  return types;
103  }
104 
105  /// Returns the hash value of the key. This combines various flags into a
106  /// single value: the identified flag sets the first bit, and the packedness
107  /// flag sets the second bit. Opacity bit is only used for construction and
108  /// does not participate in uniquing.
109  llvm::hash_code hashValue() const {
110  constexpr static unsigned kIdentifiedHashFlag = 1;
111  constexpr static unsigned kPackedHashFlag = 2;
112 
113  unsigned flags = 0;
114  if (isIdentified()) {
115  flags |= kIdentifiedHashFlag;
116  return llvm::hash_combine(flags, getIdentifier());
117  }
118  if (isPacked())
119  flags |= kPackedHashFlag;
120  return llvm::hash_combine(flags, getTypeList());
121  }
122 
123  /// Compares two keys.
124  bool operator==(const Key &other) const {
125  if (isIdentified())
126  return other.isIdentified() &&
127  other.getIdentifier().equals(getIdentifier());
128 
129  return !other.isIdentified() && other.isPacked() == isPacked() &&
130  other.getTypeList() == getTypeList();
131  }
132 
133  /// Copies dynamically-sized components of the key into the given allocator.
135  if (isIdentified())
136  return Key(allocator.copyInto(name), opaque);
137  return Key(allocator.copyInto(types), packed);
138  }
139 
140  private:
141  ArrayRef<Type> types;
142  StringRef name;
143  bool identified;
144  bool packed;
145  bool opaque;
146  };
147  using KeyTy = Key;
148 
149  /// Returns the string identifier of an identified struct.
150  StringRef getIdentifier() const {
151  assert(isIdentified() && "requested identifier on a non-identified struct");
152  return StringRef(static_cast<const char *>(keyPtr), keySize());
153  }
154 
155  /// Returns the list of types (partially) identifying a literal struct.
157  // If this triggers, use getIdentifiedStructBody() instead.
158  assert(!isIdentified() && "requested typelist on an identified struct");
159  return ArrayRef<Type>(static_cast<const Type *>(keyPtr), keySize());
160  }
161 
162  /// Returns the list of types contained in an identified struct.
164  // If this triggers, use getTypeList() instead.
165  assert(isIdentified() &&
166  "requested struct body on a non-identified struct");
167  return ArrayRef<Type>(identifiedBodyArray, identifiedBodySize());
168  }
169 
170  /// Checks whether the struct is identified.
171  bool isIdentified() const {
172  return llvm::Bitfield::get<KeyFlagIdentified>(keySizeAndFlags);
173  }
174 
175  /// Checks whether the struct is packed (both literal and identified structs).
176  bool isPacked() const {
177  return isIdentified() ? llvm::Bitfield::get<MutableFlagPacked>(
178  identifiedBodySizeAndFlags)
179  : llvm::Bitfield::get<KeyFlagPacked>(keySizeAndFlags);
180  }
181 
182  /// Checks whether a struct is marked as intentionally opaque (an
183  /// uninitialized struct is also considered opaque by the user, call
184  /// isInitialized to check that).
185  bool isOpaque() const {
186  return llvm::Bitfield::get<MutableFlagOpaque>(identifiedBodySizeAndFlags);
187  }
188 
189  /// Checks whether an identified struct has been explicitly initialized either
190  /// by setting its body or by marking it as intentionally opaque.
191  bool isInitialized() const {
192  return llvm::Bitfield::get<MutableFlagInitialized>(
193  identifiedBodySizeAndFlags);
194  }
195 
196  /// Constructs the storage from the given key. This sets up the uniquing key
197  /// components and optionally the mutable component if they construction key
198  /// has the relevant information. In the latter case, the struct is considered
199  /// as initialized and can no longer be mutated.
201  if (!key.isIdentified()) {
202  ArrayRef<Type> types = key.getTypeList();
203  keyPtr = static_cast<const void *>(types.data());
204  setKeySize(types.size());
205  llvm::Bitfield::set<KeyFlagPacked>(keySizeAndFlags, key.isPacked());
206  return;
207  }
208 
209  StringRef name = key.getIdentifier();
210  keyPtr = static_cast<const void *>(name.data());
211  setKeySize(name.size());
212  llvm::Bitfield::set<KeyFlagIdentified>(keySizeAndFlags, true);
213 
214  // If the struct is being constructed directly as opaque, mark it as
215  // initialized.
216  llvm::Bitfield::set<MutableFlagInitialized>(identifiedBodySizeAndFlags,
217  key.isOpaque());
218  llvm::Bitfield::set<MutableFlagOpaque>(identifiedBodySizeAndFlags,
219  key.isOpaque());
220  }
221 
222  /// Hook into the type uniquing infrastructure.
223  bool operator==(const KeyTy &other) const { return getKey() == other; };
224  static llvm::hash_code hashKey(const KeyTy &key) { return key.hashValue(); }
226  const KeyTy &key) {
227  return new (allocator.allocate<LLVMStructTypeStorage>())
229  }
230 
231  /// Sets the body of an identified struct. If the struct is already
232  /// initialized, succeeds only if the body is equal to the current body. Fails
233  /// if the struct is marked as intentionally opaque. The struct will be marked
234  /// as initialized as a result of this operation and can no longer be changed.
236  bool packed) {
237  if (!isIdentified())
238  return failure();
239  if (isInitialized())
240  return success(!isOpaque() && body == getIdentifiedStructBody() &&
241  packed == isPacked());
242 
243  llvm::Bitfield::set<MutableFlagInitialized>(identifiedBodySizeAndFlags,
244  true);
245  llvm::Bitfield::set<MutableFlagPacked>(identifiedBodySizeAndFlags, packed);
246 
247  ArrayRef<Type> typesInAllocator = allocator.copyInto(body);
248  identifiedBodyArray = typesInAllocator.data();
249  setIdentifiedBodySize(typesInAllocator.size());
250 
251  return success();
252  }
253 
254 private:
255  /// Returns the number of elements in the key.
256  unsigned keySize() const {
257  return llvm::Bitfield::get<KeySize>(keySizeAndFlags);
258  }
259 
260  /// Sets the number of elements in the key.
261  void setKeySize(unsigned value) {
262  llvm::Bitfield::set<KeySize>(keySizeAndFlags, value);
263  }
264 
265  /// Returns the number of types contained in an identified struct.
266  unsigned identifiedBodySize() const {
267  return llvm::Bitfield::get<MutableSize>(identifiedBodySizeAndFlags);
268  }
269  /// Sets the number of types contained in an identified struct.
270  void setIdentifiedBodySize(unsigned value) {
271  llvm::Bitfield::set<MutableSize>(identifiedBodySizeAndFlags, value);
272  }
273 
274  /// Returns the key for the current storage.
275  Key getKey() const {
276  if (isIdentified())
277  return Key(getIdentifier(), isOpaque());
278  return Key(getTypeList(), isPacked());
279  }
280 
281  /// Bitfield elements for `keyAndSizeFlags`:
282  /// - bit 0: identified key flag;
283  /// - bit 1: packed key flag;
284  /// - bits 2..bitwidth(unsigned): size of the key.
285  using KeyFlagIdentified =
286  llvm::Bitfield::Element<bool, /*Offset=*/0, /*Size=*/1>;
287  using KeyFlagPacked = llvm::Bitfield::Element<bool, /*Offset=*/1, /*Size=*/1>;
288  using KeySize =
289  llvm::Bitfield::Element<unsigned, /*Offset=*/2,
290  std::numeric_limits<unsigned>::digits - 2>;
291 
292  /// Bitfield elements for `identifiedBodySizeAndFlags`:
293  /// - bit 0: opaque flag;
294  /// - bit 1: packed mutable flag;
295  /// - bit 2: initialized flag;
296  /// - bits 3..bitwidth(unsigned): size of the identified body.
297  using MutableFlagOpaque =
298  llvm::Bitfield::Element<bool, /*Offset=*/0, /*Size=*/1>;
299  using MutableFlagPacked =
300  llvm::Bitfield::Element<bool, /*Offset=*/1, /*Size=*/1>;
301  using MutableFlagInitialized =
302  llvm::Bitfield::Element<bool, /*Offset=*/2, /*Size=*/1>;
303  using MutableSize =
304  llvm::Bitfield::Element<unsigned, /*Offset=*/3,
305  std::numeric_limits<unsigned>::digits - 3>;
306 
307  /// Pointer to the first element of the uniquing key.
308  // Note: cannot use PointerUnion because bump-ptr allocator does not guarantee
309  // address alignment.
310  const void *keyPtr = nullptr;
311 
312  /// Pointer to the first type contained in an identified struct.
313  const Type *identifiedBodyArray = nullptr;
314 
315  /// Size of the uniquing key combined with identified/literal and
316  /// packedness bits. Must only be used through the Key* bitfields.
317  unsigned keySizeAndFlags = 0;
318 
319  /// Number of the types contained in an identified struct combined with
320  /// mutable flags. Must only be used through the Mutable* bitfields.
321  unsigned identifiedBodySizeAndFlags = 0;
322 };
323 
324 //===----------------------------------------------------------------------===//
325 // LLVMTypeAndSizeStorage.
326 //===----------------------------------------------------------------------===//
327 
328 /// Common storage used for LLVM dialect types that need an element type and a
329 /// number: arrays, fixed and scalable vectors. The actual semantics of the
330 /// type is defined by its kind.
332  using KeyTy = std::tuple<Type, unsigned>;
333 
335  : elementType(std::get<0>(key)), numElements(std::get<1>(key)) {}
336 
338  const KeyTy &key) {
339  return new (allocator.allocate<LLVMTypeAndSizeStorage>())
341  }
342 
343  bool operator==(const KeyTy &key) const {
344  return std::make_tuple(elementType, numElements) == key;
345  }
346 
348  unsigned numElements;
349 };
350 
351 } // namespace detail
352 } // namespace LLVM
353 } // namespace mlir
354 
355 #endif // DIALECT_LLVMIR_IR_TYPEDETAIL_H
Construction/uniquing key class for LLVM dialect structure storage.
Definition: TypeDetail.h:69
bool isIdentified() const
Checks a specific property of the struct.
Definition: TypeDetail.h:79
llvm::hash_code hashValue() const
Returns the hash value of the key.
Definition: TypeDetail.h:109
StringRef getIdentifier() const
Returns the identifier of a key for identified structs.
Definition: TypeDetail.h:92
bool operator==(const Key &other) const
Compares two keys.
Definition: TypeDetail.h:124
Key copyIntoAllocator(TypeStorageAllocator &allocator) const
Copies dynamically-sized components of the key into the given allocator.
Definition: TypeDetail.h:134
Key(StringRef name, bool opaque)
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:99
Key(ArrayRef< Type > types, bool packed)
Constructs a key for a literal struct.
Definition: TypeDetail.h:75
This is a utility allocator used to allocate memory for instances of derived types.
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.
Base storage class appearing in a Type.
Definition: TypeSupport.h:153
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
@ Type
An inlay hint that for a type annotation.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
Type storage for LLVM structure types.
Definition: TypeDetail.h:61
ArrayRef< Type > getTypeList() const
Returns the list of types (partially) identifying a literal struct.
Definition: TypeDetail.h:156
StringRef getIdentifier() const
Returns the string identifier of an identified struct.
Definition: TypeDetail.h:150
ArrayRef< Type > getIdentifiedStructBody() const
Returns the list of types contained in an identified struct.
Definition: TypeDetail.h:163
LogicalResult mutate(TypeStorageAllocator &allocator, ArrayRef< Type > body, bool packed)
Sets the body of an identified struct.
Definition: TypeDetail.h:235
static LLVMStructTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: TypeDetail.h:225
static llvm::hash_code hashKey(const KeyTy &key)
Definition: TypeDetail.h:224
bool operator==(const KeyTy &other) const
Hook into the type uniquing infrastructure.
Definition: TypeDetail.h:223
LLVMStructTypeStorage(const KeyTy &key)
Constructs the storage from the given key.
Definition: TypeDetail.h:200
bool isIdentified() const
Checks whether the struct is identified.
Definition: TypeDetail.h:171
bool isInitialized() const
Checks whether an identified struct has been explicitly initialized either by setting its body or by ...
Definition: TypeDetail.h:191
bool isOpaque() const
Checks whether a struct is marked as intentionally opaque (an uninitialized struct is also considered...
Definition: TypeDetail.h:185
bool isPacked() const
Checks whether the struct is packed (both literal and identified structs).
Definition: TypeDetail.h:176
Common storage used for LLVM dialect types that need an element type and a number: arrays,...
Definition: TypeDetail.h:331
std::tuple< Type, unsigned > KeyTy
Definition: TypeDetail.h:332
static LLVMTypeAndSizeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: TypeDetail.h:337
bool operator==(const KeyTy &key) const
Definition: TypeDetail.h:343
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26