• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_TYPE_SUPPORT_H
14 #define MLIR_IR_TYPE_SUPPORT_H
15 
16 #include "mlir/IR/MLIRContext.h"
17 #include "mlir/IR/StorageUniquerSupport.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   /// Look up the specified abstract type in the MLIRContext and return a
33   /// reference to it.
34   static const AbstractType &lookup(TypeID typeID, MLIRContext *context);
35 
36   /// This method is used by Dialect objects when they register the list of
37   /// types they contain.
get(Dialect & dialect)38   template <typename T> static AbstractType get(Dialect &dialect) {
39     return AbstractType(dialect, T::getInterfaceMap(), T::getTypeID());
40   }
41 
42   /// Return the dialect this type was registered to.
getDialect()43   Dialect &getDialect() const { return const_cast<Dialect &>(dialect); }
44 
45   /// Returns an instance of the concept object for the given interface if it
46   /// was registered to this type, null otherwise. This should not be used
47   /// directly.
getInterface()48   template <typename T> typename T::Concept *getInterface() const {
49     return interfaceMap.lookup<T>();
50   }
51 
52   /// Return the unique identifier representing the concrete type class.
getTypeID()53   TypeID getTypeID() const { return typeID; }
54 
55 private:
AbstractType(Dialect & dialect,detail::InterfaceMap && interfaceMap,TypeID typeID)56   AbstractType(Dialect &dialect, detail::InterfaceMap &&interfaceMap,
57                TypeID typeID)
58       : dialect(dialect), interfaceMap(std::move(interfaceMap)),
59         typeID(typeID) {}
60 
61   /// This is the dialect that this type was registered to.
62   Dialect &dialect;
63 
64   /// This is a collection of the interfaces registered to this type.
65   detail::InterfaceMap interfaceMap;
66 
67   /// The unique identifier of the derived Type class.
68   TypeID typeID;
69 };
70 
71 //===----------------------------------------------------------------------===//
72 // TypeStorage
73 //===----------------------------------------------------------------------===//
74 
75 namespace detail {
76 struct TypeUniquer;
77 } // end namespace detail
78 
79 /// Base storage class appearing in a Type.
80 class TypeStorage : public StorageUniquer::BaseStorage {
81   friend detail::TypeUniquer;
82   friend StorageUniquer;
83 
84 public:
85   /// Return the abstract type descriptor for this type.
getAbstractType()86   const AbstractType &getAbstractType() {
87     assert(abstractType && "Malformed type storage object.");
88     return *abstractType;
89   }
90 
91 protected:
92   /// This constructor is used by derived classes as part of the TypeUniquer.
TypeStorage()93   TypeStorage() : abstractType(nullptr) {}
94 
95 private:
96   /// Set the abstract type for this storage instance. This is used by the
97   /// TypeUniquer when initializing a newly constructed type storage object.
initialize(const AbstractType & abstractTy)98   void initialize(const AbstractType &abstractTy) {
99     abstractType = &abstractTy;
100   }
101 
102   /// The abstract description for this type.
103   const AbstractType *abstractType;
104 };
105 
106 /// Default storage type for types that require no additional initialization or
107 /// storage.
108 using DefaultTypeStorage = TypeStorage;
109 
110 //===----------------------------------------------------------------------===//
111 // TypeStorageAllocator
112 //===----------------------------------------------------------------------===//
113 
114 /// This is a utility allocator used to allocate memory for instances of derived
115 /// Types.
116 using TypeStorageAllocator = StorageUniquer::StorageAllocator;
117 
118 //===----------------------------------------------------------------------===//
119 // TypeUniquer
120 //===----------------------------------------------------------------------===//
121 namespace detail {
122 /// A utility class to get, or create, unique instances of types within an
123 /// MLIRContext. This class manages all creation and uniquing of types.
124 struct TypeUniquer {
125   /// Get an uniqued instance of a parametric type T.
126   template <typename T, typename... Args>
127   static typename std::enable_if_t<
128       !std::is_same<typename T::ImplType, TypeStorage>::value, T>
getTypeUniquer129   get(MLIRContext *ctx, Args &&...args) {
130 #ifndef NDEBUG
131     if (!ctx->getTypeUniquer().isParametricStorageInitialized(T::getTypeID()))
132       llvm::report_fatal_error(llvm::Twine("can't create type '") +
133                                llvm::getTypeName<T>() +
134                                "' because storage uniquer isn't initialized: "
135                                "the dialect was likely not loaded.");
136 #endif
137     return ctx->getTypeUniquer().get<typename T::ImplType>(
138         [&](TypeStorage *storage) {
139           storage->initialize(AbstractType::lookup(T::getTypeID(), ctx));
140         },
141         T::getTypeID(), std::forward<Args>(args)...);
142   }
143   /// Get an uniqued instance of a singleton type T.
144   template <typename T>
145   static typename std::enable_if_t<
146       std::is_same<typename T::ImplType, TypeStorage>::value, T>
getTypeUniquer147   get(MLIRContext *ctx) {
148 #ifndef NDEBUG
149     if (!ctx->getTypeUniquer().isSingletonStorageInitialized(T::getTypeID()))
150       llvm::report_fatal_error(llvm::Twine("can't create type '") +
151                                llvm::getTypeName<T>() +
152                                "' because storage uniquer isn't initialized: "
153                                "the dialect was likely not loaded.");
154 #endif
155     return ctx->getTypeUniquer().get<typename T::ImplType>(T::getTypeID());
156   }
157 
158   /// Change the mutable component of the given type instance in the provided
159   /// context.
160   template <typename T, typename... Args>
mutateTypeUniquer161   static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl,
162                               Args &&...args) {
163     assert(impl && "cannot mutate null type");
164     return ctx->getTypeUniquer().mutate(T::getTypeID(), impl,
165                                         std::forward<Args>(args)...);
166   }
167 
168   /// Register a parametric type instance T with the uniquer.
169   template <typename T>
170   static typename std::enable_if_t<
171       !std::is_same<typename T::ImplType, TypeStorage>::value>
registerTypeTypeUniquer172   registerType(MLIRContext *ctx) {
173     ctx->getTypeUniquer().registerParametricStorageType<typename T::ImplType>(
174         T::getTypeID());
175   }
176   /// Register a singleton type instance T with the uniquer.
177   template <typename T>
178   static typename std::enable_if_t<
179       std::is_same<typename T::ImplType, TypeStorage>::value>
registerTypeTypeUniquer180   registerType(MLIRContext *ctx) {
181     ctx->getTypeUniquer().registerSingletonStorageType<TypeStorage>(
182         T::getTypeID(), [&](TypeStorage *storage) {
183           storage->initialize(AbstractType::lookup(T::getTypeID(), ctx));
184         });
185   }
186 };
187 } // namespace detail
188 
189 } // end namespace mlir
190 
191 #endif
192