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