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