# Builtin Dialect

The builtin dialect contains a core set of Attributes, Operations, and Types
that have wide applicability across a very large number of domains and
abstractions. Many of the components of this dialect are also instrumental in
the implementation of the core IR. As such, this dialect is implicitly loaded in
every `MLIRContext`

, and available directly to all users of MLIR.

Given the far-reaching nature of this dialect and the fact that MLIR is extensible by design, any potential additions are heavily scrutinized.

## Attributes ¶

### AffineMapAttr ¶

An Attribute containing an AffineMap object

Syntax:

```
affine-map-attribute ::= `affine_map` `<` affine-map `>`
```

Examples:

```
affine_map<(d0) -> (d0)>
affine_map<(d0, d1, d2) -> (d0, d1)>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

value | `AffineMap` |

### ArrayAttr ¶

A collection of other Attribute values

Syntax:

```
array-attribute ::= `[` (attribute-value (`,` attribute-value)*)? `]`
```

An array attribute is an attribute that represents a collection of attribute values.

Examples:

```
[]
[10, i32]
[affine_map<(d0, d1, d2) -> (d0, d1)>, i32, "string attribute"]
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

value | `::llvm::ArrayRef<Attribute>` |

### DenseArrayAttr ¶

A dense array of integer or floating point elements.

A dense array attribute is an attribute that represents a dense array of
primitive element types. Contrary to DenseIntOrFPElementsAttr this is a
flat unidimensional array which does not have a storage optimization for
splat. This allows to expose the raw array through a C++ API as
`ArrayRef<T>`

for compatible types. The element type must be bool or an
integer or float whose bitwidth is a multiple of 8. Bool elements are stored
as bytes.

This is the base class attribute. Access to C++ types is intended to be
managed through the subclasses `DenseI8ArrayAttr`

, `DenseI16ArrayAttr`

,
`DenseI32ArrayAttr`

, `DenseI64ArrayAttr`

, `DenseF32ArrayAttr`

,
and `DenseF64ArrayAttr`

.

Syntax:

```
dense-array-attribute ::= `array` `<` (integer-type | float-type)
(`:` tensor-literal)? `>`
```

Examples:

```
array<i8>
array<i32: 10, 42>
array<f64: 42., 12.>
```

When a specific subclass is used as argument of an operation, the declarative assembly will omit the type and print directly:

```
[1, 2, 3]
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

elementType | `Type` | |

size | `int64_t` | |

rawData | `::llvm::ArrayRef<char>` | 64-bit aligned storage for dense array elements |

### DenseIntOrFPElementsAttr ¶

An Attribute containing a dense multi-dimensional array of integer or floating-point values

Syntax:

```
tensor-literal ::= integer-literal | float-literal | bool-literal | [] | [tensor-literal (, tensor-literal)* ]
dense-intorfloat-elements-attribute ::= `dense` `<` tensor-literal `>` `:`
( tensor-type | vector-type )
```

A dense int-or-float elements attribute is an elements attribute containing
a densely packed vector or tensor of integer or floating-point values. The
element type of this attribute is required to be either an `IntegerType`

or
a `FloatType`

.

Examples:

```
// A splat tensor of integer values.
dense<10> : tensor<2xi32>
// A tensor of 2 float32 elements.
dense<[10.0, 11.0]> : tensor<2xf32>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

type | `ShapedType` | |

rawData | `ArrayRef<char>` |

### DenseResourceElementsAttr ¶

An Attribute containing a dense multi-dimensional array backed by a resource

Syntax:

```
dense-resource-elements-attribute ::=
`dense_resource` `<` resource-handle `>` `:` shaped-type
```

A dense resource elements attribute is an elements attribute backed by a
handle to a builtin dialect resource containing a densely packed array of
values. This class provides the low-level attribute, which should only be
interacted with in very generic terms, actual access to the underlying
resource data is intended to be managed through one of the subclasses, such
as; `DenseBoolResourceElementsAttr`

, `DenseUI64ResourceElementsAttr`

,
`DenseI32ResourceElementsAttr`

, `DenseF32ResourceElementsAttr`

,
`DenseF64ResourceElementsAttr`

, etc.

Examples:

```
// A tensor referencing a builtin dialect resource, `resource_1`, with two
// unsigned i32 elements.
dense_resource<resource_1> : tensor<2xui32>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

type | `ShapedType` | |

rawHandle | `DenseResourceElementsHandle` |

### DenseStringElementsAttr ¶

An Attribute containing a dense multi-dimensional array of strings

Syntax:

```
dense-string-elements-attribute ::= `dense` `<` attribute-value `>` `:`
( tensor-type | vector-type )
```

A dense string elements attribute is an elements attribute containing a densely packed vector or tensor of string values. There are no restrictions placed on the element type of this attribute, enabling the use of dialect specific string types.

Examples:

```
// A splat tensor of strings.
dense<"example"> : tensor<2x!foo.string>
// A tensor of 2 string elements.
dense<["example1", "example2"]> : tensor<2x!foo.string>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

type | `ShapedType` | |

value | `ArrayRef<StringRef>` |

### DictionaryAttr ¶

An dictionary of named Attribute values

Syntax:

```
dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`
```

A dictionary attribute is an attribute that represents a sorted collection of named attribute values. The elements are sorted by name, and each name must be unique within the collection.

Examples:

```
{}
{attr_name = "string attribute"}
{int_attr = 10, "string attr name" = "string attribute"}
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

value | `::llvm::ArrayRef<NamedAttribute>` |

### FloatAttr ¶

An Attribute containing a floating-point value

Syntax:

```
float-attribute ::= (float-literal (`:` float-type)?)
| (hexadecimal-literal `:` float-type)
```

A float attribute is a literal attribute that represents a floating point
value of the specified
float type. It can be
represented in the hexadecimal form where the hexadecimal value is
interpreted as bits of the underlying binary representation. This form is
useful for representing infinity and NaN floating point values. To avoid
confusion with integer attributes, hexadecimal literals *must* be followed
by a float type to define a float attribute.

Examples:

```
42.0 // float attribute defaults to f64 type
42.0 : f32 // float attribute of f32 type
0x7C00 : f16 // positive infinity
0x7CFF : f16 // NaN (one of possible values)
42 : f32 // Error: expected integer type
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

type | `::mlir::Type` | |

value | `::llvm::APFloat` |

### IntegerAttr ¶

An Attribute containing a integer value

Syntax:

```
integer-attribute ::= (integer-literal ( `:` (index-type | integer-type) )?)
| `true` | `false`
```

An integer attribute is a literal attribute that represents an integral
value of the specified integer or index type. `i1`

integer attributes are
treated as `boolean`

attributes, and use a unique assembly format of either
`true`

or `false`

depending on the value. The default type for non-boolean
integer attributes, if a type is not specified, is signless 64-bit integer.

Examples:

```
10 : i32
10 // : i64 is implied here.
true // A bool, i.e. i1, value.
false // A bool, i.e. i1, value.
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

type | `::mlir::Type` | |

value | `APInt` |

### IntegerSetAttr ¶

An Attribute containing an IntegerSet object

Syntax:

```
integer-set-attribute ::= `affine_set` `<` integer-set `>`
```

Examples:

```
affine_set<(d0) : (d0 - 2 >= 0)>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

value | `IntegerSet` |

### OpaqueAttr ¶

An opaque representation of another Attribute

Syntax:

```
opaque-attribute ::= dialect-namespace `<` attr-data `>`
```

Opaque attributes represent attributes of non-registered dialects. These are attribute represented in their raw string form, and can only usefully be tested for attribute equality.

Examples:

```
#dialect<"opaque attribute data">
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

dialectNamespace | `StringAttr` | |

attrData | `::llvm::StringRef` | |

type | `::mlir::Type` |

### SparseElementsAttr ¶

An opaque representation of a multi-dimensional array

Syntax:

```
sparse-elements-attribute ::= `sparse` `<` attribute-value `,`
attribute-value `>` `:`
( tensor-type | vector-type )
```

A sparse elements attribute is an elements attribute that represents a sparse vector or tensor object. This is where very few of the elements are non-zero.

The attribute uses COO (coordinate list) encoding to represent the sparse elements of the elements attribute. The indices are stored via a 2-D tensor of 64-bit integer elements with shape [N, ndims], which specifies the indices of the elements in the sparse tensor that contains non-zero values. The element values are stored via a 1-D tensor with shape [N], that supplies the corresponding values for the indices.

Example:

```
sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>
// This represents the following tensor:
/// [[1, 0, 0, 0],
/// [0, 0, 5, 0],
/// [0, 0, 0, 0]]
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

type | `ShapedType` | |

indices | `DenseIntElementsAttr` | |

values | `DenseElementsAttr` |

### StringAttr ¶

An Attribute containing a string

Syntax:

```
string-attribute ::= string-literal (`:` type)?
```

A string attribute is an attribute that represents a string literal value.

Examples:

```
"An important string"
"string with a type" : !dialect.string
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

value | `::llvm::StringRef` | |

type | `::mlir::Type` |

### SymbolRefAttr ¶

An Attribute containing a symbolic reference to an Operation

Syntax:

```
symbol-ref-attribute ::= symbol-ref-id (`::` symbol-ref-id)*
```

A symbol reference attribute is a literal attribute that represents a named
reference to an operation that is nested within an operation with the
`OpTrait::SymbolTable`

trait. As such, this reference is given meaning by
the nearest parent operation containing the `OpTrait::SymbolTable`

trait. It
may optionally contain a set of nested references that further resolve to a
symbol nested within a different symbol table.

**Rationale:** Identifying accesses to global data is critical to
enabling efficient multi-threaded compilation. Restricting global
data access to occur through symbols and limiting the places that can
legally hold a symbol reference simplifies reasoning about these data
accesses.

See
`Symbols And SymbolTables`

for more
information.

Examples:

```
@flat_reference
@parent_reference::@nested_reference
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

rootReference | `StringAttr` | |

nestedReferences | `::llvm::ArrayRef<FlatSymbolRefAttr>` |

### TypeAttr ¶

An Attribute containing a Type

Syntax:

```
type-attribute ::= type
```

A type attribute is an attribute that represents a type object.

Examples:

```
i32
!dialect.type
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

value | `Type` |

### UnitAttr ¶

An Attribute value of `unit`

type

Syntax:

```
unit-attribute ::= `unit`
```

A unit attribute is an attribute that represents a value of `unit`

type. The
`unit`

type allows only one value forming a singleton set. This attribute
value is used to represent attributes that only have meaning from their
existence.

One example of such an attribute could be the `swift.self`

attribute. This
attribute indicates that a function parameter is the self/context parameter.
It could be represented as a
boolean attribute(true or
false), but a value of false doesn’t really bring any value. The parameter
either is the self/context or it isn’t.

Examples:

```
// A unit attribute defined with the `unit` value specifier.
func.func @verbose_form() attributes {dialectName.unitAttr = unit}
// A unit attribute in an attribute dictionary can also be defined without
// the value specifier.
func.func @simple_form() attributes {dialectName.unitAttr}
```

### StridedLayoutAttr ¶

An Attribute representing a strided layout of a shaped type

Syntax:

```
strided-layout-attribute ::= `strided` `<` `[` stride-list `]`
(`,` `offset` `:` dimension)? `>`
stride-list ::= /*empty*/
| dimension (`,` dimension)*
dimension ::= decimal-literal | `?`
```

A strided layout attribute captures layout information of the memref type in
the canonical form. Specifically, it contains a list of *strides*, one for
each dimension. A stride is the number of elements in the linear storage
one must step over to reflect an increment in the given dimension. For
example, a `MxN`

row-major contiguous shaped type would have the strides
`[N, 1]`

. The layout attribute also contains the *offset* from the base
pointer of the shaped type to the first effectively accessed element,
expressed in terms of the number of contiguously stored elements.

Strides must be positive and the offset must be non-negative. Both the
strides and the offset may be *dynamic*, i.e. their value may not be known
at compile time. This is expressed as a `?`

in the assembly syntax and as
`ShapedType::kDynamic`

in the code. Stride and offset values
must satisfy the constraints above at runtime, the behavior is undefined
otherwise.

See [Dialects/Builtin.md#memreftype](MemRef type) for more information.

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

offset | `int64_t` | |

strides | `::llvm::ArrayRef<int64_t>` | array of strides (64-bit integer) |

## Location Attributes ¶

A subset of the builtin attribute values correspond to source locations, that may be attached to Operations.

### CallSiteLoc ¶

A callsite source location

Syntax:

```
callsite-location ::= `callsite` `(` location `at` location `)`
```

An instance of this location allows for representing a directed stack of
location usages. This connects a location of a `callee`

with the location
of a `caller`

.

Example:

```
loc(callsite("foo" at "mysource.cc":10:8))
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

callee | `Location` | |

caller | `Location` |

### FileLineColLoc ¶

A file:line:column source location

Syntax:

```
filelinecol-location ::= string-literal `:` integer-literal `:`
integer-literal
```

An instance of this location represents a tuple of file, line number, and column number. This is similar to the type of location that you get from most source languages.

Example:

```
loc("mysource.cc":10:8)
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

filename | `StringAttr` | |

line | `unsigned` | |

column | `unsigned` |

### FusedLoc ¶

A tuple of other source locations

Syntax:

```
fused-location ::= `fused` fusion-metadata? `[` location (location `,`)* `]`
fusion-metadata ::= `<` attribute-value `>`
```

An instance of a `fused`

location represents a grouping of several other
source locations, with optional metadata that describes the context of the
fusion. There are many places within a compiler in which several constructs
may be fused together, e.g. pattern rewriting, that normally result partial
or even total loss of location information. With `fused`

locations, this is
a non-issue.

Example:

```
loc(fused["mysource.cc":10:8, "mysource.cc":22:8)
loc(fused<"CSE">["mysource.cc":10:8, "mysource.cc":22:8])
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

locations | `::llvm::ArrayRef<Location>` | |

metadata | `Attribute` |

### NameLoc ¶

A named source location

Syntax:

```
name-location ::= string-literal (`(` location `)`)?
```

An instance of this location allows for attaching a name to a child location. This can be useful for representing the locations of variable, or node, definitions.

Example:

```
loc("CSE"("mysource.cc":10:8))
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

name | `StringAttr` | |

childLoc | `Location` |

### OpaqueLoc ¶

An opaque source location

An instance of this location essentially contains a pointer to some data structure that is external to MLIR and an optional location that can be used if the first one is not suitable. Since it contains an external structure, only the optional location is used during serialization.

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

underlyingLocation | `uintptr_t` | |

underlyingTypeID | `TypeID` | |

fallbackLocation | `Location` |

### UnknownLoc ¶

An unspecified source location

Syntax:

```
unknown-location ::= `?`
```

Source location information is an extremely integral part of the MLIR
infrastructure. As such, location information is always present in the IR,
and must explicitly be set to unknown. Thus, an instance of the `unknown`

location represents an unspecified source location.

Example:

```
loc(?)
```

## Operations ¶

`builtin.module`

(::mlir::ModuleOp) ¶

A top level container operation

Syntax:

```
operation ::= `builtin.module` ($sym_name^)? attr-dict-with-keyword $bodyRegion
```

A `module`

represents a top-level container operation. It contains a single
graph region containing a single block
which can contain any operations and does not have a terminator. Operations
within this region cannot implicitly capture values defined outside the module,
i.e. Modules are
IsolatedFromAbove. Modules have
an optional
symbol name which can be used to refer
to them in operations.

Example:

```
module {
func.func @foo()
}
```

Traits: AffineScope, HasOnlyGraphRegion, IsolatedFromAbove, NoRegionArguments, NoTerminator, SingleBlock, SymbolTable

Interfaces: OpAsmOpInterface, RegionKindInterface, Symbol

#### Attributes: ¶

Attribute | MLIR Type | Description |
---|---|---|

`sym_name` | ::mlir::StringAttr | string attribute |

`sym_visibility` | ::mlir::StringAttr | string attribute |

`builtin.unrealized_conversion_cast`

(::mlir::UnrealizedConversionCastOp) ¶

An unrealized conversion from one set of types to another

Syntax:

```
operation ::= `builtin.unrealized_conversion_cast` ($inputs^ `:` type($inputs))? `to` type($outputs) attr-dict
```

An `unrealized_conversion_cast`

operation represents an unrealized
conversion from one set of types to another, that is used to enable the
inter-mixing of different type systems. This operation should not be
attributed any special representational or execution semantics, and is
generally only intended to be used to satisfy the temporary intermixing of
type systems during the conversion of one type system to another.

This operation may produce results of arity 1-N, and accept as input operands of arity 0-N.

Example:

```
// An unrealized 0-1 conversion. These types of conversions are useful in
// cases where a type is removed from the type system, but not all uses have
// been converted. For example, imagine we have a tuple type that is
// expanded to its element types. If only some uses of an empty tuple type
// instance are converted we still need an instance of the tuple type, but
// have no inputs to the unrealized conversion.
%result = unrealized_conversion_cast to !bar.tuple_type<>
// An unrealized 1-1 conversion.
%result1 = unrealized_conversion_cast %operand : !foo.type to !bar.lowered_type
// An unrealized 1-N conversion.
%results2:2 = unrealized_conversion_cast %tuple_operand : !foo.tuple_type<!foo.type, !foo.type> to !foo.type, !foo.type
// An unrealized N-1 conversion.
%result3 = unrealized_conversion_cast %operand, %operand : !foo.type, !foo.type to !bar.tuple_type<!foo.type, !foo.type>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: CastOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands: ¶

Operand | Description |
---|---|

`inputs` | any type |

#### Results: ¶

Result | Description |
---|---|

`outputs` | any type |

## Types ¶

### BFloat16Type ¶

bfloat16 floating-point type

### ComplexType ¶

Complex number with a parameterized element type

Syntax:

```
complex-type ::= `complex` `<` type `>`
```

The value of `complex`

type represents a complex number with a parameterized
element type, which is composed of a real and imaginary value of that
element type. The element must be a floating point or integer scalar type.

Examples:

```
complex<f32>
complex<i32>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

elementType | `Type` |

### Float8E4M3B11FNUZType ¶

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

- bit encoding: S1E4M3
- exponent bias: 11
- infinities: Not supported
- NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
- denormals when exponent is 0

Related to: https://dl.acm.org/doi/10.5555/3454287.3454728

### Float8E4M3FNType ¶

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values and only two NaN representations. This type has the following characteristics:

- bit encoding: S1E4M3
- exponent bias: 7
- infinities: Not supported
- NaNs: supported with exponent bits and mantissa bits set to all 1s
- denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

### Float8E4M3FNUZType ¶

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

- bit encoding: S1E4M3
- exponent bias: 8
- infinities: Not supported
- NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
- denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

### Float8E5M2Type ¶

8-bit floating point with 2 bit mantissa

An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions with the following characteristics:

- bit encoding: S1E5M2
- exponent bias: 15
- infinities: supported with exponent set to all 1s and mantissa 0s
- NaNs: supported with exponent bits set to all 1s and mantissa of (01, 10, or 11)
- denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

### Float8E5M2FNUZType ¶

8-bit floating point with 2 bit mantissa

An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

- bit encoding: S1E5M2
- exponent bias: 16
- infinities: Not supported
- NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
- denormals when exponent is 0

Described in: https://arxiv.org/abs/2206.02915

### Float16Type ¶

16-bit floating-point type

### Float32Type ¶

32-bit floating-point type

### Float64Type ¶

64-bit floating-point type

### Float80Type ¶

80-bit floating-point type

### Float128Type ¶

128-bit floating-point type

### FunctionType ¶

Map from a list of inputs to a list of results

Syntax:

```
// Function types may have multiple results.
function-result-type ::= type-list-parens | non-function-type
function-type ::= type-list-parens `->` function-result-type
```

The function type can be thought of as a function signature. It consists of a list of formal parameter types and a list of formal result types.

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

inputs | `ArrayRef<Type>` | |

results | `ArrayRef<Type>` |

### IndexType ¶

Integer-like type with unknown platform-dependent bit width

Syntax:

```
// Target word-sized integer.
index-type ::= `index`
```

The index type is a signless integer whose size is equal to the natural machine word of the target ( rationale ) and is used by the affine constructs in MLIR.

**Rationale:** integers of platform-specific bit widths are practical to
express sizes, dimensionalities and subscripts.

### IntegerType ¶

Integer type with arbitrary precision up to a fixed limit

Syntax:

```
// Sized integers like i1, i4, i8, i16, i32.
signed-integer-type ::= `si` [1-9][0-9]*
unsigned-integer-type ::= `ui` [1-9][0-9]*
signless-integer-type ::= `i` [1-9][0-9]*
integer-type ::= signed-integer-type |
unsigned-integer-type |
signless-integer-type
```

Integer types have a designated bit width and may optionally have signedness semantics.

**Rationale:** low precision integers (like `i2`

, `i4`

etc) are useful for
low-precision inference chips, and arbitrary precision integers are useful
for hardware synthesis (where a 13 bit multiplier is a lot cheaper/smaller
than a 16 bit one).

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

width | `unsigned` | |

signedness | `SignednessSemantics` |

### MemRefType ¶

Shaped reference to a region of memory

Syntax:

```
memref-type ::= `memref` `<` dimension-list-ranked type
(`,` layout-specification)? (`,` memory-space)? `>`
layout-specification ::= attribute-value
memory-space ::= attribute-value
```

A `memref`

type is a reference to a region of memory (similar to a buffer
pointer, but more powerful). The buffer pointed to by a memref can be
allocated, aliased and deallocated. A memref can be used to read and write
data from/to the memory region which it references. Memref types use the
same shape specifier as tensor types. Note that `memref<f32>`

,
`memref<0 x f32>`

, `memref<1 x 0 x f32>`

, and `memref<0 x 1 x f32>`

are all
different types.

A `memref`

is allowed to have an unknown rank (e.g. `memref<*xf32>`

). The
purpose of unranked memrefs is to allow external library functions to
receive memref arguments of any rank without versioning the functions based
on the rank. Other uses of this type are disallowed or will have undefined
behavior.

Are accepted as elements:

- built-in integer types;
- built-in index type;
- built-in floating point types;
- built-in vector types with elements of the above types;
- another memref type;
- any other type implementing
`MemRefElementTypeInterface`

.

##### Layout ¶

A memref may optionally have a layout that indicates how indices are
transformed from the multi-dimensional form into a linear address. The
layout must avoid internal aliasing, i.e., two distinct tuples of
*in-bounds* indices must be pointing to different elements in memory. The
layout is an attribute that implements `MemRefLayoutAttrInterface`

. The
bulitin dialect offers two kinds of layouts: strided and affine map, each
of which is available as an attribute. Other attributes may be used to
represent the layout as long as they can be converted to a
semi-affine map and implement the required
interface. Users of memref are expected to fallback to the affine
representation when handling unknown memref layouts. Multi-dimensional
affine forms are interpreted in *row-major* fashion.

In absence of an explicit layout, a memref is considered to have a
multi-dimensional identity affine map layout. Identity layout maps do not
contribute to the MemRef type identification and are discarded on
construction. That is, a type with an explicit identity map is
`memref<?x?xf32, (i,j)->(i,j)>`

is strictly the same as the one without a
layout, `memref<?x?xf32>`

.

##### Affine Map Layout ¶

The layout may be represented directly as an affine map from the index space
to the storage space. For example, the following figure shows an index map
which maps a 2-dimensional index from a 2x2 index space to a 3x3 index
space, using symbols `S0`

and `S1`

as offsets.

Semi-affine maps are sufficiently flexible to represent a wide variety of dense storage layouts, including row- and column-major and tiled:

```
// MxN matrix stored in row major layout in memory:
#layout_map_row_major = (i, j) -> (i, j)
// MxN matrix stored in column major layout in memory:
#layout_map_col_major = (i, j) -> (j, i)
// MxN matrix stored in a 2-d blocked/tiled layout with 64x64 tiles.
#layout_tiled = (i, j) -> (i floordiv 64, j floordiv 64, i mod 64, j mod 64)
```

##### Strided Layout ¶

Memref layout can be expressed using strides to encode the distance, in
number of elements, in (linear) memory between successive entries along a
particular dimension. For example, a row-major strided layout for
`memref<2x3x4xf32>`

is `strided<[12, 4, 1]>`

, where the last dimension is
contiguous as indicated by the unit stride and the remaining strides are
products of the sizes of faster-variying dimensions. Strided layout can also
express non-contiguity, e.g., `memref<2x3, strided<[6, 2]>>`

only accesses
even elements of the dense consecutive storage along the innermost
dimension.

The strided layout supports an optional *offset* that indicates the
distance, in the number of elements, between the beginning of the memref
and the first accessed element. When omitted, the offset is considered to
be zero. That is, `memref<2, strided<[2], offset: 0>>`

and
`memref<2, strided<[2]>>`

are strictly the same type.

Both offsets and strides may be *dynamic*, that is, unknown at compile time.
This is represented by using a question mark (`?`

) instead of the value in
the textual form of the IR.

The strided layout converts into the following canonical one-dimensional affine form through explicit linearization:

```
affine_map<(d0, ... dN)[offset, stride0, ... strideN] ->
(offset + d0 * stride0 + ... dN * strideN)>
```

Therefore, it is never subject to the implicit row-major layout interpretation.

##### Codegen of Unranked Memref ¶

Using unranked memref in codegen besides the case mentioned above is highly discouraged. Codegen is concerned with generating loop nests and specialized instructions for high-performance, unranked memref is concerned with hiding the rank and thus, the number of enclosing loops required to iterate over the data. However, if there is a need to code-gen unranked memref, one possible path is to cast into a static ranked type based on the dynamic rank. Another possible path is to emit a single while loop conditioned on a linear index and perform delinearization of the linear index to a dynamic array containing the (unranked) indices. While this is possible, it is expected to not be a good idea to perform this during codegen as the cost of the translations is expected to be prohibitive and optimizations at this level are not expected to be worthwhile. If expressiveness is the main concern, irrespective of performance, passing unranked memrefs to an external C++ library and implementing rank-agnostic logic there is expected to be significantly simpler.

Unranked memrefs may provide expressiveness gains in the future and help bridge the gap with unranked tensors. Unranked memrefs will not be expected to be exposed to codegen but one may query the rank of an unranked memref (a special op will be needed for this purpose) and perform a switch and cast to a ranked memref as a prerequisite to codegen.

Example:

```
// With static ranks, we need a function for each possible argument type
%A = alloc() : memref<16x32xf32>
%B = alloc() : memref<16x32x64xf32>
call @helper_2D(%A) : (memref<16x32xf32>)->()
call @helper_3D(%B) : (memref<16x32x64xf32>)->()
// With unknown rank, the functions can be unified under one unranked type
%A = alloc() : memref<16x32xf32>
%B = alloc() : memref<16x32x64xf32>
// Remove rank info
%A_u = memref_cast %A : memref<16x32xf32> -> memref<*xf32>
%B_u = memref_cast %B : memref<16x32x64xf32> -> memref<*xf32>
// call same function with dynamic ranks
call @helper(%A_u) : (memref<*xf32>)->()
call @helper(%B_u) : (memref<*xf32>)->()
```

The core syntax and representation of a layout specification is a
semi-affine map. Additionally,
syntactic sugar is supported to make certain layout specifications more
intuitive to read. For the moment, a `memref`

supports parsing a strided
form which is converted to a semi-affine map automatically.

The memory space of a memref is specified by a target-specific attribute. It might be an integer value, string, dictionary or custom dialect attribute. The empty memory space (attribute is None) is target specific.

The notionally dynamic value of a memref value includes the address of the buffer allocated, as well as the symbols referred to by the shape, layout map, and index maps.

Examples of memref static type

```
// Identity index/layout map
#identity = affine_map<(d0, d1) -> (d0, d1)>
// Column major layout.
#col_major = affine_map<(d0, d1, d2) -> (d2, d1, d0)>
// A 2-d tiled layout with tiles of size 128 x 256.
#tiled_2d_128x256 = affine_map<(d0, d1) -> (d0 div 128, d1 div 256, d0 mod 128, d1 mod 256)>
// A tiled data layout with non-constant tile sizes.
#tiled_dynamic = affine_map<(d0, d1)[s0, s1] -> (d0 floordiv s0, d1 floordiv s1,
d0 mod s0, d1 mod s1)>
// A layout that yields a padding on two at either end of the minor dimension.
#padded = affine_map<(d0, d1) -> (d0, (d1 + 2) floordiv 2, (d1 + 2) mod 2)>
// The dimension list "16x32" defines the following 2D index space:
//
// { (i, j) : 0 <= i < 16, 0 <= j < 32 }
//
memref<16x32xf32, #identity>
// The dimension list "16x4x?" defines the following 3D index space:
//
// { (i, j, k) : 0 <= i < 16, 0 <= j < 4, 0 <= k < N }
//
// where N is a symbol which represents the runtime value of the size of
// the third dimension.
//
// %N here binds to the size of the third dimension.
%A = alloc(%N) : memref<16x4x?xf32, #col_major>
// A 2-d dynamic shaped memref that also has a dynamically sized tiled
// layout. The memref index space is of size %M x %N, while %B1 and %B2
// bind to the symbols s0, s1 respectively of the layout map #tiled_dynamic.
// Data tiles of size %B1 x %B2 in the logical space will be stored
// contiguously in memory. The allocation size will be
// (%M ceildiv %B1) * %B1 * (%N ceildiv %B2) * %B2 f32 elements.
%T = alloc(%M, %N) [%B1, %B2] : memref<?x?xf32, #tiled_dynamic>
// A memref that has a two-element padding at either end. The allocation
// size will fit 16 * 64 float elements of data.
%P = alloc() : memref<16x64xf32, #padded>
// Affine map with symbol 's0' used as offset for the first dimension.
#imapS = affine_map<(d0, d1) [s0] -> (d0 + s0, d1)>
// Allocate memref and bind the following symbols:
// '%n' is bound to the dynamic second dimension of the memref type.
// '%o' is bound to the symbol 's0' in the affine map of the memref type.
%n = ...
%o = ...
%A = alloc (%n)[%o] : <16x?xf32, #imapS>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

shape | `::llvm::ArrayRef<int64_t>` | |

elementType | `Type` | |

layout | `MemRefLayoutAttrInterface` | |

memorySpace | `Attribute` |

### NoneType ¶

A unit type

NoneType is a unit type, i.e. a type with exactly one possible value, where its value does not have a defined dynamic representation.

### OpaqueType ¶

Type of a non-registered dialect

Syntax:

```
opaque-type ::= `opaque` `<` type `>`
```

Opaque types represent types of non-registered dialects. These are types represented in their raw string form, and can only usefully be tested for type equality.

Examples:

```
opaque<"llvm", "struct<(i32, float)>">
opaque<"pdl", "value">
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

dialectNamespace | `StringAttr` | |

typeData | `::llvm::StringRef` |

### RankedTensorType ¶

Multi-dimensional array with a fixed number of dimensions

Syntax:

```
tensor-type ::= `tensor` `<` dimension-list type (`,` encoding)? `>`
dimension-list ::= (dimension `x`)*
dimension ::= `?` | decimal-literal
encoding ::= attribute-value
```

Values with tensor type represents aggregate N-dimensional data values, and
have a known element type and a fixed rank with a list of dimensions. Each
dimension may be a static non-negative decimal constant or be dynamically
determined (indicated by `?`

).

The runtime representation of the MLIR tensor type is intentionally
abstracted - you cannot control layout or get a pointer to the data. For
low level buffer access, MLIR has a
`memref`

type. This
abstracted runtime representation holds both the tensor data values as well
as information about the (potentially dynamic) shape of the tensor. The
`dim`

operation returns the size of a
dimension from a value of tensor type.

The `encoding`

attribute provides additional information on the tensor.
An empty attribute denotes a straightforward tensor without any specific
structure. But particular properties, like sparsity or other specific
characteristics of the data of the tensor can be encoded through this
attribute. The semantics are defined by a type and attribute interface
and must be respected by all passes that operate on tensor types.
TODO: provide this interface, and document it further.

Note: hexadecimal integer literals are not allowed in tensor type
declarations to avoid confusion between `0xf32`

and `0 x f32`

. Zero sizes
are allowed in tensors and treated as other sizes, e.g.,
`tensor<0 x 1 x i32>`

and `tensor<1 x 0 x i32>`

are different types. Since
zero sizes are not allowed in some other types, such tensors should be
optimized away before lowering tensors to vectors.

Examples:

```
// Known rank but unknown dimensions.
tensor<? x ? x ? x ? x f32>
// Partially known dimensions.
tensor<? x ? x 13 x ? x f32>
// Full static shape.
tensor<17 x 4 x 13 x 4 x f32>
// Tensor with rank zero. Represents a scalar.
tensor<f32>
// Zero-element dimensions are allowed.
tensor<0 x 42 x f32>
// Zero-element tensor of f32 type (hexadecimal literals not allowed here).
tensor<0xf32>
// Tensor with an encoding attribute (where #ENCODING is a named alias).
tensor<?x?xf64, #ENCODING>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

shape | `::llvm::ArrayRef<int64_t>` | |

elementType | `Type` | |

encoding | `Attribute` |

### TupleType ¶

Fixed-sized collection of other types

Syntax:

```
tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>`
```

The value of `tuple`

type represents a fixed-size collection of elements,
where each element may be of a different type.

**Rationale:** Though this type is first class in the type system, MLIR
provides no standard operations for operating on `tuple`

types
(
rationale).

Examples:

```
// Empty tuple.
tuple<>
// Single element
tuple<f32>
// Many elements.
tuple<i32, f32, tensor<i1>, i5>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

types | `ArrayRef<Type>` |

### UnrankedMemRefType ¶

Shaped reference, with unknown rank, to a region of memory

Syntax:

```
unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>`
memory-space ::= attribute-value
```

A `memref`

type with an unknown rank (e.g. `memref<*xf32>`

). The purpose of
unranked memrefs is to allow external library functions to receive memref
arguments of any rank without versioning the functions based on the rank.
Other uses of this type are disallowed or will have undefined behavior.

See MemRefType for more information on memref types.

Examples:

```
memref<*f32>
// An unranked memref with a memory space of 10.
memref<*f32, 10>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

elementType | `Type` | |

memorySpace | `Attribute` |

### UnrankedTensorType ¶

Multi-dimensional array with unknown dimensions

Syntax:

```
tensor-type ::= `tensor` `<` `*` `x` type `>`
```

An unranked tensor is a type of tensor in which the set of dimensions have unknown rank. See RankedTensorType for more information on tensor types.

Examples:

```
tensor<*xf32>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

elementType | `Type` |

### VectorType ¶

Multi-dimensional SIMD vector type

Syntax:

```
vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`
vector-element-type ::= float-type | integer-type | index-type
vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)?
static-dim-list ::= decimal-literal (`x` decimal-literal)*
```

The vector type represents a SIMD style vector used by target-specific
operation sets like AVX or SVE. While the most common use is for 1D
vectors (e.g. vector<16 x f32>) we also support multidimensional registers
on targets that support them (like TPUs). The dimensions of a vector type
can be fixed-length, scalable, or a combination of the two. The scalable
dimensions in a vector are indicated between square brackets ([ ]), and
all fixed-length dimensions, if present, must precede the set of scalable
dimensions. That is, a `vector<2x[4]xf32>`

is valid, but `vector<[4]x2xf32>`

is not.

Vector shapes must be positive decimal integers. 0D vectors are allowed by
omitting the dimension: `vector<f32>`

.

Note: hexadecimal integer literals are not allowed in vector type
declarations, `vector<0x42xi32>`

is invalid because it is interpreted as a
2D vector with shape `(0, 42)`

and zero shapes are not allowed.

Examples:

```
// A 2D fixed-length vector of 3x42 i32 elements.
vector<3x42xi32>
// A 1D scalable-length vector that contains a multiple of 4 f32 elements.
vector<[4]xf32>
// A 2D scalable-length vector that contains a multiple of 2x8 i8 elements.
vector<[2x8]xf32>
// A 2D mixed fixed/scalable vector that contains 4 scalable vectors of 4 f32 elements.
vector<4x[4]xf32>
```

#### Parameters: ¶

Parameter | C++ type | Description |
---|---|---|

shape | `::llvm::ArrayRef<int64_t>` | |

elementType | `Type` | |

numScalableDims | `unsigned` |