xref: /llvm-project/mlir/include/mlir/IR/BuiltinAttributes.td (revision 72e8b9aeaa3f584f223bc59924812df69a09a48b)
1//===- BuiltinAttributes.td - Builtin attr definitions -----*- tablegen -*-===//
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// Defines the set of builtin MLIR types, or the set of types necessary for the
10// validity of and defining the IR.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef BUILTIN_ATTRIBUTES
15#define BUILTIN_ATTRIBUTES
16
17include "mlir/IR/AttrTypeBase.td"
18include "mlir/IR/BuiltinDialect.td"
19include "mlir/IR/BuiltinAttributeInterfaces.td"
20include "mlir/IR/OpAsmInterface.td"
21
22// TODO: Currently the attributes defined in this file are prefixed with
23// `Builtin_`.  This is to differentiate the attributes here with the ones in
24// OpBase.td. We should remove the definitions in OpBase.td, and repoint users
25// to this file instead.
26
27// Base class for Builtin dialect attributes.
28class Builtin_Attr<string name, string attrMnemonic, list<Trait> traits = [],
29                   string baseCppClass = "::mlir::Attribute">
30    : AttrDef<Builtin_Dialect, name, traits, baseCppClass> {
31  let mnemonic = ?;
32  let attrName = "builtin." # attrMnemonic;
33}
34
35//===----------------------------------------------------------------------===//
36// AffineMapAttr
37//===----------------------------------------------------------------------===//
38
39def Builtin_AffineMapAttr : Builtin_Attr<"AffineMap", "affine_map", [
40    MemRefLayoutAttrInterface
41  ]> {
42  let summary = "An Attribute containing an AffineMap object";
43  let description = [{
44    Syntax:
45
46    ```
47    affine-map-attribute ::= `affine_map` `<` affine-map `>`
48    ```
49
50    Examples:
51
52    ```mlir
53    affine_map<(d0) -> (d0)>
54    affine_map<(d0, d1, d2) -> (d0, d1)>
55    ```
56  }];
57  let parameters = (ins "AffineMap":$value);
58  let builders = [
59    AttrBuilderWithInferredContext<(ins "AffineMap":$value), [{
60      return $_get(value.getContext(), value);
61    }]>
62  ];
63  let extraClassDeclaration = [{
64    using ValueType = AffineMap;
65    AffineMap getAffineMap() const { return getValue(); }
66  }];
67  let skipDefaultBuilders = 1;
68}
69
70//===----------------------------------------------------------------------===//
71// ArrayAttr
72//===----------------------------------------------------------------------===//
73
74def Builtin_ArrayAttr : Builtin_Attr<"Array", "array"> {
75  let summary = "A collection of other Attribute values";
76  let description = [{
77    Syntax:
78
79    ```
80    array-attribute ::= `[` (attribute-value (`,` attribute-value)*)? `]`
81    ```
82
83    An array attribute is an attribute that represents a collection of attribute
84    values.
85
86    Examples:
87
88    ```mlir
89    []
90    [10, i32]
91    [affine_map<(d0, d1, d2) -> (d0, d1)>, i32, "string attribute"]
92    ```
93  }];
94  let parameters = (ins ArrayRefParameter<"Attribute", "">:$value);
95  let extraClassDeclaration = [{
96    using ValueType = ArrayRef<Attribute>;
97
98    /// Return the element at the given index.
99    Attribute operator[](unsigned idx) const {
100      assert(idx < size() && "index out of bounds");
101      return getValue()[idx];
102    }
103
104    /// Support range iteration.
105    using iterator = llvm::ArrayRef<Attribute>::iterator;
106    iterator begin() const { return getValue().begin(); }
107    iterator end() const { return getValue().end(); }
108    size_t size() const { return getValue().size(); }
109    bool empty() const { return size() == 0; }
110
111  private:
112    /// Class for underlying value iterator support.
113    template <typename AttrTy>
114    class attr_value_iterator final
115        : public llvm::mapped_iterator<ArrayAttr::iterator,
116                                       AttrTy (*)(Attribute)> {
117    public:
118      explicit attr_value_iterator(ArrayAttr::iterator it)
119          : llvm::mapped_iterator<ArrayAttr::iterator, AttrTy (*)(Attribute)>(
120                it, [](Attribute attr) { return ::llvm::cast<AttrTy>(attr); }) {}
121      AttrTy operator*() const { return ::llvm::cast<AttrTy>(*this->I); }
122    };
123
124  public:
125    template <typename AttrTy>
126    iterator_range<attr_value_iterator<AttrTy>> getAsRange() const {
127      return llvm::make_range(attr_value_iterator<AttrTy>(begin()),
128                              attr_value_iterator<AttrTy>(end()));
129    }
130    template <typename AttrTy,
131              typename UnderlyingTy = typename AttrTy::ValueType>
132    auto getAsValueRange() const {
133      return llvm::map_range(getAsRange<AttrTy>(), [](AttrTy attr) {
134        return static_cast<UnderlyingTy>(attr.getValue());
135      });
136    }
137  }];
138}
139
140//===----------------------------------------------------------------------===//
141// DenseArrayAttr
142//===----------------------------------------------------------------------===//
143
144def Builtin_DenseArrayRawDataParameter : ArrayRefParameter<
145    "char", "64-bit aligned storage for dense array elements"> {
146  let allocator = [{
147    if (!$_self.empty()) {
148      auto *alloc = static_cast<char *>(
149          $_allocator.allocate($_self.size(), alignof(uint64_t)));
150      std::uninitialized_copy($_self.begin(), $_self.end(), alloc);
151      $_dst = ArrayRef<char>(alloc, $_self.size());
152    }
153  }];
154}
155
156def Builtin_DenseArray : Builtin_Attr<"DenseArray", "dense_array",
157    [BlobAttrInterface]> {
158  let summary = "A dense array of integer or floating point elements.";
159  let description = [{
160    A dense array attribute is an attribute that represents a dense array of
161    primitive element types. Contrary to DenseIntOrFPElementsAttr this is a
162    flat unidimensional array which does not have a storage optimization for
163    splat. This allows to expose the raw array through a C++ API as
164    `ArrayRef<T>` for compatible types. The element type must be bool or an
165    integer or float whose bitwidth is a multiple of 8. Bool elements are stored
166    as bytes.
167
168    This is the base class attribute. Access to C++ types is intended to be
169    managed through the subclasses `DenseI8ArrayAttr`, `DenseI16ArrayAttr`,
170    `DenseI32ArrayAttr`, `DenseI64ArrayAttr`, `DenseF32ArrayAttr`,
171    and `DenseF64ArrayAttr`.
172
173    Syntax:
174
175    ```
176    dense-array-attribute ::= `array` `<` (integer-type | float-type)
177                                          (`:` tensor-literal)? `>`
178    ```
179    Examples:
180
181    ```mlir
182    array<i8>
183    array<i32: 10, 42>
184    array<f64: 42., 12.>
185    ```
186
187    When a specific subclass is used as argument of an operation, the
188    declarative assembly will omit the type and print directly:
189
190    ```mlir
191    [1, 2, 3]
192    ```
193  }];
194
195  let parameters = (ins
196    "Type":$elementType,
197    "int64_t":$size,
198    Builtin_DenseArrayRawDataParameter:$rawData
199  );
200
201  let builders = [
202    AttrBuilderWithInferredContext<(ins "Type":$elementType, "unsigned":$size,
203                                        "ArrayRef<char>":$rawData), [{
204      return $_get(elementType.getContext(), elementType, size, rawData);
205    }]>,
206  ];
207
208  let genVerifyDecl = 1;
209
210  let extraClassDeclaration = [{
211    /// Get the number of elements in the array.
212    int64_t size() const { return getSize(); }
213    /// Return true if there are no elements in the dense array.
214    bool empty() const { return !size(); }
215    /// BlobAttrInterface method.
216    ArrayRef<char> getData() {
217      return getRawData();
218    }
219  }];
220}
221
222//===----------------------------------------------------------------------===//
223// DenseIntOrFPElementsAttr
224//===----------------------------------------------------------------------===//
225
226def Builtin_DenseIntOrFPElementsAttr : Builtin_Attr<
227    "DenseIntOrFPElements", "dense_int_or_fp_elements", [ElementsAttrInterface],
228    "DenseElementsAttr"
229  > {
230  let summary = "An Attribute containing a dense multi-dimensional array of "
231                "integer or floating-point values";
232  let description = [{
233    Syntax:
234
235    ```
236    tensor-literal ::= integer-literal | float-literal | bool-literal | [] | [tensor-literal (, tensor-literal)* ]
237    dense-intorfloat-elements-attribute ::= `dense` `<` tensor-literal `>` `:`
238                                            ( tensor-type | vector-type )
239    ```
240
241    A dense int-or-float elements attribute is an elements attribute containing
242    a densely packed vector or tensor of integer or floating-point values. The
243    element type of this attribute is required to be either an `IntegerType` or
244    a `FloatType`.
245
246    Examples:
247
248    ```
249    // A splat tensor of integer values.
250    dense<10> : tensor<2xi32>
251    // A tensor of 2 float32 elements.
252    dense<[10.0, 11.0]> : tensor<2xf32>
253    ```
254  }];
255  let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
256                        "ArrayRef<char>":$rawData);
257  let extraClassDeclaration = [{
258    using DenseElementsAttr::empty;
259    using DenseElementsAttr::getNumElements;
260    using DenseElementsAttr::getElementType;
261    using DenseElementsAttr::getValues;
262    using DenseElementsAttr::isSplat;
263    using DenseElementsAttr::size;
264    using DenseElementsAttr::value_begin;
265
266    /// The set of data types that can be iterated by this attribute.
267    using ContiguousIterableTypesT = std::tuple<
268      // Integer types.
269      uint8_t, uint16_t, uint32_t, uint64_t,
270      int8_t, int16_t, int32_t, int64_t,
271      short, unsigned short, int, unsigned, long, unsigned long,
272      std::complex<uint8_t>, std::complex<uint16_t>, std::complex<uint32_t>,
273      std::complex<uint64_t>,
274      std::complex<int8_t>, std::complex<int16_t>, std::complex<int32_t>,
275      std::complex<int64_t>,
276      // Float types.
277      float, double, std::complex<float>, std::complex<double>
278    >;
279    using NonContiguousIterableTypesT = std::tuple<
280      Attribute,
281      // Integer types.
282      APInt, bool, std::complex<APInt>,
283      // Float types.
284      APFloat, std::complex<APFloat>
285    >;
286
287    /// Provide a `try_value_begin_impl` to enable iteration within
288    /// ElementsAttr.
289    template <typename T>
290    auto try_value_begin_impl(OverloadToken<T>) const {
291      return try_value_begin<T>();
292    }
293
294    /// Convert endianess of input ArrayRef for big-endian(BE) machines. All of
295    /// the elements of `inRawData` has `type`. If `inRawData` is little endian
296    /// (LE), it is converted to big endian (BE). Conversely, if `inRawData` is
297    /// BE, converted to LE.
298    static void
299    convertEndianOfArrayRefForBEmachine(ArrayRef<char> inRawData,
300                                        MutableArrayRef<char> outRawData,
301                                        ShapedType type);
302
303    /// Convert endianess of input for big-endian(BE) machines. The number of
304    /// elements of `inRawData` is `numElements`, and each element has
305    /// `elementBitWidth` bits. If `inRawData` is little endian (LE), it is
306    /// converted to big endian (BE) and saved in `outRawData`. Conversely, if
307    /// `inRawData` is BE, converted to LE.
308    static void convertEndianOfCharForBEmachine(const char *inRawData,
309                                                char *outRawData,
310                                                size_t elementBitWidth,
311                                                size_t numElements);
312
313  protected:
314    friend DenseElementsAttr;
315
316    /// Constructs a dense elements attribute from an array of raw APFloat
317    /// values. Each APFloat value is expected to have the same bitwidth as the
318    /// element type of 'type'. 'type' must be a vector or tensor with static
319    /// shape.
320    ///
321    /// If the `values` array only has a single element, then this constructs
322    /// splat of that value.
323    static DenseElementsAttr getRaw(ShapedType type, size_t storageWidth,
324                                    ArrayRef<APFloat> values);
325
326    /// Constructs a dense elements attribute from an array of raw APInt values.
327    /// Each APInt value is expected to have the same bitwidth as the element
328    /// type of 'type'. 'type' must be a vector or tensor with static shape.
329    ///
330    /// If the `values` array only has a single element, then this constructs
331    /// splat of that value.
332    static DenseElementsAttr getRaw(ShapedType type, size_t storageWidth,
333                                    ArrayRef<APInt> values);
334
335    /// Get or create a new dense elements attribute instance with the given raw
336    /// data buffer. 'type' must be a vector or tensor with static shape.
337    ///
338    /// If the `values` array only has a single element, then this constructs
339    /// splat of that value.
340    static DenseElementsAttr getRaw(ShapedType type, ArrayRef<char> data);
341
342    /// Overload of the raw 'get' method that asserts that the given type is of
343    /// complex type. This method is used to verify type invariants that the
344    /// templatized 'get' method cannot.
345    static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef<char> data,
346                                           int64_t dataEltSize, bool isInt,
347                                           bool isSigned);
348
349    /// Overload of the raw 'get' method that asserts that the given type is of
350    /// integer or floating-point type. This method is used to verify type
351    /// invariants that the templatized 'get' method cannot.
352    static DenseElementsAttr getRawIntOrFloat(ShapedType type,
353                                              ArrayRef<char> data,
354                                              int64_t dataEltSize, bool isInt,
355                                              bool isSigned);
356  public:
357  }];
358  let genAccessors = 0;
359  let genStorageClass = 0;
360  let skipDefaultBuilders = 1;
361}
362
363//===----------------------------------------------------------------------===//
364// DenseStringElementsAttr
365//===----------------------------------------------------------------------===//
366
367def Builtin_DenseStringElementsAttr : Builtin_Attr<
368    "DenseStringElements", "dense_string_elements", [ElementsAttrInterface],
369    "DenseElementsAttr"
370  > {
371  let summary = "An Attribute containing a dense multi-dimensional array of "
372                "strings";
373  let description = [{
374    Syntax:
375
376    ```
377    dense-string-elements-attribute ::= `dense` `<` attribute-value `>` `:`
378                                        ( tensor-type | vector-type )
379    ```
380
381    A dense string elements attribute is an elements attribute containing a
382    densely packed vector or tensor of string values. There are no restrictions
383    placed on the element type of this attribute, enabling the use of dialect
384    specific string types.
385
386    Examples:
387
388    ```
389    // A splat tensor of strings.
390    dense<"example"> : tensor<2x!foo.string>
391    // A tensor of 2 string elements.
392    dense<["example1", "example2"]> : tensor<2x!foo.string>
393    ```
394  }];
395  let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
396                        "ArrayRef<StringRef>":$value);
397  let builders = [
398    AttrBuilderWithInferredContext<(ins "ShapedType":$type,
399                                        "ArrayRef<StringRef>":$values), [{
400      return $_get(type.getContext(), type, values,
401                   /* isSplat */(values.size() == 1));
402    }]>,
403  ];
404  let extraClassDeclaration = [{
405    using DenseElementsAttr::empty;
406    using DenseElementsAttr::getNumElements;
407    using DenseElementsAttr::getElementType;
408    using DenseElementsAttr::getValues;
409    using DenseElementsAttr::isSplat;
410    using DenseElementsAttr::size;
411    using DenseElementsAttr::value_begin;
412
413    /// The set of data types that can be iterated by this attribute.
414    using ContiguousIterableTypesT = std::tuple<StringRef>;
415    using NonContiguousIterableTypesT = std::tuple<Attribute>;
416
417    /// Provide a `try_value_begin_impl` to enable iteration within
418    /// ElementsAttr.
419    template <typename T>
420    auto try_value_begin_impl(OverloadToken<T>) const {
421      return try_value_begin<T>();
422    }
423
424  protected:
425    friend DenseElementsAttr;
426
427  public:
428  }];
429  let genAccessors = 0;
430  let genStorageClass = 0;
431  let skipDefaultBuilders = 1;
432}
433
434//===----------------------------------------------------------------------===//
435// DenseResourceElementsAttr
436//===----------------------------------------------------------------------===//
437
438def Builtin_DenseResourceElementsAttr : Builtin_Attr<"DenseResourceElements",
439    "dense_resource_elements", [ElementsAttrInterface, BlobAttrInterface]> {
440  let summary = "An Attribute containing a dense multi-dimensional array "
441                "backed by a resource";
442  let description = [{
443    Syntax:
444
445    ```
446    dense-resource-elements-attribute ::=
447      `dense_resource` `<` resource-handle `>` `:` shaped-type
448    ```
449
450    A dense resource elements attribute is an elements attribute backed by a
451    handle to a builtin dialect resource containing a densely packed array of
452    values. This class provides the low-level attribute, which should only be
453    interacted with in very generic terms, actual access to the underlying
454    resource data is intended to be managed through one of the subclasses, such
455    as; `DenseBoolResourceElementsAttr`, `DenseUI64ResourceElementsAttr`,
456    `DenseI32ResourceElementsAttr`, `DenseF32ResourceElementsAttr`,
457    `DenseF64ResourceElementsAttr`, etc.
458
459    Examples:
460
461    ```mlir
462    "example.user_op"() {attr = dense_resource<blob1> : tensor<3xi64> } : () -> ()
463
464    {-#
465    dialect_resources: {
466        builtin: {
467          blob1: "0x08000000010000000000000002000000000000000300000000000000"
468        }
469      }
470    #-}
471    ```
472  }];
473  let parameters = (ins
474    AttributeSelfTypeParameter<"", "ShapedType">:$type,
475    ResourceHandleParameter<"DenseResourceElementsHandle">:$rawHandle
476  );
477  let builders = [
478    AttrBuilderWithInferredContext<(ins
479      "ShapedType":$type, "DenseResourceElementsHandle":$handle
480    )>,
481    /// A builder that inserts a new resource into the builtin dialect's blob
482    /// manager using the provided blob. The handle of the inserted blob is used
483    /// when building the attribute. The provided `blobName` is used as a hint
484    /// for the key of the new handle for the `blob` resource, but may be
485    /// changed if necessary to ensure uniqueness during insertion.
486    /// This base class builder does no element type specific size or alignment
487    /// checking. Use the typed subclasses for more safety unless if performing
488    /// generic operations.
489    AttrBuilderWithInferredContext<(ins
490      "ShapedType":$type, "StringRef":$blobName, "AsmResourceBlob":$blob
491    )>
492  ];
493  let extraClassDeclaration = [{
494    /// BlobAttrInterface method.
495    ArrayRef<char> getData();
496  }];
497
498  let skipDefaultBuilders = 1;
499}
500
501//===----------------------------------------------------------------------===//
502// DictionaryAttr
503//===----------------------------------------------------------------------===//
504
505def Builtin_DictionaryAttr : Builtin_Attr<"Dictionary", "dictionary"> {
506  let summary = "An dictionary of named Attribute values";
507  let description = [{
508    Syntax:
509
510    ```
511    dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`
512    ```
513
514    A dictionary attribute is an attribute that represents a sorted collection of
515    named attribute values. The elements are sorted by name, and each name must be
516    unique within the collection.
517
518    Examples:
519
520    ```mlir
521    {}
522    {attr_name = "string attribute"}
523    {int_attr = 10, "string attr name" = "string attribute"}
524    ```
525  }];
526  let parameters = (ins ArrayRefParameter<"NamedAttribute", "">:$value);
527  let builders = [
528    AttrBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "std::nullopt">:$value)>
529  ];
530  let extraClassDeclaration = [{
531    using ValueType = ArrayRef<NamedAttribute>;
532
533    /// Construct a dictionary with an array of values that is known to already
534    /// be sorted by name and uniqued.
535    static DictionaryAttr getWithSorted(MLIRContext *context,
536                                        ArrayRef<NamedAttribute> value);
537
538    /// Return the specified attribute if present, null otherwise.
539    Attribute get(StringRef name) const;
540    Attribute get(StringAttr name) const;
541
542    /// Return the specified named attribute if present, std::nullopt otherwise.
543    std::optional<NamedAttribute> getNamed(StringRef name) const;
544    std::optional<NamedAttribute> getNamed(StringAttr name) const;
545
546    /// Return whether the specified attribute is present.
547    bool contains(StringRef name) const;
548    bool contains(StringAttr name) const;
549
550    /// Support range iteration.
551    using iterator = llvm::ArrayRef<NamedAttribute>::iterator;
552    iterator begin() const;
553    iterator end() const;
554    bool empty() const { return size() == 0; }
555    size_t size() const;
556
557    /// Sorts the NamedAttributes in the array ordered by name as expected by
558    /// getWithSorted and returns whether the values were sorted.
559    /// Requires: uniquely named attributes.
560    static bool sort(ArrayRef<NamedAttribute> values,
561                     SmallVectorImpl<NamedAttribute> &storage);
562
563    /// Sorts the NamedAttributes in the array ordered by name as expected by
564    /// getWithSorted in place on an array and returns whether the values needed
565    /// to be sorted.
566    /// Requires: uniquely named attributes.
567    static bool sortInPlace(SmallVectorImpl<NamedAttribute> &array);
568
569    /// Returns an entry with a duplicate name in `array`, if it exists, else
570    /// returns std::nullopt. If `isSorted` is true, the array is assumed to be
571    /// sorted else it will be sorted in place before finding the duplicate entry.
572    static std::optional<NamedAttribute>
573    findDuplicate(SmallVectorImpl<NamedAttribute> &array, bool isSorted);
574
575    /// Return the specified attribute if present and is an instance of
576    /// `AttrClass`, null otherwise.
577    template<typename AttrClass, typename NameClass>
578    AttrClass getAs(NameClass &&name) const {
579      return llvm::dyn_cast_or_null<AttrClass>(
580               get(std::forward<NameClass>(name)));
581    }
582
583  private:
584    /// Return empty dictionary.
585    static DictionaryAttr getEmpty(MLIRContext *context);
586
587    /// Return empty dictionary. This is a special variant of the above method
588    /// that is used by the MLIRContext to cache the empty dictionary instance.
589    static DictionaryAttr getEmptyUnchecked(MLIRContext *context);
590
591    /// Allow access to `getEmptyUnchecked`.
592    friend MLIRContext;
593
594  public:
595  }];
596  let skipDefaultBuilders = 1;
597}
598
599//===----------------------------------------------------------------------===//
600// FloatAttr
601//===----------------------------------------------------------------------===//
602
603def Builtin_FloatAttr : Builtin_Attr<"Float", "float", [TypedAttrInterface]> {
604  let summary = "An Attribute containing a floating-point value";
605  let description = [{
606    Syntax:
607
608    ```
609    float-attribute ::= (float-literal (`:` float-type)?)
610                      | (hexadecimal-literal `:` float-type)
611    ```
612
613    A float attribute is a literal attribute that represents a floating point
614    value of the specified [float type](#floating-point-types). It can be
615    represented in the hexadecimal form where the hexadecimal value is
616    interpreted as bits of the underlying binary representation. This form is
617    useful for representing infinity and NaN floating point values. To avoid
618    confusion with integer attributes, hexadecimal literals _must_ be followed
619    by a float type to define a float attribute.
620
621    Examples:
622
623    ```
624    42.0         // float attribute defaults to f64 type
625    42.0 : f32   // float attribute of f32 type
626    0x7C00 : f16 // positive infinity
627    0x7CFF : f16 // NaN (one of possible values)
628    42 : f32     // Error: expected integer type
629    ```
630  }];
631  let parameters = (ins AttributeSelfTypeParameter<"">:$type,
632                        APFloatParameter<"">:$value);
633  let builders = [
634    AttrBuilderWithInferredContext<(ins "Type":$type,
635                                        "const APFloat &":$value), [{
636      return $_get(type.getContext(), type, value);
637    }]>,
638    AttrBuilderWithInferredContext<(ins "Type":$type, "double":$value), [{
639      if (type.isF64() || !::llvm::isa<FloatType>(type))
640        return $_get(type.getContext(), type, APFloat(value));
641
642      // This handles, e.g., F16 because there is no APFloat constructor for it.
643      bool unused;
644      APFloat val(value);
645      val.convert(::llvm::cast<FloatType>(type).getFloatSemantics(),
646                  APFloat::rmNearestTiesToEven, &unused);
647      return $_get(type.getContext(), type, val);
648    }]>
649  ];
650  let extraClassDeclaration = [{
651    using ValueType = APFloat;
652
653    /// This function is used to convert the value to a double, even if it loses
654    /// precision.
655    double getValueAsDouble() const;
656    static double getValueAsDouble(APFloat val);
657  }];
658  let genVerifyDecl = 1;
659  let skipDefaultBuilders = 1;
660}
661
662//===----------------------------------------------------------------------===//
663// IntegerAttr
664//===----------------------------------------------------------------------===//
665
666def Builtin_IntegerAttr : Builtin_Attr<"Integer", "integer",
667    [TypedAttrInterface]> {
668  let summary = "An Attribute containing a integer value";
669  let description = [{
670    Syntax:
671
672    ```
673    integer-attribute ::= (integer-literal ( `:` (index-type | integer-type) )?)
674                          | `true` | `false`
675    ```
676
677    An integer attribute is a literal attribute that represents an integral
678    value of the specified integer or index type. `i1` integer attributes are
679    treated as `boolean` attributes, and use a unique assembly format of either
680    `true` or `false` depending on the value. The default type for non-boolean
681    integer attributes, if a type is not specified, is signless 64-bit integer.
682
683    Examples:
684
685    ```mlir
686    10 : i32
687    10    // : i64 is implied here.
688    true  // A bool, i.e. i1, value.
689    false // A bool, i.e. i1, value.
690    ```
691  }];
692  let parameters = (ins AttributeSelfTypeParameter<"">:$type, "APInt":$value);
693  let builders = [
694    AttrBuilderWithInferredContext<(ins "Type":$type,
695                                        "const APInt &":$value), [{
696      if (type.isSignlessInteger(1))
697        return BoolAttr::get(type.getContext(), value.getBoolValue());
698      return $_get(type.getContext(), type, value);
699    }]>,
700    AttrBuilder<(ins "const APSInt &":$value), [{
701      auto signedness = value.isSigned() ?
702        IntegerType::Signed : IntegerType::Unsigned;
703      auto type = IntegerType::get($_ctxt, value.getBitWidth(), signedness);
704      return $_get(type.getContext(), type, value);
705    }]>,
706    AttrBuilderWithInferredContext<(ins "Type":$type, "int64_t":$value), [{
707      // `index` has a defined internal storage width.
708      if (type.isIndex()) {
709        APInt apValue(IndexType::kInternalStorageBitWidth, value);
710        return $_get(type.getContext(), type, apValue);
711      }
712
713      // TODO: Avoid implicit trunc?
714      // See https://github.com/llvm/llvm-project/issues/112510.
715      IntegerType intTy = ::llvm::cast<IntegerType>(type);
716      APInt apValue(intTy.getWidth(), value, intTy.isSignedInteger(),
717                    /*implicitTrunc=*/true);
718      return $_get(type.getContext(), type, apValue);
719    }]>
720  ];
721  let extraClassDeclaration = [{
722    using ValueType = APInt;
723
724    /// Return the integer value as a 64-bit int. The attribute must be a
725    /// signless integer.
726    // TODO: Change callers to use getValue instead.
727    int64_t getInt() const;
728    /// Return the integer value as a signed 64-bit int. The attribute must be
729    /// a signed integer.
730    int64_t getSInt() const;
731    /// Return the integer value as a unsigned 64-bit int. The attribute must be
732    /// an unsigned integer.
733    uint64_t getUInt() const;
734
735    /// Return the value as an APSInt which carries the signed from the type of
736    /// the attribute.  This traps on signless integers types!
737    APSInt getAPSInt() const;
738
739  private:
740    /// Return a boolean attribute. This is a special variant of the `get`
741    /// method that is used by the MLIRContext to cache the boolean IntegerAttr
742    /// instances.
743    static BoolAttr getBoolAttrUnchecked(IntegerType type, bool value);
744
745    /// Allow access to `getBoolAttrUnchecked`.
746    friend MLIRContext;
747
748  public:
749  }];
750  let genVerifyDecl = 1;
751  let skipDefaultBuilders = 1;
752}
753
754//===----------------------------------------------------------------------===//
755// IntegerSetAttr
756//===----------------------------------------------------------------------===//
757
758def Builtin_IntegerSetAttr : Builtin_Attr<"IntegerSet", "integer_set"> {
759  let summary = "An Attribute containing an IntegerSet object";
760  let description = [{
761    Syntax:
762
763    ```
764    integer-set-attribute ::= `affine_set` `<` integer-set `>`
765    ```
766
767    Examples:
768
769    ```mlir
770    affine_set<(d0) : (d0 - 2 >= 0)>
771    ```
772  }];
773  let parameters = (ins "IntegerSet":$value);
774  let builders = [
775    AttrBuilderWithInferredContext<(ins "IntegerSet":$value), [{
776      return $_get(value.getContext(), value);
777    }]>
778  ];
779  let extraClassDeclaration = "using ValueType = IntegerSet;";
780  let skipDefaultBuilders = 1;
781}
782
783//===----------------------------------------------------------------------===//
784// OpaqueAttr
785//===----------------------------------------------------------------------===//
786
787def Builtin_OpaqueAttr : Builtin_Attr<"Opaque", "opaque",
788    [TypedAttrInterface]> {
789  let summary = "An opaque representation of another Attribute";
790  let description = [{
791    Syntax:
792
793    ```
794    opaque-attribute ::= dialect-namespace `<` attr-data `>`
795    ```
796
797    Opaque attributes represent attributes of non-registered dialects. These are
798    attribute represented in their raw string form, and can only usefully be
799    tested for attribute equality.
800
801    Examples:
802
803    ```mlir
804    #dialect<"opaque attribute data">
805    ```
806  }];
807  let parameters = (ins "StringAttr":$dialectNamespace,
808                        StringRefParameter<"">:$attrData,
809                        AttributeSelfTypeParameter<"">:$type);
810  let builders = [
811    AttrBuilderWithInferredContext<(ins "StringAttr":$dialect,
812                                        "StringRef":$attrData,
813                                        "Type":$type), [{
814      return $_get(dialect.getContext(), dialect, attrData, type);
815    }]>
816  ];
817  let genVerifyDecl = 1;
818  let skipDefaultBuilders = 1;
819}
820
821//===----------------------------------------------------------------------===//
822// SparseElementsAttr
823//===----------------------------------------------------------------------===//
824
825def Builtin_SparseElementsAttr : Builtin_Attr<
826    "SparseElements", "sparse_elements", [ElementsAttrInterface]
827  > {
828  let summary = "An opaque representation of a multi-dimensional array";
829  let description = [{
830    Syntax:
831
832    ```
833    sparse-elements-attribute ::= `sparse` `<` attribute-value `,`
834                                  attribute-value `>` `:`
835                                  ( tensor-type | vector-type )
836    ```
837
838    A sparse elements attribute is an elements attribute that represents a
839    sparse vector or tensor object. This is where very few of the elements are
840    non-zero.
841
842    The attribute uses COO (coordinate list) encoding to represent the sparse
843    elements of the elements attribute. The indices are stored via a 2-D tensor
844    of 64-bit integer elements with shape [N, ndims], which specifies the
845    indices of the elements in the sparse tensor that contains non-zero values.
846    The element values are stored via a 1-D tensor with shape [N], that supplies
847    the corresponding values for the indices.
848
849    Example:
850
851    ```mlir
852    sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>
853
854    // This represents the following tensor:
855    ///  [[1, 0, 0, 0],
856    ///   [0, 0, 5, 0],
857    ///   [0, 0, 0, 0]]
858    ```
859  }];
860
861  let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
862                        "DenseIntElementsAttr":$indices,
863                        "DenseElementsAttr":$values);
864  let builders = [
865    AttrBuilderWithInferredContext<(ins "ShapedType":$type,
866                                        "DenseElementsAttr":$indices,
867                                        "DenseElementsAttr":$values), [{
868      assert(indices.getType().getElementType().isInteger(64) &&
869             "expected sparse indices to be 64-bit integer values");
870      assert((::llvm::isa<RankedTensorType, VectorType>(type)) &&
871             "type must be ranked tensor or vector");
872      assert(type.hasStaticShape() && "type must have static shape");
873      return $_get(type.getContext(), type,
874                   ::llvm::cast<DenseIntElementsAttr>(indices), values);
875    }]>,
876  ];
877  let extraClassDeclaration = [{
878    /// The set of data types that can be iterated by this attribute.
879    // FIXME: Realistically, SparseElementsAttr could use ElementsAttr for the
880    // value storage. This would mean dispatching to `values` when accessing
881    // values. For now, we just add the types that can be iterated by
882    // DenseElementsAttr.
883    using NonContiguousIterableTypesT = std::tuple<
884      Attribute,
885      // Integer types.
886      APInt, bool, uint8_t, uint16_t, uint32_t, uint64_t,
887      int8_t, int16_t, int32_t, int64_t,
888      short, unsigned short, int, unsigned, long, unsigned long,
889      std::complex<APInt>, std::complex<uint8_t>, std::complex<uint16_t>,
890      std::complex<uint32_t>, std::complex<uint64_t>, std::complex<int8_t>,
891      std::complex<int16_t>, std::complex<int32_t>, std::complex<int64_t>,
892      // Float types.
893      APFloat, float, double,
894      std::complex<APFloat>, std::complex<float>, std::complex<double>,
895      // String types.
896      StringRef
897    >;
898    using ElementsAttr::Trait<SparseElementsAttr>::getValues;
899    using ElementsAttr::Trait<SparseElementsAttr>::value_begin;
900
901    template <typename T>
902    using iterator =
903        llvm::mapped_iterator<typename decltype(llvm::seq<ptrdiff_t>(0, 0))::iterator,
904                              std::function<T(ptrdiff_t)>>;
905
906    /// Provide a `try_value_begin_impl` to enable iteration within
907    /// ElementsAttr.
908    template <typename T>
909    FailureOr<iterator<T>> try_value_begin_impl(OverloadToken<T>) const;
910
911  private:
912    /// Get a zero APFloat for the given sparse attribute.
913    APFloat getZeroAPFloat() const;
914
915    /// Get a zero APInt for the given sparse attribute.
916    APInt getZeroAPInt() const;
917
918    /// Get a zero attribute for the given sparse attribute.
919    Attribute getZeroAttr() const;
920
921    /// Utility methods to generate a zero value of some type 'T'. This is used
922    /// by the 'iterator' class.
923    /// Get a zero for a given attribute type.
924    template <typename T>
925    std::enable_if_t<std::is_base_of<Attribute, T>::value, T>
926    getZeroValue() const {
927      return ::llvm::cast<T>(getZeroAttr());
928    }
929    /// Get a zero for an APInt.
930    template <typename T>
931    std::enable_if_t<std::is_same<APInt, T>::value, T>
932    getZeroValue() const {
933      return getZeroAPInt();
934    }
935    template <typename T>
936    std::enable_if_t<std::is_same<std::complex<APInt>, T>::value, T>
937    getZeroValue() const {
938      APInt intZero = getZeroAPInt();
939      return {intZero, intZero};
940    }
941    /// Get a zero for an APFloat.
942    template <typename T>
943    std::enable_if_t<std::is_same<APFloat, T>::value, T>
944    getZeroValue() const {
945      return getZeroAPFloat();
946    }
947    template <typename T>
948    std::enable_if_t<std::is_same<std::complex<APFloat>, T>::value, T>
949    getZeroValue() const {
950      APFloat floatZero = getZeroAPFloat();
951      return {floatZero, floatZero};
952    }
953
954    /// Get a zero for an C++ integer, float, StringRef, or complex type.
955    template <typename T>
956    std::enable_if_t<std::numeric_limits<T>::is_integer ||
957                         DenseElementsAttr::is_valid_cpp_fp_type<T>::value ||
958                         std::is_same<T, StringRef>::value ||
959                         (detail::is_complex_t<T>::value &&
960                          !llvm::is_one_of<T, std::complex<APInt>,
961                                           std::complex<APFloat>>::value),
962                     T>
963    getZeroValue() const {
964      return T();
965    }
966
967    /// Flatten, and return, all of the sparse indices in this attribute in
968    /// row-major order.
969    std::vector<ptrdiff_t> getFlattenedSparseIndices() const;
970
971  public:
972  }];
973  let genVerifyDecl = 1;
974  let skipDefaultBuilders = 1;
975}
976
977//===----------------------------------------------------------------------===//
978// StridedLayoutAttr
979//===----------------------------------------------------------------------===//
980
981def StridedLayoutAttr : Builtin_Attr<"StridedLayout", "strided_layout",
982    [DeclareAttrInterfaceMethods<MemRefLayoutAttrInterface,
983                                 ["verifyLayout"]>]> {
984  let summary = "An Attribute representing a strided layout of a shaped type";
985  let description = [{
986    Syntax:
987
988    ```
989    strided-layout-attribute ::= `strided` `<` `[` stride-list `]`
990                                 (`,` `offset` `:` dimension)? `>`
991    stride-list ::= /*empty*/
992                  | dimension (`,` dimension)*
993    dimension ::= decimal-literal | `?`
994    ```
995
996    A strided layout attribute captures layout information of the memref type in
997    the canonical form. Specifically, it contains a list of _strides_, one for
998    each dimension. A stride is the number of elements in the linear storage
999    one must step over to reflect an increment in the given dimension. For
1000    example, a `MxN` row-major contiguous shaped type would have the strides
1001    `[N, 1]`. The layout attribute also contains the _offset_ from the base
1002    pointer of the shaped type to the first effectively accessed element,
1003    expressed in terms of the number of contiguously stored elements.
1004
1005    Strides must be positive and the offset must be non-negative. Both the
1006    strides and the offset may be _dynamic_, i.e. their value may not be known
1007    at compile time. This is expressed as a `?` in the assembly syntax and as
1008    `ShapedType::kDynamic` in the code. Stride and offset values
1009    must satisfy the constraints above at runtime, the behavior is undefined
1010    otherwise.
1011
1012    See [Dialects/Builtin.md#memreftype](MemRef type) for more information.
1013  }];
1014
1015  let parameters = (ins
1016    "int64_t":$offset,
1017    ArrayRefParameter<
1018      "int64_t",
1019      "array of strides (64-bit integer)"
1020    >:$strides
1021  );
1022  let genVerifyDecl = 1;
1023
1024  let extraClassDeclaration = [{
1025    /// Print the attribute to the given output stream.
1026    void print(raw_ostream &os) const;
1027
1028    /// Returns true if this layout is static, i.e. the strides and offset all
1029    /// have a known value > 0.
1030    bool hasStaticLayout() const;
1031  }];
1032}
1033
1034
1035//===----------------------------------------------------------------------===//
1036// StringAttr
1037//===----------------------------------------------------------------------===//
1038
1039def Builtin_StringAttr : Builtin_Attr<"String", "string",
1040    [TypedAttrInterface]> {
1041  let summary = "An Attribute containing a string";
1042  let description = [{
1043    Syntax:
1044
1045    ```
1046    string-attribute ::= string-literal (`:` type)?
1047    ```
1048
1049    A string attribute is an attribute that represents a string literal value.
1050
1051    Examples:
1052
1053    ```mlir
1054    "An important string"
1055    "string with a type" : !dialect.string
1056    ```
1057  }];
1058  let parameters = (ins StringRefParameter<"">:$value,
1059                        AttributeSelfTypeParameter<"">:$type);
1060  let builders = [
1061    AttrBuilderWithInferredContext<(ins "const Twine &":$bytes, "Type":$type)>,
1062    /// Build an string attr with NoneType.
1063    AttrBuilder<(ins "const Twine &":$bytes)>,
1064    /// Build an empty string attr with NoneType.
1065    AttrBuilder<(ins)>
1066  ];
1067  let extraClassDeclaration = [{
1068    using ValueType = StringRef;
1069
1070    /// If the value of this string is prefixed with a dialect namespace,
1071    /// returns the dialect corresponding to that namespace if it is loaded,
1072    /// nullptr otherwise. For example, the string `llvm.fastmathflags` would
1073    /// return the LLVM dialect, assuming it is loaded in the context.
1074    Dialect *getReferencedDialect() const;
1075
1076    /// Enable conversion to StringRef.
1077    operator StringRef() const { return getValue(); }
1078
1079    /// Returns the underlying string value
1080    StringRef strref() const { return getValue(); }
1081
1082    /// Convert the underling value to an std::string.
1083    std::string str() const { return getValue().str(); }
1084
1085    /// Return a pointer to the start of the string data.
1086    const char *data() const { return getValue().data(); }
1087
1088    /// Return the number of bytes in this string.
1089    size_t size() const { return getValue().size(); }
1090
1091    /// Return whether the string is empty.
1092    bool empty() const { return getValue().empty(); }
1093
1094    /// Iterate over the underlying string data.
1095    StringRef::iterator begin() const { return getValue().begin(); }
1096    StringRef::iterator end() const { return getValue().end(); }
1097
1098    /// Compare the underlying string value to the one in `rhs`.
1099    int compare(StringAttr rhs) const {
1100      if (*this == rhs)
1101        return 0;
1102      return getValue().compare(rhs.getValue());
1103    }
1104
1105  private:
1106    /// Return an empty StringAttr with NoneType type. This is a special variant
1107    /// of the `get` method that is used by the MLIRContext to cache the
1108    /// instance.
1109    static StringAttr getEmptyStringAttrUnchecked(MLIRContext *context);
1110    friend MLIRContext;
1111  public:
1112  }];
1113  let genStorageClass = 0;
1114  let skipDefaultBuilders = 1;
1115}
1116
1117//===----------------------------------------------------------------------===//
1118// SymbolRefAttr
1119//===----------------------------------------------------------------------===//
1120
1121def Builtin_SymbolRefAttr : Builtin_Attr<"SymbolRef", "symbol_ref"> {
1122  let summary = "An Attribute containing a symbolic reference to an Operation";
1123  let description = [{
1124    Syntax:
1125
1126    ```
1127    symbol-ref-attribute ::= symbol-ref-id (`::` symbol-ref-id)*
1128    ```
1129
1130    A symbol reference attribute is a literal attribute that represents a named
1131    reference to an operation that is nested within an operation with the
1132    `OpTrait::SymbolTable` trait. As such, this reference is given meaning by
1133    the nearest parent operation containing the `OpTrait::SymbolTable` trait. It
1134    may optionally contain a set of nested references that further resolve to a
1135    symbol nested within a different symbol table.
1136
1137    **Rationale:** Identifying accesses to global data is critical to
1138    enabling efficient multi-threaded compilation. Restricting global
1139    data access to occur through symbols and limiting the places that can
1140    legally hold a symbol reference simplifies reasoning about these data
1141    accesses.
1142
1143    See [`Symbols And SymbolTables`](../SymbolsAndSymbolTables.md) for more
1144    information.
1145
1146    Examples:
1147
1148    ```mlir
1149    @flat_reference
1150    @parent_reference::@nested_reference
1151    ```
1152  }];
1153  let parameters =
1154     (ins "StringAttr":$rootReference,
1155          ArrayRefParameter<"FlatSymbolRefAttr", "">:$nestedReferences);
1156
1157  let builders = [
1158    AttrBuilderWithInferredContext<
1159      (ins "StringAttr":$rootReference,
1160           "ArrayRef<FlatSymbolRefAttr>":$nestedReferences), [{
1161      return $_get(rootReference.getContext(), rootReference, nestedReferences);
1162    }]>,
1163  ];
1164  let extraClassDeclaration = [{
1165    static SymbolRefAttr get(MLIRContext *ctx, StringRef value,
1166                             ArrayRef<FlatSymbolRefAttr> nestedRefs);
1167    /// Convenience getters for building a SymbolRefAttr with no path, which is
1168    /// known to produce a FlatSymbolRefAttr.
1169    static FlatSymbolRefAttr get(StringAttr value);
1170    static FlatSymbolRefAttr get(MLIRContext *ctx, StringRef value);
1171
1172    /// Convenience getter for buliding a SymbolRefAttr based on an operation
1173    /// that implements the SymbolTrait.
1174    static FlatSymbolRefAttr get(Operation *symbol);
1175
1176    /// Returns the name of the fully resolved symbol, i.e. the leaf of the
1177    /// reference path.
1178    StringAttr getLeafReference() const;
1179  }];
1180  let skipDefaultBuilders = 1;
1181}
1182
1183//===----------------------------------------------------------------------===//
1184// TypeAttr
1185//===----------------------------------------------------------------------===//
1186
1187def Builtin_TypeAttr : Builtin_Attr<"Type", "type"> {
1188  let summary = "An Attribute containing a Type";
1189  let description = [{
1190    Syntax:
1191
1192    ```
1193    type-attribute ::= type
1194    ```
1195
1196    A type attribute is an attribute that represents a
1197    [type object](#type-system).
1198
1199    Examples:
1200
1201    ```mlir
1202    i32
1203    !dialect.type
1204    ```
1205  }];
1206  let parameters = (ins "Type":$value);
1207  let builders = [
1208    AttrBuilderWithInferredContext<(ins "Type":$type), [{
1209      return $_get(type.getContext(), type);
1210    }]>,
1211  ];
1212  let extraClassDeclaration = "using ValueType = Type;";
1213  let skipDefaultBuilders = 1;
1214}
1215
1216//===----------------------------------------------------------------------===//
1217// UnitAttr
1218//===----------------------------------------------------------------------===//
1219
1220def Builtin_UnitAttr : Builtin_Attr<"Unit", "unit"> {
1221  let summary = "An Attribute value of `unit` type";
1222  let description = [{
1223    Syntax:
1224
1225    ```
1226    unit-attribute ::= `unit`
1227    ```
1228
1229    A unit attribute is an attribute that represents a value of `unit` type. The
1230    `unit` type allows only one value forming a singleton set. This attribute
1231    value is used to represent attributes that only have meaning from their
1232    existence.
1233
1234    One example of such an attribute could be the `swift.self` attribute. This
1235    attribute indicates that a function parameter is the self/context parameter.
1236    It could be represented as a [boolean attribute](#boolean-attribute)(true or
1237    false), but a value of false doesn't really bring any value. The parameter
1238    either is the self/context or it isn't.
1239
1240
1241    Examples:
1242
1243    ```mlir
1244    // A unit attribute defined with the `unit` value specifier.
1245    func.func @verbose_form() attributes {dialectName.unitAttr = unit}
1246
1247    // A unit attribute in an attribute dictionary can also be defined without
1248    // the value specifier.
1249    func.func @simple_form() attributes {dialectName.unitAttr}
1250    ```
1251  }];
1252  let extraClassDeclaration = [{
1253    static UnitAttr get(MLIRContext *context);
1254  }];
1255}
1256
1257#endif // BUILTIN_ATTRIBUTES
1258