xref: /llvm-project/mlir/docs/PatternRewriter.md (revision 09dfc5713d7e2342bea4c8447d1ed76c85eb8225)
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