1 | //===- BuiltinAttributes.h - MLIR Builtin 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_BUILTINATTRIBUTES_H |
10 | #define MLIR_IR_BUILTINATTRIBUTES_H |
11 | |
12 | #include "mlir/IR/BuiltinAttributeInterfaces.h" |
13 | #include "llvm/ADT/APFloat.h" |
14 | #include "llvm/ADT/Sequence.h" |
15 | #include <complex> |
16 | #include <optional> |
17 | |
18 | namespace mlir { |
19 | class AffineMap; |
20 | class AsmResourceBlob; |
21 | class BoolAttr; |
22 | class BuiltinDialect; |
23 | class DenseIntElementsAttr; |
24 | template <typename T> |
25 | struct DialectResourceBlobHandle; |
26 | class FlatSymbolRefAttr; |
27 | class FunctionType; |
28 | class IntegerSet; |
29 | class IntegerType; |
30 | class Location; |
31 | class Operation; |
32 | class RankedTensorType; |
33 | |
34 | namespace detail { |
35 | struct DenseIntOrFPElementsAttrStorage; |
36 | struct DenseStringElementsAttrStorage; |
37 | struct StringAttrStorage; |
38 | } // namespace detail |
39 | |
40 | //===----------------------------------------------------------------------===// |
41 | // Elements Attributes |
42 | //===----------------------------------------------------------------------===// |
43 | |
44 | namespace detail { |
45 | /// Pair of raw pointer and a boolean flag of whether the pointer holds a splat, |
46 | using DenseIterPtrAndSplat = std::pair<const char *, bool>; |
47 | |
48 | /// Impl iterator for indexed DenseElementsAttr iterators that records a data |
49 | /// pointer and data index that is adjusted for the case of a splat attribute. |
50 | template <typename ConcreteT, typename T, typename PointerT = T *, |
51 | typename ReferenceT = T &> |
52 | class DenseElementIndexedIteratorImpl |
53 | : public llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, |
54 | PointerT, ReferenceT> { |
55 | protected: |
56 | DenseElementIndexedIteratorImpl(const char *data, bool isSplat, |
57 | size_t dataIndex) |
58 | : llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, |
59 | PointerT, ReferenceT>({data, isSplat}, |
60 | dataIndex) {} |
61 | |
62 | /// Return the current index for this iterator, adjusted for the case of a |
63 | /// splat. |
64 | ptrdiff_t getDataIndex() const { |
65 | bool isSplat = this->base.second; |
66 | return isSplat ? 0 : this->index; |
67 | } |
68 | |
69 | /// Return the data base pointer. |
70 | const char *getData() const { return this->base.first; } |
71 | }; |
72 | |
73 | /// Type trait detector that checks if a given type T is a complex type. |
74 | template <typename T> |
75 | struct is_complex_t : public std::false_type {}; |
76 | template <typename T> |
77 | struct is_complex_t<std::complex<T>> : public std::true_type {}; |
78 | } // namespace detail |
79 | |
80 | /// An attribute that represents a reference to a dense vector or tensor |
81 | /// object. |
82 | class DenseElementsAttr : public Attribute { |
83 | public: |
84 | using Attribute::Attribute; |
85 | |
86 | /// Allow implicit conversion to ElementsAttr. |
87 | operator ElementsAttr() const { return cast_if_present<ElementsAttr>(*this); } |
88 | /// Allow implicit conversion to TypedAttr. |
89 | operator TypedAttr() const { return ElementsAttr(*this); } |
90 | |
91 | /// Type trait used to check if the given type T is a potentially valid C++ |
92 | /// floating point type that can be used to access the underlying element |
93 | /// types of a DenseElementsAttr. |
94 | template <typename T> |
95 | struct is_valid_cpp_fp_type { |
96 | /// The type is a valid floating point type if it is a builtin floating |
97 | /// point type, or is a potentially user defined floating point type. The |
98 | /// latter allows for supporting users that have custom types defined for |
99 | /// bfloat16/half/etc. |
100 | static constexpr bool value = llvm::is_one_of<T, float, double>::value || |
101 | (std::numeric_limits<T>::is_specialized && |
102 | !std::numeric_limits<T>::is_integer); |
103 | }; |
104 | |
105 | /// Method for support type inquiry through isa, cast and dyn_cast. |
106 | static bool classof(Attribute attr); |
107 | |
108 | /// Constructs a dense elements attribute from an array of element values. |
109 | /// Each element attribute value is expected to be an element of 'type'. |
110 | /// 'type' must be a vector or tensor with static shape. If the element of |
111 | /// `type` is non-integer/index/float it is assumed to be a string type. |
112 | static DenseElementsAttr get(ShapedType type, ArrayRef<Attribute> values); |
113 | |
114 | /// Constructs a dense integer elements attribute from an array of integer |
115 | /// or floating-point values. Each value is expected to be the same bitwidth |
116 | /// of the element type of 'type'. 'type' must be a vector or tensor with |
117 | /// static shape. |
118 | template <typename T, |
119 | typename = std::enable_if_t<std::numeric_limits<T>::is_integer || |
120 | is_valid_cpp_fp_type<T>::value>> |
121 | static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { |
122 | const char *data = reinterpret_cast<const char *>(values.data()); |
123 | return getRawIntOrFloat( |
124 | type, ArrayRef<char>(data, values.size() * sizeof(T)), sizeof(T), |
125 | std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed); |
126 | } |
127 | |
128 | /// Constructs a dense integer elements attribute from a single element. |
129 | template <typename T, |
130 | typename = std::enable_if_t<std::numeric_limits<T>::is_integer || |
131 | is_valid_cpp_fp_type<T>::value || |
132 | detail::is_complex_t<T>::value>> |
133 | static DenseElementsAttr get(const ShapedType &type, T value) { |
134 | return get(type, llvm::ArrayRef(value)); |
135 | } |
136 | |
137 | /// Constructs a dense complex elements attribute from an array of complex |
138 | /// values. Each value is expected to be the same bitwidth of the element type |
139 | /// of 'type'. 'type' must be a vector or tensor with static shape. |
140 | template < |
141 | typename T, typename ElementT = typename T::value_type, |
142 | typename = std::enable_if_t<detail::is_complex_t<T>::value && |
143 | (std::numeric_limits<ElementT>::is_integer || |
144 | is_valid_cpp_fp_type<ElementT>::value)>> |
145 | static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { |
146 | const char *data = reinterpret_cast<const char *>(values.data()); |
147 | return getRawComplex(type, ArrayRef<char>(data, values.size() * sizeof(T)), |
148 | sizeof(T), std::numeric_limits<ElementT>::is_integer, |
149 | std::numeric_limits<ElementT>::is_signed); |
150 | } |
151 | |
152 | /// Overload of the above 'get' method that is specialized for boolean values. |
153 | static DenseElementsAttr get(ShapedType type, ArrayRef<bool> values); |
154 | |
155 | /// Overload of the above 'get' method that is specialized for StringRef |
156 | /// values. |
157 | static DenseElementsAttr get(ShapedType type, ArrayRef<StringRef> values); |
158 | |
159 | /// Constructs a dense integer elements attribute from an array of APInt |
160 | /// values. Each APInt value is expected to have the same bitwidth as the |
161 | /// element type of 'type'. 'type' must be a vector or tensor with static |
162 | /// shape. |
163 | static DenseElementsAttr get(ShapedType type, ArrayRef<APInt> values); |
164 | |
165 | /// Constructs a dense complex elements attribute from an array of APInt |
166 | /// values. Each APInt value is expected to have the same bitwidth as the |
167 | /// element type of 'type'. 'type' must be a vector or tensor with static |
168 | /// shape. |
169 | static DenseElementsAttr get(ShapedType type, |
170 | ArrayRef<std::complex<APInt>> values); |
171 | |
172 | /// Constructs a dense float elements attribute from an array of APFloat |
173 | /// values. Each APFloat value is expected to have the same bitwidth as the |
174 | /// element type of 'type'. 'type' must be a vector or tensor with static |
175 | /// shape. |
176 | static DenseElementsAttr get(ShapedType type, ArrayRef<APFloat> values); |
177 | |
178 | /// Constructs a dense complex elements attribute from an array of APFloat |
179 | /// values. Each APFloat value is expected to have the same bitwidth as the |
180 | /// element type of 'type'. 'type' must be a vector or tensor with static |
181 | /// shape. |
182 | static DenseElementsAttr get(ShapedType type, |
183 | ArrayRef<std::complex<APFloat>> values); |
184 | |
185 | /// Construct a dense elements attribute for an initializer_list of values. |
186 | /// Each value is expected to be the same bitwidth of the element type of |
187 | /// 'type'. 'type' must be a vector or tensor with static shape. |
188 | template <typename T> |
189 | static DenseElementsAttr get(const ShapedType &type, |
190 | const std::initializer_list<T> &list) { |
191 | return get(type, ArrayRef<T>(list)); |
192 | } |
193 | |
194 | /// Construct a dense elements attribute from a raw buffer representing the |
195 | /// data for this attribute. Users are encouraged to use one of the |
196 | /// constructors above, which provide more safeties. However, this |
197 | /// constructor is useful for tools which may want to interop and can |
198 | /// follow the precise definition. |
199 | /// |
200 | /// The format of the raw buffer is a densely packed array of values that |
201 | /// can be bitcast to the storage format of the element type specified. |
202 | /// Types that are not byte aligned will be: |
203 | /// - For bitwidth > 1: Rounded up to the next byte. |
204 | /// - For bitwidth = 1: Packed into 8bit bytes with bits corresponding to |
205 | /// the linear order of the shape type from MSB to LSB, padded to on the |
206 | /// right. |
207 | static DenseElementsAttr getFromRawBuffer(ShapedType type, |
208 | ArrayRef<char> rawBuffer); |
209 | |
210 | /// Returns true if the given buffer is a valid raw buffer for the given type. |
211 | /// `detectedSplat` is set if the buffer is valid and represents a splat |
212 | /// buffer. The definition may be expanded over time, but currently, a |
213 | /// splat buffer is detected if: |
214 | /// - For >1bit: The buffer consists of a single element. |
215 | /// - For 1bit: The buffer consists of a single byte with value 0 or 255. |
216 | /// |
217 | /// User code should be prepared for additional, conformant patterns to be |
218 | /// identified as splats in the future. |
219 | static bool isValidRawBuffer(ShapedType type, ArrayRef<char> rawBuffer, |
220 | bool &detectedSplat); |
221 | |
222 | //===--------------------------------------------------------------------===// |
223 | // Iterators |
224 | //===--------------------------------------------------------------------===// |
225 | |
226 | /// The iterator range over the given iterator type T. |
227 | template <typename IteratorT> |
228 | using iterator_range_impl = detail::ElementsAttrRange<IteratorT>; |
229 | |
230 | /// The iterator for the given element type T. |
231 | template <typename T, typename AttrT = DenseElementsAttr> |
232 | using iterator = decltype(std::declval<AttrT>().template value_begin<T>()); |
233 | /// The iterator range over the given element T. |
234 | template <typename T, typename AttrT = DenseElementsAttr> |
235 | using iterator_range = |
236 | decltype(std::declval<AttrT>().template getValues<T>()); |
237 | |
238 | /// A utility iterator that allows walking over the internal Attribute values |
239 | /// of a DenseElementsAttr. |
240 | class AttributeElementIterator |
241 | : public llvm::indexed_accessor_iterator<AttributeElementIterator, |
242 | const void *, Attribute, |
243 | Attribute, Attribute> { |
244 | public: |
245 | /// Accesses the Attribute value at this iterator position. |
246 | Attribute operator*() const; |
247 | |
248 | private: |
249 | friend DenseElementsAttr; |
250 | |
251 | /// Constructs a new iterator. |
252 | AttributeElementIterator(DenseElementsAttr attr, size_t index); |
253 | }; |
254 | |
255 | /// Iterator for walking raw element values of the specified type 'T', which |
256 | /// may be any c++ data type matching the stored representation: int32_t, |
257 | /// float, etc. |
258 | template <typename T> |
259 | class ElementIterator |
260 | : public detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, |
261 | const T> { |
262 | public: |
263 | /// Accesses the raw value at this iterator position. |
264 | const T &operator*() const { |
265 | return reinterpret_cast<const T *>(this->getData())[this->getDataIndex()]; |
266 | } |
267 | |
268 | private: |
269 | friend DenseElementsAttr; |
270 | |
271 | /// Constructs a new iterator. |
272 | ElementIterator(const char *data, bool isSplat, size_t dataIndex) |
273 | : detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, const T>( |
274 | data, isSplat, dataIndex) {} |
275 | }; |
276 | |
277 | /// A utility iterator that allows walking over the internal bool values. |
278 | class BoolElementIterator |
279 | : public detail::DenseElementIndexedIteratorImpl<BoolElementIterator, |
280 | bool, bool, bool> { |
281 | public: |
282 | /// Accesses the bool value at this iterator position. |
283 | bool operator*() const; |
284 | |
285 | private: |
286 | friend DenseElementsAttr; |
287 | |
288 | /// Constructs a new iterator. |
289 | BoolElementIterator(DenseElementsAttr attr, size_t dataIndex); |
290 | }; |
291 | |
292 | /// A utility iterator that allows walking over the internal raw APInt values. |
293 | class IntElementIterator |
294 | : public detail::DenseElementIndexedIteratorImpl<IntElementIterator, |
295 | APInt, APInt, APInt> { |
296 | public: |
297 | /// Accesses the raw APInt value at this iterator position. |
298 | APInt operator*() const; |
299 | |
300 | private: |
301 | friend DenseElementsAttr; |
302 | |
303 | /// Constructs a new iterator. |
304 | IntElementIterator(DenseElementsAttr attr, size_t dataIndex); |
305 | |
306 | /// The bitwidth of the element type. |
307 | size_t bitWidth; |
308 | }; |
309 | |
310 | /// A utility iterator that allows walking over the internal raw complex APInt |
311 | /// values. |
312 | class ComplexIntElementIterator |
313 | : public detail::DenseElementIndexedIteratorImpl< |
314 | ComplexIntElementIterator, std::complex<APInt>, std::complex<APInt>, |
315 | std::complex<APInt>> { |
316 | public: |
317 | /// Accesses the raw std::complex<APInt> value at this iterator position. |
318 | std::complex<APInt> operator*() const; |
319 | |
320 | private: |
321 | friend DenseElementsAttr; |
322 | |
323 | /// Constructs a new iterator. |
324 | ComplexIntElementIterator(DenseElementsAttr attr, size_t dataIndex); |
325 | |
326 | /// The bitwidth of the element type. |
327 | size_t bitWidth; |
328 | }; |
329 | |
330 | /// Iterator for walking over APFloat values. |
331 | class FloatElementIterator final |
332 | : public llvm::mapped_iterator_base<FloatElementIterator, |
333 | IntElementIterator, APFloat> { |
334 | public: |
335 | /// Map the element to the iterator result type. |
336 | APFloat mapElement(const APInt &value) const { |
337 | return APFloat(*smt, value); |
338 | } |
339 | |
340 | private: |
341 | friend DenseElementsAttr; |
342 | |
343 | /// Initializes the float element iterator to the specified iterator. |
344 | FloatElementIterator(const llvm::fltSemantics &smt, IntElementIterator it) |
345 | : BaseT(it), smt(&smt) {} |
346 | |
347 | /// The float semantics to use when constructing the APFloat. |
348 | const llvm::fltSemantics *smt; |
349 | }; |
350 | |
351 | /// Iterator for walking over complex APFloat values. |
352 | class ComplexFloatElementIterator final |
353 | : public llvm::mapped_iterator_base<ComplexFloatElementIterator, |
354 | ComplexIntElementIterator, |
355 | std::complex<APFloat>> { |
356 | public: |
357 | /// Map the element to the iterator result type. |
358 | std::complex<APFloat> mapElement(const std::complex<APInt> &value) const { |
359 | return {APFloat(*smt, value.real()), APFloat(*smt, value.imag())}; |
360 | } |
361 | |
362 | private: |
363 | friend DenseElementsAttr; |
364 | |
365 | /// Initializes the float element iterator to the specified iterator. |
366 | ComplexFloatElementIterator(const llvm::fltSemantics &smt, |
367 | ComplexIntElementIterator it) |
368 | : BaseT(it), smt(&smt) {} |
369 | |
370 | /// The float semantics to use when constructing the APFloat. |
371 | const llvm::fltSemantics *smt; |
372 | }; |
373 | |
374 | //===--------------------------------------------------------------------===// |
375 | // Value Querying |
376 | //===--------------------------------------------------------------------===// |
377 | |
378 | /// Returns true if this attribute corresponds to a splat, i.e. if all element |
379 | /// values are the same. |
380 | bool isSplat() const; |
381 | |
382 | /// Return the splat value for this attribute. This asserts that the attribute |
383 | /// corresponds to a splat. |
384 | template <typename T> |
385 | std::enable_if_t<!std::is_base_of<Attribute, T>::value || |
386 | std::is_same<Attribute, T>::value, |
387 | T> |
388 | getSplatValue() const { |
389 | assert(isSplat() && "expected the attribute to be a splat" ); |
390 | return *value_begin<T>(); |
391 | } |
392 | /// Return the splat value for derived attribute element types. |
393 | template <typename T> |
394 | std::enable_if_t<std::is_base_of<Attribute, T>::value && |
395 | !std::is_same<Attribute, T>::value, |
396 | T> |
397 | getSplatValue() const { |
398 | return llvm::cast<T>(getSplatValue<Attribute>()); |
399 | } |
400 | |
401 | /// Try to get an iterator of the given type to the start of the held element |
402 | /// values. Return failure if the type cannot be iterated. |
403 | template <typename T> |
404 | auto try_value_begin() const { |
405 | auto range = tryGetValues<T>(); |
406 | using iterator = decltype(range->begin()); |
407 | return failed(range) ? FailureOr<iterator>(failure()) : range->begin(); |
408 | } |
409 | |
410 | /// Try to get an iterator of the given type to the end of the held element |
411 | /// values. Return failure if the type cannot be iterated. |
412 | template <typename T> |
413 | auto try_value_end() const { |
414 | auto range = tryGetValues<T>(); |
415 | using iterator = decltype(range->begin()); |
416 | return failed(range) ? FailureOr<iterator>(failure()) : range->end(); |
417 | } |
418 | |
419 | /// Return the held element values as a range of the given type. |
420 | template <typename T> |
421 | auto getValues() const { |
422 | auto range = tryGetValues<T>(); |
423 | assert(succeeded(range) && "element type cannot be iterated" ); |
424 | return std::move(*range); |
425 | } |
426 | |
427 | /// Get an iterator of the given type to the start of the held element values. |
428 | template <typename T> |
429 | auto value_begin() const { |
430 | return getValues<T>().begin(); |
431 | } |
432 | |
433 | /// Get an iterator of the given type to the end of the held element values. |
434 | template <typename T> |
435 | auto value_end() const { |
436 | return getValues<T>().end(); |
437 | } |
438 | |
439 | /// Try to get the held element values as a range of integer or floating-point |
440 | /// values. |
441 | template <typename T> |
442 | using IntFloatValueTemplateCheckT = |
443 | std::enable_if_t<(!std::is_same<T, bool>::value && |
444 | std::numeric_limits<T>::is_integer) || |
445 | is_valid_cpp_fp_type<T>::value>; |
446 | template <typename T, typename = IntFloatValueTemplateCheckT<T>> |
447 | FailureOr<iterator_range_impl<ElementIterator<T>>> tryGetValues() const { |
448 | if (!isValidIntOrFloat(dataEltSize: sizeof(T), isInt: std::numeric_limits<T>::is_integer, |
449 | isSigned: std::numeric_limits<T>::is_signed)) |
450 | return failure(); |
451 | const char *rawData = getRawData().data(); |
452 | bool splat = isSplat(); |
453 | return iterator_range_impl<ElementIterator<T>>( |
454 | getType(), ElementIterator<T>(rawData, splat, 0), |
455 | ElementIterator<T>(rawData, splat, getNumElements())); |
456 | } |
457 | |
458 | /// Try to get the held element values as a range of std::complex. |
459 | template <typename T, typename ElementT> |
460 | using ComplexValueTemplateCheckT = |
461 | std::enable_if_t<detail::is_complex_t<T>::value && |
462 | (std::numeric_limits<ElementT>::is_integer || |
463 | is_valid_cpp_fp_type<ElementT>::value)>; |
464 | template <typename T, typename ElementT = typename T::value_type, |
465 | typename = ComplexValueTemplateCheckT<T, ElementT>> |
466 | FailureOr<iterator_range_impl<ElementIterator<T>>> tryGetValues() const { |
467 | if (!isValidComplex(dataEltSize: sizeof(T), isInt: std::numeric_limits<ElementT>::is_integer, |
468 | isSigned: std::numeric_limits<ElementT>::is_signed)) |
469 | return failure(); |
470 | const char *rawData = getRawData().data(); |
471 | bool splat = isSplat(); |
472 | return iterator_range_impl<ElementIterator<T>>( |
473 | getType(), ElementIterator<T>(rawData, splat, 0), |
474 | ElementIterator<T>(rawData, splat, getNumElements())); |
475 | } |
476 | |
477 | /// Try to get the held element values as a range of StringRef. |
478 | template <typename T> |
479 | using StringRefValueTemplateCheckT = |
480 | std::enable_if_t<std::is_same<T, StringRef>::value>; |
481 | template <typename T, typename = StringRefValueTemplateCheckT<T>> |
482 | FailureOr<iterator_range_impl<ElementIterator<StringRef>>> |
483 | tryGetValues() const { |
484 | auto stringRefs = getRawStringData(); |
485 | const char *ptr = reinterpret_cast<const char *>(stringRefs.data()); |
486 | bool splat = isSplat(); |
487 | return iterator_range_impl<ElementIterator<StringRef>>( |
488 | getType(), ElementIterator<StringRef>(ptr, splat, 0), |
489 | ElementIterator<StringRef>(ptr, splat, getNumElements())); |
490 | } |
491 | |
492 | /// Try to get the held element values as a range of Attributes. |
493 | template <typename T> |
494 | using AttributeValueTemplateCheckT = |
495 | std::enable_if_t<std::is_same<T, Attribute>::value>; |
496 | template <typename T, typename = AttributeValueTemplateCheckT<T>> |
497 | FailureOr<iterator_range_impl<AttributeElementIterator>> |
498 | tryGetValues() const { |
499 | return iterator_range_impl<AttributeElementIterator>( |
500 | getType(), AttributeElementIterator(*this, 0), |
501 | AttributeElementIterator(*this, getNumElements())); |
502 | } |
503 | |
504 | /// Try to get the held element values a range of T, where T is a derived |
505 | /// attribute type. |
506 | template <typename T> |
507 | using DerivedAttrValueTemplateCheckT = |
508 | std::enable_if_t<std::is_base_of<Attribute, T>::value && |
509 | !std::is_same<Attribute, T>::value>; |
510 | template <typename T> |
511 | struct DerivedAttributeElementIterator |
512 | : public llvm::mapped_iterator_base<DerivedAttributeElementIterator<T>, |
513 | AttributeElementIterator, T> { |
514 | using llvm::mapped_iterator_base<DerivedAttributeElementIterator<T>, |
515 | AttributeElementIterator, |
516 | T>::mapped_iterator_base; |
517 | |
518 | /// Map the element to the iterator result type. |
519 | T mapElement(Attribute attr) const { return llvm::cast<T>(attr); } |
520 | }; |
521 | template <typename T, typename = DerivedAttrValueTemplateCheckT<T>> |
522 | FailureOr<iterator_range_impl<DerivedAttributeElementIterator<T>>> |
523 | tryGetValues() const { |
524 | using DerivedIterT = DerivedAttributeElementIterator<T>; |
525 | return iterator_range_impl<DerivedIterT>( |
526 | getType(), DerivedIterT(value_begin<Attribute>()), |
527 | DerivedIterT(value_end<Attribute>())); |
528 | } |
529 | |
530 | /// Try to get the held element values as a range of bool. The element type of |
531 | /// this attribute must be of integer type of bitwidth 1. |
532 | template <typename T> |
533 | using BoolValueTemplateCheckT = |
534 | std::enable_if_t<std::is_same<T, bool>::value>; |
535 | template <typename T, typename = BoolValueTemplateCheckT<T>> |
536 | FailureOr<iterator_range_impl<BoolElementIterator>> tryGetValues() const { |
537 | if (!isValidBool()) |
538 | return failure(); |
539 | return iterator_range_impl<BoolElementIterator>( |
540 | getType(), BoolElementIterator(*this, 0), |
541 | BoolElementIterator(*this, getNumElements())); |
542 | } |
543 | |
544 | /// Try to get the held element values as a range of APInts. The element type |
545 | /// of this attribute must be of integer type. |
546 | template <typename T> |
547 | using APIntValueTemplateCheckT = |
548 | std::enable_if_t<std::is_same<T, APInt>::value>; |
549 | template <typename T, typename = APIntValueTemplateCheckT<T>> |
550 | FailureOr<iterator_range_impl<IntElementIterator>> tryGetValues() const { |
551 | if (!getElementType().isIntOrIndex()) |
552 | return failure(); |
553 | return iterator_range_impl<IntElementIterator>(getType(), raw_int_begin(), |
554 | raw_int_end()); |
555 | } |
556 | |
557 | /// Try to get the held element values as a range of complex APInts. The |
558 | /// element type of this attribute must be a complex of integer type. |
559 | template <typename T> |
560 | using ComplexAPIntValueTemplateCheckT = |
561 | std::enable_if_t<std::is_same<T, std::complex<APInt>>::value>; |
562 | template <typename T, typename = ComplexAPIntValueTemplateCheckT<T>> |
563 | FailureOr<iterator_range_impl<ComplexIntElementIterator>> |
564 | tryGetValues() const { |
565 | return tryGetComplexIntValues(); |
566 | } |
567 | |
568 | /// Try to get the held element values as a range of APFloat. The element type |
569 | /// of this attribute must be of float type. |
570 | template <typename T> |
571 | using APFloatValueTemplateCheckT = |
572 | std::enable_if_t<std::is_same<T, APFloat>::value>; |
573 | template <typename T, typename = APFloatValueTemplateCheckT<T>> |
574 | FailureOr<iterator_range_impl<FloatElementIterator>> tryGetValues() const { |
575 | return tryGetFloatValues(); |
576 | } |
577 | |
578 | /// Try to get the held element values as a range of complex APFloat. The |
579 | /// element type of this attribute must be a complex of float type. |
580 | template <typename T> |
581 | using ComplexAPFloatValueTemplateCheckT = |
582 | std::enable_if_t<std::is_same<T, std::complex<APFloat>>::value>; |
583 | template <typename T, typename = ComplexAPFloatValueTemplateCheckT<T>> |
584 | FailureOr<iterator_range_impl<ComplexFloatElementIterator>> |
585 | tryGetValues() const { |
586 | return tryGetComplexFloatValues(); |
587 | } |
588 | |
589 | /// Return the raw storage data held by this attribute. Users should generally |
590 | /// not use this directly, as the internal storage format is not always in the |
591 | /// form the user might expect. |
592 | ArrayRef<char> getRawData() const; |
593 | |
594 | /// Return the raw StringRef data held by this attribute. |
595 | ArrayRef<StringRef> getRawStringData() const; |
596 | |
597 | /// Return the type of this ElementsAttr, guaranteed to be a vector or tensor |
598 | /// with static shape. |
599 | ShapedType getType() const; |
600 | |
601 | /// Return the element type of this DenseElementsAttr. |
602 | Type getElementType() const; |
603 | |
604 | /// Returns the number of elements held by this attribute. |
605 | int64_t getNumElements() const; |
606 | |
607 | /// Returns the number of elements held by this attribute. |
608 | int64_t size() const { return getNumElements(); } |
609 | |
610 | /// Returns if the number of elements held by this attribute is 0. |
611 | bool empty() const { return size() == 0; } |
612 | |
613 | //===--------------------------------------------------------------------===// |
614 | // Mutation Utilities |
615 | //===--------------------------------------------------------------------===// |
616 | |
617 | /// Return a new DenseElementsAttr that has the same data as the current |
618 | /// attribute, but has been reshaped to 'newType'. The new type must have the |
619 | /// same total number of elements as well as element type. |
620 | DenseElementsAttr reshape(ShapedType newType); |
621 | |
622 | /// Return a new DenseElementsAttr that has the same data as the current |
623 | /// attribute, but with a different shape for a splat type. The new type must |
624 | /// have the same element type. |
625 | DenseElementsAttr resizeSplat(ShapedType newType); |
626 | |
627 | /// Return a new DenseElementsAttr that has the same data as the current |
628 | /// attribute, but has bitcast elements to 'newElType'. The new type must have |
629 | /// the same bitwidth as the current element type. |
630 | DenseElementsAttr bitcast(Type newElType); |
631 | |
632 | /// Generates a new DenseElementsAttr by mapping each int value to a new |
633 | /// underlying APInt. The new values can represent either an integer or float. |
634 | /// This underlying type must be an DenseIntElementsAttr. |
635 | DenseElementsAttr mapValues(Type newElementType, |
636 | function_ref<APInt(const APInt &)> mapping) const; |
637 | |
638 | /// Generates a new DenseElementsAttr by mapping each float value to a new |
639 | /// underlying APInt. the new values can represent either an integer or float. |
640 | /// This underlying type must be an DenseFPElementsAttr. |
641 | DenseElementsAttr |
642 | mapValues(Type newElementType, |
643 | function_ref<APInt(const APFloat &)> mapping) const; |
644 | |
645 | protected: |
646 | /// Iterators to various elements that require out-of-line definition. These |
647 | /// are hidden from the user to encourage consistent use of the |
648 | /// getValues/value_begin/value_end API. |
649 | IntElementIterator raw_int_begin() const { |
650 | return IntElementIterator(*this, 0); |
651 | } |
652 | IntElementIterator raw_int_end() const { |
653 | return IntElementIterator(*this, getNumElements()); |
654 | } |
655 | FailureOr<iterator_range_impl<ComplexIntElementIterator>> |
656 | tryGetComplexIntValues() const; |
657 | FailureOr<iterator_range_impl<FloatElementIterator>> |
658 | tryGetFloatValues() const; |
659 | FailureOr<iterator_range_impl<ComplexFloatElementIterator>> |
660 | tryGetComplexFloatValues() const; |
661 | |
662 | /// Overload of the raw 'get' method that asserts that the given type is of |
663 | /// complex type. This method is used to verify type invariants that the |
664 | /// templatized 'get' method cannot. |
665 | static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef<char> data, |
666 | int64_t dataEltSize, bool isInt, |
667 | bool isSigned); |
668 | |
669 | /// Overload of the raw 'get' method that asserts that the given type is of |
670 | /// integer or floating-point type. This method is used to verify type |
671 | /// invariants that the templatized 'get' method cannot. |
672 | static DenseElementsAttr getRawIntOrFloat(ShapedType type, |
673 | ArrayRef<char> data, |
674 | int64_t dataEltSize, bool isInt, |
675 | bool isSigned); |
676 | |
677 | /// Check the information for a C++ data type, check if this type is valid for |
678 | /// the current attribute. This method is used to verify specific type |
679 | /// invariants that the templatized 'getValues' method cannot. |
680 | bool isValidBool() const { return getElementType().isInteger(width: 1); } |
681 | bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const; |
682 | bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const; |
683 | }; |
684 | |
685 | /// An attribute that represents a reference to a splat vector or tensor |
686 | /// constant, meaning all of the elements have the same value. |
687 | class SplatElementsAttr : public DenseElementsAttr { |
688 | public: |
689 | using DenseElementsAttr::DenseElementsAttr; |
690 | |
691 | /// Method for support type inquiry through isa, cast and dyn_cast. |
692 | static bool classof(Attribute attr) { |
693 | auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(Val&: attr); |
694 | return denseAttr && denseAttr.isSplat(); |
695 | } |
696 | }; |
697 | |
698 | //===----------------------------------------------------------------------===// |
699 | // DenseResourceElementsAttr |
700 | //===----------------------------------------------------------------------===// |
701 | |
702 | using DenseResourceElementsHandle = DialectResourceBlobHandle<BuiltinDialect>; |
703 | |
704 | } // namespace mlir |
705 | |
706 | //===----------------------------------------------------------------------===// |
707 | // Tablegen Attribute Declarations |
708 | //===----------------------------------------------------------------------===// |
709 | |
710 | #define GET_ATTRDEF_CLASSES |
711 | #include "mlir/IR/BuiltinAttributes.h.inc" |
712 | |
713 | //===----------------------------------------------------------------------===// |
714 | // C++ Attribute Declarations |
715 | //===----------------------------------------------------------------------===// |
716 | |
717 | namespace mlir { |
718 | //===----------------------------------------------------------------------===// |
719 | // DenseArrayAttr |
720 | |
721 | namespace detail { |
722 | /// Base class for DenseArrayAttr that is instantiated and specialized for each |
723 | /// supported element type below. |
724 | template <typename T> |
725 | class DenseArrayAttrImpl : public DenseArrayAttr { |
726 | public: |
727 | using DenseArrayAttr::DenseArrayAttr; |
728 | |
729 | /// Implicit conversion to ArrayRef<T>. |
730 | operator ArrayRef<T>() const; |
731 | ArrayRef<T> asArrayRef() const { return ArrayRef<T>{*this}; } |
732 | |
733 | /// Random access to elements. |
734 | T operator[](std::size_t index) const { return asArrayRef()[index]; } |
735 | |
736 | /// Builder from ArrayRef<T>. |
737 | static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef<T> content); |
738 | |
739 | /// Print the short form `[42, 100, -1]` without any type prefix. |
740 | void print(AsmPrinter &printer) const; |
741 | void print(raw_ostream &os) const; |
742 | /// Print the short form `42, 100, -1` without any braces or type prefix. |
743 | void printWithoutBraces(raw_ostream &os) const; |
744 | |
745 | /// Parse the short form `[42, 100, -1]` without any type prefix. |
746 | static Attribute parse(AsmParser &parser, Type type); |
747 | |
748 | /// Parse the short form `42, 100, -1` without any type prefix or braces. |
749 | static Attribute parseWithoutBraces(AsmParser &parser, Type type); |
750 | |
751 | /// Support for isa<>/cast<>. |
752 | static bool classof(Attribute attr); |
753 | }; |
754 | |
755 | extern template class DenseArrayAttrImpl<bool>; |
756 | extern template class DenseArrayAttrImpl<int8_t>; |
757 | extern template class DenseArrayAttrImpl<int16_t>; |
758 | extern template class DenseArrayAttrImpl<int32_t>; |
759 | extern template class DenseArrayAttrImpl<int64_t>; |
760 | extern template class DenseArrayAttrImpl<float>; |
761 | extern template class DenseArrayAttrImpl<double>; |
762 | } // namespace detail |
763 | |
764 | // Public name for all the supported DenseArrayAttr |
765 | using DenseBoolArrayAttr = detail::DenseArrayAttrImpl<bool>; |
766 | using DenseI8ArrayAttr = detail::DenseArrayAttrImpl<int8_t>; |
767 | using DenseI16ArrayAttr = detail::DenseArrayAttrImpl<int16_t>; |
768 | using DenseI32ArrayAttr = detail::DenseArrayAttrImpl<int32_t>; |
769 | using DenseI64ArrayAttr = detail::DenseArrayAttrImpl<int64_t>; |
770 | using DenseF32ArrayAttr = detail::DenseArrayAttrImpl<float>; |
771 | using DenseF64ArrayAttr = detail::DenseArrayAttrImpl<double>; |
772 | |
773 | //===----------------------------------------------------------------------===// |
774 | // DenseResourceElementsAttr |
775 | |
776 | namespace detail { |
777 | /// Base class for DenseResourceElementsAttr that is instantiated and |
778 | /// specialized for each supported element type below. |
779 | template <typename T> |
780 | class DenseResourceElementsAttrBase : public DenseResourceElementsAttr { |
781 | public: |
782 | using DenseResourceElementsAttr::DenseResourceElementsAttr; |
783 | |
784 | /// A builder that inserts a new resource using the provided blob. The handle |
785 | /// of the inserted blob is used when building the attribute. The provided |
786 | /// `blobName` is used as a hint for the key of the new handle for the `blob` |
787 | /// resource, but may be changed if necessary to ensure uniqueness during |
788 | /// insertion. |
789 | static DenseResourceElementsAttrBase<T> |
790 | get(ShapedType type, StringRef blobName, AsmResourceBlob blob); |
791 | |
792 | /// Return the data of this attribute as an ArrayRef<T> if it is present, |
793 | /// returns std::nullopt otherwise. |
794 | std::optional<ArrayRef<T>> tryGetAsArrayRef() const; |
795 | |
796 | /// Support for isa<>/cast<>. |
797 | static bool classof(Attribute attr); |
798 | }; |
799 | |
800 | extern template class DenseResourceElementsAttrBase<bool>; |
801 | extern template class DenseResourceElementsAttrBase<int8_t>; |
802 | extern template class DenseResourceElementsAttrBase<int16_t>; |
803 | extern template class DenseResourceElementsAttrBase<int32_t>; |
804 | extern template class DenseResourceElementsAttrBase<int64_t>; |
805 | extern template class DenseResourceElementsAttrBase<uint8_t>; |
806 | extern template class DenseResourceElementsAttrBase<uint16_t>; |
807 | extern template class DenseResourceElementsAttrBase<uint32_t>; |
808 | extern template class DenseResourceElementsAttrBase<uint64_t>; |
809 | extern template class DenseResourceElementsAttrBase<float>; |
810 | extern template class DenseResourceElementsAttrBase<double>; |
811 | } // namespace detail |
812 | |
813 | // Public names for all the supported DenseResourceElementsAttr. |
814 | |
815 | using DenseBoolResourceElementsAttr = |
816 | detail::DenseResourceElementsAttrBase<bool>; |
817 | using DenseI8ResourceElementsAttr = |
818 | detail::DenseResourceElementsAttrBase<int8_t>; |
819 | using DenseI16ResourceElementsAttr = |
820 | detail::DenseResourceElementsAttrBase<int16_t>; |
821 | using DenseI32ResourceElementsAttr = |
822 | detail::DenseResourceElementsAttrBase<int32_t>; |
823 | using DenseI64ResourceElementsAttr = |
824 | detail::DenseResourceElementsAttrBase<int64_t>; |
825 | using DenseUI8ResourceElementsAttr = |
826 | detail::DenseResourceElementsAttrBase<uint8_t>; |
827 | using DenseUI16ResourceElementsAttr = |
828 | detail::DenseResourceElementsAttrBase<uint16_t>; |
829 | using DenseUI32ResourceElementsAttr = |
830 | detail::DenseResourceElementsAttrBase<uint32_t>; |
831 | using DenseUI64ResourceElementsAttr = |
832 | detail::DenseResourceElementsAttrBase<uint64_t>; |
833 | using DenseF32ResourceElementsAttr = |
834 | detail::DenseResourceElementsAttrBase<float>; |
835 | using DenseF64ResourceElementsAttr = |
836 | detail::DenseResourceElementsAttrBase<double>; |
837 | |
838 | //===----------------------------------------------------------------------===// |
839 | // BoolAttr |
840 | //===----------------------------------------------------------------------===// |
841 | |
842 | /// Special case of IntegerAttr to represent boolean integers, i.e., signless i1 |
843 | /// integers. |
844 | class BoolAttr : public Attribute { |
845 | public: |
846 | using Attribute::Attribute; |
847 | using ValueType = bool; |
848 | |
849 | static BoolAttr get(MLIRContext *context, bool value); |
850 | |
851 | /// Enable conversion to IntegerAttr and its interfaces. This uses conversion |
852 | /// vs. inheritance to avoid bringing in all of IntegerAttrs methods. |
853 | operator IntegerAttr() const { return IntegerAttr(impl); } |
854 | operator TypedAttr() const { return IntegerAttr(impl); } |
855 | |
856 | /// Return the boolean value of this attribute. |
857 | bool getValue() const; |
858 | |
859 | /// Methods for support type inquiry through isa, cast, and dyn_cast. |
860 | static bool classof(Attribute attr); |
861 | }; |
862 | |
863 | //===----------------------------------------------------------------------===// |
864 | // FlatSymbolRefAttr |
865 | //===----------------------------------------------------------------------===// |
866 | |
867 | /// A symbol reference with a reference path containing a single element. This |
868 | /// is used to refer to an operation within the current symbol table. |
869 | class FlatSymbolRefAttr : public SymbolRefAttr { |
870 | public: |
871 | using SymbolRefAttr::SymbolRefAttr; |
872 | using ValueType = StringRef; |
873 | |
874 | /// Construct a symbol reference for the given value name. |
875 | static FlatSymbolRefAttr get(StringAttr value) { |
876 | return SymbolRefAttr::get(value); |
877 | } |
878 | static FlatSymbolRefAttr get(MLIRContext *ctx, StringRef value) { |
879 | return SymbolRefAttr::get(ctx, value); |
880 | } |
881 | |
882 | /// Convenience getter for building a SymbolRefAttr based on an operation |
883 | /// that implements the SymbolTrait. |
884 | static FlatSymbolRefAttr get(Operation *symbol) { |
885 | return SymbolRefAttr::get(symbol); |
886 | } |
887 | |
888 | /// Returns the name of the held symbol reference as a StringAttr. |
889 | StringAttr getAttr() const { return getRootReference(); } |
890 | |
891 | /// Returns the name of the held symbol reference. |
892 | StringRef getValue() const { return getAttr().getValue(); } |
893 | |
894 | /// Methods for support type inquiry through isa, cast, and dyn_cast. |
895 | static bool classof(Attribute attr) { |
896 | SymbolRefAttr refAttr = llvm::dyn_cast<SymbolRefAttr>(attr); |
897 | return refAttr && refAttr.getNestedReferences().empty(); |
898 | } |
899 | |
900 | private: |
901 | using SymbolRefAttr::get; |
902 | using SymbolRefAttr::getNestedReferences; |
903 | }; |
904 | |
905 | //===----------------------------------------------------------------------===// |
906 | // DenseFPElementsAttr |
907 | //===----------------------------------------------------------------------===// |
908 | |
909 | /// An attribute that represents a reference to a dense float vector or tensor |
910 | /// object. Each element is stored as a double. |
911 | class DenseFPElementsAttr : public DenseIntOrFPElementsAttr { |
912 | public: |
913 | using iterator = DenseElementsAttr::FloatElementIterator; |
914 | |
915 | using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; |
916 | |
917 | /// Get an instance of a DenseFPElementsAttr with the given arguments. This |
918 | /// simply wraps the DenseElementsAttr::get calls. |
919 | template <typename Arg> |
920 | static DenseFPElementsAttr get(const ShapedType &type, Arg &&arg) { |
921 | return llvm::cast<DenseFPElementsAttr>( |
922 | DenseElementsAttr::get(type, llvm::ArrayRef(arg))); |
923 | } |
924 | template <typename T> |
925 | static DenseFPElementsAttr get(const ShapedType &type, |
926 | const std::initializer_list<T> &list) { |
927 | return llvm::cast<DenseFPElementsAttr>(DenseElementsAttr::get(type, list)); |
928 | } |
929 | |
930 | /// Generates a new DenseElementsAttr by mapping each value attribute, and |
931 | /// constructing the DenseElementsAttr given the new element type. |
932 | DenseElementsAttr |
933 | mapValues(Type newElementType, |
934 | function_ref<APInt(const APFloat &)> mapping) const; |
935 | |
936 | /// Iterator access to the float element values. |
937 | iterator begin() const { return tryGetFloatValues()->begin(); } |
938 | iterator end() const { return tryGetFloatValues()->end(); } |
939 | |
940 | /// Method for supporting type inquiry through isa, cast and dyn_cast. |
941 | static bool classof(Attribute attr); |
942 | }; |
943 | |
944 | //===----------------------------------------------------------------------===// |
945 | // DenseIntElementsAttr |
946 | //===----------------------------------------------------------------------===// |
947 | |
948 | /// An attribute that represents a reference to a dense integer vector or tensor |
949 | /// object. |
950 | class DenseIntElementsAttr : public DenseIntOrFPElementsAttr { |
951 | public: |
952 | /// DenseIntElementsAttr iterates on APInt, so we can use the raw element |
953 | /// iterator directly. |
954 | using iterator = DenseElementsAttr::IntElementIterator; |
955 | |
956 | using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; |
957 | |
958 | /// Get an instance of a DenseIntElementsAttr with the given arguments. This |
959 | /// simply wraps the DenseElementsAttr::get calls. |
960 | template <typename Arg> |
961 | static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg) { |
962 | return llvm::cast<DenseIntElementsAttr>( |
963 | DenseElementsAttr::get(type, llvm::ArrayRef(arg))); |
964 | } |
965 | template <typename T> |
966 | static DenseIntElementsAttr get(const ShapedType &type, |
967 | const std::initializer_list<T> &list) { |
968 | return llvm::cast<DenseIntElementsAttr>(DenseElementsAttr::get(type, list)); |
969 | } |
970 | |
971 | /// Generates a new DenseElementsAttr by mapping each value attribute, and |
972 | /// constructing the DenseElementsAttr given the new element type. |
973 | DenseElementsAttr mapValues(Type newElementType, |
974 | function_ref<APInt(const APInt &)> mapping) const; |
975 | |
976 | /// Iterator access to the integer element values. |
977 | iterator begin() const { return raw_int_begin(); } |
978 | iterator end() const { return raw_int_end(); } |
979 | |
980 | /// Method for supporting type inquiry through isa, cast and dyn_cast. |
981 | static bool classof(Attribute attr); |
982 | }; |
983 | |
984 | //===----------------------------------------------------------------------===// |
985 | // SparseElementsAttr |
986 | //===----------------------------------------------------------------------===// |
987 | |
988 | template <typename T> |
989 | auto SparseElementsAttr::try_value_begin_impl(OverloadToken<T>) const |
990 | -> FailureOr<iterator<T>> { |
991 | auto zeroValue = getZeroValue<T>(); |
992 | auto valueIt = getValues().try_value_begin<T>(); |
993 | if (failed(valueIt)) |
994 | return failure(); |
995 | const std::vector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices()); |
996 | std::function<T(ptrdiff_t)> mapFn = |
997 | [flatSparseIndices{flatSparseIndices}, valueIt{std::move(*valueIt)}, |
998 | zeroValue{std::move(zeroValue)}](ptrdiff_t index) { |
999 | // Try to map the current index to one of the sparse indices. |
1000 | for (unsigned i = 0, e = flatSparseIndices.size(); i != e; ++i) |
1001 | if (flatSparseIndices[i] == index) |
1002 | return *std::next(valueIt, i); |
1003 | // Otherwise, return the zero value. |
1004 | return zeroValue; |
1005 | }; |
1006 | return iterator<T>(llvm::seq<ptrdiff_t>(0, getNumElements()).begin(), mapFn); |
1007 | } |
1008 | |
1009 | //===----------------------------------------------------------------------===// |
1010 | // DistinctAttr |
1011 | //===----------------------------------------------------------------------===// |
1012 | |
1013 | namespace detail { |
1014 | struct DistinctAttrStorage; |
1015 | class DistinctAttributeUniquer; |
1016 | } // namespace detail |
1017 | |
1018 | /// An attribute that associates a referenced attribute with a unique |
1019 | /// identifier. Every call to the create function allocates a new distinct |
1020 | /// attribute instance. The address of the attribute instance serves as a |
1021 | /// temporary identifier. Similar to the names of SSA values, the final |
1022 | /// identifiers are generated during pretty printing. This delayed numbering |
1023 | /// ensures the printed identifiers are deterministic even if multiple distinct |
1024 | /// attribute instances are created in-parallel. |
1025 | /// |
1026 | /// Examples: |
1027 | /// |
1028 | /// #distinct = distinct[0]<42.0 : f32> |
1029 | /// #distinct1 = distinct[1]<42.0 : f32> |
1030 | /// #distinct2 = distinct[2]<array<i32: 10, 42>> |
1031 | /// |
1032 | /// NOTE: The distinct attribute cannot be defined using ODS since it uses a |
1033 | /// custom distinct attribute uniquer that cannot be set from ODS. |
1034 | class DistinctAttr |
1035 | : public detail::StorageUserBase<DistinctAttr, Attribute, |
1036 | detail::DistinctAttrStorage, |
1037 | detail::DistinctAttributeUniquer> { |
1038 | public: |
1039 | using Base::Base; |
1040 | |
1041 | /// Returns the referenced attribute. |
1042 | Attribute getReferencedAttr() const; |
1043 | |
1044 | /// Creates a distinct attribute that associates a referenced attribute with a |
1045 | /// unique identifier. |
1046 | static DistinctAttr create(Attribute referencedAttr); |
1047 | |
1048 | static constexpr StringLiteral name = "builtin.distinct" ; |
1049 | }; |
1050 | |
1051 | //===----------------------------------------------------------------------===// |
1052 | // StringAttr |
1053 | //===----------------------------------------------------------------------===// |
1054 | |
1055 | /// Define comparisons for StringAttr against nullptr and itself to avoid the |
1056 | /// StringRef overloads from being chosen when not desirable. |
1057 | inline bool operator==(StringAttr lhs, std::nullptr_t) { return !lhs; } |
1058 | inline bool operator!=(StringAttr lhs, std::nullptr_t) { |
1059 | return static_cast<bool>(lhs); |
1060 | } |
1061 | inline bool operator==(StringAttr lhs, StringAttr rhs) { |
1062 | return (Attribute)lhs == (Attribute)rhs; |
1063 | } |
1064 | inline bool operator!=(StringAttr lhs, StringAttr rhs) { return !(lhs == rhs); } |
1065 | |
1066 | /// Allow direct comparison with StringRef. |
1067 | inline bool operator==(StringAttr lhs, StringRef rhs) { |
1068 | return lhs.getValue() == rhs; |
1069 | } |
1070 | inline bool operator!=(StringAttr lhs, StringRef rhs) { return !(lhs == rhs); } |
1071 | inline bool operator==(StringRef lhs, StringAttr rhs) { |
1072 | return rhs.getValue() == lhs; |
1073 | } |
1074 | inline bool operator!=(StringRef lhs, StringAttr rhs) { return !(lhs == rhs); } |
1075 | |
1076 | } // namespace mlir |
1077 | |
1078 | //===----------------------------------------------------------------------===// |
1079 | // Attribute Utilities |
1080 | //===----------------------------------------------------------------------===// |
1081 | |
1082 | namespace mlir { |
1083 | |
1084 | /// Given a list of strides (in which ShapedType::kDynamic |
1085 | /// represents a dynamic value), return the single result AffineMap which |
1086 | /// represents the linearized strided layout map. Dimensions correspond to the |
1087 | /// offset followed by the strides in order. Symbols are inserted for each |
1088 | /// dynamic dimension in order. A stride is always positive. |
1089 | /// |
1090 | /// Examples: |
1091 | /// ========= |
1092 | /// |
1093 | /// 1. For offset: 0 strides: ?, ?, 1 return |
1094 | /// (i, j, k)[M, N]->(M * i + N * j + k) |
1095 | /// |
1096 | /// 2. For offset: 3 strides: 32, ?, 16 return |
1097 | /// (i, j, k)[M]->(3 + 32 * i + M * j + 16 * k) |
1098 | /// |
1099 | /// 3. For offset: ? strides: ?, ?, ? return |
1100 | /// (i, j, k)[off, M, N, P]->(off + M * i + N * j + P * k) |
1101 | AffineMap makeStridedLinearLayoutMap(ArrayRef<int64_t> strides, int64_t offset, |
1102 | MLIRContext *context); |
1103 | |
1104 | } // namespace mlir |
1105 | |
1106 | namespace llvm { |
1107 | |
1108 | template <> |
1109 | struct DenseMapInfo<mlir::StringAttr> : public DenseMapInfo<mlir::Attribute> { |
1110 | static mlir::StringAttr getEmptyKey() { |
1111 | const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey(); |
1112 | return mlir::StringAttr::getFromOpaquePointer(pointer); |
1113 | } |
1114 | static mlir::StringAttr getTombstoneKey() { |
1115 | const void *pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey(); |
1116 | return mlir::StringAttr::getFromOpaquePointer(pointer); |
1117 | } |
1118 | }; |
1119 | template <> |
1120 | struct PointerLikeTypeTraits<mlir::StringAttr> |
1121 | : public PointerLikeTypeTraits<mlir::Attribute> { |
1122 | static inline mlir::StringAttr getFromVoidPointer(void *p) { |
1123 | return mlir::StringAttr::getFromOpaquePointer(p); |
1124 | } |
1125 | }; |
1126 | |
1127 | template <> |
1128 | struct PointerLikeTypeTraits<mlir::IntegerAttr> |
1129 | : public PointerLikeTypeTraits<mlir::Attribute> { |
1130 | static inline mlir::IntegerAttr getFromVoidPointer(void *p) { |
1131 | return mlir::IntegerAttr::getFromOpaquePointer(p); |
1132 | } |
1133 | }; |
1134 | |
1135 | template <> |
1136 | struct PointerLikeTypeTraits<mlir::SymbolRefAttr> |
1137 | : public PointerLikeTypeTraits<mlir::Attribute> { |
1138 | static inline mlir::SymbolRefAttr getFromVoidPointer(void *ptr) { |
1139 | return mlir::SymbolRefAttr::getFromOpaquePointer(ptr); |
1140 | } |
1141 | }; |
1142 | |
1143 | } // namespace llvm |
1144 | |
1145 | #endif // MLIR_IR_BUILTINATTRIBUTES_H |
1146 | |