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 verifier = [{
568  ...
569}];
570```
571
572Code placed in `verifier` will be called after the auto-generated verification
573code. The order of trait verification excluding those of `verifier` should not
574be relied upon.
575
576### Declarative Assembly Format
577
578The custom assembly form of the operation may be specified in a declarative
579string that matches the operations operands, attributes, etc. With the ability
580to express additional information that needs to be parsed to build the
581operation:
582
583```tablegen
584def CallOp : Std_Op<"call", ...> {
585  let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$args);
586  let results = (outs Variadic<AnyType>);
587
588  let assemblyFormat = [{
589    $callee `(` $args `)` attr-dict `:` functional-type($args, results)
590  }];
591}
592```
593
594The format is comprised of three components:
595
596#### Directives
597
598A directive is a type of builtin function, with an optional set of arguments.
599The available directives are as follows:
600
601*   `attr-dict`
602
603    -   Represents the attribute dictionary of the operation.
604
605*   `attr-dict-with-keyword`
606
607    -   Represents the attribute dictionary of the operation, but prefixes the
608        dictionary with an `attributes` keyword.
609
610*   `custom` < UserDirective > ( Params )
611
612    -   Represents a custom directive implemented by the user in C++.
613    -   See the [Custom Directives](#custom-directives) section below for more
614        details.
615
616*   `functional-type` ( inputs , results )
617
618    -   Formats the `inputs` and `results` arguments as a
619        [function type](Dialects/Builtin.md/#functiontype).
620    -   The constraints on `inputs` and `results` are the same as the `input` of
621        the `type` directive.
622
623*   `operands`
624
625    -   Represents all of the operands of an operation.
626
627*   `ref` ( input )
628
629    -   Represents a reference to the a variable or directive, that must have
630        already been resolved, that may be used as a parameter to a `custom`
631        directive.
632    -   Used to pass previously parsed entities to custom directives.
633    -   The input may be any directive or variable, aside from `functional-type`
634        and `custom`.
635
636*   `regions`
637
638    -   Represents all of the regions of an operation.
639
640*   `results`
641
642    -   Represents all of the results of an operation.
643
644*   `successors`
645
646    -   Represents all of the successors of an operation.
647
648*   `type` ( input )
649
650    -   Represents the type of the given input.
651    -   `input` must be either an operand or result [variable](#variables), the
652        `operands` directive, or the `results` directive.
653
654#### Literals
655
656A literal is either a keyword or punctuation surrounded by \`\`.
657
658The following are the set of valid punctuation:
659
660`:`, `,`, `=`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, `->`, `?`, `+`, `*`
661
662The following are valid whitespace punctuation:
663
664`\n`, ` `
665
666The `\n` literal emits a newline an indents to the start of the operation. An
667example is shown below:
668
669```tablegen
670let assemblyFormat = [{
671  `{` `\n` ` ` ` ` `this_is_on_a_newline` `\n` `}` attr-dict
672}];
673```
674
675```mlir
676%results = my.operation {
677  this_is_on_a_newline
678}
679```
680
681An empty literal \`\` may be used to remove a space that is inserted implicitly
682after certain literal elements, such as `)`/`]`/etc. For example, "`]`" may
683result in an output of `]` it is not the last element in the format. "`]` \`\`"
684would trim the trailing space in this situation.
685
686#### Variables
687
688A variable is an entity that has been registered on the operation itself, i.e.
689an argument(attribute or operand), region, result, successor, etc. In the
690`CallOp` example above, the variables would be `$callee` and `$args`.
691
692Attribute variables are printed with their respective value type, unless that
693value type is buildable. In those cases, the type of the attribute is elided.
694
695#### Custom Directives
696
697The declarative assembly format specification allows for handling a large
698majority of the common cases when formatting an operation. For the operations
699that require or desire specifying parts of the operation in a form not supported
700by the declarative syntax, custom directives may be specified. A custom
701directive essentially allows for users to use C++ for printing and parsing
702subsections of an otherwise declaratively specified format. Looking at the
703specification of a custom directive above:
704
705```
706custom-directive ::= `custom` `<` UserDirective `>` `(` Params `)`
707```
708
709A custom directive has two main parts: The `UserDirective` and the `Params`. A
710custom directive is transformed into a call to a `print*` and a `parse*` method
711when generating the C++ code for the format. The `UserDirective` is an
712identifier used as a suffix to these two calls, i.e., `custom<MyDirective>(...)`
713would result in calls to `parseMyDirective` and `printMyDirective` within the
714parser and printer respectively. `Params` may be any combination of variables
715(i.e. Attribute, Operand, Successor, etc.), type directives, and `attr-dict`.
716The type directives must refer to a variable, but that variable need not also be
717a parameter to the custom directive.
718
719The arguments to the `parse<UserDirective>` method are firstly a reference to
720the `OpAsmParser`(`OpAsmParser &`), and secondly a set of output parameters
721corresponding to the parameters specified in the format. The mapping of
722declarative parameter to `parse` method argument is detailed below:
723
724*   Attribute Variables
725    -   Single: `<Attribute-Storage-Type>(e.g. Attribute) &`
726    -   Optional: `<Attribute-Storage-Type>(e.g. Attribute) &`
727*   Operand Variables
728    -   Single: `OpAsmParser::OperandType &`
729    -   Optional: `Optional<OpAsmParser::OperandType> &`
730    -   Variadic: `SmallVectorImpl<OpAsmParser::OperandType> &`
731    -   VariadicOfVariadic:
732        `SmallVectorImpl<SmallVector<OpAsmParser::OperandType>> &`
733*   Ref Directives
734    -   A reference directive is passed to the parser using the same mapping as
735        the input operand. For example, a single region would be passed as a
736        `Region &`.
737*   Region Variables
738    -   Single: `Region &`
739    -   Variadic: `SmallVectorImpl<std::unique_ptr<Region>> &`
740*   Successor Variables
741    -   Single: `Block *&`
742    -   Variadic: `SmallVectorImpl<Block *> &`
743*   Type Directives
744    -   Single: `Type &`
745    -   Optional: `Type &`
746    -   Variadic: `SmallVectorImpl<Type> &`
747    -   VariadicOfVariadic: `SmallVectorImpl<SmallVector<Type>> &`
748*   `attr-dict` Directive: `NamedAttrList &`
749
750When a variable is optional, the value should only be specified if the variable
751is present. Otherwise, the value should remain `None` or null.
752
753The arguments to the `print<UserDirective>` method is firstly a reference to the
754`OpAsmPrinter`(`OpAsmPrinter &`), second the op (e.g. `FooOp op` which can be
755`Operation *op` alternatively), and finally a set of output parameters
756corresponding to the parameters specified in the format. The mapping of
757declarative parameter to `print` method argument is detailed below:
758
759*   Attribute Variables
760    -   Single: `<Attribute-Storage-Type>(e.g. Attribute)`
761    -   Optional: `<Attribute-Storage-Type>(e.g. Attribute)`
762*   Operand Variables
763    -   Single: `Value`
764    -   Optional: `Value`
765    -   Variadic: `OperandRange`
766    -   VariadicOfVariadic: `OperandRangeRange`
767*   Ref Directives
768    -   A reference directive is passed to the printer using the same mapping as
769        the input operand. For example, a single region would be passed as a
770        `Region &`.
771*   Region Variables
772    -   Single: `Region &`
773    -   Variadic: `MutableArrayRef<Region>`
774*   Successor Variables
775    -   Single: `Block *`
776    -   Variadic: `SuccessorRange`
777*   Type Directives
778    -   Single: `Type`
779    -   Optional: `Type`
780    -   Variadic: `TypeRange`
781    -   VariadicOfVariadic: `TypeRangeRange`
782*   `attr-dict` Directive: `DictionaryAttr`
783
784When a variable is optional, the provided value may be null.
785
786#### Optional Groups
787
788In certain situations operations may have "optional" information, e.g.
789attributes or an empty set of variadic operands. In these situations a section
790of the assembly format can be marked as `optional` based on the presence of this
791information. An optional group is defined as follows:
792
793```
794optional-group: `(` elements `)` (`:` `(` else-elements `)`)? `?`
795```
796
797The `elements` of an optional group have the following requirements:
798
799*   The first element of the group must either be a attribute, literal, operand,
800    or region.
801    -   This is because the first element must be optionally parsable.
802*   Exactly one argument variable or type directive within the group must be
803    marked as the anchor of the group.
804    -   The anchor is the element whose presence controls whether the group
805        should be printed/parsed.
806    -   An element is marked as the anchor by adding a trailing `^`.
807    -   The first element is *not* required to be the anchor of the group.
808    -   When a non-variadic region anchors a group, the detector for printing
809        the group is if the region is empty.
810*   Literals, variables, custom directives, and type directives are the only
811    valid elements within the group.
812    -   Any attribute variable may be used, but only optional attributes can be
813        marked as the anchor.
814    -   Only variadic or optional results and operand arguments and can be used.
815    -   All region variables can be used. When a non-variable length region is
816        used, if the group is not present the region is empty.
817
818An example of an operation with an optional group is `std.return`, which has a
819variadic number of operands.
820
821```tablegen
822def ReturnOp : ... {
823  let arguments = (ins Variadic<AnyType>:$operands);
824
825  // We only print the operands and types if there are a non-zero number
826  // of operands.
827  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
828}
829```
830
831##### Unit Attributes
832
833In MLIR, the [`unit` Attribute](Dialects/Builtin.md/#unitattr) is special in that it
834only has one possible value, i.e. it derives meaning from its existence. When a
835unit attribute is used to anchor an optional group and is not the first element
836of the group, the presence of the unit attribute can be directly correlated with
837the presence of the optional group itself. As such, in these situations the unit
838attribute will not be printed or present in the output and will be automatically
839inferred when parsing by the presence of the optional group itself.
840
841For example, the following operation:
842
843```tablegen
844def FooOp : ... {
845  let arguments = (ins UnitAttr:$is_read_only);
846
847  let assemblyFormat = "attr-dict (`is_read_only` $is_read_only^)?";
848}
849```
850
851would be formatted as such:
852
853```mlir
854// When the unit attribute is present:
855foo.op is_read_only
856
857// When the unit attribute is not present:
858foo.op
859```
860
861##### Optional "else" Group
862
863Optional groups also have support for an "else" group of elements. These are
864elements that are parsed/printed if the `anchor` element of the optional group
865is *not* present. Unlike the main element group, the "else" group has no
866restriction on the first element and none of the elements may act as the
867`anchor` for the optional. An example is shown below:
868
869```tablegen
870def FooOp : ... {
871  let arguments = (ins UnitAttr:$foo);
872
873  let assemblyFormat = "attr-dict (`foo_is_present` $foo^):(`foo_is_absent`)?";
874}
875```
876
877would be formatted as such:
878
879```mlir
880// When the `foo` attribute is present:
881foo.op foo_is_present
882
883// When the `foo` attribute is not present:
884foo.op foo_is_absent
885```
886
887#### Requirements
888
889The format specification has a certain set of requirements that must be adhered
890to:
891
8921.  The output and operation name are never shown as they are fixed and cannot
893    be altered.
8941.  All operands within the operation must appear within the format, either
895    individually or with the `operands` directive.
8961.  All regions within the operation must appear within the format, either
897    individually or with the `regions` directive.
8981.  All successors within the operation must appear within the format, either
899    individually or with the `successors` directive.
9001.  All operand and result types must appear within the format using the various
901    `type` directives, either individually or with the `operands` or `results`
902    directives.
9031.  The `attr-dict` directive must always be present.
9041.  Must not contain overlapping information; e.g. multiple instances of
905    'attr-dict', types, operands, etc.
906    -   Note that `attr-dict` does not overlap with individual attributes. These
907        attributes will simply be elided when printing the attribute dictionary.
908
909##### Type Inference
910
911One requirement of the format is that the types of operands and results must
912always be present. In certain instances, the type of a variable may be deduced
913via type constraints or other information available. In these cases, the type of
914that variable may be elided from the format.
915
916*   Buildable Types
917
918Some type constraints may only have one representation, allowing for them to be
919directly buildable; for example the `I32` or `Index` types. Types in `ODS` may
920mark themselves as buildable by setting the `builderCall` field or inheriting
921from the `BuildableType` class.
922
923*   Trait Equality Constraints
924
925There are many operations that have known type equality constraints registered
926as traits on the operation; for example the true, false, and result values of a
927`select` operation often have the same type. The assembly format may inspect
928these equal constraints to discern the types of missing variables. The currently
929supported traits are: `AllTypesMatch`, `TypesMatchWith`, `SameTypeOperands`, and
930`SameOperandsAndResultType`.
931
932### `hasCanonicalizer`
933
934This boolean field indicate whether canonicalization patterns have been defined
935for this operation. If it is `1`, then `::getCanonicalizationPatterns()` should
936be defined.
937
938### `hasCanonicalizeMethod`
939
940When this boolean field is set to `true`, it indicates that the op implements a
941`canonicalize` method for simple "matchAndRewrite" style canonicalization
942patterns. If `hasCanonicalizer` is 0, then an implementation of
943`::getCanonicalizationPatterns()` is implemented to call this function.
944
945### `hasFolder`
946
947This boolean field indicate whether general folding rules have been defined for
948this operation. If it is `1`, then `::fold()` should be defined.
949
950### Extra declarations
951
952One of the goals of table-driven op definition is to auto-generate as much logic
953and methods needed for each op as possible. With that said, there will always be
954long-tail cases that won't be covered. For such cases, you can use
955`extraClassDeclaration`. Code in `extraClassDeclaration` will be copied
956literally to the generated C++ op class.
957
958Note that `extraClassDeclaration` is a mechanism intended for long-tail cases by
959power users; for not-yet-implemented widely-applicable cases, improving the
960infrastructure is preferable.
961
962### Generated C++ code
963
964[OpDefinitionsGen][OpDefinitionsGen] processes the op definition spec file and
965generates two files containing the corresponding C++ code: one for declarations,
966the other for definitions. The former is generated via the `-gen-op-decls`
967command-line option, while the latter is via the `-gen-op-defs` option.
968
969The definition file contains all the op method definitions, which can be
970included and enabled by defining `GET_OP_CLASSES`. For each operation,
971OpDefinitionsGen generates an operation class and an
972[operand adaptor](#operand-adaptors) class. Besides, it also contains a
973comma-separated list of all defined ops, which can be included and enabled by
974defining `GET_OP_LIST`.
975
976#### Class name and namespaces
977
978For each operation, its generated C++ class name is the symbol `def`ed with
979TableGen with dialect prefix removed. The first `_` serves as the delimiter. For
980example, for `def TF_AddOp`, the C++ class name would be `AddOp`. We remove the
981`TF` prefix because it is for scoping ops; other dialects may as well define
982their own `AddOp`s.
983
984The namespaces of the generated C++ class will come from the dialect's
985`cppNamespace` field. For example, if a dialect's `cppNamespace` is `A::B`, then
986an op of that dialect will be placed in `namespace A { namespace B { ... } }`.
987If a dialect does not specify a `cppNamespace`, we then use the dialect's name
988as the namespace.
989
990This means the qualified name of the generated C++ class does not necessarily
991match exactly with the operation name as explained in
992[Operation name](#operation-name). This is to allow flexible naming to satisfy
993coding style requirements.
994
995#### Operand adaptors
996
997For each operation, we automatically generate an _operand adaptor_. This class
998solves the problem of accessing operands provided as a list of `Value`s without
999using "magic" constants. The operand adaptor takes a reference to an array of
1000`Value` and provides methods with the same names as those in the operation class
1001to access them. For example, for a binary arithmetic operation, it may provide
1002`.lhs()` to access the first operand and `.rhs()` to access the second operand.
1003
1004The operand adaptor class lives in the same namespace as the operation class,
1005and has the name of the operation followed by `Adaptor` as well as an alias
1006`Adaptor` inside the op class.
1007
1008Operand adaptors can be used in function templates that also process operations:
1009
1010```c++
1011template <typename BinaryOpTy>
1012std::pair<Value, Value> zip(BinaryOpTy &&op) {
1013  return std::make_pair(op.lhs(), op.rhs());;
1014}
1015
1016void process(AddOp op, ArrayRef<Value> newOperands) {
1017  zip(op);
1018  zip(Adaptor<AddOp>(newOperands));
1019  /*...*/
1020}
1021```
1022
1023## Constraints
1024
1025Constraint is a core concept in table-driven operation definition: operation
1026verification and graph operation matching are all based on satisfying
1027constraints. So both the operation definition and rewrite rules specification
1028significantly involve writing constraints. We have the `Constraint` class in
1029[`OpBase.td`][OpBase] as the common base class for all constraints.
1030
1031An operation's constraint can cover different range; it may
1032
1033*   Only concern a single attribute (e.g. being a 32-bit integer greater than
1034    5),
1035*   Multiple operands and results (e.g., the 1st result's shape must be the same
1036    as the 1st operand), or
1037*   Intrinsic to the operation itself (e.g., having no side effect).
1038
1039We call them as single-entity constraint, multi-entity constraint, and traits,
1040respectively.
1041
1042### Single-entity constraint
1043
1044Constraints scoped to a single operand, attribute, or result are specified at
1045the entity's declaration place as described in
1046[Operation arguments](#operation-arguments) and
1047[Operation results](#operation-results).
1048
1049To help modelling constraints of common types, a set of `TypeConstraint`s are
1050created; they are the `Type` subclass hierarchy. It includes `F32` for the
1051constraints of being a float, `TensorOf<[F32]>` for the constraints of being a
1052float tensor, and so on.
1053
1054Similarly, a set of `AttrConstraint`s are created for helping modelling
1055constraints of common attribute kinds. They are the `Attr` subclass hierarchy.
1056It includes `F32Attr` for the constraints of being a float attribute,
1057`F32ArrayAttr` for the constraints of being a float array attribute, and so on.
1058
1059### Multi-entity constraint
1060
1061Constraints involving more than one operand/attribute/result are quite common on
1062operations, like the element type and shape relation between operands and
1063results. These constraints should be specified as the `Op` class template
1064parameter as described in
1065[Operation traits and constraints](#operation-traits-and-constraints).
1066
1067Multi-entity constraints are modeled as `PredOpTrait` (a subclass of `OpTrait`)
1068in [`OpBase.td`][OpBase].A bunch of constraint primitives are provided to help
1069specification. See [`OpBase.td`][OpBase] for the complete list.
1070
1071### Trait
1072
1073Traits are intrinsic properties of the operation like having side effect or not,
1074commutative or not, whether is a terminator, etc. These constraints should be
1075specified as the `Op` class template parameter as described in
1076[Operation traits and constraints](#operation-traits-and-constraints).
1077
1078Traits are modeled as `NativeOpTrait` (a subclass of `OpTrait`) in
1079[`OpBase.td`][OpBase]. They are backed and will be translated into the
1080corresponding C++ `mlir::OpTrait` classes.
1081
1082### How to specify new constraint
1083
1084To write a constraint, you need to provide its predicates and give it a
1085descriptive name. Predicates, modeled with the `Pred` class, are the workhorse
1086for composing constraints. The predicate for a constraint is typically built up
1087in a nested manner, using the two categories of predicates:
1088
10891.  `CPred`: the primitive leaf predicate.
10902.  Compound predicate: a predicate composed from child predicates using
1091    predicate combiners (conjunction: `And`, disjunction: `Or`, negation: `Neg`,
1092    substitution: `SubstLeaves`, concatenation: `Concat`).
1093
1094`CPred` is the basis for composing more complex predicates. It is the "atom"
1095predicate from the perspective of TableGen and the "interface" between TableGen
1096and C++. What is inside is already C++ code, which will be treated as opaque
1097strings with special placeholders to be substituted.
1098
1099You can put any C++ code that returns a boolean value inside a `CPred`,
1100including evaluating expressions, calling functions, calling class methods, and
1101so on.
1102
1103To help interaction with the C++ environment, there are a few special
1104placeholders provided to refer to entities in the context where this predicate
1105is used. They serve as "hooks" to the enclosing environment. This includes
1106`$_builder`, `$_op`, and `$_self`:
1107
1108*   `$_builder` will be replaced by a `mlir::Builder` instance so that you can
1109    access common build methods.
1110*   `$_op` will be replaced by the current operation so that you can access
1111    information of the current operation.
1112*   `$_self` will be replaced with the entity this predicate is attached to.
1113    E.g., `BoolAttr` is an attribute constraint that wraps a
1114    `CPred<"$_self.isa<BoolAttr>()">`. Then for `F32Attr:$attr`,`$_self` will be
1115    replaced by `$attr`. For type constraints, it's a little bit special since
1116    we want the constraints on each type definition reads naturally and we want
1117    to attach type constraints directly to an operand/result, `$_self` will be
1118    replaced by the operand/result's type. E.g., for `F32` in `F32:$operand`,
1119    its `$_self` will be expanded as `operand(...).getType()`.
1120
1121TODO: Reconsider the leading symbol for special placeholders. Eventually we want
1122to allow referencing operand/result `$-name`s; such `$-name`s can start with
1123underscore.
1124
1125For example, to write an attribute `attr` is an `IntegerAttr`, in C++ you can
1126just call `attr.isa<IntegerAttr>()`. The code can be wrapped in a `CPred` as
1127`$_self.isa<IntegerAttr>()`, with `$_self` as the special placeholder to be
1128replaced by the current attribute `attr` at expansion time.
1129
1130For more complicated predicates, you can wrap it in a single `CPred`, or you can
1131use predicate combiners to combine them. For example, to write the constraint
1132that an attribute `attr` is a 32-bit or 64-bit integer, you can write it as
1133
1134```tablegen
1135And<[
1136  CPred<"$_self.isa<IntegerAttr>()">,
1137  Or<[
1138    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(32)">,
1139    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(64)">
1140  ]>
1141]>
1142```
1143
1144(Note that the above is just to show with a familiar example how you can use
1145`CPred` and predicate combiners to write complicated predicates. For integer
1146attributes specifically, [`OpBase.td`][OpBase] already defines `I32Attr` and
1147`I64Attr`. So you can actually reuse them to write it as `Or<[I32Attr.predicate,
1148I64Attr.predicate]>`.)
1149
1150TODO: Build up a library of reusable primitive constraints
1151
1152If the predicate is very complex to write with `CPred` together with predicate
1153combiners, you can also write it as a normal C++ function and use the `CPred` as
1154a way to "invoke" the function. For example, to verify an attribute `attr` has
1155some property, you can write a C++ function like
1156
1157```cpp
1158bool HasSomeProperty(Attribute attr) { ... }
1159```
1160
1161and then define the op as:
1162
1163```tablegen
1164def HasSomeProperty : AttrConstraint<CPred<"HasSomeProperty($_self)">,
1165                                     "has some property">;
1166
1167def MyOp : Op<...> {
1168  let arguments = (ins
1169    ...
1170    HasSomeProperty:$attr
1171  );
1172}
1173```
1174
1175As to whether we should define the predicate using a single `CPred` wrapping the
1176whole expression, multiple `CPred`s with predicate combiners, or a single
1177`CPred` "invoking" a function, there are no clear-cut criteria. Defining using
1178`CPred` and predicate combiners is preferable since it exposes more information
1179(instead hiding all the logic behind a C++ function) into the op definition spec
1180so that it can potentially drive more auto-generation cases. But it will require
1181a nice library of common predicates as the building blocks to avoid the
1182duplication, which is being worked on right now.
1183
1184## Attribute Definition
1185
1186An attribute is a compile-time known constant of an operation.
1187
1188ODS provides attribute wrappers over C++ attribute classes. There are a few
1189common C++ [attribute classes][AttrClasses] defined in MLIR's core IR library
1190and one is free to define dialect-specific attribute classes. ODS allows one to
1191use these attributes in TableGen to define operations, potentially with more
1192fine-grained constraints. For example, `StrAttr` directly maps to `StringAttr`;
1193`F32Attr`/`F64Attr` requires the `FloatAttr` to additionally be of a certain
1194bitwidth.
1195
1196ODS attributes are defined as having a storage type (corresponding to a backing
1197`mlir::Attribute` that _stores_ the attribute), a return type (corresponding to
1198the C++ _return_ type of the generated helper getters) as well as a method
1199to convert between the internal storage and the helper method.
1200
1201### Attribute decorators
1202
1203There are a few important attribute adapters/decorators/modifiers that can be
1204applied to ODS attributes to specify common additional properties like
1205optionality, default values, etc.:
1206
1207*   `DefaultValuedAttr`: specifies the
1208    [default value](#attributes-with-default-values) for an attribute.
1209*   `OptionalAttr`: specifies an attribute as [optional](#optional-attributes).
1210*   `Confined`: adapts an attribute with
1211    [further constraints](#confining-attributes).
1212
1213### Enum attributes
1214
1215Some attributes can only take values from a predefined enum, e.g., the
1216comparison kind of a comparison op. To define such attributes, ODS provides
1217several mechanisms: `StrEnumAttr`, `IntEnumAttr`, and `BitEnumAttr`.
1218
1219*   `StrEnumAttr`: each enum case is a string, the attribute is stored as a
1220    [`StringAttr`][StringAttr] in the op.
1221*   `IntEnumAttr`: each enum case is an integer, the attribute is stored as a
1222    [`IntegerAttr`][IntegerAttr] in the op.
1223*   `BitEnumAttr`: each enum case is a bit, the attribute is stored as a
1224    [`IntegerAttr`][IntegerAttr] in the op.
1225
1226All these `*EnumAttr` attributes require fully specifying all of the allowed
1227cases via their corresponding `*EnumAttrCase`. With this, ODS is able to
1228generate additional verification to only accept allowed cases. To facilitate the
1229interaction between `*EnumAttr`s and their C++ consumers, the
1230[`EnumsGen`][EnumsGen] TableGen backend can generate a few common utilities: a
1231C++ enum class, `llvm::DenseMapInfo` for the enum class, conversion functions
1232from/to strings. This is controlled via the `-gen-enum-decls` and
1233`-gen-enum-defs` command-line options of `mlir-tblgen`.
1234
1235For example, given the following `EnumAttr`:
1236
1237```tablegen
1238def Case15: I32EnumAttrCase<"Case15", 15>;
1239def Case20: I32EnumAttrCase<"Case20", 20>;
1240
1241def MyIntEnum: I32EnumAttr<"MyIntEnum", "An example int enum",
1242                           [Case15, Case20]> {
1243  let cppNamespace = "Outer::Inner";
1244  let stringToSymbolFnName = "ConvertToEnum";
1245  let symbolToStringFnName = "ConvertToString";
1246}
1247```
1248
1249The following will be generated via `mlir-tblgen -gen-enum-decls`:
1250
1251```c++
1252namespace Outer {
1253namespace Inner {
1254// An example int enum
1255enum class MyIntEnum : uint32_t {
1256  Case15 = 15,
1257  Case20 = 20,
1258};
1259
1260llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t);
1261llvm::StringRef ConvertToString(MyIntEnum);
1262llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef);
1263inline constexpr unsigned getMaxEnumValForMyIntEnum() {
1264  return 20;
1265}
1266
1267} // namespace Inner
1268} // namespace Outer
1269
1270namespace llvm {
1271template<> struct DenseMapInfo<Outer::Inner::MyIntEnum> {
1272  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1273
1274  static inline Outer::Inner::MyIntEnum getEmptyKey() {
1275    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getEmptyKey());
1276  }
1277
1278  static inline Outer::Inner::MyIntEnum getTombstoneKey() {
1279    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getTombstoneKey());
1280  }
1281
1282  static unsigned getHashValue(const Outer::Inner::MyIntEnum &val) {
1283    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1284  }
1285
1286  static bool isEqual(const Outer::Inner::MyIntEnum &lhs, const Outer::Inner::MyIntEnum &rhs) {
1287    return lhs == rhs;
1288  }
1289};
1290}
1291```
1292
1293The following will be generated via `mlir-tblgen -gen-enum-defs`:
1294
1295```c++
1296namespace Outer {
1297namespace Inner {
1298llvm::StringRef ConvertToString(MyIntEnum val) {
1299  switch (val) {
1300    case MyIntEnum::Case15: return "Case15";
1301    case MyIntEnum::Case20: return "Case20";
1302  }
1303  return "";
1304}
1305
1306llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef str) {
1307  return llvm::StringSwitch<llvm::Optional<MyIntEnum>>(str)
1308      .Case("Case15", MyIntEnum::Case15)
1309      .Case("Case20", MyIntEnum::Case20)
1310      .Default(llvm::None);
1311}
1312llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t value) {
1313  switch (value) {
1314  case 15: return MyIntEnum::Case15;
1315  case 20: return MyIntEnum::Case20;
1316  default: return llvm::None;
1317  }
1318}
1319
1320} // namespace Inner
1321} // namespace Outer
1322```
1323
1324Similarly for the following `BitEnumAttr` definition:
1325
1326```tablegen
1327def None: BitEnumAttrCase<"None", 0x0000>;
1328def Bit1: BitEnumAttrCase<"Bit1", 0x0001>;
1329def Bit2: BitEnumAttrCase<"Bit2", 0x0002>;
1330def Bit3: BitEnumAttrCase<"Bit3", 0x0004>;
1331
1332def MyBitEnum: BitEnumAttr<"MyBitEnum", "An example bit enum",
1333                           [None, Bit1, Bit2, Bit3]>;
1334```
1335
1336We can have:
1337
1338```c++
1339// An example bit enum
1340enum class MyBitEnum : uint32_t {
1341  None = 0,
1342  Bit1 = 1,
1343  Bit2 = 2,
1344  Bit3 = 4,
1345};
1346
1347llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t);
1348std::string stringifyMyBitEnum(MyBitEnum);
1349llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef);
1350inline MyBitEnum operator|(MyBitEnum lhs, MyBitEnum rhs) {
1351  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
1352}
1353inline MyBitEnum operator&(MyBitEnum lhs, MyBitEnum rhs) {
1354  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
1355}
1356inline bool bitEnumContains(MyBitEnum bits, MyBitEnum bit) {
1357  return (static_cast<uint32_t>(bits) & static_cast<uint32_t>(bit)) != 0;
1358}
1359
1360namespace llvm {
1361template<> struct DenseMapInfo<::MyBitEnum> {
1362  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1363
1364  static inline ::MyBitEnum getEmptyKey() {
1365    return static_cast<::MyBitEnum>(StorageInfo::getEmptyKey());
1366  }
1367
1368  static inline ::MyBitEnum getTombstoneKey() {
1369    return static_cast<::MyBitEnum>(StorageInfo::getTombstoneKey());
1370  }
1371
1372  static unsigned getHashValue(const ::MyBitEnum &val) {
1373    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1374  }
1375
1376  static bool isEqual(const ::MyBitEnum &lhs, const ::MyBitEnum &rhs) {
1377    return lhs == rhs;
1378  }
1379};
1380```
1381
1382```c++
1383std::string stringifyMyBitEnum(MyBitEnum symbol) {
1384  auto val = static_cast<uint32_t>(symbol);
1385  // Special case for all bits unset.
1386  if (val == 0) return "None";
1387
1388  llvm::SmallVector<llvm::StringRef, 2> strs;
1389  if (1u & val) { strs.push_back("Bit1"); val &= ~1u; }
1390  if (2u & val) { strs.push_back("Bit2"); val &= ~2u; }
1391  if (4u & val) { strs.push_back("Bit3"); val &= ~4u; }
1392
1393  if (val) return "";
1394  return llvm::join(strs, "|");
1395}
1396
1397llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef str) {
1398  // Special case for all bits unset.
1399  if (str == "None") return MyBitEnum::None;
1400
1401  llvm::SmallVector<llvm::StringRef, 2> symbols;
1402  str.split(symbols, "|");
1403
1404  uint32_t val = 0;
1405  for (auto symbol : symbols) {
1406    auto bit = llvm::StringSwitch<llvm::Optional<uint32_t>>(symbol)
1407      .Case("Bit1", 1)
1408      .Case("Bit2", 2)
1409      .Case("Bit3", 4)
1410      .Default(llvm::None);
1411    if (bit) { val |= *bit; } else { return llvm::None; }
1412  }
1413  return static_cast<MyBitEnum>(val);
1414}
1415
1416llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t value) {
1417  // Special case for all bits unset.
1418  if (value == 0) return MyBitEnum::None;
1419
1420  if (value & ~(1u | 2u | 4u)) return llvm::None;
1421  return static_cast<MyBitEnum>(value);
1422}
1423```
1424
1425## Type Definitions
1426
1427MLIR defines the `TypeDef` class hierarchy to enable generation of data types from
1428their specifications. A type is defined by specializing the `TypeDef` class with
1429concrete contents for all the fields it requires. For example, an integer type
1430could be defined as:
1431
1432```tablegen
1433// All of the types will extend this class.
1434class Test_Type<string name> : TypeDef<Test_Dialect, name> { }
1435
1436// An alternate int type.
1437def IntegerType : Test_Type<"TestInteger"> {
1438  let mnemonic = "int";
1439
1440  let summary = "An integer type with special semantics";
1441
1442  let description = [{
1443    An alternate integer type. This type differentiates itself from the
1444    standard integer type by not having a SignednessSemantics parameter, just
1445    a width.
1446  }];
1447
1448  let parameters = (ins "unsigned":$width);
1449
1450  // We define the printer inline.
1451  let printer = [{
1452    $_printer << "int<" << getImpl()->width << ">";
1453  }];
1454
1455  // The parser is defined here also.
1456  let parser = [{
1457    if ($_parser.parseLess())
1458      return Type();
1459    int width;
1460    if ($_parser.parseInteger(width))
1461      return Type();
1462    if ($_parser.parseGreater())
1463      return Type();
1464    return get($_ctxt, width);
1465  }];
1466}
1467```
1468
1469### Type name
1470
1471The name of the C++ class which gets generated defaults to
1472`<classParamName>Type` (e.g. `TestIntegerType` in the above example). This can
1473be overridden via the `cppClassName` field. The field `mnemonic` is to specify
1474the asm name for parsing. It is optional and not specifying it will imply that
1475no parser or printer methods are attached to this class.
1476
1477### Type documentation
1478
1479The `summary` and `description` fields exist and are to be used the same way as
1480in Operations. Namely, the summary should be a one-liner and `description`
1481should be a longer explanation.
1482
1483### Type parameters
1484
1485The `parameters` field is a list of the type's parameters. If no parameters are
1486specified (the default), this type is considered a singleton type. Parameters
1487are in the `"c++Type":$paramName` format. To use C++ types as parameters which
1488need allocation in the storage constructor, there are two options:
1489
1490-   Set `hasCustomStorageConstructor` to generate the TypeStorage class with a
1491    constructor which is just declared -- no definition -- so you can write it
1492    yourself.
1493-   Use the `TypeParameter` tablegen class instead of the "c++Type" string.
1494
1495### TypeParameter tablegen class
1496
1497This is used to further specify attributes about each of the types parameters.
1498It includes documentation (`summary` and `syntax`), the C++ type to use, a
1499custom allocator to use in the storage constructor method, and a custom
1500comparator to decide if two instances of the parameter type are equal.
1501
1502```tablegen
1503// DO NOT DO THIS!
1504let parameters = (ins "ArrayRef<int>":$dims);
1505```
1506
1507The default storage constructor blindly copies fields by value. It does not know
1508anything about the types. In this case, the ArrayRef<int> requires allocation
1509with `dims = allocator.copyInto(dims)`.
1510
1511You can specify the necessary constructor by specializing the `TypeParameter`
1512tblgen class:
1513
1514```tablegen
1515class ArrayRefIntParam :
1516    TypeParameter<"::llvm::ArrayRef<int>", "Array of ints"> {
1517  let allocator = "$_dst = $_allocator.copyInto($_self);";
1518}
1519
1520...
1521
1522let parameters = (ins ArrayRefIntParam:$dims);
1523```
1524
1525The `allocator` code block has the following substitutions:
1526
1527-   `$_allocator` is the TypeStorageAllocator in which to allocate objects.
1528-   `$_dst` is the variable in which to place the allocated data.
1529
1530The `comparator` code block has the following substitutions:
1531
1532-   `$_lhs` is an instance of the parameter type.
1533-   `$_rhs` is an instance of the parameter type.
1534
1535MLIR includes several specialized classes for common situations:
1536
1537-   `StringRefParameter<descriptionOfParam>` for StringRefs.
1538-   `ArrayRefParameter<arrayOf, descriptionOfParam>` for ArrayRefs of value
1539    types
1540-   `SelfAllocationParameter<descriptionOfParam>` for C++ classes which contain
1541    a method called `allocateInto(StorageAllocator &allocator)` to allocate
1542    itself into `allocator`.
1543-   `ArrayRefOfSelfAllocationParameter<arrayOf, descriptionOfParam>` for arrays
1544    of objects which self-allocate as per the last specialization.
1545
1546If we were to use one of these included specializations:
1547
1548```tablegen
1549let parameters = (ins
1550  ArrayRefParameter<"int", "The dimensions">:$dims
1551);
1552```
1553
1554### Parsing and printing
1555
1556If a mnemonic is specified, the `printer` and `parser` code fields are active.
1557The rules for both are:
1558
1559-   If null, generate just the declaration.
1560-   If non-null and non-empty, use the code in the definition. The `$_printer`
1561    or `$_parser` substitutions are valid and should be used.
1562-   It is an error to have an empty code block.
1563
1564For each dialect, two "dispatch" functions will be created: one for parsing and
1565one for printing. You should add calls to these in your `Dialect::printType` and
1566`Dialect::parseType` methods. They are static functions placed alongside the
1567type class definitions and have the following function signatures:
1568
1569```c++
1570static Type generatedTypeParser(MLIRContext* ctxt, DialectAsmParser& parser, StringRef mnemonic);
1571LogicalResult generatedTypePrinter(Type type, DialectAsmPrinter& printer);
1572```
1573
1574The mnemonic, parser, and printer fields are optional. If they're not defined,
1575the generated code will not include any parsing or printing code and omit the
1576type from the dispatch functions above. In this case, the dialect author is
1577responsible for parsing/printing the types in `Dialect::printType` and
1578`Dialect::parseType`.
1579
1580### Other fields
1581
1582-   If the `genStorageClass` field is set to 1 (the default) a storage class is
1583    generated with member variables corresponding to each of the specified
1584    `parameters`.
1585-   If the `genAccessors` field is 1 (the default) accessor methods will be
1586    generated on the Type class (e.g. `int getWidth() const` in the example
1587    above).
1588-   If the `genVerifyDecl` field is set, a declaration for a method `static
1589    LogicalResult verify(emitErrorFn, parameters...)` is added to the class as
1590    well as a `getChecked(emitErrorFn, parameters...)` method which checks the
1591    result of `verify` before calling `get`.
1592-   The `storageClass` field can be used to set the name of the storage class.
1593-   The `storageNamespace` field is used to set the namespace where the storage
1594    class should sit. Defaults to "detail".
1595-   The `extraClassDeclaration` field is used to include extra code in the class
1596    declaration.
1597
1598### Type builder methods
1599
1600For each type, there are a few builders(`get`/`getChecked`) automatically
1601generated based on the parameters of the type. For example, given the following
1602type definition:
1603
1604```tablegen
1605def MyType : ... {
1606  let parameters = (ins "int":$intParam);
1607}
1608```
1609
1610The following builders are generated:
1611
1612```c++
1613// Type builders are named `get`, and return a new instance of a type for a
1614// given set of parameters.
1615static MyType get(MLIRContext *context, int intParam);
1616
1617// If `genVerifyDecl` is set to 1, the following method is also generated.
1618static MyType getChecked(function_ref<InFlightDiagnostic()> emitError,
1619                         MLIRContext *context, int intParam);
1620```
1621
1622If these autogenerated methods are not desired, such as when they conflict with
1623a custom builder method, a type can set `skipDefaultBuilders` to 1 to signal
1624that they should not be generated.
1625
1626#### Custom type builder methods
1627
1628The default build methods may cover a majority of the simple cases related to
1629type construction, but when they cannot satisfy a type's needs, you can define
1630additional convenience 'get' methods in the `builders` field as follows:
1631
1632```tablegen
1633def MyType : ... {
1634  let parameters = (ins "int":$intParam);
1635
1636  let builders = [
1637    TypeBuilder<(ins "int":$intParam)>,
1638    TypeBuilder<(ins CArg<"int", "0">:$intParam)>,
1639    TypeBuilder<(ins CArg<"int", "0">:$intParam), [{
1640      // Write the body of the `get` builder inline here.
1641      return Base::get($_ctxt, intParam);
1642    }]>,
1643    TypeBuilderWithInferredContext<(ins "Type":$typeParam), [{
1644      // This builder states that it can infer an MLIRContext instance from
1645      // its arguments.
1646      return Base::get(typeParam.getContext(), ...);
1647    }]>,
1648  ];
1649}
1650```
1651
1652The `builders` field is a list of custom builders that are added to the type
1653class. In this example, we provide several different convenience builders that
1654are useful in different scenarios. The `ins` prefix is common to many function
1655declarations in ODS, which use a TableGen [`dag`](#tablegen-syntax). What
1656follows is a comma-separated list of types (quoted string or `CArg`) and names
1657prefixed with the `$` sign. The use of `CArg` allows for providing a default
1658value to that argument. Let's take a look at each of these builders individually
1659
1660The first builder will generate the declaration of a builder method that looks
1661like:
1662
1663```tablegen
1664  let builders = [
1665    TypeBuilder<(ins "int":$intParam)>,
1666  ];
1667```
1668
1669```c++
1670class MyType : /*...*/ {
1671  /*...*/
1672  static MyType get(::mlir::MLIRContext *context, int intParam);
1673};
1674```
1675
1676This builder is identical to the one that will be automatically generated for
1677`MyType`. The `context` parameter is implicitly added by the generator, and is
1678used when building the Type instance (with `Base::get`). The distinction
1679here is that we can provide the implementation of this `get` method. With this
1680style of builder definition only the declaration is generated, the implementor
1681of `MyType` will need to provide a definition of `MyType::get`.
1682
1683The second builder will generate the declaration of a builder method that looks
1684like:
1685
1686```tablegen
1687  let builders = [
1688    TypeBuilder<(ins CArg<"int", "0">:$intParam)>,
1689  ];
1690```
1691
1692```c++
1693class MyType : /*...*/ {
1694  /*...*/
1695  static MyType get(::mlir::MLIRContext *context, int intParam = 0);
1696};
1697```
1698
1699The constraints here are identical to the first builder example except for the
1700fact that `intParam` now has a default value attached.
1701
1702The third builder will generate the declaration of a builder method that looks
1703like:
1704
1705```tablegen
1706  let builders = [
1707    TypeBuilder<(ins CArg<"int", "0">:$intParam), [{
1708      // Write the body of the `get` builder inline here.
1709      return Base::get($_ctxt, intParam);
1710    }]>,
1711  ];
1712```
1713
1714```c++
1715class MyType : /*...*/ {
1716  /*...*/
1717  static MyType get(::mlir::MLIRContext *context, int intParam = 0);
1718};
1719
1720MyType MyType::get(::mlir::MLIRContext *context, int intParam) {
1721  // Write the body of the `get` builder inline here.
1722  return Base::get(context, intParam);
1723}
1724```
1725
1726This is identical to the second builder example. The difference is that now, a
1727definition for the builder method will be generated automatically using the
1728provided code block as the body. When specifying the body inline, `$_ctxt` may
1729be used to access the `MLIRContext *` parameter.
1730
1731The fourth builder will generate the declaration of a builder method that looks
1732like:
1733
1734```tablegen
1735  let builders = [
1736    TypeBuilderWithInferredContext<(ins "Type":$typeParam), [{
1737      // This builder states that it can infer an MLIRContext instance from
1738      // its arguments.
1739      return Base::get(typeParam.getContext(), ...);
1740    }]>,
1741  ];
1742```
1743
1744```c++
1745class MyType : /*...*/ {
1746  /*...*/
1747  static MyType get(Type typeParam);
1748};
1749
1750MyType MyType::get(Type typeParam) {
1751  // This builder states that it can infer an MLIRContext instance from its
1752  // arguments.
1753  return Base::get(typeParam.getContext(), ...);
1754}
1755```
1756
1757In this builder example, the main difference from the third builder example
1758there is that the `MLIRContext` parameter is no longer added. This is because
1759the type builder used `TypeBuilderWithInferredContext` implies that the context
1760parameter is not necessary as it can be inferred from the arguments to the
1761builder.
1762
1763## Debugging Tips
1764
1765### Run `mlir-tblgen` to see the generated content
1766
1767TableGen syntax sometimes can be obscure; reading the generated content can be a
1768very helpful way to understand and debug issues. To build `mlir-tblgen`, run
1769`cmake --build . --target mlir-tblgen` in your build directory and find the
1770`mlir-tblgen` binary in the `bin/` subdirectory. All the supported generators
1771can be found via `mlir-tblgen --help`. For example, `--gen-op-decls` and
1772`--gen-op-defs` as explained in [Generated C++ code](#generated-c-code).
1773
1774To see the generated code, invoke `mlir-tblgen` with a specific generator by
1775providing include paths via `-I`. For example,
1776
1777```sh
1778# To see op C++ class declaration
1779mlir-tblgen --gen-op-decls -I /path/to/mlir/include /path/to/input/td/file
1780# To see op C++ class definition
1781mlir-tblgen --gen-op-defs -I /path/to/mlir/include /path/to/input/td/file
1782# To see op documentation
1783mlir-tblgen --gen-dialect-doc -I /path/to/mlir/include /path/to/input/td/file
1784
1785# To see op interface C++ class declaration
1786mlir-tblgen --gen-op-interface-decls -I /path/to/mlir/include /path/to/input/td/file
1787# To see op interface C++ class definition
1788mlir-tblgen --gen-op-interface-defs -I /path/to/mlir/include /path/to/input/td/file
1789# To see op interface documentation
1790mlir-tblgen --gen-op-interface-doc -I /path/to/mlir/include /path/to/input/td/file
1791```
1792
1793## Appendix
1794
1795### Requirements and existing mechanisms analysis
1796
1797The op description should be as declarative as possible to allow a wide range of
1798tools to work with them and query methods generated from them. In particular
1799this means specifying traits, constraints and shape inference information in a
1800way that is easily analyzable (e.g., avoid opaque calls to C++ functions where
1801possible).
1802
1803We considered the approaches of several contemporary systems and focused on
1804requirements that were desirable:
1805
1806*   Ops registered using a registry separate from C++ code.
1807    *   Unknown ops are allowed in MLIR, so ops need not be registered. The
1808        ability of the compiler to optimize those ops or graphs containing those
1809        ops is constrained but correct.
1810    *   The current proposal does not include a runtime op description, but it
1811        does not preclude such description, it can be added later.
1812    *   The op registry is essential for generating C++ classes that make
1813        manipulating ops, verifying correct construction etc. in C++ easier by
1814        providing a typed representation and accessors.
1815*   The op registry will be defined in
1816    [TableGen](https://llvm.org/docs/TableGen/index.html) and be used to
1817    generate C++ classes and utility functions
1818    (builder/verifier/parser/printer).
1819    *   TableGen is a modelling specification language used by LLVM's backends
1820        and fits in well with trait-based modelling. This is an implementation
1821        decision and there are alternative ways of doing this. But the
1822        specification language is good for the requirements of modelling the
1823        traits (as seen from usage in LLVM processor backend modelling) and easy
1824        to extend, so a practical choice. If another good option comes up, we
1825        will consider it.
1826*   MLIR allows both defined and undefined ops.
1827    *   Defined ops should have fixed semantics and could have a corresponding
1828        reference implementation defined.
1829    *   Dialects are under full control of the dialect owner and normally live
1830        with the framework of the dialect.
1831*   The op's traits (e.g., commutative) are modelled along with the op in the
1832    registry.
1833*   The op's operand/return type constraints are modelled along with the op in
1834    the registry (see [Shape inference](ShapeInference.md) discussion below),
1835    this allows (e.g.) optimized concise syntax in textual dumps.
1836*   Behavior of the op is documented along with the op with a summary and a
1837    description. The description is written in markdown and extracted for
1838    inclusion in the generated LangRef section of the dialect.
1839*   The generic assembly form of printing and parsing is available as normal,
1840    but a custom parser and printer can either be specified or automatically
1841    generated from an optional string representation showing the mapping of the
1842    "assembly" string to operands/type.
1843    *   Parser-level remappings (e.g., `eq` to enum) will be supported as part
1844        of the parser generation.
1845*   Matching patterns are specified separately from the op description.
1846    *   Contrasted with LLVM there is no "base" set of ops that every backend
1847        needs to be aware of. Instead there are many different dialects and the
1848        transformations/legalizations between these dialects form a graph of
1849        transformations.
1850*   Reference implementation may be provided along with the op definition.
1851
1852    *   The reference implementation may be in terms of either standard ops or
1853        other reference implementations.
1854
1855    TODO: document expectation if the dependent op's definition changes.
1856
1857[TableGen]: https://llvm.org/docs/TableGen/index.html
1858[TableGenProgRef]: https://llvm.org/docs/TableGen/ProgRef.html
1859[TableGenBackend]: https://llvm.org/docs/TableGen/BackEnds.html#introduction
1860[OpBase]: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/OpBase.td
1861[OpDefinitionsGen]: https://github.com/llvm/llvm-project/blob/main/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
1862[EnumsGen]: https://github.com/llvm/llvm-project/blob/main/mlir/tools/mlir-tblgen/EnumsGen.cpp
1863[StringAttr]: Dialects/Builtin.md/#stringattr
1864[IntegerAttr]: Dialects/Builtin.md/#integertype
1865[AttrClasses]: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/Attributes.h
1866