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/BuiltinDialect.td"
18include "mlir/IR/SubElementInterfaces.td"
19
20// TODO: Currently the attributes defined in this file are prefixed with
21// `Builtin_`.  This is to differentiate the attributes here with the ones in
22// OpBase.td. We should remove the definitions in OpBase.td, and repoint users
23// to this file instead.
24
25// Base class for Builtin dialect attributes.
26class Builtin_Attr<string name, list<Trait> traits = [],
27                   string baseCppClass = "::mlir::Attribute">
28    : AttrDef<Builtin_Dialect, name, traits, baseCppClass> {
29  let mnemonic = ?;
30}
31
32//===----------------------------------------------------------------------===//
33// AffineMapAttr
34//===----------------------------------------------------------------------===//
35
36def Builtin_AffineMapAttr : Builtin_Attr<"AffineMap"> {
37  let summary = "An Attribute containing an AffineMap object";
38  let description = [{
39    Syntax:
40
41    ```
42    affine-map-attribute ::= `affine_map` `<` affine-map `>`
43    ```
44
45    Examples:
46
47    ```mlir
48    affine_map<(d0) -> (d0)>
49    affine_map<(d0, d1, d2) -> (d0, d1)>
50    ```
51  }];
52  let parameters = (ins "AffineMap":$value);
53  let builders = [
54    AttrBuilderWithInferredContext<(ins "AffineMap":$value), [{
55      return $_get(value.getContext(), value);
56    }]>
57  ];
58  let extraClassDeclaration = "using ValueType = AffineMap;";
59  let skipDefaultBuilders = 1;
60  let typeBuilder = "IndexType::get($_value.getContext())";
61}
62
63//===----------------------------------------------------------------------===//
64// ArrayAttr
65//===----------------------------------------------------------------------===//
66
67def Builtin_ArrayAttr : Builtin_Attr<"Array", [
68    DeclareAttrInterfaceMethods<SubElementAttrInterface>
69  ]> {
70  let summary = "A collection of other Attribute values";
71  let description = [{
72    Syntax:
73
74    ```
75    array-attribute ::= `[` (attribute-value (`,` attribute-value)*)? `]`
76    ```
77
78    An array attribute is an attribute that represents a collection of attribute
79    values.
80
81    Examples:
82
83    ```mlir
84    []
85    [10, i32]
86    [affine_map<(d0, d1, d2) -> (d0, d1)>, i32, "string attribute"]
87    ```
88  }];
89  let parameters = (ins ArrayRefParameter<"Attribute", "">:$value);
90  let extraClassDeclaration = [{
91    using ValueType = ArrayRef<Attribute>;
92
93    /// Return the element at the given index.
94    Attribute operator[](unsigned idx) const {
95      assert(idx < size() && "index out of bounds");
96      return getValue()[idx];
97    }
98
99    /// Support range iteration.
100    using iterator = llvm::ArrayRef<Attribute>::iterator;
101    iterator begin() const { return getValue().begin(); }
102    iterator end() const { return getValue().end(); }
103    size_t size() const { return getValue().size(); }
104    bool empty() const { return size() == 0; }
105
106  private:
107    /// Class for underlying value iterator support.
108    template <typename AttrTy>
109    class attr_value_iterator final
110        : public llvm::mapped_iterator<ArrayAttr::iterator,
111                                       AttrTy (*)(Attribute)> {
112    public:
113      explicit attr_value_iterator(ArrayAttr::iterator it)
114          : llvm::mapped_iterator<ArrayAttr::iterator, AttrTy (*)(Attribute)>(
115                it, [](Attribute attr) { return attr.cast<AttrTy>(); }) {}
116      AttrTy operator*() const { return (*this->I).template cast<AttrTy>(); }
117    };
118
119  public:
120    template <typename AttrTy>
121    iterator_range<attr_value_iterator<AttrTy>> getAsRange() const {
122      return llvm::make_range(attr_value_iterator<AttrTy>(begin()),
123                              attr_value_iterator<AttrTy>(end()));
124    }
125    template <typename AttrTy,
126              typename UnderlyingTy = typename AttrTy::ValueType>
127    auto getAsValueRange() const {
128      return llvm::map_range(getAsRange<AttrTy>(), [](AttrTy attr) {
129        return static_cast<UnderlyingTy>(attr.getValue());
130      });
131    }
132  }];
133}
134
135//===----------------------------------------------------------------------===//
136// DenseIntOrFPElementsAttr
137//===----------------------------------------------------------------------===//
138
139def Builtin_DenseIntOrFPElementsAttr
140    : Builtin_Attr<"DenseIntOrFPElements", /*traits=*/[], "DenseElementsAttr"> {
141  let summary = "An Attribute containing a dense multi-dimensional array of "
142                "integer or floating-point values";
143  let description = [{
144    Syntax:
145
146    ```
147    dense-intorfloat-elements-attribute ::= `dense` `<` attribute-value `>` `:`
148                                            ( tensor-type | vector-type )
149    ```
150
151    A dense int-or-float elements attribute is an elements attribute containing
152    a densely packed vector or tensor of integer or floating-point values. The
153    element type of this attribute is required to be either an `IntegerType` or
154    a `FloatType`.
155
156    Examples:
157
158    ```
159    // A splat tensor of integer values.
160    dense<10> : tensor<2xi32>
161    // A tensor of 2 float32 elements.
162    dense<[10.0, 11.0]> : tensor<2xf32>
163    ```
164  }];
165  let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
166                        "ArrayRef<char>":$rawData);
167  let extraClassDeclaration = [{
168    /// Convert endianess of input ArrayRef for big-endian(BE) machines. All of
169    /// the elements of `inRawData` has `type`. If `inRawData` is little endian
170    /// (LE), it is converted to big endian (BE). Conversely, if `inRawData` is
171    /// BE, converted to LE.
172    static void
173    convertEndianOfArrayRefForBEmachine(ArrayRef<char> inRawData,
174                                        MutableArrayRef<char> outRawData,
175                                        ShapedType type);
176
177    /// Convert endianess of input for big-endian(BE) machines. The number of
178    /// elements of `inRawData` is `numElements`, and each element has
179    /// `elementBitWidth` bits. If `inRawData` is little endian (LE), it is
180    /// converted to big endian (BE) and saved in `outRawData`. Conversely, if
181    /// `inRawData` is BE, converted to LE.
182    static void convertEndianOfCharForBEmachine(const char *inRawData,
183                                                char *outRawData,
184                                                size_t elementBitWidth,
185                                                size_t numElements);
186
187  protected:
188    friend DenseElementsAttr;
189
190    /// Constructs a dense elements attribute from an array of raw APFloat
191    /// values. Each APFloat value is expected to have the same bitwidth as the
192    /// element type of 'type'. 'type' must be a vector or tensor with static
193    /// shape.
194    static DenseElementsAttr getRaw(ShapedType type, size_t storageWidth,
195                                    ArrayRef<APFloat> values, bool isSplat);
196
197    /// Constructs a dense elements attribute from an array of raw APInt values.
198    /// Each APInt value is expected to have the same bitwidth as the element
199    /// type of 'type'. 'type' must be a vector or tensor with static shape.
200    static DenseElementsAttr getRaw(ShapedType type, size_t storageWidth,
201                                    ArrayRef<APInt> values, bool isSplat);
202
203    /// Get or create a new dense elements attribute instance with the given raw
204    /// data buffer. 'type' must be a vector or tensor with static shape.
205    static DenseElementsAttr getRaw(ShapedType type, ArrayRef<char> data,
206                                    bool isSplat);
207
208    /// Overload of the raw 'get' method that asserts that the given type is of
209    /// complex type. This method is used to verify type invariants that the
210    /// templatized 'get' method cannot.
211    static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef<char> data,
212                                           int64_t dataEltSize, bool isInt,
213                                           bool isSigned);
214
215    /// Overload of the raw 'get' method that asserts that the given type is of
216    /// integer or floating-point type. This method is used to verify type
217    /// invariants that the templatized 'get' method cannot.
218    static DenseElementsAttr getRawIntOrFloat(ShapedType type,
219                                              ArrayRef<char> data,
220                                              int64_t dataEltSize, bool isInt,
221                                              bool isSigned);
222
223  public:
224  }];
225  let genAccessors = 0;
226  let genStorageClass = 0;
227  let skipDefaultBuilders = 1;
228}
229
230//===----------------------------------------------------------------------===//
231// DenseStringElementsAttr
232//===----------------------------------------------------------------------===//
233
234def Builtin_DenseStringElementsAttr
235    : Builtin_Attr<"DenseStringElements", /*traits=*/[], "DenseElementsAttr"> {
236  let summary = "An Attribute containing a dense multi-dimensional array of "
237                "strings";
238  let description = [{
239    Syntax:
240
241    ```
242    dense-string-elements-attribute ::= `dense` `<` attribute-value `>` `:`
243                                        ( tensor-type | vector-type )
244    ```
245
246    A dense string elements attribute is an elements attribute containing a
247    densely packed vector or tensor of string values. There are no restrictions
248    placed on the element type of this attribute, enabling the use of dialect
249    specific string types.
250
251    Examples:
252
253    ```
254    // A splat tensor of strings.
255    dense<"example"> : tensor<2x!foo.string>
256    // A tensor of 2 string elements.
257    dense<["example1", "example2"]> : tensor<2x!foo.string>
258    ```
259  }];
260  let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
261                        "ArrayRef<StringRef>":$value);
262  let builders = [
263    AttrBuilderWithInferredContext<(ins "ShapedType":$type,
264                                        "ArrayRef<StringRef>":$values), [{
265      return $_get(type.getContext(), type, values,
266                   /* isSplat */(values.size() == 1));
267    }]>,
268  ];
269  let extraClassDeclaration = [{
270  protected:
271    friend DenseElementsAttr;
272
273  public:
274  }];
275  let genAccessors = 0;
276  let genStorageClass = 0;
277  let skipDefaultBuilders = 1;
278}
279
280//===----------------------------------------------------------------------===//
281// DictionaryAttr
282//===----------------------------------------------------------------------===//
283
284def Builtin_DictionaryAttr : Builtin_Attr<"Dictionary", [
285    DeclareAttrInterfaceMethods<SubElementAttrInterface>
286  ]> {
287  let summary = "An dictionary of named Attribute values";
288  let description = [{
289    Syntax:
290
291    ```
292    dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`
293    ```
294
295    A dictionary attribute is an attribute that represents a sorted collection of
296    named attribute values. The elements are sorted by name, and each name must be
297    unique within the collection.
298
299    Examples:
300
301    ```mlir
302    {}
303    {attr_name = "string attribute"}
304    {int_attr = 10, "string attr name" = "string attribute"}
305    ```
306  }];
307  let parameters = (ins ArrayRefParameter<"NamedAttribute", "">:$value);
308  let builders = [
309    AttrBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "llvm::None">:$value)>
310  ];
311  let extraClassDeclaration = [{
312    using ValueType = ArrayRef<NamedAttribute>;
313
314    /// Construct a dictionary with an array of values that is known to already
315    /// be sorted by name and uniqued.
316    static DictionaryAttr getWithSorted(MLIRContext *context,
317                                        ArrayRef<NamedAttribute> value);
318
319    /// Return the specified attribute if present, null otherwise.
320    Attribute get(StringRef name) const;
321    Attribute get(Identifier name) const;
322
323    /// Return the specified named attribute if present, None otherwise.
324    Optional<NamedAttribute> getNamed(StringRef name) const;
325    Optional<NamedAttribute> getNamed(Identifier name) const;
326
327    /// Support range iteration.
328    using iterator = llvm::ArrayRef<NamedAttribute>::iterator;
329    iterator begin() const;
330    iterator end() const;
331    bool empty() const { return size() == 0; }
332    size_t size() const;
333
334    /// Sorts the NamedAttributes in the array ordered by name as expected by
335    /// getWithSorted and returns whether the values were sorted.
336    /// Requires: uniquely named attributes.
337    static bool sort(ArrayRef<NamedAttribute> values,
338                     SmallVectorImpl<NamedAttribute> &storage);
339
340    /// Sorts the NamedAttributes in the array ordered by name as expected by
341    /// getWithSorted in place on an array and returns whether the values needed
342    /// to be sorted.
343    /// Requires: uniquely named attributes.
344    static bool sortInPlace(SmallVectorImpl<NamedAttribute> &array);
345
346    /// Returns an entry with a duplicate name in `array`, if it exists, else
347    /// returns llvm::None. If `isSorted` is true, the array is assumed to be
348    /// sorted else it will be sorted in place before finding the duplicate entry.
349    static Optional<NamedAttribute>
350    findDuplicate(SmallVectorImpl<NamedAttribute> &array, bool isSorted);
351
352    /// Return the specified attribute if present and is an instance of
353    /// `AttrClass`, null otherwise.
354    template<typename AttrClass, typename NameClass>
355    AttrClass getAs(NameClass &&name) const {
356      return get(std::forward<NameClass>(name))
357        .template dyn_cast_or_null<AttrClass>();
358    }
359
360  private:
361    /// Return empty dictionary.
362    static DictionaryAttr getEmpty(MLIRContext *context);
363
364    /// Return empty dictionary. This is a special variant of the above method
365    /// that is used by the MLIRContext to cache the empty dictionary instance.
366    static DictionaryAttr getEmptyUnchecked(MLIRContext *context);
367
368    /// Allow access to `getEmptyUnchecked`.
369    friend MLIRContext;
370
371  public:
372  }];
373  let skipDefaultBuilders = 1;
374}
375
376//===----------------------------------------------------------------------===//
377// FloatAttr
378//===----------------------------------------------------------------------===//
379
380def Builtin_FloatAttr : Builtin_Attr<"Float"> {
381  let summary = "An Attribute containing a floating-point value";
382  let description = [{
383    Syntax:
384
385    ```
386    float-attribute ::= (float-literal (`:` float-type)?)
387                      | (hexadecimal-literal `:` float-type)
388    ```
389
390    A float attribute is a literal attribute that represents a floating point
391    value of the specified [float type](#floating-point-types). It can be
392    represented in the hexadecimal form where the hexadecimal value is
393    interpreted as bits of the underlying binary representation. This form is
394    useful for representing infinity and NaN floating point values. To avoid
395    confusion with integer attributes, hexadecimal literals _must_ be followed
396    by a float type to define a float attribute.
397
398    Examples:
399
400    ```
401    42.0         // float attribute defaults to f64 type
402    42.0 : f32   // float attribute of f32 type
403    0x7C00 : f16 // positive infinity
404    0x7CFF : f16 // NaN (one of possible values)
405    42 : f32     // Error: expected integer type
406    ```
407  }];
408  let parameters = (ins AttributeSelfTypeParameter<"">:$type,
409                        APFloatParameter<"">:$value);
410  let builders = [
411    AttrBuilderWithInferredContext<(ins "Type":$type,
412                                        "const APFloat &":$value), [{
413      return $_get(type.getContext(), type, value);
414    }]>,
415    AttrBuilderWithInferredContext<(ins "Type":$type, "double":$value), [{
416      if (type.isF64() || !type.isa<FloatType>())
417        return $_get(type.getContext(), type, APFloat(value));
418
419      // This handles, e.g., F16 because there is no APFloat constructor for it.
420      bool unused;
421      APFloat val(value);
422      val.convert(type.cast<FloatType>().getFloatSemantics(),
423                  APFloat::rmNearestTiesToEven, &unused);
424      return $_get(type.getContext(), type, val);
425    }]>
426  ];
427  let extraClassDeclaration = [{
428    using ValueType = APFloat;
429
430    /// This function is used to convert the value to a double, even if it loses
431    /// precision.
432    double getValueAsDouble() const;
433    static double getValueAsDouble(APFloat val);
434  }];
435  let genVerifyDecl = 1;
436  let skipDefaultBuilders = 1;
437}
438
439//===----------------------------------------------------------------------===//
440// IntegerAttr
441//===----------------------------------------------------------------------===//
442
443def Builtin_IntegerAttr : Builtin_Attr<"Integer"> {
444  let summary = "An Attribute containing a integer value";
445  let description = [{
446    Syntax:
447
448    ```
449    integer-attribute ::= (integer-literal ( `:` (index-type | integer-type) )?)
450                          | `true` | `false`
451    ```
452
453    An integer attribute is a literal attribute that represents an integral
454    value of the specified integer or index type. `i1` integer attributes are
455    treated as `boolean` attributes, and use a unique assembly format of either
456    `true` or `false` depending on the value. The default type for non-boolean
457    integer attributes, if a type is not specified, is signless 64-bit integer.
458
459    Examples:
460
461    ```mlir
462    10 : i32
463    10    // : i64 is implied here.
464    true  // A bool, i.e. i1, value.
465    false // A bool, i.e. i1, value.
466    ```
467  }];
468  let parameters = (ins AttributeSelfTypeParameter<"">:$type, "APInt":$value);
469  let builders = [
470    AttrBuilderWithInferredContext<(ins "Type":$type,
471                                        "const APInt &":$value), [{
472      if (type.isSignlessInteger(1))
473        return BoolAttr::get(type.getContext(), value.getBoolValue());
474      return $_get(type.getContext(), type, value);
475    }]>,
476    AttrBuilder<(ins "const APSInt &":$value), [{
477      auto signedness = value.isSigned() ?
478        IntegerType::Signed : IntegerType::Unsigned;
479      auto type = IntegerType::get($_ctxt, value.getBitWidth(), signedness);
480      return $_get(type.getContext(), type, value);
481    }]>,
482    AttrBuilderWithInferredContext<(ins "Type":$type, "int64_t":$value), [{
483      // `index` has a defined internal storage width.
484      if (type.isIndex()) {
485        APInt apValue(IndexType::kInternalStorageBitWidth, value);
486        return $_get(type.getContext(), type, apValue);
487      }
488
489      IntegerType intTy = type.cast<IntegerType>();
490      APInt apValue(intTy.getWidth(), value, intTy.isSignedInteger());
491      return $_get(type.getContext(), type, apValue);
492    }]>
493  ];
494  let extraClassDeclaration = [{
495    using ValueType = APInt;
496
497    /// Return the integer value as a 64-bit int. The attribute must be a
498    /// signless integer.
499    // TODO: Change callers to use getValue instead.
500    int64_t getInt() const;
501    /// Return the integer value as a signed 64-bit int. The attribute must be
502    /// a signed integer.
503    int64_t getSInt() const;
504    /// Return the integer value as a unsigned 64-bit int. The attribute must be
505    /// an unsigned integer.
506    uint64_t getUInt() const;
507
508    /// Return the value as an APSInt which carries the signed from the type of
509    /// the attribute.  This traps on signless integers types!
510    APSInt getAPSInt() const;
511
512  private:
513    /// Return a boolean attribute. This is a special variant of the `get`
514    /// method that is used by the MLIRContext to cache the boolean IntegerAttr
515    /// instances.
516    static BoolAttr getBoolAttrUnchecked(IntegerType type, bool value);
517
518    /// Allow access to `getBoolAttrUnchecked`.
519    friend MLIRContext;
520
521  public:
522  }];
523  let genVerifyDecl = 1;
524  let skipDefaultBuilders = 1;
525}
526
527//===----------------------------------------------------------------------===//
528// IntegerSetAttr
529//===----------------------------------------------------------------------===//
530
531def Builtin_IntegerSetAttr : Builtin_Attr<"IntegerSet"> {
532  let summary = "An Attribute containing an IntegerSet object";
533  let description = [{
534    Syntax:
535
536    ```
537    integer-set-attribute ::= `affine_set` `<` integer-set `>`
538    ```
539
540    Examples:
541
542    ```mlir
543    affine_set<(d0) : (d0 - 2 >= 0)>
544    ```
545  }];
546  let parameters = (ins "IntegerSet":$value);
547  let builders = [
548    AttrBuilderWithInferredContext<(ins "IntegerSet":$value), [{
549      return $_get(value.getContext(), value);
550    }]>
551  ];
552  let extraClassDeclaration = "using ValueType = IntegerSet;";
553  let skipDefaultBuilders = 1;
554}
555
556//===----------------------------------------------------------------------===//
557// OpaqueAttr
558//===----------------------------------------------------------------------===//
559
560def Builtin_OpaqueAttr : Builtin_Attr<"Opaque"> {
561  let summary = "An opaque representation of another Attribute";
562  let description = [{
563    Syntax:
564
565    ```
566    opaque-attribute ::= dialect-namespace `<` attr-data `>`
567    ```
568
569    Opaque attributes represent attributes of non-registered dialects. These are
570    attribute represented in their raw string form, and can only usefully be
571    tested for attribute equality.
572
573    Examples:
574
575    ```mlir
576    #dialect<"opaque attribute data">
577    ```
578  }];
579  let parameters = (ins "Identifier":$dialectNamespace,
580                        StringRefParameter<"">:$attrData,
581                        AttributeSelfTypeParameter<"">:$type);
582  let builders = [
583    AttrBuilderWithInferredContext<(ins "Identifier":$dialect,
584                                        "StringRef":$attrData,
585                                        "Type":$type), [{
586      return $_get(dialect.getContext(), dialect, attrData, type);
587    }]>
588  ];
589  let genVerifyDecl = 1;
590  let skipDefaultBuilders = 1;
591}
592
593//===----------------------------------------------------------------------===//
594// OpaqueElementsAttr
595//===----------------------------------------------------------------------===//
596
597def Builtin_OpaqueElementsAttr
598    : Builtin_Attr<"OpaqueElements", /*traits=*/[], "ElementsAttr"> {
599  let summary = "An opaque representation of a multi-dimensional array";
600  let description = [{
601    Syntax:
602
603    ```
604    opaque-elements-attribute ::= `opaque` `<` dialect-namespace  `,`
605                                  hex-string-literal `>` `:`
606                                  ( tensor-type | vector-type )
607    ```
608
609    An opaque elements attribute is an elements attribute where the content of
610    the value is opaque. The representation of the constant stored by this
611    elements attribute is only understood, and thus decodable, by the dialect
612    that created it.
613
614    Note: The parsed string literal must be in hexadecimal form.
615
616    Examples:
617
618    ```mlir
619    opaque<"foo_dialect", "0xDEADBEEF"> : tensor<10xi32>
620    ```
621  }];
622
623  // TODO: Provide a way to avoid copying content of large opaque
624  // tensors This will likely require a new reference attribute kind.
625  let parameters = (ins "Identifier":$dialect,
626                        StringRefParameter<"">:$value,
627                        AttributeSelfTypeParameter<"", "ShapedType">:$type);
628  let builders = [
629    AttrBuilderWithInferredContext<(ins "Identifier":$dialect,
630                                        "ShapedType":$type,
631                                        "StringRef":$value), [{
632      return $_get(dialect.getContext(), dialect, value, type);
633    }]>,
634    AttrBuilderWithInferredContext<(ins "Dialect *":$dialect,
635                                        "ShapedType":$type,
636                                        "StringRef":$value), [{
637      MLIRContext *ctxt = dialect->getContext();
638      Identifier dialectName = Identifier::get(dialect->getNamespace(), ctxt);
639      return $_get(ctxt, dialectName, value, type);
640    }]>
641  ];
642  let extraClassDeclaration = [{
643    using ValueType = StringRef;
644
645    /// Return the value at the given index. The 'index' is expected to refer to
646    /// a valid element.
647    Attribute getValue(ArrayRef<uint64_t> index) const;
648
649    /// Decodes the attribute value using dialect-specific decoding hook.
650    /// Returns false if decoding is successful. If not, returns true and leaves
651    /// 'result' argument unspecified.
652    bool decode(ElementsAttr &result);
653
654  }];
655  let genVerifyDecl = 1;
656  let skipDefaultBuilders = 1;
657}
658
659//===----------------------------------------------------------------------===//
660// SparseElementsAttr
661//===----------------------------------------------------------------------===//
662
663def Builtin_SparseElementsAttr
664    : Builtin_Attr<"SparseElements", /*traits=*/[], "ElementsAttr"> {
665  let summary = "An opaque representation of a multi-dimensional array";
666  let description = [{
667    Syntax:
668
669    ```
670    sparse-elements-attribute ::= `sparse` `<` attribute-value `,`
671                                  attribute-value `>` `:`
672                                  ( tensor-type | vector-type )
673    ```
674
675    A sparse elements attribute is an elements attribute that represents a
676    sparse vector or tensor object. This is where very few of the elements are
677    non-zero.
678
679    The attribute uses COO (coordinate list) encoding to represent the sparse
680    elements of the elements attribute. The indices are stored via a 2-D tensor
681    of 64-bit integer elements with shape [N, ndims], which specifies the
682    indices of the elements in the sparse tensor that contains non-zero values.
683    The element values are stored via a 1-D tensor with shape [N], that supplies
684    the corresponding values for the indices.
685
686    Example:
687
688    ```mlir
689    sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>
690
691    // This represents the following tensor:
692    ///  [[1, 0, 0, 0],
693    ///   [0, 0, 5, 0],
694    ///   [0, 0, 0, 0]]
695    ```
696  }];
697
698  let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
699                        "DenseIntElementsAttr":$indices,
700                        "DenseElementsAttr":$values);
701  let builders = [
702    AttrBuilderWithInferredContext<(ins "ShapedType":$type,
703                                        "DenseElementsAttr":$indices,
704                                        "DenseElementsAttr":$values), [{
705      assert(indices.getType().getElementType().isInteger(64) &&
706             "expected sparse indices to be 64-bit integer values");
707      assert((type.isa<RankedTensorType, VectorType>()) &&
708             "type must be ranked tensor or vector");
709      assert(type.hasStaticShape() && "type must have static shape");
710      return $_get(type.getContext(), type,
711                   indices.cast<DenseIntElementsAttr>(), values);
712    }]>,
713  ];
714  let extraClassDeclaration = [{
715    template <typename T>
716    using iterator =
717        llvm::mapped_iterator<typename decltype(llvm::seq<ptrdiff_t>(0, 0))::iterator,
718                              std::function<T(ptrdiff_t)>>;
719
720    /// Return the values of this attribute in the form of the given type 'T'.
721    /// 'T'  may be any of Attribute, APInt, APFloat, c++ integer/float types,
722    /// etc.
723    template <typename T> llvm::iterator_range<iterator<T>> getValues() const;
724
725    /// Return the value of the element at the given index. The 'index' is
726    /// expected to refer to a valid element.
727    Attribute getValue(ArrayRef<uint64_t> index) const;
728
729  private:
730    /// Get a zero APFloat for the given sparse attribute.
731    APFloat getZeroAPFloat() const;
732
733    /// Get a zero APInt for the given sparse attribute.
734    APInt getZeroAPInt() const;
735
736    /// Get a zero attribute for the given sparse attribute.
737    Attribute getZeroAttr() const;
738
739    /// Utility methods to generate a zero value of some type 'T'. This is used
740    /// by the 'iterator' class.
741    /// Get a zero for a given attribute type.
742    template <typename T>
743    typename std::enable_if<std::is_base_of<Attribute, T>::value, T>::type
744    getZeroValue() const {
745      return getZeroAttr().template cast<T>();
746    }
747    /// Get a zero for an APInt.
748    template <typename T>
749    typename std::enable_if<std::is_same<APInt, T>::value, T>::type
750    getZeroValue() const {
751      return getZeroAPInt();
752    }
753    template <typename T>
754    typename std::enable_if<std::is_same<std::complex<APInt>, T>::value,
755                            T>::type
756    getZeroValue() const {
757      APInt intZero = getZeroAPInt();
758      return {intZero, intZero};
759    }
760    /// Get a zero for an APFloat.
761    template <typename T>
762    typename std::enable_if<std::is_same<APFloat, T>::value, T>::type
763    getZeroValue() const {
764      return getZeroAPFloat();
765    }
766    template <typename T>
767    typename std::enable_if<std::is_same<std::complex<APFloat>, T>::value,
768                            T>::type
769    getZeroValue() const {
770      APFloat floatZero = getZeroAPFloat();
771      return {floatZero, floatZero};
772    }
773
774    /// Get a zero for an C++ integer, float, StringRef, or complex type.
775    template <typename T>
776    typename std::enable_if<
777        std::numeric_limits<T>::is_integer ||
778            DenseElementsAttr::is_valid_cpp_fp_type<T>::value ||
779            std::is_same<T, StringRef>::value ||
780            (detail::is_complex_t<T>::value &&
781             !llvm::is_one_of<T, std::complex<APInt>,
782                              std::complex<APFloat>>::value),
783        T>::type
784    getZeroValue() const {
785      return T();
786    }
787
788    /// Flatten, and return, all of the sparse indices in this attribute in
789    /// row-major order.
790    std::vector<ptrdiff_t> getFlattenedSparseIndices() const;
791
792  public:
793  }];
794  let skipDefaultBuilders = 1;
795}
796
797//===----------------------------------------------------------------------===//
798// StringAttr
799//===----------------------------------------------------------------------===//
800
801def Builtin_StringAttr : Builtin_Attr<"String"> {
802  let summary = "An Attribute containing a string";
803  let description = [{
804    Syntax:
805
806    ```
807    string-attribute ::= string-literal (`:` type)?
808    ```
809
810    A string attribute is an attribute that represents a string literal value.
811
812    Examples:
813
814    ```mlir
815    "An important string"
816    "string with a type" : !dialect.string
817    ```
818  }];
819  let parameters = (ins StringRefParameter<"">:$value,
820                        AttributeSelfTypeParameter<"">:$type);
821  let builders = [
822    AttrBuilderWithInferredContext<(ins "const Twine &":$bytes, "Type":$type)>,
823    /// Build an string attr with NoneType.
824    AttrBuilder<(ins "const Twine &":$bytes)>,
825    /// Build an empty string attr with NoneType.
826    AttrBuilder<(ins)>
827  ];
828  let extraClassDeclaration = [{
829    using ValueType = StringRef;
830
831  private:
832    /// Return an empty StringAttr with NoneType type. This is a special variant
833    /// of the `get` method that is used by the MLIRContext to cache the
834    /// instance.
835    static StringAttr getEmptyStringAttrUnchecked(MLIRContext *context);
836    friend MLIRContext;
837  public:
838  }];
839  let skipDefaultBuilders = 1;
840}
841
842//===----------------------------------------------------------------------===//
843// SymbolRefAttr
844//===----------------------------------------------------------------------===//
845
846def Builtin_SymbolRefAttr : Builtin_Attr<"SymbolRef"> {
847  let summary = "An Attribute containing a symbolic reference to an Operation";
848  let description = [{
849    Syntax:
850
851    ```
852    symbol-ref-attribute ::= symbol-ref-id (`::` symbol-ref-id)*
853    ```
854
855    A symbol reference attribute is a literal attribute that represents a named
856    reference to an operation that is nested within an operation with the
857    `OpTrait::SymbolTable` trait. As such, this reference is given meaning by
858    the nearest parent operation containing the `OpTrait::SymbolTable` trait. It
859    may optionally contain a set of nested references that further resolve to a
860    symbol nested within a different symbol table.
861
862    This attribute can only be held internally by
863    [array attributes](#array-attribute) and
864    [dictionary attributes](#dictionary-attribute)(including the top-level
865    operation attribute dictionary), i.e. no other attribute kinds such as
866    Locations or extended attribute kinds.
867
868    **Rationale:** Identifying accesses to global data is critical to
869    enabling efficient multi-threaded compilation. Restricting global
870    data access to occur through symbols and limiting the places that can
871    legally hold a symbol reference simplifies reasoning about these data
872    accesses.
873
874    See [`Symbols And SymbolTables`](../SymbolsAndSymbolTables.md) for more
875    information.
876
877    Examples:
878
879    ```mlir
880    @flat_reference
881    @parent_reference::@nested_reference
882    ```
883  }];
884  let parameters = (ins
885    StringRefParameter<"">:$rootReference,
886    ArrayRefParameter<"FlatSymbolRefAttr", "">:$nestedReferences
887  );
888  let extraClassDeclaration = [{
889    static FlatSymbolRefAttr get(MLIRContext *ctx, StringRef value);
890
891    /// Returns the name of the fully resolved symbol, i.e. the leaf of the
892    /// reference path.
893    StringRef getLeafReference() const;
894  }];
895}
896
897//===----------------------------------------------------------------------===//
898// TypeAttr
899//===----------------------------------------------------------------------===//
900
901def Builtin_TypeAttr : Builtin_Attr<"Type", [
902    DeclareAttrInterfaceMethods<SubElementAttrInterface>
903  ]> {
904  let summary = "An Attribute containing a Type";
905  let description = [{
906    Syntax:
907
908    ```
909    type-attribute ::= type
910    ```
911
912    A type attribute is an attribute that represents a
913    [type object](#type-system).
914
915    Examples:
916
917    ```mlir
918    i32
919    !dialect.type
920    ```
921  }];
922  let parameters = (ins "Type":$value);
923  let builders = [
924    AttrBuilderWithInferredContext<(ins "Type":$type), [{
925      return $_get(type.getContext(), type);
926    }]>,
927  ];
928  let extraClassDeclaration = "using ValueType = Type;";
929  let skipDefaultBuilders = 1;
930}
931
932//===----------------------------------------------------------------------===//
933// UnitAttr
934//===----------------------------------------------------------------------===//
935
936def Builtin_UnitAttr : Builtin_Attr<"Unit"> {
937  let summary = "An Attribute value of `unit` type";
938  let description = [{
939    Syntax:
940
941    ```
942    unit-attribute ::= `unit`
943    ```
944
945    A unit attribute is an attribute that represents a value of `unit` type. The
946    `unit` type allows only one value forming a singleton set. This attribute
947    value is used to represent attributes that only have meaning from their
948    existence.
949
950    One example of such an attribute could be the `swift.self` attribute. This
951    attribute indicates that a function parameter is the self/context parameter.
952    It could be represented as a [boolean attribute](#boolean-attribute)(true or
953    false), but a value of false doesn't really bring any value. The parameter
954    either is the self/context or it isn't.
955
956
957    Examples:
958
959    ```mlir
960    // A unit attribute defined with the `unit` value specifier.
961    func @verbose_form() attributes {dialectName.unitAttr = unit}
962
963    // A unit attribute in an attribute dictionary can also be defined without
964    // the value specifier.
965    func @simple_form() attributes {dialectName.unitAttr}
966    ```
967  }];
968  let extraClassDeclaration = [{
969    static UnitAttr get(MLIRContext *context);
970  }];
971}
972
973#endif // BUILTIN_ATTRIBUTES
974