1*032cb165SMorten Borup Petersen //===- ForToWhile.cpp - scf.for to scf.while loop conversion --------------===//
2*032cb165SMorten Borup Petersen //
3*032cb165SMorten Borup Petersen // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*032cb165SMorten Borup Petersen // See https://llvm.org/LICENSE.txt for license information.
5*032cb165SMorten Borup Petersen // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*032cb165SMorten Borup Petersen //
7*032cb165SMorten Borup Petersen //===----------------------------------------------------------------------===//
8*032cb165SMorten Borup Petersen //
9*032cb165SMorten Borup Petersen // Transforms SCF.ForOp's into SCF.WhileOp's.
10*032cb165SMorten Borup Petersen //
11*032cb165SMorten Borup Petersen //===----------------------------------------------------------------------===//
12*032cb165SMorten Borup Petersen 
13*032cb165SMorten Borup Petersen #include "PassDetail.h"
14*032cb165SMorten Borup Petersen #include "mlir/Dialect/SCF/Passes.h"
15*032cb165SMorten Borup Petersen #include "mlir/Dialect/SCF/SCF.h"
16*032cb165SMorten Borup Petersen #include "mlir/Dialect/SCF/Transforms.h"
17*032cb165SMorten Borup Petersen #include "mlir/Dialect/StandardOps/IR/Ops.h"
18*032cb165SMorten Borup Petersen #include "mlir/IR/PatternMatch.h"
19*032cb165SMorten Borup Petersen #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
20*032cb165SMorten Borup Petersen 
21*032cb165SMorten Borup Petersen using namespace llvm;
22*032cb165SMorten Borup Petersen using namespace mlir;
23*032cb165SMorten Borup Petersen using scf::ForOp;
24*032cb165SMorten Borup Petersen using scf::WhileOp;
25*032cb165SMorten Borup Petersen 
26*032cb165SMorten Borup Petersen namespace {
27*032cb165SMorten Borup Petersen 
28*032cb165SMorten Borup Petersen struct ForLoopLoweringPattern : public OpRewritePattern<ForOp> {
29*032cb165SMorten Borup Petersen   using OpRewritePattern<ForOp>::OpRewritePattern;
30*032cb165SMorten Borup Petersen 
31*032cb165SMorten Borup Petersen   LogicalResult matchAndRewrite(ForOp forOp,
32*032cb165SMorten Borup Petersen                                 PatternRewriter &rewriter) const override {
33*032cb165SMorten Borup Petersen     // Generate type signature for the loop-carried values. The induction
34*032cb165SMorten Borup Petersen     // variable is placed first, followed by the forOp.iterArgs.
35*032cb165SMorten Borup Petersen     SmallVector<Type, 8> lcvTypes;
36*032cb165SMorten Borup Petersen     lcvTypes.push_back(forOp.getInductionVar().getType());
37*032cb165SMorten Borup Petersen     llvm::transform(forOp.initArgs(), std::back_inserter(lcvTypes),
38*032cb165SMorten Borup Petersen                     [&](auto v) { return v.getType(); });
39*032cb165SMorten Borup Petersen 
40*032cb165SMorten Borup Petersen     // Build scf.WhileOp
41*032cb165SMorten Borup Petersen     SmallVector<Value> initArgs;
42*032cb165SMorten Borup Petersen     initArgs.push_back(forOp.lowerBound());
43*032cb165SMorten Borup Petersen     llvm::append_range(initArgs, forOp.initArgs());
44*032cb165SMorten Borup Petersen     auto whileOp = rewriter.create<WhileOp>(forOp.getLoc(), lcvTypes, initArgs,
45*032cb165SMorten Borup Petersen                                             forOp->getAttrs());
46*032cb165SMorten Borup Petersen 
47*032cb165SMorten Borup Petersen     // 'before' region contains the loop condition and forwarding of iteration
48*032cb165SMorten Borup Petersen     // arguments to the 'after' region.
49*032cb165SMorten Borup Petersen     auto *beforeBlock = rewriter.createBlock(
50*032cb165SMorten Borup Petersen         &whileOp.before(), whileOp.before().begin(), lcvTypes, {});
51*032cb165SMorten Borup Petersen     rewriter.setInsertionPointToStart(&whileOp.before().front());
52*032cb165SMorten Borup Petersen     auto cmpOp = rewriter.create<CmpIOp>(whileOp.getLoc(), CmpIPredicate::slt,
53*032cb165SMorten Borup Petersen                                          beforeBlock->getArgument(0),
54*032cb165SMorten Borup Petersen                                          forOp.upperBound());
55*032cb165SMorten Borup Petersen     rewriter.create<scf::ConditionOp>(whileOp.getLoc(), cmpOp.getResult(),
56*032cb165SMorten Borup Petersen                                       beforeBlock->getArguments());
57*032cb165SMorten Borup Petersen 
58*032cb165SMorten Borup Petersen     // Inline for-loop body into an executeRegion operation in the "after"
59*032cb165SMorten Borup Petersen     // region. The return type of the execRegionOp does not contain the
60*032cb165SMorten Borup Petersen     // iv - yields in the source for-loop contain only iterArgs.
61*032cb165SMorten Borup Petersen     auto *afterBlock = rewriter.createBlock(
62*032cb165SMorten Borup Petersen         &whileOp.after(), whileOp.after().begin(), lcvTypes, {});
63*032cb165SMorten Borup Petersen 
64*032cb165SMorten Borup Petersen     // Add induction variable incrementation
65*032cb165SMorten Borup Petersen     rewriter.setInsertionPointToEnd(afterBlock);
66*032cb165SMorten Borup Petersen     auto ivIncOp = rewriter.create<AddIOp>(
67*032cb165SMorten Borup Petersen         whileOp.getLoc(), afterBlock->getArgument(0), forOp.step());
68*032cb165SMorten Borup Petersen 
69*032cb165SMorten Borup Petersen     // Rewrite uses of the for-loop block arguments to the new while-loop
70*032cb165SMorten Borup Petersen     // "after" arguments
71*032cb165SMorten Borup Petersen     for (auto barg : enumerate(forOp.getBody(0)->getArguments()))
72*032cb165SMorten Borup Petersen       barg.value().replaceAllUsesWith(afterBlock->getArgument(barg.index()));
73*032cb165SMorten Borup Petersen 
74*032cb165SMorten Borup Petersen     // Inline for-loop body operations into 'after' region.
75*032cb165SMorten Borup Petersen     for (auto &arg : llvm::make_early_inc_range(*forOp.getBody()))
76*032cb165SMorten Borup Petersen       arg.moveBefore(afterBlock, afterBlock->end());
77*032cb165SMorten Borup Petersen 
78*032cb165SMorten Borup Petersen     // Add incremented IV to yield operations
79*032cb165SMorten Borup Petersen     for (auto yieldOp : afterBlock->getOps<scf::YieldOp>()) {
80*032cb165SMorten Borup Petersen       SmallVector<Value> yieldOperands = yieldOp.getOperands();
81*032cb165SMorten Borup Petersen       yieldOperands.insert(yieldOperands.begin(), ivIncOp.getResult());
82*032cb165SMorten Borup Petersen       yieldOp->setOperands(yieldOperands);
83*032cb165SMorten Borup Petersen     }
84*032cb165SMorten Borup Petersen 
85*032cb165SMorten Borup Petersen     // We cannot do a direct replacement of the forOp since the while op returns
86*032cb165SMorten Borup Petersen     // an extra value (the induction variable escapes the loop through being
87*032cb165SMorten Borup Petersen     // carried in the set of iterargs). Instead, rewrite uses of the forOp
88*032cb165SMorten Borup Petersen     // results.
89*032cb165SMorten Borup Petersen     for (auto arg : llvm::enumerate(forOp.getResults()))
90*032cb165SMorten Borup Petersen       arg.value().replaceAllUsesWith(whileOp.getResult(arg.index() + 1));
91*032cb165SMorten Borup Petersen 
92*032cb165SMorten Borup Petersen     rewriter.eraseOp(forOp);
93*032cb165SMorten Borup Petersen     return success();
94*032cb165SMorten Borup Petersen   }
95*032cb165SMorten Borup Petersen };
96*032cb165SMorten Borup Petersen 
97*032cb165SMorten Borup Petersen struct ForToWhileLoop : public SCFForToWhileLoopBase<ForToWhileLoop> {
98*032cb165SMorten Borup Petersen   void runOnFunction() override {
99*032cb165SMorten Borup Petersen     FuncOp funcOp = getFunction();
100*032cb165SMorten Borup Petersen     MLIRContext *ctx = funcOp.getContext();
101*032cb165SMorten Borup Petersen     RewritePatternSet patterns(ctx);
102*032cb165SMorten Borup Petersen     patterns.add<ForLoopLoweringPattern>(ctx);
103*032cb165SMorten Borup Petersen     (void)applyPatternsAndFoldGreedily(funcOp, std::move(patterns));
104*032cb165SMorten Borup Petersen   }
105*032cb165SMorten Borup Petersen };
106*032cb165SMorten Borup Petersen } // namespace
107*032cb165SMorten Borup Petersen 
108*032cb165SMorten Borup Petersen std::unique_ptr<Pass> mlir::createForToWhileLoopPass() {
109*032cb165SMorten Borup Petersen   return std::make_unique<ForToWhileLoop>();
110*032cb165SMorten Borup Petersen }
111