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;
407 if (lhs == getEmptyKey() || rhs == getEmptyKey())
408 return false;
410 const_cast<Operation *>(lhs), const_cast<Operation *>(rhs),
413 }
414};
415
416/// Utility-class for transforming a region to only have one single block for
417/// every return-like operation.
418class ReturnLikeExitCombiner {
419public:
420 ReturnLikeExitCombiner(Region &topLevelRegion, CFGToSCFInterface &interface)
421 : topLevelRegion(topLevelRegion), interface(interface) {}
422
423 /// Transforms `returnLikeOp` to a branch to the only block in the
424 /// region with an instance of `returnLikeOp`s kind.
425 void combineExit(Operation *returnLikeOp,
426 function_ref<Value(unsigned)> getSwitchValue) {
427 auto [iter, inserted] = returnLikeToCombinedExit.try_emplace(returnLikeOp);
428 if (!inserted && iter->first == returnLikeOp)
429 return;
430
431 Block *exitBlock = iter->second;
432 if (inserted) {
433 exitBlock = new Block;
434 iter->second = exitBlock;
435 topLevelRegion.push_back(exitBlock);
436 exitBlock->addArguments(
437 returnLikeOp->getOperandTypes(),
438 SmallVector<Location>(returnLikeOp->getNumOperands(),
439 returnLikeOp->getLoc()));
440 }
441
442 auto builder = OpBuilder::atBlockTerminator(returnLikeOp->getBlock());
443 interface.createSingleDestinationBranch(returnLikeOp->getLoc(), builder,
444 getSwitchValue(0), exitBlock,
445 returnLikeOp->getOperands());
446
447 if (!inserted) {
448 returnLikeOp->erase();
449 return;
450 }
451
452 returnLikeOp->moveBefore(exitBlock, exitBlock->end());
453 returnLikeOp->setOperands(exitBlock->getArguments());
454 }
455
456private:
457 /// Mapping of return-like operation to block. All return-like operations
458 /// of the same kind with the same attributes, properties and types are seen
459 /// as equivalent. First occurrence seen is kept in the map.
460 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
461 returnLikeToCombinedExit;
462 Region &topLevelRegion;
463 CFGToSCFInterface &interface;
464};
465
466} // namespace
467
468/// Returns a range of all edges from `block` to each of its successors.
469static auto successorEdges(Block *block) {
470 return llvm::map_range(llvm::seq(block->getNumSuccessors()),
471 [=](unsigned index) { return Edge(block, index); });
472}
473
474/// Calculates entry, exit and back edges of the given cycle.
475static CycleEdges
476calculateCycleEdges(const llvm::SmallSetVector<Block *, 4> &cycles) {
477 CycleEdges result;
478 SmallPtrSet<Block *, 8> entryBlocks;
479
480 // First identify all exit and entry edges by checking whether any successors
481 // or predecessors are from outside the cycles.
482 for (Block *block : cycles) {
483 for (auto pred = block->pred_begin(); pred != block->pred_end(); pred++) {
484 if (cycles.contains(*pred))
485 continue;
486
487 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
488 entryBlocks.insert(block);
489 }
490
491 for (auto &&[succIndex, succ] : llvm::enumerate(block->getSuccessors())) {
492 if (cycles.contains(succ))
493 continue;
494
495 result.exitEdges.emplace_back(block, succIndex);
496 }
497 }
498
499 // With the entry blocks identified, find all the back edges.
500 for (Block *block : cycles) {
501 for (auto &&[succIndex, succ] : llvm::enumerate(block->getSuccessors())) {
502 if (!entryBlocks.contains(succ))
503 continue;
504
505 result.backEdges.emplace_back(block, succIndex);
506 }
507 }
508
509 return result;
510}
511
512/// Creates a single entry block out of multiple entry edges using an edge
513/// multiplexer and returns it.
514static EdgeMultiplexer
516 function_ref<Value(unsigned)> getSwitchValue,
517 function_ref<Value(Type)> getUndefValue,
518 CFGToSCFInterface &interface) {
519 auto result = EdgeMultiplexer::create(
520 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
521 getSwitchValue, getUndefValue);
522
523 // Redirect the edges prior to creating the switch op.
524 // We guarantee that predecessors are up to date.
525 for (Edge edge : entryEdges)
526 result.redirectEdge(edge);
527
528 auto builder = OpBuilder::atBlockBegin(result.getMultiplexerBlock());
529 result.createSwitch(loc, builder, interface);
530
531 return result;
532}
533
534namespace {
535/// Special loop properties of a structured loop.
536/// A structured loop is a loop satisfying all of the following:
537/// * Has at most one entry, one exit and one back edge.
538/// * The back edge originates from the same block as the exit edge.
539struct StructuredLoopProperties {
540 /// Block containing both the single exit edge and the single back edge.
541 Block *latch;
542 /// Loop condition of type equal to a value returned by `getSwitchValue`.
543 Value condition;
544 /// Exit block which is the only successor of the loop.
545 Block *exitBlock;
546};
547} // namespace
548
549/// Transforms a loop into a structured loop with only a single back edge and
550/// exiting edge, originating from the same block.
551static FailureOr<StructuredLoopProperties> createSingleExitingLatch(
552 Location loc, ArrayRef<Edge> backEdges, ArrayRef<Edge> exitEdges,
553 function_ref<Value(unsigned)> getSwitchValue,
554 function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
555 ReturnLikeExitCombiner &exitCombiner) {
556 assert(llvm::all_equal(
557 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
558 "All repetition edges must lead to the single loop header");
559
560 // First create the multiplexer block, which will be our latch, for all back
561 // edges and exit edges. We pass an additional argument to the multiplexer
562 // block which indicates whether the latch was reached from what was
563 // originally a back edge or an exit block.
564 // This is later used to branch using the new only back edge.
565 SmallVector<Block *> successors;
566 llvm::append_range(
567 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
568 llvm::append_range(
569 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
570 auto multiplexer =
571 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
572 /*extraArgs=*/getSwitchValue(0).getType());
573
574 auto *latchBlock = multiplexer.getMultiplexerBlock();
575
576 // Create a separate exit block that comes right after the latch.
577 auto *exitBlock = new Block;
578 exitBlock->insertAfter(latchBlock);
579
580 // Since this is a loop, all back edges point to the same loop header.
581 Block *loopHeader = backEdges.front().getSuccessor();
582
583 // Redirect the edges prior to creating the switch op.
584 // We guarantee that predecessors are up to date.
585
586 // Redirecting back edges with `shouldRepeat` as 1.
587 for (Edge backEdge : backEdges)
588 multiplexer.redirectEdge(backEdge, /*extraArgs=*/getSwitchValue(1));
589
590 // Redirecting exits edges with `shouldRepeat` as 0.
591 for (Edge exitEdge : exitEdges)
592 multiplexer.redirectEdge(exitEdge, /*extraArgs=*/getSwitchValue(0));
593
594 // Create the new only back edge to the loop header. Branch to the
595 // exit block otherwise.
596 Value shouldRepeat = latchBlock->getArguments().back();
597 {
598 auto builder = OpBuilder::atBlockBegin(latchBlock);
599 interface.createConditionalBranch(
600 loc, builder, shouldRepeat, loopHeader,
601 latchBlock->getArguments().take_front(loopHeader->getNumArguments()),
602 /*falseDest=*/exitBlock,
603 /*falseArgs=*/{});
604 }
605
606 {
607 auto builder = OpBuilder::atBlockBegin(exitBlock);
608 if (!exitEdges.empty()) {
609 // Create the switch dispatching to what were originally the multiple exit
610 // blocks. The loop header has to explicitly be excluded in the below
611 // switch as we would otherwise be creating a new loop again. All back
612 // edges leading to the loop header have already been handled in the
613 // switch above. The remaining edges can only jump to blocks outside the
614 // loop.
615
616 SmallPtrSet<Block *, 1> excluded = {loopHeader};
617 multiplexer.createSwitch(loc, builder, interface, excluded);
618 } else {
619 // A loop without an exit edge is a statically known infinite loop.
620 // Since structured control flow ops are not terminator ops, the caller
621 // has to create a fitting return-like unreachable terminator operation.
622 FailureOr<Operation *> terminator = interface.createUnreachableTerminator(
623 loc, builder, *latchBlock->getParent());
624 if (failed(terminator))
625 return failure();
626 // Transform the just created transform operation in the case that an
627 // occurrence of it existed in input IR.
628 exitCombiner.combineExit(*terminator, getSwitchValue);
629 }
630 }
631
632 return StructuredLoopProperties{latchBlock, /*condition=*/shouldRepeat,
633 exitBlock};
634}
635
636/// Transforms a structured loop into a loop in reduce form.
637///
638/// Reduce form is defined as a structured loop where:
639/// (0) No values defined within the loop body are used outside the loop body.
640/// (1) The block arguments and successor operands of the exit block are equal
641/// to the block arguments of the loop header and the successor operands
642/// of the back edge.
643///
644/// This is required for many structured control flow ops as they tend
645/// to not have separate "loop result arguments" and "loop iteration arguments"
646/// at the end of the block. Rather, the "loop iteration arguments" from the
647/// last iteration are the result of the loop.
648///
649/// Note that the requirement of (0) is shared with LCSSA form in LLVM. However,
650/// due to this being a structured loop instead of a general loop, we do not
651/// require complicated dominance algorithms nor SSA updating making this
652/// implementation easier than creating a generic LCSSA transformation pass.
654transformToReduceLoop(Block *loopHeader, Block *exitBlock,
655 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
656 function_ref<Value(Type)> getUndefValue,
657 DominanceInfo &dominanceInfo) {
658 Block *latch = exitBlock->getSinglePredecessor();
659 assert(latch &&
660 "Exit block must have only latch as predecessor at this point");
661 assert(exitBlock->getNumArguments() == 0 &&
662 "Exit block mustn't have any block arguments at this point");
663
664 unsigned loopHeaderIndex = 0;
665 unsigned exitBlockIndex = 1;
666 if (latch->getSuccessor(loopHeaderIndex) != loopHeader)
667 std::swap(loopHeaderIndex, exitBlockIndex);
668
669 assert(latch->getSuccessor(loopHeaderIndex) == loopHeader);
670 assert(latch->getSuccessor(exitBlockIndex) == exitBlock);
671
672 MutableOperandRange exitBlockSuccessorOperands =
673 getMutableSuccessorOperands(latch, exitBlockIndex);
674 // Save the values as a vector, not a `MutableOperandRange` as the latter gets
675 // invalidated when mutating the operands through a different
676 // `MutableOperandRange` of the same operation.
677 SmallVector<Value> loopHeaderSuccessorOperands =
678 llvm::to_vector(getSuccessorOperands(latch, loopHeaderIndex));
679
680 // Add all values used in the next iteration to the exit block. Replace
681 // any uses that are outside the loop with the newly created exit block.
682 for (Value arg : loopHeaderSuccessorOperands) {
683 BlockArgument exitArg = exitBlock->addArgument(arg.getType(), arg.getLoc());
684 exitBlockSuccessorOperands.append(arg);
685 arg.replaceUsesWithIf(exitArg, [&](OpOperand &use) {
686 return !loopBlocks.contains(use.getOwner()->getBlock());
687 });
688 }
689
690 // Loop below might add block arguments to the latch and loop header.
691 // Save the block arguments prior to the loop to not process these.
692 SmallVector<BlockArgument> latchBlockArgumentsPrior =
693 llvm::to_vector(latch->getArguments());
694 SmallVector<BlockArgument> loopHeaderArgumentsPrior =
695 llvm::to_vector(loopHeader->getArguments());
696
697 // Go over all values defined within the loop body. If any of them are used
698 // outside the loop body, create a block argument on the exit block and loop
699 // header and replace the outside uses with the exit block argument.
700 // The loop header block argument is added to satisfy requirement (1) in the
701 // reduce form condition.
702 for (Block *loopBlock : loopBlocks) {
703 // Cache dominance queries for loopBlock.
704 // There are likely to be many duplicate queries as there can be many value
705 // definitions within a block.
706 llvm::SmallDenseMap<Block *, bool> dominanceCache;
707 // Returns true if `loopBlock` dominates `block`.
708 auto loopBlockDominates = [&](Block *block) {
709 auto [iter, inserted] = dominanceCache.try_emplace(block);
710 if (!inserted)
711 return iter->second;
712 iter->second = dominanceInfo.dominates(loopBlock, block);
713 return iter->second;
714 };
715
716 auto checkValue = [&](Value value) {
717 Value blockArgument;
718 for (OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
719 // Go through all the parent blocks and find the one part of the region
720 // of the loop. If the block is part of the loop, then the value does
721 // not escape the loop through this use.
722 Block *currBlock = use.getOwner()->getBlock();
723 while (currBlock && currBlock->getParent() != loopHeader->getParent())
724 currBlock = currBlock->getParentOp()->getBlock();
725 if (loopBlocks.contains(currBlock))
726 continue;
727
728 // Block argument is only created the first time it is required.
729 if (!blockArgument) {
730 blockArgument =
731 exitBlock->addArgument(value.getType(), value.getLoc());
732 loopHeader->addArgument(value.getType(), value.getLoc());
733
734 // `value` might be defined in a block that does not dominate `latch`
735 // but previously dominated an exit block with a use.
736 // In this case, add a block argument to the latch and go through all
737 // predecessors. If the value dominates the predecessor, pass the
738 // value as a successor operand, otherwise pass undef.
739 // The above is unnecessary if the value is a block argument of the
740 // latch or if `value` dominates all predecessors.
741 Value argument = value;
742 if (value.getParentBlock() != latch &&
743 llvm::any_of(latch->getPredecessors(), [&](Block *pred) {
744 return !loopBlockDominates(pred);
745 })) {
746 argument = latch->addArgument(value.getType(), value.getLoc());
747 for (auto iter = latch->pred_begin(); iter != latch->pred_end();
748 ++iter) {
749 Value succOperand = value;
750 if (!loopBlockDominates(*iter))
751 succOperand = getUndefValue(value.getType());
752
753 getMutableSuccessorOperands(*iter, iter.getSuccessorIndex())
754 .append(succOperand);
755 }
756 }
757
758 loopHeaderSuccessorOperands.push_back(argument);
759 for (Edge edge : successorEdges(latch))
760 edge.getMutableSuccessorOperands().append(argument);
761 }
762
763 use.set(blockArgument);
764 }
765 };
766
767 if (loopBlock == latch)
768 llvm::for_each(latchBlockArgumentsPrior, checkValue);
769 else if (loopBlock == loopHeader)
770 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
771 else
772 llvm::for_each(loopBlock->getArguments(), checkValue);
773
774 for (Operation &op : *loopBlock)
775 llvm::for_each(op.getResults(), checkValue);
776 }
777
778 // New block arguments may have been added to the loop header.
779 // Adjust the entry edges to pass undef values to these.
780 for (auto iter = loopHeader->pred_begin(); iter != loopHeader->pred_end();
781 ++iter) {
782 // Latch successor arguments have already been handled.
783 if (*iter == latch)
784 continue;
785
786 MutableOperandRange succOps =
787 getMutableSuccessorOperands(*iter, iter.getSuccessorIndex());
788 succOps.append(llvm::map_to_vector(
789 loopHeader->getArguments().drop_front(succOps.size()),
790 [&](BlockArgument arg) { return getUndefValue(arg.getType()); }));
791 }
792
793 return loopHeaderSuccessorOperands;
794}
795
796/// Transforms all outer-most cycles in the region with the region entry
797/// `regionEntry` into structured loops. Returns the entry blocks of any newly
798/// created regions potentially requiring further transformations.
799static FailureOr<SmallVector<Block *>> transformCyclesToSCFLoops(
800 Block *regionEntry, function_ref<Value(unsigned)> getSwitchValue,
801 function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
802 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
803 SmallVector<Block *> newSubRegions;
804 auto scc = llvm::scc_begin(regionEntry);
805 while (!scc.isAtEnd()) {
806 if (!scc.hasCycle()) {
807 ++scc;
808 continue;
809 }
810
811 // Save the set and increment the SCC iterator early to avoid our
812 // modifications breaking the SCC iterator.
813 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
814 ++scc;
815
816 CycleEdges edges = calculateCycleEdges(cycleBlockSet);
817 Block *loopHeader = edges.entryEdges.front().getSuccessor();
818 // First turn the cycle into a loop by creating a single entry block if
819 // needed.
820 if (edges.entryEdges.size() > 1) {
821 SmallVector<Edge> edgesToEntryBlocks;
822 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
823 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
824
825 EdgeMultiplexer multiplexer = createSingleEntryBlock(
826 loopHeader->getTerminator()->getLoc(), edgesToEntryBlocks,
827 getSwitchValue, getUndefValue, interface);
828
829 loopHeader = multiplexer.getMultiplexerBlock();
830 }
831 cycleBlockSet.insert(loopHeader);
832
833 // Then turn it into a structured loop by creating a single latch.
834 FailureOr<StructuredLoopProperties> loopProperties =
836 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
837 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
838 interface, exitCombiner);
839 if (failed(loopProperties))
840 return failure();
841
842 Block *latchBlock = loopProperties->latch;
843 Block *exitBlock = loopProperties->exitBlock;
844 cycleBlockSet.insert(latchBlock);
845 cycleBlockSet.insert(loopHeader);
846
847 // Finally, turn it into reduce form.
849 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
850
851 // Create a block acting as replacement for the loop header and insert
852 // the structured loop into it.
853 auto *newLoopParentBlock = new Block;
854 newLoopParentBlock->insertBefore(loopHeader);
855 addBlockArgumentsFromOther(newLoopParentBlock, loopHeader);
856
857 Region::BlockListType &blocks = regionEntry->getParent()->getBlocks();
858 Region loopBody;
859 // Make sure the loop header is the entry block.
860 loopBody.push_back(blocks.remove(loopHeader));
861 for (Block *block : cycleBlockSet)
862 if (block != latchBlock && block != loopHeader)
863 loopBody.push_back(blocks.remove(block));
864 // And the latch is the last block.
865 loopBody.push_back(blocks.remove(latchBlock));
866
867 Operation *oldTerminator = latchBlock->getTerminator();
868 oldTerminator->remove();
869
870 auto builder = OpBuilder::atBlockBegin(newLoopParentBlock);
871 FailureOr<Operation *> structuredLoopOp =
873 builder, oldTerminator, newLoopParentBlock->getArguments(),
874 loopProperties->condition, iterationValues, std::move(loopBody));
875 if (failed(structuredLoopOp))
876 return failure();
877 oldTerminator->erase();
878
879 newSubRegions.push_back(loopHeader);
880
881 for (auto &&[oldValue, newValue] : llvm::zip(
882 exitBlock->getArguments(), (*structuredLoopOp)->getResults()))
883 oldValue.replaceAllUsesWith(newValue);
884
885 loopHeader->replaceAllUsesWith(newLoopParentBlock);
886 // Merge the exit block right after the loop operation.
887 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
888 exitBlock->getOperations());
889 exitBlock->erase();
890 }
891 return newSubRegions;
892}
893
894/// Makes sure the branch region only has a single exit. This is required by the
895/// recursive part of the algorithm, as it expects the CFG to be single-entry
896/// and single-exit. This is done by simply creating an empty block if there
897/// is more than one block with an edge to the continuation block. All blocks
898/// with edges to the continuation are then redirected to this block. A region
899/// terminator is later placed into the block.
901 ArrayRef<Block *> branchRegion, Block *continuation,
902 SmallVectorImpl<std::pair<Block *, SmallVector<Value>>> &createdEmptyBlocks,
903 Region &conditionalRegion) {
904 Block *singleExitBlock = nullptr;
905 std::optional<Edge> previousEdgeToContinuation;
906 Region::BlockListType &parentBlockList =
907 branchRegion.front()->getParent()->getBlocks();
908 for (Block *block : branchRegion) {
909 for (Edge edge : successorEdges(block)) {
910 if (edge.getSuccessor() != continuation)
911 continue;
912
913 if (!previousEdgeToContinuation) {
914 previousEdgeToContinuation = edge;
915 continue;
916 }
917
918 // If this is not the first edge to the continuation we create the
919 // single exit block and redirect the edges.
920 if (!singleExitBlock) {
921 singleExitBlock = new Block;
922 addBlockArgumentsFromOther(singleExitBlock, continuation);
923 previousEdgeToContinuation->setSuccessor(singleExitBlock);
924 createdEmptyBlocks.emplace_back(singleExitBlock,
925 singleExitBlock->getArguments());
926 }
927
928 edge.setSuccessor(singleExitBlock);
929 }
930
931 conditionalRegion.push_back(parentBlockList.remove(block));
932 }
933
934 if (singleExitBlock)
935 conditionalRegion.push_back(singleExitBlock);
936}
937
938/// Returns true if this block is an exit block of the region.
939static bool isRegionExitBlock(Block *block) {
940 return block->getNumSuccessors() == 0;
941}
942
943/// Transforms the first occurrence of conditional control flow in `regionEntry`
944/// into conditionally executed regions. Returns the entry block of the created
945/// regions and the region after the conditional control flow.
946static FailureOr<SmallVector<Block *>> transformToStructuredCFBranches(
947 Block *regionEntry, function_ref<Value(unsigned)> getSwitchValue,
948 function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
949 DominanceInfo &dominanceInfo) {
950 // Trivial region.
951 if (regionEntry->getNumSuccessors() == 0)
952 return SmallVector<Block *>{};
953
954 if (regionEntry->getNumSuccessors() == 1) {
955 // Single successor we can just splice together.
956 Block *successor = regionEntry->getSuccessor(0);
957 for (auto &&[oldValue, newValue] : llvm::zip(
958 successor->getArguments(), getSuccessorOperands(regionEntry, 0)))
959 oldValue.replaceAllUsesWith(newValue);
960 regionEntry->getTerminator()->erase();
961
962 regionEntry->getOperations().splice(regionEntry->end(),
963 successor->getOperations());
964 successor->erase();
965 return SmallVector<Block *>{regionEntry};
966 }
967
968 // Split the CFG into "#numSuccessor + 1" regions.
969 // For every edge to a successor, the blocks it solely dominates are
970 // determined and become the region following that edge.
971 // The last region is the continuation that follows the branch regions.
972 SmallPtrSet<Block *, 8> notContinuation;
973 notContinuation.insert(regionEntry);
974 SmallVector<SmallVector<Block *>> successorBranchRegions(
975 regionEntry->getNumSuccessors());
976 for (auto &&[blockList, succ] :
977 llvm::zip(successorBranchRegions, regionEntry->getSuccessors())) {
978 // If the region entry is not the only predecessor, then the edge does not
979 // dominate the block it leads to.
980 if (succ->getSinglePredecessor() != regionEntry)
981 continue;
982
983 // Otherwise get all blocks it dominates in DFS/pre-order.
984 DominanceInfoNode *node = dominanceInfo.getNode(succ);
985 for (DominanceInfoNode *curr : llvm::depth_first(node)) {
986 blockList.push_back(curr->getBlock());
987 notContinuation.insert(curr->getBlock());
988 }
989 }
990
991 // Finds all relevant edges and checks the shape of the control flow graph at
992 // this point.
993 // Branch regions may either:
994 // * Be post-dominated by the continuation
995 // * Be post-dominated by a return-like op
996 // * Dominate a return-like op and have an edge to the continuation.
997 //
998 // The control flow graph may then be one of three cases:
999 // 1) All branch regions are post-dominated by the continuation. This is the
1000 // usual case. If there are multiple entry blocks into the continuation a
1001 // single entry block has to be created. A structured control flow op
1002 // can then be created from the branch regions.
1003 //
1004 // 2) No branch region has an edge to a continuation:
1005 // +-----+
1006 // +-----+ bb0 +----+
1007 // v +-----+ v
1008 // Region 1 +-+--+ ... +-+--+ Region n
1009 // |ret1| |ret2|
1010 // +----+ +----+
1011 //
1012 // This can only occur if every region ends with a different kind of
1013 // return-like op. In that case the control flow operation must stay as we are
1014 // unable to create a single exit-block. We can nevertheless process all its
1015 // successors as they single-entry, single-exit regions.
1016 //
1017 // 3) Only some branch regions are post-dominated by the continuation.
1018 // The other branch regions may either be post-dominated by a return-like op
1019 // or lead to either the continuation or return-like op.
1020 // In this case we also create a single entry block like in 1) that also
1021 // includes all edges to the return-like op:
1022 // +-----+
1023 // +-----+ bb0 +----+
1024 // v +-----+ v
1025 // Region 1 +-+-+ ... +-+-+ Region n
1026 // +---+ +---+
1027 // +---+ |... ...
1028 // |ret|<-+ | |
1029 // +---+ | +---+ |
1030 // +---->++ ++<---+
1031 // | |
1032 // ++ ++ Region T
1033 // +---+
1034 // This transforms to:
1035 // +-----+
1036 // +-----+ bb0 +----+
1037 // v +-----+ v
1038 // Region 1 +-+-+ ... +-+-+ Region n
1039 // +---+ +---+
1040 // ... +-----+ ...
1041 // +---->+ bbM +<---+
1042 // +-----+
1043 // +-----+ |
1044 // | v
1045 // +---+ | +---+
1046 // |ret+<---+ ++ ++
1047 // +---+ | |
1048 // ++ ++ Region T
1049 // +---+
1050 //
1051 // bb0 to bbM is now a single-entry, single-exit region that applies to case
1052 // 1). The control flow op at the end of bbM will trigger case 2.
1053 SmallVector<Edge> continuationEdges;
1054 bool continuationPostDominatesAllRegions = true;
1055 bool noSuccessorHasContinuationEdge = true;
1056 for (auto &&[entryEdge, branchRegion] :
1057 llvm::zip(successorEdges(regionEntry), successorBranchRegions)) {
1058
1059 // If the branch region is empty then the branch target itself is part of
1060 // the continuation.
1061 if (branchRegion.empty()) {
1062 continuationEdges.push_back(entryEdge);
1063 noSuccessorHasContinuationEdge = false;
1064 continue;
1065 }
1066
1067 for (Block *block : branchRegion) {
1068 if (isRegionExitBlock(block)) {
1069 // If a return-like op is part of the branch region then the
1070 // continuation no longer post-dominates the branch region.
1071 // Add all its incoming edges to edge list to create the single-exit
1072 // block for all branch regions.
1073 continuationPostDominatesAllRegions = false;
1074 for (auto iter = block->pred_begin(); iter != block->pred_end();
1075 ++iter) {
1076 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1077 }
1078 continue;
1079 }
1080
1081 for (Edge edge : successorEdges(block)) {
1082 if (notContinuation.contains(edge.getSuccessor()))
1083 continue;
1084
1085 continuationEdges.push_back(edge);
1086 noSuccessorHasContinuationEdge = false;
1087 }
1088 }
1089 }
1090
1091 // case 2) Keep the control flow op but process its successors further.
1092 if (noSuccessorHasContinuationEdge)
1093 return llvm::to_vector(regionEntry->getSuccessors());
1094
1095 Block *continuation = llvm::find_singleton<Block>(
1096 continuationEdges, [](Edge edge, bool) { return edge.getSuccessor(); },
1097 /*AllowRepeats=*/true);
1098
1099 // In case 3) or if not all continuation edges have the same entry block,
1100 // create a single entry block as continuation for all branch regions.
1101 if (!continuation || !continuationPostDominatesAllRegions) {
1102 EdgeMultiplexer multiplexer = createSingleEntryBlock(
1103 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1104 continuationEdges, getSwitchValue, getUndefValue, interface);
1105 continuation = multiplexer.getMultiplexerBlock();
1106 }
1107
1108 // Trigger reprocess of case 3) after creating the single entry block.
1109 if (!continuationPostDominatesAllRegions) {
1110 // Unlike in the general case, we are explicitly revisiting the same region
1111 // entry again after having changed its control flow edges and dominance.
1112 // We have to therefore explicitly invalidate the dominance tree.
1113 dominanceInfo.invalidate(regionEntry->getParent());
1114 return SmallVector<Block *>{regionEntry};
1115 }
1116
1117 SmallVector<Block *> newSubRegions;
1118
1119 // Empty blocks with the values they return to the parent op.
1121
1122 // Create the branch regions.
1123 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1124 for (auto &&[branchRegion, entryEdge, conditionalRegion] :
1125 llvm::zip(successorBranchRegions, successorEdges(regionEntry),
1126 conditionalRegions)) {
1127 if (branchRegion.empty()) {
1128 // If no block is part of the branch region, we create a dummy block to
1129 // place the region terminator into.
1130 createdEmptyBlocks.emplace_back(
1131 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1132 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1133 continue;
1134 }
1135
1136 createSingleExitBranchRegion(branchRegion, continuation, createdEmptyBlocks,
1137 conditionalRegion);
1138
1139 // The entries of the branch regions may only have redundant block arguments
1140 // since the edge to the branch region is always dominating.
1141 Block *subRegionEntryBlock = &conditionalRegion.front();
1142 for (auto &&[oldValue, newValue] :
1143 llvm::zip(subRegionEntryBlock->getArguments(),
1144 entryEdge.getSuccessorOperands()))
1145 oldValue.replaceAllUsesWith(newValue);
1146
1147 subRegionEntryBlock->eraseArguments(0,
1148 subRegionEntryBlock->getNumArguments());
1149 newSubRegions.push_back(subRegionEntryBlock);
1150 }
1151
1152 Operation *structuredCondOp;
1153 {
1154 auto opBuilder = OpBuilder::atBlockTerminator(regionEntry);
1155 FailureOr<Operation *> result = interface.createStructuredBranchRegionOp(
1156 opBuilder, regionEntry->getTerminator(),
1157 continuation->getArgumentTypes(), conditionalRegions);
1158 if (failed(result)) {
1159 // Blocks were moved from the parent region into conditionalRegions before
1160 // calling createStructuredBranchRegionOp. On failure, move them back to
1161 // avoid use-after-free crashes: the moved blocks may still be referenced
1162 // as successors by blocks remaining in the parent region, so destroying
1163 // conditionalRegions with live uses would trigger an assertion.
1164 // This patching does not undo the change, it barely makes it so that the
1165 // pass can gracefully fail instead of crashing.
1166 Region *parentRegion = regionEntry->getParent();
1167 for (Region &conditionalRegion : conditionalRegions)
1168 parentRegion->getBlocks().splice(parentRegion->getBlocks().end(),
1169 conditionalRegion.getBlocks());
1170 return failure();
1171 }
1172 structuredCondOp = *result;
1173 regionEntry->getTerminator()->erase();
1174 }
1175
1176 for (auto &&[block, valueRange] : createdEmptyBlocks) {
1177 auto builder = OpBuilder::atBlockEnd(block);
1178 LogicalResult result = interface.createStructuredBranchRegionTerminatorOp(
1179 structuredCondOp->getLoc(), builder, structuredCondOp, nullptr,
1180 valueRange);
1181 if (failed(result))
1182 return failure();
1183 }
1184
1185 // Any leftover users of the continuation must be from unconditional branches
1186 // in a branch region. There can only be at most one per branch region as
1187 // all branch regions have been made single-entry single-exit above.
1188 // Replace them with the region terminator.
1189 for (Operation *user : llvm::make_early_inc_range(continuation->getUsers())) {
1190 assert(user->getNumSuccessors() == 1);
1191 auto builder = OpBuilder::atBlockTerminator(user->getBlock());
1192 LogicalResult result = interface.createStructuredBranchRegionTerminatorOp(
1193 user->getLoc(), builder, structuredCondOp, user,
1194 getMutableSuccessorOperands(user->getBlock(), 0).getAsOperandRange());
1195 if (failed(result))
1196 return failure();
1197 user->erase();
1198 }
1199
1200 for (auto &&[oldValue, newValue] :
1201 llvm::zip(continuation->getArguments(), structuredCondOp->getResults()))
1202 oldValue.replaceAllUsesWith(newValue);
1203
1204 // Splice together the continuations operations with the region entry.
1205 regionEntry->getOperations().splice(regionEntry->end(),
1206 continuation->getOperations());
1207
1208 continuation->erase();
1209
1210 // After splicing the continuation, the region has to be reprocessed as it has
1211 // new successors.
1212 newSubRegions.push_back(regionEntry);
1213
1214 return newSubRegions;
1215}
1216
1217/// Transforms the region to only have a single block for every kind of
1218/// return-like operation that all previous occurrences of the return-like op
1219/// branch to. If the region only contains a single kind of return-like
1220/// operation, it creates a single-entry and single-exit region.
1221static ReturnLikeExitCombiner createSingleExitBlocksForReturnLike(
1222 Region &region, function_ref<Value(unsigned)> getSwitchValue,
1223 CFGToSCFInterface &interface) {
1224 ReturnLikeExitCombiner exitCombiner(region, interface);
1225
1226 for (Block &block : region.getBlocks()) {
1227 if (block.getNumSuccessors() != 0)
1228 continue;
1229 exitCombiner.combineExit(block.getTerminator(), getSwitchValue);
1230 }
1231
1232 return exitCombiner;
1233}
1234
1235/// Checks all preconditions of the transformation prior to any transformations.
1236/// Returns failure if any precondition is violated.
1237static LogicalResult
1239 for (Block &block : region.getBlocks())
1240 if (block.hasNoPredecessors() && !block.isEntryBlock())
1241 return block.front().emitOpError(
1242 "transformation does not support unreachable blocks");
1243
1244 WalkResult result = region.walk([](Operation *operation) {
1245 if (operation->getNumSuccessors() == 0)
1246 return WalkResult::advance();
1247
1248 // This transformation requires all ops with successors to implement the
1249 // branch op interface. It is impossible to adjust their block arguments
1250 // otherwise.
1251 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1252 if (!branchOpInterface) {
1253 operation->emitOpError("transformation does not support terminators with "
1254 "successors not implementing BranchOpInterface");
1255 return WalkResult::interrupt();
1256 }
1257 // Branch operations must have no side effects. Replacing them would not be
1258 // valid otherwise.
1259 if (!isMemoryEffectFree(branchOpInterface)) {
1260 branchOpInterface->emitOpError(
1261 "transformation does not support terminators with side effects");
1262 return WalkResult::interrupt();
1263 }
1264
1265 for (unsigned index : llvm::seq(operation->getNumSuccessors())) {
1266 SuccessorOperands succOps = branchOpInterface.getSuccessorOperands(index);
1267
1268 // We cannot support operations with operation-produced successor operands
1269 // as it is currently not possible to pass them to any block arguments
1270 // other than the first. This breaks creating multiplexer blocks and would
1271 // likely need special handling elsewhere too.
1272 if (succOps.getProducedOperandCount() == 0)
1273 continue;
1274
1275 branchOpInterface->emitOpError("transformation does not support "
1276 "operations with operation-produced "
1277 "successor operands");
1278 return WalkResult::interrupt();
1279 }
1280 return WalkResult::advance();
1281 });
1282 if (result.wasInterrupted())
1283 return failure();
1284
1285 // Verify all multi-successor terminators are convertible before touching IR.
1286 for (Block &block : region.getBlocks()) {
1287 if (block.getNumSuccessors() <= 1)
1288 continue;
1289 Operation *terminator = block.getTerminator();
1290 if (!interface.canConvertMultiSuccessorBranchOp(terminator)) {
1291 terminator->emitOpError(
1292 "cannot convert unknown control flow op to structured control flow");
1293 return failure();
1294 }
1295 }
1296 return success();
1297}
1298
1299FailureOr<bool> mlir::transformCFGToSCF(Region &region,
1300 CFGToSCFInterface &interface,
1301 DominanceInfo &dominanceInfo) {
1302 if (region.empty() || region.hasOneBlock())
1303 return false;
1304
1305 if (failed(checkTransformationPreconditions(region, interface)))
1306 return failure();
1307
1308 DenseMap<Type, Value> typedUndefCache;
1309 auto getUndefValue = [&](Type type) {
1310 auto [iter, inserted] = typedUndefCache.try_emplace(type);
1311 if (!inserted)
1312 return iter->second;
1313
1314 auto constantBuilder = OpBuilder::atBlockBegin(&region.front());
1315
1316 iter->second =
1317 interface.getUndefValue(region.getLoc(), constantBuilder, type);
1318 return iter->second;
1319 };
1320
1321 // The transformation only creates all values in the range of 0 to
1322 // max(#numSuccessors). Therefore using a vector instead of a map.
1323 SmallVector<Value> switchValueCache;
1324 auto getSwitchValue = [&](unsigned value) {
1325 if (value < switchValueCache.size())
1326 if (switchValueCache[value])
1327 return switchValueCache[value];
1328
1329 auto constantBuilder = OpBuilder::atBlockBegin(&region.front());
1330
1331 switchValueCache.resize(
1332 std::max<size_t>(switchValueCache.size(), value + 1));
1333
1334 switchValueCache[value] =
1335 interface.getCFGSwitchValue(region.getLoc(), constantBuilder, value);
1336 return switchValueCache[value];
1337 };
1338
1339 ReturnLikeExitCombiner exitCombiner =
1340 createSingleExitBlocksForReturnLike(region, getSwitchValue, interface);
1341
1342 // Invalidate any dominance tree on the region as the exit combiner has
1343 // added new blocks and edges.
1344 dominanceInfo.invalidate(&region);
1345
1346 SmallVector<Block *> workList = {&region.front()};
1347 while (!workList.empty()) {
1348 Block *current = workList.pop_back_val();
1349
1350 // Turn all top-level cycles in the CFG to structured control flow first.
1351 // After this transformation, the remaining CFG ops form a DAG.
1352 FailureOr<SmallVector<Block *>> newRegions =
1353 transformCyclesToSCFLoops(current, getSwitchValue, getUndefValue,
1354 interface, dominanceInfo, exitCombiner);
1355 if (failed(newRegions))
1356 return failure();
1357
1358 // Add the newly created subregions to the worklist. These are the
1359 // bodies of the loops.
1360 llvm::append_range(workList, *newRegions);
1361 // Invalidate the dominance tree as blocks have been moved, created and
1362 // added during the cycle to structured loop transformation.
1363 if (!newRegions->empty())
1364 dominanceInfo.invalidate(current->getParent());
1365
1367 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1368 if (failed(newRegions))
1369 return failure();
1370 // Invalidating the dominance tree is generally not required by the
1371 // transformation above as the new region entries correspond to unaffected
1372 // subtrees in the dominator tree. Only its parent nodes have changed but
1373 // won't be visited again.
1374 llvm::append_range(workList, *newRegions);
1375 }
1376
1377 return true;
1378}
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:515
static bool isRegionExitBlock(Block *block)
Returns true if this block is an exit block of the region.
Definition CFGToSCF.cpp:939
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:946
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:654
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:469
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:551
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:900
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:799
static CycleEdges calculateCycleEdges(const llvm::SmallSetVector< Block *, 4 > &cycles)
Calculates entry, exit and back edges of the given cycle.
Definition CFGToSCF.cpp:476
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.