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