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
18namespace mlir {
19class AffineMap;
20class AsmResourceBlob;
21class BoolAttr;
22class BuiltinDialect;
23class DenseIntElementsAttr;
24template <typename T>
25struct DialectResourceBlobHandle;
26class FlatSymbolRefAttr;
27class FunctionType;
28class IntegerSet;
29class IntegerType;
30class Location;
31class Operation;
32class RankedTensorType;
33
34namespace detail {
35struct DenseIntOrFPElementsAttrStorage;
36struct DenseStringElementsAttrStorage;
37struct StringAttrStorage;
38} // namespace detail
39
40//===----------------------------------------------------------------------===//
41// Elements Attributes
42//===----------------------------------------------------------------------===//
43
44namespace detail {
45/// Pair of raw pointer and a boolean flag of whether the pointer holds a splat,
46using 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.
50template <typename ConcreteT, typename T, typename PointerT = T *,
51 typename ReferenceT = T &>
52class DenseElementIndexedIteratorImpl
53 : public llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T,
54 PointerT, ReferenceT> {
55protected:
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.
74template <typename T>
75struct is_complex_t : public std::false_type {};
76template <typename T>
77struct 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.
82class DenseElementsAttr : public Attribute {
83public:
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
645protected:
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.
687class SplatElementsAttr : public DenseElementsAttr {
688public:
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
702using 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
717namespace mlir {
718//===----------------------------------------------------------------------===//
719// DenseArrayAttr
720
721namespace detail {
722/// Base class for DenseArrayAttr that is instantiated and specialized for each
723/// supported element type below.
724template <typename T>
725class DenseArrayAttrImpl : public DenseArrayAttr {
726public:
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
755extern template class DenseArrayAttrImpl<bool>;
756extern template class DenseArrayAttrImpl<int8_t>;
757extern template class DenseArrayAttrImpl<int16_t>;
758extern template class DenseArrayAttrImpl<int32_t>;
759extern template class DenseArrayAttrImpl<int64_t>;
760extern template class DenseArrayAttrImpl<float>;
761extern template class DenseArrayAttrImpl<double>;
762} // namespace detail
763
764// Public name for all the supported DenseArrayAttr
765using DenseBoolArrayAttr = detail::DenseArrayAttrImpl<bool>;
766using DenseI8ArrayAttr = detail::DenseArrayAttrImpl<int8_t>;
767using DenseI16ArrayAttr = detail::DenseArrayAttrImpl<int16_t>;
768using DenseI32ArrayAttr = detail::DenseArrayAttrImpl<int32_t>;
769using DenseI64ArrayAttr = detail::DenseArrayAttrImpl<int64_t>;
770using DenseF32ArrayAttr = detail::DenseArrayAttrImpl<float>;
771using DenseF64ArrayAttr = detail::DenseArrayAttrImpl<double>;
772
773//===----------------------------------------------------------------------===//
774// DenseResourceElementsAttr
775
776namespace detail {
777/// Base class for DenseResourceElementsAttr that is instantiated and
778/// specialized for each supported element type below.
779template <typename T>
780class DenseResourceElementsAttrBase : public DenseResourceElementsAttr {
781public:
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
800extern template class DenseResourceElementsAttrBase<bool>;
801extern template class DenseResourceElementsAttrBase<int8_t>;
802extern template class DenseResourceElementsAttrBase<int16_t>;
803extern template class DenseResourceElementsAttrBase<int32_t>;
804extern template class DenseResourceElementsAttrBase<int64_t>;
805extern template class DenseResourceElementsAttrBase<uint8_t>;
806extern template class DenseResourceElementsAttrBase<uint16_t>;
807extern template class DenseResourceElementsAttrBase<uint32_t>;
808extern template class DenseResourceElementsAttrBase<uint64_t>;
809extern template class DenseResourceElementsAttrBase<float>;
810extern template class DenseResourceElementsAttrBase<double>;
811} // namespace detail
812
813// Public names for all the supported DenseResourceElementsAttr.
814
815using DenseBoolResourceElementsAttr =
816 detail::DenseResourceElementsAttrBase<bool>;
817using DenseI8ResourceElementsAttr =
818 detail::DenseResourceElementsAttrBase<int8_t>;
819using DenseI16ResourceElementsAttr =
820 detail::DenseResourceElementsAttrBase<int16_t>;
821using DenseI32ResourceElementsAttr =
822 detail::DenseResourceElementsAttrBase<int32_t>;
823using DenseI64ResourceElementsAttr =
824 detail::DenseResourceElementsAttrBase<int64_t>;
825using DenseUI8ResourceElementsAttr =
826 detail::DenseResourceElementsAttrBase<uint8_t>;
827using DenseUI16ResourceElementsAttr =
828 detail::DenseResourceElementsAttrBase<uint16_t>;
829using DenseUI32ResourceElementsAttr =
830 detail::DenseResourceElementsAttrBase<uint32_t>;
831using DenseUI64ResourceElementsAttr =
832 detail::DenseResourceElementsAttrBase<uint64_t>;
833using DenseF32ResourceElementsAttr =
834 detail::DenseResourceElementsAttrBase<float>;
835using 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.
844class BoolAttr : public Attribute {
845public:
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.
869class FlatSymbolRefAttr : public SymbolRefAttr {
870public:
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
900private:
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.
911class DenseFPElementsAttr : public DenseIntOrFPElementsAttr {
912public:
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.
950class DenseIntElementsAttr : public DenseIntOrFPElementsAttr {
951public:
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
988template <typename T>
989auto 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
1013namespace detail {
1014struct DistinctAttrStorage;
1015class 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.
1034class DistinctAttr
1035 : public detail::StorageUserBase<DistinctAttr, Attribute,
1036 detail::DistinctAttrStorage,
1037 detail::DistinctAttributeUniquer> {
1038public:
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.
1057inline bool operator==(StringAttr lhs, std::nullptr_t) { return !lhs; }
1058inline bool operator!=(StringAttr lhs, std::nullptr_t) {
1059 return static_cast<bool>(lhs);
1060}
1061inline bool operator==(StringAttr lhs, StringAttr rhs) {
1062 return (Attribute)lhs == (Attribute)rhs;
1063}
1064inline bool operator!=(StringAttr lhs, StringAttr rhs) { return !(lhs == rhs); }
1065
1066/// Allow direct comparison with StringRef.
1067inline bool operator==(StringAttr lhs, StringRef rhs) {
1068 return lhs.getValue() == rhs;
1069}
1070inline bool operator!=(StringAttr lhs, StringRef rhs) { return !(lhs == rhs); }
1071inline bool operator==(StringRef lhs, StringAttr rhs) {
1072 return rhs.getValue() == lhs;
1073}
1074inline bool operator!=(StringRef lhs, StringAttr rhs) { return !(lhs == rhs); }
1075
1076} // namespace mlir
1077
1078//===----------------------------------------------------------------------===//
1079// Attribute Utilities
1080//===----------------------------------------------------------------------===//
1081
1082namespace 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)
1101AffineMap makeStridedLinearLayoutMap(ArrayRef<int64_t> strides, int64_t offset,
1102 MLIRContext *context);
1103
1104} // namespace mlir
1105
1106namespace llvm {
1107
1108template <>
1109struct 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};
1119template <>
1120struct 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
1127template <>
1128struct 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
1135template <>
1136struct 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

source code of mlir/include/mlir/IR/BuiltinAttributes.h