Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Location.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/mlir/lib/IR -I /build/source/mlir/lib/IR -I include -I /build/source/llvm/include -I /build/source/mlir/include -I tools/mlir/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/mlir/lib/IR/Location.cpp

/build/source/mlir/lib/IR/Location.cpp

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
15using namespace mlir;
16using 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
29void BuiltinDialect::registerLocationAttributes() {
30 addAttributes<
1
Calling 'Dialect::addAttributes'
31#define GET_ATTRDEF_LIST
32#include "mlir/IR/BuiltinLocationAttributes.cpp.inc"
33 >();
34}
35
36//===----------------------------------------------------------------------===//
37// LocationAttr
38//===----------------------------------------------------------------------===//
39
40WalkResult 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.
66bool LocationAttr::classof(Attribute attr) {
67 return attr.isa<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
68 UnknownLoc>();
69}
70
71//===----------------------------------------------------------------------===//
72// CallSiteLoc
73//===----------------------------------------------------------------------===//
74
75CallSiteLoc 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
87Location 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}

/build/source/mlir/include/mlir/IR/Dialect.h

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
23namespace mlir {
24class DialectAsmParser;
25class DialectAsmPrinter;
26class DialectInterface;
27class OpBuilder;
28class 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///
41class Dialect {
42public:
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
199protected:
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>(), ...);
2
Calling 'Dialect::addAttribute'
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
249private:
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));
3
Calling 'AbstractAttribute::get'
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
299namespace llvm {
300/// Provide isa functionality for Dialects.
301template <typename T>
302struct 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};
308template <typename T>
309struct 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};
316template <typename T>
317struct cast_retty_impl<T, ::mlir::Dialect *> {
318 using ret_type = T *;
319};
320template <typename T>
321struct cast_retty_impl<T, ::mlir::Dialect> {
322 using ret_type = T &;
323};
324
325template <typename T>
326struct 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};
341template <class T>
342struct 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

/build/source/mlir/include/mlir/IR/AttributeSupport.h

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
22namespace mlir {
23//===----------------------------------------------------------------------===//
24// AbstractAttribute
25//===----------------------------------------------------------------------===//
26
27/// This class contains all of the static information common to all instances of
28/// a registered Attribute.
29class AbstractAttribute {
30public:
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(),
4
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
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
105private:
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
150namespace detail {
151class 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.
156class alignas(8) AttributeStorage : public StorageUniquer::BaseStorage {
157 friend detail::AttributeUniquer;
158 friend StorageUniquer;
159
160public:
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
167protected:
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
178private:
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.
185using DefaultAttributeStorage = AttributeStorage;
186
187//===----------------------------------------------------------------------===//
188// AttributeStorageAllocator
189//===----------------------------------------------------------------------===//
190
191// This is a utility allocator used to allocate memory for instances of derived
192// Attributes.
193using AttributeStorageAllocator = StorageUniquer::StorageAllocator;
194
195//===----------------------------------------------------------------------===//
196// AttributeUniquer
197//===----------------------------------------------------------------------===//
198namespace 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.
201class AttributeUniquer {
202public:
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
291private:
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>.
301template <class T>
302decltype(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