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