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