MLIR  20.0.0git
Types.h
Go to the documentation of this file.
1 //===- Types.h - MLIR Type Classes ------------------------------*- 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 #ifndef MLIR_IR_TYPES_H
10 #define MLIR_IR_TYPES_H
11 
12 #include "mlir/IR/TypeSupport.h"
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/DenseMapInfo.h"
15 #include "llvm/Support/PointerLikeTypeTraits.h"
16 
17 namespace mlir {
18 class AsmState;
19 
20 /// Instances of the Type class are uniqued, have an immutable identifier and an
21 /// optional mutable component. They wrap a pointer to the storage object owned
22 /// by MLIRContext. Therefore, instances of Type are passed around by value.
23 ///
24 /// Some types are "primitives" meaning they do not have any parameters, for
25 /// example the Index type. Parametric types have additional information that
26 /// differentiates the types of the same class, for example the Integer type has
27 /// bitwidth, making i8 and i16 belong to the same kind by be different
28 /// instances of the IntegerType. Type parameters are part of the unique
29 /// immutable key. The mutable component of the type can be modified after the
30 /// type is created, but cannot affect the identity of the type.
31 ///
32 /// Types are constructed and uniqued via the 'detail::TypeUniquer' class.
33 ///
34 /// Derived type classes are expected to implement several required
35 /// implementation hooks:
36 /// * Optional:
37 /// - static LogicalResult verifyInvariants(
38 /// function_ref<InFlightDiagnostic()> emitError,
39 /// Args... args)
40 /// * This method is invoked when calling the 'TypeBase::get/getChecked'
41 /// methods to ensure that the arguments passed in are valid to construct
42 /// a type instance with.
43 /// * This method is expected to return failure if a type cannot be
44 /// constructed with 'args', success otherwise.
45 /// * 'args' must correspond with the arguments passed into the
46 /// 'TypeBase::get' call.
47 ///
48 ///
49 /// Type storage objects inherit from TypeStorage and contain the following:
50 /// - The dialect that defined the type.
51 /// - Any parameters of the type.
52 /// - An optional mutable component.
53 /// For non-parametric types, a convenience DefaultTypeStorage is provided.
54 /// Parametric storage types must derive TypeStorage and respect the following:
55 /// - Define a type alias, KeyTy, to a type that uniquely identifies the
56 /// instance of the type.
57 /// * The key type must be constructible from the values passed into the
58 /// detail::TypeUniquer::get call.
59 /// * If the KeyTy does not have an llvm::DenseMapInfo specialization, the
60 /// storage class must define a hashing method:
61 /// 'static unsigned hashKey(const KeyTy &)'
62 ///
63 /// - Provide a method, 'bool operator==(const KeyTy &) const', to
64 /// compare the storage instance against an instance of the key type.
65 ///
66 /// - Provide a static construction method:
67 /// 'DerivedStorage *construct(TypeStorageAllocator &, const KeyTy &key)'
68 /// that builds a unique instance of the derived storage. The arguments to
69 /// this function are an allocator to store any uniqued data within the
70 /// context and the key type for this storage.
71 ///
72 /// - If they have a mutable component, this component must not be a part of
73 /// the key.
74 class Type {
75 public:
76  /// Utility class for implementing types.
77  template <typename ConcreteType, typename BaseType, typename StorageType,
78  template <typename T> class... Traits>
79  using TypeBase = detail::StorageUserBase<ConcreteType, BaseType, StorageType,
80  detail::TypeUniquer, Traits...>;
81 
83 
85 
86  constexpr Type() = default;
87  /* implicit */ Type(const ImplType *impl)
88  : impl(const_cast<ImplType *>(impl)) {}
89 
90  Type(const Type &other) = default;
91  Type &operator=(const Type &other) = default;
92 
93  bool operator==(Type other) const { return impl == other.impl; }
94  bool operator!=(Type other) const { return !(*this == other); }
95  explicit operator bool() const { return impl; }
96 
97  bool operator!() const { return impl == nullptr; }
98 
99  template <typename... Tys>
100  [[deprecated("Use mlir::isa<U>() instead")]]
101  bool isa() const;
102  template <typename... Tys>
103  [[deprecated("Use mlir::isa_and_nonnull<U>() instead")]]
104  bool isa_and_nonnull() const;
105  template <typename U>
106  [[deprecated("Use mlir::dyn_cast<U>() instead")]]
107  U dyn_cast() const;
108  template <typename U>
109  [[deprecated("Use mlir::dyn_cast_or_null<U>() instead")]]
110  U dyn_cast_or_null() const;
111  template <typename U>
112  [[deprecated("Use mlir::cast<U>() instead")]]
113  U cast() const;
114 
115  /// Return a unique identifier for the concrete type. This is used to support
116  /// dynamic type casting.
117  TypeID getTypeID() { return impl->getAbstractType().getTypeID(); }
118 
119  /// Return the MLIRContext in which this type was uniqued.
120  MLIRContext *getContext() const;
121 
122  /// Get the dialect this type is registered to.
123  Dialect &getDialect() const { return impl->getAbstractType().getDialect(); }
124 
125  // Convenience predicates. This is only for floating point types,
126  // derived types should use isa/dyn_cast.
127  bool isIndex() const;
128  bool isFloat4E2M1FN() const;
129  bool isFloat6E2M3FN() const;
130  bool isFloat6E3M2FN() const;
131  bool isFloat8E5M2() const;
132  bool isFloat8E4M3() const;
133  bool isFloat8E4M3FN() const;
134  bool isFloat8E5M2FNUZ() const;
135  bool isFloat8E4M3FNUZ() const;
136  bool isFloat8E4M3B11FNUZ() const;
137  bool isFloat8E3M4() const;
138  bool isFloat8E8M0FNU() const;
139  bool isBF16() const;
140  bool isF16() const;
141  bool isTF32() const;
142  bool isF32() const;
143  bool isF64() const;
144  bool isF80() const;
145  bool isF128() const;
146 
147  /// Return true if this is an integer type (with the specified width).
148  bool isInteger() const;
149  bool isInteger(unsigned width) const;
150  /// Return true if this is a signless integer type (with the specified width).
151  bool isSignlessInteger() const;
152  bool isSignlessInteger(unsigned width) const;
153  /// Return true if this is a signed integer type (with the specified width).
154  bool isSignedInteger() const;
155  bool isSignedInteger(unsigned width) const;
156  /// Return true if this is an unsigned integer type (with the specified
157  /// width).
158  bool isUnsignedInteger() const;
159  bool isUnsignedInteger(unsigned width) const;
160 
161  /// Return the bit width of an integer or a float type, assert failure on
162  /// other types.
163  unsigned getIntOrFloatBitWidth() const;
164 
165  /// Return true if this is a signless integer or index type.
166  bool isSignlessIntOrIndex() const;
167  /// Return true if this is a signless integer, index, or float type.
168  bool isSignlessIntOrIndexOrFloat() const;
169  /// Return true of this is a signless integer or a float type.
170  bool isSignlessIntOrFloat() const;
171 
172  /// Return true if this is an integer (of any signedness) or an index type.
173  bool isIntOrIndex() const;
174  /// Return true if this is an integer (of any signedness) or a float type.
175  bool isIntOrFloat() const;
176  /// Return true if this is an integer (of any signedness), index, or float
177  /// type.
178  bool isIntOrIndexOrFloat() const;
179 
180  /// Print the current type.
181  void print(raw_ostream &os) const;
182  void print(raw_ostream &os, AsmState &state) const;
183  void dump() const;
184 
185  friend ::llvm::hash_code hash_value(Type arg);
186 
187  /// Methods for supporting PointerLikeTypeTraits.
188  const void *getAsOpaquePointer() const {
189  return static_cast<const void *>(impl);
190  }
191  static Type getFromOpaquePointer(const void *pointer) {
192  return Type(reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
193  }
194 
195  /// Returns true if `InterfaceT` has been promised by the dialect or
196  /// implemented.
197  template <typename InterfaceT>
200  getDialect(), getTypeID(), InterfaceT::getInterfaceID()) ||
201  mlir::isa<InterfaceT>(*this);
202  }
203 
204  /// Returns true if the type was registered with a particular trait.
205  template <template <typename T> class Trait>
206  bool hasTrait() {
207  return getAbstractType().hasTrait<Trait>();
208  }
209 
210  /// Return the abstract type descriptor for this type.
211  const AbstractTy &getAbstractType() const { return impl->getAbstractType(); }
212 
213  /// Return the Type implementation.
214  ImplType *getImpl() const { return impl; }
215 
216  /// Walk all of the immediately nested sub-attributes and sub-types. This
217  /// method does not recurse into sub elements.
219  function_ref<void(Type)> walkTypesFn) const {
220  getAbstractType().walkImmediateSubElements(*this, walkAttrsFn, walkTypesFn);
221  }
222 
223  /// Replace the immediately nested sub-attributes and sub-types with those
224  /// provided. The order of the provided elements is derived from the order of
225  /// the elements returned by the callbacks of `walkImmediateSubElements`. The
226  /// element at index 0 would replace the very first attribute given by
227  /// `walkImmediateSubElements`. On success, the new instance with the values
228  /// replaced is returned. If replacement fails, nullptr is returned.
230  ArrayRef<Type> replTypes) const {
231  return getAbstractType().replaceImmediateSubElements(*this, replAttrs,
232  replTypes);
233  }
234 
235  /// Walk this type and all attibutes/types nested within using the
236  /// provided walk functions. See `AttrTypeWalker` for information on the
237  /// supported walk function types.
238  template <WalkOrder Order = WalkOrder::PostOrder, typename... WalkFns>
239  auto walk(WalkFns &&...walkFns) {
240  AttrTypeWalker walker;
241  (walker.addWalk(std::forward<WalkFns>(walkFns)), ...);
242  return walker.walk<Order>(*this);
243  }
244 
245  /// Recursively replace all of the nested sub-attributes and sub-types using
246  /// the provided map functions. Returns nullptr in the case of failure. See
247  /// `AttrTypeReplacer` for information on the support replacement function
248  /// types.
249  template <typename... ReplacementFns>
250  auto replace(ReplacementFns &&...replacementFns) {
251  AttrTypeReplacer replacer;
252  (replacer.addReplacement(std::forward<ReplacementFns>(replacementFns)),
253  ...);
254  return replacer.replace(*this);
255  }
256 
257 protected:
258  ImplType *impl{nullptr};
259 };
260 
261 inline raw_ostream &operator<<(raw_ostream &os, Type type) {
262  type.print(os);
263  return os;
264 }
265 
266 //===----------------------------------------------------------------------===//
267 // TypeTraitBase
268 //===----------------------------------------------------------------------===//
269 
270 namespace TypeTrait {
271 /// This class represents the base of a type trait.
272 template <typename ConcreteType, template <typename> class TraitType>
274 } // namespace TypeTrait
275 
276 //===----------------------------------------------------------------------===//
277 // TypeInterface
278 //===----------------------------------------------------------------------===//
279 
280 /// This class represents the base of a type interface. See the definition of
281 /// `detail::Interface` for requirements on the `Traits` type.
282 template <typename ConcreteType, typename Traits>
283 class TypeInterface : public detail::Interface<ConcreteType, Type, Traits, Type,
284  TypeTrait::TraitBase> {
285 public:
290 
291 protected:
292  /// Returns the impl interface instance for the given type.
293  static typename InterfaceBase::Concept *getInterfaceFor(Type type) {
294 #ifndef NDEBUG
295  // Check that the current interface isn't an unresolved promise for the
296  // given type.
298  type.getDialect(), type.getTypeID(), ConcreteType::getInterfaceID(),
299  llvm::getTypeName<ConcreteType>());
300 #endif
301 
302  return type.getAbstractType().getInterface<ConcreteType>();
303  }
304 
305  /// Allow access to 'getInterfaceFor'.
307 };
308 
309 //===----------------------------------------------------------------------===//
310 // Core TypeTrait
311 //===----------------------------------------------------------------------===//
312 
313 /// This trait is used to determine if a type is mutable or not. It is attached
314 /// on a type if the corresponding ImplType defines a `mutate` function with
315 /// a proper signature.
316 namespace TypeTrait {
317 template <typename ConcreteType>
319 } // namespace TypeTrait
320 
321 //===----------------------------------------------------------------------===//
322 // Type Utils
323 //===----------------------------------------------------------------------===//
324 
325 // Make Type hashable.
326 inline ::llvm::hash_code hash_value(Type arg) {
328 }
329 
330 template <typename... Tys>
331 bool Type::isa() const {
332  return llvm::isa<Tys...>(*this);
333 }
334 
335 template <typename... Tys>
336 bool Type::isa_and_nonnull() const {
337  return llvm::isa_and_present<Tys...>(*this);
338 }
339 
340 template <typename U>
341 U Type::dyn_cast() const {
342  return llvm::dyn_cast<U>(*this);
343 }
344 
345 template <typename U>
347  return llvm::dyn_cast_or_null<U>(*this);
348 }
349 
350 template <typename U>
351 U Type::cast() const {
352  return llvm::cast<U>(*this);
353 }
354 
355 } // namespace mlir
356 
357 namespace llvm {
358 
359 // Type hash just like pointers.
360 template <>
361 struct DenseMapInfo<mlir::Type> {
363  auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
364  return mlir::Type(static_cast<mlir::Type::ImplType *>(pointer));
365  }
368  return mlir::Type(static_cast<mlir::Type::ImplType *>(pointer));
369  }
370  static unsigned getHashValue(mlir::Type val) { return mlir::hash_value(val); }
371  static bool isEqual(mlir::Type LHS, mlir::Type RHS) { return LHS == RHS; }
372 };
373 template <typename T>
374 struct DenseMapInfo<T, std::enable_if_t<std::is_base_of<mlir::Type, T>::value &&
375  !mlir::detail::IsInterface<T>::value>>
376  : public DenseMapInfo<mlir::Type> {
377  static T getEmptyKey() {
378  const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey();
379  return T::getFromOpaquePointer(pointer);
380  }
381  static T getTombstoneKey() {
383  return T::getFromOpaquePointer(pointer);
384  }
385 };
386 
387 /// We align TypeStorage by 8, so allow LLVM to steal the low bits.
388 template <>
389 struct PointerLikeTypeTraits<mlir::Type> {
390 public:
391  static inline void *getAsVoidPointer(mlir::Type I) {
392  return const_cast<void *>(I.getAsOpaquePointer());
393  }
394  static inline mlir::Type getFromVoidPointer(void *P) {
396  }
397  static constexpr int NumLowBitsAvailable = 3;
398 };
399 
400 /// Add support for llvm style casts.
401 /// We provide a cast between To and From if From is mlir::Type or derives from
402 /// it
403 template <typename To, typename From>
404 struct CastInfo<
405  To, From,
406  std::enable_if_t<std::is_same_v<mlir::Type, std::remove_const_t<From>> ||
407  std::is_base_of_v<mlir::Type, From>>>
409  DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
410  /// Arguments are taken as mlir::Type here and not as `From`, because when
411  /// casting from an intermediate type of the hierarchy to one of its children,
412  /// the val.getTypeID() inside T::classof will use the static getTypeID of the
413  /// parent instead of the non-static Type::getTypeID that returns the dynamic
414  /// ID. This means that T::classof would end up comparing the static TypeID of
415  /// the children to the static TypeID of its parent, making it impossible to
416  /// downcast from the parent to the child.
417  static inline bool isPossible(mlir::Type ty) {
418  /// Return a constant true instead of a dynamic true when casting to self or
419  /// up the hierarchy.
420  if constexpr (std::is_base_of_v<To, From>) {
421  return true;
422  } else {
423  return To::classof(ty);
424  };
425  }
426  static inline To doCast(mlir::Type ty) { return To(ty.getImpl()); }
427 };
428 
429 } // namespace llvm
430 
431 #endif // MLIR_IR_TYPES_H
This class contains all of the static information common to all instances of a registered Type.
Definition: TypeSupport.h:30
Type replaceImmediateSubElements(Type type, ArrayRef< Attribute > replAttrs, ArrayRef< Type > replTypes) const
Replace the immediate sub-elements of the given type.
Definition: Types.cpp:25
void walkImmediateSubElements(Type type, function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk the immediate sub-elements of the given type.
Definition: Types.cpp:19
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this type,...
Definition: TypeSupport.h:79
bool hasTrait() const
Returns true if the type has a particular trait.
Definition: TypeSupport.h:90
This class provides management for the lifetime of the state used when printing the IR.
Definition: AsmState.h:540
This is an attribute/type replacer that is naively cached.
Attribute replace(Attribute attr)
void addWalk(WalkFn< Attribute > &&fn)
Register a walk function for a given attribute or type.
WalkResult walk(T element)
Walk the given attribute/type, and recursively walk any sub elements.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:38
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
This class represents the base of a type interface.
Definition: Types.h:284
static InterfaceBase::Concept * getInterfaceFor(Type type)
Returns the impl interface instance for the given type.
Definition: Types.h:293
friend InterfaceBase
Allow access to 'getInterfaceFor'.
Definition: Types.h:306
Base storage class appearing in a Type.
Definition: TypeSupport.h:166
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
void print(raw_ostream &os) const
Print the current type.
bool isF64() const
Definition: Types.cpp:60
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Definition: Types.h:188
bool isTF32() const
Definition: Types.cpp:58
U cast() const
Definition: Types.h:351
Dialect & getDialect() const
Get the dialect this type is registered to.
Definition: Types.h:123
auto replaceImmediateSubElements(ArrayRef< Attribute > replAttrs, ArrayRef< Type > replTypes) const
Replace the immediately nested sub-attributes and sub-types with those provided.
Definition: Types.h:229
Type(const Type &other)=default
bool isSignlessIntOrIndex() const
Return true if this is a signless integer or index type.
Definition: Types.cpp:111
U dyn_cast_or_null() const
Definition: Types.h:346
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:35
bool isa_and_nonnull() const
Definition: Types.h:336
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
Definition: Types.cpp:87
bool isFloat8E4M3FN() const
Definition: Types.cpp:42
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
Definition: Types.cpp:75
ImplType * impl
Definition: Types.h:258
friend ::llvm::hash_code hash_value(Type arg)
Definition: Types.h:326
static Type getFromOpaquePointer(const void *pointer)
Definition: Types.h:191
bool isIndex() const
Definition: Types.cpp:64
bool hasTrait()
Returns true if the type was registered with a particular trait.
Definition: Types.h:206
bool isFloat8E3M4() const
Definition: Types.cpp:55
constexpr Type()=default
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
Definition: Types.cpp:131
U dyn_cast() const
Definition: Types.h:341
bool isF32() const
Definition: Types.cpp:59
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
Definition: Types.h:218
bool hasPromiseOrImplementsInterface()
Returns true if InterfaceT has been promised by the dialect or implemented.
Definition: Types.h:198
bool isFloat8E4M3FNUZ() const
Definition: Types.cpp:46
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
Definition: Types.cpp:99
const AbstractTy & getAbstractType() const
Return the abstract type descriptor for this type.
Definition: Types.h:211
bool isIntOrIndex() const
Return true if this is an integer (of any signedness) or an index type.
Definition: Types.cpp:123
bool isFloat8E4M3B11FNUZ() const
Definition: Types.cpp:49
Type & operator=(const Type &other)=default
ImplType * getImpl() const
Return the Type implementation.
Definition: Types.h:214
bool isFloat6E3M2FN() const
Definition: Types.cpp:39
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition: Types.cpp:66
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
Definition: Types.cpp:127
Type(const ImplType *impl)
Definition: Types.h:87
bool isFloat8E5M2() const
Definition: Types.cpp:40
bool isFloat8E8M0FNU() const
Definition: Types.cpp:52
bool isFloat4E2M1FN() const
Definition: Types.cpp:37
bool operator!() const
Definition: Types.h:97
bool operator==(Type other) const
Definition: Types.h:93
bool isF128() const
Definition: Types.cpp:62
TypeID getTypeID()
Return a unique identifier for the concrete type.
Definition: Types.h:117
void dump() const
bool operator!=(Type other) const
Definition: Types.h:94
bool isF16() const
Definition: Types.cpp:57
bool isF80() const
Definition: Types.cpp:61
bool isa() const
Definition: Types.h:331
auto replace(ReplacementFns &&...replacementFns)
Recursively replace all of the nested sub-attributes and sub-types using the provided map functions.
Definition: Types.h:250
auto walk(WalkFns &&...walkFns)
Walk this type and all attibutes/types nested within using the provided walk functions.
Definition: Types.h:239
bool isFloat6E2M3FN() const
Definition: Types.cpp:38
bool isSignlessIntOrFloat() const
Return true of this is a signless integer or a float type.
Definition: Types.cpp:119
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition: Types.cpp:133
bool isBF16() const
Definition: Types.cpp:56
bool isFloat8E4M3() const
Definition: Types.cpp:41
bool isFloat8E5M2FNUZ() const
Definition: Types.cpp:43
bool isSignlessIntOrIndexOrFloat() const
Return true if this is a signless integer, index, or float type.
Definition: Types.cpp:115
void addReplacement(ReplaceFn< Attribute > fn)
Register a replacement function for mapping a given attribute or type.
This class represents an abstract interface.
Interface< ConcreteType, Type, Traits, Type, TypeTrait::TraitBase > InterfaceBase
Utility class for implementing users of storage classes uniqued by a StorageUniquer.
Helper class for implementing traits for storage classes.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
bool hasPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID)
Checks if a promise has been made for the interface/requestor pair.
Definition: Dialect.cpp:172
void handleUseOfUndefinedPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID, StringRef interfaceName)
Checks if the given interface, which is attempting to be used, is a promised interface of this dialec...
Definition: Dialect.cpp:159
Include the generated interface declarations.
WalkOrder
Traversal order for region, block and operation walk utilities.
Definition: Visitors.h:62
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition: AffineExpr.h:260
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Definition: AliasAnalysis.h:78
static bool isPossible(mlir::Type ty)
Arguments are taken as mlir::Type here and not as From, because when casting from an intermediate typ...
Definition: Types.h:417
static mlir::Type getEmptyKey()
Definition: Types.h:362
static unsigned getHashValue(mlir::Type val)
Definition: Types.h:370
static mlir::Type getTombstoneKey()
Definition: Types.h:366
static bool isEqual(mlir::Type LHS, mlir::Type RHS)
Definition: Types.h:371
static void * getAsVoidPointer(mlir::Type I)
Definition: Types.h:391
static mlir::Type getFromVoidPointer(void *P)
Definition: Types.h:394
This trait is used to determine if a storage user, like Type, is mutable or not.
A utility class to get, or create, unique instances of types within an MLIRContext.
Definition: TypeSupport.h:210