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