MLIR 23.0.0git
GreedyPatternRewriteDriver.h
Go to the documentation of this file.
1//===- GreedyPatternRewriteDriver.h - Greedy Pattern Driver -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file declares methods for applying a set of patterns greedily, choosing
10// the patterns with the highest local benefit, until a fixed point is reached.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_TRANSFORMS_GREEDYPATTERNREWRITEDRIVER_H_
15#define MLIR_TRANSFORMS_GREEDYPATTERNREWRITEDRIVER_H_
16
18
19namespace mlir {
20
21/// This enum controls which ops are put on the worklist during a greedy
22/// pattern rewrite.
24 /// No restrictions wrt. which ops are processed.
26 /// Only pre-existing and newly created ops are processed.
28 /// Only pre-existing ops are processed.
30};
31
33 /// Disable region control-flow simplification.
35 /// Run the normal simplification (e.g. dead args elimination).
37 /// Run extra simplificiations (e.g. block merging), these can be
38 /// more costly or have some tradeoffs associated.
40};
41
42/// This class allows control over how the GreedyPatternRewriteDriver works.
44public:
45 /// This specifies the order of initial traversal that populates the rewriters
46 /// worklist. When set to true, it walks the operations top-down, which is
47 /// generally more efficient in compile time. When set to false, its initial
48 /// traversal of the region tree is bottom up on each block, which may match
49 /// larger patterns when given an ambiguous pattern set.
50 ///
51 /// Note: Only applicable when simplifying entire regions.
52 bool getUseTopDownTraversal() const { return useTopDownTraversal; }
54 useTopDownTraversal = use;
55 return *this;
56 }
57
58 /// Perform control flow optimizations to the region tree after applying all
59 /// patterns.
60 ///
61 /// Note: Only applicable when simplifying entire regions.
63 return regionSimplificationLevel;
64 }
67 regionSimplificationLevel = level;
68 return *this;
69 }
70
71 /// This specifies the maximum number of times the rewriter will iterate
72 /// between applying patterns and simplifying regions. Use `kNoLimit` to
73 /// disable this iteration limit.
74 ///
75 /// Note: Only applicable when simplifying entire regions.
76 int64_t getMaxIterations() const { return maxIterations; }
78 maxIterations = iterations;
79 return *this;
80 }
81
82 /// This specifies the maximum number of rewrites within an iteration. Use
83 /// `kNoLimit` to disable this limit.
84 int64_t getMaxNumRewrites() const { return maxNumRewrites; }
86 maxNumRewrites = limit;
87 return *this;
88 }
89
90 static constexpr int64_t kNoLimit = -1;
91
92 /// Only ops within the scope are added to the worklist. If no scope is
93 /// specified, the closest enclosing region around the initial list of ops
94 /// (or the specified region, depending on which greedy rewrite entry point
95 /// is used) is used as a scope. Any region being simplified must be enclosed
96 /// by the scope (or equal to it).
97 Region *getScope() const { return scope; }
99 this->scope = scope;
100 return *this;
101 }
102
103 /// Strict mode can restrict the ops that are added to the worklist during
104 /// the rewrite.
105 ///
106 /// * GreedyRewriteStrictness::AnyOp: No ops are excluded.
107 /// * GreedyRewriteStrictness::ExistingAndNewOps: Only pre-existing ops (that
108 /// were on the worklist at the very beginning) and newly created ops are
109 /// enqueued. All other ops are excluded.
110 /// * GreedyRewriteStrictness::ExistingOps: Only pre-existing ops (that were
111 /// were on the worklist at the very beginning) enqueued. All other ops are
112 /// excluded.
113 GreedyRewriteStrictness getStrictness() const { return strictness; }
115 strictness = mode;
116 return *this;
117 }
118
119 /// An optional listener that should be notified about IR modifications.
120 RewriterBase::Listener *getListener() const { return listener; }
122 this->listener = listener;
123 return *this;
124 }
125
126 /// Whether this should fold while greedily rewriting.
127 bool isFoldingEnabled() const { return fold; }
128 GreedyRewriteConfig &enableFolding(bool enable = true) {
129 fold = enable;
130 return *this;
131 }
132
133 /// If set to "true", constants are CSE'd (even across multiple regions that
134 /// are in a parent-ancestor relationship).
135 bool isConstantCSEEnabled() const { return cseConstants; }
137 cseConstants = enable;
138 return *this;
139 }
140
141 /// If set to "true", full common-subexpression elimination is run on the
142 /// scoped region between each pattern-application iteration. Unlike
143 /// `cseConstants` (which only deduplicates constant ops via the operation
144 /// folder) this runs the standard CSE algorithm and can unblock further
145 /// canonicalizations on the next iteration. Off by default because it
146 /// rebuilds dominance info each iteration.
147 ///
148 /// Caveats when enabling this option:
149 /// - Any listener attached via `setListener` will be notified of
150 /// `notifyOperationReplaced` / `notifyOperationErased` events generated
151 /// by CSE. Pattern authors relying on operation identity (e.g., the
152 /// transform dialect's handle tracking) must account for this.
153 /// - CSE-driven changes feed back into the iteration loop: a pattern that
154 /// re-materializes duplicates that CSE keeps collapsing can extend the
155 /// iteration count and, in the worst case, hit `maxIterations`. Under
156 /// `testConvergence=true` such pipelines will be reported as
157 /// non-convergent.
158 bool isCSEBetweenIterationsEnabled() const { return cseBetweenIterations; }
160 cseBetweenIterations = enable;
161 return *this;
162 }
163
164private:
165 Region *scope = nullptr;
166 bool useTopDownTraversal = false;
167 GreedySimplifyRegionLevel regionSimplificationLevel =
169 int64_t maxIterations = 10;
170 int64_t maxNumRewrites = kNoLimit;
172 RewriterBase::Listener *listener = nullptr;
173 bool fold = true;
174 bool cseConstants = true;
175 bool cseBetweenIterations = false;
176};
177
178//===----------------------------------------------------------------------===//
179// applyPatternsGreedily
180//===----------------------------------------------------------------------===//
181
182/// Rewrite ops in the given region, which must be isolated from above, by
183/// repeatedly applying the highest benefit patterns in a greedy worklist
184/// driven manner until a fixpoint is reached.
185///
186/// The greedy rewrite may prematurely stop after a maximum number of
187/// iterations, which can be configured in the configuration parameter.
188///
189/// Also performs simple dead-code elimination before attempting to match any of
190/// the provided patterns.
191///
192/// A region scope can be set in the configuration parameter. By default, the
193/// scope is set to the specified region. Only in-scope ops are added to the
194/// worklist and only in-scope ops are allowed to be modified by the patterns.
195/// If a scope is set explicitly, it must enclose `region` (i.e., `region`
196/// must be nested within the scope, or equal to it).
197///
198/// Returns "success" if the iterative process converged (i.e., fixpoint was
199/// reached) and no more patterns can be matched within the region. `changed`
200/// is set to "true" if the IR was modified at all.
201///
202/// Note: This method does not apply patterns to the region's parent operation.
203LogicalResult
204applyPatternsGreedily(Region &region, const FrozenRewritePatternSet &patterns,
205 GreedyRewriteConfig config = GreedyRewriteConfig(),
206 bool *changed = nullptr);
207/// Rewrite ops nested under the given operation, which must be isolated from
208/// above, by repeatedly applying the highest benefit patterns in a greedy
209/// worklist driven manner until a fixpoint is reached.
210///
211/// The greedy rewrite may prematurely stop after a maximum number of
212/// iterations, which can be configured in the configuration parameter.
213///
214/// Also performs simple dead-code elimination before attempting to match any of
215/// the provided patterns.
216///
217/// This overload runs a separate greedy rewrite for each region of the
218/// specified op. A region scope can be set in the configuration parameter. By
219/// default, the scope is set to the region of the current greedy rewrite. Only
220/// in-scope ops are added to the worklist and only in-scope ops and the
221/// specified op itself are allowed to be modified by the patterns. If a scope
222/// is set explicitly, it must enclose `op` (i.e., `op` must be nested within
223/// the scope).
224///
225/// Note: The specified op may be modified, but it may not be removed by the
226/// patterns.
227///
228/// Returns "success" if the iterative process converged (i.e., fixpoint was
229/// reached) and no more patterns can be matched within the region. `changed`
230/// is set to "true" if the IR was modified at all.
231///
232/// Note: This method does not apply patterns to the given operation itself.
233inline LogicalResult
236 bool *changed = nullptr) {
237 bool anyRegionChanged = false;
238 bool failed = false;
239 for (Region &region : op->getRegions()) {
240 bool regionChanged;
241 failed |= applyPatternsGreedily(region, patterns, config, &regionChanged)
242 .failed();
243 anyRegionChanged |= regionChanged;
244 }
245 if (changed)
246 *changed = anyRegionChanged;
247 return failure(failed);
248}
249/// Rewrite the specified ops by repeatedly applying the highest benefit
250/// patterns in a greedy worklist driven manner until a fixpoint is reached.
251///
252/// The greedy rewrite may prematurely stop after a maximum number of
253/// iterations, which can be configured in the configuration parameter.
254///
255/// Also performs simple dead-code elimination before attempting to match any of
256/// the provided patterns.
257///
258/// Newly created ops and other pre-existing ops that use results of rewritten
259/// ops or supply operands to such ops are also processed, unless such ops are
260/// excluded via `config.strictMode`. Any other ops remain unmodified (i.e.,
261/// regardless of `strictMode`).
262///
263/// In addition to strictness, a region scope can be specified. Only ops within
264/// the scope are simplified. This is similar to `applyPatternsGreedily`,
265/// where only ops within the given region/op are simplified by default. If no
266/// scope is specified, it is assumed to be the first common enclosing region of
267/// the given ops.
268///
269/// Note that ops in `ops` could be erased as result of folding, becoming dead,
270/// or via pattern rewrites. If more far reaching simplification is desired,
271/// `applyPatternsGreedily` should be used.
272///
273/// Returns "success" if the iterative process converged (i.e., fixpoint was
274/// reached) and no more patterns can be matched. `changed` is set to "true" if
275/// the IR was modified at all. `allOpsErased` is set to "true" if all ops in
276/// `ops` were erased.
277LogicalResult
278applyOpPatternsGreedily(ArrayRef<Operation *> ops,
279 const FrozenRewritePatternSet &patterns,
280 GreedyRewriteConfig config = GreedyRewriteConfig(),
281 bool *changed = nullptr, bool *allErased = nullptr);
282} // namespace mlir
283
284#endif // MLIR_TRANSFORMS_GREEDYPATTERNREWRITEDRIVER_H_
This class represents a frozen set of patterns that can be processed by a pattern applicator.
This class allows control over how the GreedyPatternRewriteDriver works.
static constexpr int64_t kNoLimit
bool isFoldingEnabled() const
Whether this should fold while greedily rewriting.
GreedyRewriteConfig & setRegionSimplificationLevel(GreedySimplifyRegionLevel level)
RewriterBase::Listener * getListener() const
An optional listener that should be notified about IR modifications.
bool isConstantCSEEnabled() const
If set to "true", constants are CSE'd (even across multiple regions that are in a parent-ancestor rel...
Region * getScope() const
Only ops within the scope are added to the worklist.
GreedyRewriteConfig & enableConstantCSE(bool enable=true)
GreedyRewriteStrictness getStrictness() const
Strict mode can restrict the ops that are added to the worklist during the rewrite.
bool isCSEBetweenIterationsEnabled() const
If set to "true", full common-subexpression elimination is run on the scoped region between each patt...
bool getUseTopDownTraversal() const
This specifies the order of initial traversal that populates the rewriters worklist.
GreedyRewriteConfig & enableFolding(bool enable=true)
GreedyRewriteConfig & setScope(Region *scope)
GreedyRewriteConfig & setListener(RewriterBase::Listener *listener)
int64_t getMaxNumRewrites() const
This specifies the maximum number of rewrites within an iteration.
GreedyRewriteConfig & enableCSEBetweenIterations(bool enable=true)
GreedyRewriteConfig & setMaxIterations(int64_t iterations)
GreedyRewriteConfig & setMaxNumRewrites(int64_t limit)
int64_t getMaxIterations() const
This specifies the maximum number of times the rewriter will iterate between applying patterns and si...
GreedyRewriteConfig & setUseTopDownTraversal(bool use=true)
GreedySimplifyRegionLevel getRegionSimplificationLevel() const
Perform control flow optimizations to the region tree after applying all patterns.
GreedyRewriteConfig & setStrictness(GreedyRewriteStrictness mode)
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition Operation.h:703
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Include the generated interface declarations.
@ Aggressive
Run extra simplificiations (e.g.
@ Normal
Run the normal simplification (e.g. dead args elimination).
@ Disabled
Disable region control-flow simplification.
LogicalResult applyPatternsGreedily(Region &region, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
LogicalResult applyOpPatternsGreedily(ArrayRef< Operation * > ops, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr, bool *allErased=nullptr)
Rewrite the specified ops by repeatedly applying the highest benefit patterns in a greedy worklist dr...
GreedyRewriteStrictness
This enum controls which ops are put on the worklist during a greedy pattern rewrite.
@ ExistingOps
Only pre-existing ops are processed.
@ ExistingAndNewOps
Only pre-existing and newly created ops are processed.
@ AnyOp
No restrictions wrt. which ops are processed.