MLIR  14.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> typename T::Concept *getInterface() const {
63  return interfaceMap.lookup<T>();
64  }
65 
66  /// Returns true if the type has the interface with the given ID.
67  bool hasInterface(TypeID interfaceID) const {
68  return interfaceMap.contains(interfaceID);
69  }
70 
71  /// Returns true if the type has a particular trait.
72  template <template <typename T> class Trait>
73  bool hasTrait() const {
74  return hasTraitFn(TypeID::get<Trait>());
75  }
76 
77  /// Returns true if the type has a particular trait.
78  bool hasTrait(TypeID traitID) const { return hasTraitFn(traitID); }
79 
80  /// Return the unique identifier representing the concrete type class.
81  TypeID getTypeID() const { return typeID; }
82 
83 private:
84  AbstractType(Dialect &dialect, detail::InterfaceMap &&interfaceMap,
85  HasTraitFn &&hasTrait, TypeID typeID)
86  : dialect(dialect), interfaceMap(std::move(interfaceMap)),
87  hasTraitFn(std::move(hasTrait)), typeID(typeID) {}
88 
89  /// Give StorageUserBase access to the mutable lookup.
90  template <typename ConcreteT, typename BaseT, typename StorageT,
91  typename UniquerT, template <typename T> class... Traits>
93 
94  /// Look up the specified abstract type in the MLIRContext and return a
95  /// (mutable) pointer to it. Return a null pointer if the type could not
96  /// be found in the context.
97  static AbstractType *lookupMutable(TypeID typeID, MLIRContext *context);
98 
99  /// This is the dialect that this type was registered to.
100  const Dialect &dialect;
101 
102  /// This is a collection of the interfaces registered to this type.
103  detail::InterfaceMap interfaceMap;
104 
105  /// Function to check if the type has a particular trait.
106  HasTraitFn hasTraitFn;
107 
108  /// The unique identifier of the derived Type class.
109  const TypeID typeID;
110 };
111 
112 //===----------------------------------------------------------------------===//
113 // TypeStorage
114 //===----------------------------------------------------------------------===//
115 
116 namespace detail {
117 struct TypeUniquer;
118 } // namespace detail
119 
120 /// Base storage class appearing in a Type.
122  friend detail::TypeUniquer;
123  friend StorageUniquer;
124 
125 public:
126  /// Return the abstract type descriptor for this type.
128  assert(abstractType && "Malformed type storage object.");
129  return *abstractType;
130  }
131 
132 protected:
133  /// This constructor is used by derived classes as part of the TypeUniquer.
135 
136 private:
137  /// Set the abstract type for this storage instance. This is used by the
138  /// TypeUniquer when initializing a newly constructed type storage object.
139  void initialize(const AbstractType &abstractTy) {
140  abstractType = const_cast<AbstractType *>(&abstractTy);
141  }
142 
143  /// The abstract description for this type.
144  AbstractType *abstractType{nullptr};
145 };
146 
147 /// Default storage type for types that require no additional initialization or
148 /// storage.
150 
151 //===----------------------------------------------------------------------===//
152 // TypeStorageAllocator
153 //===----------------------------------------------------------------------===//
154 
155 /// This is a utility allocator used to allocate memory for instances of derived
156 /// Types.
158 
159 //===----------------------------------------------------------------------===//
160 // TypeUniquer
161 //===----------------------------------------------------------------------===//
162 namespace detail {
163 /// A utility class to get, or create, unique instances of types within an
164 /// MLIRContext. This class manages all creation and uniquing of types.
165 struct TypeUniquer {
166  /// Get an uniqued instance of a parametric type T.
167  template <typename T, typename... Args>
168  static typename std::enable_if_t<
170  get(MLIRContext *ctx, Args &&...args) {
171 #ifndef NDEBUG
172  if (!ctx->getTypeUniquer().isParametricStorageInitialized(T::getTypeID()))
173  llvm::report_fatal_error(
174  llvm::Twine("can't create type '") + llvm::getTypeName<T>() +
175  "' because storage uniquer isn't initialized: the dialect was likely "
176  "not loaded, or the type wasn't added with addTypes<...>() "
177  "in the Dialect::initialize() method.");
178 #endif
179  return ctx->getTypeUniquer().get<typename T::ImplType>(
180  [&](TypeStorage *storage) {
181  storage->initialize(AbstractType::lookup(T::getTypeID(), ctx));
182  },
183  T::getTypeID(), std::forward<Args>(args)...);
184  }
185  /// Get an uniqued instance of a singleton type T.
186  template <typename T>
187  static typename std::enable_if_t<
189  get(MLIRContext *ctx) {
190 #ifndef NDEBUG
191  if (!ctx->getTypeUniquer().isSingletonStorageInitialized(T::getTypeID()))
192  llvm::report_fatal_error(
193  llvm::Twine("can't create type '") + llvm::getTypeName<T>() +
194  "' because storage uniquer isn't initialized: the dialect was likely "
195  "not loaded, or the type wasn't added with addTypes<...>() "
196  "in the Dialect::initialize() method.");
197 #endif
198  return ctx->getTypeUniquer().get<typename T::ImplType>(T::getTypeID());
199  }
200 
201  /// Change the mutable component of the given type instance in the provided
202  /// context.
203  template <typename T, typename... Args>
204  static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl,
205  Args &&...args) {
206  assert(impl && "cannot mutate null type");
207  return ctx->getTypeUniquer().mutate(T::getTypeID(), impl,
208  std::forward<Args>(args)...);
209  }
210 
211  /// Register a parametric type instance T with the uniquer.
212  template <typename T>
213  static typename std::enable_if_t<
214  !std::is_same<typename T::ImplType, TypeStorage>::value>
216  ctx->getTypeUniquer().registerParametricStorageType<typename T::ImplType>(
217  T::getTypeID());
218  }
219  /// Register a singleton type instance T with the uniquer.
220  template <typename T>
221  static typename std::enable_if_t<
222  std::is_same<typename T::ImplType, TypeStorage>::value>
225  T::getTypeID(), [&](TypeStorage *storage) {
226  storage->initialize(AbstractType::lookup(T::getTypeID(), ctx));
227  });
228  }
229 };
230 } // namespace detail
231 
232 } // namespace mlir
233 
234 #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;.
Base storage class appearing in a Type.
Definition: TypeSupport.h:121
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:134
bool hasTrait(TypeID traitID) const
Returns true if the type has a particular trait.
Definition: TypeSupport.h:78
bool hasTrait() const
Returns true if the type has a particular trait.
Definition: TypeSupport.h:73
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
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:52
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:204
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
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:165
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:62
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:42
bool hasInterface(TypeID interfaceID) const
Returns true if the type has the interface with the given ID.
Definition: TypeSupport.h:67
const AbstractType & getAbstractType()
Return the abstract type descriptor for this type.
Definition: TypeSupport.h:127
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:81
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
static std::enable_if_t< std::is_same< typename T::ImplType, TypeStorage >::value > registerType(MLIRContext *ctx)
Register a singleton type instance T with the uniquer.
Definition: TypeSupport.h:223
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.
static std::enable_if_t< !std::is_same< typename T::ImplType, TypeStorage >::value > registerType(MLIRContext *ctx)
Register a parametric type instance T with the uniquer.
Definition: TypeSupport.h:215