1//===- BuiltinTypes.td - Builtin type 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_TYPES 15#define BUILTIN_TYPES 16 17include "mlir/IR/AttrTypeBase.td" 18include "mlir/IR/BuiltinDialect.td" 19include "mlir/IR/BuiltinTypeInterfaces.td" 20include "mlir/IR/CommonTypeConstraints.td" 21 22// TODO: Currently the types defined in this file are prefixed with `Builtin_`. 23// This is to differentiate the types here with the ones in OpBase.td. We should 24// remove the definitions in OpBase.td, and repoint users to this file instead. 25 26// Base class for Builtin dialect types. 27class Builtin_Type<string name, string typeMnemonic, list<Trait> traits = [], 28 string baseCppClass = "::mlir::Type"> 29 : TypeDef<Builtin_Dialect, name, traits, baseCppClass> { 30 let mnemonic = ?; 31 let typeName = "builtin." # typeMnemonic; 32} 33 34//===----------------------------------------------------------------------===// 35// Traits 36//===----------------------------------------------------------------------===// 37 38/// Type trait indicating that the type has value semantics. 39def ValueSemantics : NativeTypeTrait<"ValueSemantics"> { 40 let cppNamespace = "::mlir"; 41} 42 43//===----------------------------------------------------------------------===// 44// ComplexType 45//===----------------------------------------------------------------------===// 46 47def Builtin_Complex : Builtin_Type<"Complex", "complex"> { 48 let summary = "Complex number with a parameterized element type"; 49 let description = [{ 50 Syntax: 51 52 ``` 53 complex-type ::= `complex` `<` type `>` 54 ``` 55 56 The value of `complex` type represents a complex number with a parameterized 57 element type, which is composed of a real and imaginary value of that 58 element type. The element must be a floating point or integer scalar type. 59 60 #### Example: 61 62 ```mlir 63 complex<f32> 64 complex<i32> 65 ``` 66 }]; 67 let parameters = (ins "Type":$elementType); 68 let builders = [ 69 TypeBuilderWithInferredContext<(ins "Type":$elementType), [{ 70 return $_get(elementType.getContext(), elementType); 71 }]> 72 ]; 73 let skipDefaultBuilders = 1; 74 let genVerifyDecl = 1; 75} 76 77//===----------------------------------------------------------------------===// 78// FloatType 79//===----------------------------------------------------------------------===// 80 81// Base class for Builtin dialect float types. 82class Builtin_FloatType<string name, string mnemonic, 83 list<string> declaredInterfaceMethods = []> 84 : Builtin_Type<name, mnemonic, /*traits=*/[ 85 DeclareTypeInterfaceMethods< 86 FloatTypeInterface, 87 ["getFloatSemantics"] # declaredInterfaceMethods>]> { 88} 89 90// Float types that are cached in MLIRContext. 91class Builtin_CachedFloatType<string name, string mnemonic, 92 list<string> declaredInterfaceMethods = []> 93 : Builtin_FloatType<name, mnemonic, declaredInterfaceMethods> { 94 let extraClassDeclaration = [{ 95 static }] # name # [{Type get(MLIRContext *context); 96 }]; 97} 98 99//===----------------------------------------------------------------------===// 100// Float8E5M2Type 101 102def Builtin_Float8E5M2 : Builtin_FloatType<"Float8E5M2", "f8E5M2"> { 103 let summary = "8-bit floating point with 2 bit mantissa"; 104 let description = [{ 105 An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits 106 mantissa. This is not a standard type as defined by IEEE-754, but it 107 follows similar conventions with the following characteristics: 108 109 * bit encoding: S1E5M2 110 * exponent bias: 15 111 * infinities: supported with exponent set to all 1s and mantissa 0s 112 * NaNs: supported with exponent bits set to all 1s and mantissa of 113 (01, 10, or 11) 114 * denormals when exponent is 0 115 116 Described in: https://arxiv.org/abs/2209.05433 117 }]; 118} 119 120//===----------------------------------------------------------------------===// 121// Float8E4M3Type 122 123def Builtin_Float8E4M3 : Builtin_FloatType<"Float8E4M3", "f8E4M3"> { 124 let summary = "8-bit floating point with 3 bit mantissa"; 125 let description = [{ 126 An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits 127 mantissa. This is not a standard type as defined by IEEE-754, but it 128 follows similar conventions with the following characteristics: 129 130 * bit encoding: S1E4M3 131 * exponent bias: 7 132 * infinities: supported with exponent set to all 1s and mantissa 0s 133 * NaNs: supported with exponent bits set to all 1s and mantissa of 134 (001, 010, 011, 100, 101, 110, 111) 135 * denormals when exponent is 0 136 }]; 137} 138 139//===----------------------------------------------------------------------===// 140// Float8E4M3FNType 141 142def Builtin_Float8E4M3FN : Builtin_FloatType<"Float8E4M3FN", "f8E4M3FN"> { 143 let summary = "8-bit floating point with 3 bit mantissa"; 144 let description = [{ 145 An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits 146 mantissa. This is not a standard type as defined by IEEE-754, but it follows 147 similar conventions, with the exception that there are no infinity values 148 and only two NaN representations. This type has the following 149 characteristics: 150 151 * bit encoding: S1E4M3 152 * exponent bias: 7 153 * infinities: Not supported 154 * NaNs: supported with exponent bits and mantissa bits set to all 1s 155 * denormals when exponent is 0 156 157 Described in: https://arxiv.org/abs/2209.05433 158 }]; 159} 160 161//===----------------------------------------------------------------------===// 162// Float8E5M2FNUZType 163 164def Builtin_Float8E5M2FNUZ : Builtin_FloatType<"Float8E5M2FNUZ", "f8E5M2FNUZ"> { 165 let summary = "8-bit floating point with 2 bit mantissa"; 166 let description = [{ 167 An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits 168 mantissa. This is not a standard type as defined by IEEE-754, but it follows 169 similar conventions, with the exception that there are no infinity values, 170 no negative zero, and only one NaN representation. This type has the 171 following characteristics: 172 173 * bit encoding: S1E5M2 174 * exponent bias: 16 175 * infinities: Not supported 176 * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s 177 * denormals when exponent is 0 178 179 Described in: https://arxiv.org/abs/2206.02915 180 }]; 181} 182 183//===----------------------------------------------------------------------===// 184// Float8E4M3FNUZType 185 186def Builtin_Float8E4M3FNUZ : Builtin_FloatType<"Float8E4M3FNUZ", "f8E4M3FNUZ"> { 187 let summary = "8-bit floating point with 3 bit mantissa"; 188 let description = [{ 189 An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits 190 mantissa. This is not a standard type as defined by IEEE-754, but it follows 191 similar conventions, with the exception that there are no infinity values, 192 no negative zero, and only one NaN representation. This type has the 193 following characteristics: 194 195 * bit encoding: S1E4M3 196 * exponent bias: 8 197 * infinities: Not supported 198 * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s 199 * denormals when exponent is 0 200 201 Described in: https://arxiv.org/abs/2209.05433 202 }]; 203} 204 205//===----------------------------------------------------------------------===// 206// Float8E4M3B11FNUZType 207 208def Builtin_Float8E4M3B11FNUZ : Builtin_FloatType<"Float8E4M3B11FNUZ", "f8E4M3B11FNUZ"> { 209 let summary = "8-bit floating point with 3 bit mantissa"; 210 let description = [{ 211 An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits 212 mantissa. This is not a standard type as defined by IEEE-754, but it follows 213 similar conventions, with the exception that there are no infinity values, 214 no negative zero, and only one NaN representation. This type has the 215 following characteristics: 216 217 * bit encoding: S1E4M3 218 * exponent bias: 11 219 * infinities: Not supported 220 * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s 221 * denormals when exponent is 0 222 223 Related to: https://dl.acm.org/doi/10.5555/3454287.3454728 224 }]; 225} 226 227//===----------------------------------------------------------------------===// 228// Float8E3M4Type 229 230def Builtin_Float8E3M4 : Builtin_FloatType<"Float8E3M4", "f8E3M4"> { 231 let summary = "8-bit floating point with 3 bits exponent and 4 bit mantissa"; 232 let description = [{ 233 An 8-bit floating point type with 1 sign bit, 3 bits exponent and 4 bits 234 mantissa. This is not a standard type as defined by IEEE-754, but it 235 follows similar conventions with the following characteristics: 236 237 * bit encoding: S1E3M4 238 * exponent bias: 3 239 * infinities: supported with exponent set to all 1s and mantissa 0s 240 * NaNs: supported with exponent bits set to all 1s and mantissa values of 241 {0,1}⁴ except S.111.0000 242 * denormals when exponent is 0 243 }]; 244} 245 246//===----------------------------------------------------------------------===// 247// Float4E2M1FNType 248 249def Builtin_Float4E2M1FN : Builtin_FloatType<"Float4E2M1FN", "f4E2M1FN"> { 250 let summary = "4-bit floating point with 2-bit exponent and 1-bit mantissa"; 251 let description = [{ 252 An 4-bit floating point type with 1 sign bit, 2 bits exponent and 1 bit 253 mantissa. This is not a standard type as defined by IEEE-754, but it 254 follows similar conventions with the following characteristics: 255 256 * bit encoding: S1E2M1 257 * exponent bias: 1 258 * infinities: Not supported 259 * NaNs: Not supported 260 * denormals when exponent is 0 261 262 Open Compute Project (OCP) microscaling formats (MX) specification: 263 https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf 264 }]; 265} 266 267//===----------------------------------------------------------------------===// 268// Float6E2M3FNType 269 270def Builtin_Float6E2M3FN : Builtin_FloatType<"Float6E2M3FN", "f6E2M3FN"> { 271 let summary = "6-bit floating point with 2-bit exponent and 3-bit mantissa"; 272 let description = [{ 273 An 6-bit floating point type with 1 sign bit, 2 bits exponent and 3 bits 274 mantissa. This is not a standard type as defined by IEEE-754, but it 275 follows similar conventions with the following characteristics: 276 277 * bit encoding: S1E2M3 278 * exponent bias: 1 279 * infinities: Not supported 280 * NaNs: Not supported 281 * denormals when exponent is 0 282 283 Open Compute Project (OCP) microscaling formats (MX) specification: 284 https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf 285 }]; 286} 287 288//===----------------------------------------------------------------------===// 289// Float6E3M2FNType 290 291def Builtin_Float6E3M2FN : Builtin_FloatType<"Float6E3M2FN", "f6E3M2FN"> { 292 let summary = "6-bit floating point with 3-bit exponent and 2-bit mantissa"; 293 let description = [{ 294 An 6-bit floating point type with 1 sign bit, 3 bits exponent and 2 bits 295 mantissa. This is not a standard type as defined by IEEE-754, but it 296 follows similar conventions with the following characteristics: 297 298 * bit encoding: S1E3M2 299 * exponent bias: 3 300 * infinities: Not supported 301 * NaNs: Not supported 302 * denormals when exponent is 0 303 304 Open Compute Project (OCP) microscaling formats (MX) specification: 305 https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf 306 }]; 307} 308 309//===----------------------------------------------------------------------===// 310// Float8E8M0FNUType 311 312def Builtin_Float8E8M0FNU : Builtin_FloatType<"Float8E8M0FNU", "f8E8M0FNU"> { 313 let summary = "8-bit floating point with 8-bit exponent, no mantissa or sign"; 314 let description = [{ 315 An 8-bit floating point type with no sign bit, 8 bits exponent and no 316 mantissa. This is not a standard type as defined by IEEE-754; it is intended 317 to be used for representing scaling factors, so it cannot represent zeros 318 and negative numbers. The values it can represent are powers of two in the 319 range [-127,127] and NaN. 320 321 * bit encoding: S0E8M0 322 * exponent bias: 127 323 * infinities: Not supported 324 * NaNs: Supported with all bits set to 1 325 * denormals: Not supported 326 327 Open Compute Project (OCP) microscaling formats (MX) specification: 328 https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf 329 }]; 330} 331 332//===----------------------------------------------------------------------===// 333// BFloat16Type 334 335def Builtin_BFloat16 : Builtin_CachedFloatType<"BFloat16", "bf16", 336 /*declaredInterfaceMethods=*/["scaleElementBitwidth"]> { 337 let summary = "bfloat16 floating-point type"; 338} 339 340//===----------------------------------------------------------------------===// 341// Float16Type 342 343def Builtin_Float16 : Builtin_CachedFloatType<"Float16", "f16", 344 /*declaredInterfaceMethods=*/["scaleElementBitwidth"]> { 345 let summary = "16-bit floating-point type"; 346} 347 348//===----------------------------------------------------------------------===// 349// FloatTF32Type 350 351def Builtin_FloatTF32 : Builtin_CachedFloatType<"FloatTF32", "tf32"> { 352 let summary = "TF32 floating-point type"; 353} 354 355//===----------------------------------------------------------------------===// 356// Float32Type 357 358def Builtin_Float32 : Builtin_CachedFloatType<"Float32", "f32", 359 /*declaredInterfaceMethods=*/["scaleElementBitwidth"]> { 360 let summary = "32-bit floating-point type"; 361} 362 363//===----------------------------------------------------------------------===// 364// Float64Type 365 366def Builtin_Float64 : Builtin_CachedFloatType<"Float64", "f64"> { 367 let summary = "64-bit floating-point type"; 368} 369 370//===----------------------------------------------------------------------===// 371// Float80Type 372 373def Builtin_Float80 : Builtin_CachedFloatType<"Float80", "f80"> { 374 let summary = "80-bit floating-point type"; 375} 376 377//===----------------------------------------------------------------------===// 378// Float128Type 379 380def Builtin_Float128 : Builtin_CachedFloatType<"Float128", "f128"> { 381 let summary = "128-bit floating-point type"; 382} 383 384//===----------------------------------------------------------------------===// 385// FunctionType 386//===----------------------------------------------------------------------===// 387 388def Builtin_Function : Builtin_Type<"Function", "function"> { 389 let summary = "Map from a list of inputs to a list of results"; 390 let description = [{ 391 Syntax: 392 393 ``` 394 // Function types may have multiple results. 395 function-result-type ::= type-list-parens | non-function-type 396 function-type ::= type-list-parens `->` function-result-type 397 ``` 398 399 The function type can be thought of as a function signature. It consists of 400 a list of formal parameter types and a list of formal result types. 401 402 #### Example: 403 404 ```mlir 405 func.func @add_one(%arg0 : i64) -> i64 { 406 %c1 = arith.constant 1 : i64 407 %0 = arith.addi %arg0, %c1 : i64 408 return %0 : i64 409 } 410 ``` 411 }]; 412 let parameters = (ins "ArrayRef<Type>":$inputs, "ArrayRef<Type>":$results); 413 let builders = [ 414 TypeBuilder<(ins CArg<"TypeRange">:$inputs, CArg<"TypeRange">:$results), [{ 415 return $_get($_ctxt, inputs, results); 416 }]> 417 ]; 418 let skipDefaultBuilders = 1; 419 let genStorageClass = 0; 420 let extraClassDeclaration = [{ 421 /// Input types. 422 unsigned getNumInputs() const; 423 Type getInput(unsigned i) const { return getInputs()[i]; } 424 425 /// Result types. 426 unsigned getNumResults() const; 427 Type getResult(unsigned i) const { return getResults()[i]; } 428 429 /// Returns a clone of this function type with the given argument 430 /// and result types. 431 FunctionType clone(TypeRange inputs, TypeRange results) const; 432 433 /// Returns a new function type with the specified arguments and results 434 /// inserted. 435 FunctionType getWithArgsAndResults(ArrayRef<unsigned> argIndices, 436 TypeRange argTypes, 437 ArrayRef<unsigned> resultIndices, 438 TypeRange resultTypes); 439 440 /// Returns a new function type without the specified arguments and results. 441 FunctionType getWithoutArgsAndResults(const BitVector &argIndices, 442 const BitVector &resultIndices); 443 }]; 444} 445 446//===----------------------------------------------------------------------===// 447// IndexType 448//===----------------------------------------------------------------------===// 449 450def Builtin_Index : Builtin_Type<"Index", "index"> { 451 let summary = "Integer-like type with unknown platform-dependent bit width"; 452 let description = [{ 453 Syntax: 454 455 ``` 456 // Target word-sized integer. 457 index-type ::= `index` 458 ``` 459 460 The index type is a signless integer whose size is equal to the natural 461 machine word of the target ( [rationale](../../Rationale/Rationale/#integer-signedness-semantics) ) 462 and is used by the affine constructs in MLIR. 463 464 **Rationale:** integers of platform-specific bit widths are practical to 465 express sizes, dimensionalities and subscripts. 466 }]; 467 let extraClassDeclaration = [{ 468 static IndexType get(MLIRContext *context); 469 470 /// Storage bit width used for IndexType by internal compiler data 471 /// structures. 472 static constexpr unsigned kInternalStorageBitWidth = 64; 473 }]; 474} 475 476//===----------------------------------------------------------------------===// 477// IntegerType 478//===----------------------------------------------------------------------===// 479 480def Builtin_Integer : Builtin_Type<"Integer", "integer"> { 481 let summary = "Integer type with arbitrary precision up to a fixed limit"; 482 let description = [{ 483 Syntax: 484 485 ``` 486 // Sized integers like i1, i4, i8, i16, i32. 487 signed-integer-type ::= `si` [1-9][0-9]* 488 unsigned-integer-type ::= `ui` [1-9][0-9]* 489 signless-integer-type ::= `i` [1-9][0-9]* 490 integer-type ::= signed-integer-type | 491 unsigned-integer-type | 492 signless-integer-type 493 ``` 494 495 Integer types have a designated bit width and may optionally have signedness 496 semantics. 497 498 **Rationale:** low precision integers (like `i2`, `i4` etc) are useful for 499 low-precision inference chips, and arbitrary precision integers are useful 500 for hardware synthesis (where a 13 bit multiplier is a lot cheaper/smaller 501 than a 16 bit one). 502 }]; 503 let parameters = (ins "unsigned":$width, "SignednessSemantics":$signedness); 504 let builders = [ 505 TypeBuilder<(ins "unsigned":$width, 506 CArg<"SignednessSemantics", "Signless">:$signedness)> 507 ]; 508 509 // IntegerType uses a special storage class that compacts parameters to save 510 // memory. 511 let genStorageClass = 0; 512 let skipDefaultBuilders = 1; 513 let genVerifyDecl = 1; 514 let extraClassDeclaration = [{ 515 /// Signedness semantics. 516 enum SignednessSemantics : uint32_t { 517 Signless, /// No signedness semantics 518 Signed, /// Signed integer 519 Unsigned, /// Unsigned integer 520 }; 521 522 /// Return true if this is a signless integer type. 523 bool isSignless() const { return getSignedness() == Signless; } 524 /// Return true if this is a signed integer type. 525 bool isSigned() const { return getSignedness() == Signed; } 526 /// Return true if this is an unsigned integer type. 527 bool isUnsigned() const { return getSignedness() == Unsigned; } 528 529 /// Get or create a new IntegerType with the same signedness as `this` and a 530 /// bitwidth scaled by `scale`. 531 /// Return null if the scaled element type cannot be represented. 532 IntegerType scaleElementBitwidth(unsigned scale); 533 534 /// Integer representation maximal bitwidth. 535 /// Note: This is aligned with the maximum width of llvm::IntegerType. 536 static constexpr unsigned kMaxWidth = (1 << 24) - 1; 537 }]; 538} 539 540//===----------------------------------------------------------------------===// 541// MemRefType 542//===----------------------------------------------------------------------===// 543 544def Builtin_MemRef : Builtin_Type<"MemRef", "memref", [ 545 ShapedTypeInterface 546 ], "BaseMemRefType"> { 547 let summary = "Shaped reference to a region of memory"; 548 let description = [{ 549 Syntax: 550 551 ``` 552 layout-specification ::= attribute-value 553 memory-space ::= attribute-value 554 memref-type ::= `memref` `<` dimension-list-ranked type 555 (`,` layout-specification)? (`,` memory-space)? `>` 556 ``` 557 558 A `memref` type is a reference to a region of memory (similar to a buffer 559 pointer, but more powerful). The buffer pointed to by a memref can be 560 allocated, aliased and deallocated. A memref can be used to read and write 561 data from/to the memory region which it references. Memref types use the 562 same shape specifier as tensor types. Note that `memref<f32>`, 563 `memref<0 x f32>`, `memref<1 x 0 x f32>`, and `memref<0 x 1 x f32>` are all 564 different types. 565 566 A `memref` is allowed to have an unknown rank (e.g. `memref<*xf32>`). The 567 purpose of unranked memrefs is to allow external library functions to 568 receive memref arguments of any rank without versioning the functions based 569 on the rank. Other uses of this type are disallowed or will have undefined 570 behavior. 571 572 Are accepted as elements: 573 574 - built-in integer types; 575 - built-in index type; 576 - built-in floating point types; 577 - built-in vector types with elements of the above types; 578 - another memref type; 579 - any other type implementing `MemRefElementTypeInterface`. 580 581 ##### Layout 582 583 A memref may optionally have a layout that indicates how indices are 584 transformed from the multi-dimensional form into a linear address. The 585 layout must avoid internal aliasing, i.e., two distinct tuples of 586 _in-bounds_ indices must be pointing to different elements in memory. The 587 layout is an attribute that implements `MemRefLayoutAttrInterface`. The 588 bulitin dialect offers two kinds of layouts: strided and affine map, each 589 of which is available as an attribute. Other attributes may be used to 590 represent the layout as long as they can be converted to a 591 [semi-affine map](Affine.md/#semi-affine-maps) and implement the required 592 interface. Users of memref are expected to fallback to the affine 593 representation when handling unknown memref layouts. Multi-dimensional 594 affine forms are interpreted in _row-major_ fashion. 595 596 In absence of an explicit layout, a memref is considered to have a 597 multi-dimensional identity affine map layout. Identity layout maps do not 598 contribute to the MemRef type identification and are discarded on 599 construction. That is, a type with an explicit identity map is 600 `memref<?x?xf32, (i,j)->(i,j)>` is strictly the same as the one without a 601 layout, `memref<?x?xf32>`. 602 603 ##### Affine Map Layout 604 605 The layout may be represented directly as an affine map from the index space 606 to the storage space. For example, the following figure shows an index map 607 which maps a 2-dimensional index from a 2x2 index space to a 3x3 index 608 space, using symbols `S0` and `S1` as offsets. 609 610  611 612 Semi-affine maps are sufficiently flexible to represent a wide variety of 613 dense storage layouts, including row- and column-major and tiled: 614 615 ```mlir 616 // MxN matrix stored in row major layout in memory: 617 #layout_map_row_major = (i, j) -> (i, j) 618 619 // MxN matrix stored in column major layout in memory: 620 #layout_map_col_major = (i, j) -> (j, i) 621 622 // MxN matrix stored in a 2-d blocked/tiled layout with 64x64 tiles. 623 #layout_tiled = (i, j) -> (i floordiv 64, j floordiv 64, i mod 64, j mod 64) 624 ``` 625 626 ##### Strided Layout 627 628 Memref layout can be expressed using strides to encode the distance, in 629 number of elements, in (linear) memory between successive entries along a 630 particular dimension. For example, a row-major strided layout for 631 `memref<2x3x4xf32>` is `strided<[12, 4, 1]>`, where the last dimension is 632 contiguous as indicated by the unit stride and the remaining strides are 633 products of the sizes of faster-variying dimensions. Strided layout can also 634 express non-contiguity, e.g., `memref<2x3, strided<[6, 2]>>` only accesses 635 even elements of the dense consecutive storage along the innermost 636 dimension. 637 638 The strided layout supports an optional _offset_ that indicates the 639 distance, in the number of elements, between the beginning of the memref 640 and the first accessed element. When omitted, the offset is considered to 641 be zero. That is, `memref<2, strided<[2], offset: 0>>` and 642 `memref<2, strided<[2]>>` are strictly the same type. 643 644 Both offsets and strides may be _dynamic_, that is, unknown at compile time. 645 This is represented by using a question mark (`?`) instead of the value in 646 the textual form of the IR. 647 648 The strided layout converts into the following canonical one-dimensional 649 affine form through explicit linearization: 650 651 ```mlir 652 affine_map<(d0, ... dN)[offset, stride0, ... strideN] -> 653 (offset + d0 * stride0 + ... dN * strideN)> 654 ``` 655 656 Therefore, it is never subject to the implicit row-major layout 657 interpretation. 658 659 ##### Codegen of Unranked Memref 660 661 Using unranked memref in codegen besides the case mentioned above is highly 662 discouraged. Codegen is concerned with generating loop nests and specialized 663 instructions for high-performance, unranked memref is concerned with hiding 664 the rank and thus, the number of enclosing loops required to iterate over 665 the data. However, if there is a need to code-gen unranked memref, one 666 possible path is to cast into a static ranked type based on the dynamic 667 rank. Another possible path is to emit a single while loop conditioned on a 668 linear index and perform delinearization of the linear index to a dynamic 669 array containing the (unranked) indices. While this is possible, it is 670 expected to not be a good idea to perform this during codegen as the cost 671 of the translations is expected to be prohibitive and optimizations at this 672 level are not expected to be worthwhile. If expressiveness is the main 673 concern, irrespective of performance, passing unranked memrefs to an 674 external C++ library and implementing rank-agnostic logic there is expected 675 to be significantly simpler. 676 677 Unranked memrefs may provide expressiveness gains in the future and help 678 bridge the gap with unranked tensors. Unranked memrefs will not be expected 679 to be exposed to codegen but one may query the rank of an unranked memref 680 (a special op will be needed for this purpose) and perform a switch and cast 681 to a ranked memref as a prerequisite to codegen. 682 683 Example: 684 685 ```mlir 686 // With static ranks, we need a function for each possible argument type 687 %A = alloc() : memref<16x32xf32> 688 %B = alloc() : memref<16x32x64xf32> 689 call @helper_2D(%A) : (memref<16x32xf32>)->() 690 call @helper_3D(%B) : (memref<16x32x64xf32>)->() 691 692 // With unknown rank, the functions can be unified under one unranked type 693 %A = alloc() : memref<16x32xf32> 694 %B = alloc() : memref<16x32x64xf32> 695 // Remove rank info 696 %A_u = memref_cast %A : memref<16x32xf32> -> memref<*xf32> 697 %B_u = memref_cast %B : memref<16x32x64xf32> -> memref<*xf32> 698 // call same function with dynamic ranks 699 call @helper(%A_u) : (memref<*xf32>)->() 700 call @helper(%B_u) : (memref<*xf32>)->() 701 ``` 702 703 The core syntax and representation of a layout specification is a 704 [semi-affine map](Affine.md/#semi-affine-maps). Additionally, 705 syntactic sugar is supported to make certain layout specifications more 706 intuitive to read. For the moment, a `memref` supports parsing a strided 707 form which is converted to a semi-affine map automatically. 708 709 The memory space of a memref is specified by a target-specific attribute. 710 It might be an integer value, string, dictionary or custom dialect attribute. 711 The empty memory space (attribute is None) is target specific. 712 713 The notionally dynamic value of a memref value includes the address of the 714 buffer allocated, as well as the symbols referred to by the shape, layout 715 map, and index maps. 716 717 Examples of memref static type 718 719 ```mlir 720 // Identity index/layout map 721 #identity = affine_map<(d0, d1) -> (d0, d1)> 722 723 // Column major layout. 724 #col_major = affine_map<(d0, d1, d2) -> (d2, d1, d0)> 725 726 // A 2-d tiled layout with tiles of size 128 x 256. 727 #tiled_2d_128x256 = affine_map<(d0, d1) -> (d0 div 128, d1 div 256, d0 mod 128, d1 mod 256)> 728 729 // A tiled data layout with non-constant tile sizes. 730 #tiled_dynamic = affine_map<(d0, d1)[s0, s1] -> (d0 floordiv s0, d1 floordiv s1, 731 d0 mod s0, d1 mod s1)> 732 733 // A layout that yields a padding on two at either end of the minor dimension. 734 #padded = affine_map<(d0, d1) -> (d0, (d1 + 2) floordiv 2, (d1 + 2) mod 2)> 735 736 737 // The dimension list "16x32" defines the following 2D index space: 738 // 739 // { (i, j) : 0 <= i < 16, 0 <= j < 32 } 740 // 741 memref<16x32xf32, #identity> 742 743 // The dimension list "16x4x?" defines the following 3D index space: 744 // 745 // { (i, j, k) : 0 <= i < 16, 0 <= j < 4, 0 <= k < N } 746 // 747 // where N is a symbol which represents the runtime value of the size of 748 // the third dimension. 749 // 750 // %N here binds to the size of the third dimension. 751 %A = alloc(%N) : memref<16x4x?xf32, #col_major> 752 753 // A 2-d dynamic shaped memref that also has a dynamically sized tiled 754 // layout. The memref index space is of size %M x %N, while %B1 and %B2 755 // bind to the symbols s0, s1 respectively of the layout map #tiled_dynamic. 756 // Data tiles of size %B1 x %B2 in the logical space will be stored 757 // contiguously in memory. The allocation size will be 758 // (%M ceildiv %B1) * %B1 * (%N ceildiv %B2) * %B2 f32 elements. 759 %T = alloc(%M, %N) [%B1, %B2] : memref<?x?xf32, #tiled_dynamic> 760 761 // A memref that has a two-element padding at either end. The allocation 762 // size will fit 16 * 64 float elements of data. 763 %P = alloc() : memref<16x64xf32, #padded> 764 765 // Affine map with symbol 's0' used as offset for the first dimension. 766 #imapS = affine_map<(d0, d1) [s0] -> (d0 + s0, d1)> 767 // Allocate memref and bind the following symbols: 768 // '%n' is bound to the dynamic second dimension of the memref type. 769 // '%o' is bound to the symbol 's0' in the affine map of the memref type. 770 %n = ... 771 %o = ... 772 %A = alloc (%n)[%o] : <16x?xf32, #imapS> 773 ``` 774 }]; 775 let parameters = (ins 776 ArrayRefParameter<"int64_t">:$shape, 777 "Type":$elementType, 778 "MemRefLayoutAttrInterface":$layout, 779 "Attribute":$memorySpace 780 ); 781 let builders = [ 782 TypeBuilderWithInferredContext<(ins 783 "ArrayRef<int64_t>":$shape, "Type":$elementType, 784 CArg<"MemRefLayoutAttrInterface", "{}">:$layout, 785 CArg<"Attribute", "{}">:$memorySpace)>, 786 TypeBuilderWithInferredContext<(ins 787 "ArrayRef<int64_t>":$shape, "Type":$elementType, 788 CArg<"AffineMap">:$map, 789 CArg<"Attribute", "{}">:$memorySpace)>, 790 /// [deprecated] `Attribute`-based form should be used instead. 791 TypeBuilderWithInferredContext<(ins 792 "ArrayRef<int64_t>":$shape, "Type":$elementType, 793 "AffineMap":$map, 794 "unsigned":$memorySpaceInd)> 795 ]; 796 let extraClassDeclaration = [{ 797 using BaseMemRefType::clone; 798 using ShapedType::Trait<MemRefType>::getElementTypeBitWidth; 799 using ShapedType::Trait<MemRefType>::getRank; 800 using ShapedType::Trait<MemRefType>::getNumElements; 801 using ShapedType::Trait<MemRefType>::isDynamicDim; 802 using ShapedType::Trait<MemRefType>::hasStaticShape; 803 using ShapedType::Trait<MemRefType>::getNumDynamicDims; 804 using ShapedType::Trait<MemRefType>::getDimSize; 805 using ShapedType::Trait<MemRefType>::getDynamicDimIndex; 806 807 /// This is a builder type that keeps local references to arguments. 808 /// Arguments that are passed into the builder must outlive the builder. 809 class Builder; 810 811 /// Return "true" if the last N dimensions are contiguous. 812 /// 813 /// Examples: 814 /// - memref<5x4x3x2xi8, strided<[24, 6, 2, 1]> is contiguous when 815 /// considering both _all_ and _only_ the trailing 3 dims, 816 /// - memref<5x4x3x2xi8, strided<[48, 6, 2, 1]> is _only_ contiguous when 817 /// considering the trailing 3 dims. 818 /// 819 bool areTrailingDimsContiguous(int64_t n); 820 821 /// Return a version of this type with identity layout if it can be 822 /// determined statically that the layout is the canonical contiguous 823 /// strided layout. Otherwise pass the layout into `simplifyAffineMap` 824 /// and return a copy of this type with simplified layout. 825 MemRefType canonicalizeStridedLayout(); 826 827 /// [deprecated] Returns the memory space in old raw integer representation. 828 /// New `Attribute getMemorySpace()` method should be used instead. 829 unsigned getMemorySpaceAsInt() const; 830 831 /// Returns the strides of the MemRef if the layout map is in strided form. 832 /// MemRefs with a layout map in strided form include: 833 /// 1. empty or identity layout map, in which case the stride information 834 /// is the canonical form computed from sizes; 835 /// 2. a StridedLayoutAttr layout; 836 /// 3. any other layout that be converted into a single affine map layout 837 /// of the form `K + k0 * d0 + ... kn * dn`, where K and ki's are 838 /// constants or symbols. 839 /// 840 /// A stride specification is a list of integer values that are either 841 /// static or dynamic (encoded with ShapedType::kDynamic). Strides encode 842 /// the distance in the number of elements between successive entries along 843 /// a particular dimension. 844 LogicalResult getStridesAndOffset(SmallVectorImpl<int64_t> &strides, 845 int64_t &offset); 846 847 /// Wrapper around getStridesAndOffset(SmallVectorImpl<int64_t>, int64_t) 848 /// that will assert if the logical result is not succeeded. 849 std::pair<SmallVector<int64_t>, int64_t> getStridesAndOffset(); 850 851 /// Return "true" if the layout is compatible with strided semantics. 852 bool isStrided(); 853 854 /// Return "true" if the last dimension has a static unit stride. Also 855 /// return "true" for types with no strides. 856 bool isLastDimUnitStride(); 857 }]; 858 let skipDefaultBuilders = 1; 859 let genVerifyDecl = 1; 860} 861 862//===----------------------------------------------------------------------===// 863// NoneType 864//===----------------------------------------------------------------------===// 865 866def Builtin_None : Builtin_Type<"None", "none"> { 867 let summary = "A unit type"; 868 let description = [{ 869 Syntax: 870 871 ``` 872 none-type ::= `none` 873 ``` 874 875 NoneType is a unit type, i.e. a type with exactly one possible value, where 876 its value does not have a defined dynamic representation. 877 878 #### Example: 879 880 ```mlir 881 func.func @none_type() { 882 %none_val = "foo.unknown_op"() : () -> none 883 return 884 } 885 ``` 886 }]; 887 let extraClassDeclaration = [{ 888 static NoneType get(MLIRContext *context); 889 }]; 890} 891 892//===----------------------------------------------------------------------===// 893// OpaqueType 894//===----------------------------------------------------------------------===// 895 896def Builtin_Opaque : Builtin_Type<"Opaque", "opaque"> { 897 let summary = "Type of a non-registered dialect"; 898 let description = [{ 899 Syntax: 900 901 ``` 902 opaque-type ::= `opaque` `<` type `>` 903 ``` 904 905 Opaque types represent types of non-registered dialects. These are types 906 represented in their raw string form, and can only usefully be tested for 907 type equality. 908 909 #### Example: 910 911 ```mlir 912 opaque<"llvm", "struct<(i32, float)>"> 913 opaque<"pdl", "value"> 914 ``` 915 }]; 916 let parameters = (ins 917 "StringAttr":$dialectNamespace, 918 StringRefParameter<"">:$typeData 919 ); 920 921 let builders = [ 922 TypeBuilderWithInferredContext<(ins 923 "StringAttr":$dialectNamespace, CArg<"StringRef", "{}">:$typeData 924 ), [{ 925 return $_get(dialectNamespace.getContext(), dialectNamespace, typeData); 926 }]> 927 ]; 928 let skipDefaultBuilders = 1; 929 let genVerifyDecl = 1; 930} 931 932//===----------------------------------------------------------------------===// 933// RankedTensorType 934//===----------------------------------------------------------------------===// 935 936def Builtin_RankedTensor : Builtin_Type<"RankedTensor", "tensor", [ 937 ShapedTypeInterface, ValueSemantics 938 ], "TensorType"> { 939 let summary = "Multi-dimensional array with a fixed number of dimensions"; 940 let description = [{ 941 Syntax: 942 943 ``` 944 tensor-type ::= `tensor` `<` dimension-list type (`,` encoding)? `>` 945 dimension-list ::= (dimension `x`)* 946 dimension ::= `?` | decimal-literal 947 encoding ::= attribute-value 948 ``` 949 950 Values with tensor type represents aggregate N-dimensional data values, and 951 have a known element type and a fixed rank with a list of dimensions. Each 952 dimension may be a static non-negative decimal constant or be dynamically 953 determined (indicated by `?`). 954 955 The runtime representation of the MLIR tensor type is intentionally 956 abstracted - you cannot control layout or get a pointer to the data. For 957 low level buffer access, MLIR has a [`memref` type](#memreftype). This 958 abstracted runtime representation holds both the tensor data values as well 959 as information about the (potentially dynamic) shape of the tensor. The 960 [`dim` operation](MemRef.md/#memrefdim-mlirmemrefdimop) returns the size of a 961 dimension from a value of tensor type. 962 963 The `encoding` attribute provides additional information on the tensor. 964 An empty attribute denotes a straightforward tensor without any specific 965 structure. But particular properties, like sparsity or other specific 966 characteristics of the data of the tensor can be encoded through this 967 attribute. The semantics are defined by a type and attribute interface 968 and must be respected by all passes that operate on tensor types. 969 TODO: provide this interface, and document it further. 970 971 Note: hexadecimal integer literals are not allowed in tensor type 972 declarations to avoid confusion between `0xf32` and `0 x f32`. Zero sizes 973 are allowed in tensors and treated as other sizes, e.g., 974 `tensor<0 x 1 x i32>` and `tensor<1 x 0 x i32>` are different types. Since 975 zero sizes are not allowed in some other types, such tensors should be 976 optimized away before lowering tensors to vectors. 977 978 #### Example: 979 980 ```mlir 981 // Known rank but unknown dimensions. 982 tensor<? x ? x ? x ? x f32> 983 984 // Partially known dimensions. 985 tensor<? x ? x 13 x ? x f32> 986 987 // Full static shape. 988 tensor<17 x 4 x 13 x 4 x f32> 989 990 // Tensor with rank zero. Represents a scalar. 991 tensor<f32> 992 993 // Zero-element dimensions are allowed. 994 tensor<0 x 42 x f32> 995 996 // Zero-element tensor of f32 type (hexadecimal literals not allowed here). 997 tensor<0xf32> 998 999 // Tensor with an encoding attribute (where #ENCODING is a named alias). 1000 tensor<?x?xf64, #ENCODING> 1001 ``` 1002 }]; 1003 let parameters = (ins 1004 ArrayRefParameter<"int64_t">:$shape, 1005 "Type":$elementType, 1006 "Attribute":$encoding 1007 ); 1008 1009 let builders = [ 1010 TypeBuilderWithInferredContext<(ins 1011 "ArrayRef<int64_t>":$shape, 1012 "Type":$elementType, 1013 CArg<"Attribute", "{}">:$encoding 1014 ), [{ 1015 return $_get(elementType.getContext(), shape, elementType, encoding); 1016 }]> 1017 ]; 1018 let extraClassDeclaration = [{ 1019 using TensorType::clone; 1020 using ShapedType::Trait<RankedTensorType>::getElementTypeBitWidth; 1021 using ShapedType::Trait<RankedTensorType>::getRank; 1022 using ShapedType::Trait<RankedTensorType>::getNumElements; 1023 using ShapedType::Trait<RankedTensorType>::isDynamicDim; 1024 using ShapedType::Trait<RankedTensorType>::hasStaticShape; 1025 using ShapedType::Trait<RankedTensorType>::getNumDynamicDims; 1026 using ShapedType::Trait<RankedTensorType>::getDimSize; 1027 using ShapedType::Trait<RankedTensorType>::getDynamicDimIndex; 1028 1029 /// This is a builder type that keeps local references to arguments. 1030 /// Arguments that are passed into the builder must outlive the builder. 1031 class Builder; 1032 1033 /// Return a clone of this type with the given new element type and the same 1034 /// shape as this type. 1035 RankedTensorType clone(::mlir::Type elementType) { 1036 return ::llvm::cast<RankedTensorType>(cloneWith(getShape(), elementType)); 1037 } 1038 }]; 1039 let skipDefaultBuilders = 1; 1040 let genVerifyDecl = 1; 1041} 1042 1043//===----------------------------------------------------------------------===// 1044// TupleType 1045//===----------------------------------------------------------------------===// 1046 1047def Builtin_Tuple : Builtin_Type<"Tuple", "tuple"> { 1048 let summary = "Fixed-sized collection of other types"; 1049 let description = [{ 1050 Syntax: 1051 1052 ``` 1053 tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>` 1054 ``` 1055 1056 The value of `tuple` type represents a fixed-size collection of elements, 1057 where each element may be of a different type. 1058 1059 **Rationale:** Though this type is first class in the type system, MLIR 1060 provides no standard operations for operating on `tuple` types 1061 ([rationale](../../Rationale/Rationale/#tuple-types)). 1062 1063 #### Example: 1064 1065 ```mlir 1066 // Empty tuple. 1067 tuple<> 1068 1069 // Single element 1070 tuple<f32> 1071 1072 // Many elements. 1073 tuple<i32, f32, tensor<i1>, i5> 1074 ``` 1075 }]; 1076 let parameters = (ins "ArrayRef<Type>":$types); 1077 let builders = [ 1078 TypeBuilder<(ins "TypeRange":$elementTypes), [{ 1079 return $_get($_ctxt, elementTypes); 1080 }]>, 1081 TypeBuilder<(ins), [{ 1082 return $_get($_ctxt, TypeRange()); 1083 }]> 1084 ]; 1085 let skipDefaultBuilders = 1; 1086 let genStorageClass = 0; 1087 let extraClassDeclaration = [{ 1088 /// Accumulate the types contained in this tuple and tuples nested within 1089 /// it. Note that this only flattens nested tuples, not any other container 1090 /// type, e.g. a tuple<i32, tensor<i32>, tuple<f32, tuple<i64>>> is 1091 /// flattened to (i32, tensor<i32>, f32, i64) 1092 void getFlattenedTypes(SmallVectorImpl<Type> &types); 1093 1094 /// Return the number of held types. 1095 size_t size() const; 1096 1097 /// Iterate over the held elements. 1098 using iterator = ArrayRef<Type>::iterator; 1099 iterator begin() const { return getTypes().begin(); } 1100 iterator end() const { return getTypes().end(); } 1101 1102 /// Return the element type at index 'index'. 1103 Type getType(size_t index) const { 1104 assert(index < size() && "invalid index for tuple type"); 1105 return getTypes()[index]; 1106 } 1107 }]; 1108} 1109 1110//===----------------------------------------------------------------------===// 1111// UnrankedMemRefType 1112//===----------------------------------------------------------------------===// 1113 1114def Builtin_UnrankedMemRef : Builtin_Type<"UnrankedMemRef", "unranked_memref", [ 1115 ShapedTypeInterface 1116 ], "BaseMemRefType"> { 1117 let summary = "Shaped reference, with unknown rank, to a region of memory"; 1118 let description = [{ 1119 Syntax: 1120 1121 ``` 1122 unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>` 1123 memory-space ::= attribute-value 1124 ``` 1125 1126 A `memref` type with an unknown rank (e.g. `memref<*xf32>`). The purpose of 1127 unranked memrefs is to allow external library functions to receive memref 1128 arguments of any rank without versioning the functions based on the rank. 1129 Other uses of this type are disallowed or will have undefined behavior. 1130 1131 See [MemRefType](#memreftype) for more information on 1132 memref types. 1133 1134 #### Examples: 1135 1136 ```mlir 1137 memref<*f32> 1138 1139 // An unranked memref with a memory space of 10. 1140 memref<*f32, 10> 1141 ``` 1142 }]; 1143 let parameters = (ins "Type":$elementType, "Attribute":$memorySpace); 1144 1145 let builders = [ 1146 TypeBuilderWithInferredContext<(ins "Type":$elementType, 1147 "Attribute":$memorySpace), [{ 1148 // Drop default memory space value and replace it with empty attribute. 1149 Attribute nonDefaultMemorySpace = skipDefaultMemorySpace(memorySpace); 1150 return $_get(elementType.getContext(), elementType, nonDefaultMemorySpace); 1151 }]>, 1152 /// [deprecated] `Attribute`-based form should be used instead. 1153 TypeBuilderWithInferredContext<(ins "Type":$elementType, 1154 "unsigned":$memorySpace), [{ 1155 // Convert deprecated integer-like memory space to Attribute. 1156 Attribute memorySpaceAttr = 1157 wrapIntegerMemorySpace(memorySpace, elementType.getContext()); 1158 return UnrankedMemRefType::get(elementType, memorySpaceAttr); 1159 }]> 1160 ]; 1161 let extraClassDeclaration = [{ 1162 using BaseMemRefType::clone; 1163 using ShapedType::Trait<UnrankedMemRefType>::getElementTypeBitWidth; 1164 using ShapedType::Trait<UnrankedMemRefType>::getRank; 1165 using ShapedType::Trait<UnrankedMemRefType>::getNumElements; 1166 using ShapedType::Trait<UnrankedMemRefType>::isDynamicDim; 1167 using ShapedType::Trait<UnrankedMemRefType>::hasStaticShape; 1168 using ShapedType::Trait<UnrankedMemRefType>::getNumDynamicDims; 1169 using ShapedType::Trait<UnrankedMemRefType>::getDimSize; 1170 using ShapedType::Trait<UnrankedMemRefType>::getDynamicDimIndex; 1171 1172 ArrayRef<int64_t> getShape() const { return std::nullopt; } 1173 1174 /// [deprecated] Returns the memory space in old raw integer representation. 1175 /// New `Attribute getMemorySpace()` method should be used instead. 1176 unsigned getMemorySpaceAsInt() const; 1177 1178 /// Return a clone of this type with the given new element type and the same 1179 /// shape as this type. 1180 MemRefType clone(::mlir::Type elementType) { 1181 return ::llvm::cast<MemRefType>(cloneWith(getShape(), elementType)); 1182 } 1183 }]; 1184 let skipDefaultBuilders = 1; 1185 let genVerifyDecl = 1; 1186} 1187 1188//===----------------------------------------------------------------------===// 1189// UnrankedTensorType 1190//===----------------------------------------------------------------------===// 1191 1192def Builtin_UnrankedTensor : Builtin_Type<"UnrankedTensor", "unranked_tensor", [ 1193 ShapedTypeInterface, ValueSemantics 1194 ], "TensorType"> { 1195 let summary = "Multi-dimensional array with unknown dimensions"; 1196 let description = [{ 1197 Syntax: 1198 1199 ``` 1200 tensor-type ::= `tensor` `<` `*` `x` type `>` 1201 ``` 1202 1203 An unranked tensor is a type of tensor in which the set of dimensions have 1204 unknown rank. See [RankedTensorType](#rankedtensortype) 1205 for more information on tensor types. 1206 1207 #### Examples: 1208 1209 ```mlir 1210 tensor<*xf32> 1211 ``` 1212 }]; 1213 let parameters = (ins "Type":$elementType); 1214 1215 let builders = [ 1216 TypeBuilderWithInferredContext<(ins "Type":$elementType), [{ 1217 return $_get(elementType.getContext(), elementType); 1218 }]> 1219 ]; 1220 let extraClassDeclaration = [{ 1221 using TensorType::clone; 1222 using ShapedType::Trait<UnrankedTensorType>::getElementTypeBitWidth; 1223 using ShapedType::Trait<UnrankedTensorType>::getRank; 1224 using ShapedType::Trait<UnrankedTensorType>::getNumElements; 1225 using ShapedType::Trait<UnrankedTensorType>::isDynamicDim; 1226 using ShapedType::Trait<UnrankedTensorType>::hasStaticShape; 1227 using ShapedType::Trait<UnrankedTensorType>::getNumDynamicDims; 1228 using ShapedType::Trait<UnrankedTensorType>::getDimSize; 1229 using ShapedType::Trait<UnrankedTensorType>::getDynamicDimIndex; 1230 1231 ArrayRef<int64_t> getShape() const { return std::nullopt; } 1232 }]; 1233 let skipDefaultBuilders = 1; 1234 let genVerifyDecl = 1; 1235} 1236 1237//===----------------------------------------------------------------------===// 1238// VectorType 1239//===----------------------------------------------------------------------===// 1240 1241def Builtin_VectorTypeElementType : AnyTypeOf<[AnyInteger, Index, AnyFloat]> { 1242 let cppFunctionName = "isValidVectorTypeElementType"; 1243} 1244 1245def Builtin_Vector : Builtin_Type<"Vector", "vector", 1246 [ShapedTypeInterface, ValueSemantics], "Type"> { 1247 let summary = "Multi-dimensional SIMD vector type"; 1248 let description = [{ 1249 Syntax: 1250 1251 ``` 1252 vector-type ::= `vector` `<` vector-dim-list vector-element-type `>` 1253 vector-element-type ::= float-type | integer-type | index-type 1254 vector-dim-list := (static-dim-list `x`)? 1255 static-dim-list ::= static-dim (`x` static-dim)* 1256 static-dim ::= (decimal-literal | `[` decimal-literal `]`) 1257 ``` 1258 1259 The vector type represents a SIMD style vector used by target-specific 1260 operation sets like AVX or SVE. While the most common use is for 1D 1261 vectors (e.g. vector<16 x f32>) we also support multidimensional registers 1262 on targets that support them (like TPUs). The dimensions of a vector type 1263 can be fixed-length, scalable, or a combination of the two. The scalable 1264 dimensions in a vector are indicated between square brackets ([ ]). 1265 1266 Vector shapes must be positive decimal integers. 0D vectors are allowed by 1267 omitting the dimension: `vector<f32>`. 1268 1269 Note: hexadecimal integer literals are not allowed in vector type 1270 declarations, `vector<0x42xi32>` is invalid because it is interpreted as a 1271 2D vector with shape `(0, 42)` and zero shapes are not allowed. 1272 1273 #### Examples: 1274 1275 ```mlir 1276 // A 2D fixed-length vector of 3x42 i32 elements. 1277 vector<3x42xi32> 1278 1279 // A 1D scalable-length vector that contains a multiple of 4 f32 elements. 1280 vector<[4]xf32> 1281 1282 // A 2D scalable-length vector that contains a multiple of 2x8 f32 elements. 1283 vector<[2]x[8]xf32> 1284 1285 // A 2D mixed fixed/scalable vector that contains 4 scalable vectors of 4 f32 elements. 1286 vector<4x[4]xf32> 1287 1288 // A 3D mixed fixed/scalable vector in which only the inner dimension is 1289 // scalable. 1290 vector<2x[4]x8xf32> 1291 ``` 1292 }]; 1293 let parameters = (ins 1294 ArrayRefParameter<"int64_t">:$shape, 1295 Builtin_VectorTypeElementType:$elementType, 1296 ArrayRefParameter<"bool">:$scalableDims 1297 ); 1298 let builders = [ 1299 TypeBuilderWithInferredContext<(ins 1300 "ArrayRef<int64_t>":$shape, "Type":$elementType, 1301 CArg<"ArrayRef<bool>", "{}">:$scalableDims 1302 ), [{ 1303 // While `scalableDims` is optional, its default value should be 1304 // `false` for every dim in `shape`. 1305 SmallVector<bool> isScalableVec; 1306 if (scalableDims.empty()) { 1307 isScalableVec.resize(shape.size(), false); 1308 scalableDims = isScalableVec; 1309 } 1310 return $_get(elementType.getContext(), shape, elementType, scalableDims); 1311 }]> 1312 ]; 1313 let extraClassDeclaration = [{ 1314 /// This is a builder type that keeps local references to arguments. 1315 /// Arguments that are passed into the builder must outlive the builder. 1316 class Builder; 1317 1318 /// Returns true if the given type can be used as an element of a vector 1319 /// type. See "Builtin_VectorTypeElementType" for allowed types. 1320 static bool isValidElementType(Type t); 1321 1322 /// Returns true if the vector contains scalable dimensions. 1323 bool isScalable() const { 1324 return llvm::is_contained(getScalableDims(), true); 1325 } 1326 bool allDimsScalable() const { 1327 // Treat 0-d vectors as fixed size. 1328 if (getRank() == 0) 1329 return false; 1330 return !llvm::is_contained(getScalableDims(), false); 1331 } 1332 1333 /// Get the number of scalable dimensions. 1334 size_t getNumScalableDims() const { 1335 return llvm::count(getScalableDims(), true); 1336 } 1337 1338 /// Get or create a new VectorType with the same shape as `this` and an 1339 /// element type of bitwidth scaled by `scale`. 1340 /// Return null if the scaled element type cannot be represented. 1341 VectorType scaleElementBitwidth(unsigned scale); 1342 1343 /// Returns if this type is ranked (always true). 1344 bool hasRank() const { return true; } 1345 1346 /// Clone this vector type with the given shape and element type. If the 1347 /// provided shape is `std::nullopt`, the current shape of the type is used. 1348 VectorType cloneWith(std::optional<ArrayRef<int64_t>> shape, 1349 Type elementType) const; 1350 }]; 1351 let skipDefaultBuilders = 1; 1352 let genVerifyDecl = 1; 1353} 1354 1355#endif // BUILTIN_TYPES 1356