blob: 927d50f3bbe1c0b0a28a3d195e4af323de035da0 [file] [log] [blame] [view]
River Riddle55de49a2020-04-11 18:38:051# MLIR Language Reference
Alex Zinenko1321f6a2018-10-24 16:47:362
Mehdi Amini90b5a382019-07-18 17:34:193MLIR (Multi-Level IR) is a compiler intermediate representation with
4similarities to traditional three-address SSA representations (like
Alex Zinenko1321f6a2018-10-24 16:47:365[LLVM IR](http://llvm.org/docs/LangRef.html) or
Quinn Phamc71fbdd2021-11-03 19:41:246[SIL](https://github.com/apple/swift/blob/main/docs/SIL.rst)), but which
Alex Zinenko1321f6a2018-10-24 16:47:367introduces notions from polyhedral loop optimization as first-class concepts.
8This hybrid design is optimized to represent, analyze, and transform high level
9dataflow graphs as well as target-specific code generated for high performance
10data parallel systems. Beyond its representational capabilities, its single
11continuous design provides a framework to lower from dataflow graphs to
12high-performance target-specific code.
13
Mogballa54f4ea2021-10-12 23:14:5714This document defines and describes the key concepts in MLIR, and is intended to
15be a dry reference document - the
16[rationale documentation](Rationale/Rationale.md),
Stephen Neuendorffer62828862020-05-15 17:33:1317[glossary](../getting_started/Glossary.md), and other content are hosted
18elsewhere.
Alex Zinenko1321f6a2018-10-24 16:47:3619
20MLIR is designed to be used in three different forms: a human-readable textual
21form suitable for debugging, an in-memory form suitable for programmatic
Mogballa54f4ea2021-10-12 23:14:5722transformations and analysis, and a compact serialized form suitable for storage
23and transport. The different forms all describe the same semantic content. This
24document describes the human-readable textual form.
Alex Zinenko1321f6a2018-10-24 16:47:3625
26[TOC]
27
River Riddle465ef552019-04-05 15:19:4228## High-Level Structure
Alex Zinenko1321f6a2018-10-24 16:47:3629
Stephen Neuendorffer62828862020-05-15 17:33:1330MLIR is fundamentally based on a graph-like data structure of nodes, called
31*Operations*, and edges, called *Values*. Each Value is the result of exactly
Mogballa54f4ea2021-10-12 23:14:5732one Operation or Block Argument, and has a *Value Type* defined by the
33[type system](#type-system). [Operations](#operations) are contained in
Stephen Neuendorffer62828862020-05-15 17:33:1334[Blocks](#blocks) and Blocks are contained in [Regions](#regions). Operations
35are also ordered within their containing block and Blocks are ordered in their
Mogballa54f4ea2021-10-12 23:14:5736containing region, although this order may or may not be semantically meaningful
37in a given [kind of region](Interfaces.md/#regionkindinterfaces)). Operations
38may also contain regions, enabling hierarchical structures to be represented.
Alex Zinenko1321f6a2018-10-24 16:47:3639
Stephen Neuendorffer62828862020-05-15 17:33:1340Operations can represent many different concepts, from higher-level concepts
Mogballa54f4ea2021-10-12 23:14:5741like function definitions, function calls, buffer allocations, view or slices of
42buffers, and process creation, to lower-level concepts like target-independent
43arithmetic, target-specific instructions, configuration registers, and logic
44gates. These different concepts are represented by different operations in MLIR
45and the set of operations usable in MLIR can be arbitrarily extended.
Stephen Neuendorffer62828862020-05-15 17:33:1346
47MLIR also provides an extensible framework for transformations on operations,
48using familiar concepts of compiler [Passes](Passes.md). Enabling an arbitrary
Mogballa54f4ea2021-10-12 23:14:5749set of passes on an arbitrary set of operations results in a significant scaling
50challenge, since each transformation must potentially take into account the
51semantics of any operation. MLIR addresses this complexity by allowing operation
52semantics to be described abstractly using [Traits](Traits.md) and
53[Interfaces](Interfaces.md), enabling transformations to operate on operations
54more generically. Traits often describe verification constraints on valid IR,
55enabling complex invariants to be captured and checked. (see
56[Op vs Operation](Tutorials/Toy/Ch-2.md/#op-vs-operation-using-mlir-operations))
Stephen Neuendorffer62828862020-05-15 17:33:1357
58One obvious application of MLIR is to represent an
59[SSA-based](https://en.wikipedia.org/wiki/Static_single_assignment_form) IR,
River Riddlecaddfbd2021-03-20 01:19:1660like the LLVM core IR, with appropriate choice of operation types to define
61Modules, Functions, Branches, Memory Allocation, and verification constraints to
62ensure the SSA Dominance property. MLIR includes a collection of dialects which
63defines just such structures. However, MLIR is intended to be general enough to
64represent other compiler-like data structures, such as Abstract Syntax Trees in
65a language frontend, generated instructions in a target-specific backend, or
66circuits in a High-Level Synthesis tool.
Alex Zinenko1321f6a2018-10-24 16:47:3667
68Here's an example of an MLIR module:
69
Alex Zinenkoac487332019-12-10 11:00:2970```mlir
Chris Lattner8ebd64b2019-01-02 20:32:3071// Compute A*B using an implementation of multiply kernel and print the
Alex Zinenko1321f6a2018-10-24 16:47:3672// result using a TensorFlow op. The dimensions of A and B are partially
73// known. The shapes are assumed to match.
Chris Lattner8ebd64b2019-01-02 20:32:3074func @mul(%A: tensor<100x?xf32>, %B: tensor<?x50xf32>) -> (tensor<100x50xf32>) {
Alex Zinenko1321f6a2018-10-24 16:47:3675 // Compute the inner dimension of %A using the dim operation.
Mogballa54f4ea2021-10-12 23:14:5776 %n = memref.dim %A, 1 : tensor<100x?xf32>
Alex Zinenko1321f6a2018-10-24 16:47:3677
78 // Allocate addressable "buffers" and copy tensors %A and %B into them.
Mogballa54f4ea2021-10-12 23:14:5779 %A_m = memref.alloc(%n) : memref<100x?xf32>
80 memref.tensor_store %A to %A_m : memref<100x?xf32>
Alex Zinenko1321f6a2018-10-24 16:47:3681
Mogballa54f4ea2021-10-12 23:14:5782 %B_m = memref.alloc(%n) : memref<?x50xf32>
83 memref.tensor_store %B to %B_m : memref<?x50xf32>
Alex Zinenko1321f6a2018-10-24 16:47:3684
River Riddle6f7470a2019-02-06 00:29:2585 // Call function @multiply passing memrefs as arguments,
Alex Zinenko1321f6a2018-10-24 16:47:3686 // and getting returned the result of the multiplication.
87 %C_m = call @multiply(%A_m, %B_m)
88 : (memref<100x?xf32>, memref<?x50xf32>) -> (memref<100x50xf32>)
89
Mogballa54f4ea2021-10-12 23:14:5790 memref.dealloc %A_m : memref<100x?xf32>
91 memref.dealloc %B_m : memref<?x50xf32>
Alex Zinenko1321f6a2018-10-24 16:47:3692
93 // Load the buffer data into a higher level "tensor" value.
Mogballa54f4ea2021-10-12 23:14:5794 %C = memref.tensor_load %C_m : memref<100x50xf32>
95 memref.dealloc %C_m : memref<100x50xf32>
Alex Zinenko1321f6a2018-10-24 16:47:3696
97 // Call TensorFlow built-in function to print the result tensor.
98 "tf.Print"(%C){message: "mul result"}
99 : (tensor<100x50xf32) -> (tensor<100x50xf32>)
100
101 return %C : tensor<100x50xf32>
102}
103
Chris Lattner8ebd64b2019-01-02 20:32:30104// A function that multiplies two memrefs and returns the result.
105func @multiply(%A: memref<100x?xf32>, %B: memref<?x50xf32>)
Alex Zinenko1321f6a2018-10-24 16:47:36106 -> (memref<100x50xf32>) {
107 // Compute the inner dimension of %A.
Mogballa54f4ea2021-10-12 23:14:57108 %n = memref.dim %A, 1 : memref<100x?xf32>
Alex Zinenko1321f6a2018-10-24 16:47:36109
110 // Allocate memory for the multiplication result.
Mogballa54f4ea2021-10-12 23:14:57111 %C = memref.alloc() : memref<100x50xf32>
Alex Zinenko1321f6a2018-10-24 16:47:36112
113 // Multiplication loop nest.
River Riddle832567b2019-03-25 17:14:34114 affine.for %i = 0 to 100 {
115 affine.for %j = 0 to 50 {
Mogballa54f4ea2021-10-12 23:14:57116 memref.store 0 to %C[%i, %j] : memref<100x50xf32>
River Riddle832567b2019-03-25 17:14:34117 affine.for %k = 0 to %n {
Mogballa54f4ea2021-10-12 23:14:57118 %a_v = memref.load %A[%i, %k] : memref<100x?xf32>
119 %b_v = memref.load %B[%k, %j] : memref<?x50xf32>
120 %prod = arith.mulf %a_v, %b_v : f32
121 %c_v = memref.load %C[%i, %j] : memref<100x50xf32>
122 %sum = arith.addf %c_v, %prod : f32
123 memref.store %sum, %C[%i, %j] : memref<100x50xf32>
Alex Zinenko1321f6a2018-10-24 16:47:36124 }
125 }
126 }
127 return %C : memref<100x50xf32>
128}
129```
130
River Riddle465ef552019-04-05 15:19:42131## Notation
Alex Zinenko1321f6a2018-10-24 16:47:36132
133MLIR has a simple and unambiguous grammar, allowing it to reliably round-trip
Mogballa54f4ea2021-10-12 23:14:57134through a textual form. This is important for development of the compiler - e.g.
135for understanding the state of code as it is being transformed and writing test
136cases.
Alex Zinenko1321f6a2018-10-24 16:47:36137
138This document describes the grammar using
139[Extended Backus-Naur Form (EBNF)](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form).
140
141This is the EBNF grammar used in this document, presented in yellow boxes.
142
Alex Zinenkoac487332019-12-10 11:00:29143```
Alex Zinenko1321f6a2018-10-24 16:47:36144alternation ::= expr0 | expr1 | expr2 // Either expr0 or expr1 or expr2.
145sequence ::= expr0 expr1 expr2 // Sequence of expr0 expr1 expr2.
146repetition0 ::= expr* // 0 or more occurrences.
147repetition1 ::= expr+ // 1 or more occurrences.
148optionality ::= expr? // 0 or 1 occurrence.
149grouping ::= (expr) // Everything inside parens is grouped together.
150literal ::= `abcd` // Matches the literal `abcd`.
151```
152
153Code examples are presented in blue boxes.
154
Alex Zinenkoac487332019-12-10 11:00:29155```mlir
Alex Zinenko1321f6a2018-10-24 16:47:36156// This is an example use of the grammar above:
157// This matches things like: ba, bana, boma, banana, banoma, bomana...
158example ::= `b` (`an` | `om`)* `a`
159```
160
River Riddle465ef552019-04-05 15:19:42161### Common syntax
Alex Zinenko1321f6a2018-10-24 16:47:36162
163The following core grammar productions are used in this document:
164
Alex Zinenkoac487332019-12-10 11:00:29165```
Alex Zinenko1321f6a2018-10-24 16:47:36166// TODO: Clarify the split between lexing (tokens) and parsing (grammar).
167digit ::= [0-9]
168hex_digit ::= [0-9a-fA-F]
169letter ::= [a-zA-Z]
170id-punct ::= [$._-]
171
Alex Zinenko99b19c12019-02-07 16:36:50172integer-literal ::= decimal-literal | hexadecimal-literal
173decimal-literal ::= digit+
174hexadecimal-literal ::= `0x` hex_digit+
Andrew Andersona50f8712019-11-26 01:53:20175float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
River Riddle9db53a12020-07-07 08:35:23176string-literal ::= `"` [^"\n\f\v\r]* `"` TODO: define escaping rules
Alex Zinenko1321f6a2018-10-24 16:47:36177```
178
179Not listed here, but MLIR does support comments. They use standard BCPL syntax,
180starting with a `//` and going until the end of the line.
181
Siddharth Bhat357f2d92022-01-21 11:32:39182
183### Top level Productions
184
185```
186// Top level production
187toplevel := (operation | attribute-alias-def | type-alias-def)*
188```
189
190The production `toplevel` is the top level production that is parsed by any parsing
191consuming the MLIR syntax. [Operations](#operations),
192[Attribute alises](#attribute-value-aliases), and [Type aliases](#type-aliases)
193can be declared on the toplevel.
194
River Riddle465ef552019-04-05 15:19:42195### Identifiers and keywords
Alex Zinenko1321f6a2018-10-24 16:47:36196
197Syntax:
198
Alex Zinenkoac487332019-12-10 11:00:29199```
Alex Zinenko1321f6a2018-10-24 16:47:36200// Identifiers
River Riddle3b3e11d2019-02-27 00:43:12201bare-id ::= (letter|[_]) (letter|digit|[_$.])*
Alex Zinenko1321f6a2018-10-24 16:47:36202bare-id-list ::= bare-id (`,` bare-id)*
Stephen Neuendorffer62828862020-05-15 17:33:13203value-id ::= `%` suffix-id
River Riddle31b3e222019-12-04 20:05:52204suffix-id ::= (digit+ | ((letter|id-punct) (letter|id-punct|digit)*))
Alex Zinenko1321f6a2018-10-24 16:47:36205
River Riddle31b3e222019-12-04 20:05:52206symbol-ref-id ::= `@` (suffix-id | string-literal)
Stephen Neuendorffer62828862020-05-15 17:33:13207value-id-list ::= value-id (`,` value-id)*
Alex Zinenko1321f6a2018-10-24 16:47:36208
Stephen Neuendorffer62828862020-05-15 17:33:13209// Uses of value, e.g. in an operand list to an operation.
210value-use ::= value-id
211value-use-list ::= value-use (`,` value-use)*
Alex Zinenko1321f6a2018-10-24 16:47:36212```
213
Mogballa54f4ea2021-10-12 23:14:57214Identifiers name entities such as values, types and functions, and are chosen by
215the writer of MLIR code. Identifiers may be descriptive (e.g. `%batch_size`,
216`@matmul`), or may be non-descriptive when they are auto-generated (e.g. `%23`,
217`@func42`). Identifier names for values may be used in an MLIR text file but are
218not persisted as part of the IR - the printer will give them anonymous names
219like `%42`.
Alex Zinenko1321f6a2018-10-24 16:47:36220
221MLIR guarantees identifiers never collide with keywords by prefixing identifiers
Chris Lattner3f93d932019-04-06 02:36:42222with a sigil (e.g. `%`, `#`, `@`, `^`, `!`). In certain unambiguous contexts
223(e.g. affine expressions), identifiers are not prefixed, for brevity. New
224keywords may be added to future versions of MLIR without danger of collision
225with existing identifiers.
Alex Zinenko1321f6a2018-10-24 16:47:36226
Mogballa54f4ea2021-10-12 23:14:57227Value identifiers are only [in scope](#value-scoping) for the (nested) region in
228which they are defined and cannot be accessed or referenced outside of that
229region. Argument identifiers in mapping functions are in scope for the mapping
230body. Particular operations may further limit which identifiers are in scope in
231their regions. For instance, the scope of values in a region with
232[SSA control flow semantics](#control-flow-and-ssacfg-regions) is constrained
233according to the standard definition of
234[SSA dominance](https://en.wikipedia.org/wiki/Dominator_\(graph_theory\)).
235Another example is the [IsolatedFromAbove trait](Traits.md/#isolatedfromabove),
236which restricts directly accessing values defined in containing regions.
Stephen Neuendorffer62828862020-05-15 17:33:13237
238Function identifiers and mapping identifiers are associated with
Mogballa54f4ea2021-10-12 23:14:57239[Symbols](SymbolsAndSymbolTables.md) and have scoping rules dependent on symbol
240attributes.
Alex Zinenko1321f6a2018-10-24 16:47:36241
River Riddle986f9302019-08-22 22:53:41242## Dialects
243
Lucy Fox9d7039b2019-11-15 17:48:54244Dialects are the mechanism by which to engage with and extend the MLIR
River Riddle986f9302019-08-22 22:53:41245ecosystem. They allow for defining new [operations](#operations), as well as
246[attributes](#attributes) and [types](#type-system). Each dialect is given a
247unique `namespace` that is prefixed to each defined attribute/operation/type.
248For example, the [Affine dialect](Dialects/Affine.md) defines the namespace:
249`affine`.
250
251MLIR allows for multiple dialects, even those outside of the main tree, to
252co-exist together within one module. Dialects are produced and consumed by
253certain passes. MLIR provides a [framework](DialectConversion.md) to convert
Lucy Fox9d7039b2019-11-15 17:48:54254between, and within, different dialects.
River Riddle986f9302019-08-22 22:53:41255
256A few of the dialects supported by MLIR:
257
258* [Affine dialect](Dialects/Affine.md)
River Riddle23aa5a72022-02-26 22:49:54259* [Func dialect](Dialects/Func.md)
River Riddle986f9302019-08-22 22:53:41260* [GPU dialect](Dialects/GPU.md)
261* [LLVM dialect](Dialects/LLVM.md)
262* [SPIR-V dialect](Dialects/SPIR-V.md)
River Riddle986f9302019-08-22 22:53:41263* [Vector dialect](Dialects/Vector.md)
264
265### Target specific operations
266
267Dialects provide a modular way in which targets can expose target-specific
268operations directly through to MLIR. As an example, some targets go through
269LLVM. LLVM has a rich set of intrinsics for certain target-independent
270operations (e.g. addition with overflow check) as well as providing access to
Mogballa54f4ea2021-10-12 23:14:57271target-specific operations for the targets it supports (e.g. vector permutation
272operations). LLVM intrinsics in MLIR are represented via operations that start
273with an "llvm." name.
River Riddle986f9302019-08-22 22:53:41274
275Example:
276
Alex Zinenkoac487332019-12-10 11:00:29277```mlir
River Riddle986f9302019-08-22 22:53:41278// LLVM: %x = call {i16, i1} @llvm.sadd.with.overflow.i16(i16 %a, i16 %b)
279%x:2 = "llvm.sadd.with.overflow.i16"(%a, %b) : (i16, i16) -> (i16, i1)
280```
281
282These operations only work when targeting LLVM as a backend (e.g. for CPUs and
283GPUs), and are required to align with the LLVM definition of these intrinsics.
284
River Riddlef772d2c2019-08-23 17:08:42285## Operations
286
287Syntax:
288
Alex Zinenkoac487332019-12-10 11:00:29289```
Geoffrey Martin-Noble22411d82021-04-06 04:32:23290operation ::= op-result-list? (generic-operation | custom-operation)
291 trailing-location?
292generic-operation ::= string-literal `(` value-use-list? `)` successor-list?
293 region-list? dictionary-attribute? `:` function-type
294custom-operation ::= bare-id custom-operation-format
295op-result-list ::= op-result (`,` op-result)* `=`
296op-result ::= value-id (`:` integer-literal)
297successor-list ::= `[` successor (`,` successor)* `]`
298successor ::= caret-id (`:` bb-arg-list)?
299region-list ::= `(` region (`,` region)* `)`
300dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`
301trailing-location ::= (`loc` `(` location `)`)?
River Riddlef772d2c2019-08-23 17:08:42302```
303
Mogballa54f4ea2021-10-12 23:14:57304MLIR introduces a uniform concept called *operations* to enable describing many
305different levels of abstractions and computations. Operations in MLIR are fully
306extensible (there is no fixed list of operations) and have application-specific
307semantics. For example, MLIR supports
308[target-independent operations](Dialects/Standard.md#memory-operations),
309[affine operations](Dialects/Affine.md), and
310[target-specific machine operations](#target-specific-operations).
River Riddlef772d2c2019-08-23 17:08:42311
312The internal representation of an operation is simple: an operation is
313identified by a unique string (e.g. `dim`, `tf.Conv2d`, `x86.repmovsb`,
Mogballa54f4ea2021-10-12 23:14:57314`ppc.eieio`, etc), can return zero or more results, take zero or more operands,
315has a dictionary of [attributes](#attributes), has zero or more successors, and
316zero or more enclosed [regions](#regions). The generic printing form includes
317all these elements literally, with a function type to indicate the types of the
318results and operands.
River Riddlef772d2c2019-08-23 17:08:42319
320Example:
321
Alex Zinenkoac487332019-12-10 11:00:29322```mlir
River Riddlef772d2c2019-08-23 17:08:42323// An operation that produces two results.
324// The results of %result can be accessed via the <name> `#` <opNo> syntax.
325%result:2 = "foo_div"() : () -> (f32, i32)
326
327// Pretty form that defines a unique name for each result.
328%foo, %bar = "foo_div"() : () -> (f32, i32)
329
330// Invoke a TensorFlow function called tf.scramble with two inputs
331// and an attribute "fruit".
Sean Silva6b07a972021-02-05 00:17:45332%2 = "tf.scramble"(%result#0, %bar) {fruit = "banana"} : (f32, i32) -> f32
River Riddlef772d2c2019-08-23 17:08:42333```
334
335In addition to the basic syntax above, dialects may register known operations.
Mogballa54f4ea2021-10-12 23:14:57336This allows those dialects to support *custom assembly form* for parsing and
River Riddlef772d2c2019-08-23 17:08:42337printing operations. In the operation sets listed below, we show both forms.
338
River Riddlecaddfbd2021-03-20 01:19:16339### Builtin Operations
River Riddlef772d2c2019-08-23 17:08:42340
River Riddlecaddfbd2021-03-20 01:19:16341The [builtin dialect](Dialects/Builtin.md) defines a select few operations that
342are widely applicable by MLIR dialects, such as a universal conversion cast
343operation that simplifies inter/intra dialect conversion. This dialect also
344defines a top-level `module` operation, that represents a useful IR container.
River Riddlef772d2c2019-08-23 17:08:42345
346## Blocks
347
348Syntax:
349
Alex Zinenkoac487332019-12-10 11:00:29350```
River Riddle31b3e222019-12-04 20:05:52351block ::= block-label operation+
352block-label ::= block-id block-arg-list? `:`
353block-id ::= caret-id
354caret-id ::= `^` suffix-id
Stephen Neuendorffer62828862020-05-15 17:33:13355value-id-and-type ::= value-id `:` type
River Riddlef772d2c2019-08-23 17:08:42356
357// Non-empty list of names and types.
Stephen Neuendorffer62828862020-05-15 17:33:13358value-id-and-type-list ::= value-id-and-type (`,` value-id-and-type)*
River Riddlef772d2c2019-08-23 17:08:42359
Stephen Neuendorffer62828862020-05-15 17:33:13360block-arg-list ::= `(` value-id-and-type-list? `)`
River Riddlef772d2c2019-08-23 17:08:42361```
362
Mogballa54f4ea2021-10-12 23:14:57363A *Block* is a list of operations. In
364[SSACFG regions](#control-flow-and-ssacfg-regions), each block represents a
365compiler [basic block](https://en.wikipedia.org/wiki/Basic_block) where
366instructions inside the block are executed in order and terminator operations
367implement control flow branches between basic blocks.
River Riddlef772d2c2019-08-23 17:08:42368
Mogballa54f4ea2021-10-12 23:14:57369A region with a single block may not include a
370[terminator operation](#terminator-operations). The enclosing op can opt-out of
371this requirement with the `NoTerminator` trait. The top-level `ModuleOp` is an
372example of such operation which defined this trait and whose block body does not
373have a terminator.
Mehdi Amini973ddb72021-03-11 23:58:02374
Mogballa54f4ea2021-10-12 23:14:57375Blocks in MLIR take a list of block arguments, notated in a function-like way.
376Block arguments are bound to values specified by the semantics of individual
377operations. Block arguments of the entry block of a region are also arguments to
378the region and the values bound to these arguments are determined by the
379semantics of the containing operation. Block arguments of other blocks are
380determined by the semantics of terminator operations, e.g. Branches, which have
381the block as a successor. In regions with
382[control flow](#control-flow-and-ssacfg-regions), MLIR leverages this structure
383to implicitly represent the passage of control-flow dependent values without the
Stephen Neuendorffer62828862020-05-15 17:33:13384complex nuances of PHI nodes in traditional SSA representations. Note that
385values which are not control-flow dependent can be referenced directly and do
386not need to be passed through block arguments.
River Riddlef772d2c2019-08-23 17:08:42387
388Here is a simple example function showing branches, returns, and block
389arguments:
390
Alex Zinenkoac487332019-12-10 11:00:29391```mlir
River Riddlef772d2c2019-08-23 17:08:42392func @simple(i64, i1) -> i64 {
393^bb0(%a: i64, %cond: i1): // Code dominated by ^bb0 may refer to %a
River Riddleace01602022-02-04 04:59:43394 cf.cond_br %cond, ^bb1, ^bb2
River Riddlef772d2c2019-08-23 17:08:42395
396^bb1:
River Riddleace01602022-02-04 04:59:43397 cf.br ^bb3(%a: i64) // Branch passes %a as the argument
River Riddlef772d2c2019-08-23 17:08:42398
399^bb2:
Mogballa54f4ea2021-10-12 23:14:57400 %b = arith.addi %a, %a : i64
River Riddleace01602022-02-04 04:59:43401 cf.br ^bb3(%b: i64) // Branch passes %b as the argument
River Riddlef772d2c2019-08-23 17:08:42402
403// ^bb3 receives an argument, named %c, from predecessors
Stephen Neuendorffer62828862020-05-15 17:33:13404// and passes it on to bb4 along with %a. %a is referenced
405// directly from its defining operation and is not passed through
406// an argument of ^bb3.
River Riddlef772d2c2019-08-23 17:08:42407^bb3(%c: i64):
River Riddleace01602022-02-04 04:59:43408 cf.br ^bb4(%c, %a : i64, i64)
River Riddlef772d2c2019-08-23 17:08:42409
410^bb4(%d : i64, %e : i64):
Mogballa54f4ea2021-10-12 23:14:57411 %0 = arith.addi %d, %e : i64
Stephen Neuendorffer62828862020-05-15 17:33:13412 return %0 : i64 // Return is also a terminator.
River Riddlef772d2c2019-08-23 17:08:42413}
414```
415
Mogballa54f4ea2021-10-12 23:14:57416**Context:** The "block argument" representation eliminates a number of special
417cases from the IR compared to traditional "PHI nodes are operations" SSA IRs
418(like LLVM). For example, the
419[parallel copy semantics](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.524.5461&rep=rep1&type=pdf)
420of SSA is immediately apparent, and function arguments are no longer a special
421case: they become arguments to the entry block
422[[more rationale](Rationale/Rationale.md/#block-arguments-vs-phi-nodes)]. Blocks
423are also a fundamental concept that cannot be represented by operations because
424values defined in an operation cannot be accessed outside the operation.
River Riddlef772d2c2019-08-23 17:08:42425
426## Regions
427
428### Definition
429
Stephen Neuendorffer62828862020-05-15 17:33:13430A region is an ordered list of MLIR [Blocks](#blocks). The semantics within a
431region is not imposed by the IR. Instead, the containing operation defines the
432semantics of the regions it contains. MLIR currently defines two kinds of
433regions: [SSACFG regions](#control-flow-and-ssacfg-regions), which describe
434control flow between blocks, and [Graph regions](#graph-regions), which do not
Mogballa54f4ea2021-10-12 23:14:57435require control flow between block. The kinds of regions within an operation are
436described using the [RegionKindInterface](Interfaces.md/#regionkindinterfaces).
River Riddlef772d2c2019-08-23 17:08:42437
Mogballa54f4ea2021-10-12 23:14:57438Regions do not have a name or an address, only the blocks contained in a region
439do. Regions must be contained within operations and have no type or attributes.
440The first block in the region is a special block called the 'entry block'. The
441arguments to the entry block are also the arguments of the region itself. The
442entry block cannot be listed as a successor of any other block. The syntax for a
443region is as follows:
River Riddlef772d2c2019-08-23 17:08:42444
Alex Zinenkoac487332019-12-10 11:00:29445```
Siddharth Bhat24a37a32022-02-17 10:10:19446region ::= `{` entry-block? block* `}`
447entry-block ::= operation+
River Riddlef772d2c2019-08-23 17:08:42448```
449
Stephen Neuendorffer62828862020-05-15 17:33:13450A function body is an example of a region: it consists of a CFG of blocks and
451has additional semantic restrictions that other types of regions may not have.
452For example, in a function body, block terminators must either branch to a
453different block, or return from a function where the types of the `return`
Mogballa54f4ea2021-10-12 23:14:57454arguments must match the result types of the function signature. Similarly, the
455function arguments must match the types and count of the region arguments. In
Markus Böck286a7a42021-10-29 07:19:11456general, operations with regions can define these correspondences arbitrarily.
River Riddlef772d2c2019-08-23 17:08:42457
Siddharth Bhat24a37a32022-02-17 10:10:19458An *entry block* is a block with no label and no arguments that may occur at
459the beginning of a region. It enables a common pattern of using a region to
460open a new scope.
461
462
Stephen Neuendorffer62828862020-05-15 17:33:13463### Value Scoping
River Riddlef772d2c2019-08-23 17:08:42464
Stephen Neuendorffer62828862020-05-15 17:33:13465Regions provide hierarchical encapsulation of programs: it is impossible to
Mogballa54f4ea2021-10-12 23:14:57466reference, i.e. branch to, a block which is not in the same region as the source
467of the reference, i.e. a terminator operation. Similarly, regions provides a
468natural scoping for value visibility: values defined in a region don't escape to
469the enclosing region, if any. By default, operations inside a region can
470reference values defined outside of the region whenever it would have been legal
471for operands of the enclosing operation to reference those values, but this can
472be restricted using traits, such as
Markus Böckd35bd982021-05-24 16:40:39473[OpTrait::IsolatedFromAbove](Traits.md/#isolatedfromabove), or a custom
Stephen Neuendorffer62828862020-05-15 17:33:13474verifier.
River Riddlef772d2c2019-08-23 17:08:42475
476Example:
477
Alex Zinenkoac487332019-12-10 11:00:29478```mlir
Stephen Neuendorffer62828862020-05-15 17:33:13479 "any_op"(%a) ({ // if %a is in-scope in the containing region...
Mogballa54f4ea2021-10-12 23:14:57480 // then %a is in-scope here too.
Stephen Neuendorffer62828862020-05-15 17:33:13481 %new_value = "another_op"(%a) : (i64) -> (i64)
482 }) : (i64) -> (i64)
483```
484
Mogballa54f4ea2021-10-12 23:14:57485MLIR defines a generalized 'hierarchical dominance' concept that operates across
486hierarchy and defines whether a value is 'in scope' and can be used by a
487particular operation. Whether a value can be used by another operation in the
488same region is defined by the kind of region. A value defined in a region can be
489used by an operation which has a parent in the same region, if and only if the
490parent could use the value. A value defined by an argument to a region can
491always be used by any operation deeply contained in the region. A value defined
492in a region can never be used outside of the region.
Stephen Neuendorffer62828862020-05-15 17:33:13493
494### Control Flow and SSACFG Regions
495
496In MLIR, control flow semantics of a region is indicated by
Mogballa54f4ea2021-10-12 23:14:57497[RegionKind::SSACFG](Interfaces.md/#regionkindinterfaces). Informally, these
498regions support semantics where operations in a region 'execute sequentially'.
499Before an operation executes, its operands have well-defined values. After an
500operation executes, the operands have the same values and results also have
501well-defined values. After an operation executes, the next operation in the
502block executes until the operation is the terminator operation at the end of a
503block, in which case some other operation will execute. The determination of the
504next instruction to execute is the 'passing of control flow'.
Stephen Neuendorffer62828862020-05-15 17:33:13505
Mogballa54f4ea2021-10-12 23:14:57506In general, when control flow is passed to an operation, MLIR does not restrict
507when control flow enters or exits the regions contained in that operation.
508However, when control flow enters a region, it always begins in the first block
509of the region, called the *entry* block. Terminator operations ending each block
510represent control flow by explicitly specifying the successor blocks of the
511block. Control flow can only pass to one of the specified successor blocks as in
512a `branch` operation, or back to the containing operation as in a `return`
513operation. Terminator operations without successors can only pass control back
514to the containing operation. Within these restrictions, the particular semantics
515of terminator operations is determined by the specific dialect operations
516involved. Blocks (other than the entry block) that are not listed as a successor
517of a terminator operation are defined to be unreachable and can be removed
518without affecting the semantics of the containing operation.
Stephen Neuendorffer62828862020-05-15 17:33:13519
520Although control flow always enters a region through the entry block, control
521flow may exit a region through any block with an appropriate terminator. The
522standard dialect leverages this capability to define operations with
523Single-Entry-Multiple-Exit (SEME) regions, possibly flowing through different
Mogballa54f4ea2021-10-12 23:14:57524blocks in the region and exiting through any block with a `return` operation.
525This behavior is similar to that of a function body in most programming
526languages. In addition, control flow may also not reach the end of a block or
527region, for example if a function call does not return.
Stephen Neuendorffer62828862020-05-15 17:33:13528
529Example:
530
531```mlir
532func @accelerator_compute(i64, i1) -> i64 { // An SSACFG region
River Riddlef772d2c2019-08-23 17:08:42533^bb0(%a: i64, %cond: i1): // Code dominated by ^bb0 may refer to %a
River Riddleace01602022-02-04 04:59:43534 cf.cond_br %cond, ^bb1, ^bb2
River Riddlef772d2c2019-08-23 17:08:42535
536^bb1:
537 // This def for %value does not dominate ^bb2
538 %value = "op.convert"(%a) : (i64) -> i64
River Riddleace01602022-02-04 04:59:43539 cf.br ^bb3(%a: i64) // Branch passes %a as the argument
River Riddlef772d2c2019-08-23 17:08:42540
541^bb2:
Stephen Neuendorffer62828862020-05-15 17:33:13542 accelerator.launch() { // An SSACFG region
River Riddlef772d2c2019-08-23 17:08:42543 ^bb0:
Kazuaki Ishizakia2bce652019-09-25 18:57:13544 // Region of code nested under "accelerator.launch", it can reference %a but
River Riddlef772d2c2019-08-23 17:08:42545 // not %value.
546 %new_value = "accelerator.do_something"(%a) : (i64) -> ()
547 }
548 // %new_value cannot be referenced outside of the region
Kazuaki Ishizakia2bce652019-09-25 18:57:13549
550^bb3:
551 ...
River Riddlef772d2c2019-08-23 17:08:42552}
553```
554
Stephen Neuendorffer62828862020-05-15 17:33:13555#### Operations with Multiple Regions
River Riddlef772d2c2019-08-23 17:08:42556
Stephen Neuendorffer62828862020-05-15 17:33:13557An operation containing multiple regions also completely determines the
558semantics of those regions. In particular, when control flow is passed to an
559operation, it may transfer control flow to any contained region. When control
Mogballa54f4ea2021-10-12 23:14:57560flow exits a region and is returned to the containing operation, the containing
561operation may pass control flow to any region in the same operation. An
562operation may also pass control flow to multiple contained regions concurrently.
563An operation may also pass control flow into regions that were specified in
564other operations, in particular those that defined the values or symbols the
565given operation uses as in a call operation. This passage of control is
566generally independent of passage of control flow through the basic blocks of the
567containing region.
River Riddlef772d2c2019-08-23 17:08:42568
569#### Closure
570
571Regions allow defining an operation that creates a closure, for example by
572“boxing” the body of the region into a value they produce. It remains up to the
573operation to define its semantics. Note that if an operation triggers
574asynchronous execution of the region, it is under the responsibility of the
575operation caller to wait for the region to be executed guaranteeing that any
576directly used values remain live.
577
Stephen Neuendorffer62828862020-05-15 17:33:13578### Graph Regions
579
580In MLIR, graph-like semantics in a region is indicated by
Markus Böckd35bd982021-05-24 16:40:39581[RegionKind::Graph](Interfaces.md/#regionkindinterfaces). Graph regions are
Stephen Neuendorffer62828862020-05-15 17:33:13582appropriate for concurrent semantics without control flow, or for modeling
583generic directed graph data structures. Graph regions are appropriate for
584representing cyclic relationships between coupled values where there is no
585fundamental order to the relationships. For instance, operations in a graph
586region may represent independent threads of control with values representing
587streams of data. As usual in MLIR, the particular semantics of a region is
588completely determined by its containing operation. Graph regions may only
589contain a single basic block (the entry block).
590
Mogballa54f4ea2021-10-12 23:14:57591**Rationale:** Currently graph regions are arbitrarily limited to a single basic
592block, although there is no particular semantic reason for this limitation. This
593limitation has been added to make it easier to stabilize the pass infrastructure
594and commonly used passes for processing graph regions to properly handle
595feedback loops. Multi-block regions may be allowed in the future if use cases
596that require it arise.
Stephen Neuendorffer62828862020-05-15 17:33:13597
598In graph regions, MLIR operations naturally represent nodes, while each MLIR
599value represents a multi-edge connecting a single source node and multiple
Mogballa54f4ea2021-10-12 23:14:57600destination nodes. All values defined in the region as results of operations are
601in scope within the region and can be accessed by any other operation in the
602region. In graph regions, the order of operations within a block and the order
603of blocks in a region is not semantically meaningful and non-terminator
Stephen Neuendorffer62828862020-05-15 17:33:13604operations may be freely reordered, for instance, by canonicalization. Other
605kinds of graphs, such as graphs with multiple source nodes and multiple
606destination nodes, can also be represented by representing graph edges as MLIR
607operations.
608
609Note that cycles can occur within a single block in a graph region, or between
610basic blocks.
611
612```mlir
613"test.graph_region"() ({ // A Graph region
614 %1 = "op1"(%1, %3) : (i32, i32) -> (i32) // OK: %1, %3 allowed here
615 %2 = "test.ssacfg_region"() ({
Mogballa54f4ea2021-10-12 23:14:57616 %5 = "op2"(%1, %2, %3, %4) : (i32, i32, i32, i32) -> (i32) // OK: %1, %2, %3, %4 all defined in the containing region
Stephen Neuendorffer62828862020-05-15 17:33:13617 }) : () -> (i32)
618 %3 = "op2"(%1, %4) : (i32, i32) -> (i32) // OK: %4 allowed here
619 %4 = "op3"(%1) : (i32) -> (i32)
620}) : () -> ()
621```
622
River Riddlef772d2c2019-08-23 17:08:42623### Arguments and Results
624
625The arguments of the first block of a region are treated as arguments of the
626region. The source of these arguments is defined by the semantics of the parent
627operation. They may correspond to some of the values the operation itself uses.
628
629Regions produce a (possibly empty) list of values. The operation semantics
630defines the relation between the region results and the operation results.
631
River Riddle9fc16572019-08-22 23:43:06632## Type System
633
River Riddlecaddfbd2021-03-20 01:19:16634Each value in MLIR has a type defined by the type system. MLIR has an open type
635system (i.e. there is no fixed list of types), and types may have
636application-specific semantics. MLIR dialects may define any number of types
637with no restrictions on the abstractions they represent.
River Riddle9fc16572019-08-22 23:43:06638
Alex Zinenkoac487332019-12-10 11:00:29639```
River Riddle09f7a552020-12-04 01:22:29640type ::= type-alias | dialect-type | builtin-type
River Riddle9fc16572019-08-22 23:43:06641
642type-list-no-parens ::= type (`,` type)*
643type-list-parens ::= `(` `)`
644 | `(` type-list-no-parens `)`
645
Stephen Neuendorffer62828862020-05-15 17:33:13646// This is a common way to refer to a value with a specified type.
River Riddle9fc16572019-08-22 23:43:06647ssa-use-and-type ::= ssa-use `:` type
648
649// Non-empty list of names and types.
650ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
651```
652
653### Type Aliases
654
Alex Zinenkoac487332019-12-10 11:00:29655```
River Riddle9fc16572019-08-22 23:43:06656type-alias-def ::= '!' alias-name '=' 'type' type
657type-alias ::= '!' alias-name
658```
659
660MLIR supports defining named aliases for types. A type alias is an identifier
661that can be used in the place of the type that it defines. These aliases *must*
662be defined before their uses. Alias names may not contain a '.', since those
663names are reserved for [dialect types](#dialect-types).
664
665Example:
666
Alex Zinenkoac487332019-12-10 11:00:29667```mlir
River Riddle9fc16572019-08-22 23:43:06668!avx_m128 = type vector<4 x f32>
669
670// Using the original type.
671"foo"(%x) : vector<4 x f32> -> ()
672
673// Using the type alias.
674"foo"(%x) : !avx_m128 -> ()
675```
676
River Riddlefc86c572019-08-23 00:51:06677### Dialect Types
River Riddle986f9302019-08-22 22:53:41678
679Similarly to operations, dialects may define custom extensions to the type
River Riddle9fc16572019-08-22 23:43:06680system.
River Riddle986f9302019-08-22 22:53:41681
Alex Zinenkoac487332019-12-10 11:00:29682```
Andrew Andersona50f8712019-11-26 01:53:20683dialect-namespace ::= bare-id
River Riddle986f9302019-08-22 22:53:41684
Andrew Andersona50f8712019-11-26 01:53:20685opaque-dialect-item ::= dialect-namespace '<' string-literal '>'
686
687pretty-dialect-item ::= dialect-namespace '.' pretty-dialect-item-lead-ident
688 pretty-dialect-item-body?
689
690pretty-dialect-item-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
691pretty-dialect-item-body ::= '<' pretty-dialect-item-contents+ '>'
692pretty-dialect-item-contents ::= pretty-dialect-item-body
693 | '(' pretty-dialect-item-contents+ ')'
694 | '[' pretty-dialect-item-contents+ ']'
695 | '{' pretty-dialect-item-contents+ '}'
River Riddle986f9302019-08-22 22:53:41696 | '[^[<({>\])}\0]+'
Andrew Andersona50f8712019-11-26 01:53:20697
698dialect-type ::= '!' opaque-dialect-item
699dialect-type ::= '!' pretty-dialect-item
River Riddle986f9302019-08-22 22:53:41700```
701
702Dialect types can be specified in a verbose form, e.g. like this:
703
Alex Zinenkoac487332019-12-10 11:00:29704```mlir
River Riddle986f9302019-08-22 22:53:41705// LLVM type that wraps around llvm IR types.
706!llvm<"i32*">
707
708// Tensor flow string type.
709!tf.string
710
711// Complex type
712!foo<"something<abcd>">
713
714// Even more complex type
715!foo<"something<a%%123^^^>>>">
716```
717
718Dialect types that are simple enough can use the pretty format, which is a
719lighter weight syntax that is equivalent to the above forms:
720
Alex Zinenkoac487332019-12-10 11:00:29721```mlir
River Riddle986f9302019-08-22 22:53:41722// Tensor flow string type.
723!tf.string
724
725// Complex type
726!foo.something<abcd>
727```
728
729Sufficiently complex dialect types are required to use the verbose form for
730generality. For example, the more complex type shown above wouldn't be valid in
731the lighter syntax: `!foo.something<a%%123^^^>>>` because it contains characters
732that are not allowed in the lighter syntax, as well as unbalanced `<>`
733characters.
734
River Riddlecaddfbd2021-03-20 01:19:16735See [here](Tutorials/DefiningAttributesAndTypes.md) to learn how to define
736dialect types.
River Riddle986f9302019-08-22 22:53:41737
River Riddle09f7a552020-12-04 01:22:29738### Builtin Types
Alex Zinenko1321f6a2018-10-24 16:47:36739
River Riddlecaddfbd2021-03-20 01:19:16740The [builtin dialect](Dialects/Builtin.md) defines a set of types that are
741directly usable by any other dialect in MLIR. These types cover a range from
742primitive integer and floating-point types, function types, and more.
River Riddle1316db32019-04-28 01:35:04743
River Riddle465ef552019-04-05 15:19:42744## Attributes
Alex Zinenko1321f6a2018-10-24 16:47:36745
746Syntax:
747
Alex Zinenkoac487332019-12-10 11:00:29748```
Sean Silva6b07a972021-02-05 00:17:45749attribute-entry ::= (bare-id | string-literal) `=` attribute-value
750attribute-value ::= attribute-alias | dialect-attribute | builtin-attribute
Alex Zinenko1321f6a2018-10-24 16:47:36751```
752
River Riddlefc86c572019-08-23 00:51:06753Attributes are the mechanism for specifying constant data on operations in
Sean Silva042db542021-02-04 21:27:25754places where a variable is never allowed - e.g. the comparison predicate of a
Sean Silva6b07a972021-02-05 00:17:45755[`cmpi` operation](Dialects/Standard.md#stdcmpi-cmpiop). Each operation has an
756attribute dictionary, which associates a set of attribute names to attribute
757values. MLIR's builtin dialect provides a rich set of
758[builtin attribute values](#builtin-attribute-values) out of the box (such as
759arrays, dictionaries, strings, etc.). Additionally, dialects can define their
760own [dialect attribute values](#dialect-attribute-values).
Alex Zinenko1321f6a2018-10-24 16:47:36761
Sean Silva6b07a972021-02-05 00:17:45762The top-level attribute dictionary attached to an operation has special
763semantics. The attribute entries are considered to be of two different kinds
764based on whether their dictionary key has a dialect prefix:
River Riddlea495f962019-03-03 06:34:18765
Mogballa54f4ea2021-10-12 23:14:57766- *inherent attributes* are inherent to the definition of an operation's
767 semantics. The operation itself is expected to verify the consistency of
768 these attributes. An example is the `predicate` attribute of the
769 `arith.cmpi` op. These attributes must have names that do not start with a
770 dialect prefix.
Alex Zinenko1321f6a2018-10-24 16:47:36771
Mogballa54f4ea2021-10-12 23:14:57772- *discardable attributes* have semantics defined externally to the operation
773 itself, but must be compatible with the operations's semantics. These
774 attributes must have names that start with a dialect prefix. The dialect
775 indicated by the dialect prefix is expected to verify these attributes. An
776 example is the `gpu.container_module` attribute.
Sean Silva6b07a972021-02-05 00:17:45777
778Note that attribute values are allowed to themselves be dictionary attributes,
779but only the top-level dictionary attribute attached to the operation is subject
780to the classification above.
River Riddlefc86c572019-08-23 00:51:06781
782### Attribute Value Aliases
783
Alex Zinenkoac487332019-12-10 11:00:29784```
Sean Silva042db542021-02-04 21:27:25785attribute-alias-def ::= '#' alias-name '=' attribute-value
River Riddlefc86c572019-08-23 00:51:06786attribute-alias ::= '#' alias-name
787```
788
789MLIR supports defining named aliases for attribute values. An attribute alias is
790an identifier that can be used in the place of the attribute that it defines.
791These aliases *must* be defined before their uses. Alias names may not contain a
792'.', since those names are reserved for
793[dialect attributes](#dialect-attribute-values).
794
795Example:
796
Alex Zinenkoac487332019-12-10 11:00:29797```mlir
River Riddle4268e4f2020-01-13 21:12:37798#map = affine_map<(d0) -> (d0 + 10)>
River Riddlefc86c572019-08-23 00:51:06799
800// Using the original attribute.
River Riddle4268e4f2020-01-13 21:12:37801%b = affine.apply affine_map<(d0) -> (d0 + 10)> (%a)
River Riddlefc86c572019-08-23 00:51:06802
803// Using the attribute alias.
804%b = affine.apply #map(%a)
805```
806
807### Dialect Attribute Values
808
Andrew Andersona50f8712019-11-26 01:53:20809Similarly to operations, dialects may define custom attribute values. The
810syntactic structure of these values is identical to custom dialect type values,
Uday Bondhugulab276bf52020-12-02 20:42:01811except that dialect attribute values are distinguished with a leading '#', while
812dialect types are distinguished with a leading '!'.
River Riddlefc86c572019-08-23 00:51:06813
Alex Zinenkoac487332019-12-10 11:00:29814```
Uday Bondhugulab276bf52020-12-02 20:42:01815dialect-attribute-value ::= '#' opaque-dialect-item
816dialect-attribute-value ::= '#' pretty-dialect-item
River Riddlefc86c572019-08-23 00:51:06817```
818
Uday Bondhugulab276bf52020-12-02 20:42:01819Dialect attribute values can be specified in a verbose form, e.g. like this:
River Riddlefc86c572019-08-23 00:51:06820
Alex Zinenkoac487332019-12-10 11:00:29821```mlir
Uday Bondhugulab276bf52020-12-02 20:42:01822// Complex attribute value.
River Riddlefc86c572019-08-23 00:51:06823#foo<"something<abcd>">
824
Uday Bondhugulab276bf52020-12-02 20:42:01825// Even more complex attribute value.
River Riddlefc86c572019-08-23 00:51:06826#foo<"something<a%%123^^^>>>">
827```
828
Uday Bondhugulab276bf52020-12-02 20:42:01829Dialect attribute values that are simple enough can use the pretty format, which
830is a lighter weight syntax that is equivalent to the above forms:
River Riddlefc86c572019-08-23 00:51:06831
Alex Zinenkoac487332019-12-10 11:00:29832```mlir
River Riddlefc86c572019-08-23 00:51:06833// Complex attribute
834#foo.something<abcd>
835```
836
Uday Bondhugulab276bf52020-12-02 20:42:01837Sufficiently complex dialect attribute values are required to use the verbose
838form for generality. For example, the more complex type shown above would not be
839valid in the lighter syntax: `#foo.something<a%%123^^^>>>` because it contains
840characters that are not allowed in the lighter syntax, as well as unbalanced
841`<>` characters.
River Riddlefc86c572019-08-23 00:51:06842
Uday Bondhugulab276bf52020-12-02 20:42:01843See [here](Tutorials/DefiningAttributesAndTypes.md) on how to define dialect
River Riddlefc86c572019-08-23 00:51:06844attribute values.
845
River Riddlec7cae0e2020-12-04 01:22:57846### Builtin Attribute Values
River Riddlefc86c572019-08-23 00:51:06847
River Riddlecaddfbd2021-03-20 01:19:16848The [builtin dialect](Dialects/Builtin.md) defines a set of attribute values
849that are directly usable by any other dialect in MLIR. These types cover a range
850from primitive integer and floating-point values, attribute dictionaries, dense
851multi-dimensional arrays, and more.