MLIR  16.0.0git
TypeSupport.h
Go to the documentation of this file.
1 //===- TypeSupport.h --------------------------------------------*- 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 defines support types for registering dialect extended types.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_IR_TYPESUPPORT_H
14 #define MLIR_IR_TYPESUPPORT_H
15 
16 #include "mlir/IR/MLIRContext.h"
18 #include "llvm/ADT/Twine.h"
19 
20 namespace mlir {
21 class Dialect;
22 class MLIRContext;
23 
24 //===----------------------------------------------------------------------===//
25 // AbstractType
26 //===----------------------------------------------------------------------===//
27 
28 /// This class contains all of the static information common to all instances of
29 /// a registered Type.
30 class AbstractType {
31 public:
32  using HasTraitFn = llvm::unique_function<bool(TypeID) const>;
33 
34  /// Look up the specified abstract type in the MLIRContext and return a
35  /// reference to it.
36  static const AbstractType &lookup(TypeID typeID, MLIRContext *context);
37 
38  /// This method is used by Dialect objects when they register the list of
39  /// types they contain.
40  template <typename T>
41  static AbstractType get(Dialect &dialect) {
42  return AbstractType(dialect, T::getInterfaceMap(), T::getHasTraitFn(),
43  T::getTypeID());
44  }
45 
46  /// This method is used by Dialect objects to register types with
47  /// custom TypeIDs.
48  /// The use of this method is in general discouraged in favor of
49  /// 'get<CustomType>(dialect)';
50  static AbstractType get(Dialect &dialect, detail::InterfaceMap &&interfaceMap,
51  HasTraitFn &&hasTrait, TypeID typeID) {
52  return AbstractType(dialect, std::move(interfaceMap), std::move(hasTrait),
53  typeID);
54  }
55 
56  /// Return the dialect this type was registered to.
57  Dialect &getDialect() const { return const_cast<Dialect &>(dialect); }
58 
59  /// Returns an instance of the concept object for the given interface if it
60  /// was registered to this type, null otherwise. This should not be used
61  /// directly.
62  template <typename T>
63  typename T::Concept *getInterface() const {
64  return interfaceMap.lookup<T>();
65  }
66 
67  /// Returns true if the type has the interface with the given ID.
68  bool hasInterface(TypeID interfaceID) const {
69  return interfaceMap.contains(interfaceID);
70  }
71 
72  /// Returns true if the type has a particular trait.
73  template <template <typename T> class Trait>
74  bool hasTrait() const {
75  return hasTraitFn(TypeID::get<Trait>());
76  }
77 
78  /// Returns true if the type has a particular trait.
79  bool hasTrait(TypeID traitID) const { return hasTraitFn(traitID); }
80 
81  /// Return the unique identifier representing the concrete type class.
82  TypeID getTypeID() const { return typeID; }
83 
84 private:
85  AbstractType(Dialect &dialect, detail::InterfaceMap &&interfaceMap,
86  HasTraitFn &&hasTrait, TypeID typeID)
87  : dialect(dialect), interfaceMap(std::move(interfaceMap)),
88  hasTraitFn(std::move(hasTrait)), typeID(typeID) {}
89 
90  /// Give StorageUserBase access to the mutable lookup.
91  template <typename ConcreteT, typename BaseT, typename StorageT,
92  typename UniquerT, template <typename T> class... Traits>
94 
95  /// Look up the specified abstract type in the MLIRContext and return a
96  /// (mutable) pointer to it. Return a null pointer if the type could not
97  /// be found in the context.
98  static AbstractType *lookupMutable(TypeID typeID, MLIRContext *context);
99 
100  /// This is the dialect that this type was registered to.
101  const Dialect &dialect;
102 
103  /// This is a collection of the interfaces registered to this type.
104  detail::InterfaceMap interfaceMap;
105 
106  /// Function to check if the type has a particular trait.
107  HasTraitFn hasTraitFn;
108 
109  /// The unique identifier of the derived Type class.
110  const TypeID typeID;
111 };
112 
113 //===----------------------------------------------------------------------===//
114 // TypeStorage
115 //===----------------------------------------------------------------------===//
116 
117 namespace detail {
118 struct TypeUniquer;
119 } // namespace detail
120 
121 /// Base storage class appearing in a Type.
123  friend detail::TypeUniquer;
124  friend StorageUniquer;
125 
126 public:
127  /// Return the abstract type descriptor for this type.
129  assert(abstractType && "Malformed type storage object.");
130  return *abstractType;
131  }
132 
133 protected:
134  /// This constructor is used by derived classes as part of the TypeUniquer.
136 
137 private:
138  /// Set the abstract type for this storage instance. This is used by the
139  /// TypeUniquer when initializing a newly constructed type storage object.
140  void initialize(const AbstractType &abstractTy) {
141  abstractType = const_cast<AbstractType *>(&abstractTy);
142  }
143 
144  /// The abstract description for this type.
145  AbstractType *abstractType{nullptr};
146 };
147 
148 /// Default storage type for types that require no additional initialization or
149 /// storage.
151 
152 //===----------------------------------------------------------------------===//
153 // TypeStorageAllocator
154 //===----------------------------------------------------------------------===//
155 
156 /// This is a utility allocator used to allocate memory for instances of derived
157 /// Types.
159 
160 //===----------------------------------------------------------------------===//
161 // TypeUniquer
162 //===----------------------------------------------------------------------===//
163 namespace detail {
164 /// A utility class to get, or create, unique instances of types within an
165 /// MLIRContext. This class manages all creation and uniquing of types.
166 struct TypeUniquer {
167  /// Get an uniqued instance of a type T.
168  template <typename T, typename... Args>
169  static T get(MLIRContext *ctx, Args &&...args) {
170  return getWithTypeID<T, Args...>(ctx, T::getTypeID(),
171  std::forward<Args>(args)...);
172  }
173 
174  /// Get an uniqued instance of a parametric type T.
175  /// The use of this method is in general discouraged in favor of
176  /// 'get<T, Args>(ctx, args)'.
177  template <typename T, typename... Args>
178  static typename std::enable_if_t<
180  getWithTypeID(MLIRContext *ctx, TypeID typeID, Args &&...args) {
181 #ifndef NDEBUG
183  llvm::report_fatal_error(
184  llvm::Twine("can't create type '") + llvm::getTypeName<T>() +
185  "' because storage uniquer isn't initialized: the dialect was likely "
186  "not loaded, or the type wasn't added with addTypes<...>() "
187  "in the Dialect::initialize() method.");
188 #endif
189  return ctx->getTypeUniquer().get<typename T::ImplType>(
190  [&, typeID](TypeStorage *storage) {
191  storage->initialize(AbstractType::lookup(typeID, ctx));
192  },
193  typeID, std::forward<Args>(args)...);
194  }
195  /// Get an uniqued instance of a singleton type T.
196  /// The use of this method is in general discouraged in favor of
197  /// 'get<T, Args>(ctx, args)'.
198  template <typename T>
199  static typename std::enable_if_t<
202 #ifndef NDEBUG
203  if (!ctx->getTypeUniquer().isSingletonStorageInitialized(typeID))
204  llvm::report_fatal_error(
205  llvm::Twine("can't create type '") + llvm::getTypeName<T>() +
206  "' because storage uniquer isn't initialized: the dialect was likely "
207  "not loaded, or the type wasn't added with addTypes<...>() "
208  "in the Dialect::initialize() method.");
209 #endif
210  return ctx->getTypeUniquer().get<typename T::ImplType>(typeID);
211  }
212 
213  /// Change the mutable component of the given type instance in the provided
214  /// context.
215  template <typename T, typename... Args>
216  static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl,
217  Args &&...args) {
218  assert(impl && "cannot mutate null type");
219  return ctx->getTypeUniquer().mutate(T::getTypeID(), impl,
220  std::forward<Args>(args)...);
221  }
222 
223  /// Register a type instance T with the uniquer.
224  template <typename T>
225  static void registerType(MLIRContext *ctx) {
226  registerType<T>(ctx, T::getTypeID());
227  }
228 
229  /// Register a parametric type instance T with the uniquer.
230  /// The use of this method is in general discouraged in favor of
231  /// 'registerType<T>(ctx)'.
232  template <typename T>
233  static typename std::enable_if_t<
234  !std::is_same<typename T::ImplType, TypeStorage>::value>
236  ctx->getTypeUniquer().registerParametricStorageType<typename T::ImplType>(
237  typeID);
238  }
239  /// Register a singleton type instance T with the uniquer.
240  /// The use of this method is in general discouraged in favor of
241  /// 'registerType<T>(ctx)'.
242  template <typename T>
243  static typename std::enable_if_t<
244  std::is_same<typename T::ImplType, TypeStorage>::value>
247  typeID, [&ctx, typeID](TypeStorage *storage) {
248  storage->initialize(AbstractType::lookup(typeID, ctx));
249  });
250  }
251 };
252 } // namespace detail
253 
254 } // namespace mlir
255 
256 #endif
Include the generated interface declarations.
Storage * get(function_ref< void(Storage *)> initFn, TypeID id, Args &&...args)
Gets a uniqued instance of &#39;Storage&#39;.
static void registerType(MLIRContext *ctx)
Register a type instance T with the uniquer.
Definition: TypeSupport.h:225
Base storage class appearing in a Type.
Definition: TypeSupport.h:122
This is a utility allocator used to allocate memory for instances of derived types.
TypeStorage()
This constructor is used by derived classes as part of the TypeUniquer.
Definition: TypeSupport.h:135
bool hasTrait(TypeID traitID) const
Returns true if the type has a particular trait.
Definition: TypeSupport.h:79
bool hasTrait() const
Returns true if the type has a particular trait.
Definition: TypeSupport.h:74
static const AbstractType & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract type in the MLIRContext and return a reference to it.
This class contains all of the static information common to all instances of a registered Type...
Definition: TypeSupport.h:30
StorageUniquer & getTypeUniquer()
Returns the storage uniquer used for constructing type storage instances.
static constexpr const bool value
static std::enable_if_t< !std::is_same< typename T::ImplType, TypeStorage >::value, T > getWithTypeID(MLIRContext *ctx, TypeID typeID, Args &&...args)
Get an uniqued instance of a parametric type T.
Definition: TypeSupport.h:180
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl, Args &&...args)
Change the mutable component of the given type instance in the provided context.
Definition: TypeSupport.h:216
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
static std::enable_if_t< !std::is_same< typename T::ImplType, TypeStorage >::value > registerType(MLIRContext *ctx, TypeID typeID)
Register a parametric type instance T with the uniquer.
Definition: TypeSupport.h:235
bool isSingletonStorageInitialized(TypeID id)
Test if there is a singleton storage uniquer initialized for the provided TypeID. ...
This class provides an efficient mapping between a given Interface type, and a particular implementat...
void registerParametricStorageType(TypeID id)
Register a new parametric storage class, this is necessary to create instances of this class type...
A utility class to get, or create, unique instances of types within an MLIRContext.
Definition: TypeSupport.h:166
static std::enable_if_t< std::is_same< typename T::ImplType, TypeStorage >::value > registerType(MLIRContext *ctx, TypeID typeID)
Register a singleton type instance T with the uniquer.
Definition: TypeSupport.h:245
LogicalResult mutate(TypeID id, Storage *storage, Args &&...args)
Changes the mutable component of &#39;storage&#39; by forwarding the trailing arguments to the &#39;mutate&#39; funct...
Dialect & getDialect() const
Return the dialect this type was registered to.
Definition: TypeSupport.h:57
bool isParametricStorageInitialized(TypeID id)
Test if there is a parametric storage uniquer initialized for the provided TypeID.
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:63
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
bool hasInterface(TypeID interfaceID) const
Returns true if the type has the interface with the given ID.
Definition: TypeSupport.h:68
const AbstractType & getAbstractType()
Return the abstract type descriptor for this type.
Definition: TypeSupport.h:128
static std::enable_if_t< std::is_same< typename T::ImplType, TypeStorage >::value, T > getWithTypeID(MLIRContext *ctx, TypeID typeID)
Get an uniqued instance of a singleton type T.
Definition: TypeSupport.h:201
A utility class to get or create instances of "storage classes".
TypeID getTypeID() const
Return the unique identifier representing the concrete type class.
Definition: TypeSupport.h:82
This class acts as the base storage that all storage classes must derived from.
Utility class for implementing users of storage classes uniqued by a StorageUniquer.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
llvm::unique_function< bool(TypeID) const > HasTraitFn
Definition: TypeSupport.h:32
void registerSingletonStorageType(TypeID id, function_ref< void(Storage *)> initFn)
Register a new singleton storage class, this is necessary to get the singletone instance.