1# Operation Definition Specification (ODS)
2
3In addition to specializing the `mlir::Op` C++ template, MLIR also supports
4defining operations and data types in a table-driven manner. This is achieved
5via [TableGen][TableGen], which is both a generic language and its tooling to
6maintain records of domain-specific information. Facts regarding an operation
7are specified concisely into a TableGen record, which will be expanded into an
8equivalent `mlir::Op` C++ template specialization at compiler build time.
9
10This manual explains in detail all the available mechanisms for defining
11operations in such a table-driven manner. It aims to be a specification instead
12of a tutorial. Please refer to
13[Quickstart tutorial to adding MLIR graph rewrite](Tutorials/QuickstartRewrites.md)
14for the latter.
15
16In addition to detailing each mechanism, this manual also tries to capture best
17practices. They are rendered as quoted bullet points.
18
19## Motivation
20
21MLIR allows pluggable dialects, and dialects contain, among others, a list of
22operations. This open and extensible ecosystem leads to the "stringly" type IR
23problem, e.g., repetitive string comparisons during optimization and analysis
24passes, unintuitive accessor methods (e.g., generic/error prone `getOperand(3)`
25vs self-documenting `getStride()`) with more generic return types, verbose and
26generic constructors without default arguments, verbose textual IR dump, and so
27on. Furthermore, operation verification is:
28
291.  best case: a central string-to-verification-function map,
301.  middle case: duplication of verification across the code base, or
311.  worst case: no verification functions.
32
33The fix is to support defining ops in a table-driven manner. Then for each
34dialect, we can have a central place that contains everything you need to know
35about each op, including its constraints, custom assembly form, etc. This
36description is also used to generate helper functions and classes to allow
37building, verification, parsing, printing, analysis, and many more.
38
39## Benefits
40
41Compared to the C++ template, this table-driven approach has several benefits
42including but not limited to:
43
44*   **Single source of truth**: We strive to encode all facts regarding an
45    operation into the record, so that readers don't need to jump among code
46    snippets to fully understand an operation.
47*   **Removing boilerplate**: We can automatically generate
48    operand/attribute/result getter methods, operation build methods, operation
49    verify methods, and many more utilities from the record. This greatly
50    reduces the boilerplate needed for defining a new op.
51*   **Facilitating auto-generation**: The usage of these operation information
52    records are by no means limited to op definition itself. We can use them to
53    drive the auto-generation of many other components, like computation graph
54    serialization.
55
56## TableGen Syntax
57
58We use TableGen as the language for specifying operation information. TableGen
59itself just provides syntax for writing records; the syntax and constructs
60allowed in a TableGen file (typically with filename suffix `.td`) can be found
61[here][TableGenProgRef].
62
63*   TableGen `class` is similar to C++ class; it can be templated and
64    subclassed.
65*   TableGen `def` is similar to C++ object; it can be declared by specializing
66    a TableGen `class` (e.g., `def MyDef : MyClass<...>;`) or completely
67    independently (e.g., `def MyDef;`). It cannot be further templated or
68    subclassed.
69*   TableGen `dag` is a dedicated type for directed acyclic graph of elements. A
70    `dag` has one operator and zero or more arguments. Its syntax is `(operator
71    arg0, arg1, argN)`. The operator can be any TableGen `def`; an argument can
72    be anything, including `dag` itself. We can have names attached to both the
73    operator and the arguments like `(MyOp:$op_name MyArg:$arg_name)`.
74
75Please see the [language reference][TableGenProgRef] to learn about all the
76types and expressions supported by TableGen.
77
78## Operation Definition
79
80MLIR defines several common constructs to help operation definition and provide
81their semantics via a special [TableGen backend][TableGenBackend]:
82[`OpDefinitionsGen`][OpDefinitionsGen]. These constructs are defined in
83[`OpBase.td`][OpBase]. The main ones are
84
85*   The `Op` class: It is the main construct for defining operations. All facts
86    regarding the operation are specified when specializing this class, with the
87    help of the following constructs.
88*   The `Dialect` class: Operations belonging to one logical group are placed in
89    the same dialect. The `Dialect` class contains dialect-level information.
90*   The `OpTrait` class hierarchy: They are used to specify special properties
91    and constraints of the operation, including whether the operation has side
92    effect or whether its output has the same shape as the input.
93*   The `ins`/`outs` marker: These are two special markers builtin to the
94    `OpDefinitionsGen` backend. They lead the definitions of operands/attributes
95    and results respectively.
96*   The `TypeConstraint` class hierarchy: They are used to specify the
97    constraints over operands or results. A notable subclass hierarchy is
98    `Type`, which stands for constraints for common C++ types.
99*   The `AttrConstraint` class hierarchy: They are used to specify the
100    constraints over attributes. A notable subclass hierarchy is `Attr`, which
101    stands for constraints for attributes whose values are of common types.
102
103An operation is defined by specializing the `Op` class with concrete contents
104for all the fields it requires. For example, `tf.AvgPool` is defined as
105
106```tablegen
107def TF_AvgPoolOp : TF_Op<"AvgPool", [NoSideEffect]> {
108  let summary = "Performs average pooling on the input.";
109
110  let description = [{
111Each entry in `output` is the mean of the corresponding size `ksize`
112window in `value`.
113  }];
114
115  let arguments = (ins
116    TF_FpTensor:$value,
117
118    Confined<I64ArrayAttr, [ArrayMinCount<4>]>:$ksize,
119    Confined<I64ArrayAttr, [ArrayMinCount<4>]>:$strides,
120    TF_AnyStrAttrOf<["SAME", "VALID"]>:$padding,
121    DefaultValuedAttr<TF_ConvertDataFormatAttr, "NHWC">:$data_format
122  );
123
124  let results = (outs
125    TF_FpTensor:$output
126  );
127
128  TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>;
129}
130```
131
132In the following we describe all the fields needed. Please see the definition of
133the `Op` class for the complete list of fields supported.
134
135### Operation name
136
137The operation name is a unique identifier of the operation within MLIR, e.g.,
138`tf.Add` for addition operation in the TensorFlow dialect. This is the
139equivalent of the mnemonic in assembly language. It is used for parsing and
140printing in the textual format. It is also used for pattern matching in graph
141rewrites.
142
143The full operation name is composed of the dialect name and the op name, with
144the former provided via the dialect and the latter provided as the second
145template parameter to the `Op` class.
146
147### Operation documentation
148
149This includes both a one-line `summary` and a longer human-readable
150`description`. They will be used to drive automatic generation of dialect
151documentation. They need to be provided in the operation's definition body:
152
153```tablegen
154let summary = "...";
155
156let description = [{
157...
158}];
159```
160
161`description` should be written in Markdown syntax.
162
163Placing the documentation at the beginning is recommended since it helps in
164understanding the operation.
165
166> *   Place documentation at the beginning of the operation definition
167> *   The summary should be short and concise. It should be a one-liner without
168>     trailing punctuation. Put expanded explanation in description.
169
170### Operation arguments
171
172There are two kinds of arguments: operands and attributes. Operands are runtime
173values produced by other ops; while attributes are compile-time known constant
174values, including two categories:
175
1761.  Natural attributes: these attributes affect the behavior of the operations
177    (e.g., padding for convolution);
1781.  Derived attributes: these attributes are not needed to define the operation
179    but are instead derived from information of the operation. E.g., the output
180    shape of type. This is mostly used for convenience interface generation or
181    interaction with other frameworks/translation.
182
183    All derived attributes should be materializable as an Attribute. That is,
184    even though they are not materialized, it should be possible to store as an
185    attribute.
186
187Both operands and attributes are specified inside the `dag`-typed `arguments`,
188led by `ins`:
189
190```tablegen
191let arguments = (ins
192  <type-constraint>:$<operand-name>,
193  ...
194  <attr-constraint>:$<attr-name>,
195  ...
196);
197```
198
199Here `<type-constraint>` is a TableGen `def` from the `TypeConstraint` class
200hierarchy. Similarly, `<attr-constraint>` is a TableGen `def` from the
201`AttrConstraint` class hierarchy. See [Constraints](#constraints) for more
202information.
203
204There is no requirements on the relative order of operands and attributes; they
205can mix freely. The relative order of operands themselves matters. From each
206named argument a named getter will be generated that returns the argument with
207the return type (in the case of attributes the return type will be constructed
208from the storage type, while for operands it will be `Value`). Each attribute's
209raw value (e.g., as stored) can also be accessed via generated `<name>Attr`
210getters for use in transformation passes where the more user friendly return
211type is less suitable.
212
213All the arguments should be named to 1) provide documentation, 2) drive
214auto-generation of getter methods, 3) provide a handle to reference for other
215places like constraints.
216
217#### Variadic operands
218
219To declare a variadic operand, wrap the `TypeConstraint` for the operand with
220`Variadic<...>`.
221
222Normally operations have no variadic operands or just one variadic operand. For
223the latter case, it is easy to deduce which dynamic operands are for the static
224variadic operand definition. Though, if an operation has more than one variable
225length operands (either optional or variadic), it would be impossible to
226attribute dynamic operands to the corresponding static variadic operand
227definitions without further information from the operation. Therefore, either
228the `SameVariadicOperandSize` or `AttrSizedOperandSegments` trait is needed to
229indicate that all variable length operands have the same number of dynamic
230values.
231
232#### VariadicOfVariadic operands
233
234To declare a variadic operand that has a variadic number of sub-ranges, wrap the
235`TypeConstraint` for the operand with `VariadicOfVariadic<...,
236"<segment-attribute-name>">`.
237
238The second field of the `VariadicOfVariadic` is the name of an `I32ElementsAttr`
239argument that contains the sizes of the variadic sub-ranges. This attribute will
240be used when determining the size of sub-ranges, or when updating the size of
241sub-ranges.
242
243#### Optional operands
244
245To declare an optional operand, wrap the `TypeConstraint` for the operand with
246`Optional<...>`.
247
248Normally operations have no optional operands or just one optional operand. For
249the latter case, it is easy to deduce which dynamic operands are for the static
250operand definition. Though, if an operation has more than one variable length
251operands (either optional or variadic), it would be impossible to attribute
252dynamic operands to the corresponding static variadic operand definitions
253without further information from the operation. Therefore, either the
254`SameVariadicOperandSize` or `AttrSizedOperandSegments` trait is needed to
255indicate that all variable length operands have the same number of dynamic
256values.
257
258#### Optional attributes
259
260To declare an optional attribute, wrap the `AttrConstraint` for the attribute
261with `OptionalAttr<...>`.
262
263#### Attributes with default values
264
265To declare an attribute with a default value, wrap the `AttrConstraint` for the
266attribute with `DefaultValuedAttr<..., "...">`.
267
268The second parameter to `DefaultValuedAttr` should be a string containing the
269C++ default value. For example, a float default value should be specified as
270like `"0.5f"`, and an integer array default value should be specified as like
271`"{1, 2, 3}"`.
272
273#### Confining attributes
274
275`Confined` is provided as a general mechanism to help modelling further
276constraints on attributes beyond the ones brought by value types. You can use
277`Confined` to compose complex constraints out of more primitive ones. For
278example, a 32-bit integer attribute whose minimum value must be 10 can be
279expressed as `Confined<I32Attr, [IntMinValue<10>]>`.
280
281Right now, the following primitive constraints are supported:
282
283*   `IntMinValue<N>`: Specifying an integer attribute to be greater than or
284    equal to `N`
285*   `IntMaxValue<N>`: Specifying an integer attribute to be less than or equal
286    to `N`
287*   `ArrayMinCount<N>`: Specifying an array attribute to have at least `N`
288    elements
289*   `IntArrayNthElemEq<I, N>`: Specifying an integer array attribute's `I`-th
290    element to be equal to `N`
291*   `IntArrayNthElemMinValue<I, N>`: Specifying an integer array attribute's
292    `I`-th element to be greater than or equal to `N`
293
294TODO: Design and implement more primitive constraints
295
296### Operation regions
297
298The regions of an operation are specified inside of the `dag`-typed `regions`,
299led by `region`:
300
301```tablegen
302let regions = (region
303  <region-constraint>:$<region-name>,
304  ...
305);
306```
307
308#### Variadic regions
309
310Similar to the `Variadic` class used for variadic operands and results,
311`VariadicRegion<...>` can be used for regions. Variadic regions can currently
312only be specified as the last region in the regions list.
313
314### Operation results
315
316Similar to operands, results are specified inside the `dag`-typed `results`, led
317by `outs`:
318
319```tablegen
320let results = (outs
321  <type-constraint>:$<result-name>,
322  ...
323);
324```
325
326#### Variadic results
327
328Similar to variadic operands, `Variadic<...>` can also be used for results. And
329similarly, `SameVariadicResultSize` for multiple variadic results in the same
330operation.
331
332### Operation successors
333
334For terminator operations, the successors are specified inside of the
335`dag`-typed `successors`, led by `successor`:
336
337```tablegen
338let successors = (successor
339  <successor-constraint>:$<successor-name>,
340  ...
341);
342```
343
344#### Variadic successors
345
346Similar to the `Variadic` class used for variadic operands and results,
347`VariadicSuccessor<...>` can be used for successors. Variadic successors can
348currently only be specified as the last successor in the successor list.
349
350### Operation traits and constraints
351
352Traits are operation properties that affect syntax or semantics. MLIR C++ models
353various traits in the `mlir::OpTrait` namespace.
354
355Both operation traits, [interfaces](Interfaces.md/#utilizing-the-ods-framework),
356and constraints involving multiple operands/attributes/results are provided as
357the third template parameter to the `Op` class. They should be deriving from
358the `OpTrait` class. See [Constraints](#constraints) for more information.
359
360### Builder methods
361
362For each operation, there are a few builders automatically generated based on
363the arguments and returns types. For example, given the following op definition:
364
365```tablegen
366def MyOp : ... {
367  let arguments = (ins
368    I32:$i32_operand,
369    F32:$f32_operand,
370    ...,
371
372    I32Attr:$i32_attr,
373    F32Attr:$f32_attr,
374    ...
375  );
376
377  let results = (outs
378    I32:$i32_result,
379    F32:$f32_result,
380    ...
381  );
382}
383```
384
385The following builders are generated:
386
387```c++
388// All result-types/operands/attributes have one aggregate parameter.
389static void build(OpBuilder &odsBuilder, OperationState &odsState,
390                  ArrayRef<Type> resultTypes,
391                  ValueRange operands,
392                  ArrayRef<NamedAttribute> attributes);
393
394// Each result-type/operand/attribute has a separate parameter. The parameters
395// for attributes are of mlir::Attribute types.
396static void build(OpBuilder &odsBuilder, OperationState &odsState,
397                  Type i32_result, Type f32_result, ...,
398                  Value i32_operand, Value f32_operand, ...,
399                  IntegerAttr i32_attr, FloatAttr f32_attr, ...);
400
401// Each result-type/operand/attribute has a separate parameter. The parameters
402// for attributes are raw values unwrapped with mlir::Attribute instances.
403// (Note that this builder will not always be generated. See the following
404// explanation for more details.)
405static void build(OpBuilder &odsBuilder, OperationState &odsState,
406                  Type i32_result, Type f32_result, ...,
407                  Value i32_operand, Value f32_operand, ...,
408                  APInt i32_attr, StringRef f32_attr, ...);
409
410// Each operand/attribute has a separate parameter but result type is aggregate.
411static void build(OpBuilder &odsBuilder, OperationState &odsState,
412                  ArrayRef<Type> resultTypes,
413                  Value i32_operand, Value f32_operand, ...,
414                  IntegerAttr i32_attr, FloatAttr f32_attr, ...);
415
416// All operands/attributes have aggregate parameters.
417// Generated if return type can be inferred.
418static void build(OpBuilder &odsBuilder, OperationState &odsState,
419                  ValueRange operands, ArrayRef<NamedAttribute> attributes);
420
421// (And manually specified builders depending on the specific op.)
422```
423
424The first form provides basic uniformity so that we can create ops using the
425same form regardless of the exact op. This is particularly useful for
426implementing declarative pattern rewrites.
427
428The second and third forms are good for use in manually written code given that
429they provide better guarantee via signatures.
430
431The third form will be generated if any of the op's attribute has different
432`Attr.returnType` from `Attr.storageType` and we know how to build an attribute
433from an unwrapped value (i.e., `Attr.constBuilderCall` is defined.)
434Additionally, for the third form, if an attribute appearing later in the
435`arguments` list has a default value, the default value will be supplied in the
436declaration. This works for `BoolAttr`, `StrAttr`, `EnumAttr` for now and the
437list can grow in the future. So if possible, default valued attribute should be
438placed at the end of the `arguments` list to leverage this feature. (This
439behavior is essentially due to C++ function parameter default value placement
440restrictions.) Otherwise, the builder of the third form will still be generated
441but default values for the attributes not at the end of the `arguments` list
442will not be supplied in the builder's signature.
443
444ODS will generate a builder that doesn't require return type specified if
445
446*   Op implements InferTypeOpInterface interface;
447*   All return types are either buildable types or are the same as a given
448    operand (e.g., `AllTypesMatch` constraint between operand and result);
449
450And there may potentially exist other builders depending on the specific op;
451please refer to the
452[generated C++ file](#run-mlir-tblgen-to-see-the-generated-content) for the
453complete list.
454
455#### Custom builder methods
456
457However, if the above cases cannot satisfy all needs, you can define additional
458convenience build methods in the `builders` field as follows.
459
460```tablegen
461def MyOp : Op<"my_op", []> {
462  let arguments = (ins F32Attr:$attr);
463
464  let builders = [
465    OpBuilder<(ins "float":$val)>
466  ];
467}
468```
469
470The `builders` field is a list of custom builders that are added to the Op
471class. In this example, we provide a convenience builder that takes a floating
472point value instead of an attribute. The `ins` prefix is common to many function
473declarations in ODS, which use a TableGen [`dag`](#tablegen-syntax). What
474follows is a comma-separated list of types (quoted string) and names prefixed
475with the `$` sign. This will generate the declaration of a builder method that
476looks like:
477
478```c++
479class MyOp : /*...*/ {
480  /*...*/
481  static void build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
482                    float val);
483};
484```
485
486Note that the method has two additional leading arguments. These arguments are
487useful to construct the operation. In particular, the method must populate
488`state` with attributes, operands, regions and result types of the operation to
489be constructed. `builder` can be used to construct any IR objects that belong to
490the Op, such as types or nested operations. Since the type and name are
491generated as is in the C++ code, they should be valid C++ constructs for a type
492(in the namespace of the Op) and an identifier (e.g., `class` is not a valid
493identifier).
494
495Implementations of the builder can be provided directly in ODS, using TableGen
496code block as follows.
497
498```tablegen
499def MyOp : Op<"my_op", []> {
500  let arguments = (ins F32Attr:$attr);
501
502  let builders = [
503    OpBuilder<(ins "float":$val), [{
504      $_state.addAttribute("attr", $_builder.getF32FloatAttr(val));
505    }]>
506  ];
507}
508```
509
510The equivalents of `builder` and `state` arguments are available as `$_builder`
511and `$_state` special variables. The named arguments listed in the `ins` part
512are available directly, e.g. `val`. The body of the builder will be generated by
513substituting special variables and should otherwise be valid C++. While there is
514no limitation on the code size, we encourage one to define only short builders
515inline in ODS and put definitions of longer builders in C++ files.
516
517Finally, if some arguments need a default value, they can be defined using
518`CArg` to wrap the type and this value as follows.
519
520```tablegen
521def MyOp : Op<"my_op", []> {
522  let arguments = (ins F32Attr:$attr);
523
524  let builders = [
525    OpBuilder<(ins CArg<"float", "0.5f">:$val), [{
526      $_state.addAttribute("attr", $_builder.getF32FloatAttr(val));
527    }]>
528  ];
529}
530```
531
532The generated code will use default value in the declaration, but not in the
533definition, as required by C++.
534
535```c++
536/// Header file.
537class MyOp : /*...*/ {
538  /*...*/
539  static void build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
540                    float val = 0.5f);
541};
542
543/// Source file.
544MyOp::build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
545            float val) {
546  state.addAttribute("attr", builder.getF32FloatAttr(val));
547}
548```
549
550**Deprecated:** `OpBuilder` class allows one to specify the custom builder
551signature as a raw string, without separating parameters into different `dag`
552arguments. It also supports leading parameters of `OpBuilder &` and
553`OperationState &` types, which will be used instead of the autogenerated ones
554if present.
555
556### Custom parser and printer methods
557
558Functions to parse and print the operation's custom assembly form.
559
560### Custom verifier code
561
562Verification code will be automatically generated for
563[constraints](#constraints) specified on various entities of the op. To perform
564_additional_ verification, you can use
565
566```tablegen
567let hasVerifier = 1;
568let hasRegionVerifier = 1;
569```
570
571This will generate `LogicalResult verify()`/`LogicalResult verifyRegions()`
572method declarations on the op class that can be defined with any additional
573verification constraints. For verificaiton which needs to access the nested
574operations, you should use `hasRegionVerifier` to ensure that it won't access
575any ill-formed operation. Except that, The other verifications can be
576implemented with `hasVerifier`. Check the next section for the execution order
577of these verification methods.
578
579#### Verification Ordering
580
581The verification of an operation involves several steps,
582
5831. StructuralOpTrait will be verified first, they can be run independently.
5841. `verifyInvariants` which is constructed by ODS, it verifies the type,
585   attributes, .etc.
5861. Other Traits/Interfaces that have marked their verifier as `verifyTrait` or
587   `verifyWithRegions=0`.
5881. Custom verifier which is defined in the op and has marked `hasVerifier=1`
589
590If an operation has regions, then it may have the second phase,
591
5921. Traits/Interfaces that have marked their verifier as `verifyRegionTrait` or
593   `verifyWithRegions=1`. This implies the verifier needs to access the
594   operations in its regions.
5951. Custom verifier which is defined in the op and has marked
596   `hasRegionVerifier=1`
597
598Note that the second phase will be run after the operations in the region are
599verified. Verifiers further down the order can rely on certain invariants being
600verified by a previous verifier and do not need to re-verify them.
601
602#### Emitting diagnostics in custom verifiers
603
604Custom verifiers should avoid printing operations using custom operation
605printers, because they require the printed operation (and sometimes its parent
606operation) to be verified first. In particular, when emitting diagnostics,
607custom verifiers should use the `Error` severity level, which prints operations
608in generic form by default, and avoid using lower severity levels (`Note`,
609`Remark`, `Warning`).
610
611### Declarative Assembly Format
612
613The custom assembly form of the operation may be specified in a declarative
614string that matches the operations operands, attributes, etc. With the ability
615to express additional information that needs to be parsed to build the
616operation:
617
618```tablegen
619def CallOp : Std_Op<"call", ...> {
620  let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$args);
621  let results = (outs Variadic<AnyType>);
622
623  let assemblyFormat = [{
624    $callee `(` $args `)` attr-dict `:` functional-type($args, results)
625  }];
626}
627```
628
629The format is comprised of three components:
630
631#### Directives
632
633A directive is a type of builtin function, with an optional set of arguments.
634The available directives are as follows:
635
636*   `attr-dict`
637
638    -   Represents the attribute dictionary of the operation.
639
640*   `attr-dict-with-keyword`
641
642    -   Represents the attribute dictionary of the operation, but prefixes the
643        dictionary with an `attributes` keyword.
644
645*   `custom` < UserDirective > ( Params )
646
647    -   Represents a custom directive implemented by the user in C++.
648    -   See the [Custom Directives](#custom-directives) section below for more
649        details.
650
651*   `functional-type` ( inputs , results )
652
653    -   Formats the `inputs` and `results` arguments as a
654        [function type](Dialects/Builtin.md/#functiontype).
655    -   The constraints on `inputs` and `results` are the same as the `input` of
656        the `type` directive.
657
658*   `oilist` ( \`keyword\` elements | \`otherKeyword\` elements ...)
659
660    -   Represents an optional order-independent list of clauses. Each clause
661        has a keyword and corresponding assembly format.
662    -   Each clause can appear 0 or 1 time (in any order).
663    -   Only literals, types and variables can be used within an oilist element.
664    -   All the variables must be optional or variadic.
665
666*   `operands`
667
668    -   Represents all of the operands of an operation.
669
670*   `ref` ( input )
671
672    -   Represents a reference to the a variable or directive, that must have
673        already been resolved, that may be used as a parameter to a `custom`
674        directive.
675    -   Used to pass previously parsed entities to custom directives.
676    -   The input may be any directive or variable, aside from `functional-type`
677        and `custom`.
678
679*   `regions`
680
681    -   Represents all of the regions of an operation.
682
683*   `results`
684
685    -   Represents all of the results of an operation.
686
687*   `successors`
688
689    -   Represents all of the successors of an operation.
690
691*   `type` ( input )
692
693    -   Represents the type of the given input.
694    -   `input` must be either an operand or result [variable](#variables), the
695        `operands` directive, or the `results` directive.
696
697*   `qualified` ( type_or_attribute )
698
699    -   Wraps a `type` directive or an attribute parameter.
700    -   Used to force printing the type or attribute prefixed with its dialect
701        and mnemonic. For example the `vector.multi_reduction` operation has a
702        `kind` attribute ; by default the declarative assembly will print:
703        `vector.multi_reduction <minf>, ...` but using `qualified($kind)` in the
704        declarative assembly format will print it instead as:
705        `vector.multi_reduction #vector.kind<minf>, ...`.
706
707#### Literals
708
709A literal is either a keyword or punctuation surrounded by \`\`.
710
711The following are the set of valid punctuation:
712
713`:`, `,`, `=`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, `->`, `?`, `+`, `*`
714
715The following are valid whitespace punctuation:
716
717`\n`, ` `
718
719The `\n` literal emits a newline an indents to the start of the operation. An
720example is shown below:
721
722```tablegen
723let assemblyFormat = [{
724  `{` `\n` ` ` ` ` `this_is_on_a_newline` `\n` `}` attr-dict
725}];
726```
727
728```mlir
729%results = my.operation {
730  this_is_on_a_newline
731}
732```
733
734An empty literal \`\` may be used to remove a space that is inserted implicitly
735after certain literal elements, such as `)`/`]`/etc. For example, "`]`" may
736result in an output of `]` it is not the last element in the format. "`]` \`\`"
737would trim the trailing space in this situation.
738
739#### Variables
740
741A variable is an entity that has been registered on the operation itself, i.e.
742an argument(attribute or operand), region, result, successor, etc. In the
743`CallOp` example above, the variables would be `$callee` and `$args`.
744
745Attribute variables are printed with their respective value type, unless that
746value type is buildable. In those cases, the type of the attribute is elided.
747
748#### Custom Directives
749
750The declarative assembly format specification allows for handling a large
751majority of the common cases when formatting an operation. For the operations
752that require or desire specifying parts of the operation in a form not supported
753by the declarative syntax, custom directives may be specified. A custom
754directive essentially allows for users to use C++ for printing and parsing
755subsections of an otherwise declaratively specified format. Looking at the
756specification of a custom directive above:
757
758```
759custom-directive ::= `custom` `<` UserDirective `>` `(` Params `)`
760```
761
762A custom directive has two main parts: The `UserDirective` and the `Params`. A
763custom directive is transformed into a call to a `print*` and a `parse*` method
764when generating the C++ code for the format. The `UserDirective` is an
765identifier used as a suffix to these two calls, i.e., `custom<MyDirective>(...)`
766would result in calls to `parseMyDirective` and `printMyDirective` within the
767parser and printer respectively. `Params` may be any combination of variables
768(i.e. Attribute, Operand, Successor, etc.), type directives, and `attr-dict`.
769The type directives must refer to a variable, but that variable need not also be
770a parameter to the custom directive.
771
772The arguments to the `parse<UserDirective>` method are firstly a reference to
773the `OpAsmParser`(`OpAsmParser &`), and secondly a set of output parameters
774corresponding to the parameters specified in the format. The mapping of
775declarative parameter to `parse` method argument is detailed below:
776
777*   Attribute Variables
778    -   Single: `<Attribute-Storage-Type>(e.g. Attribute) &`
779    -   Optional: `<Attribute-Storage-Type>(e.g. Attribute) &`
780*   Operand Variables
781    -   Single: `OpAsmParser::OperandType &`
782    -   Optional: `Optional<OpAsmParser::OperandType> &`
783    -   Variadic: `SmallVectorImpl<OpAsmParser::OperandType> &`
784    -   VariadicOfVariadic:
785        `SmallVectorImpl<SmallVector<OpAsmParser::OperandType>> &`
786*   Ref Directives
787    -   A reference directive is passed to the parser using the same mapping as
788        the input operand. For example, a single region would be passed as a
789        `Region &`.
790*   Region Variables
791    -   Single: `Region &`
792    -   Variadic: `SmallVectorImpl<std::unique_ptr<Region>> &`
793*   Successor Variables
794    -   Single: `Block *&`
795    -   Variadic: `SmallVectorImpl<Block *> &`
796*   Type Directives
797    -   Single: `Type &`
798    -   Optional: `Type &`
799    -   Variadic: `SmallVectorImpl<Type> &`
800    -   VariadicOfVariadic: `SmallVectorImpl<SmallVector<Type>> &`
801*   `attr-dict` Directive: `NamedAttrList &`
802
803When a variable is optional, the value should only be specified if the variable
804is present. Otherwise, the value should remain `None` or null.
805
806The arguments to the `print<UserDirective>` method is firstly a reference to the
807`OpAsmPrinter`(`OpAsmPrinter &`), second the op (e.g. `FooOp op` which can be
808`Operation *op` alternatively), and finally a set of output parameters
809corresponding to the parameters specified in the format. The mapping of
810declarative parameter to `print` method argument is detailed below:
811
812*   Attribute Variables
813    -   Single: `<Attribute-Storage-Type>(e.g. Attribute)`
814    -   Optional: `<Attribute-Storage-Type>(e.g. Attribute)`
815*   Operand Variables
816    -   Single: `Value`
817    -   Optional: `Value`
818    -   Variadic: `OperandRange`
819    -   VariadicOfVariadic: `OperandRangeRange`
820*   Ref Directives
821    -   A reference directive is passed to the printer using the same mapping as
822        the input operand. For example, a single region would be passed as a
823        `Region &`.
824*   Region Variables
825    -   Single: `Region &`
826    -   Variadic: `MutableArrayRef<Region>`
827*   Successor Variables
828    -   Single: `Block *`
829    -   Variadic: `SuccessorRange`
830*   Type Directives
831    -   Single: `Type`
832    -   Optional: `Type`
833    -   Variadic: `TypeRange`
834    -   VariadicOfVariadic: `TypeRangeRange`
835*   `attr-dict` Directive: `DictionaryAttr`
836
837When a variable is optional, the provided value may be null.
838
839#### Optional Groups
840
841In certain situations operations may have "optional" information, e.g.
842attributes or an empty set of variadic operands. In these situations a section
843of the assembly format can be marked as `optional` based on the presence of this
844information. An optional group is defined as follows:
845
846```
847optional-group: `(` elements `)` (`:` `(` else-elements `)`)? `?`
848```
849
850The `elements` of an optional group have the following requirements:
851
852*   The first element of the group must either be a attribute, literal, operand,
853    or region.
854    -   This is because the first element must be optionally parsable.
855*   Exactly one argument variable or type directive within the group must be
856    marked as the anchor of the group.
857    -   The anchor is the element whose presence controls whether the group
858        should be printed/parsed.
859    -   An element is marked as the anchor by adding a trailing `^`.
860    -   The first element is *not* required to be the anchor of the group.
861    -   When a non-variadic region anchors a group, the detector for printing
862        the group is if the region is empty.
863*   Literals, variables, custom directives, and type directives are the only
864    valid elements within the group.
865    -   Any attribute variable may be used, but only optional attributes can be
866        marked as the anchor.
867    -   Only variadic or optional results and operand arguments and can be used.
868    -   All region variables can be used. When a non-variable length region is
869        used, if the group is not present the region is empty.
870
871An example of an operation with an optional group is `func.return`, which has a
872variadic number of operands.
873
874```tablegen
875def ReturnOp : ... {
876  let arguments = (ins Variadic<AnyType>:$operands);
877
878  // We only print the operands and types if there are a non-zero number
879  // of operands.
880  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
881}
882```
883
884##### Unit Attributes
885
886In MLIR, the [`unit` Attribute](Dialects/Builtin.md/#unitattr) is special in that it
887only has one possible value, i.e. it derives meaning from its existence. When a
888unit attribute is used to anchor an optional group and is not the first element
889of the group, the presence of the unit attribute can be directly correlated with
890the presence of the optional group itself. As such, in these situations the unit
891attribute will not be printed or present in the output and will be automatically
892inferred when parsing by the presence of the optional group itself.
893
894For example, the following operation:
895
896```tablegen
897def FooOp : ... {
898  let arguments = (ins UnitAttr:$is_read_only);
899
900  let assemblyFormat = "attr-dict (`is_read_only` $is_read_only^)?";
901}
902```
903
904would be formatted as such:
905
906```mlir
907// When the unit attribute is present:
908foo.op is_read_only
909
910// When the unit attribute is not present:
911foo.op
912```
913
914##### Optional "else" Group
915
916Optional groups also have support for an "else" group of elements. These are
917elements that are parsed/printed if the `anchor` element of the optional group
918is *not* present. Unlike the main element group, the "else" group has no
919restriction on the first element and none of the elements may act as the
920`anchor` for the optional. An example is shown below:
921
922```tablegen
923def FooOp : ... {
924  let arguments = (ins UnitAttr:$foo);
925
926  let assemblyFormat = "attr-dict (`foo_is_present` $foo^):(`foo_is_absent`)?";
927}
928```
929
930would be formatted as such:
931
932```mlir
933// When the `foo` attribute is present:
934foo.op foo_is_present
935
936// When the `foo` attribute is not present:
937foo.op foo_is_absent
938```
939
940#### Requirements
941
942The format specification has a certain set of requirements that must be adhered
943to:
944
9451.  The output and operation name are never shown as they are fixed and cannot
946    be altered.
9471.  All operands within the operation must appear within the format, either
948    individually or with the `operands` directive.
9491.  All regions within the operation must appear within the format, either
950    individually or with the `regions` directive.
9511.  All successors within the operation must appear within the format, either
952    individually or with the `successors` directive.
9531.  All operand and result types must appear within the format using the various
954    `type` directives, either individually or with the `operands` or `results`
955    directives.
9561.  The `attr-dict` directive must always be present.
9571.  Must not contain overlapping information; e.g. multiple instances of
958    'attr-dict', types, operands, etc.
959    -   Note that `attr-dict` does not overlap with individual attributes. These
960        attributes will simply be elided when printing the attribute dictionary.
961
962##### Type Inference
963
964One requirement of the format is that the types of operands and results must
965always be present. In certain instances, the type of a variable may be deduced
966via type constraints or other information available. In these cases, the type of
967that variable may be elided from the format.
968
969*   Buildable Types
970
971Some type constraints may only have one representation, allowing for them to be
972directly buildable; for example the `I32` or `Index` types. Types in `ODS` may
973mark themselves as buildable by setting the `builderCall` field or inheriting
974from the `BuildableType` class.
975
976*   Trait Equality Constraints
977
978There are many operations that have known type equality constraints registered
979as traits on the operation; for example the true, false, and result values of a
980`select` operation often have the same type. The assembly format may inspect
981these equal constraints to discern the types of missing variables. The currently
982supported traits are: `AllTypesMatch`, `TypesMatchWith`, `SameTypeOperands`, and
983`SameOperandsAndResultType`.
984
985*   InferTypeOpInterface
986
987Operations that implement `InferTypeOpInterface` can omit their result types in
988their assembly format since the result types can be inferred from the operands.
989
990### `hasCanonicalizer`
991
992This boolean field indicate whether canonicalization patterns have been defined
993for this operation. If it is `1`, then `::getCanonicalizationPatterns()` should
994be defined.
995
996### `hasCanonicalizeMethod`
997
998When this boolean field is set to `true`, it indicates that the op implements a
999`canonicalize` method for simple "matchAndRewrite" style canonicalization
1000patterns. If `hasCanonicalizer` is 0, then an implementation of
1001`::getCanonicalizationPatterns()` is implemented to call this function.
1002
1003### `hasFolder`
1004
1005This boolean field indicate whether general folding rules have been defined for
1006this operation. If it is `1`, then `::fold()` should be defined.
1007
1008### Extra declarations
1009
1010One of the goals of table-driven op definition is to auto-generate as much logic
1011and methods needed for each op as possible. With that said, there will always be
1012long-tail cases that won't be covered. For such cases, you can use
1013`extraClassDeclaration`. Code in `extraClassDeclaration` will be copied
1014literally to the generated C++ op class.
1015
1016Note that `extraClassDeclaration` is a mechanism intended for long-tail cases by
1017power users; for not-yet-implemented widely-applicable cases, improving the
1018infrastructure is preferable.
1019
1020### Extra definitions
1021
1022When defining base op classes in TableGen that are inherited many times by
1023different ops, users may want to provide common definitions of utility and
1024interface functions. However, many of these definitions may not be desirable or
1025possible in `extraClassDeclaration`, which append them to the op's C++ class
1026declaration. In these cases, users can add an `extraClassDefinition` to define
1027code that is added to the generated source file inside the op's C++ namespace.
1028The substitution `$cppClass` is replaced by the op's C++ class name.
1029
1030### Generated C++ code
1031
1032[OpDefinitionsGen][OpDefinitionsGen] processes the op definition spec file and
1033generates two files containing the corresponding C++ code: one for declarations,
1034the other for definitions. The former is generated via the `-gen-op-decls`
1035command-line option, while the latter is via the `-gen-op-defs` option.
1036
1037The definition file contains all the op method definitions, which can be
1038included and enabled by defining `GET_OP_CLASSES`. For each operation,
1039OpDefinitionsGen generates an operation class and an
1040[operand adaptor](#operand-adaptors) class. Besides, it also contains a
1041comma-separated list of all defined ops, which can be included and enabled by
1042defining `GET_OP_LIST`.
1043
1044#### Class name and namespaces
1045
1046For each operation, its generated C++ class name is the symbol `def`ed with
1047TableGen with dialect prefix removed. The first `_` serves as the delimiter. For
1048example, for `def TF_AddOp`, the C++ class name would be `AddOp`. We remove the
1049`TF` prefix because it is for scoping ops; other dialects may as well define
1050their own `AddOp`s.
1051
1052The namespaces of the generated C++ class will come from the dialect's
1053`cppNamespace` field. For example, if a dialect's `cppNamespace` is `A::B`, then
1054an op of that dialect will be placed in `namespace A { namespace B { ... } }`.
1055If a dialect does not specify a `cppNamespace`, we then use the dialect's name
1056as the namespace.
1057
1058This means the qualified name of the generated C++ class does not necessarily
1059match exactly with the operation name as explained in
1060[Operation name](#operation-name). This is to allow flexible naming to satisfy
1061coding style requirements.
1062
1063#### Operand adaptors
1064
1065For each operation, we automatically generate an _operand adaptor_. This class
1066solves the problem of accessing operands provided as a list of `Value`s without
1067using "magic" constants. The operand adaptor takes a reference to an array of
1068`Value` and provides methods with the same names as those in the operation class
1069to access them. For example, for a binary arithmetic operation, it may provide
1070`.lhs()` to access the first operand and `.rhs()` to access the second operand.
1071
1072The operand adaptor class lives in the same namespace as the operation class,
1073and has the name of the operation followed by `Adaptor` as well as an alias
1074`Adaptor` inside the op class.
1075
1076Operand adaptors can be used in function templates that also process operations:
1077
1078```c++
1079template <typename BinaryOpTy>
1080std::pair<Value, Value> zip(BinaryOpTy &&op) {
1081  return std::make_pair(op.lhs(), op.rhs());;
1082}
1083
1084void process(AddOp op, ArrayRef<Value> newOperands) {
1085  zip(op);
1086  zip(Adaptor<AddOp>(newOperands));
1087  /*...*/
1088}
1089```
1090
1091## Constraints
1092
1093Constraint is a core concept in table-driven operation definition: operation
1094verification and graph operation matching are all based on satisfying
1095constraints. So both the operation definition and rewrite rules specification
1096significantly involve writing constraints. We have the `Constraint` class in
1097[`OpBase.td`][OpBase] as the common base class for all constraints.
1098
1099An operation's constraint can cover different range; it may
1100
1101*   Only concern a single attribute (e.g. being a 32-bit integer greater than
1102    5),
1103*   Multiple operands and results (e.g., the 1st result's shape must be the same
1104    as the 1st operand), or
1105*   Intrinsic to the operation itself (e.g., having no side effect).
1106
1107We call them as single-entity constraint, multi-entity constraint, and traits,
1108respectively.
1109
1110### Single-entity constraint
1111
1112Constraints scoped to a single operand, attribute, or result are specified at
1113the entity's declaration place as described in
1114[Operation arguments](#operation-arguments) and
1115[Operation results](#operation-results).
1116
1117To help modelling constraints of common types, a set of `TypeConstraint`s are
1118created; they are the `Type` subclass hierarchy. It includes `F32` for the
1119constraints of being a float, `TensorOf<[F32]>` for the constraints of being a
1120float tensor, and so on.
1121
1122Similarly, a set of `AttrConstraint`s are created for helping modelling
1123constraints of common attribute kinds. They are the `Attr` subclass hierarchy.
1124It includes `F32Attr` for the constraints of being a float attribute,
1125`F32ArrayAttr` for the constraints of being a float array attribute, and so on.
1126
1127### Multi-entity constraint
1128
1129Constraints involving more than one operand/attribute/result are quite common on
1130operations, like the element type and shape relation between operands and
1131results. These constraints should be specified as the `Op` class template
1132parameter as described in
1133[Operation traits and constraints](#operation-traits-and-constraints).
1134
1135Multi-entity constraints are modeled as `PredOpTrait` (a subclass of `OpTrait`)
1136in [`OpBase.td`][OpBase].A bunch of constraint primitives are provided to help
1137specification. See [`OpBase.td`][OpBase] for the complete list.
1138
1139### Trait
1140
1141Traits are intrinsic properties of the operation like having side effect or not,
1142commutative or not, whether is a terminator, etc. These constraints should be
1143specified as the `Op` class template parameter as described in
1144[Operation traits and constraints](#operation-traits-and-constraints).
1145
1146Traits are modeled as `NativeOpTrait` (a subclass of `OpTrait`) in
1147[`OpBase.td`][OpBase]. They are backed and will be translated into the
1148corresponding C++ `mlir::OpTrait` classes.
1149
1150### How to specify new constraint
1151
1152To write a constraint, you need to provide its predicates and give it a
1153descriptive name. Predicates, modeled with the `Pred` class, are the workhorse
1154for composing constraints. The predicate for a constraint is typically built up
1155in a nested manner, using the two categories of predicates:
1156
11571.  `CPred`: the primitive leaf predicate.
11582.  Compound predicate: a predicate composed from child predicates using
1159    predicate combiners (conjunction: `And`, disjunction: `Or`, negation: `Neg`,
1160    substitution: `SubstLeaves`, concatenation: `Concat`).
1161
1162`CPred` is the basis for composing more complex predicates. It is the "atom"
1163predicate from the perspective of TableGen and the "interface" between TableGen
1164and C++. What is inside is already C++ code, which will be treated as opaque
1165strings with special placeholders to be substituted.
1166
1167You can put any C++ code that returns a boolean value inside a `CPred`,
1168including evaluating expressions, calling functions, calling class methods, and
1169so on.
1170
1171To help interaction with the C++ environment, there are a few special
1172placeholders provided to refer to entities in the context where this predicate
1173is used. They serve as "hooks" to the enclosing environment. This includes
1174`$_builder`, `$_op`, and `$_self`:
1175
1176*   `$_builder` will be replaced by a `mlir::Builder` instance so that you can
1177    access common build methods.
1178*   `$_op` will be replaced by the current operation so that you can access
1179    information of the current operation.
1180*   `$_self` will be replaced with the entity this predicate is attached to.
1181    E.g., `BoolAttr` is an attribute constraint that wraps a
1182    `CPred<"$_self.isa<BoolAttr>()">`. Then for `BoolAttr:$attr`,`$_self` will be
1183    replaced by `$attr`. For type constraints, it's a little bit special since
1184    we want the constraints on each type definition reads naturally and we want
1185    to attach type constraints directly to an operand/result, `$_self` will be
1186    replaced by the operand/result's type. E.g., for `F32` in `F32:$operand`,
1187    its `$_self` will be expanded as `operand(...).getType()`.
1188
1189TODO: Reconsider the leading symbol for special placeholders. Eventually we want
1190to allow referencing operand/result `$-name`s; such `$-name`s can start with
1191underscore.
1192
1193For example, to write an attribute `attr` is an `IntegerAttr`, in C++ you can
1194just call `attr.isa<IntegerAttr>()`. The code can be wrapped in a `CPred` as
1195`$_self.isa<IntegerAttr>()`, with `$_self` as the special placeholder to be
1196replaced by the current attribute `attr` at expansion time.
1197
1198For more complicated predicates, you can wrap it in a single `CPred`, or you can
1199use predicate combiners to combine them. For example, to write the constraint
1200that an attribute `attr` is a 32-bit or 64-bit integer, you can write it as
1201
1202```tablegen
1203And<[
1204  CPred<"$_self.isa<IntegerAttr>()">,
1205  Or<[
1206    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(32)">,
1207    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(64)">
1208  ]>
1209]>
1210```
1211
1212(Note that the above is just to show with a familiar example how you can use
1213`CPred` and predicate combiners to write complicated predicates. For integer
1214attributes specifically, [`OpBase.td`][OpBase] already defines `I32Attr` and
1215`I64Attr`. So you can actually reuse them to write it as `Or<[I32Attr.predicate,
1216I64Attr.predicate]>`.)
1217
1218TODO: Build up a library of reusable primitive constraints
1219
1220If the predicate is very complex to write with `CPred` together with predicate
1221combiners, you can also write it as a normal C++ function and use the `CPred` as
1222a way to "invoke" the function. For example, to verify an attribute `attr` has
1223some property, you can write a C++ function like
1224
1225```cpp
1226bool HasSomeProperty(Attribute attr) { ... }
1227```
1228
1229and then define the op as:
1230
1231```tablegen
1232def HasSomeProperty : AttrConstraint<CPred<"HasSomeProperty($_self)">,
1233                                     "has some property">;
1234
1235def MyOp : Op<...> {
1236  let arguments = (ins
1237    ...
1238    HasSomeProperty:$attr
1239  );
1240}
1241```
1242
1243As to whether we should define the predicate using a single `CPred` wrapping the
1244whole expression, multiple `CPred`s with predicate combiners, or a single
1245`CPred` "invoking" a function, there are no clear-cut criteria. Defining using
1246`CPred` and predicate combiners is preferable since it exposes more information
1247(instead hiding all the logic behind a C++ function) into the op definition spec
1248so that it can potentially drive more auto-generation cases. But it will require
1249a nice library of common predicates as the building blocks to avoid the
1250duplication, which is being worked on right now.
1251
1252## Attribute Definition
1253
1254An attribute is a compile-time known constant of an operation.
1255
1256ODS provides attribute wrappers over C++ attribute classes. There are a few
1257common C++ [attribute classes][AttrClasses] defined in MLIR's core IR library
1258and one is free to define dialect-specific attribute classes. ODS allows one to
1259use these attributes in TableGen to define operations, potentially with more
1260fine-grained constraints. For example, `StrAttr` directly maps to `StringAttr`;
1261`F32Attr`/`F64Attr` requires the `FloatAttr` to additionally be of a certain
1262bitwidth.
1263
1264ODS attributes are defined as having a storage type (corresponding to a backing
1265`mlir::Attribute` that _stores_ the attribute), a return type (corresponding to
1266the C++ _return_ type of the generated helper getters) as well as a method
1267to convert between the internal storage and the helper method.
1268
1269### Attribute decorators
1270
1271There are a few important attribute adapters/decorators/modifiers that can be
1272applied to ODS attributes to specify common additional properties like
1273optionality, default values, etc.:
1274
1275*   `DefaultValuedAttr`: specifies the
1276    [default value](#attributes-with-default-values) for an attribute.
1277*   `OptionalAttr`: specifies an attribute as [optional](#optional-attributes).
1278*   `Confined`: adapts an attribute with
1279    [further constraints](#confining-attributes).
1280
1281### Enum attributes
1282
1283Some attributes can only take values from a predefined enum, e.g., the
1284comparison kind of a comparison op. To define such attributes, ODS provides
1285several mechanisms: `StrEnumAttr`, `IntEnumAttr`, and `BitEnumAttr`.
1286
1287*   `StrEnumAttr`: each enum case is a string, the attribute is stored as a
1288    [`StringAttr`][StringAttr] in the op.
1289*   `IntEnumAttr`: each enum case is an integer, the attribute is stored as a
1290    [`IntegerAttr`][IntegerAttr] in the op.
1291*   `BitEnumAttr`: each enum case is a either the empty case, a single bit,
1292    or a group of single bits, and the attribute is stored as a
1293    [`IntegerAttr`][IntegerAttr] in the op.
1294
1295All these `*EnumAttr` attributes require fully specifying all of the allowed
1296cases via their corresponding `*EnumAttrCase`. With this, ODS is able to
1297generate additional verification to only accept allowed cases. To facilitate the
1298interaction between `*EnumAttr`s and their C++ consumers, the
1299[`EnumsGen`][EnumsGen] TableGen backend can generate a few common utilities: a
1300C++ enum class, `llvm::DenseMapInfo` for the enum class, conversion functions
1301from/to strings. This is controlled via the `-gen-enum-decls` and
1302`-gen-enum-defs` command-line options of `mlir-tblgen`.
1303
1304For example, given the following `EnumAttr`:
1305
1306```tablegen
1307def Case15: I32EnumAttrCase<"Case15", 15>;
1308def Case20: I32EnumAttrCase<"Case20", 20>;
1309
1310def MyIntEnum: I32EnumAttr<"MyIntEnum", "An example int enum",
1311                           [Case15, Case20]> {
1312  let cppNamespace = "Outer::Inner";
1313  let stringToSymbolFnName = "ConvertToEnum";
1314  let symbolToStringFnName = "ConvertToString";
1315}
1316```
1317
1318The following will be generated via `mlir-tblgen -gen-enum-decls`:
1319
1320```c++
1321namespace Outer {
1322namespace Inner {
1323// An example int enum
1324enum class MyIntEnum : uint32_t {
1325  Case15 = 15,
1326  Case20 = 20,
1327};
1328
1329llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t);
1330llvm::StringRef ConvertToString(MyIntEnum);
1331llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef);
1332inline constexpr unsigned getMaxEnumValForMyIntEnum() {
1333  return 20;
1334}
1335
1336} // namespace Inner
1337} // namespace Outer
1338
1339namespace llvm {
1340template<> struct DenseMapInfo<Outer::Inner::MyIntEnum> {
1341  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1342
1343  static inline Outer::Inner::MyIntEnum getEmptyKey() {
1344    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getEmptyKey());
1345  }
1346
1347  static inline Outer::Inner::MyIntEnum getTombstoneKey() {
1348    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getTombstoneKey());
1349  }
1350
1351  static unsigned getHashValue(const Outer::Inner::MyIntEnum &val) {
1352    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1353  }
1354
1355  static bool isEqual(const Outer::Inner::MyIntEnum &lhs, const Outer::Inner::MyIntEnum &rhs) {
1356    return lhs == rhs;
1357  }
1358};
1359}
1360```
1361
1362The following will be generated via `mlir-tblgen -gen-enum-defs`:
1363
1364```c++
1365namespace Outer {
1366namespace Inner {
1367llvm::StringRef ConvertToString(MyIntEnum val) {
1368  switch (val) {
1369    case MyIntEnum::Case15: return "Case15";
1370    case MyIntEnum::Case20: return "Case20";
1371  }
1372  return "";
1373}
1374
1375llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef str) {
1376  return llvm::StringSwitch<llvm::Optional<MyIntEnum>>(str)
1377      .Case("Case15", MyIntEnum::Case15)
1378      .Case("Case20", MyIntEnum::Case20)
1379      .Default(llvm::None);
1380}
1381llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t value) {
1382  switch (value) {
1383  case 15: return MyIntEnum::Case15;
1384  case 20: return MyIntEnum::Case20;
1385  default: return llvm::None;
1386  }
1387}
1388
1389} // namespace Inner
1390} // namespace Outer
1391```
1392
1393Similarly for the following `BitEnumAttr` definition:
1394
1395```tablegen
1396def None: BitEnumAttrCaseNone<"None">;
1397def Bit0: BitEnumAttrCaseBit<"Bit0", 0>;
1398def Bit1: BitEnumAttrCaseBit<"Bit1", 1>;
1399def Bit2: BitEnumAttrCaseBit<"Bit2", 2>;
1400def Bit3: BitEnumAttrCaseBit<"Bit3", 3>;
1401
1402def MyBitEnum: BitEnumAttr<"MyBitEnum", "An example bit enum",
1403                           [None, Bit0, Bit1, Bit2, Bit3]>;
1404```
1405
1406We can have:
1407
1408```c++
1409// An example bit enum
1410enum class MyBitEnum : uint32_t {
1411  None = 0,
1412  Bit0 = 1,
1413  Bit1 = 2,
1414  Bit2 = 4,
1415  Bit3 = 8,
1416};
1417
1418llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t);
1419std::string stringifyMyBitEnum(MyBitEnum);
1420llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef);
1421inline MyBitEnum operator|(MyBitEnum lhs, MyBitEnum rhs) {
1422  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
1423}
1424inline MyBitEnum operator&(MyBitEnum lhs, MyBitEnum rhs) {
1425  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
1426}
1427inline bool bitEnumContains(MyBitEnum bits, MyBitEnum bit) {
1428  return (static_cast<uint32_t>(bits) & static_cast<uint32_t>(bit)) != 0;
1429}
1430
1431namespace llvm {
1432template<> struct DenseMapInfo<::MyBitEnum> {
1433  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1434
1435  static inline ::MyBitEnum getEmptyKey() {
1436    return static_cast<::MyBitEnum>(StorageInfo::getEmptyKey());
1437  }
1438
1439  static inline ::MyBitEnum getTombstoneKey() {
1440    return static_cast<::MyBitEnum>(StorageInfo::getTombstoneKey());
1441  }
1442
1443  static unsigned getHashValue(const ::MyBitEnum &val) {
1444    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1445  }
1446
1447  static bool isEqual(const ::MyBitEnum &lhs, const ::MyBitEnum &rhs) {
1448    return lhs == rhs;
1449  }
1450};
1451```
1452
1453```c++
1454std::string stringifyMyBitEnum(MyBitEnum symbol) {
1455  auto val = static_cast<uint32_t>(symbol);
1456  assert(15u == (15u | val) && "invalid bits set in bit enum");
1457  // Special case for all bits unset.
1458  if (val == 0) return "None";
1459  llvm::SmallVector<llvm::StringRef, 2> strs;
1460  if (1u == (1u & val)) { strs.push_back("Bit0"); }
1461  if (2u == (2u & val)) { strs.push_back("Bit1"); }
1462  if (4u == (4u & val)) { strs.push_back("Bit2"); }
1463  if (8u == (8u & val)) { strs.push_back("Bit3"); }
1464
1465  return llvm::join(strs, "|");
1466}
1467
1468llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef str) {
1469  // Special case for all bits unset.
1470  if (str == "None") return MyBitEnum::None;
1471
1472  llvm::SmallVector<llvm::StringRef, 2> symbols;
1473  str.split(symbols, "|");
1474
1475  uint32_t val = 0;
1476  for (auto symbol : symbols) {
1477    auto bit = llvm::StringSwitch<llvm::Optional<uint32_t>>(symbol)
1478      .Case("Bit0", 1)
1479      .Case("Bit1", 2)
1480      .Case("Bit2", 4)
1481      .Case("Bit3", 8)
1482      .Default(llvm::None);
1483    if (bit) { val |= *bit; } else { return llvm::None; }
1484  }
1485  return static_cast<MyBitEnum>(val);
1486}
1487
1488llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t value) {
1489  // Special case for all bits unset.
1490  if (value == 0) return MyBitEnum::None;
1491
1492  if (value & ~(1u | 2u | 4u | 8u)) return llvm::None;
1493  return static_cast<MyBitEnum>(value);
1494}
1495```
1496
1497## Debugging Tips
1498
1499### Run `mlir-tblgen` to see the generated content
1500
1501TableGen syntax sometimes can be obscure; reading the generated content can be a
1502very helpful way to understand and debug issues. To build `mlir-tblgen`, run
1503`cmake --build . --target mlir-tblgen` in your build directory and find the
1504`mlir-tblgen` binary in the `bin/` subdirectory. All the supported generators
1505can be found via `mlir-tblgen --help`. For example, `--gen-op-decls` and
1506`--gen-op-defs` as explained in [Generated C++ code](#generated-c-code).
1507
1508To see the generated code, invoke `mlir-tblgen` with a specific generator by
1509providing include paths via `-I`. For example,
1510
1511```sh
1512# To see op C++ class declaration
1513mlir-tblgen --gen-op-decls -I /path/to/mlir/include /path/to/input/td/file
1514# To see op C++ class definition
1515mlir-tblgen --gen-op-defs -I /path/to/mlir/include /path/to/input/td/file
1516# To see op documentation
1517mlir-tblgen --gen-dialect-doc -I /path/to/mlir/include /path/to/input/td/file
1518
1519# To see op interface C++ class declaration
1520mlir-tblgen --gen-op-interface-decls -I /path/to/mlir/include /path/to/input/td/file
1521# To see op interface C++ class definition
1522mlir-tblgen --gen-op-interface-defs -I /path/to/mlir/include /path/to/input/td/file
1523# To see op interface documentation
1524mlir-tblgen --gen-op-interface-doc -I /path/to/mlir/include /path/to/input/td/file
1525```
1526
1527## Appendix
1528
1529### Requirements and existing mechanisms analysis
1530
1531The op description should be as declarative as possible to allow a wide range of
1532tools to work with them and query methods generated from them. In particular
1533this means specifying traits, constraints and shape inference information in a
1534way that is easily analyzable (e.g., avoid opaque calls to C++ functions where
1535possible).
1536
1537We considered the approaches of several contemporary systems and focused on
1538requirements that were desirable:
1539
1540*   Ops registered using a registry separate from C++ code.
1541    *   Unknown ops are allowed in MLIR, so ops need not be registered. The
1542        ability of the compiler to optimize those ops or graphs containing those
1543        ops is constrained but correct.
1544    *   The current proposal does not include a runtime op description, but it
1545        does not preclude such description, it can be added later.
1546    *   The op registry is essential for generating C++ classes that make
1547        manipulating ops, verifying correct construction etc. in C++ easier by
1548        providing a typed representation and accessors.
1549*   The op registry will be defined in
1550    [TableGen](https://llvm.org/docs/TableGen/index.html) and be used to
1551    generate C++ classes and utility functions
1552    (builder/verifier/parser/printer).
1553    *   TableGen is a modelling specification language used by LLVM's backends
1554        and fits in well with trait-based modelling. This is an implementation
1555        decision and there are alternative ways of doing this. But the
1556        specification language is good for the requirements of modelling the
1557        traits (as seen from usage in LLVM processor backend modelling) and easy
1558        to extend, so a practical choice. If another good option comes up, we
1559        will consider it.
1560*   MLIR allows both defined and undefined ops.
1561    *   Defined ops should have fixed semantics and could have a corresponding
1562        reference implementation defined.
1563    *   Dialects are under full control of the dialect owner and normally live
1564        with the framework of the dialect.
1565*   The op's traits (e.g., commutative) are modelled along with the op in the
1566    registry.
1567*   The op's operand/return type constraints are modelled along with the op in
1568    the registry (see [Shape inference](ShapeInference.md) discussion below),
1569    this allows (e.g.) optimized concise syntax in textual dumps.
1570*   Behavior of the op is documented along with the op with a summary and a
1571    description. The description is written in markdown and extracted for
1572    inclusion in the generated LangRef section of the dialect.
1573*   The generic assembly form of printing and parsing is available as normal,
1574    but a custom parser and printer can either be specified or automatically
1575    generated from an optional string representation showing the mapping of the
1576    "assembly" string to operands/type.
1577    *   Parser-level remappings (e.g., `eq` to enum) will be supported as part
1578        of the parser generation.
1579*   Matching patterns are specified separately from the op description.
1580    *   Contrasted with LLVM there is no "base" set of ops that every backend
1581        needs to be aware of. Instead there are many different dialects and the
1582        transformations/legalizations between these dialects form a graph of
1583        transformations.
1584*   Reference implementation may be provided along with the op definition.
1585
1586    *   The reference implementation may be in terms of either standard ops or
1587        other reference implementations.
1588
1589    TODO: document expectation if the dependent op's definition changes.
1590
1591[TableGen]: https://llvm.org/docs/TableGen/index.html
1592[TableGenProgRef]: https://llvm.org/docs/TableGen/ProgRef.html
1593[TableGenBackend]: https://llvm.org/docs/TableGen/BackEnds.html#introduction
1594[OpBase]: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/OpBase.td
1595[OpDefinitionsGen]: https://github.com/llvm/llvm-project/blob/main/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
1596[EnumsGen]: https://github.com/llvm/llvm-project/blob/main/mlir/tools/mlir-tblgen/EnumsGen.cpp
1597[StringAttr]: Dialects/Builtin.md/#stringattr
1598[IntegerAttr]: Dialects/Builtin.md/#integertype
1599[AttrClasses]: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/Attributes.h
1600