MLIR 24.0.0git
LoopCanonicalization.cpp
Go to the documentation of this file.
1//===- LoopCanonicalization.cpp - Cross-dialect canonicalization patterns -===//
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 contains cross-dialect canonicalization patterns that cannot be
10// actual canonicalization patterns due to undesired additional dependencies.
11//
12//===----------------------------------------------------------------------===//
13
15
24
25namespace mlir {
26#define GEN_PASS_DEF_SCFFORLOOPCANONICALIZATION
27#include "mlir/Dialect/SCF/Transforms/Passes.h.inc"
28} // namespace mlir
29
30using namespace mlir;
31using namespace mlir::scf;
32
33namespace {
34/// Fold dim ops of iter_args to dim ops of their respective init args. E.g.:
35///
36/// ```
37/// %0 = ... : tensor<?x?xf32>
38/// scf.for ... iter_args(%arg0 = %0) -> (tensor<?x?xf32>) {
39/// %1 = tensor.dim %arg0, %c0 : tensor<?x?xf32>
40/// ...
41/// }
42/// ```
43///
44/// is folded to:
45///
46/// ```
47/// %0 = ... : tensor<?x?xf32>
48/// scf.for ... iter_args(%arg0 = %0) -> (tensor<?x?xf32>) {
49/// %1 = tensor.dim %0, %c0 : tensor<?x?xf32>
50/// ...
51/// }
52/// ```
53///
54/// Note: Dim ops are folded only if it can be proven that the runtime type of
55/// the iter arg does not change with loop iterations.
56template <typename OpTy>
57struct DimOfIterArgFolder : public OpRewritePattern<OpTy> {
59
60 LogicalResult matchAndRewrite(OpTy dimOp,
61 PatternRewriter &rewriter) const override {
62 auto blockArg = dyn_cast<BlockArgument>(dimOp.getSource());
63 if (!blockArg)
64 return failure();
65 auto forOp = dyn_cast<ForOp>(blockArg.getParentBlock()->getParentOp());
66 if (!forOp)
67 return failure();
68 if (!isShapePreserving(forOp, blockArg.getArgNumber() - 1))
69 return failure();
70
71 Value initArg = forOp.getTiedLoopInit(blockArg)->get();
72 rewriter.modifyOpInPlace(
73 dimOp, [&]() { dimOp.getSourceMutable().assign(initArg); });
74
75 return success();
76 };
77};
78
79/// Fold dim ops of loop results to dim ops of their respective init args. E.g.:
80///
81/// ```
82/// %0 = ... : tensor<?x?xf32>
83/// %r = scf.for ... iter_args(%arg0 = %0) -> (tensor<?x?xf32>) {
84/// ...
85/// }
86/// %1 = tensor.dim %r, %c0 : tensor<?x?xf32>
87/// ```
88///
89/// is folded to:
90///
91/// ```
92/// %0 = ... : tensor<?x?xf32>
93/// %r = scf.for ... iter_args(%arg0 = %0) -> (tensor<?x?xf32>) {
94/// ...
95/// }
96/// %1 = tensor.dim %0, %c0 : tensor<?x?xf32>
97/// ```
98///
99/// Note: Dim ops are folded only if it can be proven that the runtime type of
100/// the iter arg does not change with loop iterations.
101template <typename OpTy>
102struct DimOfLoopResultFolder : public OpRewritePattern<OpTy> {
104
105 LogicalResult matchAndRewrite(OpTy dimOp,
106 PatternRewriter &rewriter) const override {
107 auto forOp = dimOp.getSource().template getDefiningOp<scf::ForOp>();
108 if (!forOp)
109 return failure();
110 auto opResult = cast<OpResult>(dimOp.getSource());
111 unsigned resultNumber = opResult.getResultNumber();
112 if (!isShapePreserving(forOp, resultNumber))
113 return failure();
114 rewriter.modifyOpInPlace(dimOp, [&]() {
115 dimOp.getSourceMutable().assign(forOp.getInitArgs()[resultNumber]);
116 });
117 return success();
118 }
119};
120
121/// Canonicalize AffineMinOp/AffineMaxOp operations in the context of scf.for
122/// and scf.parallel loops with a known range.
123template <typename OpTy>
124struct AffineOpSCFCanonicalizationPattern : public OpRewritePattern<OpTy> {
125 using OpRewritePattern<OpTy>::OpRewritePattern;
126
127 LogicalResult matchAndRewrite(OpTy op,
128 PatternRewriter &rewriter) const override {
130 }
131};
132
133struct SCFForLoopCanonicalization
134 : public impl::SCFForLoopCanonicalizationBase<SCFForLoopCanonicalization> {
135 void runOnOperation() override {
136 auto *parentOp = getOperation();
137 MLIRContext *ctx = parentOp->getContext();
138 RewritePatternSet patterns(ctx);
140 if (failed(applyPatternsGreedily(parentOp, std::move(patterns))))
141 signalPassFailure();
142 }
143};
144} // namespace
145
147 RewritePatternSet &patterns) {
148 MLIRContext *ctx = patterns.getContext();
149 patterns
150 .add<AffineOpSCFCanonicalizationPattern<affine::AffineMinOp>,
151 AffineOpSCFCanonicalizationPattern<affine::AffineMaxOp>,
152 DimOfIterArgFolder<tensor::DimOp>, DimOfIterArgFolder<memref::DimOp>,
153 DimOfLoopResultFolder<tensor::DimOp>,
154 DimOfLoopResultFolder<memref::DimOp>>(ctx);
155}
156
158 return std::make_unique<SCFForLoopCanonicalization>();
159}
return success()
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:853
LogicalResult matchForLikeLoop(Value iv, OpFoldResult &lb, OpFoldResult &ub, OpFoldResult &step)
Match "for loop"-like operations from the SCF dialect.
LogicalResult canonicalizeMinMaxOpInLoop(RewriterBase &rewriter, Operation *op, LoopMatcherFn loopMatcher)
Try to canonicalize the given affine.min/max operation in the context of for loops with a known range...
bool isShapePreserving(ForOp forOp, int64_t arg)
A simple, conservative analysis to determine if the loop is shape preserving.
Definition SCF.cpp:978
void populateSCFForLoopCanonicalizationPatterns(RewritePatternSet &patterns)
Populate patterns for canonicalizing operations inside SCF loop bodies.
Include the generated interface declarations.
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...
std::unique_ptr< Pass > createSCFForLoopCanonicalizationPass()
Creates a pass that canonicalizes affine.min and affine.max operations inside of scf....
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...