xref: /llvm-project/mlir/include/mlir/IR/BuiltinTypes.td (revision 6aaa8f25b66dc1fef4e465f274ee40b82d632988)
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    ![Index Map Example](/includes/img/index-map.svg)
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