3 MLIR (Multi-Level IR) is a compiler intermediate representation with
4 similarities to traditional three-address SSA representations (like
5 [LLVM IR](http://llvm.org/docs/LangRef.html) or
6 [SIL](https://github.com/apple/swift/blob/master/docs/SIL.rst)), but which
7 introduces notions from polyhedral loop optimization as first-class concepts.
8 This hybrid design is optimized to represent, analyze, and transform high level
9 dataflow graphs as well as target-specific code generated for high performance
10 data parallel systems. Beyond its representational capabilities, its single
11 continuous design provides a framework to lower from dataflow graphs to
12 high-performance target-specific code.
14 This document defines and describes the key concepts in MLIR, and is intended to
15 be a dry reference document - the [rationale documentation](Rationale.md),
16 [glossary](../getting_started/Glossary.md), and other content are hosted elsewhere.
18 MLIR is designed to be used in three different forms: a human-readable textual
19 form suitable for debugging, an in-memory form suitable for programmatic
20 transformations and analysis, and a compact serialized form suitable for storage
21 and transport. The different forms all describe the same semantic content. This
22 document describes the human-readable textual form.
26 ## High-Level Structure
29 [SSA-based](https://en.wikipedia.org/wiki/Static_single_assignment_form) IR,
30 which means that values are defined before use and have scope defined by their
31 dominance relations. Operations may produce zero or more results, and each is a
32 distinct SSA value with its own type defined by the [type system](#type-system).
34 The unit of code in MLIR is an [Operation](#operations). Operations allow for
35 representing many different concepts: allocating buffers, producing views to
36 transform them, target-independent arithmetic, target-specific operations, and
37 even arbitrary user-defined high-level operations including the
38 [Module](#module) and [Function](#functions) operations. Operations may contain
39 [Regions](#regions) that represent a Control Flow Graph (CFG) of
40 [Blocks](#blocks), that contain operations and end with a
41 [terminator operation](#terminator-operations) (like branches).
43 Here's an example of an MLIR module:
46 // Compute A*B using an implementation of multiply kernel and print the
47 // result using a TensorFlow op. The dimensions of A and B are partially
48 // known. The shapes are assumed to match.
49 func @mul(%A: tensor<100x?xf32>, %B: tensor<?x50xf32>) -> (tensor<100x50xf32>) {
50 // Compute the inner dimension of %A using the dim operation.
51 %n = dim %A, 1 : tensor<100x?xf32>
53 // Allocate addressable "buffers" and copy tensors %A and %B into them.
54 %A_m = alloc(%n) : memref<100x?xf32>
55 tensor_store %A to %A_m : memref<100x?xf32>
57 %B_m = alloc(%n) : memref<?x50xf32>
58 tensor_store %B to %B_m : memref<?x50xf32>
60 // Call function @multiply passing memrefs as arguments,
61 // and getting returned the result of the multiplication.
62 %C_m = call @multiply(%A_m, %B_m)
63 : (memref<100x?xf32>, memref<?x50xf32>) -> (memref<100x50xf32>)
65 dealloc %A_m : memref<100x?xf32>
66 dealloc %B_m : memref<?x50xf32>
68 // Load the buffer data into a higher level "tensor" value.
69 %C = tensor_load %C_m : memref<100x50xf32>
70 dealloc %C_m : memref<100x50xf32>
72 // Call TensorFlow built-in function to print the result tensor.
73 "tf.Print"(%C){message: "mul result"}
74 : (tensor<100x50xf32) -> (tensor<100x50xf32>)
76 return %C : tensor<100x50xf32>
79 // A function that multiplies two memrefs and returns the result.
80 func @multiply(%A: memref<100x?xf32>, %B: memref<?x50xf32>)
81 -> (memref<100x50xf32>) {
82 // Compute the inner dimension of %A.
83 %n = dim %A, 1 : memref<100x?xf32>
85 // Allocate memory for the multiplication result.
86 %C = alloc() : memref<100x50xf32>
88 // Multiplication loop nest.
89 affine.for %i = 0 to 100 {
90 affine.for %j = 0 to 50 {
91 store 0 to %C[%i, %j] : memref<100x50xf32>
92 affine.for %k = 0 to %n {
93 %a_v = load %A[%i, %k] : memref<100x?xf32>
94 %b_v = load %B[%k, %j] : memref<?x50xf32>
95 %prod = mulf %a_v, %b_v : f32
96 %c_v = load %C[%i, %j] : memref<100x50xf32>
97 %sum = addf %c_v, %prod : f32
98 store %sum, %C[%i, %j] : memref<100x50xf32>
102 return %C : memref<100x50xf32>
108 MLIR has a simple and unambiguous grammar, allowing it to reliably round-trip
109 through a textual form. This is important for development of the compiler - e.g.
110 for understanding the state of code as it is being transformed and writing test
113 This document describes the grammar using
114 [Extended Backus-Naur Form (EBNF)](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form).
116 This is the EBNF grammar used in this document, presented in yellow boxes.
119 alternation ::= expr0 | expr1 | expr2 // Either expr0 or expr1 or expr2.
120 sequence ::= expr0 expr1 expr2 // Sequence of expr0 expr1 expr2.
121 repetition0 ::= expr* // 0 or more occurrences.
122 repetition1 ::= expr+ // 1 or more occurrences.
123 optionality ::= expr? // 0 or 1 occurrence.
124 grouping ::= (expr) // Everything inside parens is grouped together.
125 literal ::= `abcd` // Matches the literal `abcd`.
128 Code examples are presented in blue boxes.
131 // This is an example use of the grammar above:
132 // This matches things like: ba, bana, boma, banana, banoma, bomana...
133 example ::= `b` (`an` | `om`)* `a`
138 The following core grammar productions are used in this document:
141 // TODO: Clarify the split between lexing (tokens) and parsing (grammar).
143 hex_digit ::= [0-9a-fA-F]
147 integer-literal ::= decimal-literal | hexadecimal-literal
148 decimal-literal ::= digit+
149 hexadecimal-literal ::= `0x` hex_digit+
150 float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
151 string-literal ::= `"` [^"\n\f\v\r]* `"` TODO define escaping rules
154 Not listed here, but MLIR does support comments. They use standard BCPL syntax,
155 starting with a `//` and going until the end of the line.
157 ### Identifiers and keywords
163 bare-id ::= (letter|[_]) (letter|digit|[_$.])*
164 bare-id-list ::= bare-id (`,` bare-id)*
165 ssa-id ::= `%` suffix-id
166 suffix-id ::= (digit+ | ((letter|id-punct) (letter|id-punct|digit)*))
168 symbol-ref-id ::= `@` (suffix-id | string-literal)
169 ssa-id-list ::= ssa-id (`,` ssa-id)*
171 // Uses of an SSA value, e.g. in an operand list to an operation.
173 ssa-use-list ::= ssa-use (`,` ssa-use)*
176 Identifiers name entities such as SSA values, types and functions, and are
177 chosen by the writer of MLIR code. Identifiers may be descriptive (e.g.
178 `%batch_size`, `@matmul`), or may be non-descriptive when they are
179 auto-generated (e.g. `%23`, `@func42`). Identifier names for SSA values may be
180 used in an MLIR text file but are not persisted as part of the IR - the printer
181 will give them anonymous names like `%42`.
183 MLIR guarantees identifiers never collide with keywords by prefixing identifiers
184 with a sigil (e.g. `%`, `#`, `@`, `^`, `!`). In certain unambiguous contexts
185 (e.g. affine expressions), identifiers are not prefixed, for brevity. New
186 keywords may be added to future versions of MLIR without danger of collision
187 with existing identifiers.
189 The scope of SSA values is defined based on the standard definition of
190 [dominance](https://en.wikipedia.org/wiki/Dominator_\(graph_theory\)). Argument
191 identifiers in mapping functions are in scope for the mapping body. Function
192 identifiers and mapping identifiers are visible across the entire module.
196 Dialects are the mechanism by which to engage with and extend the MLIR
197 ecosystem. They allow for defining new [operations](#operations), as well as
198 [attributes](#attributes) and [types](#type-system). Each dialect is given a
199 unique `namespace` that is prefixed to each defined attribute/operation/type.
200 For example, the [Affine dialect](Dialects/Affine.md) defines the namespace:
203 MLIR allows for multiple dialects, even those outside of the main tree, to
204 co-exist together within one module. Dialects are produced and consumed by
205 certain passes. MLIR provides a [framework](DialectConversion.md) to convert
206 between, and within, different dialects.
208 A few of the dialects supported by MLIR:
210 * [Affine dialect](Dialects/Affine.md)
211 * [GPU dialect](Dialects/GPU.md)
212 * [LLVM dialect](Dialects/LLVM.md)
213 * [SPIR-V dialect](Dialects/SPIR-V.md)
214 * [Standard dialect](Dialects/Standard.md)
215 * [Vector dialect](Dialects/Vector.md)
217 ### Target specific operations
219 Dialects provide a modular way in which targets can expose target-specific
220 operations directly through to MLIR. As an example, some targets go through
221 LLVM. LLVM has a rich set of intrinsics for certain target-independent
222 operations (e.g. addition with overflow check) as well as providing access to
223 target-specific operations for the targets it supports (e.g. vector permutation
224 operations). LLVM intrinsics in MLIR are represented via operations that start
225 with an "llvm." name.
230 // LLVM: %x = call {i16, i1} @llvm.sadd.with.overflow.i16(i16 %a, i16 %b)
231 %x:2 = "llvm.sadd.with.overflow.i16"(%a, %b) : (i16, i16) -> (i16, i1)
234 These operations only work when targeting LLVM as a backend (e.g. for CPUs and
235 GPUs), and are required to align with the LLVM definition of these intrinsics.
242 operation ::= op-result-list? (generic-operation | custom-operation)
244 generic-operation ::= string-literal '(' ssa-use-list? ')' attribute-dict?
246 custom-operation ::= bare-id custom-operation-format
247 op-result-list ::= op-result (`,` op-result)* `=`
248 op-result ::= ssa-id (`:` integer-literal)
249 successor-list ::= successor (`,` successor)*
250 successor ::= caret-id (`:` bb-arg-list)?
251 region-list ::= region (`,` region)*
252 trailing-location ::= (`loc` `(` location `)`)?
255 MLIR introduces a uniform concept called _operations_ to enable describing many
256 different levels of abstractions and computations. Operations in MLIR are fully
257 extensible (there is no fixed list of operations) and have application-specific
258 semantics. For example, MLIR supports
259 [target-independent operations](Dialects/Standard.md#memory-operations),
260 [affine operations](Dialects/Affine.md), and
261 [target-specific machine operations](#target-specific-operations).
263 The internal representation of an operation is simple: an operation is
264 identified by a unique string (e.g. `dim`, `tf.Conv2d`, `x86.repmovsb`,
265 `ppc.eieio`, etc), can return zero or more results, take zero or more SSA
266 operands, may have zero or more attributes, may have zero or more successors,
267 and zero or more enclosed [regions](#regions). The generic printing form
268 includes all these elements literally, with a function type to indicate the
269 types of the results and operands.
274 // An operation that produces two results.
275 // The results of %result can be accessed via the <name> `#` <opNo> syntax.
276 %result:2 = "foo_div"() : () -> (f32, i32)
278 // Pretty form that defines a unique name for each result.
279 %foo, %bar = "foo_div"() : () -> (f32, i32)
281 // Invoke a TensorFlow function called tf.scramble with two inputs
282 // and an attribute "fruit".
283 %2 = "tf.scramble"(%result#0, %bar) {fruit: "banana"} : (f32, i32) -> f32
286 In addition to the basic syntax above, dialects may register known operations.
287 This allows those dialects to support _custom assembly form_ for parsing and
288 printing operations. In the operation sets listed below, we show both forms.
290 ### Terminator Operations
292 These are a special category of operations that *must* terminate a block, e.g.
293 [branches](Dialects/Standard.md#terminator-operations). These operations may
294 also have a list of successors ([blocks](#blocks) and their arguments).
299 // Branch to ^bb1 or ^bb2 depending on the condition %cond.
300 // Pass value %v to ^bb2, but not to ^bb1.
301 "cond_br"(%cond)[^bb1, ^bb2(%v : index)] : (i1) -> ()
307 module ::= `module` symbol-ref-id? (`attributes` attribute-dict)? region
310 An MLIR module represents an opaque top-level container operation. It contains a
311 single region containing a single block that is comprised of any operations.
312 Operations within this region must not implicitly capture values defined above
313 it. Modules have an optional symbol name that can be used to refer to them in
318 An MLIR Function is an operation with a name containing one [region](#regions).
319 The region of a function is not allowed to implicitly capture values defined
320 outside of the function, and all external references must use function arguments
321 or attributes that establish a symbolic connection (e.g. symbols referenced by
322 name via a string attribute like [SymbolRefAttr](#symbol-reference-attribute)):
325 function ::= `func` function-signature function-attributes? function-body?
327 function-signature ::= symbol-ref-id `(` argument-list `)`
328 (`->` function-result-list)?
330 argument-list ::= (named-argument (`,` named-argument)*) | /*empty*/
331 argument-list ::= (type attribute-dict? (`,` type attribute-dict?)*) | /*empty*/
332 named-argument ::= ssa-id `:` type attribute-dict?
334 function-result-list ::= function-result-list-parens
336 function-result-list-parens ::= `(` `)`
337 | `(` function-result-list-no-parens `)`
338 function-result-list-no-parens ::= function-result (`,` function-result)*
339 function-result ::= type attribute-dict?
341 function-attributes ::= `attributes` attribute-dict
342 function-body ::= region
345 An external function declaration (used when referring to a function declared in
346 some other module) has no body. While the MLIR textual form provides a nice
347 inline syntax for function arguments, they are internally represented as "block
348 arguments" to the first block in the region.
350 Only dialect attribute names may be specified in the attribute dictionaries for
351 function arguments, results, or the function itself.
356 // External function definitions.
358 func @scribble(i32, i64, memref<? x 128 x f32, #layout_map0>) -> f64
360 // A function that returns its argument twice:
361 func @count(%x: i64) -> (i64, i64)
362 attributes {fruit: "banana"} {
363 return %x, %x: i64, i64
366 // A function with an argument attribute
367 func @example_fn_arg(%x: i32 {swift.self = unit})
369 // A function with a result attribute
370 func @example_fn_result() -> (f64 {dialectName.attrName = 0 : i64})
372 // A function with an attribute
373 func @example_fn_attr() attributes {dialectName.attrName = false}
381 block ::= block-label operation+
382 block-label ::= block-id block-arg-list? `:`
383 block-id ::= caret-id
384 caret-id ::= `^` suffix-id
385 ssa-id-and-type ::= ssa-id `:` type
387 // Non-empty list of names and types.
388 ssa-id-and-type-list ::= ssa-id-and-type (`,` ssa-id-and-type)*
390 block-arg-list ::= `(` ssa-id-and-type-list? `)`
393 A [block](https://en.wikipedia.org/wiki/Basic_block) is a sequential list of
394 operations without control flow (a call or entering an op's region is not
395 considered control flow for this purpose) that are executed from top to bottom.
396 The last operation in a block is a
397 [terminator operation](#terminator-operations), which ends the block.
399 Blocks in MLIR take a list of block arguments, which represent SSA PHI nodes in
400 a functional notation. The arguments are defined by the block, and values are
401 provided for these block arguments by branches that go to the block.
403 Here is a simple example function showing branches, returns, and block
407 func @simple(i64, i1) -> i64 {
408 ^bb0(%a: i64, %cond: i1): // Code dominated by ^bb0 may refer to %a
409 cond_br %cond, ^bb1, ^bb2
412 br ^bb3(%a: i64) // Branch passes %a as the argument
415 %b = addi %a, %a : i64
416 br ^bb3(%b: i64) // Branch passes %b as the argument
418 // ^bb3 receives an argument, named %c, from predecessors
419 // and passes it on to bb4 twice.
421 br ^bb4(%c, %c : i64, i64)
423 ^bb4(%d : i64, %e : i64):
424 %0 = addi %d, %e : i64
429 **Context:** The "block argument" representation eliminates a number of special
430 cases from the IR compared to traditional "PHI nodes are operations" SSA IRs
431 (like LLVM). For example, the
432 [parallel copy semantics](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.524.5461&rep=rep1&type=pdf)
433 of SSA is immediately apparent, and function arguments are no longer a special
434 case: they become arguments to the entry block
435 [[more rationale](Rationale.md#block-arguments-vs-phi-nodes)].
441 A region is a CFG of MLIR [Blocks](#blocks). Regions serve to group semantically
442 connected blocks, where the semantics is not imposed by the IR. Instead, the
443 containing operation defines the semantics of the regions it contains. Regions
444 do not have a name or an address, only the blocks contained in a region do.
445 Regions are meaningless outside of the containing entity and have no type or
448 The first block in the region cannot be a successor of any other block. The
449 syntax for the region is as follows:
452 region ::= `{` block* `}`
455 The function body is an example of a region: it consists of a CFG of blocks and
456 has additional semantic restrictions that other types of regions may not have
457 (block terminators must either branch to a different block, or return from a
458 function where the types of the `return` arguments must match the result types
459 of the function signature).
461 ### Control and Value Scoping
463 Regions provide nested control isolation: it is impossible to branch to a block
464 within a region from outside it or to branch from within a region to a block
465 outside it. Similarly, it provides a natural scoping for value visibility: SSA
466 values defined in a region don't escape to the enclosing region, if any. By
467 default, a region can reference values defined outside of the region whenever it
468 would have been legal to use them as operands to the enclosing operation.
473 func @accelerator_compute(i64, i1) -> i64 {
474 ^bb0(%a: i64, %cond: i1): // Code dominated by ^bb0 may refer to %a
475 cond_br %cond, ^bb1, ^bb2
478 // This def for %value does not dominate ^bb2
479 %value = "op.convert"(%a) : (i64) -> i64
480 br ^bb3(%a: i64) // Branch passes %a as the argument
483 "accelerator.launch"() {
485 // Region of code nested under "accelerator.launch", it can reference %a but
487 %new_value = "accelerator.do_something"(%a) : (i64) -> ()
489 // %new_value cannot be referenced outside of the region
496 This can be further restricted using the custom verifier associated with the
497 enclosing operation, for example, disallowing references to values defined
498 outside the region completely.
502 Regions are Single-Entry-Multiple-Exit (SEME). This means that control can only
503 flow into the first block of the region, but can flow out of the region at the
504 end of any of the contained blocks (This behavior is similar to that of a
505 function body in most programming languages). A terminator of a block within a
506 region may transfer the control flow to another block in this region, or return
507 it to the immediately enclosing op. The semantics of the enclosing op defines
508 where the control flow is transmitted next. It may, for example, enter a region
509 of the same op, including the same region that returned the control flow.
511 The enclosing operation determines the way in which control is transmitted into
512 the entry block of a Region. The successor to a region’s exit points may not
513 necessarily exist: for example a call to a function that does not return.
514 Concurrent or asynchronous execution of regions is unspecified. Operations may
515 define specific rules of execution, e.g. sequential loops or switch cases.
517 A Region may also enter another region within the enclosing operation. If an
518 operation has multiple regions, the semantics of the operation defines into
519 which regions the control flows and in which order, if any. An operation may
520 transmit control into regions that were specified in other operations, in
521 particular those that defined the values the given operation uses. Thus such
522 operations can be treated opaquely in the enclosing control flow graph,
523 providing a level of control flow isolation similar to that of the call
528 Regions allow defining an operation that creates a closure, for example by
529 “boxing” the body of the region into a value they produce. It remains up to the
530 operation to define its semantics. Note that if an operation triggers
531 asynchronous execution of the region, it is under the responsibility of the
532 operation caller to wait for the region to be executed guaranteeing that any
533 directly used values remain live.
535 ### Arguments and Results
537 The arguments of the first block of a region are treated as arguments of the
538 region. The source of these arguments is defined by the semantics of the parent
539 operation. They may correspond to some of the values the operation itself uses.
541 Regions produce a (possibly empty) list of values. The operation semantics
542 defines the relation between the region results and the operation results.
546 Each SSA value in MLIR has a type defined by the type system below. There are a
547 number of primitive types (like integers) and also aggregate types for tensors
548 and memory buffers. MLIR [standard types](#standard-types) do not include
549 structures, arrays, or dictionaries.
551 MLIR has an open type system (i.e. there is no fixed list of types), and types
552 may have application-specific semantics. For example, MLIR supports a set of
553 [dialect types](#dialect-types).
556 type ::= type-alias | dialect-type | standard-type
558 type-list-no-parens ::= type (`,` type)*
559 type-list-parens ::= `(` `)`
560 | `(` type-list-no-parens `)`
562 // This is a common way to refer to an SSA value with a specified type.
563 ssa-use-and-type ::= ssa-use `:` type
565 // Non-empty list of names and types.
566 ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
572 type-alias-def ::= '!' alias-name '=' 'type' type
573 type-alias ::= '!' alias-name
576 MLIR supports defining named aliases for types. A type alias is an identifier
577 that can be used in the place of the type that it defines. These aliases *must*
578 be defined before their uses. Alias names may not contain a '.', since those
579 names are reserved for [dialect types](#dialect-types).
584 !avx_m128 = type vector<4 x f32>
586 // Using the original type.
587 "foo"(%x) : vector<4 x f32> -> ()
589 // Using the type alias.
590 "foo"(%x) : !avx_m128 -> ()
595 Similarly to operations, dialects may define custom extensions to the type
599 dialect-namespace ::= bare-id
601 opaque-dialect-item ::= dialect-namespace '<' string-literal '>'
603 pretty-dialect-item ::= dialect-namespace '.' pretty-dialect-item-lead-ident
604 pretty-dialect-item-body?
606 pretty-dialect-item-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
607 pretty-dialect-item-body ::= '<' pretty-dialect-item-contents+ '>'
608 pretty-dialect-item-contents ::= pretty-dialect-item-body
609 | '(' pretty-dialect-item-contents+ ')'
610 | '[' pretty-dialect-item-contents+ ']'
611 | '{' pretty-dialect-item-contents+ '}'
614 dialect-type ::= '!' opaque-dialect-item
615 dialect-type ::= '!' pretty-dialect-item
618 Dialect types can be specified in a verbose form, e.g. like this:
621 // LLVM type that wraps around llvm IR types.
624 // Tensor flow string type.
628 !foo<"something<abcd>">
630 // Even more complex type
631 !foo<"something<a%%123^^^>>>">
634 Dialect types that are simple enough can use the pretty format, which is a
635 lighter weight syntax that is equivalent to the above forms:
638 // Tensor flow string type.
645 Sufficiently complex dialect types are required to use the verbose form for
646 generality. For example, the more complex type shown above wouldn't be valid in
647 the lighter syntax: `!foo.something<a%%123^^^>>>` because it contains characters
648 that are not allowed in the lighter syntax, as well as unbalanced `<>`
651 See [here](DefiningAttributesAndTypes.md) to learn how to define dialect types.
655 Standard types are a core set of [dialect types](#dialect-types) that are
656 defined in a builtin dialect and thus available to all users of MLIR.
659 standard-type ::= complex-type
676 complex-type ::= `complex` `<` type `>`
679 The value of `complex` type represents a complex number with a parameterized
680 element type, which is composed of a real and imaginary value of that element
681 type. The element must be a floating point or integer scalar type.
690 #### Floating Point Types
696 float-type ::= `f16` | `bf16` | `f32` | `f64`
699 MLIR supports float types of certain widths that are widely used as indicated
707 // MLIR functions can return multiple values.
708 function-result-type ::= type-list-parens
711 function-type ::= type-list-parens `->` function-result-type
714 MLIR supports first-class functions: for example, the
715 [`constant` operation](Dialects/Standard.md#constant-operation) produces the
716 address of a function as an SSA value. This SSA value may be passed to and
717 returned from functions, merged across control flow boundaries with
718 [block arguments](#blocks), and called with the
719 [`call_indirect` operation](Dialects/Standard.md#call-indirect-operation).
721 Function types are also used to indicate the arguments and results of
722 [operations](#operations).
729 // Target word-sized integer.
730 index-type ::= `index`
733 The `index` type is a signless integer whose size is equal to the natural
734 machine word of the target ([rationale](Rationale.md#signless-types)) and is
735 used by the affine constructs in MLIR. Unlike fixed-size integers, it cannot be
736 used as an element of vector, tensor or memref type
737 ([rationale](Rationale.md#index-type-disallowed-in-vectortensormemref-types)).
739 **Rationale:** integers of platform-specific bit widths are practical to express
740 sizes, dimensionalities and subscripts.
747 // Sized integers like i1, i4, i8, i16, i32.
748 integer-type ::= `i` [1-9][0-9]*
751 MLIR supports arbitrary precision integer types. Integer types are signless, but
752 have a designated width.
754 **Rationale:** low precision integers (like `i2`, `i4` etc) are useful for
755 low-precision inference chips, and arbitrary precision integers are useful for
756 hardware synthesis (where a 13 bit multiplier is a lot cheaper/smaller than a 16
759 TODO: Need to decide on a representation for quantized integers
760 ([initial thoughts](Rationale.md#quantized-integer-operations)).
767 memref-type ::= ranked-memref-type | unranked-memref-type
769 ranked-memref-type ::= `memref` `<` dimension-list-ranked tensor-memref-element-type
770 (`,` layout-specification)? |
771 (`,` memory-space)? `>`
773 unranked-memref-type ::= `memref` `<*x` tensor-memref-element-type
774 (`,` memory-space)? `>`
776 stride-list ::= `[` (dimension (`,` dimension)*)? `]`
777 strided-layout ::= `offset:` dimension `,` `strides: ` stride-list
778 layout-specification ::= semi-affine-map | strided-layout
779 memory-space ::= integer-literal /* | TODO: address-space-id */
782 A `memref` type is a reference to a region of memory (similar to a buffer
783 pointer, but more powerful). The buffer pointed to by a memref can be allocated,
784 aliased and deallocated. A memref can be used to read and write data from/to the
785 memory region which it references. Memref types use the same shape specifier as
786 tensor types. Note that `memref<f32>`, `memref<0 x f32>`, `memref<1 x 0 x f32>`,
787 and `memref<0 x 1 x f32>` are all different types.
789 A `memref` is allowed to have an unknown rank (e.g. `memref<*xf32>`). The
790 purpose of unranked memrefs is to allow external library functions to receive
791 memref arguments of any rank without versioning the functions based on the rank.
792 Other uses of this type are disallowed or will have undefined behavior.
794 ##### Codegen of Unranked Memref
796 Using unranked memref in codegen besides the case mentioned above is highly
797 discouraged. Codegen is concerned with generating loop nests and specialized
798 instructions for high-performance, unranked memref is concerned with hiding the
799 rank and thus, the number of enclosing loops required to iterate over the data.
800 However, if there is a need to code-gen unranked memref, one possible path is to
801 cast into a static ranked type based on the dynamic rank. Another possible path
802 is to emit a single while loop conditioned on a linear index and perform
803 delinearization of the linear index to a dynamic array containing the (unranked)
804 indices. While this is possible, it is expected to not be a good idea to perform
805 this during codegen as the cost of the translations is expected to be
806 prohibitive and optimizations at this level are not expected to be worthwhile.
807 If expressiveness is the main concern, irrespective of performance, passing
808 unranked memrefs to an external C++ library and implementing rank-agnostic logic
809 there is expected to be significantly simpler.
811 Unranked memrefs may provide expressiveness gains in the future and help bridge
812 the gap with unranked tensors. Unranked memrefs will not be expected to be
813 exposed to codegen but one may query the rank of an unranked memref (a special
814 op will be needed for this purpose) and perform a switch and cast to a ranked
815 memref as a prerequisite to codegen.
820 // With static ranks, we need a function for each possible argument type
821 %A = alloc() : memref<16x32xf32> %B = alloc() :
822 memref<16x32x64xf32> call @helper_2D(%A) : (memref<16x32xf32>)->() call
823 @helper_3D(%B) : (memref<16x32x64xf32>)->()
825 // With unknown rank, the functions can be unified under one unranked type
826 %A = alloc() : memref<16x32xf32>
827 %B = alloc() : memref<16x32x64xf32>
829 %A_u = memref_cast %A : memref<16x32xf32> -> memref<*xf32>
830 %B_u = memref_cast %B : memref<16x32x64xf32> -> memref<*xf32>
831 // call same function with dynamic ranks
832 call @helper(%A_u) : (memref<*xf32>)->()
833 call @helper(%B_u) : (memref<*xf32>)->()
836 The core syntax and representation of a layout specification is a
837 [semi-affine map](Dialects/Affine.md#semi-affine-maps). Additionally, syntactic
838 sugar is supported to make certain layout specifications more intuitive to read.
839 For the moment, a `memref` supports parsing a strided form which is converted to
840 a semi-affine map automatically.
842 The memory space of a memref is specified by a target-specific integer index. If
843 no memory space is specified, then the default memory space (0) is used. The
844 default space is target specific but always at index 0.
846 TODO: MLIR will eventually have target-dialects which allow symbolic use of
847 memory hierarchy names (e.g. L3, L2, L1, ...) but we have not spec'd the details
848 of that mechanism yet. Until then, this document pretends that it is valid to
849 refer to these memories by `bare-id`.
851 The notionally dynamic value of a memref value includes the address of the
852 buffer allocated, as well as the symbols referred to by the shape, layout map,
855 Examples of memref static type
858 // Identity index/layout map
859 #identity = affine_map<(d0, d1) -> (d0, d1)>
861 // Column major layout.
862 #col_major = affine_map<(d0, d1, d2) -> (d2, d1, d0)>
864 // A 2-d tiled layout with tiles of size 128 x 256.
865 #tiled_2d_128x256 = affine_map<(d0, d1) -> (d0 div 128, d1 div 256, d0 mod 128, d1 mod 256)>
867 // A tiled data layout with non-constant tile sizes.
868 #tiled_dynamic = affine_map<(d0, d1)[s0, s1] -> (d0 floordiv s0, d1 floordiv s1,
869 d0 mod s0, d1 mod s1)>
871 // A layout that yields a padding on two at either end of the minor dimension.
872 #padded = affine_map<(d0, d1) -> (d0, (d1 + 2) floordiv 2, (d1 + 2) mod 2)>
875 // The dimension list "16x32" defines the following 2D index space:
877 // { (i, j) : 0 <= i < 16, 0 <= j < 32 }
879 memref<16x32xf32, #identity, memspace0>
881 // The dimension list "16x4x?" defines the following 3D index space:
883 // { (i, j, k) : 0 <= i < 16, 0 <= j < 4, 0 <= k < N }
885 // where N is a symbol which represents the runtime value of the size of
886 // the third dimension.
888 // %N here binds to the size of the third dimension.
889 %A = alloc(%N) : memref<16x4x?xf32, #col_major, memspace0>
891 // A 2-d dynamic shaped memref that also has a dynamically sized tiled layout.
892 // The memref index space is of size %M x %N, while %B1 and %B2 bind to the
893 // symbols s0, s1 respectively of the layout map #tiled_dynamic. Data tiles of
894 // size %B1 x %B2 in the logical space will be stored contiguously in memory.
895 // The allocation size will be (%M ceildiv %B1) * %B1 * (%N ceildiv %B2) * %B2
897 %T = alloc(%M, %N) [%B1, %B2] : memref<?x?xf32, #tiled_dynamic>
899 // A memref that has a two-element padding at either end. The allocation size
900 // will fit 16 * 68 float elements of data.
901 %P = alloc() : memref<16x64xf32, #padded>
903 // Affine map with symbol 's0' used as offset for the first dimension.
904 #imapS = affine_map<(d0, d1) [s0] -> (d0 + s0, d1)>
905 // Allocate memref and bind the following symbols:
906 // '%n' is bound to the dynamic second dimension of the memref type.
907 // '%o' is bound to the symbol 's0' in the affine map of the memref type.
910 %A = alloc (%n)[%o] : <16x?xf32, #imapS>
915 A memref dimension list defines an index space within which the memref can be
916 indexed to access data.
920 Data is accessed through a memref type using a multidimensional index into the
921 multidimensional index space defined by the memref's dimension list.
926 // Allocates a memref with 2D index space:
927 // { (i, j) : 0 <= i < 16, 0 <= j < 32 }
928 %A = alloc() : memref<16x32xf32, #imapA, memspace0>
930 // Loads data from memref '%A' using a 2D index: (%i, %j)
931 %v = load %A[%i, %j] : memref<16x32xf32, #imapA, memspace0>
936 An index map is a one-to-one
937 [semi-affine map](Dialects/Affine.md#semi-affine-maps) that transforms a
938 multidimensional index from one index space to another. For example, the
939 following figure shows an index map which maps a 2-dimensional index from a 2x2
940 index space to a 3x3 index space, using symbols `S0` and `S1` as offsets.
942 ![Index Map Example](includes/img/index-map.svg)
944 The number of domain dimensions and range dimensions of an index map can be
945 different, but must match the number of dimensions of the input and output index
946 spaces on which the map operates. The index space is always non-negative and
947 integral. In addition, an index map must specify the size of each of its range
948 dimensions onto which it maps. Index map symbols must be listed in order with
949 symbols for dynamic dimension sizes first, followed by other required symbols.
953 A layout map is a [semi-affine map](Dialects/Affine.md#semi-affine-maps) which
954 encodes logical to physical index space mapping, by mapping input dimensions to
955 their ordering from most-major (slowest varying) to most-minor (fastest
956 varying). Therefore, an identity layout map corresponds to a row-major layout.
957 Identity layout maps do not contribute to the MemRef type identification and are
958 discarded on construction. That is, a type with an explicit identity map is
959 `memref<?x?xf32, (i,j)->(i,j)>` is strictly the same as the one without layout
960 maps, `memref<?x?xf32>`.
965 // MxN matrix stored in row major layout in memory:
966 #layout_map_row_major = (i, j) -> (i, j)
968 // MxN matrix stored in column major layout in memory:
969 #layout_map_col_major = (i, j) -> (j, i)
971 // MxN matrix stored in a 2-d blocked/tiled layout with 64x64 tiles.
972 #layout_tiled = (i, j) -> (i floordiv 64, j floordiv 64, i mod 64, j mod 64)
975 ##### Affine Map Composition
977 A memref specifies a semi-affine map composition as part of its type. A
978 semi-affine map composition is a composition of semi-affine maps beginning with
979 zero or more index maps, and ending with a layout map. The composition must be
980 conformant: the number of dimensions of the range of one map, must match the
981 number of dimensions of the domain of the next map in the composition.
983 The semi-affine map composition specified in the memref type, maps from accesses
984 used to index the memref in load/store operations to other index spaces (i.e.
985 logical to physical index mapping). Each of the
986 [semi-affine maps](Dialects/Affine.md) and thus its composition is required to
989 The semi-affine map composition can be used in dependence analysis, memory
990 access pattern analysis, and for performance optimizations like vectorization,
991 copy elision and in-place updates. If an affine map composition is not specified
992 for the memref, the identity affine map is assumed.
996 A memref may specify strides as part of its type. A stride specification is a
997 list of integer values that are either static or `?` (dynamic case). Strides
998 encode the distance, in number of elements, in (linear) memory between
999 successive entries along a particular dimension. A stride specification is
1000 syntactic sugar for an equivalent strided memref representation using
1001 semi-affine maps. For example, `memref<42x16xf32, offset: 33 strides: [1, 64]>`
1002 specifies a non-contiguous memory region of `42` by `16` `f32` elements such
1005 1. the minimal size of the enclosing memory region must be `33 + 42 * 1 + 16 *
1006 64 = 1066` elements;
1007 2. the address calculation for accessing element `(i, j)` computes `33 + i +
1009 3. the distance between two consecutive elements along the outer dimension is
1010 `1` element and the distance between two consecutive elements along the
1011 outer dimension is `64` elements.
1013 This corresponds to a column major view of the memory region and is internally
1014 represented as the type `memref<42x16xf32, (i, j) -> (33 + i + 64 * j)>`.
1016 The specification of strides must not alias: given an n-D strided memref,
1017 indices `(i1, ..., in)` and `(j1, ..., jn)` may not refer to the same memory
1018 address unless `i1 == j1, ..., in == jn`.
1020 Strided memrefs represent a view abstraction over preallocated data. They are
1021 constructed with special ops, yet to be introduced. Strided memrefs are a
1022 special subclass of memrefs with generic semi-affine map and correspond to a
1023 normalized memref descriptor when lowering to LLVM.
1030 none-type ::= `none`
1033 The `none` type is a unit type, i.e. a type with exactly one possible value,
1034 where its value does not have a defined dynamic representation.
1041 tensor-type ::= `tensor` `<` dimension-list tensor-memref-element-type `>`
1042 tensor-memref-element-type ::= vector-element-type | vector-type | complex-type
1044 // memref requires a known rank, but tensor does not.
1045 dimension-list ::= dimension-list-ranked | (`*` `x`)
1046 dimension-list-ranked ::= (dimension `x`)*
1047 dimension ::= `?` | decimal-literal
1050 SSA values of tensor type represents aggregate N-dimensional data values, and
1051 have a known element type. It may have an unknown rank (indicated by `*`) or may
1052 have a fixed rank with a list of dimensions. Each dimension may be a static
1053 non-negative decimal constant or be dynamically determined (indicated by `?`).
1055 The runtime representation of the MLIR tensor type is intentionally abstracted -
1056 you cannot control layout or get a pointer to the data. For low level buffer
1057 access, MLIR has a [`memref` type](#memref-type). This abstracted runtime
1058 representation holds both the tensor data values as well as information about
1059 the (potentially dynamic) shape of the tensor. The
1060 [`dim` operation](Dialects/Standard.md#dim-operation) returns the size of a
1061 dimension from a value of tensor type.
1063 Note: hexadecimal integer literals are not allowed in tensor type declarations
1064 to avoid confusion between `0xf32` and `0 x f32`. Zero sizes are allowed in
1065 tensors and treated as other sizes, e.g., `tensor<0 x 1 x i32>` and `tensor<1 x
1066 0 x i32>` are different types. Since zero sizes are not allowed in some other
1067 types, such tensors should be optimized away before lowering tensors to vectors.
1072 // Tensor with unknown rank.
1075 // Known rank but unknown dimensions.
1076 tensor<? x ? x ? x ? x f32>
1078 // Partially known dimensions.
1079 tensor<? x ? x 13 x ? x f32>
1081 // Full static shape.
1082 tensor<17 x 4 x 13 x 4 x f32>
1084 // Tensor with rank zero. Represents a scalar.
1087 // Zero-element dimensions are allowed.
1088 tensor<0 x 42 x f32>
1090 // Zero-element tensor of f32 type (hexadecimal literals not allowed here).
1099 tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>`
1102 The value of `tuple` type represents a fixed-size collection of elements, where
1103 each element may be of a different type.
1105 **Rationale:** Though this type is first class in the type system, MLIR provides
1106 no standard operations for operating on `tuple` types
1107 ([rationale](Rationale.md#tuple-types)).
1119 tuple<i32, f32, tensor<i1>, i5>
1127 vector-type ::= `vector` `<` static-dimension-list vector-element-type `>`
1128 vector-element-type ::= float-type | integer-type
1130 static-dimension-list ::= (decimal-literal `x`)+
1133 The vector type represents a SIMD style vector, used by target-specific
1134 operation sets like AVX. While the most common use is for 1D vectors (e.g.
1135 vector<16 x f32>) we also support multidimensional registers on targets that
1136 support them (like TPUs).
1138 Vector shapes must be positive decimal integers.
1140 Note: hexadecimal integer literals are not allowed in vector type declarations,
1141 `vector<0x42xi32>` is invalid because it is interpreted as a 2D vector with
1142 shape `(0, 42)` and zero shapes are not allowed.
1149 attribute-dict ::= `{` `}`
1150 | `{` attribute-entry (`,` attribute-entry)* `}`
1151 attribute-entry ::= dialect-attribute-entry | dependent-attribute-entry
1152 dialect-attribute-entry ::= dialect-namespace `.` bare-id `=` attribute-value
1153 dependent-attribute-entry ::= dependent-attribute-name `=` attribute-value
1154 dependent-attribute-name ::= (letter|[_]) (letter|digit|[_$])*
1157 Attributes are the mechanism for specifying constant data on operations in
1158 places where a variable is never allowed - e.g. the index of a
1159 [`dim` operation](Dialects/Standard.md#dim-operation), or the stride of a
1160 convolution. They consist of a name and a concrete attribute value. The set of
1161 expected attributes, their structure, and their interpretation are all
1162 contextually dependent on what they are attached to.
1164 There are two main classes of attributes: dependent and dialect. Dependent
1165 attributes derive their structure and meaning from what they are attached to;
1166 e.g., the meaning of the `index` attribute on a `dim` operation is defined by
1167 the `dim` operation. Dialect attributes, on the other hand, derive their context
1168 and meaning from a specific dialect. An example of a dialect attribute may be a
1169 `swift.self` function argument attribute that indicates an argument is the
1170 self/context parameter. The context of this attribute is defined by the `swift`
1171 dialect and not the function argument.
1173 Attribute values are represented by the following forms:
1176 attribute-value ::= attribute-alias | dialect-attribute | standard-attribute
1179 ### Attribute Value Aliases
1182 attribute-alias ::= '#' alias-name '=' attribute-value
1183 attribute-alias ::= '#' alias-name
1186 MLIR supports defining named aliases for attribute values. An attribute alias is
1187 an identifier that can be used in the place of the attribute that it defines.
1188 These aliases *must* be defined before their uses. Alias names may not contain a
1189 '.', since those names are reserved for
1190 [dialect attributes](#dialect-attribute-values).
1195 #map = affine_map<(d0) -> (d0 + 10)>
1197 // Using the original attribute.
1198 %b = affine.apply affine_map<(d0) -> (d0 + 10)> (%a)
1200 // Using the attribute alias.
1201 %b = affine.apply #map(%a)
1204 ### Dialect Attribute Values
1206 Similarly to operations, dialects may define custom attribute values. The
1207 syntactic structure of these values is identical to custom dialect type values,
1208 except that dialect attributes values are distinguished with a leading '#',
1209 while dialect types are distinguished with a leading '!'.
1212 dialect-attribute ::= '#' opaque-dialect-item
1213 dialect-attribute ::= '#' pretty-dialect-item
1216 Dialect attributes can be specified in a verbose form, e.g. like this:
1219 // Complex attribute
1220 #foo<"something<abcd>">
1222 // Even more complex attribute
1223 #foo<"something<a%%123^^^>>>">
1226 Dialect attributes that are simple enough can use the pretty format, which is a
1227 lighter weight syntax that is equivalent to the above forms:
1230 // Complex attribute
1231 #foo.something<abcd>
1234 Sufficiently complex dialect attributes are required to use the verbose form for
1235 generality. For example, the more complex type shown above wouldn't be valid in
1236 the lighter syntax: `#foo.something<a%%123^^^>>>` because it contains characters
1237 that are not allowed in the lighter syntax, as well as unbalanced `<>`
1240 See [here](DefiningAttributesAndTypes.md) to learn how to define dialect
1243 ### Standard Attribute Values
1245 Standard attributes are a core set of
1246 [dialect attributes](#dialect-attribute-values) that are defined in a builtin
1247 dialect and thus available to all users of MLIR.
1250 standard-attribute ::= affine-map-attribute
1253 | dictionary-attribute
1254 | elements-attribute
1257 | integer-set-attribute
1259 | symbol-ref-attribute
1264 #### AffineMap Attribute
1269 affine-map-attribute ::= `affine_map` `<` affine-map `>`
1272 An affine-map attribute is an attribute that represents a affine-map object.
1274 #### Array Attribute
1279 array-attribute ::= `[` (attribute-value (`,` attribute-value)*)? `]`
1282 An array attribute is an attribute that represents a collection of attribute
1285 #### Boolean Attribute
1290 bool-attribute ::= bool-literal
1293 A boolean attribute is a literal attribute that represents a one-bit boolean
1294 value, true or false.
1296 #### Dictionary Attribute
1301 dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`
1304 A dictionary attribute is an attribute that represents a sorted collection of
1305 named attribute values. The elements are sorted by name, and each name must be
1306 unique within the collection.
1308 #### Elements Attributes
1313 elements-attribute ::= dense-elements-attribute
1314 | opaque-elements-attribute
1315 | sparse-elements-attribute
1318 An elements attribute is a literal attribute that represents a constant
1319 [vector](#vector-type) or [tensor](#tensor-type) value.
1321 ##### Dense Elements Attribute
1326 dense-elements-attribute ::= `dense` `<` attribute-value `>` `:`
1327 ( tensor-type | vector-type )
1330 A dense elements attribute is an elements attribute where the storage for the
1331 constant vector or tensor value has been packed to the element bitwidth. The
1332 element type of the vector or tensor constant must be of integer, index, or
1333 floating point type.
1335 ##### Opaque Elements Attribute
1340 opaque-elements-attribute ::= `opaque` `<` dialect-namespace `,`
1341 hex-string-literal `>` `:`
1342 ( tensor-type | vector-type )
1345 An opaque elements attribute is an elements attribute where the content of the
1346 value is opaque. The representation of the constant stored by this elements
1347 attribute is only understood, and thus decodable, by the dialect that created
1350 Note: The parsed string literal must be in hexadecimal form.
1352 ##### Sparse Elements Attribute
1357 sparse-elements-attribute ::= `sparse` `<` attribute-value `,` attribute-value
1358 `>` `:` ( tensor-type | vector-type )
1361 A sparse elements attribute is an elements attribute that represents a sparse
1362 vector or tensor object. This is where very few of the elements are non-zero.
1364 The attribute uses COO (coordinate list) encoding to represent the sparse
1365 elements of the elements attribute. The indices are stored via a 2-D tensor of
1366 64-bit integer elements with shape [N, ndims], which specifies the indices of
1367 the elements in the sparse tensor that contains non-zero values. The element
1368 values are stored via a 1-D tensor with shape [N], that supplies the
1369 corresponding values for the indices.
1374 sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>
1376 // This represents the following tensor:
1382 #### Float Attribute
1387 float-attribute ::= (float-literal (`:` float-type)?)
1388 | (hexadecimal-literal `:` float-type)
1391 A float attribute is a literal attribute that represents a floating point value
1392 of the specified [float type](#floating-point-types). It can be represented in
1393 the hexadecimal form where the hexadecimal value is interpreted as bits of the
1394 underlying binary representation. This form is useful for representing infinity
1395 and NaN floating point values. To avoid confusion with integer attributes,
1396 hexadecimal literals _must_ be followed by a float type to define a float
1402 42.0 // float attribute defaults to f64 type
1403 42.0 : f32 // float attribute of f32 type
1404 0x7C00 : f16 // positive infinity
1405 0x7CFF : f16 // NaN (one of possible values)
1406 42 : f32 // Error: expected integer type
1409 #### Integer Attribute
1414 integer-attribute ::= integer-literal ( `:` (index-type | integer-type) )?
1417 An integer attribute is a literal attribute that represents an integral value of
1418 the specified integer or index type. The default type for this attribute, if one
1419 is not specified, is a 64-bit integer.
1421 ##### Integer Set Attribute
1426 integer-set-attribute ::= `affine_set` `<` integer-set `>`
1429 An integer-set attribute is an attribute that represents an integer-set object.
1431 #### String Attribute
1436 string-attribute ::= string-literal (`:` type)?
1439 A string attribute is an attribute that represents a string literal value.
1441 #### Symbol Reference Attribute
1446 symbol-ref-attribute ::= symbol-ref-id (`::` symbol-ref-id)*
1449 A symbol reference attribute is a literal attribute that represents a named
1450 reference to an operation that is nested within an operation with the
1451 `OpTrait::SymbolTable` trait. As such, this reference is given meaning by the
1452 nearest parent operation containing the `OpTrait::SymbolTable` trait. It may
1453 optionally contain a set of nested references that further resolve to a symbol
1454 nested within a different symbol table.
1456 This attribute can only be held internally by
1457 [array attributes](#array-attribute) and
1458 [dictionary attributes](#dictionary-attribute)(including the top-level operation
1459 attribute dictionary), i.e. no other attribute kinds such as Locations or
1460 extended attribute kinds. If a reference to a symbol is necessary from outside
1461 of the symbol table that the symbol is defined in, a
1462 [string attribute](#string-attribute) can be used to refer to the symbol name.
1464 **Rationale:** Given that MLIR models global accesses with symbol references, to
1465 enable efficient multi-threading, it becomes difficult to effectively reason
1466 about their uses. By restricting the places that can legally hold a symbol
1467 reference, we can always opaquely reason about a symbols usage characteristics.
1474 type-attribute ::= type
1477 A type attribute is an attribute that represents a [type object](#type-system).
1482 unit-attribute ::= `unit`
1485 A unit attribute is an attribute that represents a value of `unit` type. The
1486 `unit` type allows only one value forming a singleton set. This attribute value
1487 is used to represent attributes that only have meaning from their existence.
1489 One example of such an attribute could be the `swift.self` attribute. This
1490 attribute indicates that a function parameter is the self/context parameter. It
1491 could be represented as a [boolean attribute](#boolean-attribute)(true or
1492 false), but a value of false doesn't really bring any value. The parameter
1493 either is the self/context or it isn't.
1496 // A unit attribute defined with the `unit` value specifier.
1497 func @verbose_form(i1) attributes {dialectName.unitAttr = unit}
1499 // A unit attribute can also be defined without the value specifier.
1500 func @simple_form(i1) attributes {dialectName.unitAttr}