MLIR 23.0.0git
CFGToSCF.cpp
Go to the documentation of this file.
1//===- CFGToSCF.h - Control Flow Graph to Structured Control Flow *- C++ -*===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This code is an implementation of:
10// Helge Bahmann, Nico Reissmann, Magnus Jahre, and Jan Christian Meyer. 2015.
11// Perfect Reconstructability of Control Flow from Demand Dependence Graphs. ACM
12// Trans. Archit. Code Optim. 11, 4, Article 66 (January 2015), 25 pages.
13// https://doi.org/10.1145/2693261
14//
15// It defines an algorithm to translate any control flow graph with a single
16// entry and single exit block into structured control flow operations
17// consisting of regions of do-while loops and operations conditionally
18// dispatching to one out of multiple regions before continuing after the
19// operation. This includes control flow graphs containing irreducible
20// control flow.
21//
22// The implementation here additionally supports the transformation on
23// regions with multiple exit blocks. This is implemented by first
24// transforming all occurrences of return-like operations to branch to a
25// single exit block containing an instance of that return-like operation.
26// If there are multiple kinds of return-like operations, multiple exit
27// blocks are created. In that case the transformation leaves behind a
28// conditional control flow graph operation that dispatches to the given regions
29// terminating with different kinds of return-like operations each.
30//
31// If the function only contains a single kind of return-like operations,
32// it is guaranteed that all control flow graph ops will be lifted to structured
33// control flow, and that no more control flow graph ops remain after the
34// operation.
35//
36// The algorithm to lift CFGs consists of two transformations applied after each
37// other on any single-entry, single-exit region:
38// 1) Lifting cycles to structured control flow loops
39// 2) Lifting conditional branches to structured control flow branches
40// These are then applied recursively on any new single-entry single-exit
41// regions created by the transformation until no more CFG operations remain.
42//
43// The first part of cycle lifting is to detect any cycles in the CFG.
44// This is done using an algorithm for iterating over SCCs. Every SCC
45// representing a cycle is then transformed into a structured loop with a single
46// entry block and a single latch containing the only back edge to the entry
47// block and the only edge to an exit block outside the loop. Rerouting control
48// flow to create single entry and exit blocks is achieved via a multiplexer
49// construct that can be visualized as follows:
50// +-----+ +-----+ +-----+
51// | bb0 | | bb1 |...| bbN |
52// +--+--+ +--+--+ +-+---+
53// | | |
54// | v |
55// | +------+ |
56// | ++ ++<----+
57// | | Region |
58// +>| |<----+
59// ++ ++ |
60// +------+------+
61//
62// The above transforms to:
63// +-----+ +-----+ +-----+
64// | bb0 | | bb1 |...| bbN |
65// +-----+ +--|--+ ++----+
66// | v |
67// +->+-----+<---+
68// | bbM |<-------+
69// +---+-+ |
70// +---+ | +----+ |
71// | v | |
72// | +------+ | |
73// | ++ ++<-+ |
74// +->| Region | |
75// ++ ++ |
76// +------+-------+
77//
78// bbM in the above is the multiplexer block, and any block previously branching
79// to an entry block of the region are redirected to it. This includes any
80// branches from within the region. Using a block argument, bbM then dispatches
81// to the correct entry block of the region dependent on the predecessor.
82//
83// A similar transformation is done to create the latch block with the single
84// back edge and loop exit edge.
85//
86// The above form has the advantage that bbM now acts as the loop header
87// of the loop body. After the transformation on the latch, this results in a
88// structured loop that can then be lifted to structured control flow. The
89// conditional branches created in bbM are later lifted to conditional
90// branches.
91//
92// Lifting conditional branches is done by analyzing the *first* conditional
93// branch encountered in the entry region. The algorithm then identifies
94// all blocks that are dominated by a specific control flow edge and
95// the region where control flow continues:
96// +-----+
97// +-----+ bb0 +----+
98// v +-----+ v
99// Region 1 +-+-+ ... +-+-+ Region n
100// +---+ +---+
101// ... ...
102// | |
103// | +---+ |
104// +---->++ ++<---+
105// | |
106// ++ ++ Region T
107// +---+
108// Every region following bb0 consists of 0 or more blocks that eventually
109// branch to Region T. If there are multiple entry blocks into Region T, a
110// single entry block is created using a multiplexer block as shown above.
111// Region 1 to Region n are then lifted together with the conditional control
112// flow operation terminating bb0 into a structured conditional operation
113// followed by the operations of the entry block of Region T.
114//===----------------------------------------------------------------------===//
115
117
120#include "llvm/ADT/DepthFirstIterator.h"
121#include "llvm/ADT/MapVector.h"
122#include "llvm/ADT/SCCIterator.h"
123#include "llvm/ADT/SetVector.h"
124
125using namespace mlir;
126
127/// Returns the mutable operand range used to transfer operands from `block` to
128/// its successor with the given index. The returned range being mutable allows
129/// us to modify the operands being transferred.
131getMutableSuccessorOperands(Block *block, unsigned successorIndex) {
132 auto branchOpInterface = cast<BranchOpInterface>(block->getTerminator());
133 SuccessorOperands succOps =
134 branchOpInterface.getSuccessorOperands(successorIndex);
135 return succOps.getMutableForwardedOperands();
136}
137
138/// Return the operand range used to transfer operands from `block` to its
139/// successor with the given index.
141 unsigned successorIndex) {
142 return getMutableSuccessorOperands(block, successorIndex);
143}
144
145/// Appends all the block arguments from `other` to the block arguments of
146/// `block`, copying their types and locations.
147static void addBlockArgumentsFromOther(Block *block, Block *other) {
148 for (BlockArgument arg : other->getArguments())
149 block->addArgument(arg.getType(), arg.getLoc());
150}
151
152namespace {
153
154/// Class representing an edge in the CFG. Consists of a from-block, a successor
155/// and corresponding successor operands passed to the block arguments of the
156/// successor.
157class Edge {
158 Block *fromBlock;
159 unsigned successorIndex;
160
161public:
162 /// Constructs a new edge from `fromBlock` to the successor corresponding to
163 /// `successorIndex`.
164 Edge(Block *fromBlock, unsigned int successorIndex)
165 : fromBlock(fromBlock), successorIndex(successorIndex) {}
166
167 /// Returns the from-block.
168 Block *getFromBlock() const { return fromBlock; }
169
170 /// Returns the successor of the edge.
171 Block *getSuccessor() const {
172 return fromBlock->getSuccessor(successorIndex);
173 }
174
175 /// Sets the successor of the edge, adjusting the terminator in the
176 /// from-block.
177 void setSuccessor(Block *block) const {
178 fromBlock->getTerminator()->setSuccessor(block, successorIndex);
179 }
180
181 /// Returns the arguments of this edge that are passed to the block arguments
182 /// of the successor.
183 MutableOperandRange getMutableSuccessorOperands() const {
184 return ::getMutableSuccessorOperands(fromBlock, successorIndex);
185 }
186
187 /// Returns the arguments of this edge that are passed to the block arguments
188 /// of the successor.
189 OperandRange getSuccessorOperands() const {
190 return ::getSuccessorOperands(fromBlock, successorIndex);
191 }
192};
193
194/// Structure containing the entry, exit and back edges of a cycle. A cycle is a
195/// generalization of a loop that may have multiple entry edges. See also
196/// https://llvm.org/docs/CycleTerminology.html.
197struct CycleEdges {
198 /// All edges from a block outside the cycle to a block inside the cycle.
199 /// The targets of these edges are entry blocks.
200 SmallVector<Edge> entryEdges;
201 /// All edges from a block inside the cycle to a block outside the cycle.
202 SmallVector<Edge> exitEdges;
203 /// All edges from a block inside the cycle to an entry block.
204 SmallVector<Edge> backEdges;
205};
206
207/// Class used to orchestrate creation of so-called edge multiplexers.
208/// This class creates a new basic block and routes all inputs edges
209/// to this basic block before branching to their original target.
210/// The purpose of this transformation is to create single-entry,
211/// single-exit regions.
212class EdgeMultiplexer {
213public:
214 /// Creates a new edge multiplexer capable of redirecting all edges to one of
215 /// the `entryBlocks`. This creates the multiplexer basic block with
216 /// appropriate block arguments after the first entry block. `extraArgs`
217 /// contains the types of possible extra block arguments passed to the
218 /// multiplexer block that are added to the successor operands of every
219 /// outgoing edge.
220 ///
221 /// NOTE: This does not yet redirect edges to branch to the
222 /// multiplexer block nor code dispatching from the multiplexer code
223 /// to the original successors.
224 /// See `redirectEdge` and `createSwitch`.
225 static EdgeMultiplexer create(Location loc, ArrayRef<Block *> entryBlocks,
226 function_ref<Value(unsigned)> getSwitchValue,
227 function_ref<Value(Type)> getUndefValue,
228 TypeRange extraArgs = {}) {
229 assert(!entryBlocks.empty() && "Require at least one entry block");
230
231 auto *multiplexerBlock = new Block;
232 multiplexerBlock->insertAfter(entryBlocks.front());
233
234 // To implement the multiplexer block, we have to add the block arguments of
235 // every distinct successor block to the multiplexer block. When redirecting
236 // edges, block arguments designated for blocks that aren't branched to will
237 // be assigned the `getUndefValue`. The amount of block arguments and their
238 // offset is saved in the map for `redirectEdge` to transform the edges.
239 llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
240 for (Block *entryBlock : entryBlocks) {
241 auto [iter, inserted] = blockArgMapping.insert(
242 {entryBlock, multiplexerBlock->getNumArguments()});
243 if (inserted)
244 addBlockArgumentsFromOther(multiplexerBlock, entryBlock);
245 }
246
247 // If we have more than one successor, we have to additionally add a
248 // discriminator value, denoting which successor to jump to.
249 // When redirecting edges, an appropriate value will be passed using
250 // `getSwitchValue`.
251 Value discriminator;
252 if (blockArgMapping.size() > 1)
253 discriminator =
254 multiplexerBlock->addArgument(getSwitchValue(0).getType(), loc);
255
256 multiplexerBlock->addArguments(
257 extraArgs, SmallVector<Location>(extraArgs.size(), loc));
258
259 return EdgeMultiplexer(multiplexerBlock, getSwitchValue, getUndefValue,
260 std::move(blockArgMapping), discriminator);
261 }
262
263 /// Returns the created multiplexer block.
264 Block *getMultiplexerBlock() const { return multiplexerBlock; }
265
266 /// Redirects `edge` to branch to the multiplexer block before continuing to
267 /// its original target. The edges successor must have originally been part
268 /// of the entry blocks array passed to the `create` function. `extraArgs`
269 /// must be used to pass along any additional values corresponding to
270 /// `extraArgs` in `create`.
271 void redirectEdge(Edge edge, ValueRange extraArgs = {}) const {
272 const auto *result = blockArgMapping.find(edge.getSuccessor());
273 assert(result != blockArgMapping.end() &&
274 "Edge was not originally passed to `create` method.");
275
276 MutableOperandRange successorOperands = edge.getMutableSuccessorOperands();
277
278 // Extra arguments are always appended at the end of the block arguments.
279 unsigned extraArgsBeginIndex =
280 multiplexerBlock->getNumArguments() - extraArgs.size();
281 // If a discriminator exists, it is right before the extra arguments.
282 std::optional<unsigned> discriminatorIndex =
283 discriminator ? extraArgsBeginIndex - 1 : std::optional<unsigned>{};
284
285 SmallVector<Value> newSuccOperands(multiplexerBlock->getNumArguments());
286 for (BlockArgument argument : multiplexerBlock->getArguments()) {
287 unsigned index = argument.getArgNumber();
288 if (index >= result->second &&
289 index < result->second + edge.getSuccessor()->getNumArguments()) {
290 // Original block arguments to the entry block.
291 newSuccOperands[index] =
292 successorOperands[index - result->second].get();
293 continue;
294 }
295
296 // Discriminator value if it exists.
297 if (index == discriminatorIndex) {
298 newSuccOperands[index] =
299 getSwitchValue(result - blockArgMapping.begin());
300 continue;
301 }
302
303 // Followed by the extra arguments.
304 if (index >= extraArgsBeginIndex) {
305 newSuccOperands[index] = extraArgs[index - extraArgsBeginIndex];
306 continue;
307 }
308
309 // Otherwise undef values for any unused block arguments used by other
310 // entry blocks.
311 newSuccOperands[index] = getUndefValue(argument.getType());
312 }
313
314 edge.setSuccessor(multiplexerBlock);
315 successorOperands.assign(newSuccOperands);
316 }
317
318 /// Creates a switch op using `builder` which dispatches to the original
319 /// successors of the edges passed to `create` minus the ones in `excluded`.
320 /// The builder's insertion point has to be in a block dominated by the
321 /// multiplexer block. All edges to the multiplexer block must have already
322 /// been redirected using `redirectEdge`.
323 void createSwitch(
324 Location loc, OpBuilder &builder, CFGToSCFInterface &interface,
325 const SmallPtrSetImpl<Block *> &excluded = SmallPtrSet<Block *, 1>{}) {
326 // We create the switch by creating a case for all entries and then
327 // splitting of the last entry as a default case.
328
329 SmallVector<ValueRange> caseArguments;
330 SmallVector<unsigned> caseValues;
331 SmallVector<Block *> caseDestinations;
332 for (auto &&[index, pair] : llvm::enumerate(blockArgMapping)) {
333 auto &&[succ, offset] = pair;
334 if (excluded.contains(succ))
335 continue;
336
337 caseValues.push_back(index);
338 caseArguments.push_back(multiplexerBlock->getArguments().slice(
339 offset, succ->getNumArguments()));
340 caseDestinations.push_back(succ);
341 }
342
343 // If we don't have a discriminator due to only having one entry we have to
344 // create a dummy flag for the switch.
345 Value realDiscriminator = discriminator;
346 if (!realDiscriminator || caseArguments.size() == 1)
347 realDiscriminator = getSwitchValue(0);
348
349 caseValues.pop_back();
350 Block *defaultDest = caseDestinations.pop_back_val();
351 ValueRange defaultArgs = caseArguments.pop_back_val();
352
353 assert(!builder.getInsertionBlock()->hasNoPredecessors() &&
354 "Edges need to be redirected prior to creating switch.");
355 interface.createCFGSwitchOp(loc, builder, realDiscriminator, caseValues,
356 caseDestinations, caseArguments, defaultDest,
357 defaultArgs);
358 }
359
360private:
361 /// Newly created multiplexer block.
362 Block *multiplexerBlock;
363 /// Callback used to create a constant suitable as flag for
364 /// the interfaces `createCFGSwitchOp`.
365 function_ref<Value(unsigned)> getSwitchValue;
366 /// Callback used to create undefined values of a given type.
367 function_ref<Value(Type)> getUndefValue;
368
369 /// Mapping of the block arguments of an entry block to the corresponding
370 /// block arguments in the multiplexer block. Block arguments of an entry
371 /// block are simply appended ot the multiplexer block. This map simply
372 /// contains the offset to the range in the multiplexer block.
373 llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
374 /// Discriminator value used in the multiplexer block to dispatch to the
375 /// correct entry block. Null value if not required due to only having one
376 /// entry block.
377 Value discriminator;
378
379 EdgeMultiplexer(Block *multiplexerBlock,
380 function_ref<Value(unsigned)> getSwitchValue,
381 function_ref<Value(Type)> getUndefValue,
382 llvm::SmallMapVector<Block *, unsigned, 4> &&entries,
383 Value dispatchFlag)
384 : multiplexerBlock(multiplexerBlock), getSwitchValue(getSwitchValue),
385 getUndefValue(getUndefValue), blockArgMapping(std::move(entries)),
386 discriminator(dispatchFlag) {}
387};
388
389/// Alternative implementation of DenseMapInfo<Operation*> using the operation
390/// equivalence infrastructure to check whether two 'return-like' operations are
391/// equivalent in the context of this transformation. This means that both
392/// operations are of the same kind, have the same amount of operands and types
393/// and the same attributes and properties. The operands themselves don't have
394/// to be equivalent.
395struct ReturnLikeOpEquivalence : public llvm::DenseMapInfo<Operation *> {
396 static unsigned getHashValue(const Operation *opC) {
398 const_cast<Operation *>(opC),
402 }
403
404 static bool isEqual(const Operation *lhs, const Operation *rhs) {
405 if (lhs == rhs)
406 return true;
408 const_cast<Operation *>(lhs), const_cast<Operation *>(rhs),
411 }
412};
413
414/// Utility-class for transforming a region to only have one single block for
415/// every return-like operation.
416class ReturnLikeExitCombiner {
417public:
418 ReturnLikeExitCombiner(Region &topLevelRegion, CFGToSCFInterface &interface)
419 : topLevelRegion(topLevelRegion), interface(interface) {}
420
421 /// Transforms `returnLikeOp` to a branch to the only block in the
422 /// region with an instance of `returnLikeOp`s kind.
423 void combineExit(Operation *returnLikeOp,
424 function_ref<Value(unsigned)> getSwitchValue) {
425 auto [iter, inserted] = returnLikeToCombinedExit.try_emplace(returnLikeOp);
426 if (!inserted && iter->first == returnLikeOp)
427 return;
428
429 Block *exitBlock = iter->second;
430 if (inserted) {
431 exitBlock = new Block;
432 iter->second = exitBlock;
433 topLevelRegion.push_back(exitBlock);
434 exitBlock->addArguments(
435 returnLikeOp->getOperandTypes(),
436 SmallVector<Location>(returnLikeOp->getNumOperands(),
437 returnLikeOp->getLoc()));
438 }
439
440 auto builder = OpBuilder::atBlockTerminator(returnLikeOp->getBlock());
441 interface.createSingleDestinationBranch(returnLikeOp->getLoc(), builder,
442 getSwitchValue(0), exitBlock,
443 returnLikeOp->getOperands());
444
445 if (!inserted) {
446 returnLikeOp->erase();
447 return;
448 }
449
450 returnLikeOp->moveBefore(exitBlock, exitBlock->end());
451 returnLikeOp->setOperands(exitBlock->getArguments());
452 }
453
454private:
455 /// Mapping of return-like operation to block. All return-like operations
456 /// of the same kind with the same attributes, properties and types are seen
457 /// as equivalent. First occurrence seen is kept in the map.
458 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
459 returnLikeToCombinedExit;
460 Region &topLevelRegion;
461 CFGToSCFInterface &interface;
462};
463
464} // namespace
465
466/// Returns a range of all edges from `block` to each of its successors.
467static auto successorEdges(Block *block) {
468 return llvm::map_range(llvm::seq(block->getNumSuccessors()),
469 [=](unsigned index) { return Edge(block, index); });
470}
471
472/// Calculates entry, exit and back edges of the given cycle.
473static CycleEdges
474calculateCycleEdges(const llvm::SmallSetVector<Block *, 4> &cycles) {
475 CycleEdges result;
476 SmallPtrSet<Block *, 8> entryBlocks;
477
478 // First identify all exit and entry edges by checking whether any successors
479 // or predecessors are from outside the cycles.
480 for (Block *block : cycles) {
481 for (auto pred = block->pred_begin(); pred != block->pred_end(); pred++) {
482 if (cycles.contains(*pred))
483 continue;
484
485 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
486 entryBlocks.insert(block);
487 }
488
489 for (auto &&[succIndex, succ] : llvm::enumerate(block->getSuccessors())) {
490 if (cycles.contains(succ))
491 continue;
492
493 result.exitEdges.emplace_back(block, succIndex);
494 }
495 }
496
497 // With the entry blocks identified, find all the back edges.
498 for (Block *block : cycles) {
499 for (auto &&[succIndex, succ] : llvm::enumerate(block->getSuccessors())) {
500 if (!entryBlocks.contains(succ))
501 continue;
502
503 result.backEdges.emplace_back(block, succIndex);
504 }
505 }
506
507 return result;
508}
509
510/// Creates a single entry block out of multiple entry edges using an edge
511/// multiplexer and returns it.
512static EdgeMultiplexer
514 function_ref<Value(unsigned)> getSwitchValue,
515 function_ref<Value(Type)> getUndefValue,
516 CFGToSCFInterface &interface) {
517 auto result = EdgeMultiplexer::create(
518 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
519 getSwitchValue, getUndefValue);
520
521 // Redirect the edges prior to creating the switch op.
522 // We guarantee that predecessors are up to date.
523 for (Edge edge : entryEdges)
524 result.redirectEdge(edge);
525
526 auto builder = OpBuilder::atBlockBegin(result.getMultiplexerBlock());
527 result.createSwitch(loc, builder, interface);
528
529 return result;
530}
531
532namespace {
533/// Special loop properties of a structured loop.
534/// A structured loop is a loop satisfying all of the following:
535/// * Has at most one entry, one exit and one back edge.
536/// * The back edge originates from the same block as the exit edge.
537struct StructuredLoopProperties {
538 /// Block containing both the single exit edge and the single back edge.
539 Block *latch;
540 /// Loop condition of type equal to a value returned by `getSwitchValue`.
541 Value condition;
542 /// Exit block which is the only successor of the loop.
543 Block *exitBlock;
544};
545} // namespace
546
547/// Transforms a loop into a structured loop with only a single back edge and
548/// exiting edge, originating from the same block.
549static FailureOr<StructuredLoopProperties> createSingleExitingLatch(
550 Location loc, ArrayRef<Edge> backEdges, ArrayRef<Edge> exitEdges,
551 function_ref<Value(unsigned)> getSwitchValue,
552 function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
553 ReturnLikeExitCombiner &exitCombiner) {
554 assert(llvm::all_equal(
555 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
556 "All repetition edges must lead to the single loop header");
557
558 // First create the multiplexer block, which will be our latch, for all back
559 // edges and exit edges. We pass an additional argument to the multiplexer
560 // block which indicates whether the latch was reached from what was
561 // originally a back edge or an exit block.
562 // This is later used to branch using the new only back edge.
563 SmallVector<Block *> successors;
564 llvm::append_range(
565 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
566 llvm::append_range(
567 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
568 auto multiplexer =
569 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
570 /*extraArgs=*/getSwitchValue(0).getType());
571
572 auto *latchBlock = multiplexer.getMultiplexerBlock();
573
574 // Create a separate exit block that comes right after the latch.
575 auto *exitBlock = new Block;
576 exitBlock->insertAfter(latchBlock);
577
578 // Since this is a loop, all back edges point to the same loop header.
579 Block *loopHeader = backEdges.front().getSuccessor();
580
581 // Redirect the edges prior to creating the switch op.
582 // We guarantee that predecessors are up to date.
583
584 // Redirecting back edges with `shouldRepeat` as 1.
585 for (Edge backEdge : backEdges)
586 multiplexer.redirectEdge(backEdge, /*extraArgs=*/getSwitchValue(1));
587
588 // Redirecting exits edges with `shouldRepeat` as 0.
589 for (Edge exitEdge : exitEdges)
590 multiplexer.redirectEdge(exitEdge, /*extraArgs=*/getSwitchValue(0));
591
592 // Create the new only back edge to the loop header. Branch to the
593 // exit block otherwise.
594 Value shouldRepeat = latchBlock->getArguments().back();
595 {
596 auto builder = OpBuilder::atBlockBegin(latchBlock);
597 interface.createConditionalBranch(
598 loc, builder, shouldRepeat, loopHeader,
599 latchBlock->getArguments().take_front(loopHeader->getNumArguments()),
600 /*falseDest=*/exitBlock,
601 /*falseArgs=*/{});
602 }
603
604 {
605 auto builder = OpBuilder::atBlockBegin(exitBlock);
606 if (!exitEdges.empty()) {
607 // Create the switch dispatching to what were originally the multiple exit
608 // blocks. The loop header has to explicitly be excluded in the below
609 // switch as we would otherwise be creating a new loop again. All back
610 // edges leading to the loop header have already been handled in the
611 // switch above. The remaining edges can only jump to blocks outside the
612 // loop.
613
614 SmallPtrSet<Block *, 1> excluded = {loopHeader};
615 multiplexer.createSwitch(loc, builder, interface, excluded);
616 } else {
617 // A loop without an exit edge is a statically known infinite loop.
618 // Since structured control flow ops are not terminator ops, the caller
619 // has to create a fitting return-like unreachable terminator operation.
620 FailureOr<Operation *> terminator = interface.createUnreachableTerminator(
621 loc, builder, *latchBlock->getParent());
622 if (failed(terminator))
623 return failure();
624 // Transform the just created transform operation in the case that an
625 // occurrence of it existed in input IR.
626 exitCombiner.combineExit(*terminator, getSwitchValue);
627 }
628 }
629
630 return StructuredLoopProperties{latchBlock, /*condition=*/shouldRepeat,
631 exitBlock};
632}
633
634/// Transforms a structured loop into a loop in reduce form.
635///
636/// Reduce form is defined as a structured loop where:
637/// (0) No values defined within the loop body are used outside the loop body.
638/// (1) The block arguments and successor operands of the exit block are equal
639/// to the block arguments of the loop header and the successor operands
640/// of the back edge.
641///
642/// This is required for many structured control flow ops as they tend
643/// to not have separate "loop result arguments" and "loop iteration arguments"
644/// at the end of the block. Rather, the "loop iteration arguments" from the
645/// last iteration are the result of the loop.
646///
647/// Note that the requirement of (0) is shared with LCSSA form in LLVM. However,
648/// due to this being a structured loop instead of a general loop, we do not
649/// require complicated dominance algorithms nor SSA updating making this
650/// implementation easier than creating a generic LCSSA transformation pass.
652transformToReduceLoop(Block *loopHeader, Block *exitBlock,
653 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
654 function_ref<Value(Type)> getUndefValue,
655 DominanceInfo &dominanceInfo) {
656 Block *latch = exitBlock->getSinglePredecessor();
657 assert(latch &&
658 "Exit block must have only latch as predecessor at this point");
659 assert(exitBlock->getNumArguments() == 0 &&
660 "Exit block mustn't have any block arguments at this point");
661
662 unsigned loopHeaderIndex = 0;
663 unsigned exitBlockIndex = 1;
664 if (latch->getSuccessor(loopHeaderIndex) != loopHeader)
665 std::swap(loopHeaderIndex, exitBlockIndex);
666
667 assert(latch->getSuccessor(loopHeaderIndex) == loopHeader);
668 assert(latch->getSuccessor(exitBlockIndex) == exitBlock);
669
670 MutableOperandRange exitBlockSuccessorOperands =
671 getMutableSuccessorOperands(latch, exitBlockIndex);
672 // Save the values as a vector, not a `MutableOperandRange` as the latter gets
673 // invalidated when mutating the operands through a different
674 // `MutableOperandRange` of the same operation.
675 SmallVector<Value> loopHeaderSuccessorOperands =
676 llvm::to_vector(getSuccessorOperands(latch, loopHeaderIndex));
677
678 // Add all values used in the next iteration to the exit block. Replace
679 // any uses that are outside the loop with the newly created exit block.
680 for (Value arg : loopHeaderSuccessorOperands) {
681 BlockArgument exitArg = exitBlock->addArgument(arg.getType(), arg.getLoc());
682 exitBlockSuccessorOperands.append(arg);
683 arg.replaceUsesWithIf(exitArg, [&](OpOperand &use) {
684 return !loopBlocks.contains(use.getOwner()->getBlock());
685 });
686 }
687
688 // Loop below might add block arguments to the latch and loop header.
689 // Save the block arguments prior to the loop to not process these.
690 SmallVector<BlockArgument> latchBlockArgumentsPrior =
691 llvm::to_vector(latch->getArguments());
692 SmallVector<BlockArgument> loopHeaderArgumentsPrior =
693 llvm::to_vector(loopHeader->getArguments());
694
695 // Go over all values defined within the loop body. If any of them are used
696 // outside the loop body, create a block argument on the exit block and loop
697 // header and replace the outside uses with the exit block argument.
698 // The loop header block argument is added to satisfy requirement (1) in the
699 // reduce form condition.
700 for (Block *loopBlock : loopBlocks) {
701 // Cache dominance queries for loopBlock.
702 // There are likely to be many duplicate queries as there can be many value
703 // definitions within a block.
704 llvm::SmallDenseMap<Block *, bool> dominanceCache;
705 // Returns true if `loopBlock` dominates `block`.
706 auto loopBlockDominates = [&](Block *block) {
707 auto [iter, inserted] = dominanceCache.try_emplace(block);
708 if (!inserted)
709 return iter->second;
710 iter->second = dominanceInfo.dominates(loopBlock, block);
711 return iter->second;
712 };
713
714 auto checkValue = [&](Value value) {
715 Value blockArgument;
716 for (OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
717 // Go through all the parent blocks and find the one part of the region
718 // of the loop. If the block is part of the loop, then the value does
719 // not escape the loop through this use.
720 Block *currBlock = use.getOwner()->getBlock();
721 while (currBlock && currBlock->getParent() != loopHeader->getParent())
722 currBlock = currBlock->getParentOp()->getBlock();
723 if (loopBlocks.contains(currBlock))
724 continue;
725
726 // Block argument is only created the first time it is required.
727 if (!blockArgument) {
728 blockArgument =
729 exitBlock->addArgument(value.getType(), value.getLoc());
730 loopHeader->addArgument(value.getType(), value.getLoc());
731
732 // `value` might be defined in a block that does not dominate `latch`
733 // but previously dominated an exit block with a use.
734 // In this case, add a block argument to the latch and go through all
735 // predecessors. If the value dominates the predecessor, pass the
736 // value as a successor operand, otherwise pass undef.
737 // The above is unnecessary if the value is a block argument of the
738 // latch or if `value` dominates all predecessors.
739 Value argument = value;
740 if (value.getParentBlock() != latch &&
741 llvm::any_of(latch->getPredecessors(), [&](Block *pred) {
742 return !loopBlockDominates(pred);
743 })) {
744 argument = latch->addArgument(value.getType(), value.getLoc());
745 for (auto iter = latch->pred_begin(); iter != latch->pred_end();
746 ++iter) {
747 Value succOperand = value;
748 if (!loopBlockDominates(*iter))
749 succOperand = getUndefValue(value.getType());
750
751 getMutableSuccessorOperands(*iter, iter.getSuccessorIndex())
752 .append(succOperand);
753 }
754 }
755
756 loopHeaderSuccessorOperands.push_back(argument);
757 for (Edge edge : successorEdges(latch))
758 edge.getMutableSuccessorOperands().append(argument);
759 }
760
761 use.set(blockArgument);
762 }
763 };
764
765 if (loopBlock == latch)
766 llvm::for_each(latchBlockArgumentsPrior, checkValue);
767 else if (loopBlock == loopHeader)
768 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
769 else
770 llvm::for_each(loopBlock->getArguments(), checkValue);
771
772 for (Operation &op : *loopBlock)
773 llvm::for_each(op.getResults(), checkValue);
774 }
775
776 // New block arguments may have been added to the loop header.
777 // Adjust the entry edges to pass undef values to these.
778 for (auto iter = loopHeader->pred_begin(); iter != loopHeader->pred_end();
779 ++iter) {
780 // Latch successor arguments have already been handled.
781 if (*iter == latch)
782 continue;
783
784 MutableOperandRange succOps =
785 getMutableSuccessorOperands(*iter, iter.getSuccessorIndex());
786 succOps.append(llvm::map_to_vector(
787 loopHeader->getArguments().drop_front(succOps.size()),
788 [&](BlockArgument arg) { return getUndefValue(arg.getType()); }));
789 }
790
791 return loopHeaderSuccessorOperands;
792}
793
794/// Transforms all outer-most cycles in the region with the region entry
795/// `regionEntry` into structured loops. Returns the entry blocks of any newly
796/// created regions potentially requiring further transformations.
797static FailureOr<SmallVector<Block *>> transformCyclesToSCFLoops(
798 Block *regionEntry, function_ref<Value(unsigned)> getSwitchValue,
799 function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
800 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
801 SmallVector<Block *> newSubRegions;
802 auto scc = llvm::scc_begin(regionEntry);
803 while (!scc.isAtEnd()) {
804 if (!scc.hasCycle()) {
805 ++scc;
806 continue;
807 }
808
809 // Save the set and increment the SCC iterator early to avoid our
810 // modifications breaking the SCC iterator.
811 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
812 ++scc;
813
814 CycleEdges edges = calculateCycleEdges(cycleBlockSet);
815 Block *loopHeader = edges.entryEdges.front().getSuccessor();
816 // First turn the cycle into a loop by creating a single entry block if
817 // needed.
818 if (edges.entryEdges.size() > 1) {
819 SmallVector<Edge> edgesToEntryBlocks;
820 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
821 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
822
823 EdgeMultiplexer multiplexer = createSingleEntryBlock(
824 loopHeader->getTerminator()->getLoc(), edgesToEntryBlocks,
825 getSwitchValue, getUndefValue, interface);
826
827 loopHeader = multiplexer.getMultiplexerBlock();
828 }
829 cycleBlockSet.insert(loopHeader);
830
831 // Then turn it into a structured loop by creating a single latch.
832 FailureOr<StructuredLoopProperties> loopProperties =
834 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
835 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
836 interface, exitCombiner);
837 if (failed(loopProperties))
838 return failure();
839
840 Block *latchBlock = loopProperties->latch;
841 Block *exitBlock = loopProperties->exitBlock;
842 cycleBlockSet.insert(latchBlock);
843 cycleBlockSet.insert(loopHeader);
844
845 // Finally, turn it into reduce form.
847 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
848
849 // Create a block acting as replacement for the loop header and insert
850 // the structured loop into it.
851 auto *newLoopParentBlock = new Block;
852 newLoopParentBlock->insertBefore(loopHeader);
853 addBlockArgumentsFromOther(newLoopParentBlock, loopHeader);
854
855 Region::BlockListType &blocks = regionEntry->getParent()->getBlocks();
856 Region loopBody;
857 // Make sure the loop header is the entry block.
858 loopBody.push_back(blocks.remove(loopHeader));
859 for (Block *block : cycleBlockSet)
860 if (block != latchBlock && block != loopHeader)
861 loopBody.push_back(blocks.remove(block));
862 // And the latch is the last block.
863 loopBody.push_back(blocks.remove(latchBlock));
864
865 Operation *oldTerminator = latchBlock->getTerminator();
866 oldTerminator->remove();
867
868 auto builder = OpBuilder::atBlockBegin(newLoopParentBlock);
869 FailureOr<Operation *> structuredLoopOp =
871 builder, oldTerminator, newLoopParentBlock->getArguments(),
872 loopProperties->condition, iterationValues, std::move(loopBody));
873 if (failed(structuredLoopOp))
874 return failure();
875 oldTerminator->erase();
876
877 newSubRegions.push_back(loopHeader);
878
879 for (auto &&[oldValue, newValue] : llvm::zip(
880 exitBlock->getArguments(), (*structuredLoopOp)->getResults()))
881 oldValue.replaceAllUsesWith(newValue);
882
883 loopHeader->replaceAllUsesWith(newLoopParentBlock);
884 // Merge the exit block right after the loop operation.
885 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
886 exitBlock->getOperations());
887 exitBlock->erase();
888 }
889 return newSubRegions;
890}
891
892/// Makes sure the branch region only has a single exit. This is required by the
893/// recursive part of the algorithm, as it expects the CFG to be single-entry
894/// and single-exit. This is done by simply creating an empty block if there
895/// is more than one block with an edge to the continuation block. All blocks
896/// with edges to the continuation are then redirected to this block. A region
897/// terminator is later placed into the block.
899 ArrayRef<Block *> branchRegion, Block *continuation,
900 SmallVectorImpl<std::pair<Block *, SmallVector<Value>>> &createdEmptyBlocks,
901 Region &conditionalRegion) {
902 Block *singleExitBlock = nullptr;
903 std::optional<Edge> previousEdgeToContinuation;
904 Region::BlockListType &parentBlockList =
905 branchRegion.front()->getParent()->getBlocks();
906 for (Block *block : branchRegion) {
907 for (Edge edge : successorEdges(block)) {
908 if (edge.getSuccessor() != continuation)
909 continue;
910
911 if (!previousEdgeToContinuation) {
912 previousEdgeToContinuation = edge;
913 continue;
914 }
915
916 // If this is not the first edge to the continuation we create the
917 // single exit block and redirect the edges.
918 if (!singleExitBlock) {
919 singleExitBlock = new Block;
920 addBlockArgumentsFromOther(singleExitBlock, continuation);
921 previousEdgeToContinuation->setSuccessor(singleExitBlock);
922 createdEmptyBlocks.emplace_back(singleExitBlock,
923 singleExitBlock->getArguments());
924 }
925
926 edge.setSuccessor(singleExitBlock);
927 }
928
929 conditionalRegion.push_back(parentBlockList.remove(block));
930 }
931
932 if (singleExitBlock)
933 conditionalRegion.push_back(singleExitBlock);
934}
935
936/// Returns true if this block is an exit block of the region.
937static bool isRegionExitBlock(Block *block) {
938 return block->getNumSuccessors() == 0;
939}
940
941/// Transforms the first occurrence of conditional control flow in `regionEntry`
942/// into conditionally executed regions. Returns the entry block of the created
943/// regions and the region after the conditional control flow.
944static FailureOr<SmallVector<Block *>> transformToStructuredCFBranches(
945 Block *regionEntry, function_ref<Value(unsigned)> getSwitchValue,
946 function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
947 DominanceInfo &dominanceInfo) {
948 // Trivial region.
949 if (regionEntry->getNumSuccessors() == 0)
950 return SmallVector<Block *>{};
951
952 if (regionEntry->getNumSuccessors() == 1) {
953 // Single successor we can just splice together.
954 Block *successor = regionEntry->getSuccessor(0);
955 for (auto &&[oldValue, newValue] : llvm::zip(
956 successor->getArguments(), getSuccessorOperands(regionEntry, 0)))
957 oldValue.replaceAllUsesWith(newValue);
958 regionEntry->getTerminator()->erase();
959
960 regionEntry->getOperations().splice(regionEntry->end(),
961 successor->getOperations());
962 successor->erase();
963 return SmallVector<Block *>{regionEntry};
964 }
965
966 // Split the CFG into "#numSuccessor + 1" regions.
967 // For every edge to a successor, the blocks it solely dominates are
968 // determined and become the region following that edge.
969 // The last region is the continuation that follows the branch regions.
970 SmallPtrSet<Block *, 8> notContinuation;
971 notContinuation.insert(regionEntry);
972 SmallVector<SmallVector<Block *>> successorBranchRegions(
973 regionEntry->getNumSuccessors());
974 for (auto &&[blockList, succ] :
975 llvm::zip(successorBranchRegions, regionEntry->getSuccessors())) {
976 // If the region entry is not the only predecessor, then the edge does not
977 // dominate the block it leads to.
978 if (succ->getSinglePredecessor() != regionEntry)
979 continue;
980
981 // Otherwise get all blocks it dominates in DFS/pre-order.
982 DominanceInfoNode *node = dominanceInfo.getNode(succ);
983 for (DominanceInfoNode *curr : llvm::depth_first(node)) {
984 blockList.push_back(curr->getBlock());
985 notContinuation.insert(curr->getBlock());
986 }
987 }
988
989 // Finds all relevant edges and checks the shape of the control flow graph at
990 // this point.
991 // Branch regions may either:
992 // * Be post-dominated by the continuation
993 // * Be post-dominated by a return-like op
994 // * Dominate a return-like op and have an edge to the continuation.
995 //
996 // The control flow graph may then be one of three cases:
997 // 1) All branch regions are post-dominated by the continuation. This is the
998 // usual case. If there are multiple entry blocks into the continuation a
999 // single entry block has to be created. A structured control flow op
1000 // can then be created from the branch regions.
1001 //
1002 // 2) No branch region has an edge to a continuation:
1003 // +-----+
1004 // +-----+ bb0 +----+
1005 // v +-----+ v
1006 // Region 1 +-+--+ ... +-+--+ Region n
1007 // |ret1| |ret2|
1008 // +----+ +----+
1009 //
1010 // This can only occur if every region ends with a different kind of
1011 // return-like op. In that case the control flow operation must stay as we are
1012 // unable to create a single exit-block. We can nevertheless process all its
1013 // successors as they single-entry, single-exit regions.
1014 //
1015 // 3) Only some branch regions are post-dominated by the continuation.
1016 // The other branch regions may either be post-dominated by a return-like op
1017 // or lead to either the continuation or return-like op.
1018 // In this case we also create a single entry block like in 1) that also
1019 // includes all edges to the return-like op:
1020 // +-----+
1021 // +-----+ bb0 +----+
1022 // v +-----+ v
1023 // Region 1 +-+-+ ... +-+-+ Region n
1024 // +---+ +---+
1025 // +---+ |... ...
1026 // |ret|<-+ | |
1027 // +---+ | +---+ |
1028 // +---->++ ++<---+
1029 // | |
1030 // ++ ++ Region T
1031 // +---+
1032 // This transforms to:
1033 // +-----+
1034 // +-----+ bb0 +----+
1035 // v +-----+ v
1036 // Region 1 +-+-+ ... +-+-+ Region n
1037 // +---+ +---+
1038 // ... +-----+ ...
1039 // +---->+ bbM +<---+
1040 // +-----+
1041 // +-----+ |
1042 // | v
1043 // +---+ | +---+
1044 // |ret+<---+ ++ ++
1045 // +---+ | |
1046 // ++ ++ Region T
1047 // +---+
1048 //
1049 // bb0 to bbM is now a single-entry, single-exit region that applies to case
1050 // 1). The control flow op at the end of bbM will trigger case 2.
1051 SmallVector<Edge> continuationEdges;
1052 bool continuationPostDominatesAllRegions = true;
1053 bool noSuccessorHasContinuationEdge = true;
1054 for (auto &&[entryEdge, branchRegion] :
1055 llvm::zip(successorEdges(regionEntry), successorBranchRegions)) {
1056
1057 // If the branch region is empty then the branch target itself is part of
1058 // the continuation.
1059 if (branchRegion.empty()) {
1060 continuationEdges.push_back(entryEdge);
1061 noSuccessorHasContinuationEdge = false;
1062 continue;
1063 }
1064
1065 for (Block *block : branchRegion) {
1066 if (isRegionExitBlock(block)) {
1067 // If a return-like op is part of the branch region then the
1068 // continuation no longer post-dominates the branch region.
1069 // Add all its incoming edges to edge list to create the single-exit
1070 // block for all branch regions.
1071 continuationPostDominatesAllRegions = false;
1072 for (auto iter = block->pred_begin(); iter != block->pred_end();
1073 ++iter) {
1074 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1075 }
1076 continue;
1077 }
1078
1079 for (Edge edge : successorEdges(block)) {
1080 if (notContinuation.contains(edge.getSuccessor()))
1081 continue;
1082
1083 continuationEdges.push_back(edge);
1084 noSuccessorHasContinuationEdge = false;
1085 }
1086 }
1087 }
1088
1089 // case 2) Keep the control flow op but process its successors further.
1090 if (noSuccessorHasContinuationEdge)
1091 return llvm::to_vector(regionEntry->getSuccessors());
1092
1093 Block *continuation = llvm::find_singleton<Block>(
1094 continuationEdges, [](Edge edge, bool) { return edge.getSuccessor(); },
1095 /*AllowRepeats=*/true);
1096
1097 // In case 3) or if not all continuation edges have the same entry block,
1098 // create a single entry block as continuation for all branch regions.
1099 if (!continuation || !continuationPostDominatesAllRegions) {
1100 EdgeMultiplexer multiplexer = createSingleEntryBlock(
1101 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1102 continuationEdges, getSwitchValue, getUndefValue, interface);
1103 continuation = multiplexer.getMultiplexerBlock();
1104 }
1105
1106 // Trigger reprocess of case 3) after creating the single entry block.
1107 if (!continuationPostDominatesAllRegions) {
1108 // Unlike in the general case, we are explicitly revisiting the same region
1109 // entry again after having changed its control flow edges and dominance.
1110 // We have to therefore explicitly invalidate the dominance tree.
1111 dominanceInfo.invalidate(regionEntry->getParent());
1112 return SmallVector<Block *>{regionEntry};
1113 }
1114
1115 SmallVector<Block *> newSubRegions;
1116
1117 // Empty blocks with the values they return to the parent op.
1119
1120 // Create the branch regions.
1121 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1122 for (auto &&[branchRegion, entryEdge, conditionalRegion] :
1123 llvm::zip(successorBranchRegions, successorEdges(regionEntry),
1124 conditionalRegions)) {
1125 if (branchRegion.empty()) {
1126 // If no block is part of the branch region, we create a dummy block to
1127 // place the region terminator into.
1128 createdEmptyBlocks.emplace_back(
1129 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1130 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1131 continue;
1132 }
1133
1134 createSingleExitBranchRegion(branchRegion, continuation, createdEmptyBlocks,
1135 conditionalRegion);
1136
1137 // The entries of the branch regions may only have redundant block arguments
1138 // since the edge to the branch region is always dominating.
1139 Block *subRegionEntryBlock = &conditionalRegion.front();
1140 for (auto &&[oldValue, newValue] :
1141 llvm::zip(subRegionEntryBlock->getArguments(),
1142 entryEdge.getSuccessorOperands()))
1143 oldValue.replaceAllUsesWith(newValue);
1144
1145 subRegionEntryBlock->eraseArguments(0,
1146 subRegionEntryBlock->getNumArguments());
1147 newSubRegions.push_back(subRegionEntryBlock);
1148 }
1149
1150 Operation *structuredCondOp;
1151 {
1152 auto opBuilder = OpBuilder::atBlockTerminator(regionEntry);
1153 FailureOr<Operation *> result = interface.createStructuredBranchRegionOp(
1154 opBuilder, regionEntry->getTerminator(),
1155 continuation->getArgumentTypes(), conditionalRegions);
1156 if (failed(result)) {
1157 // Blocks were moved from the parent region into conditionalRegions before
1158 // calling createStructuredBranchRegionOp. On failure, move them back to
1159 // avoid use-after-free crashes: the moved blocks may still be referenced
1160 // as successors by blocks remaining in the parent region, so destroying
1161 // conditionalRegions with live uses would trigger an assertion.
1162 // This patching does not undo the change, it barely makes it so that the
1163 // pass can gracefully fail instead of crashing.
1164 Region *parentRegion = regionEntry->getParent();
1165 for (Region &conditionalRegion : conditionalRegions)
1166 parentRegion->getBlocks().splice(parentRegion->getBlocks().end(),
1167 conditionalRegion.getBlocks());
1168 return failure();
1169 }
1170 structuredCondOp = *result;
1171 regionEntry->getTerminator()->erase();
1172 }
1173
1174 for (auto &&[block, valueRange] : createdEmptyBlocks) {
1175 auto builder = OpBuilder::atBlockEnd(block);
1176 LogicalResult result = interface.createStructuredBranchRegionTerminatorOp(
1177 structuredCondOp->getLoc(), builder, structuredCondOp, nullptr,
1178 valueRange);
1179 if (failed(result))
1180 return failure();
1181 }
1182
1183 // Any leftover users of the continuation must be from unconditional branches
1184 // in a branch region. There can only be at most one per branch region as
1185 // all branch regions have been made single-entry single-exit above.
1186 // Replace them with the region terminator.
1187 for (Operation *user : llvm::make_early_inc_range(continuation->getUsers())) {
1188 assert(user->getNumSuccessors() == 1);
1189 auto builder = OpBuilder::atBlockTerminator(user->getBlock());
1190 LogicalResult result = interface.createStructuredBranchRegionTerminatorOp(
1191 user->getLoc(), builder, structuredCondOp, user,
1192 getMutableSuccessorOperands(user->getBlock(), 0).getAsOperandRange());
1193 if (failed(result))
1194 return failure();
1195 user->erase();
1196 }
1197
1198 for (auto &&[oldValue, newValue] :
1199 llvm::zip(continuation->getArguments(), structuredCondOp->getResults()))
1200 oldValue.replaceAllUsesWith(newValue);
1201
1202 // Splice together the continuations operations with the region entry.
1203 regionEntry->getOperations().splice(regionEntry->end(),
1204 continuation->getOperations());
1205
1206 continuation->erase();
1207
1208 // After splicing the continuation, the region has to be reprocessed as it has
1209 // new successors.
1210 newSubRegions.push_back(regionEntry);
1211
1212 return newSubRegions;
1213}
1214
1215/// Transforms the region to only have a single block for every kind of
1216/// return-like operation that all previous occurrences of the return-like op
1217/// branch to. If the region only contains a single kind of return-like
1218/// operation, it creates a single-entry and single-exit region.
1219static ReturnLikeExitCombiner createSingleExitBlocksForReturnLike(
1220 Region &region, function_ref<Value(unsigned)> getSwitchValue,
1221 CFGToSCFInterface &interface) {
1222 ReturnLikeExitCombiner exitCombiner(region, interface);
1223
1224 for (Block &block : region.getBlocks()) {
1225 if (block.getNumSuccessors() != 0)
1226 continue;
1227 exitCombiner.combineExit(block.getTerminator(), getSwitchValue);
1228 }
1229
1230 return exitCombiner;
1231}
1232
1233/// Checks all preconditions of the transformation prior to any transformations.
1234/// Returns failure if any precondition is violated.
1235static LogicalResult
1237 for (Block &block : region.getBlocks())
1238 if (block.hasNoPredecessors() && !block.isEntryBlock())
1239 return block.front().emitOpError(
1240 "transformation does not support unreachable blocks");
1241
1242 WalkResult result = region.walk([](Operation *operation) {
1243 if (operation->getNumSuccessors() == 0)
1244 return WalkResult::advance();
1245
1246 // This transformation requires all ops with successors to implement the
1247 // branch op interface. It is impossible to adjust their block arguments
1248 // otherwise.
1249 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1250 if (!branchOpInterface) {
1251 operation->emitOpError("transformation does not support terminators with "
1252 "successors not implementing BranchOpInterface");
1253 return WalkResult::interrupt();
1254 }
1255 // Branch operations must have no side effects. Replacing them would not be
1256 // valid otherwise.
1257 if (!isMemoryEffectFree(branchOpInterface)) {
1258 branchOpInterface->emitOpError(
1259 "transformation does not support terminators with side effects");
1260 return WalkResult::interrupt();
1261 }
1262
1263 for (unsigned index : llvm::seq(operation->getNumSuccessors())) {
1264 SuccessorOperands succOps = branchOpInterface.getSuccessorOperands(index);
1265
1266 // We cannot support operations with operation-produced successor operands
1267 // as it is currently not possible to pass them to any block arguments
1268 // other than the first. This breaks creating multiplexer blocks and would
1269 // likely need special handling elsewhere too.
1270 if (succOps.getProducedOperandCount() == 0)
1271 continue;
1272
1273 branchOpInterface->emitOpError("transformation does not support "
1274 "operations with operation-produced "
1275 "successor operands");
1276 return WalkResult::interrupt();
1277 }
1278 return WalkResult::advance();
1279 });
1280 if (result.wasInterrupted())
1281 return failure();
1282
1283 // Verify all multi-successor terminators are convertible before touching IR.
1284 for (Block &block : region.getBlocks()) {
1285 if (block.getNumSuccessors() <= 1)
1286 continue;
1287 Operation *terminator = block.getTerminator();
1288 if (!interface.canConvertMultiSuccessorBranchOp(terminator)) {
1289 terminator->emitOpError(
1290 "cannot convert unknown control flow op to structured control flow");
1291 return failure();
1292 }
1293 }
1294 return success();
1295}
1296
1297FailureOr<bool> mlir::transformCFGToSCF(Region &region,
1298 CFGToSCFInterface &interface,
1299 DominanceInfo &dominanceInfo) {
1300 if (region.empty() || region.hasOneBlock())
1301 return false;
1302
1303 if (failed(checkTransformationPreconditions(region, interface)))
1304 return failure();
1305
1306 DenseMap<Type, Value> typedUndefCache;
1307 auto getUndefValue = [&](Type type) {
1308 auto [iter, inserted] = typedUndefCache.try_emplace(type);
1309 if (!inserted)
1310 return iter->second;
1311
1312 auto constantBuilder = OpBuilder::atBlockBegin(&region.front());
1313
1314 iter->second =
1315 interface.getUndefValue(region.getLoc(), constantBuilder, type);
1316 return iter->second;
1317 };
1318
1319 // The transformation only creates all values in the range of 0 to
1320 // max(#numSuccessors). Therefore using a vector instead of a map.
1321 SmallVector<Value> switchValueCache;
1322 auto getSwitchValue = [&](unsigned value) {
1323 if (value < switchValueCache.size())
1324 if (switchValueCache[value])
1325 return switchValueCache[value];
1326
1327 auto constantBuilder = OpBuilder::atBlockBegin(&region.front());
1328
1329 switchValueCache.resize(
1330 std::max<size_t>(switchValueCache.size(), value + 1));
1331
1332 switchValueCache[value] =
1333 interface.getCFGSwitchValue(region.getLoc(), constantBuilder, value);
1334 return switchValueCache[value];
1335 };
1336
1337 ReturnLikeExitCombiner exitCombiner =
1338 createSingleExitBlocksForReturnLike(region, getSwitchValue, interface);
1339
1340 // Invalidate any dominance tree on the region as the exit combiner has
1341 // added new blocks and edges.
1342 dominanceInfo.invalidate(&region);
1343
1344 SmallVector<Block *> workList = {&region.front()};
1345 while (!workList.empty()) {
1346 Block *current = workList.pop_back_val();
1347
1348 // Turn all top-level cycles in the CFG to structured control flow first.
1349 // After this transformation, the remaining CFG ops form a DAG.
1350 FailureOr<SmallVector<Block *>> newRegions =
1351 transformCyclesToSCFLoops(current, getSwitchValue, getUndefValue,
1352 interface, dominanceInfo, exitCombiner);
1353 if (failed(newRegions))
1354 return failure();
1355
1356 // Add the newly created subregions to the worklist. These are the
1357 // bodies of the loops.
1358 llvm::append_range(workList, *newRegions);
1359 // Invalidate the dominance tree as blocks have been moved, created and
1360 // added during the cycle to structured loop transformation.
1361 if (!newRegions->empty())
1362 dominanceInfo.invalidate(current->getParent());
1363
1365 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1366 if (failed(newRegions))
1367 return failure();
1368 // Invalidating the dominance tree is generally not required by the
1369 // transformation above as the new region entries correspond to unaffected
1370 // subtrees in the dominator tree. Only its parent nodes have changed but
1371 // won't be visited again.
1372 llvm::append_range(workList, *newRegions);
1373 }
1374
1375 return true;
1376}
return success()
static EdgeMultiplexer createSingleEntryBlock(Location loc, ArrayRef< Edge > entryEdges, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface)
Creates a single entry block out of multiple entry edges using an edge multiplexer and returns it.
Definition CFGToSCF.cpp:513
static bool isRegionExitBlock(Block *block)
Returns true if this block is an exit block of the region.
Definition CFGToSCF.cpp:937
static FailureOr< SmallVector< Block * > > transformToStructuredCFBranches(Block *regionEntry, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo)
Transforms the first occurrence of conditional control flow in regionEntry into conditionally execute...
Definition CFGToSCF.cpp:944
static SmallVector< Value > transformToReduceLoop(Block *loopHeader, Block *exitBlock, const llvm::SmallSetVector< Block *, 4 > &loopBlocks, function_ref< Value(Type)> getUndefValue, DominanceInfo &dominanceInfo)
Transforms a structured loop into a loop in reduce form.
Definition CFGToSCF.cpp:652
static MutableOperandRange getMutableSuccessorOperands(Block *block, unsigned successorIndex)
Returns the mutable operand range used to transfer operands from block to its successor with the give...
Definition CFGToSCF.cpp:131
static auto successorEdges(Block *block)
Returns a range of all edges from block to each of its successors.
Definition CFGToSCF.cpp:467
static FailureOr< StructuredLoopProperties > createSingleExitingLatch(Location loc, ArrayRef< Edge > backEdges, ArrayRef< Edge > exitEdges, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface, ReturnLikeExitCombiner &exitCombiner)
Transforms a loop into a structured loop with only a single back edge and exiting edge,...
Definition CFGToSCF.cpp:549
static void addBlockArgumentsFromOther(Block *block, Block *other)
Appends all the block arguments from other to the block arguments of block, copying their types and l...
Definition CFGToSCF.cpp:147
static void createSingleExitBranchRegion(ArrayRef< Block * > branchRegion, Block *continuation, SmallVectorImpl< std::pair< Block *, SmallVector< Value > > > &createdEmptyBlocks, Region &conditionalRegion)
Makes sure the branch region only has a single exit.
Definition CFGToSCF.cpp:898
static LogicalResult checkTransformationPreconditions(Region &region, CFGToSCFInterface &interface)
Checks all preconditions of the transformation prior to any transformations.
static OperandRange getSuccessorOperands(Block *block, unsigned successorIndex)
Return the operand range used to transfer operands from block to its successor with the given index.
Definition CFGToSCF.cpp:140
static FailureOr< SmallVector< Block * > > transformCyclesToSCFLoops(Block *regionEntry, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner)
Transforms all outer-most cycles in the region with the region entry regionEntry into structured loop...
Definition CFGToSCF.cpp:797
static CycleEdges calculateCycleEdges(const llvm::SmallSetVector< Block *, 4 > &cycles)
Calculates entry, exit and back edges of the given cycle.
Definition CFGToSCF.cpp:474
static ReturnLikeExitCombiner createSingleExitBlocksForReturnLike(Region &region, function_ref< Value(unsigned)> getSwitchValue, CFGToSCFInterface &interface)
Transforms the region to only have a single block for every kind of return-like operation that all pr...
lhs
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
This class represents an argument of a Block.
Definition Value.h:306
Block represents an ordered list of Operations.
Definition Block.h:33
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
Definition Block.cpp:154
unsigned getNumSuccessors()
Definition Block.cpp:270
unsigned getNumArguments()
Definition Block.h:138
iterator_range< pred_iterator > getPredecessors()
Definition Block.h:250
void erase()
Unlink this Block from its parent region and delete it.
Definition Block.cpp:66
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
Definition Block.cpp:165
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Definition Block.cpp:27
OpListType & getOperations()
Definition Block.h:147
Operation & front()
Definition Block.h:163
pred_iterator pred_begin()
Definition Block.h:246
SuccessorRange getSuccessors()
Definition Block.h:280
Block * getSinglePredecessor()
If this block has exactly one predecessor, return it.
Definition Block.cpp:285
void insertAfter(Block *block)
Insert this block (which must not already be in a region) right after the specified block.
Definition Block.cpp:46
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition Block.cpp:158
void eraseArguments(unsigned start, unsigned num)
Erases 'num' arguments from the index 'start'.
Definition Block.cpp:206
BlockArgListType getArguments()
Definition Block.h:97
iterator end()
Definition Block.h:154
Block * getSuccessor(unsigned i)
Definition Block.cpp:274
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Definition Block.cpp:36
void insertBefore(Block *block)
Insert this block (which must not already be in a region) right before the specified block.
Definition Block.cpp:40
pred_iterator pred_end()
Definition Block.h:249
void push_back(Operation *op)
Definition Block.h:159
bool hasNoPredecessors()
Return true if this block has no predecessors.
Definition Block.h:255
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition Block.cpp:31
Interface that should be implemented by any caller of transformCFGToSCF.
Definition CFGToSCF.h:28
virtual FailureOr< Operation * > createStructuredBranchRegionOp(OpBuilder &builder, Operation *controlFlowCondOp, TypeRange resultTypes, MutableArrayRef< Region > regions)=0
Creates a structured control flow operation branching to one of regions.
virtual FailureOr< Operation * > createUnreachableTerminator(Location loc, OpBuilder &builder, Region &region)=0
Creates a return-like terminator indicating unreachable.
virtual FailureOr< Operation * > createStructuredDoWhileLoopOp(OpBuilder &builder, Operation *replacedOp, ValueRange loopValuesInit, Value condition, ValueRange loopValuesNextIter, Region &&loopBody)=0
Creates a structured control flow operation representing a do-while loop.
virtual Value getCFGSwitchValue(Location loc, OpBuilder &builder, unsigned value)=0
Creates a constant operation with a result representing value that is suitable as flag for createCFGS...
void createConditionalBranch(Location loc, OpBuilder &builder, Value condition, Block *trueDest, ValueRange trueArgs, Block *falseDest, ValueRange falseArgs)
Helper function to create a conditional branch using createCFGSwitchOp.
Definition CFGToSCF.h:132
virtual void createCFGSwitchOp(Location loc, OpBuilder &builder, Value flag, ArrayRef< unsigned > caseValues, BlockRange caseDestinations, ArrayRef< ValueRange > caseArguments, Block *defaultDest, ValueRange defaultArgs)=0
Creates a switch CFG branch operation branching to one of caseDestinations or defaultDest.
virtual Value getUndefValue(Location loc, OpBuilder &builder, Type type)=0
Creates a constant operation returning an undefined instance of type.
virtual LogicalResult createStructuredBranchRegionTerminatorOp(Location loc, OpBuilder &builder, Operation *branchRegionOp, Operation *replacedControlFlowOp, ValueRange results)=0
Creates a return-like terminator for a branch region of the op returned by createStructuredBranchRegi...
virtual bool canConvertMultiSuccessorBranchOp(Operation *op)
Returns true if this operation (which has >1 successors) can be converted to structured control flow ...
Definition CFGToSCF.h:103
A class for computing basic dominance information.
Definition Dominance.h:143
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
Definition Dominance.h:161
user_range getUsers() const
Returns a range of all users.
void replaceAllUsesWith(ValueT &&newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class provides a mutable adaptor for a range of operands.
Definition ValueRange.h:119
unsigned size() const
Returns the current size of the range.
Definition ValueRange.h:157
void assign(ValueRange values)
Assign this range to the given values.
void append(ValueRange values)
Append the given values to the range.
static OpBuilder atBlockBegin(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to before the first operation in the block but still ins...
Definition Builders.h:242
static OpBuilder atBlockEnd(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to after the last operation in the block but still insid...
Definition Builders.h:248
static OpBuilder atBlockTerminator(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to before the block terminator.
Definition Builders.h:254
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
Definition Builders.h:444
This class represents an operand of an operation.
Definition Value.h:254
This class implements the operand iterators for the Operation class.
Definition ValueRange.h:44
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
unsigned getNumSuccessors()
Definition Operation.h:731
Block * getBlock()
Returns the operation block that contains this operation.
Definition Operation.h:230
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
unsigned getNumOperands()
Definition Operation.h:371
void remove()
Remove the operation from its parent block, but don't delete it.
operand_type_range getOperandTypes()
Definition Operation.h:422
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:403
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
void replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this operation with the provided 'values'.
Definition Operation.h:297
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
result_range getResults()
Definition Operation.h:440
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
void erase()
Remove this operation from its parent block and delete it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
llvm::iplist< Block > BlockListType
Definition Region.h:44
Block & front()
Definition Region.h:65
void push_back(Block *block)
Definition Region.h:61
bool empty()
Definition Region.h:60
Location getLoc()
Return a location for this region.
Definition Region.cpp:31
BlockListType & getBlocks()
Definition Region.h:45
bool hasOneBlock()
Return true if this region has exactly one block.
Definition Region.h:68
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
Definition Region.h:296
This class models how operands are forwarded to block arguments in control flow.
MutableOperandRange getMutableForwardedOperands() const
Get the range of operands that are simply forwarded to the successor.
unsigned getProducedOperandCount() const
Returns the amount of operands that are produced internally by the operation.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
A utility result that is used to signal how to proceed with an ongoing walk:
Definition WalkResult.h:29
static WalkResult advance()
Definition WalkResult.h:47
static WalkResult interrupt()
Definition WalkResult.h:46
DominanceInfoNode * getNode(Block *a)
Return the dominance node from the Region containing block A.
Definition Dominance.h:85
void invalidate()
Invalidate dominance info.
Definition Dominance.cpp:37
Operation * getOwner() const
Return the owner of this operand.
Definition UseDefLists.h:38
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:307
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
llvm::DomTreeNodeBase< Block > DominanceInfoNode
Definition Dominance.h:30
FailureOr< bool > transformCFGToSCF(Region &region, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo)
Transformation lifting any dialect implementing control flow graph operations to a dialect implementi...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147
static llvm::hash_code ignoreHashValue(Value)
Helper that can be used with computeHash above to ignore operation operands/result mapping.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two operations (including their regions) and return if they are equivalent.
static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs)
Helper that can be used with isEquivalentTo above to consider ops equivalent even if their operands a...
static llvm::hash_code computeHash(Operation *op, function_ref< llvm::hash_code(Value)> hashOperands=[](Value v) { return hash_value(v);}, function_ref< llvm::hash_code(Value)> hashResults=[](Value v) { return hash_value(v);}, Flags flags=Flags::None)
Compute a hash for the given operation.