1ace01605SRiver Riddle //===- SCFToControlFlow.cpp - SCF to CF conversion ------------------------===// 2ace01605SRiver Riddle // 3ace01605SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ace01605SRiver Riddle // See https://llvm.org/LICENSE.txt for license information. 5ace01605SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ace01605SRiver Riddle // 7ace01605SRiver Riddle //===----------------------------------------------------------------------===// 8ace01605SRiver Riddle // 9ace01605SRiver Riddle // This file implements a pass to convert scf.for, scf.if and loop.terminator 10ace01605SRiver Riddle // ops into standard CFG ops. 11ace01605SRiver Riddle // 12ace01605SRiver Riddle //===----------------------------------------------------------------------===// 13ace01605SRiver Riddle 14ace01605SRiver Riddle #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" 1567d0d7acSMichele Scuttari 16abc362a1SJakub Kuderski #include "mlir/Dialect/Arith/IR/Arith.h" 17ace01605SRiver Riddle #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" 1806fd8086SChristopher Bate #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 198b68da2cSAlex Zinenko #include "mlir/Dialect/SCF/IR/SCF.h" 200b665c3dSSpenser Bauman #include "mlir/Dialect/SCF/Transforms/Transforms.h" 21ace01605SRiver Riddle #include "mlir/IR/Builders.h" 22ace01605SRiver Riddle #include "mlir/IR/BuiltinOps.h" 234d67b278SJeff Niu #include "mlir/IR/IRMapping.h" 24ace01605SRiver Riddle #include "mlir/IR/MLIRContext.h" 25ace01605SRiver Riddle #include "mlir/IR/PatternMatch.h" 26ace01605SRiver Riddle #include "mlir/Transforms/DialectConversion.h" 27ace01605SRiver Riddle #include "mlir/Transforms/Passes.h" 28ace01605SRiver Riddle 2967d0d7acSMichele Scuttari namespace mlir { 3067d0d7acSMichele Scuttari #define GEN_PASS_DEF_SCFTOCONTROLFLOW 3167d0d7acSMichele Scuttari #include "mlir/Conversion/Passes.h.inc" 3267d0d7acSMichele Scuttari } // namespace mlir 3367d0d7acSMichele Scuttari 34ace01605SRiver Riddle using namespace mlir; 35ace01605SRiver Riddle using namespace mlir::scf; 36ace01605SRiver Riddle 37ace01605SRiver Riddle namespace { 38ace01605SRiver Riddle 39039b969bSMichele Scuttari struct SCFToControlFlowPass 4067d0d7acSMichele Scuttari : public impl::SCFToControlFlowBase<SCFToControlFlowPass> { 41ace01605SRiver Riddle void runOnOperation() override; 42ace01605SRiver Riddle }; 43ace01605SRiver Riddle 44ace01605SRiver Riddle // Create a CFG subgraph for the loop around its body blocks (if the body 45ace01605SRiver Riddle // contained other loops, they have been already lowered to a flow of blocks). 46ace01605SRiver Riddle // Maintain the invariants that a CFG subgraph created for any loop has a single 47ace01605SRiver Riddle // entry and a single exit, and that the entry/exit blocks are respectively 48ace01605SRiver Riddle // first/last blocks in the parent region. The original loop operation is 49ace01605SRiver Riddle // replaced by the initialization operations that set up the initial value of 50ace01605SRiver Riddle // the loop induction variable (%iv) and computes the loop bounds that are loop- 51ace01605SRiver Riddle // invariant for affine loops. The operations following the original scf.for 52ace01605SRiver Riddle // are split out into a separate continuation (exit) block. A condition block is 53ace01605SRiver Riddle // created before the continuation block. It checks the exit condition of the 54ace01605SRiver Riddle // loop and branches either to the continuation block, or to the first block of 55ace01605SRiver Riddle // the body. The condition block takes as arguments the values of the induction 56ace01605SRiver Riddle // variable followed by loop-carried values. Since it dominates both the body 57ace01605SRiver Riddle // blocks and the continuation block, loop-carried values are visible in all of 58ace01605SRiver Riddle // those blocks. Induction variable modification is appended to the last block 59ace01605SRiver Riddle // of the body (which is the exit block from the body subgraph thanks to the 60ace01605SRiver Riddle // invariant we maintain) along with a branch that loops back to the condition 61ace01605SRiver Riddle // block. Loop-carried values are the loop terminator operands, which are 62ace01605SRiver Riddle // forwarded to the branch. 63ace01605SRiver Riddle // 64ace01605SRiver Riddle // +---------------------------------+ 65ace01605SRiver Riddle // | <code before the ForOp> | 66ace01605SRiver Riddle // | <definitions of %init...> | 67ace01605SRiver Riddle // | <compute initial %iv value> | 68ace01605SRiver Riddle // | cf.br cond(%iv, %init...) | 69ace01605SRiver Riddle // +---------------------------------+ 70ace01605SRiver Riddle // | 71ace01605SRiver Riddle // -------| | 72ace01605SRiver Riddle // | v v 73ace01605SRiver Riddle // | +--------------------------------+ 74ace01605SRiver Riddle // | | cond(%iv, %init...): | 75ace01605SRiver Riddle // | | <compare %iv to upper bound> | 76ace01605SRiver Riddle // | | cf.cond_br %r, body, end | 77ace01605SRiver Riddle // | +--------------------------------+ 78ace01605SRiver Riddle // | | | 79ace01605SRiver Riddle // | | -------------| 80ace01605SRiver Riddle // | v | 81ace01605SRiver Riddle // | +--------------------------------+ | 82ace01605SRiver Riddle // | | body-first: | | 83ace01605SRiver Riddle // | | <%init visible by dominance> | | 84ace01605SRiver Riddle // | | <body contents> | | 85ace01605SRiver Riddle // | +--------------------------------+ | 86ace01605SRiver Riddle // | | | 87ace01605SRiver Riddle // | ... | 88ace01605SRiver Riddle // | | | 89ace01605SRiver Riddle // | +--------------------------------+ | 90ace01605SRiver Riddle // | | body-last: | | 91ace01605SRiver Riddle // | | <body contents> | | 92ace01605SRiver Riddle // | | <operands of yield = %yields>| | 93ace01605SRiver Riddle // | | %new_iv =<add step to %iv> | | 94ace01605SRiver Riddle // | | cf.br cond(%new_iv, %yields) | | 95ace01605SRiver Riddle // | +--------------------------------+ | 96ace01605SRiver Riddle // | | | 97ace01605SRiver Riddle // |----------- |-------------------- 98ace01605SRiver Riddle // v 99ace01605SRiver Riddle // +--------------------------------+ 100ace01605SRiver Riddle // | end: | 101ace01605SRiver Riddle // | <code after the ForOp> | 102ace01605SRiver Riddle // | <%init visible by dominance> | 103ace01605SRiver Riddle // +--------------------------------+ 104ace01605SRiver Riddle // 105ace01605SRiver Riddle struct ForLowering : public OpRewritePattern<ForOp> { 106ace01605SRiver Riddle using OpRewritePattern<ForOp>::OpRewritePattern; 107ace01605SRiver Riddle 108ace01605SRiver Riddle LogicalResult matchAndRewrite(ForOp forOp, 109ace01605SRiver Riddle PatternRewriter &rewriter) const override; 110ace01605SRiver Riddle }; 111ace01605SRiver Riddle 112ace01605SRiver Riddle // Create a CFG subgraph for the scf.if operation (including its "then" and 113ace01605SRiver Riddle // optional "else" operation blocks). We maintain the invariants that the 114ace01605SRiver Riddle // subgraph has a single entry and a single exit point, and that the entry/exit 115ace01605SRiver Riddle // blocks are respectively the first/last block of the enclosing region. The 116ace01605SRiver Riddle // operations following the scf.if are split into a continuation (subgraph 117ace01605SRiver Riddle // exit) block. The condition is lowered to a chain of blocks that implement the 118ace01605SRiver Riddle // short-circuit scheme. The "scf.if" operation is replaced with a conditional 119ace01605SRiver Riddle // branch to either the first block of the "then" region, or to the first block 120ace01605SRiver Riddle // of the "else" region. In these blocks, "scf.yield" is unconditional branches 121ace01605SRiver Riddle // to the post-dominating block. When the "scf.if" does not return values, the 122ace01605SRiver Riddle // post-dominating block is the same as the continuation block. When it returns 123ace01605SRiver Riddle // values, the post-dominating block is a new block with arguments that 124ace01605SRiver Riddle // correspond to the values returned by the "scf.if" that unconditionally 125ace01605SRiver Riddle // branches to the continuation block. This allows block arguments to dominate 126ace01605SRiver Riddle // any uses of the hitherto "scf.if" results that they replaced. (Inserting a 127ace01605SRiver Riddle // new block allows us to avoid modifying the argument list of an existing 128ace01605SRiver Riddle // block, which is illegal in a conversion pattern). When the "else" region is 129ace01605SRiver Riddle // empty, which is only allowed for "scf.if"s that don't return values, the 130ace01605SRiver Riddle // condition branches directly to the continuation block. 131ace01605SRiver Riddle // 132ace01605SRiver Riddle // CFG for a scf.if with else and without results. 133ace01605SRiver Riddle // 134ace01605SRiver Riddle // +--------------------------------+ 135ace01605SRiver Riddle // | <code before the IfOp> | 136ace01605SRiver Riddle // | cf.cond_br %cond, %then, %else | 137ace01605SRiver Riddle // +--------------------------------+ 138ace01605SRiver Riddle // | | 139ace01605SRiver Riddle // | --------------| 140ace01605SRiver Riddle // v | 141ace01605SRiver Riddle // +--------------------------------+ | 142ace01605SRiver Riddle // | then: | | 143ace01605SRiver Riddle // | <then contents> | | 144ace01605SRiver Riddle // | cf.br continue | | 145ace01605SRiver Riddle // +--------------------------------+ | 146ace01605SRiver Riddle // | | 147ace01605SRiver Riddle // |---------- |------------- 148ace01605SRiver Riddle // | V 149ace01605SRiver Riddle // | +--------------------------------+ 150ace01605SRiver Riddle // | | else: | 151ace01605SRiver Riddle // | | <else contents> | 152ace01605SRiver Riddle // | | cf.br continue | 153ace01605SRiver Riddle // | +--------------------------------+ 154ace01605SRiver Riddle // | | 155ace01605SRiver Riddle // ------| | 156ace01605SRiver Riddle // v v 157ace01605SRiver Riddle // +--------------------------------+ 158ace01605SRiver Riddle // | continue: | 159ace01605SRiver Riddle // | <code after the IfOp> | 160ace01605SRiver Riddle // +--------------------------------+ 161ace01605SRiver Riddle // 162ace01605SRiver Riddle // CFG for a scf.if with results. 163ace01605SRiver Riddle // 164ace01605SRiver Riddle // +--------------------------------+ 165ace01605SRiver Riddle // | <code before the IfOp> | 166ace01605SRiver Riddle // | cf.cond_br %cond, %then, %else | 167ace01605SRiver Riddle // +--------------------------------+ 168ace01605SRiver Riddle // | | 169ace01605SRiver Riddle // | --------------| 170ace01605SRiver Riddle // v | 171ace01605SRiver Riddle // +--------------------------------+ | 172ace01605SRiver Riddle // | then: | | 173ace01605SRiver Riddle // | <then contents> | | 174ace01605SRiver Riddle // | cf.br dom(%args...) | | 175ace01605SRiver Riddle // +--------------------------------+ | 176ace01605SRiver Riddle // | | 177ace01605SRiver Riddle // |---------- |------------- 178ace01605SRiver Riddle // | V 179ace01605SRiver Riddle // | +--------------------------------+ 180ace01605SRiver Riddle // | | else: | 181ace01605SRiver Riddle // | | <else contents> | 182ace01605SRiver Riddle // | | cf.br dom(%args...) | 183ace01605SRiver Riddle // | +--------------------------------+ 184ace01605SRiver Riddle // | | 185ace01605SRiver Riddle // ------| | 186ace01605SRiver Riddle // v v 187ace01605SRiver Riddle // +--------------------------------+ 188ace01605SRiver Riddle // | dom(%args...): | 189ace01605SRiver Riddle // | cf.br continue | 190ace01605SRiver Riddle // +--------------------------------+ 191ace01605SRiver Riddle // | 192ace01605SRiver Riddle // v 193ace01605SRiver Riddle // +--------------------------------+ 194ace01605SRiver Riddle // | continue: | 195ace01605SRiver Riddle // | <code after the IfOp> | 196ace01605SRiver Riddle // +--------------------------------+ 197ace01605SRiver Riddle // 198ace01605SRiver Riddle struct IfLowering : public OpRewritePattern<IfOp> { 199ace01605SRiver Riddle using OpRewritePattern<IfOp>::OpRewritePattern; 200ace01605SRiver Riddle 201ace01605SRiver Riddle LogicalResult matchAndRewrite(IfOp ifOp, 202ace01605SRiver Riddle PatternRewriter &rewriter) const override; 203ace01605SRiver Riddle }; 204ace01605SRiver Riddle 205ace01605SRiver Riddle struct ExecuteRegionLowering : public OpRewritePattern<ExecuteRegionOp> { 206ace01605SRiver Riddle using OpRewritePattern<ExecuteRegionOp>::OpRewritePattern; 207ace01605SRiver Riddle 208ace01605SRiver Riddle LogicalResult matchAndRewrite(ExecuteRegionOp op, 209ace01605SRiver Riddle PatternRewriter &rewriter) const override; 210ace01605SRiver Riddle }; 211ace01605SRiver Riddle 212ace01605SRiver Riddle struct ParallelLowering : public OpRewritePattern<mlir::scf::ParallelOp> { 213ace01605SRiver Riddle using OpRewritePattern<mlir::scf::ParallelOp>::OpRewritePattern; 214ace01605SRiver Riddle 215ace01605SRiver Riddle LogicalResult matchAndRewrite(mlir::scf::ParallelOp parallelOp, 216ace01605SRiver Riddle PatternRewriter &rewriter) const override; 217ace01605SRiver Riddle }; 218ace01605SRiver Riddle 219ace01605SRiver Riddle /// Create a CFG subgraph for this loop construct. The regions of the loop need 220ace01605SRiver Riddle /// not be a single block anymore (for example, if other SCF constructs that 221ace01605SRiver Riddle /// they contain have been already converted to CFG), but need to be single-exit 222ace01605SRiver Riddle /// from the last block of each region. The operations following the original 223ace01605SRiver Riddle /// WhileOp are split into a new continuation block. Both regions of the WhileOp 224ace01605SRiver Riddle /// are inlined, and their terminators are rewritten to organize the control 225ace01605SRiver Riddle /// flow implementing the loop as follows. 226ace01605SRiver Riddle /// 227ace01605SRiver Riddle /// +---------------------------------+ 228ace01605SRiver Riddle /// | <code before the WhileOp> | 229ace01605SRiver Riddle /// | cf.br ^before(%operands...) | 230ace01605SRiver Riddle /// +---------------------------------+ 231ace01605SRiver Riddle /// | 232ace01605SRiver Riddle /// -------| | 233ace01605SRiver Riddle /// | v v 234ace01605SRiver Riddle /// | +--------------------------------+ 235ace01605SRiver Riddle /// | | ^before(%bargs...): | 236ace01605SRiver Riddle /// | | %vals... = <some payload> | 237ace01605SRiver Riddle /// | +--------------------------------+ 238ace01605SRiver Riddle /// | | 239ace01605SRiver Riddle /// | ... 240ace01605SRiver Riddle /// | | 241ace01605SRiver Riddle /// | +--------------------------------+ 242ace01605SRiver Riddle /// | | ^before-last: 243ace01605SRiver Riddle /// | | %cond = <compute condition> | 244ace01605SRiver Riddle /// | | cf.cond_br %cond, | 245ace01605SRiver Riddle /// | | ^after(%vals...), ^cont | 246ace01605SRiver Riddle /// | +--------------------------------+ 247ace01605SRiver Riddle /// | | | 248ace01605SRiver Riddle /// | | -------------| 249ace01605SRiver Riddle /// | v | 250ace01605SRiver Riddle /// | +--------------------------------+ | 251ace01605SRiver Riddle /// | | ^after(%aargs...): | | 252ace01605SRiver Riddle /// | | <body contents> | | 253ace01605SRiver Riddle /// | +--------------------------------+ | 254ace01605SRiver Riddle /// | | | 255ace01605SRiver Riddle /// | ... | 256ace01605SRiver Riddle /// | | | 257ace01605SRiver Riddle /// | +--------------------------------+ | 258ace01605SRiver Riddle /// | | ^after-last: | | 259ace01605SRiver Riddle /// | | %yields... = <some payload> | | 260ace01605SRiver Riddle /// | | cf.br ^before(%yields...) | | 261ace01605SRiver Riddle /// | +--------------------------------+ | 262ace01605SRiver Riddle /// | | | 263ace01605SRiver Riddle /// |----------- |-------------------- 264ace01605SRiver Riddle /// v 265ace01605SRiver Riddle /// +--------------------------------+ 266ace01605SRiver Riddle /// | ^cont: | 267ace01605SRiver Riddle /// | <code after the WhileOp> | 268ace01605SRiver Riddle /// | <%vals from 'before' region | 269ace01605SRiver Riddle /// | visible by dominance> | 270ace01605SRiver Riddle /// +--------------------------------+ 271ace01605SRiver Riddle /// 272ace01605SRiver Riddle /// Values are communicated between ex-regions (the groups of blocks that used 273ace01605SRiver Riddle /// to form a region before inlining) through block arguments of their 274ace01605SRiver Riddle /// entry blocks, which are visible in all other dominated blocks. Similarly, 275ace01605SRiver Riddle /// the results of the WhileOp are defined in the 'before' region, which is 276ace01605SRiver Riddle /// required to have a single existing block, and are therefore accessible in 277ace01605SRiver Riddle /// the continuation block due to dominance. 278ace01605SRiver Riddle struct WhileLowering : public OpRewritePattern<WhileOp> { 279ace01605SRiver Riddle using OpRewritePattern<WhileOp>::OpRewritePattern; 280ace01605SRiver Riddle 281ace01605SRiver Riddle LogicalResult matchAndRewrite(WhileOp whileOp, 282ace01605SRiver Riddle PatternRewriter &rewriter) const override; 283ace01605SRiver Riddle }; 284ace01605SRiver Riddle 285ace01605SRiver Riddle /// Optimized version of the above for the case of the "after" region merely 286ace01605SRiver Riddle /// forwarding its arguments back to the "before" region (i.e., a "do-while" 287ace01605SRiver Riddle /// loop). This avoid inlining the "after" region completely and branches back 288ace01605SRiver Riddle /// to the "before" entry instead. 289ace01605SRiver Riddle struct DoWhileLowering : public OpRewritePattern<WhileOp> { 290ace01605SRiver Riddle using OpRewritePattern<WhileOp>::OpRewritePattern; 291ace01605SRiver Riddle 292ace01605SRiver Riddle LogicalResult matchAndRewrite(WhileOp whileOp, 293ace01605SRiver Riddle PatternRewriter &rewriter) const override; 294ace01605SRiver Riddle }; 29591effec8SJeff Niu 29691effec8SJeff Niu /// Lower an `scf.index_switch` operation to a `cf.switch` operation. 29791effec8SJeff Niu struct IndexSwitchLowering : public OpRewritePattern<IndexSwitchOp> { 29891effec8SJeff Niu using OpRewritePattern::OpRewritePattern; 29991effec8SJeff Niu 30091effec8SJeff Niu LogicalResult matchAndRewrite(IndexSwitchOp op, 30191effec8SJeff Niu PatternRewriter &rewriter) const override; 30291effec8SJeff Niu }; 30387568ff3SMatthias Springer 30487568ff3SMatthias Springer /// Lower an `scf.forall` operation to an `scf.parallel` op, assuming that it 30587568ff3SMatthias Springer /// has no shared outputs. Ops with shared outputs should be bufferized first. 30687568ff3SMatthias Springer /// Specialized lowerings for `scf.forall` (e.g., for GPUs) exist in other 30787568ff3SMatthias Springer /// dialects/passes. 30887568ff3SMatthias Springer struct ForallLowering : public OpRewritePattern<mlir::scf::ForallOp> { 30987568ff3SMatthias Springer using OpRewritePattern<mlir::scf::ForallOp>::OpRewritePattern; 31087568ff3SMatthias Springer 31187568ff3SMatthias Springer LogicalResult matchAndRewrite(mlir::scf::ForallOp forallOp, 31287568ff3SMatthias Springer PatternRewriter &rewriter) const override; 31387568ff3SMatthias Springer }; 31487568ff3SMatthias Springer 315ace01605SRiver Riddle } // namespace 316ace01605SRiver Riddle 317ace01605SRiver Riddle LogicalResult ForLowering::matchAndRewrite(ForOp forOp, 318ace01605SRiver Riddle PatternRewriter &rewriter) const { 319ace01605SRiver Riddle Location loc = forOp.getLoc(); 320ace01605SRiver Riddle 321ace01605SRiver Riddle // Start by splitting the block containing the 'scf.for' into two parts. 322ace01605SRiver Riddle // The part before will get the init code, the part after will be the end 323ace01605SRiver Riddle // point. 324ace01605SRiver Riddle auto *initBlock = rewriter.getInsertionBlock(); 325ace01605SRiver Riddle auto initPosition = rewriter.getInsertionPoint(); 326ace01605SRiver Riddle auto *endBlock = rewriter.splitBlock(initBlock, initPosition); 327ace01605SRiver Riddle 328ace01605SRiver Riddle // Use the first block of the loop body as the condition block since it is the 329ace01605SRiver Riddle // block that has the induction variable and loop-carried values as arguments. 330ace01605SRiver Riddle // Split out all operations from the first block into a new block. Move all 331ace01605SRiver Riddle // body blocks from the loop body region to the region containing the loop. 332ace01605SRiver Riddle auto *conditionBlock = &forOp.getRegion().front(); 333ace01605SRiver Riddle auto *firstBodyBlock = 334ace01605SRiver Riddle rewriter.splitBlock(conditionBlock, conditionBlock->begin()); 335ace01605SRiver Riddle auto *lastBodyBlock = &forOp.getRegion().back(); 336ace01605SRiver Riddle rewriter.inlineRegionBefore(forOp.getRegion(), endBlock); 337ace01605SRiver Riddle auto iv = conditionBlock->getArgument(0); 338ace01605SRiver Riddle 339ace01605SRiver Riddle // Append the induction variable stepping logic to the last body block and 340ace01605SRiver Riddle // branch back to the condition block. Loop-carried values are taken from 341ace01605SRiver Riddle // operands of the loop terminator. 342ace01605SRiver Riddle Operation *terminator = lastBodyBlock->getTerminator(); 343ace01605SRiver Riddle rewriter.setInsertionPointToEnd(lastBodyBlock); 344ace01605SRiver Riddle auto step = forOp.getStep(); 345ace01605SRiver Riddle auto stepped = rewriter.create<arith::AddIOp>(loc, iv, step).getResult(); 346ace01605SRiver Riddle if (!stepped) 347ace01605SRiver Riddle return failure(); 348ace01605SRiver Riddle 349ace01605SRiver Riddle SmallVector<Value, 8> loopCarried; 350ace01605SRiver Riddle loopCarried.push_back(stepped); 351ace01605SRiver Riddle loopCarried.append(terminator->operand_begin(), terminator->operand_end()); 352ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, conditionBlock, loopCarried); 353ace01605SRiver Riddle rewriter.eraseOp(terminator); 354ace01605SRiver Riddle 355ace01605SRiver Riddle // Compute loop bounds before branching to the condition. 356ace01605SRiver Riddle rewriter.setInsertionPointToEnd(initBlock); 357ace01605SRiver Riddle Value lowerBound = forOp.getLowerBound(); 358ace01605SRiver Riddle Value upperBound = forOp.getUpperBound(); 359ace01605SRiver Riddle if (!lowerBound || !upperBound) 360ace01605SRiver Riddle return failure(); 361ace01605SRiver Riddle 362ace01605SRiver Riddle // The initial values of loop-carried values is obtained from the operands 363ace01605SRiver Riddle // of the loop operation. 364ace01605SRiver Riddle SmallVector<Value, 8> destOperands; 365ace01605SRiver Riddle destOperands.push_back(lowerBound); 3665cf714bbSMatthias Springer llvm::append_range(destOperands, forOp.getInitArgs()); 367ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, conditionBlock, destOperands); 368ace01605SRiver Riddle 369ace01605SRiver Riddle // With the body block done, we can fill in the condition block. 370ace01605SRiver Riddle rewriter.setInsertionPointToEnd(conditionBlock); 371ace01605SRiver Riddle auto comparison = rewriter.create<arith::CmpIOp>( 372ace01605SRiver Riddle loc, arith::CmpIPredicate::slt, iv, upperBound); 373ace01605SRiver Riddle 374fbf81e30Sxiaoleis-nv auto condBranchOp = rewriter.create<cf::CondBranchOp>( 375fbf81e30Sxiaoleis-nv loc, comparison, firstBodyBlock, ArrayRef<Value>(), endBlock, 376ace01605SRiver Riddle ArrayRef<Value>()); 377fbf81e30Sxiaoleis-nv 378fbf81e30Sxiaoleis-nv // Let the CondBranchOp carry the LLVM attributes from the ForOp, such as the 379fbf81e30Sxiaoleis-nv // llvm.loop_annotation attribute. 380fbf81e30Sxiaoleis-nv SmallVector<NamedAttribute> llvmAttrs; 381fbf81e30Sxiaoleis-nv llvm::copy_if(forOp->getAttrs(), std::back_inserter(llvmAttrs), 38206fd8086SChristopher Bate [](auto attr) { 38306fd8086SChristopher Bate return isa<LLVM::LLVMDialect>(attr.getValue().getDialect()); 384fbf81e30Sxiaoleis-nv }); 385fbf81e30Sxiaoleis-nv condBranchOp->setDiscardableAttrs(llvmAttrs); 386ace01605SRiver Riddle // The result of the loop operation is the values of the condition block 387ace01605SRiver Riddle // arguments except the induction variable on the last iteration. 388ace01605SRiver Riddle rewriter.replaceOp(forOp, conditionBlock->getArguments().drop_front()); 389ace01605SRiver Riddle return success(); 390ace01605SRiver Riddle } 391ace01605SRiver Riddle 392ace01605SRiver Riddle LogicalResult IfLowering::matchAndRewrite(IfOp ifOp, 393ace01605SRiver Riddle PatternRewriter &rewriter) const { 394ace01605SRiver Riddle auto loc = ifOp.getLoc(); 395ace01605SRiver Riddle 396ace01605SRiver Riddle // Start by splitting the block containing the 'scf.if' into two parts. 397ace01605SRiver Riddle // The part before will contain the condition, the part after will be the 398ace01605SRiver Riddle // continuation point. 399ace01605SRiver Riddle auto *condBlock = rewriter.getInsertionBlock(); 400ace01605SRiver Riddle auto opPosition = rewriter.getInsertionPoint(); 401ace01605SRiver Riddle auto *remainingOpsBlock = rewriter.splitBlock(condBlock, opPosition); 402ace01605SRiver Riddle Block *continueBlock; 403ace01605SRiver Riddle if (ifOp.getNumResults() == 0) { 404ace01605SRiver Riddle continueBlock = remainingOpsBlock; 405ace01605SRiver Riddle } else { 406ace01605SRiver Riddle continueBlock = 407ace01605SRiver Riddle rewriter.createBlock(remainingOpsBlock, ifOp.getResultTypes(), 408ace01605SRiver Riddle SmallVector<Location>(ifOp.getNumResults(), loc)); 409ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, remainingOpsBlock); 410ace01605SRiver Riddle } 411ace01605SRiver Riddle 412ace01605SRiver Riddle // Move blocks from the "then" region to the region containing 'scf.if', 413ace01605SRiver Riddle // place it before the continuation block, and branch to it. 414ace01605SRiver Riddle auto &thenRegion = ifOp.getThenRegion(); 415ace01605SRiver Riddle auto *thenBlock = &thenRegion.front(); 416ace01605SRiver Riddle Operation *thenTerminator = thenRegion.back().getTerminator(); 417ace01605SRiver Riddle ValueRange thenTerminatorOperands = thenTerminator->getOperands(); 418ace01605SRiver Riddle rewriter.setInsertionPointToEnd(&thenRegion.back()); 419ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, continueBlock, thenTerminatorOperands); 420ace01605SRiver Riddle rewriter.eraseOp(thenTerminator); 421ace01605SRiver Riddle rewriter.inlineRegionBefore(thenRegion, continueBlock); 422ace01605SRiver Riddle 423ace01605SRiver Riddle // Move blocks from the "else" region (if present) to the region containing 424ace01605SRiver Riddle // 'scf.if', place it before the continuation block and branch to it. It 425ace01605SRiver Riddle // will be placed after the "then" regions. 426ace01605SRiver Riddle auto *elseBlock = continueBlock; 427ace01605SRiver Riddle auto &elseRegion = ifOp.getElseRegion(); 428ace01605SRiver Riddle if (!elseRegion.empty()) { 429ace01605SRiver Riddle elseBlock = &elseRegion.front(); 430ace01605SRiver Riddle Operation *elseTerminator = elseRegion.back().getTerminator(); 431ace01605SRiver Riddle ValueRange elseTerminatorOperands = elseTerminator->getOperands(); 432ace01605SRiver Riddle rewriter.setInsertionPointToEnd(&elseRegion.back()); 433ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, continueBlock, elseTerminatorOperands); 434ace01605SRiver Riddle rewriter.eraseOp(elseTerminator); 435ace01605SRiver Riddle rewriter.inlineRegionBefore(elseRegion, continueBlock); 436ace01605SRiver Riddle } 437ace01605SRiver Riddle 438ace01605SRiver Riddle rewriter.setInsertionPointToEnd(condBlock); 439ace01605SRiver Riddle rewriter.create<cf::CondBranchOp>(loc, ifOp.getCondition(), thenBlock, 440ace01605SRiver Riddle /*trueArgs=*/ArrayRef<Value>(), elseBlock, 441ace01605SRiver Riddle /*falseArgs=*/ArrayRef<Value>()); 442ace01605SRiver Riddle 443ace01605SRiver Riddle // Ok, we're done! 444ace01605SRiver Riddle rewriter.replaceOp(ifOp, continueBlock->getArguments()); 445ace01605SRiver Riddle return success(); 446ace01605SRiver Riddle } 447ace01605SRiver Riddle 448ace01605SRiver Riddle LogicalResult 449ace01605SRiver Riddle ExecuteRegionLowering::matchAndRewrite(ExecuteRegionOp op, 450ace01605SRiver Riddle PatternRewriter &rewriter) const { 451ace01605SRiver Riddle auto loc = op.getLoc(); 452ace01605SRiver Riddle 453ace01605SRiver Riddle auto *condBlock = rewriter.getInsertionBlock(); 454ace01605SRiver Riddle auto opPosition = rewriter.getInsertionPoint(); 455ace01605SRiver Riddle auto *remainingOpsBlock = rewriter.splitBlock(condBlock, opPosition); 456ace01605SRiver Riddle 457ace01605SRiver Riddle auto ®ion = op.getRegion(); 458ace01605SRiver Riddle rewriter.setInsertionPointToEnd(condBlock); 459ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, ®ion.front()); 460ace01605SRiver Riddle 461ace01605SRiver Riddle for (Block &block : region) { 462ace01605SRiver Riddle if (auto terminator = dyn_cast<scf::YieldOp>(block.getTerminator())) { 463ace01605SRiver Riddle ValueRange terminatorOperands = terminator->getOperands(); 464ace01605SRiver Riddle rewriter.setInsertionPointToEnd(&block); 465ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, remainingOpsBlock, terminatorOperands); 466ace01605SRiver Riddle rewriter.eraseOp(terminator); 467ace01605SRiver Riddle } 468ace01605SRiver Riddle } 469ace01605SRiver Riddle 470ace01605SRiver Riddle rewriter.inlineRegionBefore(region, remainingOpsBlock); 471ace01605SRiver Riddle 472ace01605SRiver Riddle SmallVector<Value> vals; 473ace01605SRiver Riddle SmallVector<Location> argLocs(op.getNumResults(), op->getLoc()); 474ace01605SRiver Riddle for (auto arg : 475ace01605SRiver Riddle remainingOpsBlock->addArguments(op->getResultTypes(), argLocs)) 476ace01605SRiver Riddle vals.push_back(arg); 477ace01605SRiver Riddle rewriter.replaceOp(op, vals); 478ace01605SRiver Riddle return success(); 479ace01605SRiver Riddle } 480ace01605SRiver Riddle 481ace01605SRiver Riddle LogicalResult 482ace01605SRiver Riddle ParallelLowering::matchAndRewrite(ParallelOp parallelOp, 483ace01605SRiver Riddle PatternRewriter &rewriter) const { 484ace01605SRiver Riddle Location loc = parallelOp.getLoc(); 485*c02fd17cSdonald chen auto reductionOp = dyn_cast<ReduceOp>(parallelOp.getBody()->getTerminator()); 486*c02fd17cSdonald chen if (!reductionOp) { 487*c02fd17cSdonald chen return failure(); 488*c02fd17cSdonald chen } 489ace01605SRiver Riddle 490ace01605SRiver Riddle // For a parallel loop, we essentially need to create an n-dimensional loop 491ace01605SRiver Riddle // nest. We do this by translating to scf.for ops and have those lowered in 492ace01605SRiver Riddle // a further rewrite. If a parallel loop contains reductions (and thus returns 493ace01605SRiver Riddle // values), forward the initial values for the reductions down the loop 494ace01605SRiver Riddle // hierarchy and bubble up the results by modifying the "yield" terminator. 495ace01605SRiver Riddle SmallVector<Value, 4> iterArgs = llvm::to_vector<4>(parallelOp.getInitVals()); 496ace01605SRiver Riddle SmallVector<Value, 4> ivs; 497ace01605SRiver Riddle ivs.reserve(parallelOp.getNumLoops()); 498ace01605SRiver Riddle bool first = true; 499ace01605SRiver Riddle SmallVector<Value, 4> loopResults(iterArgs); 5009fa59e76SBenjamin Kramer for (auto [iv, lower, upper, step] : 501ace01605SRiver Riddle llvm::zip(parallelOp.getInductionVars(), parallelOp.getLowerBound(), 502ace01605SRiver Riddle parallelOp.getUpperBound(), parallelOp.getStep())) { 503ace01605SRiver Riddle ForOp forOp = rewriter.create<ForOp>(loc, lower, upper, step, iterArgs); 504ace01605SRiver Riddle ivs.push_back(forOp.getInductionVar()); 505ace01605SRiver Riddle auto iterRange = forOp.getRegionIterArgs(); 506ace01605SRiver Riddle iterArgs.assign(iterRange.begin(), iterRange.end()); 507ace01605SRiver Riddle 508ace01605SRiver Riddle if (first) { 509ace01605SRiver Riddle // Store the results of the outermost loop that will be used to replace 510ace01605SRiver Riddle // the results of the parallel loop when it is fully rewritten. 511ace01605SRiver Riddle loopResults.assign(forOp.result_begin(), forOp.result_end()); 512ace01605SRiver Riddle first = false; 513ace01605SRiver Riddle } else if (!forOp.getResults().empty()) { 514ace01605SRiver Riddle // A loop is constructed with an empty "yield" terminator if there are 515ace01605SRiver Riddle // no results. 516ace01605SRiver Riddle rewriter.setInsertionPointToEnd(rewriter.getInsertionBlock()); 517ace01605SRiver Riddle rewriter.create<scf::YieldOp>(loc, forOp.getResults()); 518ace01605SRiver Riddle } 519ace01605SRiver Riddle 520ace01605SRiver Riddle rewriter.setInsertionPointToStart(forOp.getBody()); 521ace01605SRiver Riddle } 522ace01605SRiver Riddle 523ace01605SRiver Riddle // First, merge reduction blocks into the main region. 52410056c82SMatthias Springer SmallVector<Value> yieldOperands; 525ace01605SRiver Riddle yieldOperands.reserve(parallelOp.getNumResults()); 52610056c82SMatthias Springer for (int64_t i = 0, e = parallelOp.getNumResults(); i < e; ++i) { 52710056c82SMatthias Springer Block &reductionBody = reductionOp.getReductions()[i].front(); 528ace01605SRiver Riddle Value arg = iterArgs[yieldOperands.size()]; 52910056c82SMatthias Springer yieldOperands.push_back( 53010056c82SMatthias Springer cast<ReduceReturnOp>(reductionBody.getTerminator()).getResult()); 53110056c82SMatthias Springer rewriter.eraseOp(reductionBody.getTerminator()); 53210056c82SMatthias Springer rewriter.inlineBlockBefore(&reductionBody, reductionOp, 53310056c82SMatthias Springer {arg, reductionOp.getOperands()[i]}); 534ace01605SRiver Riddle } 53510056c82SMatthias Springer rewriter.eraseOp(reductionOp); 536ace01605SRiver Riddle 537ace01605SRiver Riddle // Then merge the loop body without the terminator. 538ace01605SRiver Riddle Block *newBody = rewriter.getInsertionBlock(); 539ace01605SRiver Riddle if (newBody->empty()) 540ace01605SRiver Riddle rewriter.mergeBlocks(parallelOp.getBody(), newBody, ivs); 541ace01605SRiver Riddle else 54242c31d83SMatthias Springer rewriter.inlineBlockBefore(parallelOp.getBody(), newBody->getTerminator(), 543ace01605SRiver Riddle ivs); 544ace01605SRiver Riddle 545ace01605SRiver Riddle // Finally, create the terminator if required (for loops with no results, it 546ace01605SRiver Riddle // has been already created in loop construction). 547ace01605SRiver Riddle if (!yieldOperands.empty()) { 548ace01605SRiver Riddle rewriter.setInsertionPointToEnd(rewriter.getInsertionBlock()); 549ace01605SRiver Riddle rewriter.create<scf::YieldOp>(loc, yieldOperands); 550ace01605SRiver Riddle } 551ace01605SRiver Riddle 552ace01605SRiver Riddle rewriter.replaceOp(parallelOp, loopResults); 553ace01605SRiver Riddle 554ace01605SRiver Riddle return success(); 555ace01605SRiver Riddle } 556ace01605SRiver Riddle 557ace01605SRiver Riddle LogicalResult WhileLowering::matchAndRewrite(WhileOp whileOp, 558ace01605SRiver Riddle PatternRewriter &rewriter) const { 559ace01605SRiver Riddle OpBuilder::InsertionGuard guard(rewriter); 560ace01605SRiver Riddle Location loc = whileOp.getLoc(); 561ace01605SRiver Riddle 562ace01605SRiver Riddle // Split the current block before the WhileOp to create the inlining point. 563ace01605SRiver Riddle Block *currentBlock = rewriter.getInsertionBlock(); 564ace01605SRiver Riddle Block *continuation = 565ace01605SRiver Riddle rewriter.splitBlock(currentBlock, rewriter.getInsertionPoint()); 566ace01605SRiver Riddle 567ace01605SRiver Riddle // Inline both regions. 5687c74a250SMatthias Springer Block *after = whileOp.getAfterBody(); 5697c74a250SMatthias Springer Block *before = whileOp.getBeforeBody(); 570ace01605SRiver Riddle rewriter.inlineRegionBefore(whileOp.getAfter(), continuation); 571ace01605SRiver Riddle rewriter.inlineRegionBefore(whileOp.getBefore(), after); 572ace01605SRiver Riddle 573ace01605SRiver Riddle // Branch to the "before" region. 574ace01605SRiver Riddle rewriter.setInsertionPointToEnd(currentBlock); 575ace01605SRiver Riddle rewriter.create<cf::BranchOp>(loc, before, whileOp.getInits()); 576ace01605SRiver Riddle 577ace01605SRiver Riddle // Replace terminators with branches. Assuming bodies are SESE, which holds 578ace01605SRiver Riddle // given only the patterns from this file, we only need to look at the last 579ace01605SRiver Riddle // block. This should be reconsidered if we allow break/continue in SCF. 5807c74a250SMatthias Springer rewriter.setInsertionPointToEnd(before); 5817c74a250SMatthias Springer auto condOp = cast<ConditionOp>(before->getTerminator()); 582ace01605SRiver Riddle rewriter.replaceOpWithNewOp<cf::CondBranchOp>(condOp, condOp.getCondition(), 583ace01605SRiver Riddle after, condOp.getArgs(), 584ace01605SRiver Riddle continuation, ValueRange()); 585ace01605SRiver Riddle 5867c74a250SMatthias Springer rewriter.setInsertionPointToEnd(after); 5877c74a250SMatthias Springer auto yieldOp = cast<scf::YieldOp>(after->getTerminator()); 588ace01605SRiver Riddle rewriter.replaceOpWithNewOp<cf::BranchOp>(yieldOp, before, 589ace01605SRiver Riddle yieldOp.getResults()); 590ace01605SRiver Riddle 591ace01605SRiver Riddle // Replace the op with values "yielded" from the "before" region, which are 592ace01605SRiver Riddle // visible by dominance. 593ace01605SRiver Riddle rewriter.replaceOp(whileOp, condOp.getArgs()); 594ace01605SRiver Riddle 595ace01605SRiver Riddle return success(); 596ace01605SRiver Riddle } 597ace01605SRiver Riddle 598ace01605SRiver Riddle LogicalResult 599ace01605SRiver Riddle DoWhileLowering::matchAndRewrite(WhileOp whileOp, 600ace01605SRiver Riddle PatternRewriter &rewriter) const { 6017c74a250SMatthias Springer Block &afterBlock = *whileOp.getAfterBody(); 602ace01605SRiver Riddle if (!llvm::hasSingleElement(afterBlock)) 603ace01605SRiver Riddle return rewriter.notifyMatchFailure(whileOp, 604ace01605SRiver Riddle "do-while simplification applicable " 605ace01605SRiver Riddle "only if 'after' region has no payload"); 606ace01605SRiver Riddle 607ace01605SRiver Riddle auto yield = dyn_cast<scf::YieldOp>(&afterBlock.front()); 608ace01605SRiver Riddle if (!yield || yield.getResults() != afterBlock.getArguments()) 609ace01605SRiver Riddle return rewriter.notifyMatchFailure(whileOp, 610ace01605SRiver Riddle "do-while simplification applicable " 611ace01605SRiver Riddle "only to forwarding 'after' regions"); 612ace01605SRiver Riddle 613ace01605SRiver Riddle // Split the current block before the WhileOp to create the inlining point. 614ace01605SRiver Riddle OpBuilder::InsertionGuard guard(rewriter); 615ace01605SRiver Riddle Block *currentBlock = rewriter.getInsertionBlock(); 616ace01605SRiver Riddle Block *continuation = 617ace01605SRiver Riddle rewriter.splitBlock(currentBlock, rewriter.getInsertionPoint()); 618ace01605SRiver Riddle 619ace01605SRiver Riddle // Only the "before" region should be inlined. 6207c74a250SMatthias Springer Block *before = whileOp.getBeforeBody(); 621ace01605SRiver Riddle rewriter.inlineRegionBefore(whileOp.getBefore(), continuation); 622ace01605SRiver Riddle 623ace01605SRiver Riddle // Branch to the "before" region. 624ace01605SRiver Riddle rewriter.setInsertionPointToEnd(currentBlock); 625ace01605SRiver Riddle rewriter.create<cf::BranchOp>(whileOp.getLoc(), before, whileOp.getInits()); 626ace01605SRiver Riddle 627ace01605SRiver Riddle // Loop around the "before" region based on condition. 6287c74a250SMatthias Springer rewriter.setInsertionPointToEnd(before); 6297c74a250SMatthias Springer auto condOp = cast<ConditionOp>(before->getTerminator()); 630ace01605SRiver Riddle rewriter.replaceOpWithNewOp<cf::CondBranchOp>(condOp, condOp.getCondition(), 631ace01605SRiver Riddle before, condOp.getArgs(), 632ace01605SRiver Riddle continuation, ValueRange()); 633ace01605SRiver Riddle 634ace01605SRiver Riddle // Replace the op with values "yielded" from the "before" region, which are 635ace01605SRiver Riddle // visible by dominance. 636ace01605SRiver Riddle rewriter.replaceOp(whileOp, condOp.getArgs()); 637ace01605SRiver Riddle 638ace01605SRiver Riddle return success(); 639ace01605SRiver Riddle } 640ace01605SRiver Riddle 64191effec8SJeff Niu LogicalResult 64291effec8SJeff Niu IndexSwitchLowering::matchAndRewrite(IndexSwitchOp op, 64391effec8SJeff Niu PatternRewriter &rewriter) const { 64491effec8SJeff Niu // Split the block at the op. 64591effec8SJeff Niu Block *condBlock = rewriter.getInsertionBlock(); 64691effec8SJeff Niu Block *continueBlock = rewriter.splitBlock(condBlock, Block::iterator(op)); 64791effec8SJeff Niu 64891effec8SJeff Niu // Create the arguments on the continue block with which to replace the 64991effec8SJeff Niu // results of the op. 65091effec8SJeff Niu SmallVector<Value> results; 65191effec8SJeff Niu results.reserve(op.getNumResults()); 65291effec8SJeff Niu for (Type resultType : op.getResultTypes()) 65391effec8SJeff Niu results.push_back(continueBlock->addArgument(resultType, op.getLoc())); 65491effec8SJeff Niu 65591effec8SJeff Niu // Handle the regions. 65691effec8SJeff Niu auto convertRegion = [&](Region ®ion) -> FailureOr<Block *> { 65791effec8SJeff Niu Block *block = ®ion.front(); 65891effec8SJeff Niu 65991effec8SJeff Niu // Convert the yield terminator to a branch to the continue block. 66091effec8SJeff Niu auto yield = cast<scf::YieldOp>(block->getTerminator()); 66191effec8SJeff Niu rewriter.setInsertionPoint(yield); 66291effec8SJeff Niu rewriter.replaceOpWithNewOp<cf::BranchOp>(yield, continueBlock, 66391effec8SJeff Niu yield.getOperands()); 66491effec8SJeff Niu 66591effec8SJeff Niu // Inline the region. 66691effec8SJeff Niu rewriter.inlineRegionBefore(region, continueBlock); 66791effec8SJeff Niu return block; 66891effec8SJeff Niu }; 66991effec8SJeff Niu 67091effec8SJeff Niu // Convert the case regions. 67191effec8SJeff Niu SmallVector<Block *> caseSuccessors; 67291effec8SJeff Niu SmallVector<int32_t> caseValues; 67391effec8SJeff Niu caseSuccessors.reserve(op.getCases().size()); 67491effec8SJeff Niu caseValues.reserve(op.getCases().size()); 67591effec8SJeff Niu for (auto [region, value] : llvm::zip(op.getCaseRegions(), op.getCases())) { 67691effec8SJeff Niu FailureOr<Block *> block = convertRegion(region); 67791effec8SJeff Niu if (failed(block)) 67891effec8SJeff Niu return failure(); 67991effec8SJeff Niu caseSuccessors.push_back(*block); 68091effec8SJeff Niu caseValues.push_back(value); 68191effec8SJeff Niu } 68291effec8SJeff Niu 68391effec8SJeff Niu // Convert the default region. 68491effec8SJeff Niu FailureOr<Block *> defaultBlock = convertRegion(op.getDefaultRegion()); 68591effec8SJeff Niu if (failed(defaultBlock)) 68691effec8SJeff Niu return failure(); 68791effec8SJeff Niu 68891effec8SJeff Niu // Create the switch. 68991effec8SJeff Niu rewriter.setInsertionPointToEnd(condBlock); 69091effec8SJeff Niu SmallVector<ValueRange> caseOperands(caseSuccessors.size(), {}); 69103b43d3dSEugene Zhulenev 69203b43d3dSEugene Zhulenev // Cast switch index to integer case value. 69303b43d3dSEugene Zhulenev Value caseValue = rewriter.create<arith::IndexCastOp>( 69403b43d3dSEugene Zhulenev op.getLoc(), rewriter.getI32Type(), op.getArg()); 69503b43d3dSEugene Zhulenev 69691effec8SJeff Niu rewriter.create<cf::SwitchOp>( 69703b43d3dSEugene Zhulenev op.getLoc(), caseValue, *defaultBlock, ValueRange(), 69891effec8SJeff Niu rewriter.getDenseI32ArrayAttr(caseValues), caseSuccessors, caseOperands); 69991effec8SJeff Niu rewriter.replaceOp(op, continueBlock->getArguments()); 70091effec8SJeff Niu return success(); 70191effec8SJeff Niu } 70291effec8SJeff Niu 70387568ff3SMatthias Springer LogicalResult ForallLowering::matchAndRewrite(ForallOp forallOp, 70487568ff3SMatthias Springer PatternRewriter &rewriter) const { 7050b665c3dSSpenser Bauman return scf::forallToParallelLoop(rewriter, forallOp); 70687568ff3SMatthias Springer } 70787568ff3SMatthias Springer 708ace01605SRiver Riddle void mlir::populateSCFToControlFlowConversionPatterns( 709ace01605SRiver Riddle RewritePatternSet &patterns) { 71087568ff3SMatthias Springer patterns.add<ForallLowering, ForLowering, IfLowering, ParallelLowering, 71187568ff3SMatthias Springer WhileLowering, ExecuteRegionLowering, IndexSwitchLowering>( 71291effec8SJeff Niu patterns.getContext()); 713ace01605SRiver Riddle patterns.add<DoWhileLowering>(patterns.getContext(), /*benefit=*/2); 714ace01605SRiver Riddle } 715ace01605SRiver Riddle 716039b969bSMichele Scuttari void SCFToControlFlowPass::runOnOperation() { 717ace01605SRiver Riddle RewritePatternSet patterns(&getContext()); 718ace01605SRiver Riddle populateSCFToControlFlowConversionPatterns(patterns); 719ace01605SRiver Riddle 720ace01605SRiver Riddle // Configure conversion to lower out SCF operations. 721ace01605SRiver Riddle ConversionTarget target(getContext()); 72287568ff3SMatthias Springer target.addIllegalOp<scf::ForallOp, scf::ForOp, scf::IfOp, scf::IndexSwitchOp, 72303b43d3dSEugene Zhulenev scf::ParallelOp, scf::WhileOp, scf::ExecuteRegionOp>(); 724ace01605SRiver Riddle target.markUnknownOpDynamicallyLegal([](Operation *) { return true; }); 725ace01605SRiver Riddle if (failed( 726ace01605SRiver Riddle applyPartialConversion(getOperation(), target, std::move(patterns)))) 727ace01605SRiver Riddle signalPassFailure(); 728ace01605SRiver Riddle } 729039b969bSMichele Scuttari 730039b969bSMichele Scuttari std::unique_ptr<Pass> mlir::createConvertSCFToCFPass() { 731039b969bSMichele Scuttari return std::make_unique<SCFToControlFlowPass>(); 732039b969bSMichele Scuttari } 733