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