• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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