Bug Summary

File:build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/include/mlir/IR/Attributes.h
Warning:line 74, column 12
Called C++ object pointer is null

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 IRNumbering.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/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.0.0 -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/mlir/lib/Bytecode/Writer -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/lib/Bytecode/Writer -I include -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/llvm/include -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/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-16/lib/clang/16.0.0/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/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -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/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -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-2022-09-04-125545-48738-1 -x c++ /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/lib/Bytecode/Writer/IRNumbering.cpp

/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/lib/Bytecode/Writer/IRNumbering.cpp

1//===- IRNumbering.cpp - MLIR Bytecode IR numbering -----------------------===//
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 "IRNumbering.h"
10#include "mlir/Bytecode/BytecodeImplementation.h"
11#include "mlir/Bytecode/BytecodeWriter.h"
12#include "mlir/IR/BuiltinTypes.h"
13#include "mlir/IR/OpDefinition.h"
14
15using namespace mlir;
16using namespace mlir::bytecode::detail;
17
18//===----------------------------------------------------------------------===//
19// NumberingDialectWriter
20//===----------------------------------------------------------------------===//
21
22struct IRNumberingState::NumberingDialectWriter : public DialectBytecodeWriter {
23 NumberingDialectWriter(IRNumberingState &state) : state(state) {}
24
25 void writeAttribute(Attribute attr) override { state.number(attr); }
26 void writeType(Type type) override { state.number(type); }
27
28 /// Stubbed out methods that are not used for numbering.
29 void writeVarInt(uint64_t) override {}
30 void writeSignedVarInt(int64_t value) override {}
31 void writeAPIntWithKnownWidth(const APInt &value) override {}
32 void writeAPFloatWithKnownSemantics(const APFloat &value) override {}
33 void writeOwnedString(StringRef) override {
34 // TODO: It might be nice to prenumber strings and sort by the number of
35 // references. This could potentially be useful for optimizing things like
36 // file locations.
37 }
38
39 /// The parent numbering state that is populated by this writer.
40 IRNumberingState &state;
41};
42
43//===----------------------------------------------------------------------===//
44// IR Numbering
45//===----------------------------------------------------------------------===//
46
47/// Group and sort the elements of the given range by their parent dialect. This
48/// grouping is applied to sub-sections of the ranged defined by how many bytes
49/// it takes to encode a varint index to that sub-section.
50template <typename T>
51static void groupByDialectPerByte(T range) {
52 if (range.empty())
53 return;
54
55 // A functor used to sort by a given dialect, with a desired dialect to be
56 // ordered first (to better enable sharing of dialects across byte groups).
57 auto sortByDialect = [](unsigned dialectToOrderFirst, const auto &lhs,
58 const auto &rhs) {
59 if (lhs->dialect->number == dialectToOrderFirst)
60 return rhs->dialect->number != dialectToOrderFirst;
61 return lhs->dialect->number < rhs->dialect->number;
62 };
63
64 unsigned dialectToOrderFirst = 0;
65 size_t elementsInByteGroup = 0;
66 auto iterRange = range;
67 for (unsigned i = 1; i < 9; ++i) {
68 // Update the number of elements in the current byte grouping. Reminder
69 // that varint encodes 7-bits per byte, so that's how we compute the
70 // number of elements in each byte grouping.
71 elementsInByteGroup = (1ULL << (7ULL * i)) - elementsInByteGroup;
72
73 // Slice out the sub-set of elements that are in the current byte grouping
74 // to be sorted.
75 auto byteSubRange = iterRange.take_front(elementsInByteGroup);
76 iterRange = iterRange.drop_front(byteSubRange.size());
77
78 // Sort the sub range for this byte.
79 llvm::stable_sort(byteSubRange, [&](const auto &lhs, const auto &rhs) {
80 return sortByDialect(dialectToOrderFirst, lhs, rhs);
81 });
82
83 // Update the dialect to order first to be the dialect at the end of the
84 // current grouping. This seeks to allow larger dialect groupings across
85 // byte boundaries.
86 dialectToOrderFirst = byteSubRange.back()->dialect->number;
87
88 // If the data range is now empty, we are done.
89 if (iterRange.empty())
90 break;
91 }
92
93 // Assign the entry numbers based on the sort order.
94 for (auto &entry : llvm::enumerate(range))
95 entry.value()->number = entry.index();
96}
97
98IRNumberingState::IRNumberingState(Operation *op) {
99 // Number the root operation.
100 number(*op);
101
102 // Push all of the regions of the root operation onto the worklist.
103 SmallVector<std::pair<Region *, unsigned>, 8> numberContext;
104 for (Region &region : op->getRegions())
1
Assuming '__begin1' is equal to '__end1'
105 numberContext.emplace_back(&region, nextValueID);
106
107 // Iteratively process each of the nested regions.
108 while (!numberContext.empty()) {
2
Loop condition is true. Entering loop body
109 Region *region;
110 std::tie(region, nextValueID) = numberContext.pop_back_val();
111 number(*region);
3
Calling 'IRNumberingState::number'
112
113 // Traverse into nested regions.
114 for (Operation &op : region->getOps()) {
115 // Isolated regions don't share value numbers with their parent, so we can
116 // start numbering these regions at zero.
117 unsigned opFirstValueID =
118 op.hasTrait<OpTrait::IsIsolatedFromAbove>() ? 0 : nextValueID;
119 for (Region &region : op.getRegions())
120 numberContext.emplace_back(&region, opFirstValueID);
121 }
122 }
123
124 // Number each of the dialects. For now this is just in the order they were
125 // found, given that the number of dialects on average is small enough to fit
126 // within a singly byte (128). If we ever have real world use cases that have
127 // a huge number of dialects, this could be made more intelligent.
128 for (auto &it : llvm::enumerate(dialects))
129 it.value().second->number = it.index();
130
131 // Number each of the recorded components within each dialect.
132
133 // First sort by ref count so that the most referenced elements are first. We
134 // try to bias more heavily used elements to the front. This allows for more
135 // frequently referenced things to be encoded using smaller varints.
136 auto sortByRefCountFn = [](const auto &lhs, const auto &rhs) {
137 return lhs->refCount > rhs->refCount;
138 };
139 llvm::stable_sort(orderedAttrs, sortByRefCountFn);
140 llvm::stable_sort(orderedOpNames, sortByRefCountFn);
141 llvm::stable_sort(orderedTypes, sortByRefCountFn);
142
143 // After that, we apply a secondary ordering based on the parent dialect. This
144 // ordering is applied to sub-sections of the element list defined by how many
145 // bytes it takes to encode a varint index to that sub-section. This allows
146 // for more efficiently encoding components of the same dialect (e.g. we only
147 // have to encode the dialect reference once).
148 groupByDialectPerByte(llvm::makeMutableArrayRef(orderedAttrs));
149 groupByDialectPerByte(llvm::makeMutableArrayRef(orderedOpNames));
150 groupByDialectPerByte(llvm::makeMutableArrayRef(orderedTypes));
151}
152
153void IRNumberingState::number(Attribute attr) {
154 auto it = attrs.insert({attr, nullptr});
155 if (!it.second) {
10
Assuming field 'second' is true
11
Taking false branch
156 ++it.first->second->refCount;
157 return;
158 }
159 auto *numbering = new (attrAllocator.Allocate()) AttributeNumbering(attr);
160 it.first->second = numbering;
161 orderedAttrs.push_back(numbering);
162
163 // Check for OpaqueAttr, which is a dialect-specific attribute that didn't
164 // have a registered dialect when it got created. We don't want to encode this
165 // as the builtin OpaqueAttr, we want to encode it as if the dialect was
166 // actually loaded.
167 if (OpaqueAttr opaqueAttr = attr.dyn_cast<OpaqueAttr>()) {
12
Assuming pointer value is null
13
Taking false branch
168 numbering->dialect = &numberDialect(opaqueAttr.getDialectNamespace());
169 return;
170 }
171 numbering->dialect = &numberDialect(&attr.getDialect());
14
Calling 'Attribute::getDialect'
172
173 // If this attribute will be emitted using the bytecode format, perform a
174 // dummy writing to number any nested components.
175 if (const auto *interface = numbering->dialect->interface) {
176 // TODO: We don't allow custom encodings for mutable attributes right now.
177 if (attr.hasTrait<AttributeTrait::IsMutable>())
178 return;
179
180 NumberingDialectWriter writer(*this);
181 (void)interface->writeAttribute(attr, writer);
182 }
183}
184
185void IRNumberingState::number(Block &block) {
186 // Number the arguments of the block.
187 for (BlockArgument arg : block.getArguments()) {
7
Assuming '__begin1' is not equal to '__end1'
188 valueIDs.try_emplace(arg, nextValueID++);
189 number(arg.getLoc());
8
Value assigned to 'attr.impl'
9
Calling 'IRNumberingState::number'
190 number(arg.getType());
191 }
192
193 // Number the operations in this block.
194 unsigned &numOps = blockOperationCounts[&block];
195 for (Operation &op : block) {
196 number(op);
197 ++numOps;
198 }
199}
200
201auto IRNumberingState::numberDialect(Dialect *dialect) -> DialectNumbering & {
202 DialectNumbering *&numbering = registeredDialects[dialect];
203 if (!numbering) {
204 numbering = &numberDialect(dialect->getNamespace());
205 numbering->interface = dyn_cast<BytecodeDialectInterface>(dialect);
206 }
207 return *numbering;
208}
209
210auto IRNumberingState::numberDialect(StringRef dialect) -> DialectNumbering & {
211 DialectNumbering *&numbering = dialects[dialect];
212 if (!numbering) {
213 numbering = new (dialectAllocator.Allocate())
214 DialectNumbering(dialect, dialects.size() - 1);
215 }
216 return *numbering;
217}
218
219void IRNumberingState::number(Region &region) {
220 if (region.empty())
4
Assuming the condition is false
5
Taking false branch
221 return;
222 size_t firstValueID = nextValueID;
223
224 // Number the blocks within this region.
225 size_t blockCount = 0;
226 for (auto &it : llvm::enumerate(region)) {
227 blockIDs.try_emplace(&it.value(), it.index());
228 number(it.value());
6
Calling 'IRNumberingState::number'
229 ++blockCount;
230 }
231
232 // Remember the number of blocks and values in this region.
233 regionBlockValueCounts.try_emplace(&region, blockCount,
234 nextValueID - firstValueID);
235}
236
237void IRNumberingState::number(Operation &op) {
238 // Number the components of an operation that won't be numbered elsewhere
239 // (e.g. we don't number operands, regions, or successors here).
240 number(op.getName());
241 for (OpResult result : op.getResults()) {
242 valueIDs.try_emplace(result, nextValueID++);
243 number(result.getType());
244 }
245
246 // Only number the operation's dictionary if it isn't empty.
247 DictionaryAttr dictAttr = op.getAttrDictionary();
248 if (!dictAttr.empty())
249 number(dictAttr);
250
251 number(op.getLoc());
252}
253
254void IRNumberingState::number(OperationName opName) {
255 OpNameNumbering *&numbering = opNames[opName];
256 if (numbering) {
257 ++numbering->refCount;
258 return;
259 }
260 DialectNumbering *dialectNumber = nullptr;
261 if (Dialect *dialect = opName.getDialect())
262 dialectNumber = &numberDialect(dialect);
263 else
264 dialectNumber = &numberDialect(opName.getDialectNamespace());
265
266 numbering =
267 new (opNameAllocator.Allocate()) OpNameNumbering(dialectNumber, opName);
268 orderedOpNames.push_back(numbering);
269}
270
271void IRNumberingState::number(Type type) {
272 auto it = types.insert({type, nullptr});
273 if (!it.second) {
274 ++it.first->second->refCount;
275 return;
276 }
277 auto *numbering = new (typeAllocator.Allocate()) TypeNumbering(type);
278 it.first->second = numbering;
279 orderedTypes.push_back(numbering);
280
281 // Check for OpaqueType, which is a dialect-specific type that didn't have a
282 // registered dialect when it got created. We don't want to encode this as the
283 // builtin OpaqueType, we want to encode it as if the dialect was actually
284 // loaded.
285 if (OpaqueType opaqueType = type.dyn_cast<OpaqueType>()) {
286 numbering->dialect = &numberDialect(opaqueType.getDialectNamespace());
287 return;
288 }
289 numbering->dialect = &numberDialect(&type.getDialect());
290
291 // If this type will be emitted using the bytecode format, perform a dummy
292 // writing to number any nested components.
293 if (const auto *interface = numbering->dialect->interface) {
294 // TODO: We don't allow custom encodings for mutable types right now.
295 if (type.hasTrait<TypeTrait::IsMutable>())
296 return;
297
298 NumberingDialectWriter writer(*this);
299 (void)interface->writeType(type, writer);
300 }
301}

/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/include/mlir/IR/Attributes.h

1//===- Attributes.h - MLIR Attribute Classes --------------------*- 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#ifndef MLIR_IR_ATTRIBUTES_H
10#define MLIR_IR_ATTRIBUTES_H
11
12#include "mlir/IR/AttributeSupport.h"
13#include "llvm/Support/PointerLikeTypeTraits.h"
14
15namespace mlir {
16class StringAttr;
17
18/// Attributes are known-constant values of operations.
19///
20/// Instances of the Attribute class are references to immortal key-value pairs
21/// with immutable, uniqued keys owned by MLIRContext. As such, an Attribute is
22/// a thin wrapper around an underlying storage pointer. Attributes are usually
23/// passed by value.
24class Attribute {
25public:
26 /// Utility class for implementing attributes.
27 template <typename ConcreteType, typename BaseType, typename StorageType,
28 template <typename T> class... Traits>
29 using AttrBase = detail::StorageUserBase<ConcreteType, BaseType, StorageType,
30 detail::AttributeUniquer, Traits...>;
31
32 using ImplType = AttributeStorage;
33 using ValueType = void;
34 using AbstractTy = AbstractAttribute;
35
36 constexpr Attribute() {}
37 /* implicit */ Attribute(const ImplType *impl)
38 : impl(const_cast<ImplType *>(impl)) {}
39
40 Attribute(const Attribute &other) = default;
41 Attribute &operator=(const Attribute &other) = default;
42
43 bool operator==(Attribute other) const { return impl == other.impl; }
44 bool operator!=(Attribute other) const { return !(*this == other); }
45 explicit operator bool() const { return impl; }
46
47 bool operator!() const { return impl == nullptr; }
48
49 template <typename U>
50 bool isa() const;
51 template <typename First, typename Second, typename... Rest>
52 bool isa() const;
53 template <typename First, typename... Rest>
54 bool isa_and_nonnull() const;
55 template <typename U>
56 U dyn_cast() const;
57 template <typename U>
58 U dyn_cast_or_null() const;
59 template <typename U>
60 U cast() const;
61
62 // Support dyn_cast'ing Attribute to itself.
63 static bool classof(Attribute) { return true; }
64
65 /// Return a unique identifier for the concrete attribute type. This is used
66 /// to support dynamic type casting.
67 TypeID getTypeID() { return impl->getAbstractAttribute().getTypeID(); }
68
69 /// Return the context this attribute belongs to.
70 MLIRContext *getContext() const;
71
72 /// Get the dialect this attribute is registered to.
73 Dialect &getDialect() const {
74 return impl->getAbstractAttribute().getDialect();
15
Called C++ object pointer is null
75 }
76
77 /// Print the attribute.
78 void print(raw_ostream &os) const;
79 void dump() const;
80
81 /// Get an opaque pointer to the attribute.
82 const void *getAsOpaquePointer() const { return impl; }
83 /// Construct an attribute from the opaque pointer representation.
84 static Attribute getFromOpaquePointer(const void *ptr) {
85 return Attribute(reinterpret_cast<const ImplType *>(ptr));
86 }
87
88 friend ::llvm::hash_code hash_value(Attribute arg);
89
90 /// Returns true if the type was registered with a particular trait.
91 template <template <typename T> class Trait>
92 bool hasTrait() {
93 return getAbstractAttribute().hasTrait<Trait>();
94 }
95
96 /// Return the abstract descriptor for this attribute.
97 const AbstractTy &getAbstractAttribute() const {
98 return impl->getAbstractAttribute();
99 }
100
101protected:
102 ImplType *impl{nullptr};
103};
104
105inline raw_ostream &operator<<(raw_ostream &os, Attribute attr) {
106 attr.print(os);
107 return os;
108}
109
110template <typename U>
111bool Attribute::isa() const {
112 assert(impl && "isa<> used on a null attribute.")(static_cast <bool> (impl && "isa<> used on a null attribute."
) ? void (0) : __assert_fail ("impl && \"isa<> used on a null attribute.\""
, "mlir/include/mlir/IR/Attributes.h", 112, __extension__ __PRETTY_FUNCTION__
))
;
113 return U::classof(*this);
114}
115
116template <typename First, typename Second, typename... Rest>
117bool Attribute::isa() const {
118 return isa<First>() || isa<Second, Rest...>();
119}
120
121template <typename First, typename... Rest>
122bool Attribute::isa_and_nonnull() const {
123 return impl && isa<First, Rest...>();
124}
125
126template <typename U>
127U Attribute::dyn_cast() const {
128 return isa<U>() ? U(impl) : U(nullptr);
129}
130template <typename U>
131U Attribute::dyn_cast_or_null() const {
132 return (impl && isa<U>()) ? U(impl) : U(nullptr);
133}
134template <typename U>
135U Attribute::cast() const {
136 assert(isa<U>())(static_cast <bool> (isa<U>()) ? void (0) : __assert_fail
("isa<U>()", "mlir/include/mlir/IR/Attributes.h", 136,
__extension__ __PRETTY_FUNCTION__))
;
137 return U(impl);
138}
139
140inline ::llvm::hash_code hash_value(Attribute arg) {
141 return DenseMapInfo<const Attribute::ImplType *>::getHashValue(arg.impl);
142}
143
144//===----------------------------------------------------------------------===//
145// NamedAttribute
146//===----------------------------------------------------------------------===//
147
148/// NamedAttribute represents a combination of a name and an Attribute value.
149class NamedAttribute {
150public:
151 NamedAttribute(StringAttr name, Attribute value);
152
153 /// Return the name of the attribute.
154 StringAttr getName() const;
155
156 /// Return the dialect of the name of this attribute, if the name is prefixed
157 /// by a dialect namespace. For example, `llvm.fast_math` would return the
158 /// LLVM dialect (if it is loaded). Returns nullptr if the dialect isn't
159 /// loaded, or if the name is not prefixed by a dialect namespace.
160 Dialect *getNameDialect() const;
161
162 /// Return the value of the attribute.
163 Attribute getValue() const { return value; }
164
165 /// Set the name of this attribute.
166 void setName(StringAttr newName);
167
168 /// Set the value of this attribute.
169 void setValue(Attribute newValue) {
170 assert(value && "expected valid attribute value")(static_cast <bool> (value && "expected valid attribute value"
) ? void (0) : __assert_fail ("value && \"expected valid attribute value\""
, "mlir/include/mlir/IR/Attributes.h", 170, __extension__ __PRETTY_FUNCTION__
))
;
171 value = newValue;
172 }
173
174 /// Compare this attribute to the provided attribute, ordering by name.
175 bool operator<(const NamedAttribute &rhs) const;
176 /// Compare this attribute to the provided string, ordering by name.
177 bool operator<(StringRef rhs) const;
178
179 bool operator==(const NamedAttribute &rhs) const {
180 return name == rhs.name && value == rhs.value;
181 }
182 bool operator!=(const NamedAttribute &rhs) const { return !(*this == rhs); }
183
184private:
185 NamedAttribute(Attribute name, Attribute value) : name(name), value(value) {}
186
187 /// Allow access to internals to enable hashing.
188 friend ::llvm::hash_code hash_value(const NamedAttribute &arg);
189 friend DenseMapInfo<NamedAttribute>;
190
191 /// The name of the attribute. This is represented as a StringAttr, but
192 /// type-erased to Attribute in the field.
193 Attribute name;
194 /// The value of the attribute.
195 Attribute value;
196};
197
198inline ::llvm::hash_code hash_value(const NamedAttribute &arg) {
199 using AttrPairT = std::pair<Attribute, Attribute>;
200 return DenseMapInfo<AttrPairT>::getHashValue(AttrPairT(arg.name, arg.value));
201}
202
203//===----------------------------------------------------------------------===//
204// AttributeTraitBase
205//===----------------------------------------------------------------------===//
206
207namespace AttributeTrait {
208/// This class represents the base of an attribute trait.
209template <typename ConcreteType, template <typename> class TraitType>
210using TraitBase = detail::StorageUserTraitBase<ConcreteType, TraitType>;
211} // namespace AttributeTrait
212
213//===----------------------------------------------------------------------===//
214// AttributeInterface
215//===----------------------------------------------------------------------===//
216
217/// This class represents the base of an attribute interface. See the definition
218/// of `detail::Interface` for requirements on the `Traits` type.
219template <typename ConcreteType, typename Traits>
220class AttributeInterface
221 : public detail::Interface<ConcreteType, Attribute, Traits, Attribute,
222 AttributeTrait::TraitBase> {
223public:
224 using Base = AttributeInterface<ConcreteType, Traits>;
225 using InterfaceBase = detail::Interface<ConcreteType, Attribute, Traits,
226 Attribute, AttributeTrait::TraitBase>;
227 using InterfaceBase::InterfaceBase;
228
229private:
230 /// Returns the impl interface instance for the given type.
231 static typename InterfaceBase::Concept *getInterfaceFor(Attribute attr) {
232 return attr.getAbstractAttribute().getInterface<ConcreteType>();
233 }
234
235 /// Allow access to 'getInterfaceFor'.
236 friend InterfaceBase;
237};
238
239//===----------------------------------------------------------------------===//
240// Core AttributeTrait
241//===----------------------------------------------------------------------===//
242
243/// This trait is used to determine if an attribute is mutable or not. It is
244/// attached on an attribute if the corresponding ImplType defines a `mutate`
245/// function with proper signature.
246namespace AttributeTrait {
247template <typename ConcreteType>
248using IsMutable = detail::StorageUserTrait::IsMutable<ConcreteType>;
249} // namespace AttributeTrait
250
251} // namespace mlir.
252
253namespace llvm {
254
255// Attribute hash just like pointers.
256template <>
257struct DenseMapInfo<mlir::Attribute> {
258 static mlir::Attribute getEmptyKey() {
259 auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
260 return mlir::Attribute(static_cast<mlir::Attribute::ImplType *>(pointer));
261 }
262 static mlir::Attribute getTombstoneKey() {
263 auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
264 return mlir::Attribute(static_cast<mlir::Attribute::ImplType *>(pointer));
265 }
266 static unsigned getHashValue(mlir::Attribute val) {
267 return mlir::hash_value(val);
268 }
269 static bool isEqual(mlir::Attribute LHS, mlir::Attribute RHS) {
270 return LHS == RHS;
271 }
272};
273template <typename T>
274struct DenseMapInfo<
275 T, std::enable_if_t<std::is_base_of<mlir::Attribute, T>::value &&
276 !mlir::detail::IsInterface<T>::value>>
277 : public DenseMapInfo<mlir::Attribute> {
278 static T getEmptyKey() {
279 const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey();
280 return T::getFromOpaquePointer(pointer);
281 }
282 static T getTombstoneKey() {
283 const void *pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey();
284 return T::getFromOpaquePointer(pointer);
285 }
286};
287
288/// Allow LLVM to steal the low bits of Attributes.
289template <>
290struct PointerLikeTypeTraits<mlir::Attribute> {
291 static inline void *getAsVoidPointer(mlir::Attribute attr) {
292 return const_cast<void *>(attr.getAsOpaquePointer());
293 }
294 static inline mlir::Attribute getFromVoidPointer(void *ptr) {
295 return mlir::Attribute::getFromOpaquePointer(ptr);
296 }
297 static constexpr int NumLowBitsAvailable = llvm::PointerLikeTypeTraits<
298 mlir::AttributeStorage *>::NumLowBitsAvailable;
299};
300
301template <>
302struct DenseMapInfo<mlir::NamedAttribute> {
303 static mlir::NamedAttribute getEmptyKey() {
304 auto emptyAttr = llvm::DenseMapInfo<mlir::Attribute>::getEmptyKey();
305 return mlir::NamedAttribute(emptyAttr, emptyAttr);
306 }
307 static mlir::NamedAttribute getTombstoneKey() {
308 auto tombAttr = llvm::DenseMapInfo<mlir::Attribute>::getTombstoneKey();
309 return mlir::NamedAttribute(tombAttr, tombAttr);
310 }
311 static unsigned getHashValue(mlir::NamedAttribute val) {
312 return mlir::hash_value(val);
313 }
314 static bool isEqual(mlir::NamedAttribute lhs, mlir::NamedAttribute rhs) {
315 return lhs == rhs;
316 }
317};
318
319} // namespace llvm
320
321#endif