1f7a13479SRiver Riddle# Pattern Rewriting : Generic DAG-to-DAG Rewriting 2f7a13479SRiver Riddle 3f7a13479SRiver Riddle[TOC] 4f7a13479SRiver Riddle 5f7a13479SRiver RiddleThis document details the design and API of the pattern rewriting infrastructure 6f7a13479SRiver Riddlepresent in MLIR, a general DAG-to-DAG transformation framework. This framework 7f7a13479SRiver Riddleis widely used throughout MLIR for canonicalization, conversion, and general 8f7a13479SRiver Riddletransformation. 9f7a13479SRiver Riddle 10f7a13479SRiver RiddleFor an introduction to DAG-to-DAG transformation, and the rationale behind this 11f7a13479SRiver Riddleframework please take a look at the 12f7a13479SRiver Riddle[Generic DAG Rewriter Rationale](Rationale/RationaleGenericDAGRewriter.md). 13f7a13479SRiver Riddle 14f7a13479SRiver Riddle## Introduction 15f7a13479SRiver Riddle 16f7a13479SRiver RiddleThe pattern rewriting framework can largely be decomposed into two parts: 17f7a13479SRiver RiddlePattern Definition and Pattern Application. 18f7a13479SRiver Riddle 19f7a13479SRiver Riddle## Defining Patterns 20f7a13479SRiver Riddle 21f7a13479SRiver RiddlePatterns are defined by inheriting from the `RewritePattern` class. This class 22f7a13479SRiver Riddlerepresents the base class of all rewrite patterns within MLIR, and is comprised 23f7a13479SRiver Riddleof the following components: 24f7a13479SRiver Riddle 25f7a13479SRiver Riddle### Benefit 26f7a13479SRiver Riddle 27f7a13479SRiver RiddleThis is the expected benefit of applying a given pattern. This benefit is static 28f7a13479SRiver Riddleupon construction of the pattern, but may be computed dynamically at pattern 29f7a13479SRiver Riddleinitialization time, e.g. allowing the benefit to be derived from domain 30f7a13479SRiver Riddlespecific information (like the target architecture). This limitation allows for 31f7a13479SRiver Riddleperforming pattern fusion and compiling patterns into an efficient state 32f7a13479SRiver Riddlemachine, and 33f7a13479SRiver Riddle[Thier, Ertl, and Krall](https://dl.acm.org/citation.cfm?id=3179501) have shown 34f7a13479SRiver Riddlethat match predicates eliminate the need for dynamically computed costs in 35f7a13479SRiver Riddlealmost all cases: you can simply instantiate the same pattern one time for each 36f7a13479SRiver Riddlepossible cost and use the predicate to guard the match. 37f7a13479SRiver Riddle 38f7a13479SRiver Riddle### Root Operation Name (Optional) 39f7a13479SRiver Riddle 40f7a13479SRiver RiddleThe name of the root operation that this pattern matches against. If specified, 41f7a13479SRiver Riddleonly operations with the given root name will be provided to the `match` and 42f7a13479SRiver Riddle`rewrite` implementation. If not specified, any operation type may be provided. 43f7a13479SRiver RiddleThe root operation name should be provided whenever possible, because it 44f7a13479SRiver Riddlesimplifies the analysis of patterns when applying a cost model. To match any 45f7a13479SRiver Riddleoperation type, a special tag must be provided to make the intent explicit: 46f7a13479SRiver Riddle`MatchAnyOpTypeTag`. 47f7a13479SRiver Riddle 48f7a13479SRiver Riddle### `match` and `rewrite` implementation 49f7a13479SRiver Riddle 50f7a13479SRiver RiddleThis is the chunk of code that matches a given root `Operation` and performs a 51f7a13479SRiver Riddlerewrite of the IR. A `RewritePattern` can specify this implementation either via 52f7a13479SRiver Riddleseparate `match` and `rewrite` methods, or via a combined `matchAndRewrite` 53f7a13479SRiver Riddlemethod. When using the combined `matchAndRewrite` method, no IR mutation should 54f7a13479SRiver Riddletake place before the match is deemed successful. The combined `matchAndRewrite` 55f7a13479SRiver Riddleis useful when non-trivially recomputable information is required by the 56f7a13479SRiver Riddlematching and rewriting phase. See below for examples: 57f7a13479SRiver Riddle 58f7a13479SRiver Riddle```c++ 59f7a13479SRiver Riddleclass MyPattern : public RewritePattern { 60f7a13479SRiver Riddlepublic: 61f7a13479SRiver Riddle /// This overload constructs a pattern that only matches operations with the 62f7a13479SRiver Riddle /// root name of `MyOp`. 63f7a13479SRiver Riddle MyPattern(PatternBenefit benefit, MLIRContext *context) 64f7a13479SRiver Riddle : RewritePattern(MyOp::getOperationName(), benefit, context) {} 65f7a13479SRiver Riddle /// This overload constructs a pattern that matches any operation type. 66f7a13479SRiver Riddle MyPattern(PatternBenefit benefit) 67f7a13479SRiver Riddle : RewritePattern(benefit, MatchAnyOpTypeTag()) {} 68f7a13479SRiver Riddle 69f7a13479SRiver Riddle /// In this section, the `match` and `rewrite` implementation is specified 70f7a13479SRiver Riddle /// using the separate hooks. 71f7a13479SRiver Riddle LogicalResult match(Operation *op) const override { 72f7a13479SRiver Riddle // The `match` method returns `success()` if the pattern is a match, failure 73f7a13479SRiver Riddle // otherwise. 74f7a13479SRiver Riddle // ... 75f7a13479SRiver Riddle } 768c5a3a97SJefferson Le Quellec void rewrite(Operation *op, PatternRewriter &rewriter) const override { 77f7a13479SRiver Riddle // The `rewrite` method performs mutations on the IR rooted at `op` using 78f7a13479SRiver Riddle // the provided rewriter. All mutations must go through the provided 79f7a13479SRiver Riddle // rewriter. 80f7a13479SRiver Riddle } 81f7a13479SRiver Riddle 82f7a13479SRiver Riddle /// In this section, the `match` and `rewrite` implementation is specified 83f7a13479SRiver Riddle /// using a single hook. 848c5a3a97SJefferson Le Quellec LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) const override { 85f7a13479SRiver Riddle // The `matchAndRewrite` method performs both the matching and the mutation. 86f7a13479SRiver Riddle // Note that the match must reach a successful point before IR mutation may 87f7a13479SRiver Riddle // take place. 88f7a13479SRiver Riddle } 89f7a13479SRiver Riddle}; 90f7a13479SRiver Riddle``` 91f7a13479SRiver Riddle 92f7a13479SRiver Riddle#### Restrictions 93f7a13479SRiver Riddle 94f7a13479SRiver RiddleWithin the `match` section of a pattern, the following constraints apply: 95f7a13479SRiver Riddle 96f7a13479SRiver Riddle* No mutation of the IR is allowed. 97f7a13479SRiver Riddle 98f7a13479SRiver RiddleWithin the `rewrite` section of a pattern, the following constraints apply: 99f7a13479SRiver Riddle 100f7a13479SRiver Riddle* All IR mutations, including creation, *must* be performed by the given 101f7a13479SRiver Riddle `PatternRewriter`. This class provides hooks for performing all of the 102f7a13479SRiver Riddle possible mutations that may take place within a pattern. For example, this 103f7a13479SRiver Riddle means that an operation should not be erased via its `erase` method. To 104f7a13479SRiver Riddle erase an operation, the appropriate `PatternRewriter` hook (in this case 105f7a13479SRiver Riddle `eraseOp`) should be used instead. 106f7a13479SRiver Riddle* The root operation is required to either be: updated in-place, replaced, or 107f7a13479SRiver Riddle erased. 108f7a13479SRiver Riddle 10993cb71a4SRiver Riddle### Application Recursion 11093cb71a4SRiver Riddle 11193cb71a4SRiver RiddleRecursion is an important topic in the context of pattern rewrites, as a pattern 11293cb71a4SRiver Riddlemay often be applicable to its own result. For example, imagine a pattern that 11393cb71a4SRiver Riddlepeels a single iteration from a loop operation. If the loop has multiple 11493cb71a4SRiver Riddlepeelable iterations, this pattern may apply multiple times during the 11593cb71a4SRiver Riddleapplication process. By looking at the implementation of this pattern, the bound 11693cb71a4SRiver Riddlefor recursive application may be obvious, e.g. there are no peelable iterations 11793cb71a4SRiver Riddlewithin the loop, but from the perspective of the pattern driver this recursion 11893cb71a4SRiver Riddleis potentially dangerous. Often times the recursive application of a pattern 11993cb71a4SRiver Riddleindicates a bug in the matching logic. These types of bugs generally do not 12093cb71a4SRiver Riddlecause crashes, but create infinite loops within the application process. Given 12193cb71a4SRiver Riddlethis, the pattern rewriting infrastructure conservatively assumes that no 12293cb71a4SRiver Riddlepatterns have a proper bounded recursion, and will fail if recursion is 12393cb71a4SRiver Riddledetected. A pattern that is known to have proper support for handling recursion 12493cb71a4SRiver Riddlecan signal this by calling `setHasBoundedRewriteRecursion` when initializing the 12593cb71a4SRiver Riddlepattern. This will signal to the pattern driver that recursive application of 12693cb71a4SRiver Riddlethis pattern may happen, and the pattern is equipped to safely handle it. 12793cb71a4SRiver Riddle 1280289a269SRiver Riddle### Debug Names and Labels 1290289a269SRiver Riddle 1300289a269SRiver RiddleTo aid in debugging, patterns may specify: a debug name (via `setDebugName`), 1310289a269SRiver Riddlewhich should correspond to an identifier that uniquely identifies the specific 1320289a269SRiver Riddlepattern; and a set of debug labels (via `addDebugLabels`), which correspond to 1330289a269SRiver Riddleidentifiers that uniquely identify groups of patterns. This information is used 1340289a269SRiver Riddleby various utilities to aid in the debugging of pattern rewrites, e.g. in debug 1350289a269SRiver Riddlelogs, to provide pattern filtering, etc. A simple code example is shown below: 1360289a269SRiver Riddle 1370289a269SRiver Riddle```c++ 1380289a269SRiver Riddleclass MyPattern : public RewritePattern { 1390289a269SRiver Riddlepublic: 1400289a269SRiver Riddle /// Inherit constructors from RewritePattern. 1410289a269SRiver Riddle using RewritePattern::RewritePattern; 1420289a269SRiver Riddle 1430289a269SRiver Riddle void initialize() { 1440289a269SRiver Riddle setDebugName("MyPattern"); 1450289a269SRiver Riddle addDebugLabels("MyRewritePass"); 1460289a269SRiver Riddle } 1470289a269SRiver Riddle 1480289a269SRiver Riddle // ... 1490289a269SRiver Riddle}; 1500289a269SRiver Riddle 1510289a269SRiver Riddlevoid populateMyPatterns(RewritePatternSet &patterns, MLIRContext *ctx) { 1520289a269SRiver Riddle // Debug labels may also be attached to patterns during insertion. This allows 1530289a269SRiver Riddle // for easily attaching common labels to groups of patterns. 1540289a269SRiver Riddle patterns.addWithLabel<MyPattern, ...>("MyRewritePatterns", ctx); 1550289a269SRiver Riddle} 1560289a269SRiver Riddle``` 1570289a269SRiver Riddle 1582257e4a7SRiver Riddle### Initialization 1592257e4a7SRiver Riddle 1602257e4a7SRiver RiddleSeveral pieces of pattern state require explicit initialization by the pattern, 1612257e4a7SRiver Riddlefor example setting `setHasBoundedRewriteRecursion` if a pattern safely handles 1622257e4a7SRiver Riddlerecursive application. This pattern state can be initialized either in the 1632257e4a7SRiver Riddleconstructor of the pattern or via the utility `initialize` hook. Using the 1642257e4a7SRiver Riddle`initialize` hook removes the need to redefine pattern constructors just to 1652257e4a7SRiver Riddleinject additional pattern state initialization. An example is shown below: 1662257e4a7SRiver Riddle 1672257e4a7SRiver Riddle```c++ 1682257e4a7SRiver Riddleclass MyPattern : public RewritePattern { 1692257e4a7SRiver Riddlepublic: 1702257e4a7SRiver Riddle /// Inherit the constructors from RewritePattern. 1712257e4a7SRiver Riddle using RewritePattern::RewritePattern; 1722257e4a7SRiver Riddle 1732257e4a7SRiver Riddle /// Initialize the pattern. 1742257e4a7SRiver Riddle void initialize() { 1752257e4a7SRiver Riddle /// Signal that this pattern safely handles recursive application. 1762257e4a7SRiver Riddle setHasBoundedRewriteRecursion(); 1772257e4a7SRiver Riddle } 1782257e4a7SRiver Riddle 1792257e4a7SRiver Riddle // ... 1802257e4a7SRiver Riddle}; 1812257e4a7SRiver Riddle``` 1822257e4a7SRiver Riddle 1832257e4a7SRiver Riddle### Construction 1842257e4a7SRiver Riddle 1852257e4a7SRiver RiddleConstructing a RewritePattern should be performed by using the static 1862257e4a7SRiver Riddle`RewritePattern::create<T>` utility method. This method ensures that the pattern 1872257e4a7SRiver Riddleis properly initialized and prepared for insertion into a `RewritePatternSet`. 1882257e4a7SRiver Riddle 18993cb71a4SRiver Riddle## Pattern Rewriter 190f7a13479SRiver Riddle 191f7a13479SRiver RiddleA `PatternRewriter` is a special class that allows for a pattern to communicate 192f7a13479SRiver Riddlewith the driver of pattern application. As noted above, *all* IR mutations, 193f7a13479SRiver Riddleincluding creations, are required to be performed via the `PatternRewriter` 194f7a13479SRiver Riddleclass. This is required because the underlying pattern driver may have state 195f7a13479SRiver Riddlethat would be invalidated when a mutation takes place. Examples of some of the 196f7a13479SRiver Riddlemore prevalent `PatternRewriter` API is shown below, please refer to the 19794fac81fSxgupta[class documentation](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/PatternMatch.h#L235) 198f7a13479SRiver Riddlefor a more up-to-date listing of the available API: 199f7a13479SRiver Riddle 200f7a13479SRiver Riddle* Erase an Operation : `eraseOp` 201f7a13479SRiver Riddle 202f7a13479SRiver RiddleThis method erases an operation that either has no results, or whose results are 203f7a13479SRiver Riddleall known to have no uses. 204f7a13479SRiver Riddle 205f7a13479SRiver Riddle* Notify why a `match` failed : `notifyMatchFailure` 206f7a13479SRiver Riddle 207f7a13479SRiver RiddleThis method allows for providing a diagnostic message within a `matchAndRewrite` 208f7a13479SRiver Riddleas to why a pattern failed to match. How this message is displayed back to the 209f7a13479SRiver Riddleuser is determined by the specific pattern driver. 210f7a13479SRiver Riddle 211f7a13479SRiver Riddle* Replace an Operation : `replaceOp`/`replaceOpWithNewOp` 212f7a13479SRiver Riddle 213f7a13479SRiver RiddleThis method replaces an operation's results with a set of provided values, and 214f7a13479SRiver Riddleerases the operation. 215f7a13479SRiver Riddle 2165fcf907bSMatthias Springer* Update an Operation in-place : `(start|cancel|finalize)OpModification` 217f7a13479SRiver Riddle 218f7a13479SRiver RiddleThis is a collection of methods that provide a transaction-like API for updating 219f7a13479SRiver Riddlethe attributes, location, operands, or successors of an operation in-place 220f7a13479SRiver Riddlewithin a pattern. An in-place update transaction is started with 2215fcf907bSMatthias Springer`startOpModification`, and may either be canceled or finalized with 2225fcf907bSMatthias Springer`cancelOpModification` and `finalizeOpModification` respectively. A convenience 2235fcf907bSMatthias Springerwrapper, `modifyOpInPlace`, is provided that wraps a `start` and `finalize` 2245fcf907bSMatthias Springeraround a callback. 225f7a13479SRiver Riddle 226f7a13479SRiver Riddle* OpBuilder API 227f7a13479SRiver Riddle 228f7a13479SRiver RiddleThe `PatternRewriter` inherits from the `OpBuilder` class, and thus provides all 229f7a13479SRiver Riddleof the same functionality present within an `OpBuilder`. This includes operation 230f7a13479SRiver Riddlecreation, as well as many useful attribute and type construction methods. 231f7a13479SRiver Riddle 232f7a13479SRiver Riddle## Pattern Application 233f7a13479SRiver Riddle 234f7a13479SRiver RiddleAfter a set of patterns have been defined, they are collected and provided to a 235d356cdcfSPriyansh Singhspecific driver for application. A driver consists of several high level parts: 236f7a13479SRiver Riddle 237dc4e913bSChris Lattner* Input `RewritePatternSet` 238f7a13479SRiver Riddle 239f7a13479SRiver RiddleThe input patterns to a driver are provided in the form of an 240dc4e913bSChris Lattner`RewritePatternSet`. This class provides a simplified API for building a 241f7a13479SRiver Riddlelist of patterns. 242f7a13479SRiver Riddle 243f7a13479SRiver Riddle* Driver-specific `PatternRewriter` 244f7a13479SRiver Riddle 245f7a13479SRiver RiddleTo ensure that the driver state does not become invalidated by IR mutations 246f7a13479SRiver Riddlewithin the pattern rewriters, a driver must provide a `PatternRewriter` instance 247f7a13479SRiver Riddlewith the necessary hooks overridden. If a driver does not need to hook into 248f7a13479SRiver Riddlecertain mutations, a default implementation is provided that will perform the 249f7a13479SRiver Riddlemutation directly. 250f7a13479SRiver Riddle 251f7a13479SRiver Riddle* Pattern Application and Cost Model 252f7a13479SRiver Riddle 253f7a13479SRiver RiddleEach driver is responsible for defining its own operation visitation order as 254f7a13479SRiver Riddlewell as pattern cost model, but the final application is performed via a 255f7a13479SRiver Riddle`PatternApplicator` class. This class takes as input the 256dc4e913bSChris Lattner`RewritePatternSet` and transforms the patterns based upon a provided 257b99bd771SRiver Riddlecost model. This cost model computes a final benefit for a given pattern, using 258b99bd771SRiver Riddlewhatever driver specific information necessary. After a cost model has been 259b99bd771SRiver Riddlecomputed, the driver may begin to match patterns against operations using 260b99bd771SRiver Riddle`PatternApplicator::matchAndRewrite`. 261f7a13479SRiver Riddle 262f7a13479SRiver RiddleAn example is shown below: 263f7a13479SRiver Riddle 264f7a13479SRiver Riddle```c++ 265f7a13479SRiver Riddleclass MyPattern : public RewritePattern { 266f7a13479SRiver Riddlepublic: 267f7a13479SRiver Riddle MyPattern(PatternBenefit benefit, MLIRContext *context) 268f7a13479SRiver Riddle : RewritePattern(MyOp::getOperationName(), benefit, context) {} 269f7a13479SRiver Riddle}; 270f7a13479SRiver Riddle 271f7a13479SRiver Riddle/// Populate the pattern list. 272dc4e913bSChris Lattnervoid collectMyPatterns(RewritePatternSet &patterns, MLIRContext *ctx) { 273dc4e913bSChris Lattner patterns.add<MyPattern>(/*benefit=*/1, ctx); 274f7a13479SRiver Riddle} 275f7a13479SRiver Riddle 276f7a13479SRiver Riddle/// Define a custom PatternRewriter for use by the driver. 277f7a13479SRiver Riddleclass MyPatternRewriter : public PatternRewriter { 278f7a13479SRiver Riddlepublic: 279f7a13479SRiver Riddle MyPatternRewriter(MLIRContext *ctx) : PatternRewriter(ctx) {} 280f7a13479SRiver Riddle 281f7a13479SRiver Riddle /// Override the necessary PatternRewriter hooks here. 282f7a13479SRiver Riddle}; 283f7a13479SRiver Riddle 284f7a13479SRiver Riddle/// Apply the custom driver to `op`. 285f7a13479SRiver Riddlevoid applyMyPatternDriver(Operation *op, 286d4a7ca81SIngo Müller const FrozenRewritePatternSet &patterns) { 287f7a13479SRiver Riddle // Initialize the custom PatternRewriter. 288f7a13479SRiver Riddle MyPatternRewriter rewriter(op->getContext()); 289f7a13479SRiver Riddle 290f7a13479SRiver Riddle // Create the applicator and apply our cost model. 291f7a13479SRiver Riddle PatternApplicator applicator(patterns); 292b99bd771SRiver Riddle applicator.applyCostModel([](const Pattern &pattern) { 293f7a13479SRiver Riddle // Apply a default cost model. 294f7a13479SRiver Riddle // Note: This is just for demonstration, if the default cost model is truly 295f7a13479SRiver Riddle // desired `applicator.applyDefaultCostModel()` should be used 296f7a13479SRiver Riddle // instead. 297f7a13479SRiver Riddle return pattern.getBenefit(); 298f7a13479SRiver Riddle }); 299f7a13479SRiver Riddle 300f7a13479SRiver Riddle // Try to match and apply a pattern. 301f7a13479SRiver Riddle LogicalResult result = applicator.matchAndRewrite(op, rewriter); 302f7a13479SRiver Riddle if (failed(result)) { 303f7a13479SRiver Riddle // ... No patterns were applied. 304f7a13479SRiver Riddle } 305f7a13479SRiver Riddle // ... A pattern was successfully applied. 306f7a13479SRiver Riddle} 307f7a13479SRiver Riddle``` 308f7a13479SRiver Riddle 309f7a13479SRiver Riddle## Common Pattern Drivers 310f7a13479SRiver Riddle 311f7a13479SRiver RiddleMLIR provides several common pattern drivers that serve a variety of different 312f7a13479SRiver Riddleuse cases. 313f7a13479SRiver Riddle 314f7a13479SRiver Riddle### Dialect Conversion Driver 315f7a13479SRiver Riddle 316f7a13479SRiver RiddleThis driver provides a framework in which to perform operation conversions 317f7a13479SRiver Riddlebetween, and within dialects using a concept of "legality". This framework 318f7a13479SRiver Riddleallows for transforming illegal operations to those supported by a provided 319f7a13479SRiver Riddleconversion target, via a set of pattern-based operation rewriting patterns. This 320f7a13479SRiver Riddleframework also provides support for type conversions. More information on this 3219d2529a3Sergawydriver can be found [here](DialectConversion.md). 322f7a13479SRiver Riddle 3230f8a6b7dSJakub Kuderski### Walk Pattern Rewrite Driver 3240f8a6b7dSJakub Kuderski 3250f8a6b7dSJakub KuderskiThis is a fast and simple driver that walks the given op and applies patterns 3260f8a6b7dSJakub Kuderskithat locally have the most benefit. The benefit of a pattern is decided solely 3270f8a6b7dSJakub Kuderskiby the benefit specified on the pattern, and the relative order of the pattern 3280f8a6b7dSJakub Kuderskiwithin the pattern list (when two patterns have the same local benefit). 3290f8a6b7dSJakub Kuderski 3300f8a6b7dSJakub KuderskiThe driver performs a post-order traversal. Note that it walks regions of the 3310f8a6b7dSJakub Kuderskigiven op but does not visit the op. 3320f8a6b7dSJakub Kuderski 3330f8a6b7dSJakub KuderskiThis driver does not (re)visit modified or newly replaced ops, and does not 3340f8a6b7dSJakub Kuderskiallow for progressive rewrites of the same op. Op and block erasure is only 3350f8a6b7dSJakub Kuderskisupported for the currently matched op and its descendant. If your pattern 3360f8a6b7dSJakub Kuderskiset requires these, consider using the Greedy Pattern Rewrite Driver instead, 3370f8a6b7dSJakub Kuderskiat the expense of extra overhead. 3380f8a6b7dSJakub Kuderski 3390f8a6b7dSJakub KuderskiThis driver is exposed using the `walkAndApplyPatterns` function. 3400f8a6b7dSJakub Kuderski 3410f8a6b7dSJakub KuderskiNote: This driver listens for IR changes via the callbacks provided by 3420f8a6b7dSJakub Kuderski`RewriterBase`. It is important that patterns announce all IR changes to the 3430f8a6b7dSJakub Kuderskirewriter and do not bypass the rewriter API by modifying ops directly. 3440f8a6b7dSJakub Kuderski 3450f8a6b7dSJakub Kuderski#### Debugging 3460f8a6b7dSJakub Kuderski 3470f8a6b7dSJakub KuderskiYou can debug the Walk Pattern Rewrite Driver by passing the 3480f8a6b7dSJakub Kuderski`--debug-only=walk-rewriter` CLI flag. This will print the visited and matched 3490f8a6b7dSJakub Kuderskiops. 3500f8a6b7dSJakub Kuderski 351f7a13479SRiver Riddle### Greedy Pattern Rewrite Driver 352f7a13479SRiver Riddle 3539d5c63f6SMatthias SpringerThis driver processes ops in a worklist-driven fashion and greedily applies the 3540f8a6b7dSJakub Kuderskipatterns that locally have the most benefit (same as the Walk Pattern Rewrite 3550f8a6b7dSJakub KuderskiDriver). Patterns are iteratively applied to operations until a fixed point is 3560f8a6b7dSJakub Kuderskireached or until the configurable maximum number of iterations exhausted, at 3570f8a6b7dSJakub Kuderskiwhich point the driver finishes. 358f7a13479SRiver Riddle 3599d5c63f6SMatthias SpringerThis driver comes in two fashions: 3609d5c63f6SMatthias Springer 361*09dfc571SJacques Pienaar* `applyPatternsGreedily` ("region-based driver") applies patterns to 3629d5c63f6SMatthias Springer all ops in a given region or a given container op (but not the container op 3639d5c63f6SMatthias Springer itself). I.e., the worklist is initialized with all containing ops. 3649d5c63f6SMatthias Springer* `applyOpPatternsAndFold` ("op-based driver") applies patterns to the 3659d5c63f6SMatthias Springer provided list of operations. I.e., the worklist is initialized with the 3669d5c63f6SMatthias Springer specified list of ops. 3679d5c63f6SMatthias Springer 3689d5c63f6SMatthias SpringerThe driver is configurable via `GreedyRewriteConfig`. The region-based driver 3699d5c63f6SMatthias Springersupports two modes for populating the initial worklist: 3709d5c63f6SMatthias Springer 3719d5c63f6SMatthias Springer* Top-down traversal: Traverse the container op/region top down and in 3729d5c63f6SMatthias Springer pre-order. This is generally more efficient in compile time. 3739d5c63f6SMatthias Springer* Bottom-up traversal: This is the default setting. It builds the initial 3749d5c63f6SMatthias Springer worklist with a postorder traversal and then reverses the worklist. This may 375648f34a2SChris Lattner match larger patterns with ambiguous pattern sets. 376648f34a2SChris Lattner 3779d5c63f6SMatthias SpringerBy default, ops that were modified in-place and newly created are added back to 3789d5c63f6SMatthias Springerthe worklist. Ops that are outside of the configurable "scope" of the driver are 3799d5c63f6SMatthias Springernot added to the worklist. Furthermore, "strict mode" can exclude certain ops 3809d5c63f6SMatthias Springerfrom being added to the worklist throughout the rewrite process: 3819d5c63f6SMatthias Springer 3829d5c63f6SMatthias Springer* `GreedyRewriteStrictness::AnyOp`: No ops are excluded (apart from the ones 3839d5c63f6SMatthias Springer that are out of scope). 3849d5c63f6SMatthias Springer* `GreedyRewriteStrictness::ExistingAndNewOps`: Only pre-existing ops (with 3859d5c63f6SMatthias Springer which the worklist was initialized) and newly created ops are added to the 3869d5c63f6SMatthias Springer worklist. 3879d5c63f6SMatthias Springer* `GreedyRewriteStrictness::ExistingOps`: Only pre-existing ops (with which 3889d5c63f6SMatthias Springer the worklist was initialized) are added to the worklist. 3899d5c63f6SMatthias Springer 3909d5c63f6SMatthias SpringerNote: This driver listens for IR changes via the callbacks provided by 3919d5c63f6SMatthias Springer`RewriterBase`. It is important that patterns announce all IR changes to the 3929d5c63f6SMatthias Springerrewriter and do not bypass the rewriter API by modifying ops directly. 3939d5c63f6SMatthias Springer 394f7a13479SRiver RiddleNote: This driver is the one used by the [canonicalization](Canonicalization.md) 395267beb10Smlevesquedion[pass](Passes.md/#-canonicalize) in MLIR. 3960289a269SRiver Riddle 3970f8a6b7dSJakub Kuderski#### Debugging 3985652ecc3SRiver Riddle 3995652ecc3SRiver RiddleTo debug the execution of the greedy pattern rewrite driver, 4005652ecc3SRiver Riddle`-debug-only=greedy-rewriter` may be used. This command line flag activates 4015652ecc3SRiver RiddleLLVM's debug logging infrastructure solely for the greedy pattern rewriter. The 4025652ecc3SRiver Riddleoutput is formatted as a tree structure, mirroring the structure of the pattern 4035652ecc3SRiver Riddleapplication process. This output contains all of the actions performed by the 4045652ecc3SRiver Riddlerewriter, how operations get processed and patterns are applied, and why they 4055652ecc3SRiver Riddlefail. 4065652ecc3SRiver Riddle 4075652ecc3SRiver RiddleExample output is shown below: 4085652ecc3SRiver Riddle 4095652ecc3SRiver Riddle``` 4105652ecc3SRiver Riddle//===-------------------------------------------===// 411ace01605SRiver RiddleProcessing operation : 'cf.cond_br'(0x60f000001120) { 412363b6559SMehdi Amini "cf.cond_br"(%arg0)[^bb2, ^bb2] {operandSegmentSizes = array<i32: 1, 0, 0>} : (i1) -> () 4135652ecc3SRiver Riddle 414ace01605SRiver Riddle * Pattern SimplifyConstCondBranchPred : 'cf.cond_br -> ()' { 4155652ecc3SRiver Riddle } -> failure : pattern failed to match 4165652ecc3SRiver Riddle 417ace01605SRiver Riddle * Pattern SimplifyCondBranchIdenticalSuccessors : 'cf.cond_br -> ()' { 418ace01605SRiver Riddle ** Insert : 'cf.br'(0x60b000003690) 419ace01605SRiver Riddle ** Replace : 'cf.cond_br'(0x60f000001120) 4205652ecc3SRiver Riddle } -> success : pattern applied successfully 4215652ecc3SRiver Riddle} -> success : pattern matched 4225652ecc3SRiver Riddle//===-------------------------------------------===// 4235652ecc3SRiver Riddle``` 4245652ecc3SRiver Riddle 425ace01605SRiver RiddleThis output is describing the processing of a `cf.cond_br` operation. We first 4265652ecc3SRiver Riddletry to apply the `SimplifyConstCondBranchPred`, which fails. From there, another 4275652ecc3SRiver Riddlepattern (`SimplifyCondBranchIdenticalSuccessors`) is applied that matches the 428ace01605SRiver Riddle`cf.cond_br` and replaces it with a `cf.br`. 4295652ecc3SRiver Riddle 4300289a269SRiver Riddle## Debugging 4310289a269SRiver Riddle 4320289a269SRiver Riddle### Pattern Filtering 4330289a269SRiver Riddle 4340289a269SRiver RiddleTo simplify test case definition and reduction, the `FrozenRewritePatternSet` 4350289a269SRiver Riddleclass provides built-in support for filtering which patterns should be provided 4360289a269SRiver Riddleto the pattern driver for application. Filtering behavior is specified by 4370289a269SRiver Riddleproviding a `disabledPatterns` and `enabledPatterns` list when constructing the 4380289a269SRiver Riddle`FrozenRewritePatternSet`. The `disabledPatterns` list should contain a set of 4390289a269SRiver Riddledebug names or labels for patterns that are disabled during pattern application, 4400289a269SRiver Riddlei.e. which patterns should be filtered out. The `enabledPatterns` list should 4410289a269SRiver Riddlecontain a set of debug names or labels for patterns that are enabled during 4420289a269SRiver Riddlepattern application, patterns that do not satisfy this constraint are filtered 4430289a269SRiver Riddleout. Note that patterns specified by the `disabledPatterns` list will be 4440289a269SRiver Riddlefiltered out even if they match criteria in the `enabledPatterns` list. An 4450289a269SRiver Riddleexample is shown below: 4460289a269SRiver Riddle 4470289a269SRiver Riddle```c++ 4480289a269SRiver Riddlevoid MyPass::initialize(MLIRContext *context) { 4490289a269SRiver Riddle // No patterns are explicitly disabled. 4500289a269SRiver Riddle SmallVector<std::string> disabledPatterns; 4510289a269SRiver Riddle // Enable only patterns with a debug name or label of `MyRewritePatterns`. 4520289a269SRiver Riddle SmallVector<std::string> enabledPatterns(1, "MyRewritePatterns"); 4530289a269SRiver Riddle 4540289a269SRiver Riddle RewritePatternSet rewritePatterns(context); 4550289a269SRiver Riddle // ... 4560289a269SRiver Riddle frozenPatterns = FrozenRewritePatternSet(rewritePatterns, disabledPatterns, 4570289a269SRiver Riddle enabledPatterns); 4580289a269SRiver Riddle} 4590289a269SRiver Riddle``` 4600289a269SRiver Riddle 4610289a269SRiver Riddle### Common Pass Utilities 4620289a269SRiver Riddle 4630289a269SRiver RiddlePasses that utilize rewrite patterns should aim to provide a common set of 4640289a269SRiver Riddleoptions and toggles to simplify the debugging experience when switching between 4650289a269SRiver Riddledifferent passes/projects/etc. To aid in this endeavor, MLIR provides a common 4660289a269SRiver Riddleset of utilities that can be easily included when defining a custom pass. These 467d0b7633dSTimothy Hoffmanare defined in `mlir/Rewrite/PassUtil.td`; an example usage is shown below: 4680289a269SRiver Riddle 4690289a269SRiver Riddle```tablegen 4700289a269SRiver Riddledef MyRewritePass : Pass<"..."> { 4710289a269SRiver Riddle let summary = "..."; 4720289a269SRiver Riddle let constructor = "createMyRewritePass()"; 4730289a269SRiver Riddle 4740289a269SRiver Riddle // Inherit the common pattern rewrite options from `RewritePassUtils`. 4750289a269SRiver Riddle let options = RewritePassUtils.options; 4760289a269SRiver Riddle} 4770289a269SRiver Riddle``` 4780289a269SRiver Riddle 4790289a269SRiver Riddle#### Rewrite Pass Options 4800289a269SRiver Riddle 4810289a269SRiver RiddleThis section documents common pass options that are useful for controlling the 4820289a269SRiver Riddlebehavior of rewrite pattern application. 4830289a269SRiver Riddle 4840289a269SRiver Riddle##### Pattern Filtering 4850289a269SRiver Riddle 4860289a269SRiver RiddleTwo common pattern filtering options are exposed, `disable-patterns` and 4870289a269SRiver Riddle`enable-patterns`, matching the behavior of the `disabledPatterns` and 4880289a269SRiver Riddle`enabledPatterns` lists described in the [Pattern Filtering](#pattern-filtering) 4890289a269SRiver Riddlesection above. A snippet of the tablegen definition of these options is shown 4900289a269SRiver Riddlebelow: 4910289a269SRiver Riddle 4920289a269SRiver Riddle```tablegen 4930289a269SRiver RiddleListOption<"disabledPatterns", "disable-patterns", "std::string", 4946edef135SRiver Riddle "Labels of patterns that should be filtered out during application">, 4950289a269SRiver RiddleListOption<"enabledPatterns", "enable-patterns", "std::string", 4960289a269SRiver Riddle "Labels of patterns that should be used during application, all " 4976edef135SRiver Riddle "other patterns are filtered out">, 4980289a269SRiver Riddle``` 4990289a269SRiver Riddle 5000289a269SRiver RiddleThese options may be used to provide filtering behavior when constructing any 5010289a269SRiver Riddle`FrozenRewritePatternSet`s within the pass: 5020289a269SRiver Riddle 5030289a269SRiver Riddle```c++ 5040289a269SRiver Riddlevoid MyRewritePass::initialize(MLIRContext *context) { 5050289a269SRiver Riddle RewritePatternSet rewritePatterns(context); 5060289a269SRiver Riddle // ... 5070289a269SRiver Riddle 5080289a269SRiver Riddle // When constructing the `FrozenRewritePatternSet`, we provide the filter 5090289a269SRiver Riddle // list options. 5100289a269SRiver Riddle frozenPatterns = FrozenRewritePatternSet(rewritePatterns, disabledPatterns, 5110289a269SRiver Riddle enabledPatterns); 5120289a269SRiver Riddle} 5130289a269SRiver Riddle``` 514