1 //===- AttributeSupport.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 attributes. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef MLIR_IR_ATTRIBUTESUPPORT_H 14 #define MLIR_IR_ATTRIBUTESUPPORT_H 15 16 #include "mlir/IR/MLIRContext.h" 17 #include "mlir/IR/StorageUniquerSupport.h" 18 #include "llvm/ADT/PointerIntPair.h" 19 #include "llvm/ADT/Twine.h" 20 21 namespace mlir { 22 class MLIRContext; 23 class Type; 24 25 //===----------------------------------------------------------------------===// 26 // AbstractAttribute 27 //===----------------------------------------------------------------------===// 28 29 /// This class contains all of the static information common to all instances of 30 /// a registered Attribute. 31 class AbstractAttribute { 32 public: 33 /// Look up the specified abstract attribute in the MLIRContext and return a 34 /// reference to it. 35 static const AbstractAttribute &lookup(TypeID typeID, MLIRContext *context); 36 37 /// This method is used by Dialect objects when they register the list of 38 /// attributes they contain. get(Dialect & dialect)39 template <typename T> static AbstractAttribute get(Dialect &dialect) { 40 return AbstractAttribute(dialect, T::getInterfaceMap(), T::getTypeID()); 41 } 42 43 /// Return the dialect this attribute was registered to. getDialect()44 Dialect &getDialect() const { return const_cast<Dialect &>(dialect); } 45 46 /// Returns an instance of the concept object for the given interface if it 47 /// was registered to this attribute, null otherwise. This should not be used 48 /// directly. getInterface()49 template <typename T> typename T::Concept *getInterface() const { 50 return interfaceMap.lookup<T>(); 51 } 52 53 /// Return the unique identifier representing the concrete attribute class. getTypeID()54 TypeID getTypeID() const { return typeID; } 55 56 private: AbstractAttribute(Dialect & dialect,detail::InterfaceMap && interfaceMap,TypeID typeID)57 AbstractAttribute(Dialect &dialect, detail::InterfaceMap &&interfaceMap, 58 TypeID typeID) 59 : dialect(dialect), interfaceMap(std::move(interfaceMap)), 60 typeID(typeID) {} 61 62 /// This is the dialect that this attribute was registered to. 63 Dialect &dialect; 64 65 /// This is a collection of the interfaces registered to this attribute. 66 detail::InterfaceMap interfaceMap; 67 68 /// The unique identifier of the derived Attribute class. 69 TypeID typeID; 70 }; 71 72 //===----------------------------------------------------------------------===// 73 // AttributeStorage 74 //===----------------------------------------------------------------------===// 75 76 namespace detail { 77 class AttributeUniquer; 78 } // end namespace detail 79 80 /// Base storage class appearing in an attribute. Derived storage classes should 81 /// only be constructed within the context of the AttributeUniquer. 82 class alignas(8) AttributeStorage : public StorageUniquer::BaseStorage { 83 friend detail::AttributeUniquer; 84 friend StorageUniquer; 85 86 public: 87 /// Get the type of this attribute. 88 Type getType() const; 89 90 /// Return the abstract descriptor for this attribute. getAbstractAttribute()91 const AbstractAttribute &getAbstractAttribute() const { 92 assert(abstractAttribute && "Malformed attribute storage object."); 93 return *abstractAttribute; 94 } 95 96 protected: 97 /// Construct a new attribute storage instance with the given type. 98 /// Note: All attributes require a valid type. If no type is provided here, 99 /// the type of the attribute will automatically default to NoneType 100 /// upon initialization in the uniquer. 101 AttributeStorage(Type type); 102 AttributeStorage(); 103 104 /// Set the type of this attribute. 105 void setType(Type type); 106 107 // Set the abstract attribute for this storage instance. This is used by the 108 // AttributeUniquer when initializing a newly constructed storage object. initialize(const AbstractAttribute & abstractAttr)109 void initialize(const AbstractAttribute &abstractAttr) { 110 abstractAttribute = &abstractAttr; 111 } 112 113 private: 114 /// The abstract descriptor for this attribute. 115 const AbstractAttribute *abstractAttribute; 116 117 /// The opaque type of the attribute value. 118 const void *type; 119 }; 120 121 /// Default storage type for attributes that require no additional 122 /// initialization or storage. 123 using DefaultAttributeStorage = AttributeStorage; 124 125 //===----------------------------------------------------------------------===// 126 // AttributeStorageAllocator 127 //===----------------------------------------------------------------------===// 128 129 // This is a utility allocator used to allocate memory for instances of derived 130 // Attributes. 131 using AttributeStorageAllocator = StorageUniquer::StorageAllocator; 132 133 //===----------------------------------------------------------------------===// 134 // AttributeUniquer 135 //===----------------------------------------------------------------------===// 136 namespace detail { 137 // A utility class to get, or create, unique instances of attributes within an 138 // MLIRContext. This class manages all creation and uniquing of attributes. 139 class AttributeUniquer { 140 public: 141 /// Get an uniqued instance of a parametric attribute T. 142 template <typename T, typename... Args> 143 static typename std::enable_if_t< 144 !std::is_same<typename T::ImplType, AttributeStorage>::value, T> get(MLIRContext * ctx,Args &&...args)145 get(MLIRContext *ctx, Args &&...args) { 146 #ifndef NDEBUG 147 if (!ctx->getAttributeUniquer().isParametricStorageInitialized( 148 T::getTypeID())) 149 llvm::report_fatal_error(llvm::Twine("can't create Attribute '") + 150 llvm::getTypeName<T>() + 151 "' because storage uniquer isn't initialized: " 152 "the dialect was likely not loaded."); 153 #endif 154 return ctx->getAttributeUniquer().get<typename T::ImplType>( 155 [ctx](AttributeStorage *storage) { 156 initializeAttributeStorage(storage, ctx, T::getTypeID()); 157 }, 158 T::getTypeID(), std::forward<Args>(args)...); 159 } 160 /// Get an uniqued instance of a singleton attribute T. 161 template <typename T> 162 static typename std::enable_if_t< 163 std::is_same<typename T::ImplType, AttributeStorage>::value, T> get(MLIRContext * ctx)164 get(MLIRContext *ctx) { 165 #ifndef NDEBUG 166 if (!ctx->getAttributeUniquer().isSingletonStorageInitialized( 167 T::getTypeID())) 168 llvm::report_fatal_error(llvm::Twine("can't create Attribute '") + 169 llvm::getTypeName<T>() + 170 "' because storage uniquer isn't initialized: " 171 "the dialect was likely not loaded."); 172 #endif 173 return ctx->getAttributeUniquer().get<typename T::ImplType>(T::getTypeID()); 174 } 175 176 template <typename T, typename... Args> mutate(MLIRContext * ctx,typename T::ImplType * impl,Args &&...args)177 static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl, 178 Args &&...args) { 179 assert(impl && "cannot mutate null attribute"); 180 return ctx->getAttributeUniquer().mutate(T::getTypeID(), impl, 181 std::forward<Args>(args)...); 182 } 183 184 /// Register a parametric attribute instance T with the uniquer. 185 template <typename T> 186 static typename std::enable_if_t< 187 !std::is_same<typename T::ImplType, AttributeStorage>::value> registerAttribute(MLIRContext * ctx)188 registerAttribute(MLIRContext *ctx) { 189 ctx->getAttributeUniquer() 190 .registerParametricStorageType<typename T::ImplType>(T::getTypeID()); 191 } 192 /// Register a singleton attribute instance T with the uniquer. 193 template <typename T> 194 static typename std::enable_if_t< 195 std::is_same<typename T::ImplType, AttributeStorage>::value> registerAttribute(MLIRContext * ctx)196 registerAttribute(MLIRContext *ctx) { 197 ctx->getAttributeUniquer() 198 .registerSingletonStorageType<typename T::ImplType>( 199 T::getTypeID(), [ctx](AttributeStorage *storage) { 200 initializeAttributeStorage(storage, ctx, T::getTypeID()); 201 }); 202 } 203 204 private: 205 /// Initialize the given attribute storage instance. 206 static void initializeAttributeStorage(AttributeStorage *storage, 207 MLIRContext *ctx, TypeID attrID); 208 }; 209 } // namespace detail 210 211 } // end namespace mlir 212 213 #endif 214