1# Pattern Rewriting : Generic DAG-to-DAG Rewriting
2
3[TOC]
4
5This document details the design and API of the pattern rewriting infrastructure
6present in MLIR, a general DAG-to-DAG transformation framework. This framework
7is widely used throughout MLIR for canonicalization, conversion, and general
8transformation.
9
10For an introduction to DAG-to-DAG transformation, and the rationale behind this
11framework please take a look at the
12[Generic DAG Rewriter Rationale](Rationale/RationaleGenericDAGRewriter.md).
13
14## Introduction
15
16The pattern rewriting framework can largely be decomposed into two parts:
17Pattern Definition and Pattern Application.
18
19## Defining Patterns
20
21Patterns are defined by inheriting from the `RewritePattern` class. This class
22represents the base class of all rewrite patterns within MLIR, and is comprised
23of the following components:
24
25### Benefit
26
27This is the expected benefit of applying a given pattern. This benefit is static
28upon construction of the pattern, but may be computed dynamically at pattern
29initialization time, e.g. allowing the benefit to be derived from domain
30specific information (like the target architecture). This limitation allows for
31performing pattern fusion and compiling patterns into an efficient state
32machine, and
33[Thier, Ertl, and Krall](https://dl.acm.org/citation.cfm?id=3179501) have shown
34that match predicates eliminate the need for dynamically computed costs in
35almost all cases: you can simply instantiate the same pattern one time for each
36possible cost and use the predicate to guard the match.
37
38### Root Operation Name (Optional)
39
40The name of the root operation that this pattern matches against. If specified,
41only operations with the given root name will be provided to the `match` and
42`rewrite` implementation. If not specified, any operation type may be provided.
43The root operation name should be provided whenever possible, because it
44simplifies the analysis of patterns when applying a cost model. To match any
45operation type, a special tag must be provided to make the intent explicit:
46`MatchAnyOpTypeTag`.
47
48### `match` and `rewrite` implementation
49
50This is the chunk of code that matches a given root `Operation` and performs a
51rewrite of the IR. A `RewritePattern` can specify this implementation either via
52separate `match` and `rewrite` methods, or via a combined `matchAndRewrite`
53method. When using the combined `matchAndRewrite` method, no IR mutation should
54take place before the match is deemed successful. The combined `matchAndRewrite`
55is useful when non-trivially recomputable information is required by the
56matching and rewriting phase. See below for examples:
57
58```c++
59class MyPattern : public RewritePattern {
60public:
61  /// This overload constructs a pattern that only matches operations with the
62  /// root name of `MyOp`.
63  MyPattern(PatternBenefit benefit, MLIRContext *context)
64      : RewritePattern(MyOp::getOperationName(), benefit, context) {}
65  /// This overload constructs a pattern that matches any operation type.
66  MyPattern(PatternBenefit benefit)
67      : RewritePattern(benefit, MatchAnyOpTypeTag()) {}
68
69  /// In this section, the `match` and `rewrite` implementation is specified
70  /// using the separate hooks.
71  LogicalResult match(Operation *op) const override {
72    // The `match` method returns `success()` if the pattern is a match, failure
73    // otherwise.
74    // ...
75  }
76  void rewrite(Operation *op, PatternRewriter &rewriter) {
77    // The `rewrite` method performs mutations on the IR rooted at `op` using
78    // the provided rewriter. All mutations must go through the provided
79    // rewriter.
80  }
81
82  /// In this section, the `match` and `rewrite` implementation is specified
83  /// using a single hook.
84  LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) {
85    // The `matchAndRewrite` method performs both the matching and the mutation.
86    // Note that the match must reach a successful point before IR mutation may
87    // take place.
88  }
89};
90```
91
92#### Restrictions
93
94Within the `match` section of a pattern, the following constraints apply:
95
96*   No mutation of the IR is allowed.
97
98Within the `rewrite` section of a pattern, the following constraints apply:
99
100*   All IR mutations, including creation, *must* be performed by the given
101    `PatternRewriter`. This class provides hooks for performing all of the
102    possible mutations that may take place within a pattern. For example, this
103    means that an operation should not be erased via its `erase` method. To
104    erase an operation, the appropriate `PatternRewriter` hook (in this case
105    `eraseOp`) should be used instead.
106*   The root operation is required to either be: updated in-place, replaced, or
107    erased.
108
109### Application Recursion
110
111Recursion is an important topic in the context of pattern rewrites, as a pattern
112may often be applicable to its own result. For example, imagine a pattern that
113peels a single iteration from a loop operation. If the loop has multiple
114peelable iterations, this pattern may apply multiple times during the
115application process. By looking at the implementation of this pattern, the bound
116for recursive application may be obvious, e.g. there are no peelable iterations
117within the loop, but from the perspective of the pattern driver this recursion
118is potentially dangerous. Often times the recursive application of a pattern
119indicates a bug in the matching logic. These types of bugs generally do not
120cause crashes, but create infinite loops within the application process. Given
121this, the pattern rewriting infrastructure conservatively assumes that no
122patterns have a proper bounded recursion, and will fail if recursion is
123detected. A pattern that is known to have proper support for handling recursion
124can signal this by calling `setHasBoundedRewriteRecursion` when initializing the
125pattern. This will signal to the pattern driver that recursive application of
126this pattern may happen, and the pattern is equipped to safely handle it.
127
128### Debug Names and Labels
129
130To aid in debugging, patterns may specify: a debug name (via `setDebugName`),
131which should correspond to an identifier that uniquely identifies the specific
132pattern; and a set of debug labels (via `addDebugLabels`), which correspond to
133identifiers that uniquely identify groups of patterns. This information is used
134by various utilities to aid in the debugging of pattern rewrites, e.g. in debug
135logs, to provide pattern filtering, etc. A simple code example is shown below:
136
137```c++
138class MyPattern : public RewritePattern {
139public:
140  /// Inherit constructors from RewritePattern.
141  using RewritePattern::RewritePattern;
142
143  void initialize() {
144    setDebugName("MyPattern");
145    addDebugLabels("MyRewritePass");
146  }
147
148  // ...
149};
150
151void populateMyPatterns(RewritePatternSet &patterns, MLIRContext *ctx) {
152  // Debug labels may also be attached to patterns during insertion. This allows
153  // for easily attaching common labels to groups of patterns.
154  patterns.addWithLabel<MyPattern, ...>("MyRewritePatterns", ctx);
155}
156```
157
158### Initialization
159
160Several pieces of pattern state require explicit initialization by the pattern,
161for example setting `setHasBoundedRewriteRecursion` if a pattern safely handles
162recursive application. This pattern state can be initialized either in the
163constructor of the pattern or via the utility `initialize` hook. Using the
164`initialize` hook removes the need to redefine pattern constructors just to
165inject additional pattern state initialization. An example is shown below:
166
167```c++
168class MyPattern : public RewritePattern {
169public:
170  /// Inherit the constructors from RewritePattern.
171  using RewritePattern::RewritePattern;
172
173  /// Initialize the pattern.
174  void initialize() {
175    /// Signal that this pattern safely handles recursive application.
176    setHasBoundedRewriteRecursion();
177  }
178
179  // ...
180};
181```
182
183### Construction
184
185Constructing a RewritePattern should be performed by using the static
186`RewritePattern::create<T>` utility method. This method ensures that the pattern
187is properly initialized and prepared for insertion into a `RewritePatternSet`.
188
189## Pattern Rewriter
190
191A `PatternRewriter` is a special class that allows for a pattern to communicate
192with the driver of pattern application. As noted above, *all* IR mutations,
193including creations, are required to be performed via the `PatternRewriter`
194class. This is required because the underlying pattern driver may have state
195that would be invalidated when a mutation takes place. Examples of some of the
196more prevalent `PatternRewriter` API is shown below, please refer to the
197[class documentation](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/PatternMatch.h#L235)
198for a more up-to-date listing of the available API:
199
200*   Erase an Operation : `eraseOp`
201
202This method erases an operation that either has no results, or whose results are
203all known to have no uses.
204
205*   Notify why a `match` failed : `notifyMatchFailure`
206
207This method allows for providing a diagnostic message within a `matchAndRewrite`
208as to why a pattern failed to match. How this message is displayed back to the
209user is determined by the specific pattern driver.
210
211*   Replace an Operation : `replaceOp`/`replaceOpWithNewOp`
212
213This method replaces an operation's results with a set of provided values, and
214erases the operation.
215
216*   Update an Operation in-place : `(start|cancel|finalize)RootUpdate`
217
218This is a collection of methods that provide a transaction-like API for updating
219the attributes, location, operands, or successors of an operation in-place
220within a pattern. An in-place update transaction is started with
221`startRootUpdate`, and may either be canceled or finalized with
222`cancelRootUpdate` and `finalizeRootUpdate` respectively. A convenience wrapper,
223`updateRootInPlace`, is provided that wraps a `start` and `finalize` around a
224callback.
225
226*   OpBuilder API
227
228The `PatternRewriter` inherits from the `OpBuilder` class, and thus provides all
229of the same functionality present within an `OpBuilder`. This includes operation
230creation, as well as many useful attribute and type construction methods.
231
232## Pattern Application
233
234After a set of patterns have been defined, they are collected and provided to a
235specific driver for application. A driver consists of several high level parts:
236
237*   Input `RewritePatternSet`
238
239The input patterns to a driver are provided in the form of an
240`RewritePatternSet`. This class provides a simplified API for building a
241list of patterns.
242
243*   Driver-specific `PatternRewriter`
244
245To ensure that the driver state does not become invalidated by IR mutations
246within the pattern rewriters, a driver must provide a `PatternRewriter` instance
247with the necessary hooks overridden. If a driver does not need to hook into
248certain mutations, a default implementation is provided that will perform the
249mutation directly.
250
251*   Pattern Application and Cost Model
252
253Each driver is responsible for defining its own operation visitation order as
254well as pattern cost model, but the final application is performed via a
255`PatternApplicator` class. This class takes as input the
256`RewritePatternSet` and transforms the patterns based upon a provided
257cost model. This cost model computes a final benefit for a given pattern, using
258whatever driver specific information necessary. After a cost model has been
259computed, the driver may begin to match patterns against operations using
260`PatternApplicator::matchAndRewrite`.
261
262An example is shown below:
263
264```c++
265class MyPattern : public RewritePattern {
266public:
267  MyPattern(PatternBenefit benefit, MLIRContext *context)
268      : RewritePattern(MyOp::getOperationName(), benefit, context) {}
269};
270
271/// Populate the pattern list.
272void collectMyPatterns(RewritePatternSet &patterns, MLIRContext *ctx) {
273  patterns.add<MyPattern>(/*benefit=*/1, ctx);
274}
275
276/// Define a custom PatternRewriter for use by the driver.
277class MyPatternRewriter : public PatternRewriter {
278public:
279  MyPatternRewriter(MLIRContext *ctx) : PatternRewriter(ctx) {}
280
281  /// Override the necessary PatternRewriter hooks here.
282};
283
284/// Apply the custom driver to `op`.
285void applyMyPatternDriver(Operation *op,
286                          const FrozenRewritePatternSet &patterns) {
287  // Initialize the custom PatternRewriter.
288  MyPatternRewriter rewriter(op->getContext());
289
290  // Create the applicator and apply our cost model.
291  PatternApplicator applicator(patterns);
292  applicator.applyCostModel([](const Pattern &pattern) {
293    // Apply a default cost model.
294    // Note: This is just for demonstration, if the default cost model is truly
295    //       desired `applicator.applyDefaultCostModel()` should be used
296    //       instead.
297    return pattern.getBenefit();
298  });
299
300  // Try to match and apply a pattern.
301  LogicalResult result = applicator.matchAndRewrite(op, rewriter);
302  if (failed(result)) {
303    // ... No patterns were applied.
304  }
305  // ... A pattern was successfully applied.
306}
307```
308
309## Common Pattern Drivers
310
311MLIR provides several common pattern drivers that serve a variety of different
312use cases.
313
314### Dialect Conversion Driver
315
316This driver provides a framework in which to perform operation conversions
317between, and within dialects using a concept of "legality". This framework
318allows for transforming illegal operations to those supported by a provided
319conversion target, via a set of pattern-based operation rewriting patterns. This
320framework also provides support for type conversions. More information on this
321driver can be found [here](DialectConversion.md).
322
323### Greedy Pattern Rewrite Driver
324
325This driver walks the provided operations and greedily applies the patterns that
326locally have the most benefit. The benefit of
327a pattern is decided solely by the benefit specified on the pattern, and the
328relative order of the pattern within the pattern list (when two patterns have
329the same local benefit). Patterns are iteratively applied to operations until a
330fixed point is reached, at which point the driver finishes. This driver may be
331used via the following: `applyPatternsAndFoldGreedily` and
332`applyOpPatternsAndFold`. The latter of which only applies patterns to the
333provided operation, and will not traverse the IR.
334
335The driver is configurable and supports two modes: 1) you may opt-in to a
336"top-down" traversal, which seeds the worklist with each operation top down and
337in a pre-order over the region tree.  This is generally more efficient in
338compile time.  2) the default is a "bottom up" traversal, which builds the
339initial worklist with a postorder traversal of the region tree.  This may
340match larger patterns with ambiguous pattern sets.
341
342Note: This driver is the one used by the [canonicalization](Canonicalization.md)
343[pass](Passes.md/#-canonicalize-canonicalize-operations) in MLIR.
344
345### Debugging
346
347To debug the execution of the greedy pattern rewrite driver,
348`-debug-only=greedy-rewriter` may be used. This command line flag activates
349LLVM's debug logging infrastructure solely for the greedy pattern rewriter. The
350output is formatted as a tree structure, mirroring the structure of the pattern
351application process. This output contains all of the actions performed by the
352rewriter, how operations get processed and patterns are applied, and why they
353fail.
354
355Example output is shown below:
356
357```
358//===-------------------------------------------===//
359Processing operation : 'cf.cond_br'(0x60f000001120) {
360  "cf.cond_br"(%arg0)[^bb2, ^bb2] {operand_segment_sizes = dense<[1, 0, 0]> : vector<3xi32>} : (i1) -> ()
361
362  * Pattern SimplifyConstCondBranchPred : 'cf.cond_br -> ()' {
363  } -> failure : pattern failed to match
364
365  * Pattern SimplifyCondBranchIdenticalSuccessors : 'cf.cond_br -> ()' {
366    ** Insert  : 'cf.br'(0x60b000003690)
367    ** Replace : 'cf.cond_br'(0x60f000001120)
368  } -> success : pattern applied successfully
369} -> success : pattern matched
370//===-------------------------------------------===//
371```
372
373This output is describing the processing of a `cf.cond_br` operation. We first
374try to apply the `SimplifyConstCondBranchPred`, which fails. From there, another
375pattern (`SimplifyCondBranchIdenticalSuccessors`) is applied that matches the
376`cf.cond_br` and replaces it with a `cf.br`.
377
378## Debugging
379
380### Pattern Filtering
381
382To simplify test case definition and reduction, the `FrozenRewritePatternSet`
383class provides built-in support for filtering which patterns should be provided
384to the pattern driver for application. Filtering behavior is specified by
385providing a `disabledPatterns` and `enabledPatterns` list when constructing the
386`FrozenRewritePatternSet`. The `disabledPatterns` list should contain a set of
387debug names or labels for patterns that are disabled during pattern application,
388i.e. which patterns should be filtered out. The `enabledPatterns` list should
389contain a set of debug names or labels for patterns that are enabled during
390pattern application, patterns that do not satisfy this constraint are filtered
391out. Note that patterns specified by the `disabledPatterns` list will be
392filtered out even if they match criteria in the `enabledPatterns` list. An
393example is shown below:
394
395```c++
396void MyPass::initialize(MLIRContext *context) {
397  // No patterns are explicitly disabled.
398  SmallVector<std::string> disabledPatterns;
399  // Enable only patterns with a debug name or label of `MyRewritePatterns`.
400  SmallVector<std::string> enabledPatterns(1, "MyRewritePatterns");
401
402  RewritePatternSet rewritePatterns(context);
403  // ...
404  frozenPatterns = FrozenRewritePatternSet(rewritePatterns, disabledPatterns,
405                                           enabledPatterns);
406}
407```
408
409### Common Pass Utilities
410
411Passes that utilize rewrite patterns should aim to provide a common set of
412options and toggles to simplify the debugging experience when switching between
413different passes/projects/etc. To aid in this endeavor, MLIR provides a common
414set of utilities that can be easily included when defining a custom pass. These
415are defined in `mlir/RewritePassUtil.td`; an example usage is shown below:
416
417```tablegen
418def MyRewritePass : Pass<"..."> {
419  let summary = "...";
420  let constructor = "createMyRewritePass()";
421
422  // Inherit the common pattern rewrite options from `RewritePassUtils`.
423  let options = RewritePassUtils.options;
424}
425```
426
427#### Rewrite Pass Options
428
429This section documents common pass options that are useful for controlling the
430behavior of rewrite pattern application.
431
432##### Pattern Filtering
433
434Two common pattern filtering options are exposed, `disable-patterns` and
435`enable-patterns`, matching the behavior of the `disabledPatterns` and
436`enabledPatterns` lists described in the [Pattern Filtering](#pattern-filtering)
437section above. A snippet of the tablegen definition of these options is shown
438below:
439
440```tablegen
441ListOption<"disabledPatterns", "disable-patterns", "std::string",
442           "Labels of patterns that should be filtered out during application">,
443ListOption<"enabledPatterns", "enable-patterns", "std::string",
444           "Labels of patterns that should be used during application, all "
445           "other patterns are filtered out">,
446```
447
448These options may be used to provide filtering behavior when constructing any
449`FrozenRewritePatternSet`s within the pass:
450
451```c++
452void MyRewritePass::initialize(MLIRContext *context) {
453  RewritePatternSet rewritePatterns(context);
454  // ...
455
456  // When constructing the `FrozenRewritePatternSet`, we provide the filter
457  // list options.
458  frozenPatterns = FrozenRewritePatternSet(rewritePatterns, disabledPatterns,
459                                           enabledPatterns);
460}
461```
462