MLIR  18.0.0git
AttributeSupport.h
Go to the documentation of this file.
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"
18 #include "mlir/IR/Types.h"
19 #include "llvm/ADT/PointerIntPair.h"
20 #include "llvm/ADT/Twine.h"
21 
22 namespace mlir {
23 //===----------------------------------------------------------------------===//
24 // AbstractAttribute
25 //===----------------------------------------------------------------------===//
26 
27 /// This class contains all of the static information common to all instances of
28 /// a registered Attribute.
30 public:
31  using HasTraitFn = llvm::unique_function<bool(TypeID) const>;
36 
37  /// Look up the specified abstract attribute in the MLIRContext and return a
38  /// reference to it.
39  static const AbstractAttribute &lookup(TypeID typeID, MLIRContext *context);
40 
41  /// This method is used by Dialect objects when they register the list of
42  /// attributes they contain.
43  template <typename T>
44  static AbstractAttribute get(Dialect &dialect) {
45  return AbstractAttribute(dialect, T::getInterfaceMap(), T::getHasTraitFn(),
46  T::getWalkImmediateSubElementsFn(),
47  T::getReplaceImmediateSubElementsFn(),
48  T::getTypeID());
49  }
50 
51  /// This method is used by Dialect objects to register attributes with
52  /// custom TypeIDs.
53  /// The use of this method is in general discouraged in favor of
54  /// 'get<CustomAttribute>(dialect)'.
55  static AbstractAttribute
56  get(Dialect &dialect, detail::InterfaceMap &&interfaceMap,
58  WalkImmediateSubElementsFn walkImmediateSubElementsFn,
59  ReplaceImmediateSubElementsFn replaceImmediateSubElementsFn,
60  TypeID typeID) {
61  return AbstractAttribute(dialect, std::move(interfaceMap),
62  std::move(hasTrait), walkImmediateSubElementsFn,
63  replaceImmediateSubElementsFn, typeID);
64  }
65 
66  /// Return the dialect this attribute was registered to.
67  Dialect &getDialect() const { return const_cast<Dialect &>(dialect); }
68 
69  /// Returns an instance of the concept object for the given interface if it
70  /// was registered to this attribute, null otherwise. This should not be used
71  /// directly.
72  template <typename T>
73  typename T::Concept *getInterface() const {
74  return interfaceMap.lookup<T>();
75  }
76 
77  /// Returns true if the attribute has the interface with the given ID
78  /// registered.
79  bool hasInterface(TypeID interfaceID) const {
80  return interfaceMap.contains(interfaceID);
81  }
82 
83  /// Returns true if the attribute has a particular trait.
84  template <template <typename T> class Trait>
85  bool hasTrait() const {
86  return hasTraitFn(TypeID::get<Trait>());
87  }
88 
89  /// Returns true if the attribute has a particular trait.
90  bool hasTrait(TypeID traitID) const { return hasTraitFn(traitID); }
91 
92  /// Walk the immediate sub-elements of this attribute.
94  function_ref<void(Attribute)> walkAttrsFn,
95  function_ref<void(Type)> walkTypesFn) const;
96 
97  /// Replace the immediate sub-elements of this attribute.
99  ArrayRef<Attribute> replAttrs,
100  ArrayRef<Type> replTypes) const;
101 
102  /// Return the unique identifier representing the concrete attribute class.
103  TypeID getTypeID() const { return typeID; }
104 
105 private:
106  AbstractAttribute(Dialect &dialect, detail::InterfaceMap &&interfaceMap,
107  HasTraitFn &&hasTraitFn,
108  WalkImmediateSubElementsFn walkImmediateSubElementsFn,
109  ReplaceImmediateSubElementsFn replaceImmediateSubElementsFn,
110  TypeID typeID)
111  : dialect(dialect), interfaceMap(std::move(interfaceMap)),
112  hasTraitFn(std::move(hasTraitFn)),
113  walkImmediateSubElementsFn(walkImmediateSubElementsFn),
114  replaceImmediateSubElementsFn(replaceImmediateSubElementsFn),
115  typeID(typeID) {}
116 
117  /// Give StorageUserBase access to the mutable lookup.
118  template <typename ConcreteT, typename BaseT, typename StorageT,
119  typename UniquerT, template <typename T> class... Traits>
121 
122  /// Look up the specified abstract attribute in the MLIRContext and return a
123  /// (mutable) pointer to it. Return a null pointer if the attribute could not
124  /// be found in the context.
125  static AbstractAttribute *lookupMutable(TypeID typeID, MLIRContext *context);
126 
127  /// This is the dialect that this attribute was registered to.
128  const Dialect &dialect;
129 
130  /// This is a collection of the interfaces registered to this attribute.
131  detail::InterfaceMap interfaceMap;
132 
133  /// Function to check if the attribute has a particular trait.
134  HasTraitFn hasTraitFn;
135 
136  /// Function to walk the immediate sub-elements of this attribute.
137  WalkImmediateSubElementsFn walkImmediateSubElementsFn;
138 
139  /// Function to replace the immediate sub-elements of this attribute.
140  ReplaceImmediateSubElementsFn replaceImmediateSubElementsFn;
141 
142  /// The unique identifier of the derived Attribute class.
143  const TypeID typeID;
144 };
145 
146 //===----------------------------------------------------------------------===//
147 // AttributeStorage
148 //===----------------------------------------------------------------------===//
149 
150 namespace detail {
151 class AttributeUniquer;
152 class DistinctAttributeUniquer;
153 } // namespace detail
154 
155 /// Base storage class appearing in an attribute. Derived storage classes should
156 /// only be constructed within the context of the AttributeUniquer.
160  friend StorageUniquer;
161 
162 public:
163  /// Return the abstract descriptor for this attribute.
165  assert(abstractAttribute && "Malformed attribute storage object.");
166  return *abstractAttribute;
167  }
168 
169 protected:
170  /// Set the abstract attribute for this storage instance. This is used by the
171  /// AttributeUniquer when initializing a newly constructed storage object.
172  void initializeAbstractAttribute(const AbstractAttribute &abstractAttr) {
173  abstractAttribute = &abstractAttr;
174  }
175 
176  /// Default initialization for attribute storage classes that require no
177  /// additional initialization.
178  void initialize(MLIRContext *context) {}
179 
180 private:
181  /// The abstract descriptor for this attribute.
182  const AbstractAttribute *abstractAttribute = nullptr;
183 };
184 
185 /// Default storage type for attributes that require no additional
186 /// initialization or storage.
188 
189 //===----------------------------------------------------------------------===//
190 // AttributeStorageAllocator
191 //===----------------------------------------------------------------------===//
192 
193 // This is a utility allocator used to allocate memory for instances of derived
194 // Attributes.
196 
197 //===----------------------------------------------------------------------===//
198 // AttributeUniquer
199 //===----------------------------------------------------------------------===//
200 namespace detail {
201 // A utility class to get, or create, unique instances of attributes within an
202 // MLIRContext. This class manages all creation and uniquing of attributes.
204 public:
205  /// Get an uniqued instance of an attribute T.
206  template <typename T, typename... Args>
207  static T get(MLIRContext *ctx, Args &&...args) {
208  return getWithTypeID<T, Args...>(ctx, T::getTypeID(),
209  std::forward<Args>(args)...);
210  }
211 
212  /// Get an uniqued instance of a parametric attribute T.
213  /// The use of this method is in general discouraged in favor of
214  /// 'get<T, Args>(ctx, args)'.
215  template <typename T, typename... Args>
216  static std::enable_if_t<
217  !std::is_same<typename T::ImplType, AttributeStorage>::value, T>
218  getWithTypeID(MLIRContext *ctx, TypeID typeID, Args &&...args) {
219 #ifndef NDEBUG
221  llvm::report_fatal_error(
222  llvm::Twine("can't create Attribute '") + llvm::getTypeName<T>() +
223  "' because storage uniquer isn't initialized: the dialect was likely "
224  "not loaded, or the attribute wasn't added with addAttributes<...>() "
225  "in the Dialect::initialize() method.");
226 #endif
227  return ctx->getAttributeUniquer().get<typename T::ImplType>(
228  [typeID, ctx](AttributeStorage *storage) {
229  initializeAttributeStorage(storage, ctx, typeID);
230 
231  // Execute any additional attribute storage initialization with the
232  // context.
233  static_cast<typename T::ImplType *>(storage)->initialize(ctx);
234  },
235  typeID, std::forward<Args>(args)...);
236  }
237  /// Get an uniqued instance of a singleton attribute T.
238  /// The use of this method is in general discouraged in favor of
239  /// 'get<T, Args>(ctx, args)'.
240  template <typename T>
241  static std::enable_if_t<
242  std::is_same<typename T::ImplType, AttributeStorage>::value, T>
244 #ifndef NDEBUG
246  llvm::report_fatal_error(
247  llvm::Twine("can't create Attribute '") + llvm::getTypeName<T>() +
248  "' because storage uniquer isn't initialized: the dialect was likely "
249  "not loaded, or the attribute wasn't added with addAttributes<...>() "
250  "in the Dialect::initialize() method.");
251 #endif
252  return ctx->getAttributeUniquer().get<typename T::ImplType>(typeID);
253  }
254 
255  template <typename T, typename... Args>
256  static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl,
257  Args &&...args) {
258  assert(impl && "cannot mutate null attribute");
259  return ctx->getAttributeUniquer().mutate(T::getTypeID(), impl,
260  std::forward<Args>(args)...);
261  }
262 
263  /// Register an attribute instance T with the uniquer.
264  template <typename T>
265  static void registerAttribute(MLIRContext *ctx) {
266  registerAttribute<T>(ctx, T::getTypeID());
267  }
268 
269  /// Register a parametric attribute instance T with the uniquer.
270  /// The use of this method is in general discouraged in favor of
271  /// 'registerAttribute<T>(ctx)'.
272  template <typename T>
273  static std::enable_if_t<
274  !std::is_same<typename T::ImplType, AttributeStorage>::value>
276  ctx->getAttributeUniquer()
277  .registerParametricStorageType<typename T::ImplType>(typeID);
278  }
279  /// Register a singleton attribute instance T with the uniquer.
280  /// The use of this method is in general discouraged in favor of
281  /// 'registerAttribute<T>(ctx)'.
282  template <typename T>
283  static std::enable_if_t<
284  std::is_same<typename T::ImplType, AttributeStorage>::value>
286  ctx->getAttributeUniquer()
287  .registerSingletonStorageType<typename T::ImplType>(
288  typeID, [ctx, typeID](AttributeStorage *storage) {
289  initializeAttributeStorage(storage, ctx, typeID);
290  });
291  }
292 
293 private:
294  /// Initialize the given attribute storage instance.
295  static void initializeAttributeStorage(AttributeStorage *storage,
296  MLIRContext *ctx, TypeID attrID);
297 };
298 
299 // Internal function called by ODS generated code.
300 // Default initializes the type within a FailureOr<T> if T is default
301 // constructible and returns a reference to the instance.
302 // Otherwise, returns a reference to the FailureOr<T>.
303 template <class T>
304 decltype(auto) unwrapForCustomParse(FailureOr<T> &failureOr) {
305  if constexpr (std::is_default_constructible_v<T>)
306  return failureOr.emplace();
307  else
308  return failureOr;
309 }
310 
311 } // namespace detail
312 
313 } // namespace mlir
314 
315 #endif
This class contains all of the static information common to all instances of a registered Attribute.
function_ref< Attribute(Attribute, ArrayRef< Attribute >, ArrayRef< Type >)> ReplaceImmediateSubElementsFn
static AbstractAttribute get(Dialect &dialect, detail::InterfaceMap &&interfaceMap, HasTraitFn &&hasTrait, WalkImmediateSubElementsFn walkImmediateSubElementsFn, ReplaceImmediateSubElementsFn replaceImmediateSubElementsFn, TypeID typeID)
This method is used by Dialect objects to register attributes with custom TypeIDs.
llvm::unique_function< bool(TypeID) const > HasTraitFn
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this attrib...
static AbstractAttribute get(Dialect &dialect)
This method is used by Dialect objects when they register the list of attributes they contain.
static const AbstractAttribute & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract attribute in the MLIRContext and return a reference to it.
TypeID getTypeID() const
Return the unique identifier representing the concrete attribute class.
bool hasTrait() const
Returns true if the attribute has a particular trait.
void walkImmediateSubElements(Attribute attr, function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk the immediate sub-elements of this attribute.
Definition: Attributes.cpp:19
bool hasTrait(TypeID traitID) const
Returns true if the attribute has a particular trait.
Attribute replaceImmediateSubElements(Attribute attr, ArrayRef< Attribute > replAttrs, ArrayRef< Type > replTypes) const
Replace the immediate sub-elements of this attribute.
Definition: Attributes.cpp:26
function_ref< void(Attribute, function_ref< void(Attribute)>, function_ref< void(Type)>)> WalkImmediateSubElementsFn
Dialect & getDialect() const
Return the dialect this attribute was registered to.
bool hasInterface(TypeID interfaceID) const
Returns true if the attribute has the interface with the given ID registered.
Base storage class appearing in an attribute.
void initializeAbstractAttribute(const AbstractAttribute &abstractAttr)
Set the abstract attribute for this storage instance.
const AbstractAttribute & getAbstractAttribute() const
Return the abstract descriptor for this attribute.
void initialize(MLIRContext *context)
Default initialization for attribute storage classes that require no additional initialization.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
StorageUniquer & getAttributeUniquer()
Returns the storage uniquer used for constructing attribute storage instances.
This class acts as the base storage that all storage classes must derived from.
This is a utility allocator used to allocate memory for instances of derived types.
A utility class to get or create instances of "storage classes".
LogicalResult mutate(TypeID id, Storage *storage, Args &&...args)
Changes the mutable component of 'storage' by forwarding the trailing arguments to the 'mutate' funct...
void registerSingletonStorageType(TypeID id, function_ref< void(Storage *)> initFn)
Register a new singleton storage class, this is necessary to get the singletone instance.
bool isSingletonStorageInitialized(TypeID id)
Test if there is a singleton storage uniquer initialized for the provided TypeID.
Storage * get(function_ref< void(Storage *)> initFn, TypeID id, Args &&...args)
Gets a uniqued instance of 'Storage'.
bool isParametricStorageInitialized(TypeID id)
Test if there is a parametric storage uniquer initialized for the provided TypeID.
void registerParametricStorageType(TypeID id)
Register a new parametric storage class, this is necessary to create instances of this class type.
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
static std::enable_if_t< !std::is_same< typename T::ImplType, AttributeStorage >::value, T > getWithTypeID(MLIRContext *ctx, TypeID typeID, Args &&...args)
Get an uniqued instance of a parametric attribute T.
static std::enable_if_t< std::is_same< typename T::ImplType, AttributeStorage >::value > registerAttribute(MLIRContext *ctx, TypeID typeID)
Register a singleton attribute instance T with the uniquer.
static void registerAttribute(MLIRContext *ctx)
Register an attribute instance T with the uniquer.
static std::enable_if_t< std::is_same< typename T::ImplType, AttributeStorage >::value, T > getWithTypeID(MLIRContext *ctx, TypeID typeID)
Get an uniqued instance of a singleton attribute T.
static T get(MLIRContext *ctx, Args &&...args)
Get an uniqued instance of an attribute T.
static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl, Args &&...args)
static std::enable_if_t< !std::is_same< typename T::ImplType, AttributeStorage >::value > registerAttribute(MLIRContext *ctx, TypeID typeID)
Register a parametric attribute instance T with the uniquer.
A specialized attribute uniquer for distinct attributes that always allocates since the distinct attr...
This class provides an efficient mapping between a given Interface type, and a particular implementat...
bool contains(TypeID interfaceID) const
Returns true if the interface map contains an interface for the given id.
T::Concept * lookup() const
Returns an instance of the concept object for the given interface if it was registered to this map,...
Utility class for implementing users of storage classes uniqued by a StorageUniquer.
decltype(auto) unwrapForCustomParse(FailureOr< T > &failureOr)
This header declares functions that assist transformations in the MemRef dialect.
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26