1# Operation Definition Specification (ODS)
2
3In addition to specializing the `mlir::Op` C++ template, MLIR also supports
4defining operations in a table-driven manner. This is achieved via
5[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 [Quickstart tutorial to adding MLIR graph
13rewrite](Tutorials/QuickstartRewrites.md) for the latter.
14
15In addition to detailing each mechanism, this manual also tries to capture
16best practices. They are rendered as quoted bullet points.
17
18## Motivation
19
20MLIR allows pluggable dialects, and dialects contain, among others, a list of
21operations. This open and extensible ecosystem leads to the "stringly" type IR
22problem, e.g., repetitive string comparisons during optimization and analysis
23passes, unintuitive accessor methods (e.g., generic/error prone `getOperand(3)`
24vs self-documenting `getStride()`) with more generic return types, verbose and
25generic constructors without default arguments, verbose textual IR dump, and
26so on. Furthermore, operation verification is:
27
281. best case: a central string-to-verification-function map,
291. middle case: duplication of verification across the code base, or
301. worst case: no verification functions.
31
32The fix is to support defining ops in a table-driven manner. Then for each
33dialect, we can have a central place that contains everything you need to know
34about each op, including its constraints, custom assembly form, etc. This
35description is also used to generate helper functions and classes to allow
36building, verification, parsing, printing, analysis, and many more.
37
38## Benefits
39
40Compared to the C++ template, this table-driven approach has several benefits
41including but not limited to:
42
43* **Single source of truth**: We strive to encode all facts regarding an
44  operation into the record, so that readers don't need to jump among code
45  snippets to fully understand an operation.
46* **Removing boilerplate**: We can automatically generate
47  operand/attribute/result getter methods, operation build methods, operation
48  verify methods, and many more utilities from the record. This greatly reduces
49  the boilerplate needed for defining a new op.
50* **Facilitating auto-generation**: The usage of these operation information
51  records are by no means limited to op definition itself. We can use them to
52  drive the auto-generation of many other components, like computation graph
53  serialization.
54
55## TableGen Syntax
56
57We use TableGen as the language for specifying operation information. TableGen
58itself just provides syntax for writing records; the syntax and constructs
59allowed in a TableGen file (typically with filename suffix `.td`) can be found
60[here][TableGenIntro]. The formal language specification can be found
61[here][TableGenRef]. _Roughly_ speaking,
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 introduction][TableGenIntro] 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
133of the `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
164it helps in understanding 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
185   an 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
208constructed from the storage type, while for operands it will be `Value`). Each
209attribute's raw value (e.g., as stored) can also be accessed via generated
210`<name>Attr` getters for use in transformation passes where the more user
211friendly return type 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.
318And similarly, `SameVariadicResultSize` for multiple variadic results in the
319same operation.
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++
342models various traits in the `mlir::OpTrait` namespace.
343
344Both operation traits, [interfaces](#operation-interfaces), and constraints
345involving multiple operands/attributes/results are provided as the second
346template parameter to the `Op` class. They should be deriving from the `OpTrait`
347class. See [Constraints](#constraints) for more information.
348
349### Operation interfaces
350
351[Operation interfaces](Interfaces.md#operation-interfaces) allow
352operations to expose method calls without the
353caller needing to know the exact operation type. Operation interfaces
354defined in C++ can be accessed in the ODS framework via the
355`OpInterfaceTrait` class. Aside from using pre-existing interfaces in
356the C++ API, the ODS framework also provides a simplified mechanism
357for defining such interfaces which removes much of the boilerplate
358necessary.
359
360Providing a definition of the `OpInterface` class will auto-generate the C++
361classes for the interface. An `OpInterface` includes a name, for the C++ class,
362a description, and a list of interface methods.
363
364```tablegen
365def MyInterface : OpInterface<"MyInterface"> {
366  let description = ...;
367  let methods = [...];
368}
369```
370
371There are two types of methods that can be used with an interface,
372`InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the
373same core components, with the distinction that `StaticInterfaceMethod` models a
374static method on the derived operation.
375
376An `InterfaceMethod` is comprised of the following components:
377
378*   Description
379    -   A string description of what this method does and its invariants.
380*   ReturnType
381    -   A string corresponding to the C++ return type of the method.
382*   MethodName
383    -   A string corresponding to the desired name of the method.
384*   Arguments (Optional)
385    -   A dag of strings that correspond to a C++ type and variable name
386        respectively.
387*   MethodBody (Optional)
388    -   An optional explicit implementation of the interface method.
389    -   `ConcreteOp` is an implicitly defined typename that can be used to refer
390        to the type of the derived operation currently being operated on.
391    -   In non-static methods, a variable 'ConcreteOp op' is defined and may be
392        used to refer to an instance of the derived operation.
393*   DefaultImplementation (Optional)
394    -   An optional explicit default implementation of the interface method.
395    -   This method is placed within the `Trait` class that is attached to the
396        operation. As such, this method has the same characteristics as any
397        other [`Trait`](Traits.md) method.
398    -   `ConcreteOp` is an implicitly defined typename that can be used to refer
399        to the type of the derived operation currently being operated on.
400
401ODS also allows generating the declarations for the `InterfaceMethod` of the op
402if one specifies the interface with `DeclareOpInterfaceMethods` (see example
403below).
404
405Examples:
406
407```tablegen
408def MyInterface : OpInterface<"MyInterface"> {
409  let description = [{
410    My interface is very interesting. ...
411  }];
412
413  let methods = [
414    // A simple non-static method with no inputs.
415    InterfaceMethod<"'foo' is a non-static method with no inputs.",
416      "unsigned", "foo"
417    >,
418
419    // A new non-static method accepting an input argument.
420    InterfaceMethod<"/*insert doc here*/",
421      "Value ", "bar", (ins "unsigned":$i)
422    >,
423
424    // Query a static property of the derived operation.
425    StaticInterfaceMethod<"'fooStatic' is a static method with no inputs.",
426      "unsigned", "fooStatic"
427    >,
428
429    // Provide the definition of a static interface method.
430    // Note: `ConcreteOp` corresponds to the derived operation typename.
431    StaticInterfaceMethod<"/*insert doc here*/",
432      "Operation *", "create", (ins "OpBuilder &":$builder, "Location":$loc), [{
433        return builder.create<ConcreteOp>(loc);
434    }]>,
435
436    // Provide a definition of the non-static method.
437    // Note: `op` corresponds to the derived operation variable.
438    InterfaceMethod<"/*insert doc here*/",
439      "unsigned", "getNumInputsAndOutputs", (ins), [{
440        return op.getNumInputs() + op.getNumOutputs();
441    }]>,
442
443    // Provide only a default definition of the method.
444    // Note: `ConcreteOp` corresponds to the derived operation typename.
445    InterfaceMethod<"/*insert doc here*/",
446      "unsigned", "getNumWithDefault", (ins), /*methodBody=*/[{}], [{
447        ConcreteOp op = cast<ConcreteOp>(getOperation());
448        return op.getNumInputs() + op.getNumOutputs();
449    }]>,
450  ];
451}
452
453// Interfaces can optionally be wrapped inside DeclareOpInterfaceMethods. This
454// would result in autogenerating declarations for members `foo`, `bar` and
455// `fooStatic`. Methods with bodies are not declared inside the op
456// declaration but instead handled by the op interface trait directly.
457def OpWithInferTypeInterfaceOp : Op<...
458    [DeclareOpInterfaceMethods<MyInterface>]> { ... }
459
460// Methods that have a default implementation do not have declarations
461// generated. If an operation wishes to override the default behavior, it can
462// explicitly specify the method that it wishes to override. This will force
463// the generation of a declaration for those methods.
464def OpWithOverrideInferTypeInterfaceOp : Op<...
465    [DeclareOpInterfaceMethods<MyInterface, ["getNumWithDefault"]>]> { ... }
466```
467
468A verification method can also be specified on the `OpInterface` by setting
469`verify`. Setting `verify` results in the generated trait having a `verifyTrait`
470method that is applied to all operations implementing the trait.
471
472### Builder methods
473
474For each operation, there are a few builders automatically generated based on
475the arguments and returns types. For example, given the following op definition:
476
477```tablegen
478def MyOp : ... {
479  let arguments = (ins
480    I32:$i32_operand,
481    F32:$f32_operand,
482    ...,
483
484    I32Attr:$i32_attr,
485    F32Attr:$f32_attr,
486    ...
487  );
488
489  let results = (outs
490    I32:$i32_result,
491    F32:$f32_result,
492    ...
493  );
494}
495```
496
497The following builders are generated:
498
499```c++
500// All result-types/operands/attributes have one aggregate parameter.
501static void build(OpBuilder &odsBuilder, OperationState &odsState,
502                  ArrayRef<Type> resultTypes,
503                  ValueRange operands,
504                  ArrayRef<NamedAttribute> attributes);
505
506// Each result-type/operand/attribute has a separate parameter. The parameters
507// for attributes are of mlir::Attribute types.
508static void build(OpBuilder &odsBuilder, OperationState &odsState,
509                  Type i32_result, Type f32_result, ...,
510                  Value i32_operand, Value f32_operand, ...,
511                  IntegerAttr i32_attr, FloatAttr f32_attr, ...);
512
513// Each result-type/operand/attribute has a separate parameter. The parameters
514// for attributes are raw values unwrapped with mlir::Attribute instances.
515// (Note that this builder will not always be generated. See the following
516// explanation for more details.)
517static void build(OpBuilder &odsBuilder, OperationState &odsState,
518                  Type i32_result, Type f32_result, ...,
519                  Value i32_operand, Value f32_operand, ...,
520                  APInt i32_attr, StringRef f32_attr, ...);
521
522// Each operand/attribute has a separate parameter but result type is aggregate.
523static void build(OpBuilder &odsBuilder, OperationState &odsState,
524                  ArrayRef<Type> resultTypes,
525                  Value i32_operand, Value f32_operand, ...,
526                  IntegerAttr i32_attr, FloatAttr f32_attr, ...);
527
528// All operands/attributes have aggregate parameters.
529// Generated if return type can be inferred.
530static void build(OpBuilder &odsBuilder, OperationState &odsState,
531                  ValueRange operands, ArrayRef<NamedAttribute> attributes);
532
533// (And manually specified builders depending on the specific op.)
534```
535
536The first form provides basic uniformity so that we can create ops using the
537same form regardless of the exact op. This is particularly useful for
538implementing declarative pattern rewrites.
539
540The second and third forms are good for use in manually written code given that
541they provide better guarantee via signatures.
542
543The third form will be generated if any of the op's attribute has different
544`Attr.returnType` from `Attr.storageType` and we know how to build an attribute
545from an unwrapped value (i.e., `Attr.constBuilderCall` is defined.)
546Additionally, for the third form, if an attribute appearing later in the
547`arguments` list has a default value, the default value will be supplied in the
548declaration. This works for `BoolAttr`, `StrAttr`, `EnumAttr` for now and the
549list can grow in the future. So if possible, default valued attribute should be
550placed at the end of the `arguments` list to leverage this feature. (This
551behavior is essentially due to C++ function parameter default value placement
552restrictions.) Otherwise, the builder of the third form will still be generated
553but default values for the attributes not at the end of the `arguments` list
554will not be supplied in the builder's signature.
555
556ODS will generate a builder that doesn't require return type specified if
557
558*   Op implements InferTypeOpInterface interface;
559*   All return types are either buildable types or are the same as a given
560    operand (e.g., `AllTypesMatch` constraint between operand and result);
561
562And there may potentially exist other builders depending on the specific op;
563please refer to the
564[generated C++ file](#run-mlir-tblgen-to-see-the-generated-content) for the
565complete list.
566
567#### Custom builder methods
568
569However, if the above cases cannot satisfy all needs, you can define additional
570convenience build methods with `OpBuilder`.
571
572`OpBuilder` is a class that takes the parameter list and the optional `build()`
573method body. They are separated because we need to generate op declaration and
574definition into separate files. The parameter list should _include_ `Builder
575*builder, OperationState &state`. If the `body` is not provided, _only_ the
576builder declaration will be generated; this provides a way to define complicated
577builders entirely in C++ files.
578
579For example, for the following op:
580
581```tablegen
582def MyOp : Op<"my_op", []> {
583  let arguments = (ins F32Attr:$attr);
584
585  let results = (outs);
586}
587```
588
589If we want to define a builder with a default value for the only attribute, we
590can add into `MyOp`:
591
592```tablegen
593def MyOp : ... {
594  ...
595
596  let builders = [
597    OpBuilder<"OpBuilder &builder, OperationState &state, float val = 0.5f", [{
598      state.addAttribute("attr", builder.getF32FloatAttr(val));
599    }]>
600  ];
601}
602```
603
604The generated builder will look like:
605
606```c++
607static void build(OpBuilder &builder, OperationState &state, float val = 0.5f) {
608  state.addAttribute("attr", builder.getF32FloatAttr(val));
609}
610```
611
612### Custom parser and printer methods
613
614Functions to parse and print the operation's custom assembly form.
615
616### Custom verifier code
617
618Verification code will be automatically generated for
619[constraints](#constraints) specified on various entities of the op. To
620perform _additional_ verification, you can use
621
622```tablegen
623let verifier = [{
624  ...
625}];
626```
627
628Code placed in `verifier` will be called after the auto-generated verification
629code. The order of trait verification excluding those of `verifier` should not
630be relied upon.
631
632### Declarative Assembly Format
633
634The custom assembly form of the operation may be specified in a declarative
635string that matches the operations operands, attributes, etc. With the ability
636to express additional information that needs to be parsed to build the
637operation:
638
639```tablegen
640def CallOp : Std_Op<"call", ...> {
641  let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$args);
642  let results = (outs Variadic<AnyType>);
643
644  let assemblyFormat = [{
645    $callee `(` $args `)` attr-dict `:` functional-type($args, results)
646  }];
647}
648```
649
650The format is comprised of three components:
651
652#### Directives
653
654A directive is a type of builtin function, with an optional set of arguments.
655The available directives are as follows:
656
657*   `attr-dict`
658
659    -   Represents the attribute dictionary of the operation.
660
661*   `attr-dict-with-keyword`
662
663    -   Represents the attribute dictionary of the operation, but prefixes the
664        dictionary with an `attributes` keyword.
665
666*   `functional-type` ( inputs , results )
667
668    -   Formats the `inputs` and `results` arguments as a
669        [function type](LangRef.md#function-type).
670    -   The constraints on `inputs` and `results` are the same as the `input` of
671        the `type` directive.
672
673*   `operands`
674
675    -   Represents all of the operands of an operation.
676
677*   `results`
678
679    -   Represents all of the results of an operation.
680
681*   `successors`
682
683    -   Represents all of the successors of an operation.
684
685*   `type` ( input )
686
687    -   Represents the type of the given input.
688    -   `input` must be either an operand or result [variable](#variables), the
689        `operands` directive, or the `results` directive.
690
691#### Literals
692
693A literal is either a keyword or punctuation surrounded by \`\`.
694
695The following are the set of valid punctuation:
696  `:`, `,`, `=`, `<`, `>`, `(`, `)`, `[`, `]`, `->`
697
698#### Variables
699
700A variable is an entity that has been registered on the operation itself, i.e.
701an argument(attribute or operand), result, successor, etc. In the `CallOp`
702example above, the variables would be `$callee` and `$args`.
703
704Attribute variables are printed with their respective value type, unless that
705value type is buildable. In those cases, the type of the attribute is elided.
706
707#### Optional Groups
708
709In certain situations operations may have "optional" information, e.g.
710attributes or an empty set of variadic operands. In these situations a section
711of the assembly format can be marked as `optional` based on the presence of this
712information. An optional group is defined by wrapping a set of elements within
713`()` followed by a `?` and has the following requirements:
714
715*   The first element of the group must either be a literal or an operand.
716    -   This is because the first element must be optionally parsable.
717*   Exactly one argument variable within the group must be marked as the anchor
718    of the group.
719    -   The anchor is the element whose presence controls whether the group
720        should be printed/parsed.
721    -   An element is marked as the anchor by adding a trailing `^`.
722    -   The first element is *not* required to be the anchor of the group.
723*   Literals, variables, and type directives are the only valid elements within
724    the group.
725    -   Any attribute variable may be used, but only optional attributes can be
726        marked as the anchor.
727    -   Only variadic or optional operand arguments can be used.
728    -   The operands to a type directive must be defined within the optional
729        group.
730
731An example of an operation with an optional group is `std.return`, which has a
732variadic number of operands.
733
734```
735def ReturnOp : ... {
736  let arguments = (ins Variadic<AnyType>:$operands);
737
738  // We only print the operands and types if there are a non-zero number
739  // of operands.
740  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
741}
742```
743
744#### Requirements
745
746The format specification has a certain set of requirements that must be adhered
747to:
748
7491. The output and operation name are never shown as they are fixed and cannot be
750   altered.
7511. All operands within the operation must appear within the format, either
752   individually or with the `operands` directive.
7531. All operand and result types must appear within the format using the various
754   `type` directives, either individually or with the `operands` or `results`
755   directives.
7561. The `attr-dict` directive must always be present.
7571. Must not contain overlapping information; e.g. multiple instances of
758   'attr-dict', types, operands, etc.
759   -  Note that `attr-dict` does not overlap with individual attributes. These
760      attributes will simply be elided when printing the attribute dictionary.
761
762##### Type Inference
763
764One requirement of the format is that the types of operands and results must
765always be present. In certain instances, the type of a variable may be deduced
766via type constraints or other information available. In these cases, the type of
767that variable may be elided from the format.
768
769* Buildable Types
770
771Some type constraints may only have one representation, allowing for them to
772be directly buildable; for example the `I32` or `Index` types. Types in `ODS`
773may mark themselves as buildable by setting the `builderCall` field or
774inheriting from the `BuildableType` class.
775
776* Trait Equality Constraints
777
778There are many operations that have known type equality constraints registered
779as traits on the operation; for example the true, false, and result values of a
780`select` operation often have the same type. The assembly format may inspect
781these equal constraints to discern the types of missing variables. The currently
782supported traits are: `AllTypesMatch`, `SameTypeOperands`, and
783`SameOperandsAndResultType`.
784
785### `hasCanonicalizer`
786
787This boolean field indicate whether canonicalization patterns have been defined
788for this operation. If it is `1`, then `::getCanonicalizationPatterns()` should
789be defined.
790
791### `hasFolder`
792
793This boolean field indicate whether general folding rules have been defined
794for this operation. If it is `1`, then `::fold()` should be defined.
795
796### Extra declarations
797
798One of the goals of table-driven op definition is to auto-generate as much logic
799and methods needed for each op as possible. With that said, there will always be
800long-tail cases that won't be covered. For such cases, you can use
801`extraClassDeclaration`. Code in `extraClassDeclaration` will be copied
802literally to the generated C++ op class.
803
804Note that `extraClassDeclaration` is a mechanism intended for long-tail cases
805by power users; for not-yet-implemented widely-applicable cases, improving the
806infrastructure is preferable.
807
808### Generated C++ code
809
810[OpDefinitionsGen][OpDefinitionsGen] processes the op definition spec file and
811generates two files containing the corresponding C++ code: one for declarations,
812the other for definitions. The former is generated via the `-gen-op-decls`
813command-line option, while the latter is via the `-gen-op-defs` option.
814
815The definition file contains all the op method definitions, which can be
816included and enabled by defining `GET_OP_CLASSES`. For each operation,
817OpDefinitionsGen generates an operation class and an
818[operand adaptor](#operand-adaptors) class. Besides, it also contains a
819comma-separated list of all defined ops, which can be included and enabled by
820defining `GET_OP_LIST`.
821
822#### Class name and namespaces
823
824For each operation, its generated C++ class name is the symbol `def`ed with
825TableGen with dialect prefix removed. The first `_` serves as the delimiter.
826For example, for `def TF_AddOp`, the C++ class name would be `AddOp`.
827We remove the `TF` prefix because it is for scoping ops; other dialects
828may as well define their own `AddOp`s.
829
830The namespaces of the generated C++ class will come from the dialect's
831`cppNamespace` field. For example, if a dialect's `cppNamespace` is `A::B`,
832then an op of that dialect will be placed in
833`namespace A { namespace B { ... } }`. If a dialect does not specify a
834`cppNamespace`, we then use the dialect's name as the namespace.
835
836This means the qualified name of the generated C++ class does not necessarily
837match exactly with the operation name as explained in
838[Operation name](#operation-name). This is to allow flexible naming to satisfy
839coding style requirements.
840
841#### Operand adaptors
842
843For each operation, we automatically generate an _operand adaptor_. This class
844solves the problem of accessing operands provided as a list of `Value`s without
845using "magic" constants. The operand adaptor takes a reference to an array of
846`Value` and provides methods with the same names as those in the operation class
847to access them. For example, for a binary arithmetic operation, it may provide
848`.lhs()` to access the first operand and `.rhs()` to access the second operand.
849
850The operand adaptor class lives in the same namespace as the operation class,
851and has the name of the operation followed by `OperandAdaptor`. A template
852declaration `OperandAdaptor<>` is provided to look up the operand adaptor for
853the given operation.
854
855Operand adaptors can be used in function templates that also process operations:
856
857```c++
858template <typename BinaryOpTy>
859std::pair<Value, Value> zip(BinaryOpTy &&op) {
860  return std::make_pair(op.lhs(), op.rhs());;
861}
862
863void process(AddOp op, ArrayRef<Value> newOperands) {
864  zip(op);
865  zip(OperandAdaptor<AddOp>(newOperands));
866  /*...*/
867}
868```
869
870## Constraints
871
872Constraint is a core concept in table-driven operation definition: operation
873verification and graph operation matching are all based on satisfying
874constraints. So both the operation definition and rewrite rules specification
875significantly involve writing constraints. We have the `Constraint` class in
876[`OpBase.td`][OpBase] has the common base class for all constraints.
877
878An operation's constraint can cover different range; it may
879
880* Only concern a single attribute (e.g. being a 32-bit integer greater than 5),
881* Multiple operands and results (e.g., the 1st result's shape must be the same
882  as the 1st operand), or
883* Intrinsic to the operation itself (e.g., having no side effect).
884
885We call them as single-entity constraint, multi-entity constraint, and traits,
886respectively.
887
888### Single-entity constraint
889
890Constraints scoped to a single operand, attribute, or result are specified at
891the entity's declaration place as described in
892[Operation arguments](#operation-arguments) and
893[Operation results](#operation-results).
894
895To help modelling constraints of common types, a set of `TypeConstraint`s are
896created; they are the `Type` subclass hierarchy. It includes `F32` for the
897constraints of being a float, `TensorOf<[F32]>` for the constraints of being
898a float tensor, and so on.
899
900Similarly, a set of `AttrConstraint`s are created for helping modelling
901constraints of common attribute kinds. They are the `Attr` subclass hierarchy.
902It includes `F32Attr` for the constraints of being a float attribute,
903`F32ArrayAttr` for the constraints of being a float array attribute, and so on.
904
905### Multi-entity constraint
906
907Constraints involving more than one operand/attribute/result are quite common
908on operations, like the element type and shape relation between operands and
909results. These constraints should be specified as the `Op` class template
910parameter as described in
911[Operation traits and constraints](#operation-traits-and-constraints).
912
913Multi-entity constraints are modeled as `PredOpTrait` (a subclass of `OpTrait`)
914in [`OpBase.td`][OpBase].A bunch of constraint primitives are provided to help
915specification. See [`OpBase.td`][OpBase] for the complete list.
916
917### Trait
918
919Traits are intrinsic properties of the operation like having side effect or not,
920commutative or not, whether is a terminator, etc. These constraints should be
921specified as the `Op` class template parameter as described in
922[Operation traits and constraints](#operation-traits-and-constraints).
923
924Traits are modeled as `NativeOpTrait` (a subclass of `OpTrait`) in
925[`OpBase.td`][OpBase]. They are backed and will be translated into the
926corresponding C++ `mlir::OpTrait` classes.
927
928### How to specify new constraint
929
930To write a constraint, you need to provide its predicates and give it a
931descriptive name. Predicates, modeled with the `Pred` class, are the workhorse
932for composing constraints. The predicate for a constraint is typically built up
933in a nested manner, using the two categories of predicates:
934
9351.  `CPred`: the primitive leaf predicate.
9362.  Compound predicate: a predicate composed from child predicates using
937    predicate combiners (conjunction: `And`, disjunction: `Or`, negation: `Neg`,
938    substitution: `SubstLeaves`, concatenation: `Concat`).
939
940`CPred` is the basis for composing more complex predicates. It is the "atom"
941predicate from the perspective of TableGen and the "interface" between
942TableGen and C++. What is inside is already C++ code, which will be treated
943as opaque strings with special placeholders to be substituted.
944
945You can put any C++ code that returns a boolean value inside a `CPred`,
946including evaluating expressions, calling functions, calling class methods,
947and so on.
948
949To help interaction with the C++ environment, there are a few special
950placeholders provided to refer to entities in the context where this predicate
951is used. They serve as "hooks" to the enclosing environment.  This includes
952`$_builder`, `$_op`, and `$_self`:
953
954* `$_builder` will be replaced by a `mlir::Builder` instance so that you can
955  access common build methods.
956* `$_op` will be replaced by the current operation so that you can access
957  information of the current operation.
958* `$_self` will be replaced with the entity this predicate is attached to.
959  E.g., `BoolAttr` is an attribute constraint that wraps a
960  `CPred<"$_self.isa<BoolAttr>()">`. Then for `F32:$attr`,`$_self` will be
961  replaced by `$attr`. For type constraints, it's a little bit special since
962  we want the constraints on each type definition reads naturally and we want
963  to attach type constraints directly to an operand/result, `$_self` will be
964  replaced by the operand/result's type. E.g., for `F32` in `F32:$operand`, its
965  `$_self` will be expanded as `getOperand(...).getType()`.
966
967TODO(b/130663252): Reconsider the leading symbol for special placeholders.
968Eventually we want to allow referencing operand/result $-names; such $-names
969can start with underscore.
970
971For example, to write an attribute `attr` is an `IntegerAttr`, in C++ you can
972just call `attr.isa<IntegerAttr>()`. The code can be wrapped in a `CPred` as
973`$_self.isa<IntegerAttr>()`, with `$_self` as the special placeholder to be
974replaced by the current attribute `attr` at expansion time.
975
976For more complicated predicates, you can wrap it in a single `CPred`, or you
977can use predicate combiners to combine them. For example, to write the
978constraint that an attribute `attr` is a 32-bit or 64-bit integer, you can
979write it as
980
981```tablegen
982And<[
983  CPred<"$_self.isa<IntegerAttr>()">,
984  Or<[
985    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(32)">,
986    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(64)">
987  ]>
988]>
989```
990
991(Note that the above is just to show with a familiar example how you can use
992`CPred` and predicate combiners to write complicated predicates. For integer
993attributes specifically, [`OpBase.td`][OpBase] already defines `I32Attr` and
994`I64Attr`. So you can actually reuse them to write it as `Or<[I32Attr.predicate,
995I64Attr.predicate]>`.)
996
997TODO: Build up a library of reusable primitive constraints
998
999If the predicate is very complex to write with `CPred` together with predicate
1000combiners, you can also write it as a normal C++ function and use the `CPred`
1001as a way to "invoke" the function. For example, to verify an attribute `attr`
1002has some property, you can write a C++ function like
1003
1004```cpp
1005bool HasSomeProperty(Attribute attr) { ... }
1006```
1007
1008and then define the op as:
1009
1010```tablegen
1011def HasSomeProperty : AttrConstraint<CPred<"HasSomeProperty($_self)">,
1012                                     "has some property">;
1013
1014def MyOp : Op<...> {
1015  let arguments = (ins
1016    ...
1017    HasSomeProperty:$attr
1018  );
1019}
1020```
1021
1022As to whether we should define the predicate using a single `CPred` wrapping
1023the whole expression, multiple `CPred`s with predicate combiners, or a single
1024`CPred` "invoking" a function, there are no clear-cut criteria. Defining using
1025`CPred` and predicate combiners is preferable since it exposes more information
1026(instead hiding all the logic behind a C++ function) into the op definition spec
1027so that it can potentially drive more auto-generation cases. But it will
1028require a nice library of common predicates as the building blocks to avoid the
1029duplication, which is being worked on right now.
1030
1031## Attribute Definition
1032
1033An attribute is a compile-time known constant of an operation.
1034
1035ODS provides attribute wrappers over C++ attribute classes. There are a few
1036common C++ [attribute classes][AttrClasses] defined in MLIR's core IR library
1037and one is free to define dialect-specific attribute classes. ODS allows one
1038to use these attributes in TableGen to define operations, potentially with
1039more fine-grained constraints. For example, `StrAttr` directly maps to
1040`StringAttr`; `F32Attr`/`F64Attr` requires the `FloatAttr` to additionally
1041be of a certain bitwidth.
1042
1043ODS attributes are defined as having a storage type (corresponding to a backing
1044`mlir::Attribute` that _stores_ the attribute), a return type (corresponding to
1045the C++ _return_ type of the generated of the helper getters) as well as method
1046to convert between the internal storage and the helper method.
1047
1048### Attribute decorators
1049
1050There are a few important attribute adapters/decorators/modifers that can be
1051applied to ODS attributes to specify common additional properties like
1052optionality, default values, etc.:
1053
1054*   `DefaultValuedAttr`: specifies the
1055    [default value](#attributes-with-default-values) for an attribute.
1056*   `OptionalAttr`: specifies an attribute as [optional](#optional-attributes).
1057*   `Confined`: adapts an attribute with
1058    [further constraints](#confining-attributes).
1059
1060### Enum attributes
1061
1062Some attributes can only take values from a predefined enum, e.g., the
1063comparison kind of a comparison op. To define such attributes, ODS provides
1064several mechanisms: `StrEnumAttr`, `IntEnumAttr`, and `BitEnumAttr`.
1065
1066*   `StrEnumAttr`: each enum case is a string, the attribute is stored as a
1067    [`StringAttr`][StringAttr] in the op.
1068*   `IntEnumAttr`: each enum case is an integer, the attribute is stored as a
1069    [`IntegerAttr`][IntegerAttr] in the op.
1070*   `BitEnumAttr`: each enum case is a bit, the attribute is stored as a
1071    [`IntegerAttr`][IntegerAttr] in the op.
1072
1073All these `*EnumAttr` attributes require fully specifying all of the allowed
1074cases via their corresponding `*EnumAttrCase`. With this, ODS is able to
1075generate additional verification to only accept allowed cases. To facilitate the
1076interaction between `*EnumAttr`s and their C++ consumers, the
1077[`EnumsGen`][EnumsGen] TableGen backend can generate a few common utilities: a
1078C++ enum class, `llvm::DenseMapInfo` for the enum class, conversion functions
1079from/to strings. This is controlled via the `-gen-enum-decls` and
1080`-gen-enum-defs` command-line options of `mlir-tblgen`.
1081
1082For example, given the following `EnumAttr`:
1083
1084```tablegen
1085def Case15: I32EnumAttrCase<"Case15", 15>;
1086def Case20: I32EnumAttrCase<"Case20", 20>;
1087
1088def MyIntEnum: I32EnumAttr<"MyIntEnum", "An example int enum",
1089                           [Case15, Case20]> {
1090  let cppNamespace = "Outer::Inner";
1091  let stringToSymbolFnName = "ConvertToEnum";
1092  let symbolToStringFnName = "ConvertToString";
1093}
1094```
1095
1096The following will be generated via `mlir-tblgen -gen-enum-decls`:
1097
1098```c++
1099namespace Outer {
1100namespace Inner {
1101// An example int enum
1102enum class MyIntEnum : uint32_t {
1103  Case15 = 15,
1104  Case20 = 20,
1105};
1106
1107llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t);
1108llvm::StringRef ConvertToString(MyIntEnum);
1109llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef);
1110inline constexpr unsigned getMaxEnumValForMyIntEnum() {
1111  return 20;
1112}
1113
1114} // namespace Inner
1115} // namespace Outer
1116
1117namespace llvm {
1118template<> struct DenseMapInfo<Outer::Inner::MyIntEnum> {
1119  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1120
1121  static inline Outer::Inner::MyIntEnum getEmptyKey() {
1122    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getEmptyKey());
1123  }
1124
1125  static inline Outer::Inner::MyIntEnum getTombstoneKey() {
1126    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getTombstoneKey());
1127  }
1128
1129  static unsigned getHashValue(const Outer::Inner::MyIntEnum &val) {
1130    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1131  }
1132
1133  static bool isEqual(const Outer::Inner::MyIntEnum &lhs, const Outer::Inner::MyIntEnum &rhs) {
1134    return lhs == rhs;
1135  }
1136};
1137}
1138```
1139
1140The following will be generated via `mlir-tblgen -gen-enum-defs`:
1141
1142```c++
1143namespace Outer {
1144namespace Inner {
1145llvm::StringRef ConvertToString(MyIntEnum val) {
1146  switch (val) {
1147    case MyIntEnum::Case15: return "Case15";
1148    case MyIntEnum::Case20: return "Case20";
1149  }
1150  return "";
1151}
1152
1153llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef str) {
1154  return llvm::StringSwitch<llvm::Optional<MyIntEnum>>(str)
1155      .Case("Case15", MyIntEnum::Case15)
1156      .Case("Case20", MyIntEnum::Case20)
1157      .Default(llvm::None);
1158}
1159llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t value) {
1160  switch (value) {
1161  case 15: return MyIntEnum::Case15;
1162  case 20: return MyIntEnum::Case20;
1163  default: return llvm::None;
1164  }
1165}
1166
1167} // namespace Inner
1168} // namespace Outer
1169```
1170
1171Similarly for the following `BitEnumAttr` definition:
1172
1173```tablegen
1174def None: BitEnumAttrCase<"None", 0x0000>;
1175def Bit1: BitEnumAttrCase<"Bit1", 0x0001>;
1176def Bit2: BitEnumAttrCase<"Bit2", 0x0002>;
1177def Bit3: BitEnumAttrCase<"Bit3", 0x0004>;
1178
1179def MyBitEnum: BitEnumAttr<"MyBitEnum", "An example bit enum",
1180                           [None, Bit1, Bit2, Bit3]>;
1181```
1182
1183We can have:
1184
1185```c++
1186// An example bit enum
1187enum class MyBitEnum : uint32_t {
1188  None = 0,
1189  Bit1 = 1,
1190  Bit2 = 2,
1191  Bit3 = 4,
1192};
1193
1194llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t);
1195std::string stringifyMyBitEnum(MyBitEnum);
1196llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef);
1197inline MyBitEnum operator|(MyBitEnum lhs, MyBitEnum rhs) {
1198  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
1199}
1200inline MyBitEnum operator&(MyBitEnum lhs, MyBitEnum rhs) {
1201  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
1202}
1203inline bool bitEnumContains(MyBitEnum bits, MyBitEnum bit) {
1204  return (static_cast<uint32_t>(bits) & static_cast<uint32_t>(bit)) != 0;
1205}
1206
1207namespace llvm {
1208template<> struct DenseMapInfo<::MyBitEnum> {
1209  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1210
1211  static inline ::MyBitEnum getEmptyKey() {
1212    return static_cast<::MyBitEnum>(StorageInfo::getEmptyKey());
1213  }
1214
1215  static inline ::MyBitEnum getTombstoneKey() {
1216    return static_cast<::MyBitEnum>(StorageInfo::getTombstoneKey());
1217  }
1218
1219  static unsigned getHashValue(const ::MyBitEnum &val) {
1220    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1221  }
1222
1223  static bool isEqual(const ::MyBitEnum &lhs, const ::MyBitEnum &rhs) {
1224    return lhs == rhs;
1225  }
1226};
1227```
1228
1229```c++
1230std::string stringifyMyBitEnum(MyBitEnum symbol) {
1231  auto val = static_cast<uint32_t>(symbol);
1232  // Special case for all bits unset.
1233  if (val == 0) return "None";
1234
1235  llvm::SmallVector<llvm::StringRef, 2> strs;
1236  if (1u & val) { strs.push_back("Bit1"); val &= ~1u; }
1237  if (2u & val) { strs.push_back("Bit2"); val &= ~2u; }
1238  if (4u & val) { strs.push_back("Bit3"); val &= ~4u; }
1239
1240  if (val) return "";
1241  return llvm::join(strs, "|");
1242}
1243
1244llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef str) {
1245  // Special case for all bits unset.
1246  if (str == "None") return MyBitEnum::None;
1247
1248  llvm::SmallVector<llvm::StringRef, 2> symbols;
1249  str.split(symbols, "|");
1250
1251  uint32_t val = 0;
1252  for (auto symbol : symbols) {
1253    auto bit = llvm::StringSwitch<llvm::Optional<uint32_t>>(symbol)
1254      .Case("Bit1", 1)
1255      .Case("Bit2", 2)
1256      .Case("Bit3", 4)
1257      .Default(llvm::None);
1258    if (bit) { val |= *bit; } else { return llvm::None; }
1259  }
1260  return static_cast<MyBitEnum>(val);
1261}
1262
1263llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t value) {
1264  // Special case for all bits unset.
1265  if (value == 0) return MyBitEnum::None;
1266
1267  if (value & ~(1u | 2u | 4u)) return llvm::None;
1268  return static_cast<MyBitEnum>(value);
1269}
1270```
1271
1272## Debugging Tips
1273
1274### Run `mlir-tblgen` to see the generated content
1275
1276TableGen syntax sometimes can be obscure; reading the generated content can be
1277a very helpful way to understand and debug issues. To build `mlir-tblgen`, run
1278`cmake --build . --target mlir-tblgen` in your build directory and find the
1279`mlir-tblgen` binary in the `bin/` subdirectory. All the supported generators
1280can be found via `mlir-tblgen --help`. For example, `--gen-op-decls` and
1281`--gen-op-defs` as explained in [Generated C++ code](#generated-c++-code).
1282
1283To see the generated code, invoke `mlir-tblgen` with a specific generator by
1284providing include paths via `-I`. For example,
1285
1286```sh
1287# To see op C++ class declaration
1288mlir-tblgen --gen-op-decls -I /path/to/mlir/include /path/to/input/td/file
1289# To see op C++ class definition
1290mlir-tblgen --gen-op-defs -I /path/to/mlir/include /path/to/input/td/file
1291# To see op documentation
1292mlir-tblgen --gen-dialect-doc -I /path/to/mlir/include /path/to/input/td/file
1293
1294# To see op interface C++ class declaration
1295mlir-tblgen --gen-op-interface-decls -I /path/to/mlir/include /path/to/input/td/file
1296# To see op interface C++ class definition
1297mlir-tblgen --gen-op-interface-defs -I /path/to/mlir/include /path/to/input/td/file
1298# To see op interface documentation
1299mlir-tblgen --gen-op-interface-doc -I /path/to/mlir/include /path/to/input/td/file
1300```
1301
1302## Appendix
1303
1304### Requirements and existing mechanisms analysis
1305
1306The op description should as declarative as possible to allow a wide range of
1307tools to work with them and query methods generated from them. In particular
1308this means specifying traits, constraints and shape inference information in
1309a way that is easily analyzable (e.g., avoid opaque calls to C++ functions where
1310possible).
1311
1312We considered the approaches of several contemporary systems and focused on
1313requirements that were desirable:
1314
1315*   Ops registered using a registry separate from C++ code.
1316    *   Unknown ops are allowed in MLIR, so ops need not be registered. The
1317        ability of the compiler to optimize those ops or graphs containing those
1318        ops is constrained but correct.
1319    *   The current proposal does not include a runtime op description, but it
1320        does not preclude such description, it can be added later.
1321    *   The op registry is essential for generating C++ classes that make
1322        manipulating ops, verifying correct construction etc. in C++ easier by
1323        providing a typed representation and accessors.
1324*   The op registry will be defined in
1325    [TableGen](https://llvm.org/docs/TableGen/index.html) and be used to
1326    generate C++ classes and utility functions
1327    (builder/verifier/parser/printer).
1328    *   TableGen is a modelling specification language used by LLVM's backends
1329        and fits in well with trait-based modelling. This is an implementation
1330        decision and there are alternative ways of doing this. But the
1331        specification language is good for the requirements of modelling the
1332        traits (as seen from usage in LLVM processor backend modelling) and easy
1333        to extend, so a practical choice. If another good option comes up, we
1334        will consider it.
1335*   MLIR allows both defined and undefined ops.
1336    *   Defined ops should have fixed semantics and could have a corresponding
1337        reference implementation defined using, for example, EDSC.
1338    *   Dialects are under full control of the dialect owner and normally live
1339        with the framework of the dialect.
1340*   The op's traits (e.g., commutative) are modelled along with the op in the
1341    registry.
1342*   The op's operand/return type constraints are modelled along with the op in
1343    the registry (see [Shape inference](ShapeInference.md) discussion below),
1344    this allows (e.g.) optimized concise syntax in textual dumps.
1345*   Behavior of the op is documented along with the op with a summary and a
1346    description. The description is written in markdown and extracted for
1347    inclusion in the generated LangRef section of the dialect.
1348*   The generic assembly form of printing and parsing is available as normal,
1349    but a custom parser and printer can either be specified or automatically
1350    generated from an optional string representation showing the mapping of the
1351    "assembly" string to operands/type.
1352    *   Parser-level remappings (e.g., `eq` to enum) will be supported as part
1353        of the parser generation.
1354*   Matching patterns are specified separately from the op description.
1355    *   Contrasted with LLVM there is no "base" set of ops that every backend
1356        needs to be aware of. Instead there are many different dialects and the
1357        transformations/legalizations between these dialects form a graph of
1358        transformations.
1359*   Reference implementation may be provided along with the op definition.
1360
1361    *   The reference implementation may be in terms of either standard ops or
1362        other reference implementations.
1363
1364    TODO: document expectation if the dependent op's definition changes.
1365
1366[TableGen]: https://llvm.org/docs/TableGen/index.html
1367[TableGenIntro]: https://llvm.org/docs/TableGen/LangIntro.html
1368[TableGenRef]: https://llvm.org/docs/TableGen/LangRef.html
1369[TableGenBackend]: https://llvm.org/docs/TableGen/BackEnds.html#introduction
1370[OpBase]: https://github.com/llvm/llvm-project/blob/master/mlir/include/mlir/IR/OpBase.td
1371[OpDefinitionsGen]: https://github.com/llvm/llvm-project/blob/master/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
1372[EnumsGen]: https://github.com/llvm/llvm-project/blob/master/mlir/tools/mlir-tblgen/EnumsGen.cpp
1373[StringAttr]: LangRef.md#string-attribute
1374[IntegerAttr]: LangRef.md#integer-attribute
1375[AttrClasses]: https://github.com/llvm/llvm-project/blob/master/mlir/include/mlir/IR/Attributes.h
1376