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### Initialization
129
130Several pieces of pattern state require explicit initialization by the pattern,
131for example setting `setHasBoundedRewriteRecursion` if a pattern safely handles
132recursive application. This pattern state can be initialized either in the
133constructor of the pattern or via the utility `initialize` hook. Using the
134`initialize` hook removes the need to redefine pattern constructors just to
135inject additional pattern state initialization. An example is shown below:
136
137```c++
138class MyPattern : public RewritePattern {
139public:
140  /// Inherit the constructors from RewritePattern.
141  using RewritePattern::RewritePattern;
142
143  /// Initialize the pattern.
144  void initialize() {
145    /// Signal that this pattern safely handles recursive application.
146    setHasBoundedRewriteRecursion();
147  }
148
149  // ...
150};
151```
152
153### Construction
154
155Constructing a RewritePattern should be performed by using the static
156`RewritePattern::create<T>` utility method. This method ensures that the pattern
157is properly initialized and prepared for insertion into a `RewritePatternSet`.
158
159## Pattern Rewriter
160
161A `PatternRewriter` is a special class that allows for a pattern to communicate
162with the driver of pattern application. As noted above, *all* IR mutations,
163including creations, are required to be performed via the `PatternRewriter`
164class. This is required because the underlying pattern driver may have state
165that would be invalidated when a mutation takes place. Examples of some of the
166more prevalent `PatternRewriter` API is shown below, please refer to the
167[class documentation](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/PatternMatch.h#L235)
168for a more up-to-date listing of the available API:
169
170*   Erase an Operation : `eraseOp`
171
172This method erases an operation that either has no results, or whose results are
173all known to have no uses.
174
175*   Notify why a `match` failed : `notifyMatchFailure`
176
177This method allows for providing a diagnostic message within a `matchAndRewrite`
178as to why a pattern failed to match. How this message is displayed back to the
179user is determined by the specific pattern driver.
180
181*   Replace an Operation : `replaceOp`/`replaceOpWithNewOp`
182
183This method replaces an operation's results with a set of provided values, and
184erases the operation.
185
186*   Update an Operation in-place : `(start|cancel|finalize)RootUpdate`
187
188This is a collection of methods that provide a transaction-like API for updating
189the attributes, location, operands, or successors of an operation in-place
190within a pattern. An in-place update transaction is started with
191`startRootUpdate`, and may either be canceled or finalized with
192`cancelRootUpdate` and `finalizeRootUpdate` respectively. A convenience wrapper,
193`updateRootInPlace`, is provided that wraps a `start` and `finalize` around a
194callback.
195
196*   OpBuilder API
197
198The `PatternRewriter` inherits from the `OpBuilder` class, and thus provides all
199of the same functionality present within an `OpBuilder`. This includes operation
200creation, as well as many useful attribute and type construction methods.
201
202## Pattern Application
203
204After a set of patterns have been defined, they are collected and provided to a
205specific driver for application. A driver consists of several high levels parts:
206
207*   Input `RewritePatternSet`
208
209The input patterns to a driver are provided in the form of an
210`RewritePatternSet`. This class provides a simplified API for building a
211list of patterns.
212
213*   Driver-specific `PatternRewriter`
214
215To ensure that the driver state does not become invalidated by IR mutations
216within the pattern rewriters, a driver must provide a `PatternRewriter` instance
217with the necessary hooks overridden. If a driver does not need to hook into
218certain mutations, a default implementation is provided that will perform the
219mutation directly.
220
221*   Pattern Application and Cost Model
222
223Each driver is responsible for defining its own operation visitation order as
224well as pattern cost model, but the final application is performed via a
225`PatternApplicator` class. This class takes as input the
226`RewritePatternSet` and transforms the patterns based upon a provided
227cost model. This cost model computes a final benefit for a given pattern, using
228whatever driver specific information necessary. After a cost model has been
229computed, the driver may begin to match patterns against operations using
230`PatternApplicator::matchAndRewrite`.
231
232An example is shown below:
233
234```c++
235class MyPattern : public RewritePattern {
236public:
237  MyPattern(PatternBenefit benefit, MLIRContext *context)
238      : RewritePattern(MyOp::getOperationName(), benefit, context) {}
239};
240
241/// Populate the pattern list.
242void collectMyPatterns(RewritePatternSet &patterns, MLIRContext *ctx) {
243  patterns.add<MyPattern>(/*benefit=*/1, ctx);
244}
245
246/// Define a custom PatternRewriter for use by the driver.
247class MyPatternRewriter : public PatternRewriter {
248public:
249  MyPatternRewriter(MLIRContext *ctx) : PatternRewriter(ctx) {}
250
251  /// Override the necessary PatternRewriter hooks here.
252};
253
254/// Apply the custom driver to `op`.
255void applyMyPatternDriver(Operation *op,
256                          const RewritePatternSet &patterns) {
257  // Initialize the custom PatternRewriter.
258  MyPatternRewriter rewriter(op->getContext());
259
260  // Create the applicator and apply our cost model.
261  PatternApplicator applicator(patterns);
262  applicator.applyCostModel([](const Pattern &pattern) {
263    // Apply a default cost model.
264    // Note: This is just for demonstration, if the default cost model is truly
265    //       desired `applicator.applyDefaultCostModel()` should be used
266    //       instead.
267    return pattern.getBenefit();
268  });
269
270  // Try to match and apply a pattern.
271  LogicalResult result = applicator.matchAndRewrite(op, rewriter);
272  if (failed(result)) {
273    // ... No patterns were applied.
274  }
275  // ... A pattern was successfully applied.
276}
277```
278
279## Common Pattern Drivers
280
281MLIR provides several common pattern drivers that serve a variety of different
282use cases.
283
284### Dialect Conversion Driver
285
286This driver provides a framework in which to perform operation conversions
287between, and within dialects using a concept of "legality". This framework
288allows for transforming illegal operations to those supported by a provided
289conversion target, via a set of pattern-based operation rewriting patterns. This
290framework also provides support for type conversions. More information on this
291driver can be found [here](DialectConversion.md).
292
293### Greedy Pattern Rewrite Driver
294
295This driver walks the provided operations and greedily applies the patterns that
296locally have the most benefit. The benefit of
297a pattern is decided solely by the benefit specified on the pattern, and the
298relative order of the pattern within the pattern list (when two patterns have
299the same local benefit). Patterns are iteratively applied to operations until a
300fixed point is reached, at which point the driver finishes. This driver may be
301used via the following: `applyPatternsAndFoldGreedily` and
302`applyOpPatternsAndFold`. The latter of which only applies patterns to the
303provided operation, and will not traverse the IR.
304
305The driver is configurable and supports two modes: 1) you may opt-in to a
306"top-down" traversal, which seeds the worklist with each operation top down and
307in a pre-order over the region tree.  This is generally more efficient in
308compile time.  2) the default is a "bottom up" traversal, which builds the
309initial worklist with a postorder traversal of the region tree.  This may
310match larger patterns with ambiguous pattern sets.
311
312Note: This driver is the one used by the [canonicalization](Canonicalization.md)
313[pass](Passes.md/#-canonicalize-canonicalize-operations) in MLIR.
314