xref: /llvm-project/mlir/docs/DeclarativeRewrites.md (revision 830b9b072d8458ee89c48f00d4de59456c9f467f)
1# Table-driven Declarative Rewrite Rule (DRR)
2
3In addition to subclassing the `mlir::RewritePattern` C++ class, MLIR also
4supports defining rewrite rules in a declarative manner. Similar to
5[Op Definition Specification](DefiningDialects/Operations.md) (ODS), this is achieved via
6[TableGen][TableGen], which is a language to maintain records of domain-specific
7information. The rewrite rules are specified concisely in a TableGen record,
8which will be expanded into an equivalent `mlir::RewritePattern` subclass at
9compiler build time.
10
11This manual explains in detail all of the available mechanisms for defining
12rewrite rules in such a declarative manner. It aims to be a specification
13instead of a tutorial. Please refer to
14[Quickstart tutorial to adding MLIR graph rewrite](Tutorials/QuickstartRewrites.md)
15for the latter.
16
17Given that declarative rewrite rules depend on op definition specification, this
18manual assumes knowledge of the [ODS](DefiningDialects/Operations.md) doc.
19
20[TOC]
21
22## Benefits
23
24Compared to the hand-written C++ classes, this declarative approach has several
25benefits, including but not limited to:
26
27*   **Being declarative**: The pattern creator just needs to state the rewrite
28    pattern declaratively, without worrying about the concrete C++ methods to
29    call.
30*   **Removing boilerplate and showing the very essence of the rewrite**:
31    `mlir::RewritePattern` is already good at hiding boilerplate for defining a
32    rewrite rule. But we still need to write the class and function structures
33    required by the C++ programming language, inspect ops for matching, and call
34    op `build()` methods for constructing. These statements are typically quite
35    simple and similar, so they can be further condensed with auto-generation.
36    Because we reduce the boilerplate to the bare minimum, the declarative
37    rewrite rule will just contain the very essence of the rewrite. This makes
38    it very easy to understand the pattern.
39
40## Strengths and Limitations
41
42The declarative rewrite rule is **operation-based**: it describes a rule to
43match against a directed acyclic graph (DAG) of operations and generate DAGs of
44operations. This gives DRR both its strengths and limitations: it is good at
45expressing op to op conversions, but not that well suited for, say, converting
46an op into a loop nest.
47
48Per the current implementation, DRR does not have good support for the following
49features:
50
51*   Matching and generating ops with regions.
52*   Matching and generating ops with block arguments.
53*   Matching multi-result ops in nested patterns.
54*   Matching and generating variadic operand/result ops in nested patterns.
55*   Packing and unpacking variadic operands/results during generation.
56*   [`NativeCodeCall`](#nativecodecall-transforming-the-generated-op) returning
57    more than one results.
58
59## Rule Definition
60
61The core construct for defining a rewrite rule is defined in
62[`PatternBase.td`][PatternBase] as
63
64```tablegen
65class Pattern<
66    dag sourcePattern, list<dag> resultPatterns,
67    list<dag> additionalConstraints = [],
68    list<dag> supplementalPatterns = [],
69    dag benefitsAdded = (addBenefit 0)>;
70```
71
72A declarative rewrite rule contains two main components:
73
74*   A *source pattern*, which is used for matching a DAG of operations.
75*   One or more *result patterns*, which are used for generating DAGs of
76    operations to replace the matched DAG of operations.
77
78We allow multiple result patterns to support
79[multi-result ops](#supporting-multi-result-ops) and
80[auxiliary ops](#supporting-auxiliary-ops), but frequently we just want to
81convert one DAG of operations to another DAG of operations. There is a handy
82wrapper of `Pattern`, `Pat`, which takes a single result pattern:
83
84```tablegen
85class Pat<
86    dag sourcePattern, dag resultPattern,
87    list<dag> additionalConstraints = [],
88    dag benefitsAdded = (addBenefit 0)> :
89  Pattern<sourcePattern, [resultPattern], additionalConstraints, benefitAdded>;
90```
91
92Each pattern is specified as a TableGen `dag` object with the syntax of
93`(operator arg0, arg1, ...)`.
94
95`operator` is typically an MLIR op, but it can also be other
96[directives](#rewrite-directives). `argN` is for matching (if used in source
97pattern) or generating (if used in result pattern) the `N`-th argument for
98`operator`. If the `operator` is some MLIR operation, it means the `N`-th
99argument as specified in the `arguments` list of the op's definition. Therefore,
100we say op argument specification in pattern is **position-based**: the position
101where they appear matters.
102
103`argN` can be a `dag` object itself, thus we can have nested `dag` tree to model
104the def-use relationship between ops.
105
106### Source pattern
107
108The source pattern is for matching a DAG of operations. Arguments in the `dag`
109object are intended to **capture** the op arguments. They can also be used to
110**further limit** the match criteria. The capturing is done by specifying a
111symbol starting with the `$` sign, while further constraints are introduced by
112specifying a `TypeConstraint` (for an operand) or a `AttrConstraint` (for an
113attribute).
114
115#### Binding op arguments and limiting the match
116
117For example,
118
119```tablegen
120def AOp : Op<"a_op"> {
121    let arguments = (ins
122      AnyType:$a_input,
123      AnyAttr:$a_attr
124    );
125
126    let results = (outs
127      AnyType:$a_output
128    );
129}
130
131def : Pat<(AOp $input, F32Attr:$attr), ...>;
132```
133
134In the above, we are matching an `AOp` whose `$input` can be anything valid as
135defined by the op and whose `$attr` must be a float attribute. If the match
136succeeds, we bind the `$input` symbol to the op's only input (`$a_input`) and
137`$attr` to the only attribute (`$a_attr`); we can reference them using `$input`
138and `$attr` in result patterns and additional constraints.
139
140The pattern is position-based: the symbol names used for capturing here do not
141need to match with the op definition as shown in the above example. As another
142example, the pattern can be written as `def : Pat<(AOp $a, F32Attr:$b), ...>;`
143and use `$a` and `$b` to refer to the captured input and attribute. But using
144the ODS name directly in the pattern is also allowed. Operands in the source
145pattern can have the same name. This bounds one operand to the name while
146verifying the rest are all equal.
147
148Also note that we only need to add `TypeConstraint` or `AttributeConstraint`
149when we need to further limit the match criteria. If all valid cases to the op
150are acceptable, then we can leave the constraint unspecified.
151
152`$_` is a special symbol to mean ignore capturing an argument. For example,
153`def : Pat<(AOp $_, $b), ...>` means only `$b` is interesting to capture and
154will be referenced later in result patterns. It's still possible to place
155additional constraints even if the symbol is not to be captured; for such case,
156you can simply use just the `TypeConstraint` or `AttributeConstraint` without a
157bound symbol, for example, `def : Pat<(AOp $a, F32Attr), ...>`.
158
159#### Matching DAG of operations
160
161To match a DAG of ops, use nested `dag` objects:
162
163```tablegen
164
165def BOp : Op<"b_op"> {
166    let arguments = (ins);
167
168    let results = (outs
169      AnyType:$b_output
170    );
171}
172
173
174def : Pat<(AOp (BOp), $attr), ...>;
175```
176
177The above pattern matches an `AOp` whose only operand is generated by a `BOp`,
178that is, the following MLIR code:
179
180```mlir
181%0 = "b_op"() : () -> (...)
182%1 = "a_op"(%0) {attr: ...} : () -> (...)
183```
184
185#### Binding op results
186
187To bind a symbol to the results of a matched op for later reference, attach the
188symbol to the op itself:
189
190```tablegen
191def : Pat<(AOp (BOp:$b_result), $attr), ...>;
192```
193
194The above will bind `$b_result` to the matched `BOp`'s result. (There are more
195details regarding multi-result ops, which is covered
196[later](#supporting-multi-result-ops).)
197
198### Result pattern
199
200The result pattern is for generating a DAG of operations. Arguments in the `dag`
201object are intended to **reference** values captured in the source pattern and
202potentially **apply transformations**.
203
204#### Referencing bound symbols
205
206For example,
207
208```tablegen
209def COp : Op<"c_op"> {
210    let arguments = (ins
211      AnyType:$c_input,
212      AnyAttr:$c_attr
213    );
214
215    let results = (outs
216      AnyType:$c_output
217    );
218}
219
220def : Pat<(AOp $input, $attr), (COp $input, $attr)>;
221```
222
223In the above, `AOp`'s only operand and attribute are bound to `$input` and
224`$attr`, respectively. We then reference them in the result pattern for
225generating the `COp` by passing them in as arguments to `COp`'s `build()`
226method.
227
228We can also reference symbols bound to matched op's results:
229
230```tablegen
231def : Pat<(AOp (BOp:$b_result) $attr), (COp $b_result $attr)>;
232```
233
234In the above, we are using `BOp`'s result for building `COp`.
235
236#### Building operations
237
238Given that `COp` was specified with table-driven op definition, there will be
239several `build()` methods generated for it. One of them has aggregated
240parameters for result types, operands, and attributes in the signature: `void
241COp::build(..., ArrayRef<Type> resultTypes, Array<Value> operands,
242ArrayRef<NamedAttribute> attr)`. The pattern in the above calls this `build()`
243method for constructing the `COp`.
244
245In general, arguments in the result pattern will be passed directly to the
246`build()` method to leverage the auto-generated `build()` method, list them in
247the pattern by following the exact same order as the ODS `arguments` definition.
248Otherwise, a custom `build()` method that matches the argument list is required.
249
250Right now all ODS-generated `build()` methods require specifying the result
251type(s), unless the op has known traits like `SameOperandsAndResultType` that we
252can use to auto-generate a `build()` method with result type deduction. When
253generating an op to replace the result of the matched root op, we can use the
254matched root op's result type when calling the ODS-generated builder. Otherwise
255(e.g., generating an [auxiliary op](#supporting-auxiliary-ops) or generating an
256op with a nested result pattern), DRR will not be able to deduce the result
257type(s). The pattern author will need to define a custom builder that has result
258type deduction ability via `OpBuilder` in ODS. For example, in the following
259pattern
260
261```tablegen
262def : Pat<(AOp $input, $attr), (COp (AOp $input, $attr) $attr)>;
263```
264
265`AOp` is generated via a nested result pattern; DRR won't be able to deduce the
266result type for it. A custom builder for `AOp` should be defined and it should
267deduce the result type by itself. The builder should have the separate parameter
268for each operand and attribute and deduce the result type internally by itself.
269For example, for the above `AOp`, a possible builder is:
270
271```c++
272
273void AOp::build(OpBuilder &builder, OperationState &state,
274                Value input, Attribute attr) {
275  state.addOperands({input});
276  state.addAttribute("a_attr", attr);
277  Type type = ...; // Deduce result type here
278  state.addTypes({type});
279}
280```
281
282Failing to define such a builder will result in an error at C++ compilation time
283saying the call to `AOp::build()` cannot be resolved because of the number of
284parameters mismatch.
285
286#### Generating DAG of operations
287
288`dag` objects can be nested to generate a DAG of operations:
289
290```tablegen
291def : Pat<(AOp $input, $attr), (COp (BOp), $attr)>;
292```
293
294In the above, we generate a `BOp`, and then use its result to generate the `COp`
295to replace the matched `AOp`.
296
297#### Binding op results
298
299In the result pattern, we can bind to the result(s) of a newly built op by
300attaching symbols to the op. (But we **cannot** bind to op arguments given that
301they are referencing previously bound symbols.) This is useful for reusing newly
302created results where suitable. For example,
303
304```tablegen
305def DOp : Op<"d_op"> {
306    let arguments = (ins
307      AnyType:$d_input1,
308      AnyType:$d_input2,
309    );
310
311    let results = (outs
312      AnyType:$d_output
313    );
314}
315
316def : Pat<(AOp $input, $ignored_attr), (DOp (BOp:$b_result) $b_result)>;
317```
318
319In this pattern, an `AOp` is matched and replaced with a `DOp` whose two
320operands are from the result of a single `BOp`. This is only possible by binding
321the result of the `BOp` to a name and reuse it for the second operand of the
322`DOp`
323
324#### `NativeCodeCall`: transforming the generated op
325
326Sometimes the captured arguments are not exactly what we want so they cannot be
327directly fed in as arguments to build the new op. For such cases, we can apply
328transformations on the arguments by calling into C++ helper functions. This is
329achieved by `NativeCodeCall`.
330
331For example, if we want to capture some op's attributes and group them as an
332array attribute to construct a new op:
333
334```tablegen
335
336def TwoAttrOp : Op<"two_attr_op"> {
337    let arguments = (ins
338      AnyAttr:$op_attr1,
339      AnyAttr:$op_attr2
340    );
341
342    let results = (outs
343      AnyType:$op_output
344    );
345}
346
347def OneAttrOp : Op<"one_attr_op"> {
348    let arguments = (ins
349      ArrayAttr:$op_attr
350    );
351
352    let results = (outs
353      AnyType:$op_output
354    );
355}
356```
357
358We can write a C++ helper function:
359
360```c++
361ArrayAttr createArrayAttr(Builder &builder, Attribute a, Attribute b) {
362  return builder.getArrayAttr({a, b});
363}
364```
365
366And then write the pattern as:
367
368```tablegen
369def createArrayAttr : NativeCodeCall<"createArrayAttr($_builder, $0, $1)">;
370
371def : Pat<(TwoAttrOp $attr1, $attr2),
372          (OneAttrOp (createArrayAttr $attr1, $attr2))>;
373```
374
375And make sure the generated C++ code from the above pattern has access to the
376definition of the C++ helper function.
377
378In the above example, we are using a string to specialize the `NativeCodeCall`
379template. The string can be an arbitrary C++ expression that evaluates into some
380C++ object expected at the `NativeCodeCall` site (here it would be expecting an
381array attribute). Typically the string should be a function call.
382
383##### `NativeCodeCall` placeholders
384
385In `NativeCodeCall`, we can use placeholders like `$_builder`, `$N` and `$N...`.
386The former is called *special placeholder*, while the latter is called
387*positional placeholder* and *positional range placeholder*.
388
389`NativeCodeCall` right now only supports three special placeholders:
390`$_builder`, `$_loc`, and `$_self`:
391
392*   `$_builder` will be replaced by the current `mlir::PatternRewriter`.
393*   `$_loc` will be replaced by the fused location or custom location (as
394    determined by location directive).
395*   `$_self` will be replaced by the defining operation in a source pattern.
396
397We have seen how `$_builder` can be used in the above; it allows us to pass a
398`mlir::Builder` (`mlir::PatternRewriter` is a subclass of `mlir::OpBuilder`,
399which is a subclass of `mlir::Builder`) to the C++ helper function to use the
400handy methods on `mlir::Builder`.
401
402Here's an example how we should use `$_self` in source pattern,
403
404```tablegen
405
406def : Pat<(OneAttrOp (NativeCodeCall<"Foo($_self, &$0)"> I32Attr:$val)),
407          (TwoAttrOp $val, $val)>;
408```
409
410In the above, `$_self` is substituted by the defining operation of the first
411operand of OneAttrOp. Note that we don't support binding name to
412`NativeCodeCall` in the source pattern. To carry some return values from a
413helper function, put the names (constraint is optional) in the parameter list
414and they will be bound to the variables with corresponding type. Then these names
415must be either passed by reference or pointer to the variable used as argument
416so that the matched value can be returned. In the same example, `$val` will be
417bound to a variable with `Attribute` type (as `I32Attr`) and the type of the
418second argument in `Foo()` could be `Attribute&` or `Attribute*`. Names with
419attribute constraints will be captured as `Attribute`s while everything else
420will be treated as `Value`s.
421
422Positional placeholders will be substituted by the `dag` object parameters at
423the `NativeCodeCall` use site. For example, if we define `SomeCall :
424NativeCodeCall<"someFn($1, $2, $0)">` and use it like `(SomeCall $in0, $in1,
425$in2)`, then this will be translated into C++ call `someFn($in1, $in2, $in0)`.
426
427Positional range placeholders will be substituted by multiple `dag` object
428parameters at the `NativeCodeCall` use site. For example, if we define
429`SomeCall : NativeCodeCall<"someFn($1...)">` and use it like `(SomeCall $in0,
430$in1, $in2)`, then this will be translated into C++ call `someFn($in1, $in2)`.
431
432##### `NativeCodeCall` binding multi-results
433
434To bind multi-results and access the N-th result with `$<name>__N`, specify the
435number of return values in the template. Note that only `Value` type is
436supported for multiple results binding. For example,
437
438```tablegen
439
440def PackAttrs : NativeCodeCall<"packAttrs($0, $1)", 2>;
441def : Pattern<(TwoResultOp $attr1, $attr2),
442              [(OneResultOp (PackAttr:$res__0, $attr1, $attr2)),
443               (OneResultOp $res__1)]>;
444
445```
446
447Use `NativeCodeCallVoid` for cases with no return value.
448
449The correct number of returned value specified in NativeCodeCall is important.
450It will be used to verify the consistency of the number of return values.
451Additionally, `mlir-tblgen` will try to capture the return values of
452`NativeCodeCall` in the generated code so that it will trigger a later
453compilation error if a `NativeCodeCall` that doesn't return any result isn't
454labeled with 0 returns.
455
456##### Customizing entire op building
457
458`NativeCodeCall` is not only limited to transforming arguments for building an
459op; it can be also used to specify how to build an op entirely. An example:
460
461If we have a C++ function for building an op:
462
463```c++
464Operation *createMyOp(OpBuilder builder, Value input, Attribute attr);
465```
466
467We can wrap it up and invoke it like:
468
469```tablegen
470def createMyOp : NativeCodeCall<"createMyOp($_builder, $0, $1)">;
471
472def : Pat<(... $input, $attr), (createMyOp $input, $attr)>;
473```
474
475### Supporting auxiliary ops
476
477A declarative rewrite rule supports multiple result patterns. One of the
478purposes is to allow generating *auxiliary ops*. Auxiliary ops are operations
479used for building the replacement ops; but they are not directly used for
480replacement themselves.
481
482For the case of uni-result ops, if there are multiple result patterns, only the
483value generated from the last result pattern will be used to replace the matched
484root op's result; all other result patterns will be considered as generating
485auxiliary ops.
486
487Normally we want to specify ops as nested `dag` objects if their def-use
488relationship can be expressed in the way that an op's result can feed as the
489argument to consuming op. But that is not always possible. For example, if we
490want to allocate memory and store some computation (in pseudocode):
491
492```mlir
493%dst = arith.addi %lhs, %rhs
494```
495
496into
497
498```mlir
499%shape = shape %lhs
500%mem = memref.alloc %shape
501%sum = arith.addi %lhs, %rhs
502memref.store %mem, %sum
503%dst = memref.load %mem
504```
505
506We cannot fit in with just one result pattern given `store` does not return a
507value. Instead we can use multiple result patterns:
508
509```tablegen
510def : Pattern<(AddIOp $lhs, $rhs),
511              [(StoreOp (AllocOp:$mem (ShapeOp $lhs)), (AddIOp $lhs, $rhs)),
512               (LoadOp $mem)];
513```
514
515In the above we use the first result pattern to generate the first four ops, and
516use the last pattern to generate the last op, which is used to replace the
517matched op.
518
519### Supporting multi-result ops
520
521Multi-result ops bring extra complexity to declarative rewrite rules. We use
522TableGen `dag` objects to represent ops in patterns; there is no native way to
523indicate that an op generates multiple results. The approach adopted is based on
524**naming convention**: a `__N` suffix is added to a symbol to indicate the
525`N`-th result.
526
527#### `__N` suffix
528
529The `__N` suffix is specifying the `N`-th result as a whole (which can be
530[variadic](#supporting-variadic-ops)). For example, we can bind a symbol to some
531multi-result op and reference a specific result later:
532
533```tablegen
534def ThreeResultOp : Op<"three_result_op"> {
535    let arguments = (ins ...);
536
537    let results = (outs
538      AnyTensor:$output1,
539      AnyTensor:$output2,
540      AnyTensor:$output3
541    );
542}
543
544def : Pattern<(ThreeResultOp:$results ...),
545              [(... $results__0), ..., (... $results__2), ...]>;
546```
547
548In the above pattern we bind `$results` to all the results generated by
549`ThreeResultOp` and references its `$output1` and `$output3` later in the result
550patterns.
551
552We can also bind a symbol and reference one of its specific result at the same
553time, which is typically useful when generating multi-result ops:
554
555```tablegen
556// TwoResultOp has similar definition as ThreeResultOp, but only has two
557// results.
558
559def : Pattern<(TwoResultOp ...),
560              [(ThreeResultOp:$results__2, ...),
561               (replaceWithValue $results__0)]>;
562```
563
564In the above, we created a `ThreeResultOp` and bind `results` to its results,
565and uses its last result (`$output3`) and first result (`$output1`) to replace
566the `TwoResultOp`'s two results, respectively.
567
568#### Replacing multi-result ops
569
570The above example also shows how to replace a matched multi-result op.
571
572To replace an `N`-result op, the result patterns must generate at least `N`
573declared values (see [Declared vs. actual value](#declared-vs-actual-value) for
574definition). If there are more than `N` declared values generated, only the last
575`N` declared values will be used to replace the matched op. Note that because of
576the existence of multi-result op, one result pattern **may** generate multiple
577declared values. So it means we do not necessarily need `N` result patterns to
578replace an `N`-result op. For example, to replace an op with three results, you
579can have
580
581```tablegen
582// ThreeResultOp/TwoResultOp/OneResultOp generates three/two/one result(s),
583// respectively.
584
585// Replace each result with a result generated from an individual op.
586def : Pattern<(ThreeResultOp ...),
587              [(OneResultOp ...), (OneResultOp ...), (OneResultOp ...)]>;
588
589// Replace the first two results with two results generated from the same op.
590def : Pattern<(ThreeResultOp ...),
591              [(TwoResultOp ...), (OneResultOp ...)]>;
592
593// Replace all three results with three results generated from the same op.
594def : Pat<(ThreeResultOp ...), (ThreeResultOp ...)>;
595
596def : Pattern<(ThreeResultOp ...),
597              [(AuxiliaryOp ...), (ThreeResultOp ...)]>;
598```
599
600But using a single op to serve as both auxiliary op and replacement op is
601forbidden, i.e., the following is not allowed because that the first
602`TwoResultOp` generates two results but only the second result is used for
603replacing the matched op's result:
604
605```tablegen
606def : Pattern<(ThreeResultOp ...),
607              [(TwoResultOp ...), (TwoResultOp ...)]>;
608```
609
610### Supporting variadic ops
611
612#### Declared vs. actual value
613
614Before going into details on variadic op support, we need to define a few terms
615regarding an op's values.
616
617*   *Value*: either an operand or a result
618*   *Declared operand/result/value*: an operand/result/value statically declared
619    in ODS of the op
620*   *Actual operand/result/value*: an operand/result/value of an op instance at
621    runtime
622
623The above terms are needed because ops can have multiple results, and some of
624the results can also be variadic. For example,
625
626```tablegen
627def MultiVariadicOp : Op<"multi_variadic_op"> {
628    let arguments = (ins
629      AnyTensor:$input1,
630      Variadic<AnyTensor>:$input2,
631      AnyTensor:$input3
632    );
633
634    let results = (outs
635      AnyTensor:$output1,
636      Variadic<AnyTensor>:$output2,
637      AnyTensor:$output3
638    );
639}
640```
641
642We say the above op has 3 declared operands and 3 declared results. But at
643runtime, an instance can have 3 values corresponding to `$input2` and 2 values
644correspond to `$output2`; we say it has 5 actual operands and 4 actual results.
645A variadic operand/result is a considered as a declared value that can
646correspond to multiple actual values.
647
648[TODO]
649
650#### Match variadic operand
651
652Use the `variadic` DAG node to match a variadic operand with a fixed number of
653actual sub-operands.
654
655For example, assume that `ConcatenateOp` is an operation with a variadic
656operand:
657
658```tablegen
659def ConcatenateOp : TEST_Op<"concatenate"> {
660  let arguments = (ins
661    Variadic<AnyTensor>:$inputs,
662    I32Attr:$axis
663  );
664
665  let results = (outs
666    AnyTensor$output
667  );
668}
669```
670
671We can match `ConcatenateOp` with exactly 2 actual operands with:
672
673```tablegen
674def : Pat<(ConcatenateOp (variadic $input0, $input1), $axis),
675          ...>;
676```
677
678The variadic sub-operands can be sub-DAGs to be matched:
679
680```tablegen
681def : Pat<(ConcatenateOp (variadic (SomeOp $a), (AnotherOp $b, $c)), $axis),
682          (OtherOp $a, $b, $c)>;
683```
684
685The variadic DAG can be bound to a symbol, which refers to the full
686`operand_range`:
687
688```tablegen
689def : Pat<(ConcatenateOp (variadic:$inputs $input0, $input1),
690                         ConstantAttr<I32Attr, "0">),
691          (VStackOp $inputs)>;
692```
693
694### Supplying additional constraints
695
696Constraints can be placed on op arguments when matching. But sometimes we need
697to also place constraints on the matched op's results or sometimes need to limit
698the matching with some constraints that cover both the arguments and the
699results. The third parameter to `Pattern` (and `Pat`) is for this purpose.
700
701For example, we can write
702
703```tablegen
704def HasNoUseOf: Constraint<CPred<"$_self.use_empty()">, "has no use">;
705
706def HasSameElementType : Constraint<
707    CPred<"$0.cast<ShapedType>().getElementType() == "
708          "$1.cast<ShapedType>().getElementType()">,
709    "has same element type">;
710
711def : Pattern<(TwoResultOp:$results $input),
712              [(...), (...)],
713              [(F32Tensor:$results__0), (HasNoUseOf:$results__1),
714               (HasSameElementShape $results__0, $input)]>;
715```
716
717You can
718
719*   Use normal `TypeConstraint`s on previous bound symbols (the first result of
720    `TwoResultOp` must be a float tensor);
721*   Define new `Constraint` for previous bound symbols (the second result of
722    `TwoResultOp` must has no use);
723*   Apply constraints on multiple bound symbols (`$input` and `TwoResultOp`'s
724    first result must have the same element type).
725
726### Supplying additional result patterns
727
728Sometimes we need to add additional code after the result patterns, e.g. coping
729the attributes of the source op to the result ops. These can be specified via
730`SupplementalPatterns` parameter. Similar to auxiliary patterns, they are not
731for replacing results in the source pattern.
732
733For example, we can write
734
735```tablegen
736def GetOwner: NativeCodeCall<"$0.getOwner()">;
737
738def CopyAttrFoo: NativeCodeCallVoid<
739  "$1->setAttr($_builder.getStringAttr(\"foo\"), $0->getInherentAttr(\"foo\"))">;
740
741def CopyAttrBar: NativeCodeCallVoid<
742  "$1->setAttr($_builder.getStringAttr(\"bar\"), $0->getInherentAttr(\"bar\"))">;
743
744
745def : Pattern<
746  (ThreeResultOp:$src ...),
747  [(ZeroResultOp:$dest1 ...), (ThreeResultOp:$dest2 ...)],
748  [(CopyAttrFoo (GetOwner $src), $dest1),
749    (CopyAttrBar (GetOwner $src), (GetOwner $dest2))]>;
750```
751
752This will copy the attribute `foo` and `bar` of `ThreeResultOp` in the source
753pattern to `ZeroResultOp` and `ThreeResultOp` in the result patterns respectively.
754The patterns are executed in specified order.
755
756### Adjusting benefits
757
758The benefit of a `Pattern` is an integer value indicating the benefit of
759matching the pattern. It determines the priorities of patterns inside the
760pattern rewrite driver. A pattern with a higher benefit is applied before one
761with a lower benefit.
762
763In DRR, a rule is set to have a benefit of the number of ops in the source
764pattern. This is based on the heuristics and assumptions that:
765
766*   Larger matches are more beneficial than smaller ones.
767*   If a smaller one is applied first the larger one may not apply anymore.
768
769The fourth parameter to `Pattern` (and `Pat`) allows to manually tweak a
770pattern's benefit. Just supply `(addBenefit N)` to add `N` to the benefit value.
771
772## Rewrite directives
773
774### `location`
775
776By default the C++ pattern expanded from a DRR pattern uses the fused location
777of all source ops as the location for all generated ops. This is not always the
778best location mapping relationship. For such cases, DRR provides the `location`
779directive to provide finer control.
780
781`location` is of the following syntax:
782
783```tablegen
784(location $symbol0, $symbol1, ...)
785```
786
787where all `$symbol` should be bound previously in the pattern and one optional
788string may be specified as an attribute. The following locations are created:
789
790*   If only 1 symbol is specified then that symbol's location is used,
791*   If multiple are specified then a fused location is created;
792*   If no symbol is specified then string must be specified and a NamedLoc is
793    created instead;
794
795`location` must be used as a trailing argument to an op creation. For example,
796
797```tablegen
798def : Pat<(LocSrc1Op:$src1 (LocSrc2Op:$src2 ...),
799          (LocDst1Op (LocDst2Op ..., (location $src2)), (location "outer"))>;
800```
801
802In the above pattern, the generated `LocDst2Op` will use the matched location of
803`LocSrc2Op` while the root `LocDst1Op` node will used the named location
804`outer`.
805
806### `replaceWithValue`
807
808The `replaceWithValue` directive is used to eliminate a matched op by replacing
809all of its uses with a captured value. It is of the following syntax:
810
811```tablegen
812(replaceWithValue $symbol)
813```
814
815where `$symbol` should be a symbol bound previously in the pattern.
816
817For example,
818
819```tablegen
820def : Pat<(Foo $input), (replaceWithValue $input)>;
821```
822
823The above pattern removes the `Foo` and replaces all uses of `Foo` with
824`$input`.
825
826### `returnType`
827
828The `returnType` directive allows patterns to directly specify return types for
829replacement ops that lack return type inference with op traits or user-defined
830builders with return type deduction.
831
832The `returnType` directive must be used as a trailing argument to a node
833describing a replacement op. The directive comes in three forms:
834
835*   `(returnType $value)`: copy the type of the operand or result bound to
836    `value`.
837*   `(returnType "$_builder.getI32Type()")`: a string literal embedding C++. The
838    embedded snippet is expected to return a `Type` or a `TypeRange`.
839*   `(returnType (NativeCodeCall<"myFunc($0)"> $value))`: a DAG node with a
840    native code call that can be passed any bound variables arguments.
841
842Specify multiple return types with a mix of any of the above. Example:
843
844```tablegen
845def : Pat<(SourceOp $arg0, $arg1),
846          (OpA $arg0, (TwoResultOp:$res__1 $arg1,
847                         (returnType $arg1, "$_builder.getI64Type()")))>;
848```
849
850Explicitly-specified return types will take precedence over return types
851inferred from op traits or user-defined builders. The return types of values
852replacing root op results cannot be overridden.
853
854### `either`
855
856The `either` directive is used to specify the operands may be matched in either
857order.
858
859```tablegen
860def : Pat<(TwoArgOp (either $firstArg, (AnOp $secondArg))),
861          (...)>;
862```
863
864The above pattern will accept either `"test.TwoArgOp"(%I32Arg, %AnOpArg)` and
865`"test.TwoArgOp"(%AnOpArg, %I32Arg)`.
866
867Only operand is supported with `either` and note that an operation with
868`Commutative` trait doesn't imply that it'll have the same behavior than
869`either` while pattern matching.
870
871## Debugging Tips
872
873### Run `mlir-tblgen` to see the generated content
874
875TableGen syntax sometimes can be obscure; reading the generated content can be a
876very helpful way to understand and debug issues. To build `mlir-tblgen`, run
877`cmake --build . --target mlir-tblgen` in your build directory and find the
878`mlir-tblgen` binary in the `bin/` subdirectory. All the supported generators
879can be found via `mlir-tblgen --help`.
880
881To see the generated code, invoke `mlir-tblgen` with a specific generator by
882providing include paths via `-I`. For example,
883
884```sh
885# To see all the C++ pattern rewrite classes
886mlir-tblgen --gen-rewriters -I /path/to/mlir/include /path/to/input/td/file
887```
888
889### Compilation error: no matching member function for call to 'build'
890
891This is because DRR is failing to call a `build()` method with result type
892deduction ability. See [building operations](#building-operations) for more
893details.
894
895[TableGen]: https://llvm.org/docs/TableGen/index.html
896[OpBase]: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/OpBase.td
897