File: | build/source/mlir/include/mlir/IR/AttributeSupport.h |
Warning: | line 45, column 5 Address of stack memory associated with temporary object of type '(lambda at /build/source/mlir/include/mlir/IR/StorageUniquerSupport.h:133:12)' is still referred to by a temporary object on the stack upon returning to the caller. This will be a dangling reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- Location.cpp - MLIR Location Classes -------------------------------===// | |||
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 | #include "mlir/IR/Location.h" | |||
10 | #include "mlir/IR/BuiltinDialect.h" | |||
11 | #include "mlir/IR/Visitors.h" | |||
12 | #include "llvm/ADT/SetVector.h" | |||
13 | #include "llvm/ADT/TypeSwitch.h" | |||
14 | ||||
15 | using namespace mlir; | |||
16 | using namespace mlir::detail; | |||
17 | ||||
18 | //===----------------------------------------------------------------------===// | |||
19 | /// Tablegen Attribute Definitions | |||
20 | //===----------------------------------------------------------------------===// | |||
21 | ||||
22 | #define GET_ATTRDEF_CLASSES | |||
23 | #include "mlir/IR/BuiltinLocationAttributes.cpp.inc" | |||
24 | ||||
25 | //===----------------------------------------------------------------------===// | |||
26 | // BuiltinDialect | |||
27 | //===----------------------------------------------------------------------===// | |||
28 | ||||
29 | void BuiltinDialect::registerLocationAttributes() { | |||
30 | addAttributes< | |||
| ||||
31 | #define GET_ATTRDEF_LIST | |||
32 | #include "mlir/IR/BuiltinLocationAttributes.cpp.inc" | |||
33 | >(); | |||
34 | } | |||
35 | ||||
36 | //===----------------------------------------------------------------------===// | |||
37 | // LocationAttr | |||
38 | //===----------------------------------------------------------------------===// | |||
39 | ||||
40 | WalkResult LocationAttr::walk(function_ref<WalkResult(Location)> walkFn) { | |||
41 | if (walkFn(*this).wasInterrupted()) | |||
42 | return WalkResult::interrupt(); | |||
43 | ||||
44 | return TypeSwitch<LocationAttr, WalkResult>(*this) | |||
45 | .Case([&](CallSiteLoc callLoc) -> WalkResult { | |||
46 | if (callLoc.getCallee()->walk(walkFn).wasInterrupted()) | |||
47 | return WalkResult::interrupt(); | |||
48 | return callLoc.getCaller()->walk(walkFn); | |||
49 | }) | |||
50 | .Case([&](FusedLoc fusedLoc) -> WalkResult { | |||
51 | for (Location subLoc : fusedLoc.getLocations()) | |||
52 | if (subLoc->walk(walkFn).wasInterrupted()) | |||
53 | return WalkResult::interrupt(); | |||
54 | return WalkResult::advance(); | |||
55 | }) | |||
56 | .Case([&](NameLoc nameLoc) -> WalkResult { | |||
57 | return nameLoc.getChildLoc()->walk(walkFn); | |||
58 | }) | |||
59 | .Case([&](OpaqueLoc opaqueLoc) -> WalkResult { | |||
60 | return opaqueLoc.getFallbackLocation()->walk(walkFn); | |||
61 | }) | |||
62 | .Default(WalkResult::advance()); | |||
63 | } | |||
64 | ||||
65 | /// Methods for support type inquiry through isa, cast, and dyn_cast. | |||
66 | bool LocationAttr::classof(Attribute attr) { | |||
67 | return attr.isa<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc, | |||
68 | UnknownLoc>(); | |||
69 | } | |||
70 | ||||
71 | //===----------------------------------------------------------------------===// | |||
72 | // CallSiteLoc | |||
73 | //===----------------------------------------------------------------------===// | |||
74 | ||||
75 | CallSiteLoc CallSiteLoc::get(Location name, ArrayRef<Location> frames) { | |||
76 | assert(!frames.empty() && "required at least 1 call frame")(static_cast <bool> (!frames.empty() && "required at least 1 call frame" ) ? void (0) : __assert_fail ("!frames.empty() && \"required at least 1 call frame\"" , "mlir/lib/IR/Location.cpp", 76, __extension__ __PRETTY_FUNCTION__ )); | |||
77 | Location caller = frames.back(); | |||
78 | for (auto frame : llvm::reverse(frames.drop_back())) | |||
79 | caller = CallSiteLoc::get(frame, caller); | |||
80 | return CallSiteLoc::get(name, caller); | |||
81 | } | |||
82 | ||||
83 | //===----------------------------------------------------------------------===// | |||
84 | // FusedLoc | |||
85 | //===----------------------------------------------------------------------===// | |||
86 | ||||
87 | Location FusedLoc::get(ArrayRef<Location> locs, Attribute metadata, | |||
88 | MLIRContext *context) { | |||
89 | // Unique the set of locations to be fused. | |||
90 | llvm::SmallSetVector<Location, 4> decomposedLocs; | |||
91 | for (auto loc : locs) { | |||
92 | // If the location is a fused location we decompose it if it has no | |||
93 | // metadata or the metadata is the same as the top level metadata. | |||
94 | if (auto fusedLoc = llvm::dyn_cast<FusedLoc>(loc)) { | |||
95 | if (fusedLoc.getMetadata() == metadata) { | |||
96 | // UnknownLoc's have already been removed from FusedLocs so we can | |||
97 | // simply add all of the internal locations. | |||
98 | decomposedLocs.insert(fusedLoc.getLocations().begin(), | |||
99 | fusedLoc.getLocations().end()); | |||
100 | continue; | |||
101 | } | |||
102 | } | |||
103 | // Otherwise, only add known locations to the set. | |||
104 | if (!loc.isa<UnknownLoc>()) | |||
105 | decomposedLocs.insert(loc); | |||
106 | } | |||
107 | locs = decomposedLocs.getArrayRef(); | |||
108 | ||||
109 | // Handle the simple cases of less than two locations. Ensure the metadata (if | |||
110 | // provided) is not dropped. | |||
111 | if (locs.empty()) { | |||
112 | if (!metadata) | |||
113 | return UnknownLoc::get(context); | |||
114 | // TODO: Investigate ASAN failure when using implicit conversion from | |||
115 | // Location to ArrayRef<Location> below. | |||
116 | return Base::get(context, ArrayRef<Location>{UnknownLoc::get(context)}, | |||
117 | metadata); | |||
118 | } | |||
119 | if (locs.size() == 1 && !metadata) | |||
120 | return locs.front(); | |||
121 | ||||
122 | return Base::get(context, locs, metadata); | |||
123 | } |
1 | //===- Dialect.h - IR Dialect Description -----------------------*- 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 the 'dialect' abstraction. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef MLIR_IR_DIALECT_H |
14 | #define MLIR_IR_DIALECT_H |
15 | |
16 | #include "mlir/IR/DialectRegistry.h" |
17 | #include "mlir/IR/OperationSupport.h" |
18 | #include "mlir/Support/TypeID.h" |
19 | |
20 | #include <map> |
21 | #include <tuple> |
22 | |
23 | namespace mlir { |
24 | class DialectAsmParser; |
25 | class DialectAsmPrinter; |
26 | class DialectInterface; |
27 | class OpBuilder; |
28 | class Type; |
29 | |
30 | //===----------------------------------------------------------------------===// |
31 | // Dialect |
32 | //===----------------------------------------------------------------------===// |
33 | |
34 | /// Dialects are groups of MLIR operations, types and attributes, as well as |
35 | /// behavior associated with the entire group. For example, hooks into other |
36 | /// systems for constant folding, interfaces, default named types for asm |
37 | /// printing, etc. |
38 | /// |
39 | /// Instances of the dialect object are loaded in a specific MLIRContext. |
40 | /// |
41 | class Dialect { |
42 | public: |
43 | /// Type for a callback provided by the dialect to parse a custom operation. |
44 | /// This is used for the dialect to provide an alternative way to parse custom |
45 | /// operations, including unregistered ones. |
46 | using ParseOpHook = |
47 | function_ref<ParseResult(OpAsmParser &parser, OperationState &result)>; |
48 | |
49 | virtual ~Dialect(); |
50 | |
51 | /// Utility function that returns if the given string is a valid dialect |
52 | /// namespace |
53 | static bool isValidNamespace(StringRef str); |
54 | |
55 | MLIRContext *getContext() const { return context; } |
56 | |
57 | StringRef getNamespace() const { return name; } |
58 | |
59 | /// Returns the unique identifier that corresponds to this dialect. |
60 | TypeID getTypeID() const { return dialectID; } |
61 | |
62 | /// Returns true if this dialect allows for unregistered operations, i.e. |
63 | /// operations prefixed with the dialect namespace but not registered with |
64 | /// addOperation. |
65 | bool allowsUnknownOperations() const { return unknownOpsAllowed; } |
66 | |
67 | /// Return true if this dialect allows for unregistered types, i.e., types |
68 | /// prefixed with the dialect namespace but not registered with addType. |
69 | /// These are represented with OpaqueType. |
70 | bool allowsUnknownTypes() const { return unknownTypesAllowed; } |
71 | |
72 | /// Register dialect-wide canonicalization patterns. This method should only |
73 | /// be used to register canonicalization patterns that do not conceptually |
74 | /// belong to any single operation in the dialect. (In that case, use the op's |
75 | /// canonicalizer.) E.g., canonicalization patterns for op interfaces should |
76 | /// be registered here. |
77 | virtual void getCanonicalizationPatterns(RewritePatternSet &results) const {} |
78 | |
79 | /// Registered hook to materialize a single constant operation from a given |
80 | /// attribute value with the desired resultant type. This method should use |
81 | /// the provided builder to create the operation without changing the |
82 | /// insertion position. The generated operation is expected to be constant |
83 | /// like, i.e. single result, zero operands, non side-effecting, etc. On |
84 | /// success, this hook should return the value generated to represent the |
85 | /// constant value. Otherwise, it should return null on failure. |
86 | virtual Operation *materializeConstant(OpBuilder &builder, Attribute value, |
87 | Type type, Location loc) { |
88 | return nullptr; |
89 | } |
90 | |
91 | //===--------------------------------------------------------------------===// |
92 | // Parsing Hooks |
93 | //===--------------------------------------------------------------------===// |
94 | |
95 | /// Parse an attribute registered to this dialect. If 'type' is nonnull, it |
96 | /// refers to the expected type of the attribute. |
97 | virtual Attribute parseAttribute(DialectAsmParser &parser, Type type) const; |
98 | |
99 | /// Print an attribute registered to this dialect. Note: The type of the |
100 | /// attribute need not be printed by this method as it is always printed by |
101 | /// the caller. |
102 | virtual void printAttribute(Attribute, DialectAsmPrinter &) const { |
103 | llvm_unreachable("dialect has no registered attribute printing hook")::llvm::llvm_unreachable_internal("dialect has no registered attribute printing hook" , "mlir/include/mlir/IR/Dialect.h", 103); |
104 | } |
105 | |
106 | /// Parse a type registered to this dialect. |
107 | virtual Type parseType(DialectAsmParser &parser) const; |
108 | |
109 | /// Print a type registered to this dialect. |
110 | virtual void printType(Type, DialectAsmPrinter &) const { |
111 | llvm_unreachable("dialect has no registered type printing hook")::llvm::llvm_unreachable_internal("dialect has no registered type printing hook" , "mlir/include/mlir/IR/Dialect.h", 111); |
112 | } |
113 | |
114 | /// Return the hook to parse an operation registered to this dialect, if any. |
115 | /// By default this will lookup for registered operations and return the |
116 | /// `parse()` method registered on the RegisteredOperationName. Dialects can |
117 | /// override this behavior and handle unregistered operations as well. |
118 | virtual std::optional<ParseOpHook> |
119 | getParseOperationHook(StringRef opName) const; |
120 | |
121 | /// Print an operation registered to this dialect. |
122 | /// This hook is invoked for registered operation which don't override the |
123 | /// `print()` method to define their own custom assembly. |
124 | virtual llvm::unique_function<void(Operation *, OpAsmPrinter &printer)> |
125 | getOperationPrinter(Operation *op) const; |
126 | |
127 | //===--------------------------------------------------------------------===// |
128 | // Verification Hooks |
129 | //===--------------------------------------------------------------------===// |
130 | |
131 | /// Verify an attribute from this dialect on the argument at 'argIndex' for |
132 | /// the region at 'regionIndex' on the given operation. Returns failure if |
133 | /// the verification failed, success otherwise. This hook may optionally be |
134 | /// invoked from any operation containing a region. |
135 | virtual LogicalResult verifyRegionArgAttribute(Operation *, |
136 | unsigned regionIndex, |
137 | unsigned argIndex, |
138 | NamedAttribute); |
139 | |
140 | /// Verify an attribute from this dialect on the result at 'resultIndex' for |
141 | /// the region at 'regionIndex' on the given operation. Returns failure if |
142 | /// the verification failed, success otherwise. This hook may optionally be |
143 | /// invoked from any operation containing a region. |
144 | virtual LogicalResult verifyRegionResultAttribute(Operation *, |
145 | unsigned regionIndex, |
146 | unsigned resultIndex, |
147 | NamedAttribute); |
148 | |
149 | /// Verify an attribute from this dialect on the given operation. Returns |
150 | /// failure if the verification failed, success otherwise. |
151 | virtual LogicalResult verifyOperationAttribute(Operation *, NamedAttribute) { |
152 | return success(); |
153 | } |
154 | |
155 | //===--------------------------------------------------------------------===// |
156 | // Interfaces |
157 | //===--------------------------------------------------------------------===// |
158 | |
159 | /// Lookup an interface for the given ID if one is registered, otherwise |
160 | /// nullptr. |
161 | DialectInterface *getRegisteredInterface(TypeID interfaceID) { |
162 | auto it = registeredInterfaces.find(interfaceID); |
163 | return it != registeredInterfaces.end() ? it->getSecond().get() : nullptr; |
164 | } |
165 | template <typename InterfaceT> |
166 | InterfaceT *getRegisteredInterface() { |
167 | return static_cast<InterfaceT *>( |
168 | getRegisteredInterface(InterfaceT::getInterfaceID())); |
169 | } |
170 | |
171 | /// Lookup an op interface for the given ID if one is registered, otherwise |
172 | /// nullptr. |
173 | virtual void *getRegisteredInterfaceForOp(TypeID interfaceID, |
174 | OperationName opName) { |
175 | return nullptr; |
176 | } |
177 | template <typename InterfaceT> |
178 | typename InterfaceT::Concept * |
179 | getRegisteredInterfaceForOp(OperationName opName) { |
180 | return static_cast<typename InterfaceT::Concept *>( |
181 | getRegisteredInterfaceForOp(InterfaceT::getInterfaceID(), opName)); |
182 | } |
183 | |
184 | /// Register a dialect interface with this dialect instance. |
185 | void addInterface(std::unique_ptr<DialectInterface> interface); |
186 | |
187 | /// Register a set of dialect interfaces with this dialect instance. |
188 | template <typename... Args> |
189 | void addInterfaces() { |
190 | (addInterface(std::make_unique<Args>(this)), ...); |
191 | } |
192 | template <typename InterfaceT, typename... Args> |
193 | InterfaceT &addInterface(Args &&...args) { |
194 | InterfaceT *interface = new InterfaceT(this, std::forward<Args>(args)...); |
195 | addInterface(std::unique_ptr<DialectInterface>(interface)); |
196 | return *interface; |
197 | } |
198 | |
199 | protected: |
200 | /// The constructor takes a unique namespace for this dialect as well as the |
201 | /// context to bind to. |
202 | /// Note: The namespace must not contain '.' characters. |
203 | /// Note: All operations belonging to this dialect must have names starting |
204 | /// with the namespace followed by '.'. |
205 | /// Example: |
206 | /// - "tf" for the TensorFlow ops like "tf.add". |
207 | Dialect(StringRef name, MLIRContext *context, TypeID id); |
208 | |
209 | /// This method is used by derived classes to add their operations to the set. |
210 | /// |
211 | template <typename... Args> |
212 | void addOperations() { |
213 | // This initializer_list argument pack expansion is essentially equal to |
214 | // using a fold expression with a comma operator. Clang however, refuses |
215 | // to compile a fold expression with a depth of more than 256 by default. |
216 | // There seem to be no such limitations for initializer_list. |
217 | (void)std::initializer_list<int>{ |
218 | 0, (RegisteredOperationName::insert<Args>(*this), 0)...}; |
219 | } |
220 | |
221 | /// Register a set of type classes with this dialect. |
222 | template <typename... Args> |
223 | void addTypes() { |
224 | (addType<Args>(), ...); |
225 | } |
226 | |
227 | /// Register a type instance with this dialect. |
228 | /// The use of this method is in general discouraged in favor of |
229 | /// 'addTypes<CustomType>()'. |
230 | void addType(TypeID typeID, AbstractType &&typeInfo); |
231 | |
232 | /// Register a set of attribute classes with this dialect. |
233 | template <typename... Args> |
234 | void addAttributes() { |
235 | (addAttribute<Args>(), ...); |
236 | } |
237 | |
238 | /// Register an attribute instance with this dialect. |
239 | /// The use of this method is in general discouraged in favor of |
240 | /// 'addAttributes<CustomAttr>()'. |
241 | void addAttribute(TypeID typeID, AbstractAttribute &&attrInfo); |
242 | |
243 | /// Enable support for unregistered operations. |
244 | void allowUnknownOperations(bool allow = true) { unknownOpsAllowed = allow; } |
245 | |
246 | /// Enable support for unregistered types. |
247 | void allowUnknownTypes(bool allow = true) { unknownTypesAllowed = allow; } |
248 | |
249 | private: |
250 | Dialect(const Dialect &) = delete; |
251 | void operator=(Dialect &) = delete; |
252 | |
253 | /// Register an attribute instance with this dialect. |
254 | template <typename T> |
255 | void addAttribute() { |
256 | // Add this attribute to the dialect and register it with the uniquer. |
257 | addAttribute(T::getTypeID(), AbstractAttribute::get<T>(*this)); |
258 | detail::AttributeUniquer::registerAttribute<T>(context); |
259 | } |
260 | |
261 | /// Register a type instance with this dialect. |
262 | template <typename T> |
263 | void addType() { |
264 | // Add this type to the dialect and register it with the uniquer. |
265 | addType(T::getTypeID(), AbstractType::get<T>(*this)); |
266 | detail::TypeUniquer::registerType<T>(context); |
267 | } |
268 | |
269 | /// The namespace of this dialect. |
270 | StringRef name; |
271 | |
272 | /// The unique identifier of the derived Op class, this is used in the context |
273 | /// to allow registering multiple times the same dialect. |
274 | TypeID dialectID; |
275 | |
276 | /// This is the context that owns this Dialect object. |
277 | MLIRContext *context; |
278 | |
279 | /// Flag that specifies whether this dialect supports unregistered operations, |
280 | /// i.e. operations prefixed with the dialect namespace but not registered |
281 | /// with addOperation. |
282 | bool unknownOpsAllowed = false; |
283 | |
284 | /// Flag that specifies whether this dialect allows unregistered types, i.e. |
285 | /// types prefixed with the dialect namespace but not registered with addType. |
286 | /// These types are represented with OpaqueType. |
287 | bool unknownTypesAllowed = false; |
288 | |
289 | /// A collection of registered dialect interfaces. |
290 | DenseMap<TypeID, std::unique_ptr<DialectInterface>> registeredInterfaces; |
291 | |
292 | friend class DialectRegistry; |
293 | friend void registerDialect(); |
294 | friend class MLIRContext; |
295 | }; |
296 | |
297 | } // namespace mlir |
298 | |
299 | namespace llvm { |
300 | /// Provide isa functionality for Dialects. |
301 | template <typename T> |
302 | struct isa_impl<T, ::mlir::Dialect, |
303 | std::enable_if_t<std::is_base_of<::mlir::Dialect, T>::value>> { |
304 | static inline bool doit(const ::mlir::Dialect &dialect) { |
305 | return mlir::TypeID::get<T>() == dialect.getTypeID(); |
306 | } |
307 | }; |
308 | template <typename T> |
309 | struct isa_impl< |
310 | T, ::mlir::Dialect, |
311 | std::enable_if_t<std::is_base_of<::mlir::DialectInterface, T>::value>> { |
312 | static inline bool doit(const ::mlir::Dialect &dialect) { |
313 | return const_cast<::mlir::Dialect &>(dialect).getRegisteredInterface<T>(); |
314 | } |
315 | }; |
316 | template <typename T> |
317 | struct cast_retty_impl<T, ::mlir::Dialect *> { |
318 | using ret_type = T *; |
319 | }; |
320 | template <typename T> |
321 | struct cast_retty_impl<T, ::mlir::Dialect> { |
322 | using ret_type = T &; |
323 | }; |
324 | |
325 | template <typename T> |
326 | struct cast_convert_val<T, ::mlir::Dialect, ::mlir::Dialect> { |
327 | template <typename To> |
328 | static std::enable_if_t<std::is_base_of<::mlir::Dialect, To>::value, To &> |
329 | doitImpl(::mlir::Dialect &dialect) { |
330 | return static_cast<To &>(dialect); |
331 | } |
332 | template <typename To> |
333 | static std::enable_if_t<std::is_base_of<::mlir::DialectInterface, To>::value, |
334 | To &> |
335 | doitImpl(::mlir::Dialect &dialect) { |
336 | return *dialect.getRegisteredInterface<To>(); |
337 | } |
338 | |
339 | static auto &doit(::mlir::Dialect &dialect) { return doitImpl<T>(dialect); } |
340 | }; |
341 | template <class T> |
342 | struct cast_convert_val<T, ::mlir::Dialect *, ::mlir::Dialect *> { |
343 | static auto doit(::mlir::Dialect *dialect) { |
344 | return &cast_convert_val<T, ::mlir::Dialect, ::mlir::Dialect>::doit( |
345 | *dialect); |
346 | } |
347 | }; |
348 | |
349 | } // namespace llvm |
350 | |
351 | #endif |
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 "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. | |||
29 | class AbstractAttribute { | |||
30 | public: | |||
31 | using HasTraitFn = llvm::unique_function<bool(TypeID) const>; | |||
32 | using WalkImmediateSubElementsFn = function_ref<void( | |||
33 | Attribute, function_ref<void(Attribute)>, function_ref<void(Type)>)>; | |||
34 | using ReplaceImmediateSubElementsFn = | |||
35 | function_ref<Attribute(Attribute, ArrayRef<Attribute>, ArrayRef<Type>)>; | |||
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, | |||
57 | HasTraitFn &&hasTrait, | |||
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. | |||
93 | void walkImmediateSubElements(Attribute attr, | |||
94 | function_ref<void(Attribute)> walkAttrsFn, | |||
95 | function_ref<void(Type)> walkTypesFn) const; | |||
96 | ||||
97 | /// Replace the immediate sub-elements of this attribute. | |||
98 | Attribute replaceImmediateSubElements(Attribute attr, | |||
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> | |||
120 | friend class detail::StorageUserBase; | |||
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 | } // namespace detail | |||
153 | ||||
154 | /// Base storage class appearing in an attribute. Derived storage classes should | |||
155 | /// only be constructed within the context of the AttributeUniquer. | |||
156 | class alignas(8) AttributeStorage : public StorageUniquer::BaseStorage { | |||
157 | friend detail::AttributeUniquer; | |||
158 | friend StorageUniquer; | |||
159 | ||||
160 | public: | |||
161 | /// Return the abstract descriptor for this attribute. | |||
162 | const AbstractAttribute &getAbstractAttribute() const { | |||
163 | assert(abstractAttribute && "Malformed attribute storage object.")(static_cast <bool> (abstractAttribute && "Malformed attribute storage object." ) ? void (0) : __assert_fail ("abstractAttribute && \"Malformed attribute storage object.\"" , "mlir/include/mlir/IR/AttributeSupport.h", 163, __extension__ __PRETTY_FUNCTION__)); | |||
164 | return *abstractAttribute; | |||
165 | } | |||
166 | ||||
167 | protected: | |||
168 | /// Set the abstract attribute for this storage instance. This is used by the | |||
169 | /// AttributeUniquer when initializing a newly constructed storage object. | |||
170 | void initializeAbstractAttribute(const AbstractAttribute &abstractAttr) { | |||
171 | abstractAttribute = &abstractAttr; | |||
172 | } | |||
173 | ||||
174 | /// Default initialization for attribute storage classes that require no | |||
175 | /// additional initialization. | |||
176 | void initialize(MLIRContext *context) {} | |||
177 | ||||
178 | private: | |||
179 | /// The abstract descriptor for this attribute. | |||
180 | const AbstractAttribute *abstractAttribute = nullptr; | |||
181 | }; | |||
182 | ||||
183 | /// Default storage type for attributes that require no additional | |||
184 | /// initialization or storage. | |||
185 | using DefaultAttributeStorage = AttributeStorage; | |||
186 | ||||
187 | //===----------------------------------------------------------------------===// | |||
188 | // AttributeStorageAllocator | |||
189 | //===----------------------------------------------------------------------===// | |||
190 | ||||
191 | // This is a utility allocator used to allocate memory for instances of derived | |||
192 | // Attributes. | |||
193 | using AttributeStorageAllocator = StorageUniquer::StorageAllocator; | |||
194 | ||||
195 | //===----------------------------------------------------------------------===// | |||
196 | // AttributeUniquer | |||
197 | //===----------------------------------------------------------------------===// | |||
198 | namespace detail { | |||
199 | // A utility class to get, or create, unique instances of attributes within an | |||
200 | // MLIRContext. This class manages all creation and uniquing of attributes. | |||
201 | class AttributeUniquer { | |||
202 | public: | |||
203 | /// Get an uniqued instance of an attribute T. | |||
204 | template <typename T, typename... Args> | |||
205 | static T get(MLIRContext *ctx, Args &&...args) { | |||
206 | return getWithTypeID<T, Args...>(ctx, T::getTypeID(), | |||
207 | std::forward<Args>(args)...); | |||
208 | } | |||
209 | ||||
210 | /// Get an uniqued instance of a parametric attribute T. | |||
211 | /// The use of this method is in general discouraged in favor of | |||
212 | /// 'get<T, Args>(ctx, args)'. | |||
213 | template <typename T, typename... Args> | |||
214 | static std::enable_if_t< | |||
215 | !std::is_same<typename T::ImplType, AttributeStorage>::value, T> | |||
216 | getWithTypeID(MLIRContext *ctx, TypeID typeID, Args &&...args) { | |||
217 | #ifndef NDEBUG | |||
218 | if (!ctx->getAttributeUniquer().isParametricStorageInitialized(typeID)) | |||
219 | llvm::report_fatal_error( | |||
220 | llvm::Twine("can't create Attribute '") + llvm::getTypeName<T>() + | |||
221 | "' because storage uniquer isn't initialized: the dialect was likely " | |||
222 | "not loaded, or the attribute wasn't added with addAttributes<...>() " | |||
223 | "in the Dialect::initialize() method."); | |||
224 | #endif | |||
225 | return ctx->getAttributeUniquer().get<typename T::ImplType>( | |||
226 | [typeID, ctx](AttributeStorage *storage) { | |||
227 | initializeAttributeStorage(storage, ctx, typeID); | |||
228 | ||||
229 | // Execute any additional attribute storage initialization with the | |||
230 | // context. | |||
231 | static_cast<typename T::ImplType *>(storage)->initialize(ctx); | |||
232 | }, | |||
233 | typeID, std::forward<Args>(args)...); | |||
234 | } | |||
235 | /// Get an uniqued instance of a singleton attribute T. | |||
236 | /// The use of this method is in general discouraged in favor of | |||
237 | /// 'get<T, Args>(ctx, args)'. | |||
238 | template <typename T> | |||
239 | static std::enable_if_t< | |||
240 | std::is_same<typename T::ImplType, AttributeStorage>::value, T> | |||
241 | getWithTypeID(MLIRContext *ctx, TypeID typeID) { | |||
242 | #ifndef NDEBUG | |||
243 | if (!ctx->getAttributeUniquer().isSingletonStorageInitialized(typeID)) | |||
244 | llvm::report_fatal_error( | |||
245 | llvm::Twine("can't create Attribute '") + llvm::getTypeName<T>() + | |||
246 | "' because storage uniquer isn't initialized: the dialect was likely " | |||
247 | "not loaded, or the attribute wasn't added with addAttributes<...>() " | |||
248 | "in the Dialect::initialize() method."); | |||
249 | #endif | |||
250 | return ctx->getAttributeUniquer().get<typename T::ImplType>(typeID); | |||
251 | } | |||
252 | ||||
253 | template <typename T, typename... Args> | |||
254 | static LogicalResult mutate(MLIRContext *ctx, typename T::ImplType *impl, | |||
255 | Args &&...args) { | |||
256 | assert(impl && "cannot mutate null attribute")(static_cast <bool> (impl && "cannot mutate null attribute" ) ? void (0) : __assert_fail ("impl && \"cannot mutate null attribute\"" , "mlir/include/mlir/IR/AttributeSupport.h", 256, __extension__ __PRETTY_FUNCTION__)); | |||
257 | return ctx->getAttributeUniquer().mutate(T::getTypeID(), impl, | |||
258 | std::forward<Args>(args)...); | |||
259 | } | |||
260 | ||||
261 | /// Register an attribute instance T with the uniquer. | |||
262 | template <typename T> | |||
263 | static void registerAttribute(MLIRContext *ctx) { | |||
264 | registerAttribute<T>(ctx, T::getTypeID()); | |||
265 | } | |||
266 | ||||
267 | /// Register a parametric attribute instance T with the uniquer. | |||
268 | /// The use of this method is in general discouraged in favor of | |||
269 | /// 'registerAttribute<T>(ctx)'. | |||
270 | template <typename T> | |||
271 | static std::enable_if_t< | |||
272 | !std::is_same<typename T::ImplType, AttributeStorage>::value> | |||
273 | registerAttribute(MLIRContext *ctx, TypeID typeID) { | |||
274 | ctx->getAttributeUniquer() | |||
275 | .registerParametricStorageType<typename T::ImplType>(typeID); | |||
276 | } | |||
277 | /// Register a singleton attribute instance T with the uniquer. | |||
278 | /// The use of this method is in general discouraged in favor of | |||
279 | /// 'registerAttribute<T>(ctx)'. | |||
280 | template <typename T> | |||
281 | static std::enable_if_t< | |||
282 | std::is_same<typename T::ImplType, AttributeStorage>::value> | |||
283 | registerAttribute(MLIRContext *ctx, TypeID typeID) { | |||
284 | ctx->getAttributeUniquer() | |||
285 | .registerSingletonStorageType<typename T::ImplType>( | |||
286 | typeID, [ctx, typeID](AttributeStorage *storage) { | |||
287 | initializeAttributeStorage(storage, ctx, typeID); | |||
288 | }); | |||
289 | } | |||
290 | ||||
291 | private: | |||
292 | /// Initialize the given attribute storage instance. | |||
293 | static void initializeAttributeStorage(AttributeStorage *storage, | |||
294 | MLIRContext *ctx, TypeID attrID); | |||
295 | }; | |||
296 | ||||
297 | // Internal function called by ODS generated code. | |||
298 | // Default initializes the type within a FailureOr<T> if T is default | |||
299 | // constructible and returns a reference to the instance. | |||
300 | // Otherwise, returns a reference to the FailureOr<T>. | |||
301 | template <class T> | |||
302 | decltype(auto) unwrapForCustomParse(FailureOr<T> &failureOr) { | |||
303 | if constexpr (std::is_default_constructible_v<T>) | |||
304 | return failureOr.emplace(); | |||
305 | else | |||
306 | return failureOr; | |||
307 | } | |||
308 | ||||
309 | } // namespace detail | |||
310 | ||||
311 | } // namespace mlir | |||
312 | ||||
313 | #endif |