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" 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 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> get(Dialect & dialect)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)'; get(Dialect & dialect,detail::InterfaceMap && interfaceMap,HasTraitFn && hasTrait,TypeID typeID)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. getDialect()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> getInterface()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. hasInterface(TypeID interfaceID)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> hasTrait()74 bool hasTrait() const { 75 return hasTraitFn(TypeID::get<Trait>()); 76 } 77 78 /// Returns true if the type has a particular trait. hasTrait(TypeID traitID)79 bool hasTrait(TypeID traitID) const { return hasTraitFn(traitID); } 80 81 /// Return the unique identifier representing the concrete type class. getTypeID()82 TypeID getTypeID() const { return typeID; } 83 84 private: AbstractType(Dialect & dialect,detail::InterfaceMap && interfaceMap,HasTraitFn && hasTrait,TypeID typeID)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> 93 friend class detail::StorageUserBase; 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. 122 class TypeStorage : public StorageUniquer::BaseStorage { 123 friend detail::TypeUniquer; 124 friend StorageUniquer; 125 126 public: 127 /// Return the abstract type descriptor for this type. getAbstractType()128 const AbstractType &getAbstractType() { 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. TypeStorage()135 TypeStorage() {} 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. initialize(const AbstractType & abstractTy)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. 150 using DefaultTypeStorage = TypeStorage; 151 152 //===----------------------------------------------------------------------===// 153 // TypeStorageAllocator 154 //===----------------------------------------------------------------------===// 155 156 /// This is a utility allocator used to allocate memory for instances of derived 157 /// Types. 158 using TypeStorageAllocator = StorageUniquer::StorageAllocator; 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> getTypeUniquer169 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< 179 !std::is_same<typename T::ImplType, TypeStorage>::value, T> getWithTypeIDTypeUniquer180 getWithTypeID(MLIRContext *ctx, TypeID typeID, Args &&...args) { 181 #ifndef NDEBUG 182 if (!ctx->getTypeUniquer().isParametricStorageInitialized(typeID)) 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< 200 std::is_same<typename T::ImplType, TypeStorage>::value, T> getWithTypeIDTypeUniquer201 getWithTypeID(MLIRContext *ctx, TypeID typeID) { 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> mutateTypeUniquer216 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> registerTypeTypeUniquer225 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> registerTypeTypeUniquer235 registerType(MLIRContext *ctx, TypeID typeID) { 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> registerTypeTypeUniquer245 registerType(MLIRContext *ctx, TypeID typeID) { 246 ctx->getTypeUniquer().registerSingletonStorageType<TypeStorage>( 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 257