xref: /llvm-project/mlir/lib/Conversion/SCFToControlFlow/SCFToControlFlow.cpp (revision c02fd17c1e20615c9e6174a3f8ad4ef0ec5ebbec)
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 &region = op.getRegion();
458ace01605SRiver Riddle   rewriter.setInsertionPointToEnd(condBlock);
459ace01605SRiver Riddle   rewriter.create<cf::BranchOp>(loc, &region.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 &region) -> FailureOr<Block *> {
65791effec8SJeff Niu     Block *block = &region.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