• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
8an equivalent `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][TableGenProgRef].
61
62*   TableGen `class` is similar to C++ class; it can be templated and
63    subclassed.
64*   TableGen `def` is similar to C++ object; it can be declared by specializing
65    a TableGen `class` (e.g., `def MyDef : MyClass<...>;`) or completely
66    independently (e.g., `def MyDef;`). It cannot be further templated or
67    subclassed.
68*   TableGen `dag` is a dedicated type for directed acyclic graph of elements. A
69    `dag` has one operator and zero or more arguments. Its syntax is `(operator
70    arg0, arg1, argN)`. The operator can be any TableGen `def`; an argument can
71    be anything, including `dag` itself. We can have names attached to both the
72    operator and the arguments like `(MyOp:$op_name MyArg:$arg_name)`.
73
74Please see the [language reference][TableGenProgRef] to learn about all the
75types and expressions supported by TableGen.
76
77## Operation Definition
78
79MLIR defines several common constructs to help operation definition and provide
80their semantics via a special [TableGen backend][TableGenBackend]:
81[`OpDefinitionsGen`][OpDefinitionsGen]. These constructs are defined in
82[`OpBase.td`][OpBase]. The main ones are
83
84*   The `Op` class: It is the main construct for defining operations. All facts
85    regarding the operation are specified when specializing this class, with the
86    help of the following constructs.
87*   The `Dialect` class: Operations belonging to one logical group are placed in
88    the same dialect. The `Dialect` class contains dialect-level information.
89*   The `OpTrait` class hierarchy: They are used to specify special properties
90    and constraints of the operation, including whether the operation has side
91    effect or whether its output has the same shape as the input.
92*   The `ins`/`outs` marker: These are two special makers builtin to the
93    `OpDefinitionsGen` backend. They lead the definitions of operands/attributes
94    and results respectively.
95*   The `TypeConstraint` class hierarchy: They are used to specify the
96    constraints over operands or results. A notable subclass hierarchy is
97    `Type`, which stands for constraints for common C++ types.
98*   The `AttrConstraint` class hierarchy: They are used to specify the
99    constraints over attributes. A notable subclass hierarchy is `Attr`, which
100    stands for constraints for attributes whose values are of common types.
101
102An operation is defined by specializing the `Op` class with concrete contents
103for all the fields it requires. For example, `tf.AvgPool` is defined as
104
105```tablegen
106def TF_AvgPoolOp : TF_Op<"AvgPool", [NoSideEffect]> {
107  let summary = "Performs average pooling on the input.";
108
109  let description = [{
110Each entry in `output` is the mean of the corresponding size `ksize`
111window in `value`.
112  }];
113
114  let arguments = (ins
115    TF_FpTensor:$value,
116
117    Confined<I64ArrayAttr, [ArrayMinCount<4>]>:$ksize,
118    Confined<I64ArrayAttr, [ArrayMinCount<4>]>:$strides,
119    TF_AnyStrAttrOf<["SAME", "VALID"]>:$padding,
120    DefaultValuedAttr<TF_ConvertDataFormatAttr, "NHWC">:$data_format
121  );
122
123  let results = (outs
124    TF_FpTensor:$output
125  );
126
127  TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>;
128}
129```
130
131In the following we describe all the fields needed. Please see the definition
132of the `Op` class for the complete list of fields supported.
133
134### Operation name
135
136The operation name is a unique identifier of the operation within MLIR, e.g.,
137`tf.Add` for addition operation in the TensorFlow dialect. This is the
138equivalent of the mnemonic in assembly language. It is used for parsing and
139printing in the textual format. It is also used for pattern matching in graph
140rewrites.
141
142The full operation name is composed of the dialect name and the op name, with
143the former provided via the dialect and the latter provided as the second
144template parameter to the `Op` class.
145
146### Operation documentation
147
148This includes both a one-line `summary` and a longer human-readable
149`description`. They will be used to drive automatic generation of dialect
150documentation. They need to be provided in the operation's definition body:
151
152```tablegen
153let summary = "...";
154
155let description = [{
156...
157}];
158```
159
160`description` should be written in Markdown syntax.
161
162Placing the documentation at the beginning is recommended since
163it helps in understanding the operation.
164
165> * Place documentation at the beginning of the operation definition
166> * The summary should be short and concise. It should be a one-liner without
167>   trailing punctuation. Put expanded explanation in description.
168
169### Operation arguments
170
171There are two kinds of arguments: operands and attributes. Operands are runtime
172values produced by other ops; while attributes are compile-time known constant
173values, including two categories:
174
1751. Natural attributes: these attributes affect the behavior of the operations
176   (e.g., padding for convolution);
1771. Derived attributes: these attributes are not needed to define the operation
178   but are instead derived from information of the operation. E.g., the output
179   shape of type. This is mostly used for convenience interface generation or
180   interaction with other frameworks/translation.
181
182   All derived attributes should be materializable as an Attribute. That is,
183   even though they are not materialized, it should be possible to store as
184   an attribute.
185
186Both operands and attributes are specified inside the `dag`-typed `arguments`,
187led by `ins`:
188
189```tablegen
190let arguments = (ins
191  <type-constraint>:$<operand-name>,
192  ...
193  <attr-constraint>:$<attr-name>,
194  ...
195);
196```
197
198Here `<type-constraint>` is a TableGen `def` from the `TypeConstraint` class
199hierarchy. Similarly, `<attr-constraint>` is a TableGen `def` from the
200`AttrConstraint` class hierarchy. See [Constraints](#constraints) for more
201information.
202
203There is no requirements on the relative order of operands and attributes; they
204can mix freely. The relative order of operands themselves matters. From each
205named argument a named getter will be generated that returns the argument with
206the return type (in the case of attributes the return type will be
207constructed from the storage type, while for operands it will be `Value`). Each
208attribute's raw value (e.g., as stored) can also be accessed via generated
209`<name>Attr` getters for use in transformation passes where the more user
210friendly return type is less suitable.
211
212All the arguments should be named to 1) provide documentation, 2) drive
213auto-generation of getter methods, 3) provide a handle to reference for other
214places like constraints.
215
216#### Variadic operands
217
218To declare a variadic operand, wrap the `TypeConstraint` for the operand with
219`Variadic<...>`.
220
221Normally operations have no variadic operands or just one variadic operand. For
222the latter case, it is easy to deduce which dynamic operands are for the static
223variadic operand definition. Though, if an operation has more than one variable
224length operands (either optional or variadic), it would be impossible to
225attribute dynamic operands to the corresponding static variadic operand
226definitions without further information from the operation. Therefore, either
227the `SameVariadicOperandSize` or `AttrSizedOperandSegments` trait is needed to
228indicate that all variable length operands have the same number of dynamic
229values.
230
231#### Optional operands
232
233To declare an optional operand, wrap the `TypeConstraint` for the operand with
234`Optional<...>`.
235
236Normally operations have no optional operands or just one optional operand. For
237the latter case, it is easy to deduce which dynamic operands are for the static
238operand definition. Though, if an operation has more than one variable length
239operands (either optional or variadic), it would be impossible to attribute
240dynamic operands to the corresponding static variadic operand definitions
241without further information from the operation. Therefore, either the
242`SameVariadicOperandSize` or `AttrSizedOperandSegments` trait is needed to
243indicate that all variable length operands have the same number of dynamic
244values.
245
246#### Optional attributes
247
248To declare an optional attribute, wrap the `AttrConstraint` for the attribute
249with `OptionalAttr<...>`.
250
251#### Attributes with default values
252
253To declare an attribute with a default value, wrap the `AttrConstraint` for the
254attribute with `DefaultValuedAttr<..., "...">`.
255
256The second parameter to `DefaultValuedAttr` should be a string containing the
257C++ default value. For example, a float default value should be specified as
258like `"0.5f"`, and an integer array default value should be specified as like
259`"{1, 2, 3}"`.
260
261#### Confining attributes
262
263`Confined` is provided as a general mechanism to help modelling further
264constraints on attributes beyond the ones brought by value types. You can use
265`Confined` to compose complex constraints out of more primitive ones. For
266example, a 32-bit integer attribute whose minimum value must be 10 can be
267expressed as `Confined<I32Attr, [IntMinValue<10>]>`.
268
269Right now, the following primitive constraints are supported:
270
271*   `IntMinValue<N>`: Specifying an integer attribute to be greater than or
272    equal to `N`
273*   `IntMaxValue<N>`: Specifying an integer attribute to be less than or equal
274    to `N`
275*   `ArrayMinCount<N>`: Specifying an array attribute to have at least `N`
276    elements
277*   `IntArrayNthElemEq<I, N>`: Specifying an integer array attribute's `I`-th
278    element to be equal to `N`
279*   `IntArrayNthElemMinValue<I, N>`: Specifying an integer array attribute's
280    `I`-th element to be greater than or equal to `N`
281
282TODO: Design and implement more primitive constraints
283
284### Operation regions
285
286The regions of an operation are specified inside of the `dag`-typed `regions`,
287led by `region`:
288
289```tablegen
290let regions = (region
291  <region-constraint>:$<region-name>,
292  ...
293);
294```
295
296#### Variadic regions
297
298Similar to the `Variadic` class used for variadic operands and results,
299`VariadicRegion<...>` can be used for regions. Variadic regions can currently
300only be specified as the last region in the regions list.
301
302### Operation results
303
304Similar to operands, results are specified inside the `dag`-typed `results`, led
305by `outs`:
306
307```tablegen
308let results = (outs
309  <type-constraint>:$<result-name>,
310  ...
311);
312```
313
314#### Variadic results
315
316Similar to variadic operands, `Variadic<...>` can also be used for results.
317And similarly, `SameVariadicResultSize` for multiple variadic results in the
318same operation.
319
320### Operation successors
321
322For terminator operations, the successors are specified inside of the
323`dag`-typed `successors`, led by `successor`:
324
325```tablegen
326let successors = (successor
327  <successor-constraint>:$<successor-name>,
328  ...
329);
330```
331
332#### Variadic successors
333
334Similar to the `Variadic` class used for variadic operands and results,
335`VariadicSuccessor<...>` can be used for successors. Variadic successors can
336currently only be specified as the last successor in the successor list.
337
338### Operation traits and constraints
339
340Traits are operation properties that affect syntax or semantics. MLIR C++
341models various traits in the `mlir::OpTrait` namespace.
342
343Both operation traits, [interfaces](#operation-interfaces), and constraints
344involving multiple operands/attributes/results are provided as the second
345template parameter to the `Op` class. They should be deriving from the `OpTrait`
346class. See [Constraints](#constraints) for more information.
347
348### Interfaces
349
350[Interfaces](Interfaces.md#attribute-operation-type-interfaces) allow for
351attributes, operations, and types to expose method calls without the caller
352needing to know the derived type. Operation interfaces defined in C++ can be
353accessed in the ODS framework via the `OpInterfaceTrait` class. Aside from using
354pre-existing interfaces in the C++ API, the ODS framework also provides a
355simplified mechanism for defining such interfaces which removes much of the
356boilerplate necessary.
357
358Providing a definition of the `AttrInterface`, `OpInterface`, or `TypeInterface`
359class will auto-generate the C++ classes for the interface. An interface
360includes a name, for the C++ class, a description, and a list of interface
361methods.
362
363```tablegen
364def MyInterface : OpInterface<"MyInterface"> {
365  let description = ...;
366  let methods = [...];
367}
368```
369
370There are two types of methods that can be used with an interface,
371`InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the
372same core components, with the distinction that `StaticInterfaceMethod` models a
373static method on the derived operation.
374
375An `InterfaceMethod` is comprised of the following components:
376
377*   Description
378    -   A string description of what this method does and its invariants.
379*   ReturnType
380    -   A string corresponding to the C++ return type of the method.
381*   MethodName
382    -   A string corresponding to the desired name of the method.
383*   Arguments (Optional)
384    -   A dag of strings that correspond to a C++ type and variable name
385        respectively.
386*   MethodBody (Optional)
387    -   An optional explicit implementation of the interface method.
388    -   `ConcreteOp` is an implicitly defined typename that can be used to refer
389        to the type of the derived operation currently being operated on.
390    -   In non-static methods, a variable 'ConcreteOp op' is defined and may be
391        used to refer to an instance of the derived operation.
392*   DefaultImplementation (Optional)
393    -   An optional explicit default implementation of the interface method.
394    -   This method is placed within the `Trait` class that is attached to the
395        operation. As such, this method has the same characteristics as any
396        other [`Trait`](Traits.md) method.
397    -   `ConcreteOp` is an implicitly defined typename that can be used to refer
398        to the type of the derived operation currently being operated on.
399
400ODS also allows generating the declarations for the `InterfaceMethod` of the op
401if one specifies the interface with `DeclareOpInterfaceMethods` (see example
402below).
403
404Examples:
405
406```tablegen
407def MyInterface : OpInterface<"MyInterface"> {
408  let description = [{
409    My interface is very interesting. ...
410  }];
411
412  let methods = [
413    // A simple non-static method with no inputs.
414    InterfaceMethod<"'foo' is a non-static method with no inputs.",
415      "unsigned", "foo"
416    >,
417
418    // A new non-static method accepting an input argument.
419    InterfaceMethod<"/*insert doc here*/",
420      "Value ", "bar", (ins "unsigned":$i)
421    >,
422
423    // Query a static property of the derived operation.
424    StaticInterfaceMethod<"'fooStatic' is a static method with no inputs.",
425      "unsigned", "fooStatic"
426    >,
427
428    // Provide the definition of a static interface method.
429    // Note: `ConcreteOp` corresponds to the derived operation typename.
430    StaticInterfaceMethod<"/*insert doc here*/",
431      "Operation *", "create", (ins "OpBuilder &":$builder, "Location":$loc), [{
432        return builder.create<ConcreteOp>(loc);
433    }]>,
434
435    // Provide a definition of the non-static method.
436    // Note: `op` corresponds to the derived operation variable.
437    InterfaceMethod<"/*insert doc here*/",
438      "unsigned", "getNumInputsAndOutputs", (ins), [{
439        return op.getNumInputs() + op.getNumOutputs();
440    }]>,
441
442    // Provide only a default definition of the method.
443    // Note: `ConcreteOp` corresponds to the derived operation typename.
444    InterfaceMethod<"/*insert doc here*/",
445      "unsigned", "getNumWithDefault", (ins), /*methodBody=*/[{}], [{
446        ConcreteOp op = cast<ConcreteOp>(this->getOperation());
447        return op.getNumInputs() + op.getNumOutputs();
448    }]>,
449  ];
450}
451
452// Operation interfaces can optionally be wrapped inside
453// DeclareOpInterfaceMethods. This would result in autogenerating declarations
454// for members `foo`, `bar` and `fooStatic`. Methods with bodies are not
455// declared inside the op declaration but instead handled by the op interface
456// 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
468Operation interfaces may also provide a verification method on `OpInterface` by
469setting `verify`. Setting `verify` results in the generated trait having a
470`verifyTrait` method 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 in the `builders` field as follows.
571
572```tablegen
573def MyOp : Op<"my_op", []> {
574  let arguments = (ins F32Attr:$attr);
575
576  let builders = [
577    OpBuilderDAG<(ins "float":$val)>
578  ];
579}
580```
581
582The `builders` field is a list of custom builders that are added to the Op
583class. In this example, we provide a convenience builder that takes a floating
584point value instead of an attribute. The `ins` prefix is common to many function
585declarations in ODS, which use a TableGen [`dag`](#tablegen-syntax). What
586follows is a comma-separated list of types (quoted string) and names prefixed
587with the `$` sign. This will generate the declaration of a builder method that
588looks like:
589
590```c++
591class MyOp : /*...*/ {
592  /*...*/
593  static void build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
594                    float val);
595};
596```
597
598Note that the method has two additional leading arguments. These arguments are
599useful to construct the operation. In particular, the method must populate
600`state` with attributes, operands, regions and result types of the operation to
601be constructed. `builder` can be used to construct any IR objects that belong to
602the Op, such as types or nested operations. Since the type and name are
603generated as is in the C++ code, they should be valid C++ constructs for a type
604(in the namespace of the Op) and an identifier (e.g., `class` is not a valid
605identifier).
606
607Implementations of the builder can be provided directly in ODS, using TableGen
608code block as follows.
609
610```tablegen
611def MyOp : Op<"my_op", []> {
612  let arguments = (ins F32Attr:$attr);
613
614  let builders = [
615    OpBuilderDAG<(ins "float":$val), [{
616      $_state.addAttribute("attr", $_builder.getF32FloatAttr(val));
617    }]>
618  ];
619}
620```
621
622The equivalents of `builder` and `state` arguments are available as `$_builder`
623and `$_state` special variables. The named arguments listed in the `ins` part
624are available directly, e.g. `val`. The body of the builder will be generated by
625substituting special variables and should otherwise be valid C++. While there is
626no limitation on the code size, we encourage one to define only short builders
627inline in ODS and put definitions of longer builders in C++ files.
628
629Finally, if some arguments need a default value, they can be defined using
630`CArg` to wrap the type and this value as follows.
631
632```tablegen
633def MyOp : Op<"my_op", []> {
634  let arguments = (ins F32Attr:$attr);
635
636  let builders = [
637    OpBuilderDAG<(ins CArg<"float", "0.5f">:$val), [{
638      $_state.addAttribute("attr", $_builder.getF32FloatAttr(val));
639    }]>
640  ];
641}
642```
643
644The generated code will use default value in the declaration, but not in the
645definition, as required by C++.
646
647```c++
648/// Header file.
649class MyOp : /*...*/ {
650  /*...*/
651  static void build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
652                    float val = 0.5f);
653};
654
655/// Source file.
656MyOp::build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
657            float val) {
658  state.addAttribute("attr", builder.getF32FloatAttr(val));
659}
660```
661
662**Deprecated:** `OpBuilder` class allows one to specify the custom builder
663signature as a raw string, without separating parameters into different `dag`
664arguments. It also supports leading parameters of `OpBuilder &` and
665`OperationState &` types, which will be used instead of the autogenerated ones
666if present.
667
668### Custom parser and printer methods
669
670Functions to parse and print the operation's custom assembly form.
671
672### Custom verifier code
673
674Verification code will be automatically generated for
675[constraints](#constraints) specified on various entities of the op. To
676perform _additional_ verification, you can use
677
678```tablegen
679let verifier = [{
680  ...
681}];
682```
683
684Code placed in `verifier` will be called after the auto-generated verification
685code. The order of trait verification excluding those of `verifier` should not
686be relied upon.
687
688### Declarative Assembly Format
689
690The custom assembly form of the operation may be specified in a declarative
691string that matches the operations operands, attributes, etc. With the ability
692to express additional information that needs to be parsed to build the
693operation:
694
695```tablegen
696def CallOp : Std_Op<"call", ...> {
697  let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$args);
698  let results = (outs Variadic<AnyType>);
699
700  let assemblyFormat = [{
701    $callee `(` $args `)` attr-dict `:` functional-type($args, results)
702  }];
703}
704```
705
706The format is comprised of three components:
707
708#### Directives
709
710A directive is a type of builtin function, with an optional set of arguments.
711The available directives are as follows:
712
713*   `attr-dict`
714
715    -   Represents the attribute dictionary of the operation.
716
717*   `attr-dict-with-keyword`
718
719    -   Represents the attribute dictionary of the operation, but prefixes the
720        dictionary with an `attributes` keyword.
721
722*   `custom` < UserDirective > ( Params )
723
724    -   Represents a custom directive implemented by the user in C++.
725    -   See the [Custom Directives](#custom-directives) section below for more
726        details.
727
728*   `functional-type` ( inputs , results )
729
730    -   Formats the `inputs` and `results` arguments as a
731        [function type](LangRef.md#function-type).
732    -   The constraints on `inputs` and `results` are the same as the `input` of
733        the `type` directive.
734
735*   `operands`
736
737    -   Represents all of the operands of an operation.
738
739*   `regions`
740
741    -   Represents all of the regions of an operation.
742
743*   `results`
744
745    -   Represents all of the results of an operation.
746
747*   `successors`
748
749    -   Represents all of the successors of an operation.
750
751*   `type` ( input )
752
753    -   Represents the type of the given input.
754    -   `input` must be either an operand or result [variable](#variables), the
755        `operands` directive, or the `results` directive.
756
757*   `type_ref` ( input )
758
759    -   Represents a reference to the type of the given input that must have
760        already been resolved.
761    -   `input` must be either an operand or result [variable](#variables), the
762        `operands` directive, or the `results` directive.
763    -   Used to pass previously parsed types to custom directives.
764
765#### Literals
766
767A literal is either a keyword or punctuation surrounded by \`\`.
768
769The following are the set of valid punctuation:
770
771`:`, `,`, `=`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, `->`, `?`, `+`, `*`
772
773#### Variables
774
775A variable is an entity that has been registered on the operation itself, i.e.
776an argument(attribute or operand), region, result, successor, etc. In the
777`CallOp` example above, the variables would be `$callee` and `$args`.
778
779Attribute variables are printed with their respective value type, unless that
780value type is buildable. In those cases, the type of the attribute is elided.
781
782#### Custom Directives
783
784The declarative assembly format specification allows for handling a large
785majority of the common cases when formatting an operation. For the operations
786that require or desire specifying parts of the operation in a form not supported
787by the declarative syntax, custom directives may be specified. A custom
788directive essentially allows for users to use C++ for printing and parsing
789subsections of an otherwise declaratively specified format. Looking at the
790specification of a custom directive above:
791
792```
793custom-directive ::= `custom` `<` UserDirective `>` `(` Params `)`
794```
795
796A custom directive has two main parts: The `UserDirective` and the `Params`. A
797custom directive is transformed into a call to a `print*` and a `parse*` method
798when generating the C++ code for the format. The `UserDirective` is an
799identifier used as a suffix to these two calls, i.e., `custom<MyDirective>(...)`
800would result in calls to `parseMyDirective` and `printMyDirective` within the
801parser and printer respectively. `Params` may be any combination of variables
802(i.e. Attribute, Operand, Successor, etc.), type directives, and `attr-dict`.
803The type directives must refer to a variable, but that variable need not also
804be a parameter to the custom directive.
805
806The arguments to the `parse<UserDirective>` method are firstly a reference to
807the `OpAsmParser`(`OpAsmParser &`), and secondly a set of output parameters
808corresponding to the parameters specified in the format. The mapping of
809declarative parameter to `parse` method argument is detailed below:
810
811*   Attribute Variables
812    -   Single: `<Attribute-Storage-Type>(e.g. Attribute) &`
813    -   Optional: `<Attribute-Storage-Type>(e.g. Attribute) &`
814*   Operand Variables
815    -   Single: `OpAsmParser::OperandType &`
816    -   Optional: `Optional<OpAsmParser::OperandType> &`
817    -   Variadic: `SmallVectorImpl<OpAsmParser::OperandType> &`
818*   Region Variables
819    -   Single: `Region &`
820    -   Variadic: `SmallVectorImpl<std::unique_ptr<Region>> &`
821*   Successor Variables
822    -   Single: `Block *&`
823    -   Variadic: `SmallVectorImpl<Block *> &`
824*   Type Directives
825    -   Single: `Type &`
826    -   Optional: `Type &`
827    -   Variadic: `SmallVectorImpl<Type> &`
828*   TypeRef Directives
829    -   Single: `Type`
830    -   Optional: `Type`
831    -   Variadic: `const SmallVectorImpl<Type> &`
832*   `attr-dict` Directive: `NamedAttrList &`
833
834When a variable is optional, the value should only be specified if the variable
835is present. Otherwise, the value should remain `None` or null.
836
837The arguments to the `print<UserDirective>` method is firstly a reference to
838the `OpAsmPrinter`(`OpAsmPrinter &`), second the op (e.g. `FooOp op` which
839can be `Operation *op` alternatively), and finally a set of output parameters
840corresponding to the parameters specified in the format. The mapping of
841declarative parameter to `print` method argument is detailed below:
842
843*   Attribute Variables
844    -   Single: `<Attribute-Storage-Type>(e.g. Attribute)`
845    -   Optional: `<Attribute-Storage-Type>(e.g. Attribute)`
846*   Operand Variables
847    -   Single: `Value`
848    -   Optional: `Value`
849    -   Variadic: `OperandRange`
850*   Region Variables
851    -   Single: `Region &`
852    -   Variadic: `MutableArrayRef<Region>`
853*   Successor Variables
854    -   Single: `Block *`
855    -   Variadic: `SuccessorRange`
856*   Type Directives
857    -   Single: `Type`
858    -   Optional: `Type`
859    -   Variadic: `TypeRange`
860*   TypeRef Directives
861    -   Single: `Type`
862    -   Optional: `Type`
863    -   Variadic: `TypeRange`
864*   `attr-dict` Directive: `const MutableDictionaryAttr&`
865
866When a variable is optional, the provided value may be null.
867
868#### Optional Groups
869
870In certain situations operations may have "optional" information, e.g.
871attributes or an empty set of variadic operands. In these situations a section
872of the assembly format can be marked as `optional` based on the presence of this
873information. An optional group is defined by wrapping a set of elements within
874`()` followed by a `?` and has the following requirements:
875
876*   The first element of the group must either be a attribute, literal, operand,
877    or region.
878    -   This is because the first element must be optionally parsable.
879*   Exactly one argument variable within the group must be marked as the anchor
880    of the group.
881    -   The anchor is the element whose presence controls whether the group
882        should be printed/parsed.
883    -   An element is marked as the anchor by adding a trailing `^`.
884    -   The first element is *not* required to be the anchor of the group.
885    -   When a non-variadic region anchors a group, the detector for printing
886        the group is if the region is empty.
887*   Literals, variables, custom directives, and type directives are the only
888    valid elements within the group.
889    -   Any attribute variable may be used, but only optional attributes can be
890        marked as the anchor.
891    -   Only variadic or optional operand arguments can be used.
892    -   All region variables can be used. When a non-variable length region is
893        used, if the group is not present the region is empty.
894    -   The operands to a type directive must be defined within the optional
895        group.
896
897An example of an operation with an optional group is `std.return`, which has a
898variadic number of operands.
899
900```tablegen
901def ReturnOp : ... {
902  let arguments = (ins Variadic<AnyType>:$operands);
903
904  // We only print the operands and types if there are a non-zero number
905  // of operands.
906  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
907}
908```
909
910##### Unit Attributes
911
912In MLIR, the [`unit` Attribute](LangRef.md#unit-attribute) is special in that it
913only has one possible value, i.e. it derives meaning from its existence. When a
914unit attribute is used to anchor an optional group and is not the first element
915of the group, the presence of the unit attribute can be directly correlated with
916the presence of the optional group itself. As such, in these situations the unit
917attribute will not be printed or present in the output and will be automatically
918inferred when parsing by the presence of the optional group itself.
919
920For example, the following operation:
921
922```tablegen
923def FooOp : ... {
924  let arguments = (ins UnitAttr:$is_read_only);
925
926  let assemblyFormat = "attr-dict (`is_read_only` $is_read_only^)?";
927}
928```
929
930would be formatted as such:
931
932```mlir
933// When the unit attribute is present:
934foo.op is_read_only
935
936// When the unit attribute is not present:
937foo.op
938```
939
940#### Requirements
941
942The format specification has a certain set of requirements that must be adhered
943to:
944
9451.  The output and operation name are never shown as they are fixed and cannot
946    be altered.
9471.  All operands within the operation must appear within the format, either
948    individually or with the `operands` directive.
9491.  All regions within the operation must appear within the format, either
950    individually or with the `regions` directive.
9511.  All successors within the operation must appear within the format, either
952    individually or with the `successors` directive.
9531.  All operand and result types must appear within the format using the various
954    `type` directives, either individually or with the `operands` or `results`
955    directives.
9561.  The `attr-dict` directive must always be present.
9571.  Must not contain overlapping information; e.g. multiple instances of
958    'attr-dict', types, operands, etc.
959    -   Note that `attr-dict` does not overlap with individual attributes. These
960        attributes will simply be elided when printing the attribute dictionary.
961
962##### Type Inference
963
964One requirement of the format is that the types of operands and results must
965always be present. In certain instances, the type of a variable may be deduced
966via type constraints or other information available. In these cases, the type of
967that variable may be elided from the format.
968
969* Buildable Types
970
971Some type constraints may only have one representation, allowing for them to
972be directly buildable; for example the `I32` or `Index` types. Types in `ODS`
973may mark themselves as buildable by setting the `builderCall` field or
974inheriting from the `BuildableType` class.
975
976* Trait Equality Constraints
977
978There are many operations that have known type equality constraints registered
979as traits on the operation; for example the true, false, and result values of a
980`select` operation often have the same type. The assembly format may inspect
981these equal constraints to discern the types of missing variables. The currently
982supported traits are: `AllTypesMatch`, `TypesMatchWith`, `SameTypeOperands`,
983and `SameOperandsAndResultType`.
984
985### `hasCanonicalizer`
986
987This boolean field indicate whether canonicalization patterns have been defined
988for this operation. If it is `1`, then `::getCanonicalizationPatterns()` should
989be defined.
990
991### `hasFolder`
992
993This boolean field indicate whether general folding rules have been defined
994for this operation. If it is `1`, then `::fold()` should be defined.
995
996### Extra declarations
997
998One of the goals of table-driven op definition is to auto-generate as much logic
999and methods needed for each op as possible. With that said, there will always be
1000long-tail cases that won't be covered. For such cases, you can use
1001`extraClassDeclaration`. Code in `extraClassDeclaration` will be copied
1002literally to the generated C++ op class.
1003
1004Note that `extraClassDeclaration` is a mechanism intended for long-tail cases
1005by power users; for not-yet-implemented widely-applicable cases, improving the
1006infrastructure is preferable.
1007
1008### Generated C++ code
1009
1010[OpDefinitionsGen][OpDefinitionsGen] processes the op definition spec file and
1011generates two files containing the corresponding C++ code: one for declarations,
1012the other for definitions. The former is generated via the `-gen-op-decls`
1013command-line option, while the latter is via the `-gen-op-defs` option.
1014
1015The definition file contains all the op method definitions, which can be
1016included and enabled by defining `GET_OP_CLASSES`. For each operation,
1017OpDefinitionsGen generates an operation class and an
1018[operand adaptor](#operand-adaptors) class. Besides, it also contains a
1019comma-separated list of all defined ops, which can be included and enabled by
1020defining `GET_OP_LIST`.
1021
1022#### Class name and namespaces
1023
1024For each operation, its generated C++ class name is the symbol `def`ed with
1025TableGen with dialect prefix removed. The first `_` serves as the delimiter.
1026For example, for `def TF_AddOp`, the C++ class name would be `AddOp`.
1027We remove the `TF` prefix because it is for scoping ops; other dialects
1028may as well define their own `AddOp`s.
1029
1030The namespaces of the generated C++ class will come from the dialect's
1031`cppNamespace` field. For example, if a dialect's `cppNamespace` is `A::B`,
1032then an op of that dialect will be placed in
1033`namespace A { namespace B { ... } }`. If a dialect does not specify a
1034`cppNamespace`, we then use the dialect's name as the namespace.
1035
1036This means the qualified name of the generated C++ class does not necessarily
1037match exactly with the operation name as explained in
1038[Operation name](#operation-name). This is to allow flexible naming to satisfy
1039coding style requirements.
1040
1041#### Operand adaptors
1042
1043For each operation, we automatically generate an _operand adaptor_. This class
1044solves the problem of accessing operands provided as a list of `Value`s without
1045using "magic" constants. The operand adaptor takes a reference to an array of
1046`Value` and provides methods with the same names as those in the operation class
1047to access them. For example, for a binary arithmetic operation, it may provide
1048`.lhs()` to access the first operand and `.rhs()` to access the second operand.
1049
1050The operand adaptor class lives in the same namespace as the operation class,
1051and has the name of the operation followed by `Adaptor` as well as an alias
1052`Adaptor` inside the op class.
1053
1054Operand adaptors can be used in function templates that also process operations:
1055
1056```c++
1057template <typename BinaryOpTy>
1058std::pair<Value, Value> zip(BinaryOpTy &&op) {
1059  return std::make_pair(op.lhs(), op.rhs());;
1060}
1061
1062void process(AddOp op, ArrayRef<Value> newOperands) {
1063  zip(op);
1064  zip(Adaptor<AddOp>(newOperands));
1065  /*...*/
1066}
1067```
1068
1069## Constraints
1070
1071Constraint is a core concept in table-driven operation definition: operation
1072verification and graph operation matching are all based on satisfying
1073constraints. So both the operation definition and rewrite rules specification
1074significantly involve writing constraints. We have the `Constraint` class in
1075[`OpBase.td`][OpBase] has the common base class for all constraints.
1076
1077An operation's constraint can cover different range; it may
1078
1079* Only concern a single attribute (e.g. being a 32-bit integer greater than 5),
1080* Multiple operands and results (e.g., the 1st result's shape must be the same
1081  as the 1st operand), or
1082* Intrinsic to the operation itself (e.g., having no side effect).
1083
1084We call them as single-entity constraint, multi-entity constraint, and traits,
1085respectively.
1086
1087### Single-entity constraint
1088
1089Constraints scoped to a single operand, attribute, or result are specified at
1090the entity's declaration place as described in
1091[Operation arguments](#operation-arguments) and
1092[Operation results](#operation-results).
1093
1094To help modelling constraints of common types, a set of `TypeConstraint`s are
1095created; they are the `Type` subclass hierarchy. It includes `F32` for the
1096constraints of being a float, `TensorOf<[F32]>` for the constraints of being
1097a float tensor, and so on.
1098
1099Similarly, a set of `AttrConstraint`s are created for helping modelling
1100constraints of common attribute kinds. They are the `Attr` subclass hierarchy.
1101It includes `F32Attr` for the constraints of being a float attribute,
1102`F32ArrayAttr` for the constraints of being a float array attribute, and so on.
1103
1104### Multi-entity constraint
1105
1106Constraints involving more than one operand/attribute/result are quite common
1107on operations, like the element type and shape relation between operands and
1108results. These constraints should be specified as the `Op` class template
1109parameter as described in
1110[Operation traits and constraints](#operation-traits-and-constraints).
1111
1112Multi-entity constraints are modeled as `PredOpTrait` (a subclass of `OpTrait`)
1113in [`OpBase.td`][OpBase].A bunch of constraint primitives are provided to help
1114specification. See [`OpBase.td`][OpBase] for the complete list.
1115
1116### Trait
1117
1118Traits are intrinsic properties of the operation like having side effect or not,
1119commutative or not, whether is a terminator, etc. These constraints should be
1120specified as the `Op` class template parameter as described in
1121[Operation traits and constraints](#operation-traits-and-constraints).
1122
1123Traits are modeled as `NativeOpTrait` (a subclass of `OpTrait`) in
1124[`OpBase.td`][OpBase]. They are backed and will be translated into the
1125corresponding C++ `mlir::OpTrait` classes.
1126
1127### How to specify new constraint
1128
1129To write a constraint, you need to provide its predicates and give it a
1130descriptive name. Predicates, modeled with the `Pred` class, are the workhorse
1131for composing constraints. The predicate for a constraint is typically built up
1132in a nested manner, using the two categories of predicates:
1133
11341.  `CPred`: the primitive leaf predicate.
11352.  Compound predicate: a predicate composed from child predicates using
1136    predicate combiners (conjunction: `And`, disjunction: `Or`, negation: `Neg`,
1137    substitution: `SubstLeaves`, concatenation: `Concat`).
1138
1139`CPred` is the basis for composing more complex predicates. It is the "atom"
1140predicate from the perspective of TableGen and the "interface" between
1141TableGen and C++. What is inside is already C++ code, which will be treated
1142as opaque strings with special placeholders to be substituted.
1143
1144You can put any C++ code that returns a boolean value inside a `CPred`,
1145including evaluating expressions, calling functions, calling class methods,
1146and so on.
1147
1148To help interaction with the C++ environment, there are a few special
1149placeholders provided to refer to entities in the context where this predicate
1150is used. They serve as "hooks" to the enclosing environment.  This includes
1151`$_builder`, `$_op`, and `$_self`:
1152
1153* `$_builder` will be replaced by a `mlir::Builder` instance so that you can
1154  access common build methods.
1155* `$_op` will be replaced by the current operation so that you can access
1156  information of the current operation.
1157* `$_self` will be replaced with the entity this predicate is attached to.
1158  E.g., `BoolAttr` is an attribute constraint that wraps a
1159  `CPred<"$_self.isa<BoolAttr>()">`. Then for `F32:$attr`,`$_self` will be
1160  replaced by `$attr`. For type constraints, it's a little bit special since
1161  we want the constraints on each type definition reads naturally and we want
1162  to attach type constraints directly to an operand/result, `$_self` will be
1163  replaced by the operand/result's type. E.g., for `F32` in `F32:$operand`, its
1164  `$_self` will be expanded as `getOperand(...).getType()`.
1165
1166TODO: Reconsider the leading symbol for special placeholders. Eventually we want
1167to allow referencing operand/result $-names; such $-names can start with
1168underscore.
1169
1170For example, to write an attribute `attr` is an `IntegerAttr`, in C++ you can
1171just call `attr.isa<IntegerAttr>()`. The code can be wrapped in a `CPred` as
1172`$_self.isa<IntegerAttr>()`, with `$_self` as the special placeholder to be
1173replaced by the current attribute `attr` at expansion time.
1174
1175For more complicated predicates, you can wrap it in a single `CPred`, or you
1176can use predicate combiners to combine them. For example, to write the
1177constraint that an attribute `attr` is a 32-bit or 64-bit integer, you can
1178write it as
1179
1180```tablegen
1181And<[
1182  CPred<"$_self.isa<IntegerAttr>()">,
1183  Or<[
1184    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(32)">,
1185    CPred<"$_self.cast<IntegerAttr>().getType().isInteger(64)">
1186  ]>
1187]>
1188```
1189
1190(Note that the above is just to show with a familiar example how you can use
1191`CPred` and predicate combiners to write complicated predicates. For integer
1192attributes specifically, [`OpBase.td`][OpBase] already defines `I32Attr` and
1193`I64Attr`. So you can actually reuse them to write it as `Or<[I32Attr.predicate,
1194I64Attr.predicate]>`.)
1195
1196TODO: Build up a library of reusable primitive constraints
1197
1198If the predicate is very complex to write with `CPred` together with predicate
1199combiners, you can also write it as a normal C++ function and use the `CPred`
1200as a way to "invoke" the function. For example, to verify an attribute `attr`
1201has some property, you can write a C++ function like
1202
1203```cpp
1204bool HasSomeProperty(Attribute attr) { ... }
1205```
1206
1207and then define the op as:
1208
1209```tablegen
1210def HasSomeProperty : AttrConstraint<CPred<"HasSomeProperty($_self)">,
1211                                     "has some property">;
1212
1213def MyOp : Op<...> {
1214  let arguments = (ins
1215    ...
1216    HasSomeProperty:$attr
1217  );
1218}
1219```
1220
1221As to whether we should define the predicate using a single `CPred` wrapping
1222the whole expression, multiple `CPred`s with predicate combiners, or a single
1223`CPred` "invoking" a function, there are no clear-cut criteria. Defining using
1224`CPred` and predicate combiners is preferable since it exposes more information
1225(instead hiding all the logic behind a C++ function) into the op definition spec
1226so that it can potentially drive more auto-generation cases. But it will
1227require a nice library of common predicates as the building blocks to avoid the
1228duplication, which is being worked on right now.
1229
1230## Attribute Definition
1231
1232An attribute is a compile-time known constant of an operation.
1233
1234ODS provides attribute wrappers over C++ attribute classes. There are a few
1235common C++ [attribute classes][AttrClasses] defined in MLIR's core IR library
1236and one is free to define dialect-specific attribute classes. ODS allows one
1237to use these attributes in TableGen to define operations, potentially with
1238more fine-grained constraints. For example, `StrAttr` directly maps to
1239`StringAttr`; `F32Attr`/`F64Attr` requires the `FloatAttr` to additionally
1240be of a certain bitwidth.
1241
1242ODS attributes are defined as having a storage type (corresponding to a backing
1243`mlir::Attribute` that _stores_ the attribute), a return type (corresponding to
1244the C++ _return_ type of the generated of the helper getters) as well as method
1245to convert between the internal storage and the helper method.
1246
1247### Attribute decorators
1248
1249There are a few important attribute adapters/decorators/modifiers that can be
1250applied to ODS attributes to specify common additional properties like
1251optionality, default values, etc.:
1252
1253*   `DefaultValuedAttr`: specifies the
1254    [default value](#attributes-with-default-values) for an attribute.
1255*   `OptionalAttr`: specifies an attribute as [optional](#optional-attributes).
1256*   `Confined`: adapts an attribute with
1257    [further constraints](#confining-attributes).
1258
1259### Enum attributes
1260
1261Some attributes can only take values from a predefined enum, e.g., the
1262comparison kind of a comparison op. To define such attributes, ODS provides
1263several mechanisms: `StrEnumAttr`, `IntEnumAttr`, and `BitEnumAttr`.
1264
1265*   `StrEnumAttr`: each enum case is a string, the attribute is stored as a
1266    [`StringAttr`][StringAttr] in the op.
1267*   `IntEnumAttr`: each enum case is an integer, the attribute is stored as a
1268    [`IntegerAttr`][IntegerAttr] in the op.
1269*   `BitEnumAttr`: each enum case is a bit, the attribute is stored as a
1270    [`IntegerAttr`][IntegerAttr] in the op.
1271
1272All these `*EnumAttr` attributes require fully specifying all of the allowed
1273cases via their corresponding `*EnumAttrCase`. With this, ODS is able to
1274generate additional verification to only accept allowed cases. To facilitate the
1275interaction between `*EnumAttr`s and their C++ consumers, the
1276[`EnumsGen`][EnumsGen] TableGen backend can generate a few common utilities: a
1277C++ enum class, `llvm::DenseMapInfo` for the enum class, conversion functions
1278from/to strings. This is controlled via the `-gen-enum-decls` and
1279`-gen-enum-defs` command-line options of `mlir-tblgen`.
1280
1281For example, given the following `EnumAttr`:
1282
1283```tablegen
1284def Case15: I32EnumAttrCase<"Case15", 15>;
1285def Case20: I32EnumAttrCase<"Case20", 20>;
1286
1287def MyIntEnum: I32EnumAttr<"MyIntEnum", "An example int enum",
1288                           [Case15, Case20]> {
1289  let cppNamespace = "Outer::Inner";
1290  let stringToSymbolFnName = "ConvertToEnum";
1291  let symbolToStringFnName = "ConvertToString";
1292}
1293```
1294
1295The following will be generated via `mlir-tblgen -gen-enum-decls`:
1296
1297```c++
1298namespace Outer {
1299namespace Inner {
1300// An example int enum
1301enum class MyIntEnum : uint32_t {
1302  Case15 = 15,
1303  Case20 = 20,
1304};
1305
1306llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t);
1307llvm::StringRef ConvertToString(MyIntEnum);
1308llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef);
1309inline constexpr unsigned getMaxEnumValForMyIntEnum() {
1310  return 20;
1311}
1312
1313} // namespace Inner
1314} // namespace Outer
1315
1316namespace llvm {
1317template<> struct DenseMapInfo<Outer::Inner::MyIntEnum> {
1318  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1319
1320  static inline Outer::Inner::MyIntEnum getEmptyKey() {
1321    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getEmptyKey());
1322  }
1323
1324  static inline Outer::Inner::MyIntEnum getTombstoneKey() {
1325    return static_cast<Outer::Inner::MyIntEnum>(StorageInfo::getTombstoneKey());
1326  }
1327
1328  static unsigned getHashValue(const Outer::Inner::MyIntEnum &val) {
1329    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1330  }
1331
1332  static bool isEqual(const Outer::Inner::MyIntEnum &lhs, const Outer::Inner::MyIntEnum &rhs) {
1333    return lhs == rhs;
1334  }
1335};
1336}
1337```
1338
1339The following will be generated via `mlir-tblgen -gen-enum-defs`:
1340
1341```c++
1342namespace Outer {
1343namespace Inner {
1344llvm::StringRef ConvertToString(MyIntEnum val) {
1345  switch (val) {
1346    case MyIntEnum::Case15: return "Case15";
1347    case MyIntEnum::Case20: return "Case20";
1348  }
1349  return "";
1350}
1351
1352llvm::Optional<MyIntEnum> ConvertToEnum(llvm::StringRef str) {
1353  return llvm::StringSwitch<llvm::Optional<MyIntEnum>>(str)
1354      .Case("Case15", MyIntEnum::Case15)
1355      .Case("Case20", MyIntEnum::Case20)
1356      .Default(llvm::None);
1357}
1358llvm::Optional<MyIntEnum> symbolizeMyIntEnum(uint32_t value) {
1359  switch (value) {
1360  case 15: return MyIntEnum::Case15;
1361  case 20: return MyIntEnum::Case20;
1362  default: return llvm::None;
1363  }
1364}
1365
1366} // namespace Inner
1367} // namespace Outer
1368```
1369
1370Similarly for the following `BitEnumAttr` definition:
1371
1372```tablegen
1373def None: BitEnumAttrCase<"None", 0x0000>;
1374def Bit1: BitEnumAttrCase<"Bit1", 0x0001>;
1375def Bit2: BitEnumAttrCase<"Bit2", 0x0002>;
1376def Bit3: BitEnumAttrCase<"Bit3", 0x0004>;
1377
1378def MyBitEnum: BitEnumAttr<"MyBitEnum", "An example bit enum",
1379                           [None, Bit1, Bit2, Bit3]>;
1380```
1381
1382We can have:
1383
1384```c++
1385// An example bit enum
1386enum class MyBitEnum : uint32_t {
1387  None = 0,
1388  Bit1 = 1,
1389  Bit2 = 2,
1390  Bit3 = 4,
1391};
1392
1393llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t);
1394std::string stringifyMyBitEnum(MyBitEnum);
1395llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef);
1396inline MyBitEnum operator|(MyBitEnum lhs, MyBitEnum rhs) {
1397  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
1398}
1399inline MyBitEnum operator&(MyBitEnum lhs, MyBitEnum rhs) {
1400  return static_cast<MyBitEnum>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
1401}
1402inline bool bitEnumContains(MyBitEnum bits, MyBitEnum bit) {
1403  return (static_cast<uint32_t>(bits) & static_cast<uint32_t>(bit)) != 0;
1404}
1405
1406namespace llvm {
1407template<> struct DenseMapInfo<::MyBitEnum> {
1408  using StorageInfo = llvm::DenseMapInfo<uint32_t>;
1409
1410  static inline ::MyBitEnum getEmptyKey() {
1411    return static_cast<::MyBitEnum>(StorageInfo::getEmptyKey());
1412  }
1413
1414  static inline ::MyBitEnum getTombstoneKey() {
1415    return static_cast<::MyBitEnum>(StorageInfo::getTombstoneKey());
1416  }
1417
1418  static unsigned getHashValue(const ::MyBitEnum &val) {
1419    return StorageInfo::getHashValue(static_cast<uint32_t>(val));
1420  }
1421
1422  static bool isEqual(const ::MyBitEnum &lhs, const ::MyBitEnum &rhs) {
1423    return lhs == rhs;
1424  }
1425};
1426```
1427
1428```c++
1429std::string stringifyMyBitEnum(MyBitEnum symbol) {
1430  auto val = static_cast<uint32_t>(symbol);
1431  // Special case for all bits unset.
1432  if (val == 0) return "None";
1433
1434  llvm::SmallVector<llvm::StringRef, 2> strs;
1435  if (1u & val) { strs.push_back("Bit1"); val &= ~1u; }
1436  if (2u & val) { strs.push_back("Bit2"); val &= ~2u; }
1437  if (4u & val) { strs.push_back("Bit3"); val &= ~4u; }
1438
1439  if (val) return "";
1440  return llvm::join(strs, "|");
1441}
1442
1443llvm::Optional<MyBitEnum> symbolizeMyBitEnum(llvm::StringRef str) {
1444  // Special case for all bits unset.
1445  if (str == "None") return MyBitEnum::None;
1446
1447  llvm::SmallVector<llvm::StringRef, 2> symbols;
1448  str.split(symbols, "|");
1449
1450  uint32_t val = 0;
1451  for (auto symbol : symbols) {
1452    auto bit = llvm::StringSwitch<llvm::Optional<uint32_t>>(symbol)
1453      .Case("Bit1", 1)
1454      .Case("Bit2", 2)
1455      .Case("Bit3", 4)
1456      .Default(llvm::None);
1457    if (bit) { val |= *bit; } else { return llvm::None; }
1458  }
1459  return static_cast<MyBitEnum>(val);
1460}
1461
1462llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t value) {
1463  // Special case for all bits unset.
1464  if (value == 0) return MyBitEnum::None;
1465
1466  if (value & ~(1u | 2u | 4u)) return llvm::None;
1467  return static_cast<MyBitEnum>(value);
1468}
1469```
1470
1471## Type Definitions
1472
1473MLIR defines the TypeDef class hierarchy to enable generation of data types
1474from their specifications. A type is defined by specializing the TypeDef
1475class with concrete contents for all the fields it requires. For example, an
1476integer type could be defined as:
1477
1478```tablegen
1479// All of the types will extend this class.
1480class Test_Type<string name> : TypeDef<Test_Dialect, name> { }
1481
1482// An alternate int type.
1483def IntegerType : Test_Type<"TestInteger"> {
1484  let mnemonic = "int";
1485
1486  let summary = "An integer type with special semantics";
1487
1488  let description = [{
1489    An alternate integer type. This type differentiates itself from the
1490    standard integer type by not having a SignednessSemantics parameter, just
1491    a width.
1492  }];
1493
1494  let parameters = (ins "unsigned":$width);
1495
1496  // We define the printer inline.
1497  let printer = [{
1498    $_printer << "int<" << getImpl()->width << ">";
1499  }];
1500
1501  // The parser is defined here also.
1502  let parser = [{
1503    if (parser.parseLess())
1504      return Type();
1505    int width;
1506    if ($_parser.parseInteger(width))
1507      return Type();
1508    if ($_parser.parseGreater())
1509      return Type();
1510    return get(ctxt, width);
1511  }];
1512```
1513
1514### Type name
1515
1516The name of the C++ class which gets generated defaults to
1517`<classParamName>Type` (e.g. `TestIntegerType` in the above example). This
1518can be overridden via the `cppClassName` field. The field `mnemonic` is
1519to specify the asm name for parsing. It is optional and not specifying it
1520will imply that no parser or printer methods are attached to this class.
1521
1522### Type documentation
1523
1524The `summary` and `description` fields exist and are to be used the same way
1525as in Operations. Namely, the summary should be a one-liner and `description`
1526should be a longer explanation.
1527
1528### Type parameters
1529
1530The `parameters` field is a list of the types parameters. If no parameters
1531are specified (the default), this type is considered a singleton type.
1532Parameters are in the `"c++Type":$paramName` format.
1533To use C++ types as parameters which need allocation in the storage
1534constructor, there are two options:
1535
1536- Set `hasCustomStorageConstructor` to generate the TypeStorage class with
1537a constructor which is just declared -- no definition -- so you can write it
1538yourself.
1539- Use the `TypeParameter` tablegen class instead of the "c++Type" string.
1540
1541### TypeParameter tablegen class
1542
1543This is used to further specify attributes about each of the types
1544parameters. It includes documentation (`description` and `syntax`), the C++
1545type to use, and a custom allocator to use in the storage constructor method.
1546
1547```tablegen
1548// DO NOT DO THIS!
1549let parameters = (ins
1550  "ArrayRef<int>":$dims);
1551```
1552
1553The default storage constructor blindly copies fields by value. It does not
1554know anything about the types. In this case, the ArrayRef<int> requires
1555allocation with `dims = allocator.copyInto(dims)`.
1556
1557You can specify the necessary constructor by specializing the `TypeParameter`
1558tblgen class:
1559
1560```tablegen
1561class ArrayRefIntParam :
1562    TypeParameter<"::llvm::ArrayRef<int>", "Array of ints"> {
1563  let allocator = [{$_dst = $_allocator.copyInto($_self);}];
1564}
1565
1566...
1567
1568let parameters = (ins
1569  ArrayRefIntParam:$dims);
1570```
1571
1572The `allocator` code block has the following substitutions:
1573- `$_allocator` is the TypeStorageAllocator in which to allocate objects.
1574- `$_dst` is the variable in which to place the allocated data.
1575
1576MLIR includes several specialized classes for common situations:
1577- `StringRefParameter<descriptionOfParam>` for StringRefs.
1578- `ArrayRefParameter<arrayOf, descriptionOfParam>` for ArrayRefs of value
1579types
1580- `SelfAllocationParameter<descriptionOfParam>` for C++ classes which contain
1581a method called `allocateInto(StorageAllocator &allocator)` to allocate
1582itself into `allocator`.
1583- `ArrayRefOfSelfAllocationParameter<arrayOf, descriptionOfParam>` for arrays
1584of objects which self-allocate as per the last specialization.
1585
1586If we were to use one of these included specializations:
1587
1588```tablegen
1589let parameters = (ins
1590  ArrayRefParameter<"int", "The dimensions">:$dims
1591);
1592```
1593
1594### Parsing and printing
1595
1596If a mnemonic is specified, the `printer` and `parser` code fields are active.
1597The rules for both are:
1598- If null, generate just the declaration.
1599- If non-null and non-empty, use the code in the definition. The `$_printer`
1600or `$_parser` substitutions are valid and should be used.
1601- It is an error to have an empty code block.
1602
1603For each dialect, two "dispatch" functions will be created: one for parsing
1604and one for printing. You should add calls to these in your
1605`Dialect::printType` and `Dialect::parseType` methods. They are created in
1606the dialect's namespace and their function signatures are:
1607```c++
1608Type generatedTypeParser(MLIRContext* ctxt, DialectAsmParser& parser,
1609                         StringRef mnemonic);
1610LogicalResult generatedTypePrinter(Type type, DialectAsmPrinter& printer);
1611```
1612
1613The mnemonic, parser, and printer fields are optional. If they're not
1614defined, the generated code will not include any parsing or printing code and
1615omit the type from the dispatch functions above. In this case, the dialect
1616author is responsible for parsing/printing the types in `Dialect::printType`
1617and `Dialect::parseType`.
1618
1619### Other fields
1620
1621- If the `genStorageClass` field is set to 1 (the default) a storage class is
1622generated with member variables corresponding to each of the specified
1623`parameters`.
1624- If the `genAccessors` field is 1 (the default) accessor methods will be
1625generated on the Type class (e.g. `int getWidth() const` in the example
1626above).
1627- If the `genVerifyInvariantsDecl` field is set, a declaration for a method
1628`static LogicalResult verifyConstructionInvariants(Location, parameters...)`
1629is added to the class as well as a `getChecked(Location, parameters...)`
1630method which gets the result of `verifyConstructionInvariants` before calling
1631`get`.
1632- The `storageClass` field can be used to set the name of the storage class.
1633- The `storageNamespace` field is used to set the namespace where the storage
1634class should sit. Defaults to "detail".
1635- The `extraClassDeclaration` field is used to include extra code in the
1636class declaration.
1637
1638## Debugging Tips
1639
1640### Run `mlir-tblgen` to see the generated content
1641
1642TableGen syntax sometimes can be obscure; reading the generated content can be
1643a very helpful way to understand and debug issues. To build `mlir-tblgen`, run
1644`cmake --build . --target mlir-tblgen` in your build directory and find the
1645`mlir-tblgen` binary in the `bin/` subdirectory. All the supported generators
1646can be found via `mlir-tblgen --help`. For example, `--gen-op-decls` and
1647`--gen-op-defs` as explained in [Generated C++ code](#generated-c++-code).
1648
1649To see the generated code, invoke `mlir-tblgen` with a specific generator by
1650providing include paths via `-I`. For example,
1651
1652```sh
1653# To see op C++ class declaration
1654mlir-tblgen --gen-op-decls -I /path/to/mlir/include /path/to/input/td/file
1655# To see op C++ class definition
1656mlir-tblgen --gen-op-defs -I /path/to/mlir/include /path/to/input/td/file
1657# To see op documentation
1658mlir-tblgen --gen-dialect-doc -I /path/to/mlir/include /path/to/input/td/file
1659
1660# To see op interface C++ class declaration
1661mlir-tblgen --gen-op-interface-decls -I /path/to/mlir/include /path/to/input/td/file
1662# To see op interface C++ class definition
1663mlir-tblgen --gen-op-interface-defs -I /path/to/mlir/include /path/to/input/td/file
1664# To see op interface documentation
1665mlir-tblgen --gen-op-interface-doc -I /path/to/mlir/include /path/to/input/td/file
1666```
1667
1668## Appendix
1669
1670### Requirements and existing mechanisms analysis
1671
1672The op description should as declarative as possible to allow a wide range of
1673tools to work with them and query methods generated from them. In particular
1674this means specifying traits, constraints and shape inference information in
1675a way that is easily analyzable (e.g., avoid opaque calls to C++ functions where
1676possible).
1677
1678We considered the approaches of several contemporary systems and focused on
1679requirements that were desirable:
1680
1681*   Ops registered using a registry separate from C++ code.
1682    *   Unknown ops are allowed in MLIR, so ops need not be registered. The
1683        ability of the compiler to optimize those ops or graphs containing those
1684        ops is constrained but correct.
1685    *   The current proposal does not include a runtime op description, but it
1686        does not preclude such description, it can be added later.
1687    *   The op registry is essential for generating C++ classes that make
1688        manipulating ops, verifying correct construction etc. in C++ easier by
1689        providing a typed representation and accessors.
1690*   The op registry will be defined in
1691    [TableGen](https://llvm.org/docs/TableGen/index.html) and be used to
1692    generate C++ classes and utility functions
1693    (builder/verifier/parser/printer).
1694    *   TableGen is a modelling specification language used by LLVM's backends
1695        and fits in well with trait-based modelling. This is an implementation
1696        decision and there are alternative ways of doing this. But the
1697        specification language is good for the requirements of modelling the
1698        traits (as seen from usage in LLVM processor backend modelling) and easy
1699        to extend, so a practical choice. If another good option comes up, we
1700        will consider it.
1701*   MLIR allows both defined and undefined ops.
1702    *   Defined ops should have fixed semantics and could have a corresponding
1703        reference implementation defined using, for example, EDSC.
1704    *   Dialects are under full control of the dialect owner and normally live
1705        with the framework of the dialect.
1706*   The op's traits (e.g., commutative) are modelled along with the op in the
1707    registry.
1708*   The op's operand/return type constraints are modelled along with the op in
1709    the registry (see [Shape inference](ShapeInference.md) discussion below),
1710    this allows (e.g.) optimized concise syntax in textual dumps.
1711*   Behavior of the op is documented along with the op with a summary and a
1712    description. The description is written in markdown and extracted for
1713    inclusion in the generated LangRef section of the dialect.
1714*   The generic assembly form of printing and parsing is available as normal,
1715    but a custom parser and printer can either be specified or automatically
1716    generated from an optional string representation showing the mapping of the
1717    "assembly" string to operands/type.
1718    *   Parser-level remappings (e.g., `eq` to enum) will be supported as part
1719        of the parser generation.
1720*   Matching patterns are specified separately from the op description.
1721    *   Contrasted with LLVM there is no "base" set of ops that every backend
1722        needs to be aware of. Instead there are many different dialects and the
1723        transformations/legalizations between these dialects form a graph of
1724        transformations.
1725*   Reference implementation may be provided along with the op definition.
1726
1727    *   The reference implementation may be in terms of either standard ops or
1728        other reference implementations.
1729
1730    TODO: document expectation if the dependent op's definition changes.
1731
1732[TableGen]: https://llvm.org/docs/TableGen/index.html
1733[TableGenProgRef]: https://llvm.org/docs/TableGen/ProgRef.html
1734[TableGenBackend]: https://llvm.org/docs/TableGen/BackEnds.html#introduction
1735[OpBase]: https://github.com/llvm/llvm-project/blob/master/mlir/include/mlir/IR/OpBase.td
1736[OpDefinitionsGen]: https://github.com/llvm/llvm-project/blob/master/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
1737[EnumsGen]: https://github.com/llvm/llvm-project/blob/master/mlir/tools/mlir-tblgen/EnumsGen.cpp
1738[StringAttr]: LangRef.md#string-attribute
1739[IntegerAttr]: LangRef.md#integer-attribute
1740[AttrClasses]: https://github.com/llvm/llvm-project/blob/master/mlir/include/mlir/IR/Attributes.h
1741