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 | |
722 | namespace detail { |
723 | /// Base class for DenseArrayAttr that is instantiated and specialized for each |
724 | /// supported element type below. |
725 | template <typename T> |
726 | class DenseArrayAttrImpl : public DenseArrayAttr { |
727 | public: |
728 | using DenseArrayAttr::DenseArrayAttr; |
729 | |
730 | /// Implicit conversion to ArrayRef<T>. |
731 | operator ArrayRef<T>() const; |
732 | ArrayRef<T> asArrayRef() const { return ArrayRef<T>{*this}; } |
733 | |
734 | /// Random access to elements. |
735 | T operator[](std::size_t index) const { return asArrayRef()[index]; } |
736 | |
737 | /// Builder from ArrayRef<T>. |
738 | static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef<T> content); |
739 | |
740 | /// Print the short form `[42, 100, -1]` without any type prefix. |
741 | void print(AsmPrinter &printer) const; |
742 | void print(raw_ostream &os) const; |
743 | /// Print the short form `42, 100, -1` without any braces or type prefix. |
744 | void printWithoutBraces(raw_ostream &os) const; |
745 | |
746 | /// Parse the short form `[42, 100, -1]` without any type prefix. |
747 | static Attribute parse(AsmParser &parser, Type type); |
748 | |
749 | /// Parse the short form `42, 100, -1` without any type prefix or braces. |
750 | static Attribute parseWithoutBraces(AsmParser &parser, Type type); |
751 | |
752 | /// Support for isa<>/cast<>. |
753 | static bool classof(Attribute attr); |
754 | }; |
755 | |
756 | extern template class DenseArrayAttrImpl<bool>; |
757 | extern template class DenseArrayAttrImpl<int8_t>; |
758 | extern template class DenseArrayAttrImpl<int16_t>; |
759 | extern template class DenseArrayAttrImpl<int32_t>; |
760 | extern template class DenseArrayAttrImpl<int64_t>; |
761 | extern template class DenseArrayAttrImpl<float>; |
762 | extern template class DenseArrayAttrImpl<double>; |
763 | } // namespace detail |
764 | |
765 | // Public name for all the supported DenseArrayAttr |
766 | using DenseBoolArrayAttr = detail::DenseArrayAttrImpl<bool>; |
767 | using DenseI8ArrayAttr = detail::DenseArrayAttrImpl<int8_t>; |
768 | using DenseI16ArrayAttr = detail::DenseArrayAttrImpl<int16_t>; |
769 | using DenseI32ArrayAttr = detail::DenseArrayAttrImpl<int32_t>; |
770 | using DenseI64ArrayAttr = detail::DenseArrayAttrImpl<int64_t>; |
771 | using DenseF32ArrayAttr = detail::DenseArrayAttrImpl<float>; |
772 | using DenseF64ArrayAttr = detail::DenseArrayAttrImpl<double>; |
773 | |
774 | //===----------------------------------------------------------------------===// |
775 | // DenseResourceElementsAttr |
776 | //===----------------------------------------------------------------------===// |
777 | |
778 | namespace detail { |
779 | /// Base class for DenseResourceElementsAttr that is instantiated and |
780 | /// specialized for each supported element type below. |
781 | template <typename T> |
782 | class DenseResourceElementsAttrBase : public DenseResourceElementsAttr { |
783 | public: |
784 | using DenseResourceElementsAttr::DenseResourceElementsAttr; |
785 | |
786 | /// A builder that inserts a new resource using the provided blob. The handle |
787 | /// of the inserted blob is used when building the attribute. The provided |
788 | /// `blobName` is used as a hint for the key of the new handle for the `blob` |
789 | /// resource, but may be changed if necessary to ensure uniqueness during |
790 | /// insertion. |
791 | static DenseResourceElementsAttrBase<T> |
792 | get(ShapedType type, StringRef blobName, AsmResourceBlob blob); |
793 | |
794 | /// Return the data of this attribute as an ArrayRef<T> if it is present, |
795 | /// returns std::nullopt otherwise. |
796 | std::optional<ArrayRef<T>> tryGetAsArrayRef() const; |
797 | |
798 | /// Support for isa<>/cast<>. |
799 | static bool classof(Attribute attr); |
800 | }; |
801 | |
802 | extern template class DenseResourceElementsAttrBase<bool>; |
803 | extern template class DenseResourceElementsAttrBase<int8_t>; |
804 | extern template class DenseResourceElementsAttrBase<int16_t>; |
805 | extern template class DenseResourceElementsAttrBase<int32_t>; |
806 | extern template class DenseResourceElementsAttrBase<int64_t>; |
807 | extern template class DenseResourceElementsAttrBase<uint8_t>; |
808 | extern template class DenseResourceElementsAttrBase<uint16_t>; |
809 | extern template class DenseResourceElementsAttrBase<uint32_t>; |
810 | extern template class DenseResourceElementsAttrBase<uint64_t>; |
811 | extern template class DenseResourceElementsAttrBase<float>; |
812 | extern template class DenseResourceElementsAttrBase<double>; |
813 | } // namespace detail |
814 | |
815 | // Public names for all the supported DenseResourceElementsAttr. |
816 | |
817 | using DenseBoolResourceElementsAttr = |
818 | detail::DenseResourceElementsAttrBase<bool>; |
819 | using DenseI8ResourceElementsAttr = |
820 | detail::DenseResourceElementsAttrBase<int8_t>; |
821 | using DenseI16ResourceElementsAttr = |
822 | detail::DenseResourceElementsAttrBase<int16_t>; |
823 | using DenseI32ResourceElementsAttr = |
824 | detail::DenseResourceElementsAttrBase<int32_t>; |
825 | using DenseI64ResourceElementsAttr = |
826 | detail::DenseResourceElementsAttrBase<int64_t>; |
827 | using DenseUI8ResourceElementsAttr = |
828 | detail::DenseResourceElementsAttrBase<uint8_t>; |
829 | using DenseUI16ResourceElementsAttr = |
830 | detail::DenseResourceElementsAttrBase<uint16_t>; |
831 | using DenseUI32ResourceElementsAttr = |
832 | detail::DenseResourceElementsAttrBase<uint32_t>; |
833 | using DenseUI64ResourceElementsAttr = |
834 | detail::DenseResourceElementsAttrBase<uint64_t>; |
835 | using DenseF32ResourceElementsAttr = |
836 | detail::DenseResourceElementsAttrBase<float>; |
837 | using DenseF64ResourceElementsAttr = |
838 | detail::DenseResourceElementsAttrBase<double>; |
839 | |
840 | //===----------------------------------------------------------------------===// |
841 | // BoolAttr |
842 | //===----------------------------------------------------------------------===// |
843 | |
844 | /// Special case of IntegerAttr to represent boolean integers, i.e., signless i1 |
845 | /// integers. |
846 | class BoolAttr : public Attribute { |
847 | public: |
848 | using Attribute::Attribute; |
849 | using ValueType = bool; |
850 | |
851 | static BoolAttr get(MLIRContext *context, bool value); |
852 | |
853 | /// Enable conversion to IntegerAttr and its interfaces. This uses conversion |
854 | /// vs. inheritance to avoid bringing in all of IntegerAttrs methods. |
855 | operator IntegerAttr() const { return IntegerAttr(impl); } |
856 | operator TypedAttr() const { return IntegerAttr(impl); } |
857 | |
858 | /// Return the boolean value of this attribute. |
859 | bool getValue() const; |
860 | |
861 | /// Methods for support type inquiry through isa, cast, and dyn_cast. |
862 | static bool classof(Attribute attr); |
863 | }; |
864 | |
865 | //===----------------------------------------------------------------------===// |
866 | // FlatSymbolRefAttr |
867 | //===----------------------------------------------------------------------===// |
868 | |
869 | /// A symbol reference with a reference path containing a single element. This |
870 | /// is used to refer to an operation within the current symbol table. |
871 | class FlatSymbolRefAttr : public SymbolRefAttr { |
872 | public: |
873 | using SymbolRefAttr::SymbolRefAttr; |
874 | using ValueType = StringRef; |
875 | |
876 | /// Construct a symbol reference for the given value name. |
877 | static FlatSymbolRefAttr get(StringAttr value) { |
878 | return SymbolRefAttr::get(value); |
879 | } |
880 | static FlatSymbolRefAttr get(MLIRContext *ctx, StringRef value) { |
881 | return SymbolRefAttr::get(ctx, value); |
882 | } |
883 | |
884 | /// Convenience getter for building a SymbolRefAttr based on an operation |
885 | /// that implements the SymbolTrait. |
886 | static FlatSymbolRefAttr get(Operation *symbol) { |
887 | return SymbolRefAttr::get(symbol); |
888 | } |
889 | |
890 | /// Returns the name of the held symbol reference as a StringAttr. |
891 | StringAttr getAttr() const { return getRootReference(); } |
892 | |
893 | /// Returns the name of the held symbol reference. |
894 | StringRef getValue() const { return getAttr().getValue(); } |
895 | |
896 | /// Methods for support type inquiry through isa, cast, and dyn_cast. |
897 | static bool classof(Attribute attr) { |
898 | SymbolRefAttr refAttr = llvm::dyn_cast<SymbolRefAttr>(attr); |
899 | return refAttr && refAttr.getNestedReferences().empty(); |
900 | } |
901 | |
902 | private: |
903 | using SymbolRefAttr::get; |
904 | using SymbolRefAttr::getNestedReferences; |
905 | }; |
906 | |
907 | //===----------------------------------------------------------------------===// |
908 | // DenseFPElementsAttr |
909 | //===----------------------------------------------------------------------===// |
910 | |
911 | /// An attribute that represents a reference to a dense float vector or tensor |
912 | /// object. Each element is stored as a double. |
913 | class DenseFPElementsAttr : public DenseIntOrFPElementsAttr { |
914 | public: |
915 | using iterator = DenseElementsAttr::FloatElementIterator; |
916 | |
917 | using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; |
918 | |
919 | /// Get an instance of a DenseFPElementsAttr with the given arguments. This |
920 | /// simply wraps the DenseElementsAttr::get calls. |
921 | template <typename Arg> |
922 | static DenseFPElementsAttr get(const ShapedType &type, Arg &&arg) { |
923 | return llvm::cast<DenseFPElementsAttr>( |
924 | DenseElementsAttr::get(type, llvm::ArrayRef(arg))); |
925 | } |
926 | template <typename T> |
927 | static DenseFPElementsAttr get(const ShapedType &type, |
928 | const std::initializer_list<T> &list) { |
929 | return llvm::cast<DenseFPElementsAttr>(DenseElementsAttr::get(type, list)); |
930 | } |
931 | |
932 | /// Generates a new DenseElementsAttr by mapping each value attribute, and |
933 | /// constructing the DenseElementsAttr given the new element type. |
934 | DenseElementsAttr |
935 | mapValues(Type newElementType, |
936 | function_ref<APInt(const APFloat &)> mapping) const; |
937 | |
938 | /// Iterator access to the float element values. |
939 | iterator begin() const { return tryGetFloatValues()->begin(); } |
940 | iterator end() const { return tryGetFloatValues()->end(); } |
941 | |
942 | /// Method for supporting type inquiry through isa, cast and dyn_cast. |
943 | static bool classof(Attribute attr); |
944 | }; |
945 | |
946 | //===----------------------------------------------------------------------===// |
947 | // DenseIntElementsAttr |
948 | //===----------------------------------------------------------------------===// |
949 | |
950 | /// An attribute that represents a reference to a dense integer vector or tensor |
951 | /// object. |
952 | class DenseIntElementsAttr : public DenseIntOrFPElementsAttr { |
953 | public: |
954 | /// DenseIntElementsAttr iterates on APInt, so we can use the raw element |
955 | /// iterator directly. |
956 | using iterator = DenseElementsAttr::IntElementIterator; |
957 | |
958 | using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; |
959 | |
960 | /// Get an instance of a DenseIntElementsAttr with the given arguments. This |
961 | /// simply wraps the DenseElementsAttr::get calls. |
962 | template <typename Arg> |
963 | static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg) { |
964 | return llvm::cast<DenseIntElementsAttr>( |
965 | DenseElementsAttr::get(type, llvm::ArrayRef(arg))); |
966 | } |
967 | template <typename T> |
968 | static DenseIntElementsAttr get(const ShapedType &type, |
969 | const std::initializer_list<T> &list) { |
970 | return llvm::cast<DenseIntElementsAttr>(DenseElementsAttr::get(type, list)); |
971 | } |
972 | |
973 | /// Generates a new DenseElementsAttr by mapping each value attribute, and |
974 | /// constructing the DenseElementsAttr given the new element type. |
975 | DenseElementsAttr mapValues(Type newElementType, |
976 | function_ref<APInt(const APInt &)> mapping) const; |
977 | |
978 | /// Iterator access to the integer element values. |
979 | iterator begin() const { return raw_int_begin(); } |
980 | iterator end() const { return raw_int_end(); } |
981 | |
982 | /// Method for supporting type inquiry through isa, cast and dyn_cast. |
983 | static bool classof(Attribute attr); |
984 | }; |
985 | |
986 | //===----------------------------------------------------------------------===// |
987 | // SparseElementsAttr |
988 | //===----------------------------------------------------------------------===// |
989 | |
990 | template <typename T> |
991 | auto SparseElementsAttr::try_value_begin_impl(OverloadToken<T>) const |
992 | -> FailureOr<iterator<T>> { |
993 | auto zeroValue = getZeroValue<T>(); |
994 | auto valueIt = getValues().try_value_begin<T>(); |
995 | if (failed(valueIt)) |
996 | return failure(); |
997 | const SmallVector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices()); |
998 | std::function<T(ptrdiff_t)> mapFn = |
999 | [flatSparseIndices{flatSparseIndices}, valueIt{std::move(*valueIt)}, |
1000 | zeroValue{std::move(zeroValue)}](ptrdiff_t index) { |
1001 | // Try to map the current index to one of the sparse indices. |
1002 | for (unsigned i = 0, e = flatSparseIndices.size(); i != e; ++i) |
1003 | if (flatSparseIndices[i] == index) |
1004 | return *std::next(valueIt, i); |
1005 | // Otherwise, return the zero value. |
1006 | return zeroValue; |
1007 | }; |
1008 | return iterator<T>(llvm::seq<ptrdiff_t>(0, getNumElements()).begin(), mapFn); |
1009 | } |
1010 | |
1011 | //===----------------------------------------------------------------------===// |
1012 | // DistinctAttr |
1013 | //===----------------------------------------------------------------------===// |
1014 | |
1015 | namespace detail { |
1016 | struct DistinctAttrStorage; |
1017 | class DistinctAttributeUniquer; |
1018 | } // namespace detail |
1019 | |
1020 | /// An attribute that associates a referenced attribute with a unique |
1021 | /// identifier. Every call to the create function allocates a new distinct |
1022 | /// attribute instance. The address of the attribute instance serves as a |
1023 | /// temporary identifier. Similar to the names of SSA values, the final |
1024 | /// identifiers are generated during pretty printing. This delayed numbering |
1025 | /// ensures the printed identifiers are deterministic even if multiple distinct |
1026 | /// attribute instances are created in-parallel. |
1027 | /// |
1028 | /// Examples: |
1029 | /// |
1030 | /// #distinct = distinct[0]<42.0 : f32> |
1031 | /// #distinct1 = distinct[1]<42.0 : f32> |
1032 | /// #distinct2 = distinct[2]<array<i32: 10, 42>> |
1033 | /// |
1034 | /// NOTE: The distinct attribute cannot be defined using ODS since it uses a |
1035 | /// custom distinct attribute uniquer that cannot be set from ODS. |
1036 | class DistinctAttr |
1037 | : public detail::StorageUserBase<DistinctAttr, Attribute, |
1038 | detail::DistinctAttrStorage, |
1039 | detail::DistinctAttributeUniquer> { |
1040 | public: |
1041 | using Base::Base; |
1042 | |
1043 | /// Returns the referenced attribute. |
1044 | Attribute getReferencedAttr() const; |
1045 | |
1046 | /// Creates a distinct attribute that associates a referenced attribute with a |
1047 | /// unique identifier. |
1048 | static DistinctAttr create(Attribute referencedAttr); |
1049 | |
1050 | static constexpr StringLiteral name = "builtin.distinct"; |
1051 | }; |
1052 | |
1053 | //===----------------------------------------------------------------------===// |
1054 | // StringAttr |
1055 | //===----------------------------------------------------------------------===// |
1056 | |
1057 | /// Define comparisons for StringAttr against nullptr and itself to avoid the |
1058 | /// StringRef overloads from being chosen when not desirable. |
1059 | inline bool operator==(StringAttr lhs, std::nullptr_t) { return !lhs; } |
1060 | inline bool operator!=(StringAttr lhs, std::nullptr_t) { |
1061 | return static_cast<bool>(lhs); |
1062 | } |
1063 | inline bool operator==(StringAttr lhs, StringAttr rhs) { |
1064 | return (Attribute)lhs == (Attribute)rhs; |
1065 | } |
1066 | inline bool operator!=(StringAttr lhs, StringAttr rhs) { return !(lhs == rhs); } |
1067 | |
1068 | /// Allow direct comparison with StringRef. |
1069 | inline bool operator==(StringAttr lhs, StringRef rhs) { |
1070 | return lhs.getValue() == rhs; |
1071 | } |
1072 | inline bool operator!=(StringAttr lhs, StringRef rhs) { return !(lhs == rhs); } |
1073 | inline bool operator==(StringRef lhs, StringAttr rhs) { |
1074 | return rhs.getValue() == lhs; |
1075 | } |
1076 | inline bool operator!=(StringRef lhs, StringAttr rhs) { return !(lhs == rhs); } |
1077 | |
1078 | } // namespace mlir |
1079 | |
1080 | //===----------------------------------------------------------------------===// |
1081 | // Attribute Utilities |
1082 | //===----------------------------------------------------------------------===// |
1083 | |
1084 | namespace mlir { |
1085 | |
1086 | /// Given a list of strides (in which ShapedType::kDynamic |
1087 | /// represents a dynamic value), return the single result AffineMap which |
1088 | /// represents the linearized strided layout map. Dimensions correspond to the |
1089 | /// offset followed by the strides in order. Symbols are inserted for each |
1090 | /// dynamic dimension in order. A stride is always positive. |
1091 | /// |
1092 | /// Examples: |
1093 | /// ========= |
1094 | /// |
1095 | /// 1. For offset: 0 strides: ?, ?, 1 return |
1096 | /// (i, j, k)[M, N]->(M * i + N * j + k) |
1097 | /// |
1098 | /// 2. For offset: 3 strides: 32, ?, 16 return |
1099 | /// (i, j, k)[M]->(3 + 32 * i + M * j + 16 * k) |
1100 | /// |
1101 | /// 3. For offset: ? strides: ?, ?, ? return |
1102 | /// (i, j, k)[off, M, N, P]->(off + M * i + N * j + P * k) |
1103 | AffineMap makeStridedLinearLayoutMap(ArrayRef<int64_t> strides, int64_t offset, |
1104 | MLIRContext *context); |
1105 | |
1106 | } // namespace mlir |
1107 | |
1108 | namespace llvm { |
1109 | |
1110 | template <> |
1111 | struct DenseMapInfo<mlir::StringAttr> : public DenseMapInfo<mlir::Attribute> { |
1112 | static mlir::StringAttr getEmptyKey() { |
1113 | const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey(); |
1114 | return mlir::StringAttr::getFromOpaquePointer(pointer); |
1115 | } |
1116 | static mlir::StringAttr getTombstoneKey() { |
1117 | const void *pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey(); |
1118 | return mlir::StringAttr::getFromOpaquePointer(pointer); |
1119 | } |
1120 | }; |
1121 | template <> |
1122 | struct PointerLikeTypeTraits<mlir::StringAttr> |
1123 | : public PointerLikeTypeTraits<mlir::Attribute> { |
1124 | static inline mlir::StringAttr getFromVoidPointer(void *p) { |
1125 | return mlir::StringAttr::getFromOpaquePointer(p); |
1126 | } |
1127 | }; |
1128 | |
1129 | template <> |
1130 | struct PointerLikeTypeTraits<mlir::IntegerAttr> |
1131 | : public PointerLikeTypeTraits<mlir::Attribute> { |
1132 | static inline mlir::IntegerAttr getFromVoidPointer(void *p) { |
1133 | return mlir::IntegerAttr::getFromOpaquePointer(p); |
1134 | } |
1135 | }; |
1136 | |
1137 | template <> |
1138 | struct PointerLikeTypeTraits<mlir::SymbolRefAttr> |
1139 | : public PointerLikeTypeTraits<mlir::Attribute> { |
1140 | static inline mlir::SymbolRefAttr getFromVoidPointer(void *ptr) { |
1141 | return mlir::SymbolRefAttr::getFromOpaquePointer(ptr); |
1142 | } |
1143 | }; |
1144 | |
1145 | } // namespace llvm |
1146 | |
1147 | #endif // MLIR_IR_BUILTINATTRIBUTES_H |
1148 |
Definitions
- DenseElementIndexedIteratorImpl
- DenseElementIndexedIteratorImpl
- getDataIndex
- getData
- is_complex_t
- is_complex_t
- DenseElementsAttr
- get
- get
- get
- get
- AttributeElementIterator
- ElementIterator
- operator*
- ElementIterator
- BoolElementIterator
- IntElementIterator
- ComplexIntElementIterator
- FloatElementIterator
- mapElement
- FloatElementIterator
- ComplexFloatElementIterator
- mapElement
- ComplexFloatElementIterator
- getSplatValue
- getSplatValue
- try_value_begin
- try_value_end
- getValues
- value_begin
- value_end
- tryGetValues
- tryGetValues
- tryGetValues
- tryGetValues
- DerivedAttributeElementIterator
- mapElement
- tryGetValues
- tryGetValues
- tryGetValues
- tryGetValues
- tryGetValues
- tryGetValues
- size
- empty
- raw_int_begin
- raw_int_end
- isValidBool
- SplatElementsAttr
- classof
- DenseArrayAttrImpl
- asArrayRef
- operator[]
- DenseResourceElementsAttrBase
- BoolAttr
- FlatSymbolRefAttr
- get
- get
- get
- getAttr
- getValue
- classof
- DenseFPElementsAttr
- get
- get
- begin
- end
- DenseIntElementsAttr
- get
- get
- begin
- end
- DistinctAttr
- name
- operator==
- operator!=
- operator==
- operator!=
- operator==
- operator!=
- operator==
- operator!=
- DenseMapInfo
- getEmptyKey
- getTombstoneKey
- PointerLikeTypeTraits
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more