blob: 78d8fd2c89b65e3411296a2d40a81b992b7b1459 [file] [log] [blame]
Alex Zinenko971b8dd2019-11-14 18:34:461//===- AffineToStandard.cpp - Lower affine constructs to primitives -------===//
Chris Lattnerae618422018-12-31 00:22:502//
Mehdi Amini30857102020-01-26 03:58:303// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
Mehdi Amini56222a02019-12-23 17:35:364// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Chris Lattnerae618422018-12-31 00:22:506//
Mehdi Amini56222a02019-12-23 17:35:367//===----------------------------------------------------------------------===//
Chris Lattnerae618422018-12-31 00:22:508//
Alex Zinenko0c4ee542019-01-02 20:52:419// This file lowers affine constructs (If and For statements, AffineApply
Nicolas Vasilachecab671d2019-07-12 13:48:4510// operations) within a function into their standard If and For equivalent ops.
Chris Lattnerae618422018-12-31 00:22:5011//
12//===----------------------------------------------------------------------===//
13
Alex Zinenko971b8dd2019-11-14 18:34:4614#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"
15
River Riddle1834ad4a2020-04-07 20:58:1216#include "../PassDetail.h"
Rob Sudermane7084712020-03-20 21:18:4717#include "mlir/Dialect/Affine/IR/AffineOps.h"
Uday Bondhugula8d12bf42022-02-10 04:26:1018#include "mlir/Dialect/Affine/Utils.h"
River Riddle23aa5a72022-02-26 22:49:5419#include "mlir/Dialect/Func/IR/FuncOps.h"
Julian Grosse2310702021-02-10 12:53:1120#include "mlir/Dialect/MemRef/IR/MemRef.h"
Alex Zinenkoc25b20c2020-05-11 13:00:4821#include "mlir/Dialect/SCF/SCF.h"
Matthias Springer99ef9ee2022-01-31 10:10:5122#include "mlir/Dialect/Vector/IR/VectorOps.h"
Alex Zinenko8ad35b92019-06-11 15:33:1823#include "mlir/IR/BlockAndValueMapping.h"
River Riddle5052bd82019-02-02 00:42:1824#include "mlir/IR/IntegerSet.h"
Alex Zinenko0c4ee542019-01-02 20:52:4125#include "mlir/IR/MLIRContext.h"
River Riddle48ccae22019-02-20 01:17:4626#include "mlir/Pass/Pass.h"
Alex Zinenko8ad35b92019-06-11 15:33:1827#include "mlir/Transforms/DialectConversion.h"
Chris Lattnerae618422018-12-31 00:22:5028#include "mlir/Transforms/Passes.h"
Alex Zinenko8ad35b92019-06-11 15:33:1829
Chris Lattnerae618422018-12-31 00:22:5030using namespace mlir;
Diego Caballerobc5565f2020-05-14 19:05:4631using namespace mlir::vector;
Chris Lattnerae618422018-12-31 00:22:5032
Alex Zinenko6895a1c2020-01-28 09:21:1233/// Given a range of values, emit the code that reduces them with "min" or "max"
34/// depending on the provided comparison predicate. The predicate defines which
35/// comparison to perform, "lt" for "min", "gt" for "max" and is used for the
36/// `cmpi` operation followed by the `select` operation:
37///
Mogballa54f4ea2021-10-12 23:14:5738/// %cond = arith.cmpi "predicate" %v0, %v1
Alex Zinenko6895a1c2020-01-28 09:21:1239/// %result = select %cond, %v0, %v1
40///
41/// Multiple values are scanned in a linear sequence. This creates a data
42/// dependences that wouldn't exist in a tree reduction, but is easier to
43/// recognize as a reduction by the subsequent passes.
Mogballa54f4ea2021-10-12 23:14:5744static Value buildMinMaxReductionSeq(Location loc,
45 arith::CmpIPredicate predicate,
Alex Zinenko8ed47b72020-01-28 10:53:0046 ValueRange values, OpBuilder &builder) {
Chris Lattnerae618422018-12-31 00:22:5047 assert(!llvm::empty(values) && "empty min/max chain");
48
49 auto valueIt = values.begin();
River Riddlee62a6952019-12-23 22:45:0150 Value value = *valueIt++;
Chris Lattnerae618422018-12-31 00:22:5051 for (; valueIt != values.end(); ++valueIt) {
Mogballa54f4ea2021-10-12 23:14:5752 auto cmpOp = builder.create<arith::CmpIOp>(loc, predicate, value, *valueIt);
River Riddledec8af72022-01-31 20:44:3553 value = builder.create<arith::SelectOp>(loc, cmpOp.getResult(), value,
54 *valueIt);
Chris Lattnerae618422018-12-31 00:22:5055 }
56
57 return value;
58}
59
Kazuaki Ishizakie5a85122020-03-26 18:51:3760/// Emit instructions that correspond to computing the maximum value among the
OuHangKresnik5c3b3492020-02-06 09:25:5561/// values of a (potentially) multi-output affine map applied to `operands`.
62static Value lowerAffineMapMax(OpBuilder &builder, Location loc, AffineMap map,
63 ValueRange operands) {
64 if (auto values = expandAffineMap(builder, loc, map, operands))
Mogballa54f4ea2021-10-12 23:14:5765 return buildMinMaxReductionSeq(loc, arith::CmpIPredicate::sgt, *values,
66 builder);
OuHangKresnik5c3b3492020-02-06 09:25:5567 return nullptr;
Alex Zinenkoee6f84a2019-06-14 08:56:1968}
69
Kazuaki Ishizakie5a85122020-03-26 18:51:3770/// Emit instructions that correspond to computing the minimum value among the
Alex Zinenko6895a1c2020-01-28 09:21:1271/// values of a (potentially) multi-output affine map applied to `operands`.
Alex Zinenko51ba5b52020-01-27 16:14:5672static Value lowerAffineMapMin(OpBuilder &builder, Location loc, AffineMap map,
73 ValueRange operands) {
Alex Zinenko8ed47b72020-01-28 10:53:0074 if (auto values = expandAffineMap(builder, loc, map, operands))
Mogballa54f4ea2021-10-12 23:14:5775 return buildMinMaxReductionSeq(loc, arith::CmpIPredicate::slt, *values,
76 builder);
Alex Zinenko51ba5b52020-01-27 16:14:5677 return nullptr;
78}
79
Alex Zinenko6895a1c2020-01-28 09:21:1280/// Emit instructions that correspond to the affine map in the upper bound
81/// applied to the respective operands, and compute the minimum value across
82/// the results.
River Riddlee62a6952019-12-23 22:45:0183Value mlir::lowerAffineUpperBound(AffineForOp op, OpBuilder &builder) {
Alex Zinenko51ba5b52020-01-27 16:14:5684 return lowerAffineMapMin(builder, op.getLoc(), op.getUpperBoundMap(),
85 op.getUpperBoundOperands());
Alex Zinenkoee6f84a2019-06-14 08:56:1986}
87
OuHangKresnik5c3b3492020-02-06 09:25:5588/// Emit instructions that correspond to the affine map in the lower bound
89/// applied to the respective operands, and compute the maximum value across
90/// the results.
91Value mlir::lowerAffineLowerBound(AffineForOp op, OpBuilder &builder) {
92 return lowerAffineMapMax(builder, op.getLoc(), op.getLowerBoundMap(),
93 op.getLowerBoundOperands());
94}
95
Alex Zinenko8ad35b92019-06-11 15:33:1896namespace {
Alex Zinenko51ba5b52020-01-27 16:14:5697class AffineMinLowering : public OpRewritePattern<AffineMinOp> {
98public:
99 using OpRewritePattern<AffineMinOp>::OpRewritePattern;
100
River Riddle31454272020-03-18 03:07:55101 LogicalResult matchAndRewrite(AffineMinOp op,
102 PatternRewriter &rewriter) const override {
Alex Zinenko51ba5b52020-01-27 16:14:56103 Value reduced =
104 lowerAffineMapMin(rewriter, op.getLoc(), op.map(), op.operands());
105 if (!reduced)
River Riddle31454272020-03-18 03:07:55106 return failure();
Alex Zinenko51ba5b52020-01-27 16:14:56107
108 rewriter.replaceOp(op, reduced);
River Riddle31454272020-03-18 03:07:55109 return success();
Alex Zinenko51ba5b52020-01-27 16:14:56110 }
111};
112
OuHangKresnik5c3b3492020-02-06 09:25:55113class AffineMaxLowering : public OpRewritePattern<AffineMaxOp> {
114public:
115 using OpRewritePattern<AffineMaxOp>::OpRewritePattern;
116
River Riddle31454272020-03-18 03:07:55117 LogicalResult matchAndRewrite(AffineMaxOp op,
118 PatternRewriter &rewriter) const override {
OuHangKresnik5c3b3492020-02-06 09:25:55119 Value reduced =
120 lowerAffineMapMax(rewriter, op.getLoc(), op.map(), op.operands());
121 if (!reduced)
River Riddle31454272020-03-18 03:07:55122 return failure();
OuHangKresnik5c3b3492020-02-06 09:25:55123
124 rewriter.replaceOp(op, reduced);
River Riddle31454272020-03-18 03:07:55125 return success();
OuHangKresnik5c3b3492020-02-06 09:25:55126 }
127};
128
Jeremy Bruestle2ede8912020-07-09 19:02:20129/// Affine yields ops are removed.
130class AffineYieldOpLowering : public OpRewritePattern<AffineYieldOp> {
Alex Zinenko8ad35b92019-06-11 15:33:18131public:
Jeremy Bruestle2ede8912020-07-09 19:02:20132 using OpRewritePattern<AffineYieldOp>::OpRewritePattern;
Alex Zinenko8ad35b92019-06-11 15:33:18133
Jeremy Bruestle2ede8912020-07-09 19:02:20134 LogicalResult matchAndRewrite(AffineYieldOp op,
River Riddle31454272020-03-18 03:07:55135 PatternRewriter &rewriter) const override {
Christian Siggbadc7602021-01-06 20:26:59136 if (isa<scf::ParallelOp>(op->getParentOp())) {
Prateek Gupta3e07b0b2020-12-22 16:10:17137 // scf.parallel does not yield any values via its terminator scf.yield but
138 // models reductions differently using additional ops in its region.
139 rewriter.replaceOpWithNewOp<scf::YieldOp>(op);
140 return success();
141 }
142 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, op.operands());
River Riddle31454272020-03-18 03:07:55143 return success();
Alex Zinenko8ad35b92019-06-11 15:33:18144 }
145};
146
River Riddle40715782019-07-15 14:35:00147class AffineForLowering : public OpRewritePattern<AffineForOp> {
Alex Zinenko8ad35b92019-06-11 15:33:18148public:
River Riddle40715782019-07-15 14:35:00149 using OpRewritePattern<AffineForOp>::OpRewritePattern;
Chris Lattnerae618422018-12-31 00:22:50150
River Riddle31454272020-03-18 03:07:55151 LogicalResult matchAndRewrite(AffineForOp op,
152 PatternRewriter &rewriter) const override {
River Riddle40715782019-07-15 14:35:00153 Location loc = op.getLoc();
River Riddlee62a6952019-12-23 22:45:01154 Value lowerBound = lowerAffineLowerBound(op, rewriter);
155 Value upperBound = lowerAffineUpperBound(op, rewriter);
Mogballa54f4ea2021-10-12 23:14:57156 Value step = rewriter.create<arith::ConstantIndexOp>(loc, op.getStep());
Prateek Gupta3e07b0b2020-12-22 16:10:17157 auto scfForOp = rewriter.create<scf::ForOp>(loc, lowerBound, upperBound,
158 step, op.getIterOperands());
159 rewriter.eraseBlock(scfForOp.getBody());
Jacques Pienaarc0342a22021-12-20 16:03:43160 rewriter.inlineRegionBefore(op.region(), scfForOp.getRegion(),
161 scfForOp.getRegion().end());
162 rewriter.replaceOp(op, scfForOp.getResults());
River Riddle31454272020-03-18 03:07:55163 return success();
Alex Zinenko8ad35b92019-06-11 15:33:18164 }
165};
Chris Lattnerae618422018-12-31 00:22:50166
Yash Jain3382b712020-07-18 07:39:30167/// Convert an `affine.parallel` (loop nest) operation into a `scf.parallel`
168/// operation.
169class AffineParallelLowering : public OpRewritePattern<AffineParallelOp> {
170public:
171 using OpRewritePattern<AffineParallelOp>::OpRewritePattern;
172
173 LogicalResult matchAndRewrite(AffineParallelOp op,
174 PatternRewriter &rewriter) const override {
175 Location loc = op.getLoc();
176 SmallVector<Value, 8> steps;
177 SmallVector<Value, 8> upperBoundTuple;
178 SmallVector<Value, 8> lowerBoundTuple;
Prateek Gupta3e07b0b2020-12-22 16:10:17179 SmallVector<Value, 8> identityVals;
Alex Zinenko6841e6a2021-04-29 11:15:21180 // Emit IR computing the lower and upper bound by expanding the map
181 // expression.
182 lowerBoundTuple.reserve(op.getNumDims());
183 upperBoundTuple.reserve(op.getNumDims());
184 for (unsigned i = 0, e = op.getNumDims(); i < e; ++i) {
185 Value lower = lowerAffineMapMax(rewriter, loc, op.getLowerBoundMap(i),
186 op.getLowerBoundsOperands());
187 if (!lower)
188 return rewriter.notifyMatchFailure(op, "couldn't convert lower bounds");
189 lowerBoundTuple.push_back(lower);
190
191 Value upper = lowerAffineMapMin(rewriter, loc, op.getUpperBoundMap(i),
192 op.getUpperBoundsOperands());
193 if (!upper)
194 return rewriter.notifyMatchFailure(op, "couldn't convert upper bounds");
195 upperBoundTuple.push_back(upper);
196 }
Yash Jain3382b712020-07-18 07:39:30197 steps.reserve(op.steps().size());
198 for (Attribute step : op.steps())
Mogballa54f4ea2021-10-12 23:14:57199 steps.push_back(rewriter.create<arith::ConstantIndexOp>(
Yash Jain3382b712020-07-18 07:39:30200 loc, step.cast<IntegerAttr>().getInt()));
Alex Zinenko6841e6a2021-04-29 11:15:21201
Prateek Gupta3e07b0b2020-12-22 16:10:17202 // Get the terminator op.
203 Operation *affineParOpTerminator = op.getBody()->getTerminator();
204 scf::ParallelOp parOp;
205 if (op.results().empty()) {
206 // Case with no reduction operations/return values.
207 parOp = rewriter.create<scf::ParallelOp>(loc, lowerBoundTuple,
208 upperBoundTuple, steps,
209 /*bodyBuilderFn=*/nullptr);
210 rewriter.eraseBlock(parOp.getBody());
Jacques Pienaarc0342a22021-12-20 16:03:43211 rewriter.inlineRegionBefore(op.region(), parOp.getRegion(),
212 parOp.getRegion().end());
213 rewriter.replaceOp(op, parOp.getResults());
Prateek Gupta3e07b0b2020-12-22 16:10:17214 return success();
215 }
216 // Case with affine.parallel with reduction operations/return values.
217 // scf.parallel handles the reduction operation differently unlike
218 // affine.parallel.
219 ArrayRef<Attribute> reductions = op.reductions().getValue();
Alex Zinenko7dc77902021-04-06 10:53:04220 for (auto pair : llvm::zip(reductions, op.getResultTypes())) {
Prateek Gupta3e07b0b2020-12-22 16:10:17221 // For each of the reduction operations get the identity values for
222 // initialization of the result values.
Alex Zinenko7dc77902021-04-06 10:53:04223 Attribute reduction = std::get<0>(pair);
224 Type resultType = std::get<1>(pair);
William S. Mosesa6a583d2021-12-30 05:59:58225 Optional<arith::AtomicRMWKind> reductionOp =
226 arith::symbolizeAtomicRMWKind(
227 static_cast<uint64_t>(reduction.cast<IntegerAttr>().getInt()));
Prateek Gupta3e07b0b2020-12-22 16:10:17228 assert(reductionOp.hasValue() &&
229 "Reduction operation cannot be of None Type");
William S. Mosesa6a583d2021-12-30 05:59:58230 arith::AtomicRMWKind reductionOpValue = reductionOp.getValue();
Alex Zinenko7dc77902021-04-06 10:53:04231 identityVals.push_back(
William S. Mosesa6a583d2021-12-30 05:59:58232 arith::getIdentityValue(reductionOpValue, resultType, rewriter, loc));
Prateek Gupta3e07b0b2020-12-22 16:10:17233 }
234 parOp = rewriter.create<scf::ParallelOp>(
235 loc, lowerBoundTuple, upperBoundTuple, steps, identityVals,
236 /*bodyBuilderFn=*/nullptr);
237
238 // Copy the body of the affine.parallel op.
239 rewriter.eraseBlock(parOp.getBody());
Jacques Pienaarc0342a22021-12-20 16:03:43240 rewriter.inlineRegionBefore(op.region(), parOp.getRegion(),
241 parOp.getRegion().end());
Prateek Gupta3e07b0b2020-12-22 16:10:17242 assert(reductions.size() == affineParOpTerminator->getNumOperands() &&
243 "Unequal number of reductions and operands.");
244 for (unsigned i = 0, end = reductions.size(); i < end; i++) {
245 // For each of the reduction operations get the respective mlir::Value.
William S. Mosesa6a583d2021-12-30 05:59:58246 Optional<arith::AtomicRMWKind> reductionOp =
247 arith::symbolizeAtomicRMWKind(
248 reductions[i].cast<IntegerAttr>().getInt());
Prateek Gupta3e07b0b2020-12-22 16:10:17249 assert(reductionOp.hasValue() &&
250 "Reduction Operation cannot be of None Type");
William S. Mosesa6a583d2021-12-30 05:59:58251 arith::AtomicRMWKind reductionOpValue = reductionOp.getValue();
Prateek Gupta3e07b0b2020-12-22 16:10:17252 rewriter.setInsertionPoint(&parOp.getBody()->back());
253 auto reduceOp = rewriter.create<scf::ReduceOp>(
254 loc, affineParOpTerminator->getOperand(i));
Jacques Pienaarc0342a22021-12-20 16:03:43255 rewriter.setInsertionPointToEnd(&reduceOp.getReductionOperator().front());
William S. Mosesa6a583d2021-12-30 05:59:58256 Value reductionResult = arith::getReductionOp(
Jacques Pienaarc0342a22021-12-20 16:03:43257 reductionOpValue, rewriter, loc,
258 reduceOp.getReductionOperator().front().getArgument(0),
259 reduceOp.getReductionOperator().front().getArgument(1));
Prateek Gupta3e07b0b2020-12-22 16:10:17260 rewriter.create<scf::ReduceReturnOp>(loc, reductionResult);
261 }
Jacques Pienaarc0342a22021-12-20 16:03:43262 rewriter.replaceOp(op, parOp.getResults());
Yash Jain3382b712020-07-18 07:39:30263 return success();
264 }
265};
266
River Riddle40715782019-07-15 14:35:00267class AffineIfLowering : public OpRewritePattern<AffineIfOp> {
Alex Zinenko8ad35b92019-06-11 15:33:18268public:
River Riddle40715782019-07-15 14:35:00269 using OpRewritePattern<AffineIfOp>::OpRewritePattern;
Chris Lattnerae618422018-12-31 00:22:50270
River Riddle31454272020-03-18 03:07:55271 LogicalResult matchAndRewrite(AffineIfOp op,
272 PatternRewriter &rewriter) const override {
River Riddle40715782019-07-15 14:35:00273 auto loc = op.getLoc();
Chris Lattnerae618422018-12-31 00:22:50274
Alex Zinenko8ad35b92019-06-11 15:33:18275 // Now we just have to handle the condition logic.
River Riddle40715782019-07-15 14:35:00276 auto integerSet = op.getIntegerSet();
Mogballa54f4ea2021-10-12 23:14:57277 Value zeroConstant = rewriter.create<arith::ConstantIndexOp>(loc, 0);
River Riddlee62a6952019-12-23 22:45:01278 SmallVector<Value, 8> operands(op.getOperands());
River Riddle40715782019-07-15 14:35:00279 auto operandsRef = llvm::makeArrayRef(operands);
Alex Zinenko8ad35b92019-06-11 15:33:18280
Nicolas Vasilachecab671d2019-07-12 13:48:45281 // Calculate cond as a conjunction without short-circuiting.
River Riddlee62a6952019-12-23 22:45:01282 Value cond = nullptr;
Alex Zinenko8ad35b92019-06-11 15:33:18283 for (unsigned i = 0, e = integerSet.getNumConstraints(); i < e; ++i) {
284 AffineExpr constraintExpr = integerSet.getConstraint(i);
285 bool isEquality = integerSet.isEq(i);
286
Alex Zinenko8ad35b92019-06-11 15:33:18287 // Build and apply an affine expression
288 auto numDims = integerSet.getNumDims();
River Riddlee62a6952019-12-23 22:45:01289 Value affResult = expandAffineExpr(rewriter, loc, constraintExpr,
290 operandsRef.take_front(numDims),
291 operandsRef.drop_front(numDims));
Alex Zinenko8ad35b92019-06-11 15:33:18292 if (!affResult)
River Riddle31454272020-03-18 03:07:55293 return failure();
Mogballa54f4ea2021-10-12 23:14:57294 auto pred =
295 isEquality ? arith::CmpIPredicate::eq : arith::CmpIPredicate::sge;
River Riddlee62a6952019-12-23 22:45:01296 Value cmpVal =
Mogballa54f4ea2021-10-12 23:14:57297 rewriter.create<arith::CmpIOp>(loc, pred, affResult, zeroConstant);
298 cond = cond
299 ? rewriter.create<arith::AndIOp>(loc, cond, cmpVal).getResult()
300 : cmpVal;
Nicolas Vasilachecab671d2019-07-12 13:48:45301 }
302 cond = cond ? cond
Mogballa54f4ea2021-10-12 23:14:57303 : rewriter.create<arith::ConstantIntOp>(loc, /*value=*/1,
304 /*width=*/1);
Nicolas Vasilachecab671d2019-07-12 13:48:45305
Nicolas Vasilache0002e292019-07-16 19:20:15306 bool hasElseRegion = !op.elseRegion().empty();
Gaurav Shukla8e3075c2021-03-17 10:18:33307 auto ifOp = rewriter.create<scf::IfOp>(loc, op.getResultTypes(), cond,
308 hasElseRegion);
Jacques Pienaarc0342a22021-12-20 16:03:43309 rewriter.inlineRegionBefore(op.thenRegion(), &ifOp.getThenRegion().back());
310 rewriter.eraseBlock(&ifOp.getThenRegion().back());
Nicolas Vasilachecab671d2019-07-12 13:48:45311 if (hasElseRegion) {
Jacques Pienaarc0342a22021-12-20 16:03:43312 rewriter.inlineRegionBefore(op.elseRegion(),
313 &ifOp.getElseRegion().back());
314 rewriter.eraseBlock(&ifOp.getElseRegion().back());
Alex Zinenko8ad35b92019-06-11 15:33:18315 }
316
Gaurav Shukla8e3075c2021-03-17 10:18:33317 // Replace the Affine IfOp finally.
Jacques Pienaarc0342a22021-12-20 16:03:43318 rewriter.replaceOp(op, ifOp.getResults());
River Riddle31454272020-03-18 03:07:55319 return success();
River Riddle75553832019-01-29 05:23:53320 }
Alex Zinenko8ad35b92019-06-11 15:33:18321};
Chris Lattnerae618422018-12-31 00:22:50322
Alex Zinenko6895a1c2020-01-28 09:21:12323/// Convert an "affine.apply" operation into a sequence of arithmetic
324/// operations using the StandardOps dialect.
River Riddle40715782019-07-15 14:35:00325class AffineApplyLowering : public OpRewritePattern<AffineApplyOp> {
Alex Zinenko8ad35b92019-06-11 15:33:18326public:
River Riddle40715782019-07-15 14:35:00327 using OpRewritePattern<AffineApplyOp>::OpRewritePattern;
Chris Lattnerb42bea22019-01-27 17:33:19328
River Riddle31454272020-03-18 03:07:55329 LogicalResult matchAndRewrite(AffineApplyOp op,
330 PatternRewriter &rewriter) const override {
River Riddle40715782019-07-15 14:35:00331 auto maybeExpandedMap =
332 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(),
333 llvm::to_vector<8>(op.getOperands()));
Alex Zinenko8ad35b92019-06-11 15:33:18334 if (!maybeExpandedMap)
River Riddle31454272020-03-18 03:07:55335 return failure();
Alex Zinenko8ad35b92019-06-11 15:33:18336 rewriter.replaceOp(op, *maybeExpandedMap);
River Riddle31454272020-03-18 03:07:55337 return success();
River Riddle5052bd82019-02-02 00:42:18338 }
Alex Zinenko8ad35b92019-06-11 15:33:18339};
Andy Davisf487d202019-07-01 15:32:44340
Alex Zinenko6895a1c2020-01-28 09:21:12341/// Apply the affine map from an 'affine.load' operation to its operands, and
Julian Grosse2310702021-02-10 12:53:11342/// feed the results to a newly created 'memref.load' operation (which replaces
343/// the original 'affine.load').
River Riddle40715782019-07-15 14:35:00344class AffineLoadLowering : public OpRewritePattern<AffineLoadOp> {
Andy Davisf487d202019-07-01 15:32:44345public:
River Riddle40715782019-07-15 14:35:00346 using OpRewritePattern<AffineLoadOp>::OpRewritePattern;
Andy Davisf487d202019-07-01 15:32:44347
River Riddle31454272020-03-18 03:07:55348 LogicalResult matchAndRewrite(AffineLoadOp op,
349 PatternRewriter &rewriter) const override {
Andy Davisf487d202019-07-01 15:32:44350 // Expand affine map from 'affineLoadOp'.
River Riddlee62a6952019-12-23 22:45:01351 SmallVector<Value, 8> indices(op.getMapOperands());
Uday Bondhugula47034c42019-12-18 17:59:37352 auto resultOperands =
River Riddle40715782019-07-15 14:35:00353 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices);
Uday Bondhugula47034c42019-12-18 17:59:37354 if (!resultOperands)
River Riddle31454272020-03-18 03:07:55355 return failure();
River Riddle40715782019-07-15 14:35:00356
Diego Caballeroee66e432021-02-12 17:41:46357 // Build vector.load memref[expandedMap.results].
Julian Grosse2310702021-02-10 12:53:11358 rewriter.replaceOpWithNewOp<memref::LoadOp>(op, op.getMemRef(),
359 *resultOperands);
River Riddle31454272020-03-18 03:07:55360 return success();
Uday Bondhugula47034c42019-12-18 17:59:37361 }
362};
363
Alex Zinenko6895a1c2020-01-28 09:21:12364/// Apply the affine map from an 'affine.prefetch' operation to its operands,
Julian Grosse2310702021-02-10 12:53:11365/// and feed the results to a newly created 'memref.prefetch' operation (which
Alex Zinenko6895a1c2020-01-28 09:21:12366/// replaces the original 'affine.prefetch').
Uday Bondhugula47034c42019-12-18 17:59:37367class AffinePrefetchLowering : public OpRewritePattern<AffinePrefetchOp> {
368public:
369 using OpRewritePattern<AffinePrefetchOp>::OpRewritePattern;
370
River Riddle31454272020-03-18 03:07:55371 LogicalResult matchAndRewrite(AffinePrefetchOp op,
372 PatternRewriter &rewriter) const override {
Uday Bondhugula47034c42019-12-18 17:59:37373 // Expand affine map from 'affinePrefetchOp'.
River Riddlee62a6952019-12-23 22:45:01374 SmallVector<Value, 8> indices(op.getMapOperands());
Uday Bondhugula47034c42019-12-18 17:59:37375 auto resultOperands =
376 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices);
377 if (!resultOperands)
River Riddle31454272020-03-18 03:07:55378 return failure();
Uday Bondhugula47034c42019-12-18 17:59:37379
Julian Grosse2310702021-02-10 12:53:11380 // Build memref.prefetch memref[expandedMap.results].
381 rewriter.replaceOpWithNewOp<memref::PrefetchOp>(
382 op, op.memref(), *resultOperands, op.isWrite(), op.localityHint(),
383 op.isDataCache());
River Riddle31454272020-03-18 03:07:55384 return success();
Andy Davisf487d202019-07-01 15:32:44385 }
386};
387
Alex Zinenko6895a1c2020-01-28 09:21:12388/// Apply the affine map from an 'affine.store' operation to its operands, and
Julian Grosse2310702021-02-10 12:53:11389/// feed the results to a newly created 'memref.store' operation (which replaces
Alex Zinenko6895a1c2020-01-28 09:21:12390/// the original 'affine.store').
River Riddle40715782019-07-15 14:35:00391class AffineStoreLowering : public OpRewritePattern<AffineStoreOp> {
Andy Davisf487d202019-07-01 15:32:44392public:
River Riddle40715782019-07-15 14:35:00393 using OpRewritePattern<AffineStoreOp>::OpRewritePattern;
Andy Davisf487d202019-07-01 15:32:44394
River Riddle31454272020-03-18 03:07:55395 LogicalResult matchAndRewrite(AffineStoreOp op,
396 PatternRewriter &rewriter) const override {
Andy Davisf487d202019-07-01 15:32:44397 // Expand affine map from 'affineStoreOp'.
River Riddlee62a6952019-12-23 22:45:01398 SmallVector<Value, 8> indices(op.getMapOperands());
Andy Davisf487d202019-07-01 15:32:44399 auto maybeExpandedMap =
River Riddle40715782019-07-15 14:35:00400 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices);
Andy Davisf487d202019-07-01 15:32:44401 if (!maybeExpandedMap)
River Riddle31454272020-03-18 03:07:55402 return failure();
River Riddle40715782019-07-15 14:35:00403
Julian Grosse2310702021-02-10 12:53:11404 // Build memref.store valueToStore, memref[expandedMap.results].
405 rewriter.replaceOpWithNewOp<memref::StoreOp>(
Diego Caballeroee66e432021-02-12 17:41:46406 op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap);
River Riddle31454272020-03-18 03:07:55407 return success();
Andy Davisf487d202019-07-01 15:32:44408 }
409};
410
Alex Zinenko6895a1c2020-01-28 09:21:12411/// Apply the affine maps from an 'affine.dma_start' operation to each of their
412/// respective map operands, and feed the results to a newly created
Julian Grosse2310702021-02-10 12:53:11413/// 'memref.dma_start' operation (which replaces the original
414/// 'affine.dma_start').
River Riddle40715782019-07-15 14:35:00415class AffineDmaStartLowering : public OpRewritePattern<AffineDmaStartOp> {
Andy Davisf487d202019-07-01 15:32:44416public:
River Riddle40715782019-07-15 14:35:00417 using OpRewritePattern<AffineDmaStartOp>::OpRewritePattern;
Andy Davisf487d202019-07-01 15:32:44418
River Riddle31454272020-03-18 03:07:55419 LogicalResult matchAndRewrite(AffineDmaStartOp op,
420 PatternRewriter &rewriter) const override {
River Riddlee62a6952019-12-23 22:45:01421 SmallVector<Value, 8> operands(op.getOperands());
River Riddle40715782019-07-15 14:35:00422 auto operandsRef = llvm::makeArrayRef(operands);
423
Andy Davisf487d202019-07-01 15:32:44424 // Expand affine map for DMA source memref.
425 auto maybeExpandedSrcMap = expandAffineMap(
River Riddle40715782019-07-15 14:35:00426 rewriter, op.getLoc(), op.getSrcMap(),
427 operandsRef.drop_front(op.getSrcMemRefOperandIndex() + 1));
Andy Davisf487d202019-07-01 15:32:44428 if (!maybeExpandedSrcMap)
River Riddle31454272020-03-18 03:07:55429 return failure();
Andy Davisf487d202019-07-01 15:32:44430 // Expand affine map for DMA destination memref.
431 auto maybeExpandedDstMap = expandAffineMap(
River Riddle40715782019-07-15 14:35:00432 rewriter, op.getLoc(), op.getDstMap(),
433 operandsRef.drop_front(op.getDstMemRefOperandIndex() + 1));
Andy Davisf487d202019-07-01 15:32:44434 if (!maybeExpandedDstMap)
River Riddle31454272020-03-18 03:07:55435 return failure();
Andy Davisf487d202019-07-01 15:32:44436 // Expand affine map for DMA tag memref.
437 auto maybeExpandedTagMap = expandAffineMap(
River Riddle40715782019-07-15 14:35:00438 rewriter, op.getLoc(), op.getTagMap(),
439 operandsRef.drop_front(op.getTagMemRefOperandIndex() + 1));
Andy Davisf487d202019-07-01 15:32:44440 if (!maybeExpandedTagMap)
River Riddle31454272020-03-18 03:07:55441 return failure();
Andy Davisf487d202019-07-01 15:32:44442
Julian Grosse2310702021-02-10 12:53:11443 // Build memref.dma_start operation with affine map results.
444 rewriter.replaceOpWithNewOp<memref::DmaStartOp>(
River Riddle40715782019-07-15 14:35:00445 op, op.getSrcMemRef(), *maybeExpandedSrcMap, op.getDstMemRef(),
446 *maybeExpandedDstMap, op.getNumElements(), op.getTagMemRef(),
447 *maybeExpandedTagMap, op.getStride(), op.getNumElementsPerStride());
River Riddle31454272020-03-18 03:07:55448 return success();
Andy Davisf487d202019-07-01 15:32:44449 }
450};
451
Alex Zinenko6895a1c2020-01-28 09:21:12452/// Apply the affine map from an 'affine.dma_wait' operation tag memref,
Julian Grosse2310702021-02-10 12:53:11453/// and feed the results to a newly created 'memref.dma_wait' operation (which
Alex Zinenko6895a1c2020-01-28 09:21:12454/// replaces the original 'affine.dma_wait').
River Riddle40715782019-07-15 14:35:00455class AffineDmaWaitLowering : public OpRewritePattern<AffineDmaWaitOp> {
Andy Davisf487d202019-07-01 15:32:44456public:
River Riddle40715782019-07-15 14:35:00457 using OpRewritePattern<AffineDmaWaitOp>::OpRewritePattern;
Andy Davisf487d202019-07-01 15:32:44458
River Riddle31454272020-03-18 03:07:55459 LogicalResult matchAndRewrite(AffineDmaWaitOp op,
460 PatternRewriter &rewriter) const override {
Andy Davisf487d202019-07-01 15:32:44461 // Expand affine map for DMA tag memref.
River Riddlee62a6952019-12-23 22:45:01462 SmallVector<Value, 8> indices(op.getTagIndices());
Andy Davisf487d202019-07-01 15:32:44463 auto maybeExpandedTagMap =
River Riddle40715782019-07-15 14:35:00464 expandAffineMap(rewriter, op.getLoc(), op.getTagMap(), indices);
Andy Davisf487d202019-07-01 15:32:44465 if (!maybeExpandedTagMap)
River Riddle31454272020-03-18 03:07:55466 return failure();
Andy Davisf487d202019-07-01 15:32:44467
Julian Grosse2310702021-02-10 12:53:11468 // Build memref.dma_wait operation with affine map results.
469 rewriter.replaceOpWithNewOp<memref::DmaWaitOp>(
River Riddle40715782019-07-15 14:35:00470 op, op.getTagMemRef(), *maybeExpandedTagMap, op.getNumElements());
River Riddle31454272020-03-18 03:07:55471 return success();
Andy Davisf487d202019-07-01 15:32:44472 }
473};
474
Diego Caballerobc5565f2020-05-14 19:05:46475/// Apply the affine map from an 'affine.vector_load' operation to its operands,
Diego Caballeroee66e432021-02-12 17:41:46476/// and feed the results to a newly created 'vector.load' operation (which
477/// replaces the original 'affine.vector_load').
Diego Caballerobc5565f2020-05-14 19:05:46478class AffineVectorLoadLowering : public OpRewritePattern<AffineVectorLoadOp> {
479public:
480 using OpRewritePattern<AffineVectorLoadOp>::OpRewritePattern;
481
482 LogicalResult matchAndRewrite(AffineVectorLoadOp op,
483 PatternRewriter &rewriter) const override {
484 // Expand affine map from 'affineVectorLoadOp'.
485 SmallVector<Value, 8> indices(op.getMapOperands());
486 auto resultOperands =
487 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices);
488 if (!resultOperands)
489 return failure();
490
Diego Caballeroee66e432021-02-12 17:41:46491 // Build vector.load memref[expandedMap.results].
492 rewriter.replaceOpWithNewOp<vector::LoadOp>(
Diego Caballerobc5565f2020-05-14 19:05:46493 op, op.getVectorType(), op.getMemRef(), *resultOperands);
494 return success();
495 }
496};
497
498/// Apply the affine map from an 'affine.vector_store' operation to its
Diego Caballeroee66e432021-02-12 17:41:46499/// operands, and feed the results to a newly created 'vector.store' operation
500/// (which replaces the original 'affine.vector_store').
Diego Caballerobc5565f2020-05-14 19:05:46501class AffineVectorStoreLowering : public OpRewritePattern<AffineVectorStoreOp> {
502public:
503 using OpRewritePattern<AffineVectorStoreOp>::OpRewritePattern;
504
505 LogicalResult matchAndRewrite(AffineVectorStoreOp op,
506 PatternRewriter &rewriter) const override {
507 // Expand affine map from 'affineVectorStoreOp'.
508 SmallVector<Value, 8> indices(op.getMapOperands());
509 auto maybeExpandedMap =
510 expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices);
511 if (!maybeExpandedMap)
512 return failure();
513
Diego Caballeroee66e432021-02-12 17:41:46514 rewriter.replaceOpWithNewOp<vector::StoreOp>(
Diego Caballerobc5565f2020-05-14 19:05:46515 op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap);
516 return success();
517 }
518};
519
Mehdi Aminibe0a7e92021-12-07 18:27:58520} // namespace
Alex Zinenkod4c071c2019-05-28 07:49:23521
Chris Lattnerdc4e9132021-03-22 23:58:34522void mlir::populateAffineToStdConversionPatterns(RewritePatternSet &patterns) {
Alex Zinenko51ba5b52020-01-27 16:14:56523 // clang-format off
Chris Lattnerdc4e9132021-03-22 23:58:34524 patterns.add<
Alex Zinenko51ba5b52020-01-27 16:14:56525 AffineApplyLowering,
526 AffineDmaStartLowering,
527 AffineDmaWaitLowering,
528 AffineLoadLowering,
529 AffineMinLowering,
OuHangKresnik5c3b3492020-02-06 09:25:55530 AffineMaxLowering,
Yash Jain3382b712020-07-18 07:39:30531 AffineParallelLowering,
Alex Zinenko51ba5b52020-01-27 16:14:56532 AffinePrefetchLowering,
533 AffineStoreLowering,
534 AffineForLowering,
535 AffineIfLowering,
Chris Lattner3a506b32021-03-20 23:29:41536 AffineYieldOpLowering>(patterns.getContext());
Alex Zinenko51ba5b52020-01-27 16:14:56537 // clang-format on
Alex Zinenkod4c071c2019-05-28 07:49:23538}
539
Diego Caballerobc5565f2020-05-14 19:05:46540void mlir::populateAffineToVectorConversionPatterns(
Chris Lattnerdc4e9132021-03-22 23:58:34541 RewritePatternSet &patterns) {
Diego Caballerobc5565f2020-05-14 19:05:46542 // clang-format off
Chris Lattnerdc4e9132021-03-22 23:58:34543 patterns.add<
Diego Caballerobc5565f2020-05-14 19:05:46544 AffineVectorLoadLowering,
Chris Lattner3a506b32021-03-20 23:29:41545 AffineVectorStoreLowering>(patterns.getContext());
Diego Caballerobc5565f2020-05-14 19:05:46546 // clang-format on
547}
548
Alex Zinenko8ad35b92019-06-11 15:33:18549namespace {
River Riddle1834ad4a2020-04-07 20:58:12550class LowerAffinePass : public ConvertAffineToStandardBase<LowerAffinePass> {
MaheshRavishankarfbe911e2020-07-27 19:13:08551 void runOnOperation() override {
Chris Lattnerdc4e9132021-03-22 23:58:34552 RewritePatternSet patterns(&getContext());
Chris Lattner3a506b32021-03-20 23:29:41553 populateAffineToStdConversionPatterns(patterns);
554 populateAffineToVectorConversionPatterns(patterns);
River Riddle2087bf62019-07-15 19:52:44555 ConversionTarget target(getContext());
River Riddle23aa5a72022-02-26 22:49:54556 target.addLegalDialect<arith::ArithmeticDialect, func::FuncDialect,
557 memref::MemRefDialect, scf::SCFDialect,
558 VectorDialect>();
River Riddle3fffffa82020-10-27 00:25:01559 if (failed(applyPartialConversion(getOperation(), target,
560 std::move(patterns))))
River Riddle2087bf62019-07-15 19:52:44561 signalPassFailure();
562 }
Alex Zinenko8ad35b92019-06-11 15:33:18563};
564} // namespace
Chris Lattnerae618422018-12-31 00:22:50565
River Riddle99b87c92019-03-27 21:02:02566/// Lowers If and For operations within a function into their lower level CFG
Chris Lattnerae618422018-12-31 00:22:50567/// equivalent blocks.
MaheshRavishankarfbe911e2020-07-27 19:13:08568std::unique_ptr<Pass> mlir::createLowerAffinePass() {
Jacques Pienaar79f53b02019-08-17 18:05:35569 return std::make_unique<LowerAffinePass>();
River Riddlec6c53442019-02-27 18:59:29570}