xref: /llvm-project/mlir/lib/Transforms/Utils/CFGToSCF.cpp (revision a9304edf20756dd63f896a98bad89e9eac54aebd)
13b45fe2eSMarkus Böck //===- CFGToSCF.h - Control Flow Graph to Structured Control Flow *- C++ -*===//
23b45fe2eSMarkus Böck //
33b45fe2eSMarkus Böck // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43b45fe2eSMarkus Böck // See https://llvm.org/LICENSE.txt for license information.
53b45fe2eSMarkus Böck // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63b45fe2eSMarkus Böck //
73b45fe2eSMarkus Böck //===----------------------------------------------------------------------===//
83b45fe2eSMarkus Böck //
93b45fe2eSMarkus Böck // This code is an implementation of:
103b45fe2eSMarkus Böck // Helge Bahmann, Nico Reissmann, Magnus Jahre, and Jan Christian Meyer. 2015.
113b45fe2eSMarkus Böck // Perfect Reconstructability of Control Flow from Demand Dependence Graphs. ACM
123b45fe2eSMarkus Böck // Trans. Archit. Code Optim. 11, 4, Article 66 (January 2015), 25 pages.
133b45fe2eSMarkus Böck // https://doi.org/10.1145/2693261
143b45fe2eSMarkus Böck //
153b45fe2eSMarkus Böck // It defines an algorithm to translate any control flow graph with a single
163b45fe2eSMarkus Böck // entry and single exit block into structured control flow operations
173b45fe2eSMarkus Böck // consisting of regions of do-while loops and operations conditionally
183b45fe2eSMarkus Böck // dispatching to one out of multiple regions before continuing after the
193b45fe2eSMarkus Böck // operation. This includes control flow graphs containing irreducible
203b45fe2eSMarkus Böck // control flow.
213b45fe2eSMarkus Böck //
223b45fe2eSMarkus Böck // The implementation here additionally supports the transformation on
233b45fe2eSMarkus Böck // regions with multiple exit blocks. This is implemented by first
243b45fe2eSMarkus Böck // transforming all occurrences of return-like operations to branch to a
253b45fe2eSMarkus Böck // single exit block containing an instance of that return-like operation.
263b45fe2eSMarkus Böck // If there are multiple kinds of return-like operations, multiple exit
273b45fe2eSMarkus Böck // blocks are created. In that case the transformation leaves behind a
283b45fe2eSMarkus Böck // conditional control flow graph operation that dispatches to the given regions
293b45fe2eSMarkus Böck // terminating with different kinds of return-like operations each.
303b45fe2eSMarkus Böck //
313b45fe2eSMarkus Böck // If the function only contains a single kind of return-like operations,
323b45fe2eSMarkus Böck // it is guaranteed that all control flow graph ops will be lifted to structured
333b45fe2eSMarkus Böck // control flow, and that no more control flow graph ops remain after the
343b45fe2eSMarkus Böck // operation.
353b45fe2eSMarkus Böck //
363b45fe2eSMarkus Böck // The algorithm to lift CFGs consists of two transformations applied after each
373b45fe2eSMarkus Böck // other on any single-entry, single-exit region:
383b45fe2eSMarkus Böck // 1) Lifting cycles to structured control flow loops
393b45fe2eSMarkus Böck // 2) Lifting conditional branches to structured control flow branches
403b45fe2eSMarkus Böck // These are then applied recursively on any new single-entry single-exit
413b45fe2eSMarkus Böck // regions created by the transformation until no more CFG operations remain.
423b45fe2eSMarkus Böck //
433b45fe2eSMarkus Böck // The first part of cycle lifting is to detect any cycles in the CFG.
443b45fe2eSMarkus Böck // This is done using an algorithm for iterating over SCCs. Every SCC
453b45fe2eSMarkus Böck // representing a cycle is then transformed into a structured loop with a single
463b45fe2eSMarkus Böck // entry block and a single latch containing the only back edge to the entry
473b45fe2eSMarkus Böck // block and the only edge to an exit block outside the loop. Rerouting control
483b45fe2eSMarkus Böck // flow to create single entry and exit blocks is achieved via a multiplexer
493b45fe2eSMarkus Böck // construct that can be visualized as follows:
503b45fe2eSMarkus Böck //                         +-----+ +-----+   +-----+
513b45fe2eSMarkus Böck //                         | bb0 | | bb1 |...| bbN |
523b45fe2eSMarkus Böck //                         +--+--+ +--+--+   +-+---+
533b45fe2eSMarkus Böck //                            |       |        |
543b45fe2eSMarkus Böck //                            |       v        |
553b45fe2eSMarkus Böck //                            |  +------+      |
563b45fe2eSMarkus Böck //                            | ++      ++<----+
573b45fe2eSMarkus Böck //                            | | Region |
583b45fe2eSMarkus Böck //                            +>|        |<----+
593b45fe2eSMarkus Böck //                              ++      ++     |
603b45fe2eSMarkus Böck //                               +------+------+
613b45fe2eSMarkus Böck //
623b45fe2eSMarkus Böck // The above transforms to:
633b45fe2eSMarkus Böck //                         +-----+ +-----+   +-----+
643b45fe2eSMarkus Böck //                         | bb0 | | bb1 |...| bbN |
653b45fe2eSMarkus Böck //                         +-----+ +--|--+   ++----+
663b45fe2eSMarkus Böck //                              |     v       |
673b45fe2eSMarkus Böck //                              +->+-----+<---+
683b45fe2eSMarkus Böck //                                 | bbM |<-------+
693b45fe2eSMarkus Böck //                                 +---+-+        |
703b45fe2eSMarkus Böck //                             +---+   | +----+   |
713b45fe2eSMarkus Böck //                             |       v      |   |
723b45fe2eSMarkus Böck //                             |   +------+   |   |
733b45fe2eSMarkus Böck //                             |  ++      ++<-+   |
743b45fe2eSMarkus Böck //                             +->| Region |      |
753b45fe2eSMarkus Böck //                                ++      ++      |
763b45fe2eSMarkus Böck //                                 +------+-------+
773b45fe2eSMarkus Böck //
783b45fe2eSMarkus Böck // bbM in the above is the multiplexer block, and any block previously branching
793b45fe2eSMarkus Böck // to an entry block of the region are redirected to it. This includes any
803b45fe2eSMarkus Böck // branches from within the region. Using a block argument, bbM then dispatches
813b45fe2eSMarkus Böck // to the correct entry block of the region dependent on the predecessor.
823b45fe2eSMarkus Böck //
833b45fe2eSMarkus Böck // A similar transformation is done to create the latch block with the single
843b45fe2eSMarkus Böck // back edge and loop exit edge.
853b45fe2eSMarkus Böck //
863b45fe2eSMarkus Böck // The above form has the advantage that bbM now acts as the loop header
873b45fe2eSMarkus Böck // of the loop body. After the transformation on the latch, this results in a
883b45fe2eSMarkus Böck // structured loop that can then be lifted to structured control flow. The
893b45fe2eSMarkus Böck // conditional branches created in bbM are later lifted to conditional
903b45fe2eSMarkus Böck // branches.
913b45fe2eSMarkus Böck //
923b45fe2eSMarkus Böck // Lifting conditional branches is done by analyzing the *first* conditional
933b45fe2eSMarkus Böck // branch encountered in the entry region. The algorithm then identifies
943b45fe2eSMarkus Böck // all blocks that are dominated by a specific control flow edge and
953b45fe2eSMarkus Böck // the region where control flow continues:
963b45fe2eSMarkus Böck //                                 +-----+
973b45fe2eSMarkus Böck //                           +-----+ bb0 +----+
983b45fe2eSMarkus Böck //                           v     +-----+    v
993b45fe2eSMarkus Böck //                Region 1 +-+-+    ...     +-+-+ Region n
1003b45fe2eSMarkus Böck //                         +---+            +---+
1013b45fe2eSMarkus Böck //                          ...              ...
1023b45fe2eSMarkus Böck //                           |                |
1033b45fe2eSMarkus Böck //                           |      +---+     |
1043b45fe2eSMarkus Böck //                           +---->++   ++<---+
1053b45fe2eSMarkus Böck //                                 |     |
1063b45fe2eSMarkus Böck //                                 ++   ++ Region T
1073b45fe2eSMarkus Böck //                                  +---+
1083b45fe2eSMarkus Böck // Every region following bb0 consists of 0 or more blocks that eventually
1093b45fe2eSMarkus Böck // branch to Region T. If there are multiple entry blocks into Region T, a
1103b45fe2eSMarkus Böck // single entry block is created using a multiplexer block as shown above.
1113b45fe2eSMarkus Böck // Region 1 to Region n are then lifted together with the conditional control
1123b45fe2eSMarkus Böck // flow operation terminating bb0 into a structured conditional operation
1133b45fe2eSMarkus Böck // followed by the operations of the entry block of Region T.
1143b45fe2eSMarkus Böck //===----------------------------------------------------------------------===//
1153b45fe2eSMarkus Böck 
1163b45fe2eSMarkus Böck #include "mlir/Transforms/CFGToSCF.h"
1173b45fe2eSMarkus Böck 
1183b45fe2eSMarkus Böck #include "mlir/IR/RegionGraphTraits.h"
1193b45fe2eSMarkus Böck #include "mlir/Interfaces/ControlFlowInterfaces.h"
1203b45fe2eSMarkus Böck #include "mlir/Interfaces/SideEffectInterfaces.h"
1213b45fe2eSMarkus Böck #include "llvm/ADT/DepthFirstIterator.h"
1223b45fe2eSMarkus Böck #include "llvm/ADT/MapVector.h"
1233b45fe2eSMarkus Böck #include "llvm/ADT/SCCIterator.h"
1243b45fe2eSMarkus Böck #include "llvm/ADT/SetVector.h"
1253b45fe2eSMarkus Böck #include "llvm/ADT/SmallPtrSet.h"
1263b45fe2eSMarkus Böck 
1273b45fe2eSMarkus Böck using namespace mlir;
1283b45fe2eSMarkus Böck 
1293b45fe2eSMarkus Böck /// Returns the mutable operand range used to transfer operands from `block` to
1303b45fe2eSMarkus Böck /// its successor with the given index. The returned range being mutable allows
1313b45fe2eSMarkus Böck /// us to modify the operands being transferred.
1323b45fe2eSMarkus Böck static MutableOperandRange
getMutableSuccessorOperands(Block * block,unsigned successorIndex)1333b45fe2eSMarkus Böck getMutableSuccessorOperands(Block *block, unsigned successorIndex) {
1343b45fe2eSMarkus Böck   auto branchOpInterface = cast<BranchOpInterface>(block->getTerminator());
1353b45fe2eSMarkus Böck   SuccessorOperands succOps =
1363b45fe2eSMarkus Böck       branchOpInterface.getSuccessorOperands(successorIndex);
1373b45fe2eSMarkus Böck   return succOps.getMutableForwardedOperands();
1383b45fe2eSMarkus Böck }
1393b45fe2eSMarkus Böck 
1406923a315SMatthias Springer /// Return the operand range used to transfer operands from `block` to its
1416923a315SMatthias Springer /// successor with the given index.
getSuccessorOperands(Block * block,unsigned successorIndex)1426923a315SMatthias Springer static OperandRange getSuccessorOperands(Block *block,
1436923a315SMatthias Springer                                          unsigned successorIndex) {
1446923a315SMatthias Springer   return getMutableSuccessorOperands(block, successorIndex);
1456923a315SMatthias Springer }
1466923a315SMatthias Springer 
1473b45fe2eSMarkus Böck /// Appends all the block arguments from `other` to the block arguments of
1483b45fe2eSMarkus Böck /// `block`, copying their types and locations.
addBlockArgumentsFromOther(Block * block,Block * other)1493b45fe2eSMarkus Böck static void addBlockArgumentsFromOther(Block *block, Block *other) {
1503b45fe2eSMarkus Böck   for (BlockArgument arg : other->getArguments())
1513b45fe2eSMarkus Böck     block->addArgument(arg.getType(), arg.getLoc());
1523b45fe2eSMarkus Böck }
1533b45fe2eSMarkus Böck 
1543b45fe2eSMarkus Böck namespace {
1553b45fe2eSMarkus Böck 
1563b45fe2eSMarkus Böck /// Class representing an edge in the CFG. Consists of a from-block, a successor
1573b45fe2eSMarkus Böck /// and corresponding successor operands passed to the block arguments of the
1583b45fe2eSMarkus Böck /// successor.
1593b45fe2eSMarkus Böck class Edge {
1603b45fe2eSMarkus Böck   Block *fromBlock;
1613b45fe2eSMarkus Böck   unsigned successorIndex;
1623b45fe2eSMarkus Böck 
1633b45fe2eSMarkus Böck public:
1643b45fe2eSMarkus Böck   /// Constructs a new edge from `fromBlock` to the successor corresponding to
1653b45fe2eSMarkus Böck   /// `successorIndex`.
Edge(Block * fromBlock,unsigned int successorIndex)1663b45fe2eSMarkus Böck   Edge(Block *fromBlock, unsigned int successorIndex)
1673b45fe2eSMarkus Böck       : fromBlock(fromBlock), successorIndex(successorIndex) {}
1683b45fe2eSMarkus Böck 
1693b45fe2eSMarkus Böck   /// Returns the from-block.
getFromBlock() const1703b45fe2eSMarkus Böck   Block *getFromBlock() const { return fromBlock; }
1713b45fe2eSMarkus Böck 
1723b45fe2eSMarkus Böck   /// Returns the successor of the edge.
getSuccessor() const1733b45fe2eSMarkus Böck   Block *getSuccessor() const {
1743b45fe2eSMarkus Böck     return fromBlock->getSuccessor(successorIndex);
1753b45fe2eSMarkus Böck   }
1763b45fe2eSMarkus Böck 
1773b45fe2eSMarkus Böck   /// Sets the successor of the edge, adjusting the terminator in the
1783b45fe2eSMarkus Böck   /// from-block.
setSuccessor(Block * block) const1793b45fe2eSMarkus Böck   void setSuccessor(Block *block) const {
1803b45fe2eSMarkus Böck     fromBlock->getTerminator()->setSuccessor(block, successorIndex);
1813b45fe2eSMarkus Böck   }
1823b45fe2eSMarkus Böck 
1833b45fe2eSMarkus Böck   /// Returns the arguments of this edge that are passed to the block arguments
1843b45fe2eSMarkus Böck   /// of the successor.
getMutableSuccessorOperands() const1856923a315SMatthias Springer   MutableOperandRange getMutableSuccessorOperands() const {
1866923a315SMatthias Springer     return ::getMutableSuccessorOperands(fromBlock, successorIndex);
1876923a315SMatthias Springer   }
1886923a315SMatthias Springer 
1896923a315SMatthias Springer   /// Returns the arguments of this edge that are passed to the block arguments
1906923a315SMatthias Springer   /// of the successor.
getSuccessorOperands() const1916923a315SMatthias Springer   OperandRange getSuccessorOperands() const {
1926923a315SMatthias Springer     return ::getSuccessorOperands(fromBlock, successorIndex);
1933b45fe2eSMarkus Böck   }
1943b45fe2eSMarkus Böck };
1953b45fe2eSMarkus Böck 
1963b45fe2eSMarkus Böck /// Structure containing the entry, exit and back edges of a cycle. A cycle is a
1973b45fe2eSMarkus Böck /// generalization of a loop that may have multiple entry edges. See also
1983b45fe2eSMarkus Böck /// https://llvm.org/docs/CycleTerminology.html.
1993b45fe2eSMarkus Böck struct CycleEdges {
2003b45fe2eSMarkus Böck   /// All edges from a block outside the cycle to a block inside the cycle.
2013b45fe2eSMarkus Böck   /// The targets of these edges are entry blocks.
2023b45fe2eSMarkus Böck   SmallVector<Edge> entryEdges;
2033b45fe2eSMarkus Böck   /// All edges from a block inside the cycle to a block outside the cycle.
2043b45fe2eSMarkus Böck   SmallVector<Edge> exitEdges;
2053b45fe2eSMarkus Böck   /// All edges from a block inside the cycle to an entry block.
2063b45fe2eSMarkus Böck   SmallVector<Edge> backEdges;
2073b45fe2eSMarkus Böck };
2083b45fe2eSMarkus Böck 
2093b45fe2eSMarkus Böck /// Class used to orchestrate creation of so-called edge multiplexers.
2103b45fe2eSMarkus Böck /// This class creates a new basic block and routes all inputs edges
2113b45fe2eSMarkus Böck /// to this basic block before branching to their original target.
2123b45fe2eSMarkus Böck /// The purpose of this transformation is to create single-entry,
2133b45fe2eSMarkus Böck /// single-exit regions.
2143b45fe2eSMarkus Böck class EdgeMultiplexer {
2153b45fe2eSMarkus Böck public:
2163b45fe2eSMarkus Böck   /// Creates a new edge multiplexer capable of redirecting all edges to one of
2173b45fe2eSMarkus Böck   /// the `entryBlocks`. This creates the multiplexer basic block with
2183b45fe2eSMarkus Böck   /// appropriate block arguments after the first entry block. `extraArgs`
2193b45fe2eSMarkus Böck   /// contains the types of possible extra block arguments passed to the
2203b45fe2eSMarkus Böck   /// multiplexer block that are added to the successor operands of every
2213b45fe2eSMarkus Böck   /// outgoing edge.
2223b45fe2eSMarkus Böck   ///
2233b45fe2eSMarkus Böck   /// NOTE: This does not yet redirect edges to branch to the
2243b45fe2eSMarkus Böck   /// multiplexer block nor code dispatching from the multiplexer code
2253b45fe2eSMarkus Böck   /// to the original successors.
2263b45fe2eSMarkus Böck   /// See `redirectEdge` and `createSwitch`.
create(Location loc,ArrayRef<Block * > entryBlocks,function_ref<Value (unsigned)> getSwitchValue,function_ref<Value (Type)> getUndefValue,TypeRange extraArgs={})2273b45fe2eSMarkus Böck   static EdgeMultiplexer create(Location loc, ArrayRef<Block *> entryBlocks,
2283b45fe2eSMarkus Böck                                 function_ref<Value(unsigned)> getSwitchValue,
2293b45fe2eSMarkus Böck                                 function_ref<Value(Type)> getUndefValue,
2303b45fe2eSMarkus Böck                                 TypeRange extraArgs = {}) {
2313b45fe2eSMarkus Böck     assert(!entryBlocks.empty() && "Require at least one entry block");
2323b45fe2eSMarkus Böck 
2333b45fe2eSMarkus Böck     auto *multiplexerBlock = new Block;
2343b45fe2eSMarkus Böck     multiplexerBlock->insertAfter(entryBlocks.front());
2353b45fe2eSMarkus Böck 
2363b45fe2eSMarkus Böck     // To implement the multiplexer block, we have to add the block arguments of
2373b45fe2eSMarkus Böck     // every distinct successor block to the multiplexer block. When redirecting
2383b45fe2eSMarkus Böck     // edges, block arguments designated for blocks that aren't branched to will
2393b45fe2eSMarkus Böck     // be assigned the `getUndefValue`. The amount of block arguments and their
2403b45fe2eSMarkus Böck     // offset is saved in the map for `redirectEdge` to transform the edges.
2413b45fe2eSMarkus Böck     llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
2423b45fe2eSMarkus Böck     for (Block *entryBlock : entryBlocks) {
2433b45fe2eSMarkus Böck       auto [iter, inserted] = blockArgMapping.insert(
2443b45fe2eSMarkus Böck           {entryBlock, multiplexerBlock->getNumArguments()});
2453b45fe2eSMarkus Böck       if (inserted)
2463b45fe2eSMarkus Böck         addBlockArgumentsFromOther(multiplexerBlock, entryBlock);
2473b45fe2eSMarkus Böck     }
2483b45fe2eSMarkus Böck 
2493b45fe2eSMarkus Böck     // If we have more than one successor, we have to additionally add a
2503b45fe2eSMarkus Böck     // discriminator value, denoting which successor to jump to.
2513b45fe2eSMarkus Böck     // When redirecting edges, an appropriate value will be passed using
2523b45fe2eSMarkus Böck     // `getSwitchValue`.
2533b45fe2eSMarkus Böck     Value discriminator;
2543b45fe2eSMarkus Böck     if (blockArgMapping.size() > 1)
2553b45fe2eSMarkus Böck       discriminator =
2563b45fe2eSMarkus Böck           multiplexerBlock->addArgument(getSwitchValue(0).getType(), loc);
2573b45fe2eSMarkus Böck 
2583b45fe2eSMarkus Böck     multiplexerBlock->addArguments(
2593b45fe2eSMarkus Böck         extraArgs, SmallVector<Location>(extraArgs.size(), loc));
2603b45fe2eSMarkus Böck 
2613b45fe2eSMarkus Böck     return EdgeMultiplexer(multiplexerBlock, getSwitchValue, getUndefValue,
2623b45fe2eSMarkus Böck                            std::move(blockArgMapping), discriminator);
2633b45fe2eSMarkus Böck   }
2643b45fe2eSMarkus Böck 
2653b45fe2eSMarkus Böck   /// Returns the created multiplexer block.
getMultiplexerBlock() const2663b45fe2eSMarkus Böck   Block *getMultiplexerBlock() const { return multiplexerBlock; }
2673b45fe2eSMarkus Böck 
2683b45fe2eSMarkus Böck   /// Redirects `edge` to branch to the multiplexer block before continuing to
2693b45fe2eSMarkus Böck   /// its original target. The edges successor must have originally been part
2703b45fe2eSMarkus Böck   /// of the entry blocks array passed to the `create` function. `extraArgs`
2713b45fe2eSMarkus Böck   /// must be used to pass along any additional values corresponding to
2723b45fe2eSMarkus Böck   /// `extraArgs` in `create`.
redirectEdge(Edge edge,ValueRange extraArgs={}) const2733b45fe2eSMarkus Böck   void redirectEdge(Edge edge, ValueRange extraArgs = {}) const {
2743b45fe2eSMarkus Böck     const auto *result = blockArgMapping.find(edge.getSuccessor());
2753b45fe2eSMarkus Böck     assert(result != blockArgMapping.end() &&
2763b45fe2eSMarkus Böck            "Edge was not originally passed to `create` method.");
2773b45fe2eSMarkus Böck 
2786923a315SMatthias Springer     MutableOperandRange successorOperands = edge.getMutableSuccessorOperands();
2793b45fe2eSMarkus Böck 
2803b45fe2eSMarkus Böck     // Extra arguments are always appended at the end of the block arguments.
2813b45fe2eSMarkus Böck     unsigned extraArgsBeginIndex =
2823b45fe2eSMarkus Böck         multiplexerBlock->getNumArguments() - extraArgs.size();
2833b45fe2eSMarkus Böck     // If a discriminator exists, it is right before the extra arguments.
2843b45fe2eSMarkus Böck     std::optional<unsigned> discriminatorIndex =
2853b45fe2eSMarkus Böck         discriminator ? extraArgsBeginIndex - 1 : std::optional<unsigned>{};
2863b45fe2eSMarkus Böck 
2873b45fe2eSMarkus Böck     SmallVector<Value> newSuccOperands(multiplexerBlock->getNumArguments());
2883b45fe2eSMarkus Böck     for (BlockArgument argument : multiplexerBlock->getArguments()) {
2893b45fe2eSMarkus Böck       unsigned index = argument.getArgNumber();
2903b45fe2eSMarkus Böck       if (index >= result->second &&
2913b45fe2eSMarkus Böck           index < result->second + edge.getSuccessor()->getNumArguments()) {
2923b45fe2eSMarkus Böck         // Original block arguments to the entry block.
2930f952cfeSMatthias Springer         newSuccOperands[index] =
2940f952cfeSMatthias Springer             successorOperands[index - result->second].get();
2953b45fe2eSMarkus Böck         continue;
2963b45fe2eSMarkus Böck       }
2973b45fe2eSMarkus Böck 
2983b45fe2eSMarkus Böck       // Discriminator value if it exists.
2993b45fe2eSMarkus Böck       if (index == discriminatorIndex) {
3003b45fe2eSMarkus Böck         newSuccOperands[index] =
3013b45fe2eSMarkus Böck             getSwitchValue(result - blockArgMapping.begin());
3023b45fe2eSMarkus Böck         continue;
3033b45fe2eSMarkus Böck       }
3043b45fe2eSMarkus Böck 
3053b45fe2eSMarkus Böck       // Followed by the extra arguments.
3063b45fe2eSMarkus Böck       if (index >= extraArgsBeginIndex) {
3073b45fe2eSMarkus Böck         newSuccOperands[index] = extraArgs[index - extraArgsBeginIndex];
3083b45fe2eSMarkus Böck         continue;
3093b45fe2eSMarkus Böck       }
3103b45fe2eSMarkus Böck 
3113b45fe2eSMarkus Böck       // Otherwise undef values for any unused block arguments used by other
3123b45fe2eSMarkus Böck       // entry blocks.
3133b45fe2eSMarkus Böck       newSuccOperands[index] = getUndefValue(argument.getType());
3143b45fe2eSMarkus Böck     }
3153b45fe2eSMarkus Böck 
3163b45fe2eSMarkus Böck     edge.setSuccessor(multiplexerBlock);
3173b45fe2eSMarkus Böck     successorOperands.assign(newSuccOperands);
3183b45fe2eSMarkus Böck   }
3193b45fe2eSMarkus Böck 
3203b45fe2eSMarkus Böck   /// Creates a switch op using `builder` which dispatches to the original
3213b45fe2eSMarkus Böck   /// successors of the edges passed to `create` minus the ones in `excluded`.
3223b45fe2eSMarkus Böck   /// The builder's insertion point has to be in a block dominated by the
323359ba0b0SMarkus Böck   /// multiplexer block. All edges to the multiplexer block must have already
324359ba0b0SMarkus Böck   /// been redirected using `redirectEdge`.
3253b45fe2eSMarkus Böck   void createSwitch(
3263b45fe2eSMarkus Böck       Location loc, OpBuilder &builder, CFGToSCFInterface &interface,
3273b45fe2eSMarkus Böck       const SmallPtrSetImpl<Block *> &excluded = SmallPtrSet<Block *, 1>{}) {
3283b45fe2eSMarkus Böck     // We create the switch by creating a case for all entries and then
3293b45fe2eSMarkus Böck     // splitting of the last entry as a default case.
3303b45fe2eSMarkus Böck 
3313b45fe2eSMarkus Böck     SmallVector<ValueRange> caseArguments;
3323b45fe2eSMarkus Böck     SmallVector<unsigned> caseValues;
3333b45fe2eSMarkus Böck     SmallVector<Block *> caseDestinations;
3343b45fe2eSMarkus Böck     for (auto &&[index, pair] : llvm::enumerate(blockArgMapping)) {
3353b45fe2eSMarkus Böck       auto &&[succ, offset] = pair;
3363b45fe2eSMarkus Böck       if (excluded.contains(succ))
3373b45fe2eSMarkus Böck         continue;
3383b45fe2eSMarkus Böck 
3393b45fe2eSMarkus Böck       caseValues.push_back(index);
3403b45fe2eSMarkus Böck       caseArguments.push_back(multiplexerBlock->getArguments().slice(
3413b45fe2eSMarkus Böck           offset, succ->getNumArguments()));
3423b45fe2eSMarkus Böck       caseDestinations.push_back(succ);
3433b45fe2eSMarkus Böck     }
3443b45fe2eSMarkus Böck 
3453b45fe2eSMarkus Böck     // If we don't have a discriminator due to only having one entry we have to
3463b45fe2eSMarkus Böck     // create a dummy flag for the switch.
3473b45fe2eSMarkus Böck     Value realDiscriminator = discriminator;
3483b45fe2eSMarkus Böck     if (!realDiscriminator || caseArguments.size() == 1)
3493b45fe2eSMarkus Böck       realDiscriminator = getSwitchValue(0);
3503b45fe2eSMarkus Böck 
3513b45fe2eSMarkus Böck     caseValues.pop_back();
3523b45fe2eSMarkus Böck     Block *defaultDest = caseDestinations.pop_back_val();
3533b45fe2eSMarkus Böck     ValueRange defaultArgs = caseArguments.pop_back_val();
3543b45fe2eSMarkus Böck 
355359ba0b0SMarkus Böck     assert(!builder.getInsertionBlock()->hasNoPredecessors() &&
356359ba0b0SMarkus Böck            "Edges need to be redirected prior to creating switch.");
3573b45fe2eSMarkus Böck     interface.createCFGSwitchOp(loc, builder, realDiscriminator, caseValues,
3583b45fe2eSMarkus Böck                                 caseDestinations, caseArguments, defaultDest,
3593b45fe2eSMarkus Böck                                 defaultArgs);
3603b45fe2eSMarkus Böck   }
3613b45fe2eSMarkus Böck 
3623b45fe2eSMarkus Böck private:
3633b45fe2eSMarkus Böck   /// Newly created multiplexer block.
3643b45fe2eSMarkus Böck   Block *multiplexerBlock;
3653b45fe2eSMarkus Böck   /// Callback used to create a constant suitable as flag for
3663b45fe2eSMarkus Böck   /// the interfaces `createCFGSwitchOp`.
3673b45fe2eSMarkus Böck   function_ref<Value(unsigned)> getSwitchValue;
3683b45fe2eSMarkus Böck   /// Callback used to create undefined values of a given type.
3693b45fe2eSMarkus Böck   function_ref<Value(Type)> getUndefValue;
3703b45fe2eSMarkus Böck 
3713b45fe2eSMarkus Böck   /// Mapping of the block arguments of an entry block to the corresponding
3723b45fe2eSMarkus Böck   /// block arguments in the multiplexer block. Block arguments of an entry
3733b45fe2eSMarkus Böck   /// block are simply appended ot the multiplexer block. This map simply
3743b45fe2eSMarkus Böck   /// contains the offset to the range in the multiplexer block.
3753b45fe2eSMarkus Böck   llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
3763b45fe2eSMarkus Böck   /// Discriminator value used in the multiplexer block to dispatch to the
3773b45fe2eSMarkus Böck   /// correct entry block. Null value if not required due to only having one
3783b45fe2eSMarkus Böck   /// entry block.
3793b45fe2eSMarkus Böck   Value discriminator;
3803b45fe2eSMarkus Böck 
EdgeMultiplexer(Block * multiplexerBlock,function_ref<Value (unsigned)> getSwitchValue,function_ref<Value (Type)> getUndefValue,llvm::SmallMapVector<Block *,unsigned,4> && entries,Value dispatchFlag)3813b45fe2eSMarkus Böck   EdgeMultiplexer(Block *multiplexerBlock,
3823b45fe2eSMarkus Böck                   function_ref<Value(unsigned)> getSwitchValue,
3833b45fe2eSMarkus Böck                   function_ref<Value(Type)> getUndefValue,
3843b45fe2eSMarkus Böck                   llvm::SmallMapVector<Block *, unsigned, 4> &&entries,
3853b45fe2eSMarkus Böck                   Value dispatchFlag)
3863b45fe2eSMarkus Böck       : multiplexerBlock(multiplexerBlock), getSwitchValue(getSwitchValue),
3873b45fe2eSMarkus Böck         getUndefValue(getUndefValue), blockArgMapping(std::move(entries)),
3883b45fe2eSMarkus Böck         discriminator(dispatchFlag) {}
3893b45fe2eSMarkus Böck };
3903b45fe2eSMarkus Böck 
3913b45fe2eSMarkus Böck /// Alternative implementation of DenseMapInfo<Operation*> using the operation
3923b45fe2eSMarkus Böck /// equivalence infrastructure to check whether two 'return-like' operations are
3933b45fe2eSMarkus Böck /// equivalent in the context of this transformation. This means that both
3943b45fe2eSMarkus Böck /// operations are of the same kind, have the same amount of operands and types
3953b45fe2eSMarkus Böck /// and the same attributes and properties. The operands themselves don't have
3963b45fe2eSMarkus Böck /// to be equivalent.
3973b45fe2eSMarkus Böck struct ReturnLikeOpEquivalence : public llvm::DenseMapInfo<Operation *> {
getHashValue__anoncfa425e90111::ReturnLikeOpEquivalence3983b45fe2eSMarkus Böck   static unsigned getHashValue(const Operation *opC) {
3993b45fe2eSMarkus Böck     return OperationEquivalence::computeHash(
4003b45fe2eSMarkus Böck         const_cast<Operation *>(opC),
4013b45fe2eSMarkus Böck         /*hashOperands=*/OperationEquivalence::ignoreHashValue,
4023b45fe2eSMarkus Böck         /*hashResults=*/OperationEquivalence::ignoreHashValue,
4033b45fe2eSMarkus Böck         OperationEquivalence::IgnoreLocations);
4043b45fe2eSMarkus Böck   }
4053b45fe2eSMarkus Böck 
isEqual__anoncfa425e90111::ReturnLikeOpEquivalence4063b45fe2eSMarkus Böck   static bool isEqual(const Operation *lhs, const Operation *rhs) {
4073b45fe2eSMarkus Böck     if (lhs == rhs)
4083b45fe2eSMarkus Böck       return true;
4093b45fe2eSMarkus Böck     if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
4103b45fe2eSMarkus Böck         rhs == getTombstoneKey() || rhs == getEmptyKey())
4113b45fe2eSMarkus Böck       return false;
4123b45fe2eSMarkus Böck     return OperationEquivalence::isEquivalentTo(
4133b45fe2eSMarkus Böck         const_cast<Operation *>(lhs), const_cast<Operation *>(rhs),
4143b45fe2eSMarkus Böck         OperationEquivalence::ignoreValueEquivalence, nullptr,
4153b45fe2eSMarkus Böck         OperationEquivalence::IgnoreLocations);
4163b45fe2eSMarkus Böck   }
4173b45fe2eSMarkus Böck };
4183b45fe2eSMarkus Böck 
4193b45fe2eSMarkus Böck /// Utility-class for transforming a region to only have one single block for
4203b45fe2eSMarkus Böck /// every return-like operation.
4213b45fe2eSMarkus Böck class ReturnLikeExitCombiner {
4223b45fe2eSMarkus Böck public:
ReturnLikeExitCombiner(Region & topLevelRegion,CFGToSCFInterface & interface)4233b45fe2eSMarkus Böck   ReturnLikeExitCombiner(Region &topLevelRegion, CFGToSCFInterface &interface)
4243b45fe2eSMarkus Böck       : topLevelRegion(topLevelRegion), interface(interface) {}
4253b45fe2eSMarkus Böck 
4263b45fe2eSMarkus Böck   /// Transforms `returnLikeOp` to a branch to the only block in the
4273b45fe2eSMarkus Böck   /// region with an instance of `returnLikeOp`s kind.
combineExit(Operation * returnLikeOp,function_ref<Value (unsigned)> getSwitchValue)4283b45fe2eSMarkus Böck   void combineExit(Operation *returnLikeOp,
4293b45fe2eSMarkus Böck                    function_ref<Value(unsigned)> getSwitchValue) {
4303b45fe2eSMarkus Böck     auto [iter, inserted] =
4313b45fe2eSMarkus Böck         returnLikeToCombinedExit.insert({returnLikeOp, nullptr});
4323b45fe2eSMarkus Böck     if (!inserted && iter->first == returnLikeOp)
4333b45fe2eSMarkus Böck       return;
4343b45fe2eSMarkus Böck 
4353b45fe2eSMarkus Böck     Block *exitBlock = iter->second;
4363b45fe2eSMarkus Böck     if (inserted) {
4373b45fe2eSMarkus Böck       exitBlock = new Block;
4383b45fe2eSMarkus Böck       iter->second = exitBlock;
4393b45fe2eSMarkus Böck       topLevelRegion.push_back(exitBlock);
4403b45fe2eSMarkus Böck       exitBlock->addArguments(
4413b45fe2eSMarkus Böck           returnLikeOp->getOperandTypes(),
4423b45fe2eSMarkus Böck           SmallVector<Location>(returnLikeOp->getNumOperands(),
4433b45fe2eSMarkus Böck                                 returnLikeOp->getLoc()));
4443b45fe2eSMarkus Böck     }
4453b45fe2eSMarkus Böck 
4463b45fe2eSMarkus Böck     auto builder = OpBuilder::atBlockTerminator(returnLikeOp->getBlock());
4473b45fe2eSMarkus Böck     interface.createSingleDestinationBranch(returnLikeOp->getLoc(), builder,
4483b45fe2eSMarkus Böck                                             getSwitchValue(0), exitBlock,
4493b45fe2eSMarkus Böck                                             returnLikeOp->getOperands());
4503b45fe2eSMarkus Böck 
4513b45fe2eSMarkus Böck     if (!inserted) {
4523b45fe2eSMarkus Böck       returnLikeOp->erase();
4533b45fe2eSMarkus Böck       return;
4543b45fe2eSMarkus Böck     }
4553b45fe2eSMarkus Böck 
4563b45fe2eSMarkus Böck     returnLikeOp->moveBefore(exitBlock, exitBlock->end());
4573b45fe2eSMarkus Böck     returnLikeOp->setOperands(exitBlock->getArguments());
4583b45fe2eSMarkus Böck   }
4593b45fe2eSMarkus Böck 
4603b45fe2eSMarkus Böck private:
4613b45fe2eSMarkus Böck   /// Mapping of return-like operation to block. All return-like operations
4623b45fe2eSMarkus Böck   /// of the same kind with the same attributes, properties and types are seen
4633b45fe2eSMarkus Böck   /// as equivalent. First occurrence seen is kept in the map.
4643b45fe2eSMarkus Böck   llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
4653b45fe2eSMarkus Böck       returnLikeToCombinedExit;
4663b45fe2eSMarkus Böck   Region &topLevelRegion;
4673b45fe2eSMarkus Böck   CFGToSCFInterface &interface;
4683b45fe2eSMarkus Böck };
4693b45fe2eSMarkus Böck 
4703b45fe2eSMarkus Böck } // namespace
4713b45fe2eSMarkus Böck 
4723b45fe2eSMarkus Böck /// Returns a range of all edges from `block` to each of its successors.
successorEdges(Block * block)4733b45fe2eSMarkus Böck static auto successorEdges(Block *block) {
4743b45fe2eSMarkus Böck   return llvm::map_range(llvm::seq(block->getNumSuccessors()),
4753b45fe2eSMarkus Böck                          [=](unsigned index) { return Edge(block, index); });
4763b45fe2eSMarkus Böck }
4773b45fe2eSMarkus Böck 
4783b45fe2eSMarkus Böck /// Calculates entry, exit and back edges of the given cycle.
4793b45fe2eSMarkus Böck static CycleEdges
calculateCycleEdges(const llvm::SmallSetVector<Block *,4> & cycles)4803b45fe2eSMarkus Böck calculateCycleEdges(const llvm::SmallSetVector<Block *, 4> &cycles) {
4813b45fe2eSMarkus Böck   CycleEdges result;
4823b45fe2eSMarkus Böck   SmallPtrSet<Block *, 8> entryBlocks;
4833b45fe2eSMarkus Böck 
4843b45fe2eSMarkus Böck   // First identify all exit and entry edges by checking whether any successors
4853b45fe2eSMarkus Böck   // or predecessors are from outside the cycles.
4863b45fe2eSMarkus Böck   for (Block *block : cycles) {
4873b45fe2eSMarkus Böck     for (auto pred = block->pred_begin(); pred != block->pred_end(); pred++) {
4883b45fe2eSMarkus Böck       if (cycles.contains(*pred))
4893b45fe2eSMarkus Böck         continue;
4903b45fe2eSMarkus Böck 
4913b45fe2eSMarkus Böck       result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
4923b45fe2eSMarkus Böck       entryBlocks.insert(block);
4933b45fe2eSMarkus Böck     }
4943b45fe2eSMarkus Böck 
4953b45fe2eSMarkus Böck     for (auto &&[succIndex, succ] : llvm::enumerate(block->getSuccessors())) {
4963b45fe2eSMarkus Böck       if (cycles.contains(succ))
4973b45fe2eSMarkus Böck         continue;
4983b45fe2eSMarkus Böck 
4993b45fe2eSMarkus Böck       result.exitEdges.emplace_back(block, succIndex);
5003b45fe2eSMarkus Böck     }
5013b45fe2eSMarkus Böck   }
5023b45fe2eSMarkus Böck 
5033b45fe2eSMarkus Böck   // With the entry blocks identified, find all the back edges.
5043b45fe2eSMarkus Böck   for (Block *block : cycles) {
5053b45fe2eSMarkus Böck     for (auto &&[succIndex, succ] : llvm::enumerate(block->getSuccessors())) {
5063b45fe2eSMarkus Böck       if (!entryBlocks.contains(succ))
5073b45fe2eSMarkus Böck         continue;
5083b45fe2eSMarkus Böck 
5093b45fe2eSMarkus Böck       result.backEdges.emplace_back(block, succIndex);
5103b45fe2eSMarkus Böck     }
5113b45fe2eSMarkus Böck   }
5123b45fe2eSMarkus Böck 
5133b45fe2eSMarkus Böck   return result;
5143b45fe2eSMarkus Böck }
5153b45fe2eSMarkus Böck 
5163b45fe2eSMarkus Böck /// Creates a single entry block out of multiple entry edges using an edge
5173b45fe2eSMarkus Böck /// multiplexer and returns it.
5183b45fe2eSMarkus Böck static EdgeMultiplexer
createSingleEntryBlock(Location loc,ArrayRef<Edge> entryEdges,function_ref<Value (unsigned)> getSwitchValue,function_ref<Value (Type)> getUndefValue,CFGToSCFInterface & interface)5193b45fe2eSMarkus Böck createSingleEntryBlock(Location loc, ArrayRef<Edge> entryEdges,
5203b45fe2eSMarkus Böck                        function_ref<Value(unsigned)> getSwitchValue,
5213b45fe2eSMarkus Böck                        function_ref<Value(Type)> getUndefValue,
5223b45fe2eSMarkus Böck                        CFGToSCFInterface &interface) {
5233b45fe2eSMarkus Böck   auto result = EdgeMultiplexer::create(
5243b45fe2eSMarkus Böck       loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
5253b45fe2eSMarkus Böck       getSwitchValue, getUndefValue);
5263b45fe2eSMarkus Böck 
527359ba0b0SMarkus Böck   // Redirect the edges prior to creating the switch op.
528359ba0b0SMarkus Böck   // We guarantee that predecessors are up to date.
5293b45fe2eSMarkus Böck   for (Edge edge : entryEdges)
5303b45fe2eSMarkus Böck     result.redirectEdge(edge);
5313b45fe2eSMarkus Böck 
532359ba0b0SMarkus Böck   auto builder = OpBuilder::atBlockBegin(result.getMultiplexerBlock());
533359ba0b0SMarkus Böck   result.createSwitch(loc, builder, interface);
534359ba0b0SMarkus Böck 
5353b45fe2eSMarkus Böck   return result;
5363b45fe2eSMarkus Böck }
5373b45fe2eSMarkus Böck 
5383b45fe2eSMarkus Böck namespace {
5393b45fe2eSMarkus Böck /// Special loop properties of a structured loop.
5403b45fe2eSMarkus Böck /// A structured loop is a loop satisfying all of the following:
5413b45fe2eSMarkus Böck /// * Has at most one entry, one exit and one back edge.
5423b45fe2eSMarkus Böck /// * The back edge originates from the same block as the exit edge.
5433b45fe2eSMarkus Böck struct StructuredLoopProperties {
5443b45fe2eSMarkus Böck   /// Block containing both the single exit edge and the single back edge.
5453b45fe2eSMarkus Böck   Block *latch;
5463b45fe2eSMarkus Böck   /// Loop condition of type equal to a value returned by `getSwitchValue`.
5473b45fe2eSMarkus Böck   Value condition;
5483b45fe2eSMarkus Böck   /// Exit block which is the only successor of the loop.
5493b45fe2eSMarkus Böck   Block *exitBlock;
5503b45fe2eSMarkus Böck };
5513b45fe2eSMarkus Böck } // namespace
5523b45fe2eSMarkus Böck 
5533b45fe2eSMarkus Böck /// Transforms a loop into a structured loop with only a single back edge and
5543b45fe2eSMarkus Böck /// exiting edge, originating from the same block.
createSingleExitingLatch(Location loc,ArrayRef<Edge> backEdges,ArrayRef<Edge> exitEdges,function_ref<Value (unsigned)> getSwitchValue,function_ref<Value (Type)> getUndefValue,CFGToSCFInterface & interface,ReturnLikeExitCombiner & exitCombiner)5553b45fe2eSMarkus Böck static FailureOr<StructuredLoopProperties> createSingleExitingLatch(
5563b45fe2eSMarkus Böck     Location loc, ArrayRef<Edge> backEdges, ArrayRef<Edge> exitEdges,
5573b45fe2eSMarkus Böck     function_ref<Value(unsigned)> getSwitchValue,
5583b45fe2eSMarkus Böck     function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
5593b45fe2eSMarkus Böck     ReturnLikeExitCombiner &exitCombiner) {
5603b45fe2eSMarkus Böck   assert(llvm::all_equal(
5613b45fe2eSMarkus Böck              llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
5623b45fe2eSMarkus Böck          "All repetition edges must lead to the single loop header");
5633b45fe2eSMarkus Böck 
5643b45fe2eSMarkus Böck   // First create the multiplexer block, which will be our latch, for all back
5653b45fe2eSMarkus Böck   // edges and exit edges. We pass an additional argument to the multiplexer
5663b45fe2eSMarkus Böck   // block which indicates whether the latch was reached from what was
5673b45fe2eSMarkus Böck   // originally a back edge or an exit block.
5683b45fe2eSMarkus Böck   // This is later used to branch using the new only back edge.
5693b45fe2eSMarkus Böck   SmallVector<Block *> successors;
5703b45fe2eSMarkus Böck   llvm::append_range(
5713b45fe2eSMarkus Böck       successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
5723b45fe2eSMarkus Böck   llvm::append_range(
5733b45fe2eSMarkus Böck       successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
5743b45fe2eSMarkus Böck   auto multiplexer =
5753b45fe2eSMarkus Böck       EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
5763b45fe2eSMarkus Böck                               /*extraArgs=*/getSwitchValue(0).getType());
5773b45fe2eSMarkus Böck 
5783b45fe2eSMarkus Böck   auto *latchBlock = multiplexer.getMultiplexerBlock();
5793b45fe2eSMarkus Böck 
5803b45fe2eSMarkus Böck   // Create a separate exit block that comes right after the latch.
5813b45fe2eSMarkus Böck   auto *exitBlock = new Block;
5823b45fe2eSMarkus Böck   exitBlock->insertAfter(latchBlock);
5833b45fe2eSMarkus Böck 
5843b45fe2eSMarkus Böck   // Since this is a loop, all back edges point to the same loop header.
5853b45fe2eSMarkus Böck   Block *loopHeader = backEdges.front().getSuccessor();
5863b45fe2eSMarkus Böck 
587359ba0b0SMarkus Böck   // Redirect the edges prior to creating the switch op.
588359ba0b0SMarkus Böck   // We guarantee that predecessors are up to date.
589359ba0b0SMarkus Böck 
590359ba0b0SMarkus Böck   // Redirecting back edges with `shouldRepeat` as 1.
591359ba0b0SMarkus Böck   for (Edge backEdge : backEdges)
592359ba0b0SMarkus Böck     multiplexer.redirectEdge(backEdge, /*extraArgs=*/getSwitchValue(1));
593359ba0b0SMarkus Böck 
594359ba0b0SMarkus Böck   // Redirecting exits edges with `shouldRepeat` as 0.
595359ba0b0SMarkus Böck   for (Edge exitEdge : exitEdges)
596359ba0b0SMarkus Böck     multiplexer.redirectEdge(exitEdge, /*extraArgs=*/getSwitchValue(0));
597359ba0b0SMarkus Böck 
5983b45fe2eSMarkus Böck   // Create the new only back edge to the loop header. Branch to the
5993b45fe2eSMarkus Böck   // exit block otherwise.
6003b45fe2eSMarkus Böck   Value shouldRepeat = latchBlock->getArguments().back();
6013b45fe2eSMarkus Böck   {
6023b45fe2eSMarkus Böck     auto builder = OpBuilder::atBlockBegin(latchBlock);
6033b45fe2eSMarkus Böck     interface.createConditionalBranch(
604cdaaa4d7SChristian Ulmann         loc, builder, shouldRepeat, loopHeader,
6053b45fe2eSMarkus Böck         latchBlock->getArguments().take_front(loopHeader->getNumArguments()),
6063b45fe2eSMarkus Böck         /*falseDest=*/exitBlock,
6073b45fe2eSMarkus Böck         /*falseArgs=*/{});
6083b45fe2eSMarkus Böck   }
6093b45fe2eSMarkus Böck 
6103b45fe2eSMarkus Böck   {
6113b45fe2eSMarkus Böck     auto builder = OpBuilder::atBlockBegin(exitBlock);
6123b45fe2eSMarkus Böck     if (!exitEdges.empty()) {
6133b45fe2eSMarkus Böck       // Create the switch dispatching to what were originally the multiple exit
6143b45fe2eSMarkus Böck       // blocks. The loop header has to explicitly be excluded in the below
6153b45fe2eSMarkus Böck       // switch as we would otherwise be creating a new loop again. All back
6163b45fe2eSMarkus Böck       // edges leading to the loop header have already been handled in the
6173b45fe2eSMarkus Böck       // switch above. The remaining edges can only jump to blocks outside the
6183b45fe2eSMarkus Böck       // loop.
6193b45fe2eSMarkus Böck 
6203b45fe2eSMarkus Böck       SmallPtrSet<Block *, 1> excluded = {loopHeader};
6213b45fe2eSMarkus Böck       multiplexer.createSwitch(loc, builder, interface, excluded);
6223b45fe2eSMarkus Böck     } else {
6233b45fe2eSMarkus Böck       // A loop without an exit edge is a statically known infinite loop.
6243b45fe2eSMarkus Böck       // Since structured control flow ops are not terminator ops, the caller
6253b45fe2eSMarkus Böck       // has to create a fitting return-like unreachable terminator operation.
6263b45fe2eSMarkus Böck       FailureOr<Operation *> terminator = interface.createUnreachableTerminator(
6273b45fe2eSMarkus Böck           loc, builder, *latchBlock->getParent());
6283b45fe2eSMarkus Böck       if (failed(terminator))
6293b45fe2eSMarkus Böck         return failure();
6303b45fe2eSMarkus Böck       // Transform the just created transform operation in the case that an
6313b45fe2eSMarkus Böck       // occurrence of it existed in input IR.
6323b45fe2eSMarkus Böck       exitCombiner.combineExit(*terminator, getSwitchValue);
6333b45fe2eSMarkus Böck     }
6343b45fe2eSMarkus Böck   }
6353b45fe2eSMarkus Böck 
6363b45fe2eSMarkus Böck   return StructuredLoopProperties{latchBlock, /*condition=*/shouldRepeat,
6373b45fe2eSMarkus Böck                                   exitBlock};
6383b45fe2eSMarkus Böck }
6393b45fe2eSMarkus Böck 
6403b45fe2eSMarkus Böck /// Transforms a structured loop into a loop in reduce form.
6413b45fe2eSMarkus Böck ///
6423b45fe2eSMarkus Böck /// Reduce form is defined as a structured loop where:
6433b45fe2eSMarkus Böck /// (0) No values defined within the loop body are used outside the loop body.
6443b45fe2eSMarkus Böck /// (1) The block arguments and successor operands of the exit block are equal
6453b45fe2eSMarkus Böck ///     to the block arguments of the loop header and the successor operands
6463b45fe2eSMarkus Böck ///     of the back edge.
6473b45fe2eSMarkus Böck ///
6483b45fe2eSMarkus Böck /// This is required for many structured control flow ops as they tend
6493b45fe2eSMarkus Böck /// to not have separate "loop result arguments" and "loop iteration arguments"
6503b45fe2eSMarkus Böck /// at the end of the block. Rather, the "loop iteration arguments" from the
6513b45fe2eSMarkus Böck /// last iteration are the result of the loop.
6523b45fe2eSMarkus Böck ///
6533b45fe2eSMarkus Böck /// Note that the requirement of (0) is shared with LCSSA form in LLVM. However,
6543b45fe2eSMarkus Böck /// due to this being a structured loop instead of a general loop, we do not
6553b45fe2eSMarkus Böck /// require complicated dominance algorithms nor SSA updating making this
6563b45fe2eSMarkus Böck /// implementation easier than creating a generic LCSSA transformation pass.
6573b45fe2eSMarkus Böck static SmallVector<Value>
transformToReduceLoop(Block * loopHeader,Block * exitBlock,const llvm::SmallSetVector<Block *,4> & loopBlocks,function_ref<Value (Type)> getUndefValue,DominanceInfo & dominanceInfo)6583b45fe2eSMarkus Böck transformToReduceLoop(Block *loopHeader, Block *exitBlock,
6593b45fe2eSMarkus Böck                       const llvm::SmallSetVector<Block *, 4> &loopBlocks,
6603b45fe2eSMarkus Böck                       function_ref<Value(Type)> getUndefValue,
6613b45fe2eSMarkus Böck                       DominanceInfo &dominanceInfo) {
6623b45fe2eSMarkus Böck   Block *latch = exitBlock->getSinglePredecessor();
6633b45fe2eSMarkus Böck   assert(latch &&
6643b45fe2eSMarkus Böck          "Exit block must have only latch as predecessor at this point");
6653b45fe2eSMarkus Böck   assert(exitBlock->getNumArguments() == 0 &&
6663b45fe2eSMarkus Böck          "Exit block mustn't have any block arguments at this point");
6673b45fe2eSMarkus Böck 
6683b45fe2eSMarkus Böck   unsigned loopHeaderIndex = 0;
6693b45fe2eSMarkus Böck   unsigned exitBlockIndex = 1;
6703b45fe2eSMarkus Böck   if (latch->getSuccessor(loopHeaderIndex) != loopHeader)
6713b45fe2eSMarkus Böck     std::swap(loopHeaderIndex, exitBlockIndex);
6723b45fe2eSMarkus Böck 
6733b45fe2eSMarkus Böck   assert(latch->getSuccessor(loopHeaderIndex) == loopHeader);
6743b45fe2eSMarkus Böck   assert(latch->getSuccessor(exitBlockIndex) == exitBlock);
6753b45fe2eSMarkus Böck 
6763b45fe2eSMarkus Böck   MutableOperandRange exitBlockSuccessorOperands =
6773b45fe2eSMarkus Böck       getMutableSuccessorOperands(latch, exitBlockIndex);
6783b45fe2eSMarkus Böck   // Save the values as a vector, not a `MutableOperandRange` as the latter gets
6793b45fe2eSMarkus Böck   // invalidated when mutating the operands through a different
6803b45fe2eSMarkus Böck   // `MutableOperandRange` of the same operation.
6813b45fe2eSMarkus Böck   SmallVector<Value> loopHeaderSuccessorOperands =
6826923a315SMatthias Springer       llvm::to_vector(getSuccessorOperands(latch, loopHeaderIndex));
6833b45fe2eSMarkus Böck 
6843b45fe2eSMarkus Böck   // Add all values used in the next iteration to the exit block. Replace
6853b45fe2eSMarkus Böck   // any uses that are outside the loop with the newly created exit block.
6863b45fe2eSMarkus Böck   for (Value arg : loopHeaderSuccessorOperands) {
6873b45fe2eSMarkus Böck     BlockArgument exitArg = exitBlock->addArgument(arg.getType(), arg.getLoc());
6883b45fe2eSMarkus Böck     exitBlockSuccessorOperands.append(arg);
6893b45fe2eSMarkus Böck     arg.replaceUsesWithIf(exitArg, [&](OpOperand &use) {
6903b45fe2eSMarkus Böck       return !loopBlocks.contains(use.getOwner()->getBlock());
6913b45fe2eSMarkus Böck     });
6923b45fe2eSMarkus Böck   }
6933b45fe2eSMarkus Böck 
6943b45fe2eSMarkus Böck   // Loop below might add block arguments to the latch and loop header.
6953b45fe2eSMarkus Böck   // Save the block arguments prior to the loop to not process these.
6963b45fe2eSMarkus Böck   SmallVector<BlockArgument> latchBlockArgumentsPrior =
6973b45fe2eSMarkus Böck       llvm::to_vector(latch->getArguments());
6983b45fe2eSMarkus Böck   SmallVector<BlockArgument> loopHeaderArgumentsPrior =
6993b45fe2eSMarkus Böck       llvm::to_vector(loopHeader->getArguments());
7003b45fe2eSMarkus Böck 
7013b45fe2eSMarkus Böck   // Go over all values defined within the loop body. If any of them are used
7023b45fe2eSMarkus Böck   // outside the loop body, create a block argument on the exit block and loop
7033b45fe2eSMarkus Böck   // header and replace the outside uses with the exit block argument.
7043b45fe2eSMarkus Böck   // The loop header block argument is added to satisfy requirement (1) in the
7053b45fe2eSMarkus Böck   // reduce form condition.
7063b45fe2eSMarkus Böck   for (Block *loopBlock : loopBlocks) {
7073b45fe2eSMarkus Böck     // Cache dominance queries for loopBlock.
7083b45fe2eSMarkus Böck     // There are likely to be many duplicate queries as there can be many value
7093b45fe2eSMarkus Böck     // definitions within a block.
7103b45fe2eSMarkus Böck     llvm::SmallDenseMap<Block *, bool> dominanceCache;
7113b45fe2eSMarkus Böck     // Returns true if `loopBlock` dominates `block`.
7123b45fe2eSMarkus Böck     auto loopBlockDominates = [&](Block *block) {
7133b45fe2eSMarkus Böck       auto [iter, inserted] = dominanceCache.insert({block, false});
7143b45fe2eSMarkus Böck       if (!inserted)
7153b45fe2eSMarkus Böck         return iter->second;
7163b45fe2eSMarkus Böck       iter->second = dominanceInfo.dominates(loopBlock, block);
7173b45fe2eSMarkus Böck       return iter->second;
7183b45fe2eSMarkus Böck     };
7193b45fe2eSMarkus Böck 
7203b45fe2eSMarkus Böck     auto checkValue = [&](Value value) {
7213b45fe2eSMarkus Böck       Value blockArgument;
7223b45fe2eSMarkus Böck       for (OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
72330fe8762SMarkus Böck         // Go through all the parent blocks and find the one part of the region
72430fe8762SMarkus Böck         // of the loop. If the block is part of the loop, then the value does
72530fe8762SMarkus Böck         // not escape the loop through this use.
72630fe8762SMarkus Böck         Block *currBlock = use.getOwner()->getBlock();
72730fe8762SMarkus Böck         while (currBlock && currBlock->getParent() != loopHeader->getParent())
72830fe8762SMarkus Böck           currBlock = currBlock->getParentOp()->getBlock();
72930fe8762SMarkus Böck         if (loopBlocks.contains(currBlock))
7303b45fe2eSMarkus Böck           continue;
7313b45fe2eSMarkus Böck 
7323b45fe2eSMarkus Böck         // Block argument is only created the first time it is required.
7333b45fe2eSMarkus Böck         if (!blockArgument) {
7343b45fe2eSMarkus Böck           blockArgument =
7353b45fe2eSMarkus Böck               exitBlock->addArgument(value.getType(), value.getLoc());
7363b45fe2eSMarkus Böck           loopHeader->addArgument(value.getType(), value.getLoc());
7373b45fe2eSMarkus Böck 
7383b45fe2eSMarkus Böck           // `value` might be defined in a block that does not dominate `latch`
7393b45fe2eSMarkus Böck           // but previously dominated an exit block with a use.
7403b45fe2eSMarkus Böck           // In this case, add a block argument to the latch and go through all
7413b45fe2eSMarkus Böck           // predecessors. If the value dominates the predecessor, pass the
7423b45fe2eSMarkus Böck           // value as a successor operand, otherwise pass undef.
7433b45fe2eSMarkus Böck           // The above is unnecessary if the value is a block argument of the
7443b45fe2eSMarkus Böck           // latch or if `value` dominates all predecessors.
7453b45fe2eSMarkus Böck           Value argument = value;
7463b45fe2eSMarkus Böck           if (value.getParentBlock() != latch &&
7473b45fe2eSMarkus Böck               llvm::any_of(latch->getPredecessors(), [&](Block *pred) {
7483b45fe2eSMarkus Böck                 return !loopBlockDominates(pred);
7493b45fe2eSMarkus Böck               })) {
7503b45fe2eSMarkus Böck             argument = latch->addArgument(value.getType(), value.getLoc());
7513b45fe2eSMarkus Böck             for (auto iter = latch->pred_begin(); iter != latch->pred_end();
7523b45fe2eSMarkus Böck                  ++iter) {
7533b45fe2eSMarkus Böck               Value succOperand = value;
7543b45fe2eSMarkus Böck               if (!loopBlockDominates(*iter))
7553b45fe2eSMarkus Böck                 succOperand = getUndefValue(value.getType());
7563b45fe2eSMarkus Böck 
7573b45fe2eSMarkus Böck               getMutableSuccessorOperands(*iter, iter.getSuccessorIndex())
7583b45fe2eSMarkus Böck                   .append(succOperand);
7593b45fe2eSMarkus Böck             }
7603b45fe2eSMarkus Böck           }
7613b45fe2eSMarkus Böck 
7623b45fe2eSMarkus Böck           loopHeaderSuccessorOperands.push_back(argument);
7633b45fe2eSMarkus Böck           for (Edge edge : successorEdges(latch))
7646923a315SMatthias Springer             edge.getMutableSuccessorOperands().append(argument);
7653b45fe2eSMarkus Böck         }
7663b45fe2eSMarkus Böck 
7673b45fe2eSMarkus Böck         use.set(blockArgument);
7683b45fe2eSMarkus Böck       }
7693b45fe2eSMarkus Böck     };
7703b45fe2eSMarkus Böck 
7713b45fe2eSMarkus Böck     if (loopBlock == latch)
7723b45fe2eSMarkus Böck       llvm::for_each(latchBlockArgumentsPrior, checkValue);
7733b45fe2eSMarkus Böck     else if (loopBlock == loopHeader)
7743b45fe2eSMarkus Böck       llvm::for_each(loopHeaderArgumentsPrior, checkValue);
7753b45fe2eSMarkus Böck     else
7763b45fe2eSMarkus Böck       llvm::for_each(loopBlock->getArguments(), checkValue);
7773b45fe2eSMarkus Böck 
7783b45fe2eSMarkus Böck     for (Operation &op : *loopBlock)
7793b45fe2eSMarkus Böck       llvm::for_each(op.getResults(), checkValue);
7803b45fe2eSMarkus Böck   }
7813b45fe2eSMarkus Böck 
7823b45fe2eSMarkus Böck   // New block arguments may have been added to the loop header.
7833b45fe2eSMarkus Böck   // Adjust the entry edges to pass undef values to these.
7843b45fe2eSMarkus Böck   for (auto iter = loopHeader->pred_begin(); iter != loopHeader->pred_end();
7853b45fe2eSMarkus Böck        ++iter) {
7863b45fe2eSMarkus Böck     // Latch successor arguments have already been handled.
7873b45fe2eSMarkus Böck     if (*iter == latch)
7883b45fe2eSMarkus Böck       continue;
7893b45fe2eSMarkus Böck 
7903b45fe2eSMarkus Böck     MutableOperandRange succOps =
7913b45fe2eSMarkus Böck         getMutableSuccessorOperands(*iter, iter.getSuccessorIndex());
7923b45fe2eSMarkus Böck     succOps.append(llvm::map_to_vector(
7933b45fe2eSMarkus Böck         loopHeader->getArguments().drop_front(succOps.size()),
7943b45fe2eSMarkus Böck         [&](BlockArgument arg) { return getUndefValue(arg.getType()); }));
7953b45fe2eSMarkus Böck   }
7963b45fe2eSMarkus Böck 
7973b45fe2eSMarkus Böck   return loopHeaderSuccessorOperands;
7983b45fe2eSMarkus Böck }
7993b45fe2eSMarkus Böck 
8003b45fe2eSMarkus Böck /// Transforms all outer-most cycles in the region with the region entry
8013b45fe2eSMarkus Böck /// `regionEntry` into structured loops. Returns the entry blocks of any newly
8023b45fe2eSMarkus Böck /// created regions potentially requiring further transformations.
transformCyclesToSCFLoops(Block * regionEntry,function_ref<Value (unsigned)> getSwitchValue,function_ref<Value (Type)> getUndefValue,CFGToSCFInterface & interface,DominanceInfo & dominanceInfo,ReturnLikeExitCombiner & exitCombiner)8033b45fe2eSMarkus Böck static FailureOr<SmallVector<Block *>> transformCyclesToSCFLoops(
8043b45fe2eSMarkus Böck     Block *regionEntry, function_ref<Value(unsigned)> getSwitchValue,
8053b45fe2eSMarkus Böck     function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
8063b45fe2eSMarkus Böck     DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
8073b45fe2eSMarkus Böck   SmallVector<Block *> newSubRegions;
8083b45fe2eSMarkus Böck   auto scc = llvm::scc_begin(regionEntry);
8093b45fe2eSMarkus Böck   while (!scc.isAtEnd()) {
8103b45fe2eSMarkus Böck     if (!scc.hasCycle()) {
8113b45fe2eSMarkus Böck       ++scc;
8123b45fe2eSMarkus Böck       continue;
8133b45fe2eSMarkus Böck     }
8143b45fe2eSMarkus Böck 
8153b45fe2eSMarkus Böck     // Save the set and increment the SCC iterator early to avoid our
8163b45fe2eSMarkus Böck     // modifications breaking the SCC iterator.
8173b45fe2eSMarkus Böck     llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
8183b45fe2eSMarkus Böck     ++scc;
8193b45fe2eSMarkus Böck 
8203b45fe2eSMarkus Böck     CycleEdges edges = calculateCycleEdges(cycleBlockSet);
8213b45fe2eSMarkus Böck     Block *loopHeader = edges.entryEdges.front().getSuccessor();
8223b45fe2eSMarkus Böck     // First turn the cycle into a loop by creating a single entry block if
8233b45fe2eSMarkus Böck     // needed.
8243b45fe2eSMarkus Böck     if (edges.entryEdges.size() > 1) {
825359ba0b0SMarkus Böck       SmallVector<Edge> edgesToEntryBlocks;
826359ba0b0SMarkus Böck       llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
827359ba0b0SMarkus Böck       llvm::append_range(edgesToEntryBlocks, edges.backEdges);
8283b45fe2eSMarkus Böck 
829359ba0b0SMarkus Böck       EdgeMultiplexer multiplexer = createSingleEntryBlock(
830359ba0b0SMarkus Böck           loopHeader->getTerminator()->getLoc(), edgesToEntryBlocks,
831359ba0b0SMarkus Böck           getSwitchValue, getUndefValue, interface);
8323b45fe2eSMarkus Böck 
8333b45fe2eSMarkus Böck       loopHeader = multiplexer.getMultiplexerBlock();
8343b45fe2eSMarkus Böck     }
8353b45fe2eSMarkus Böck     cycleBlockSet.insert(loopHeader);
8363b45fe2eSMarkus Böck 
8373b45fe2eSMarkus Böck     // Then turn it into a structured loop by creating a single latch.
8383b45fe2eSMarkus Böck     FailureOr<StructuredLoopProperties> loopProperties =
8393b45fe2eSMarkus Böck         createSingleExitingLatch(
8403b45fe2eSMarkus Böck             edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
8413b45fe2eSMarkus Böck             edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
8423b45fe2eSMarkus Böck             interface, exitCombiner);
8433b45fe2eSMarkus Böck     if (failed(loopProperties))
8443b45fe2eSMarkus Böck       return failure();
8453b45fe2eSMarkus Böck 
8463b45fe2eSMarkus Böck     Block *latchBlock = loopProperties->latch;
8473b45fe2eSMarkus Böck     Block *exitBlock = loopProperties->exitBlock;
8483b45fe2eSMarkus Böck     cycleBlockSet.insert(latchBlock);
8493b45fe2eSMarkus Böck     cycleBlockSet.insert(loopHeader);
8503b45fe2eSMarkus Böck 
8513b45fe2eSMarkus Böck     // Finally, turn it into reduce form.
8523b45fe2eSMarkus Böck     SmallVector<Value> iterationValues = transformToReduceLoop(
8533b45fe2eSMarkus Böck         loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
8543b45fe2eSMarkus Böck 
8553b45fe2eSMarkus Böck     // Create a block acting as replacement for the loop header and insert
8563b45fe2eSMarkus Böck     // the structured loop into it.
8573b45fe2eSMarkus Böck     auto *newLoopParentBlock = new Block;
8583b45fe2eSMarkus Böck     newLoopParentBlock->insertBefore(loopHeader);
8593b45fe2eSMarkus Böck     addBlockArgumentsFromOther(newLoopParentBlock, loopHeader);
8603b45fe2eSMarkus Böck 
8613b45fe2eSMarkus Böck     Region::BlockListType &blocks = regionEntry->getParent()->getBlocks();
8623b45fe2eSMarkus Böck     Region loopBody;
8633b45fe2eSMarkus Böck     // Make sure the loop header is the entry block.
8643b45fe2eSMarkus Böck     loopBody.push_back(blocks.remove(loopHeader));
8653b45fe2eSMarkus Böck     for (Block *block : cycleBlockSet)
8663b45fe2eSMarkus Böck       if (block != latchBlock && block != loopHeader)
8673b45fe2eSMarkus Böck         loopBody.push_back(blocks.remove(block));
8683b45fe2eSMarkus Böck     // And the latch is the last block.
8693b45fe2eSMarkus Böck     loopBody.push_back(blocks.remove(latchBlock));
8703b45fe2eSMarkus Böck 
8713b45fe2eSMarkus Böck     Operation *oldTerminator = latchBlock->getTerminator();
8723b45fe2eSMarkus Böck     oldTerminator->remove();
8733b45fe2eSMarkus Böck 
8743b45fe2eSMarkus Böck     auto builder = OpBuilder::atBlockBegin(newLoopParentBlock);
8753b45fe2eSMarkus Böck     FailureOr<Operation *> structuredLoopOp =
8763b45fe2eSMarkus Böck         interface.createStructuredDoWhileLoopOp(
8773b45fe2eSMarkus Böck             builder, oldTerminator, newLoopParentBlock->getArguments(),
8783b45fe2eSMarkus Böck             loopProperties->condition, iterationValues, std::move(loopBody));
8793b45fe2eSMarkus Böck     if (failed(structuredLoopOp))
8803b45fe2eSMarkus Böck       return failure();
8813b45fe2eSMarkus Böck     oldTerminator->erase();
8823b45fe2eSMarkus Böck 
8833b45fe2eSMarkus Böck     newSubRegions.push_back(loopHeader);
8843b45fe2eSMarkus Böck 
8853b45fe2eSMarkus Böck     for (auto &&[oldValue, newValue] : llvm::zip(
8863b45fe2eSMarkus Böck              exitBlock->getArguments(), (*structuredLoopOp)->getResults()))
8873b45fe2eSMarkus Böck       oldValue.replaceAllUsesWith(newValue);
8883b45fe2eSMarkus Böck 
8893b45fe2eSMarkus Böck     loopHeader->replaceAllUsesWith(newLoopParentBlock);
8903b45fe2eSMarkus Böck     // Merge the exit block right after the loop operation.
8913b45fe2eSMarkus Böck     newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
8923b45fe2eSMarkus Böck                                                exitBlock->getOperations());
8933b45fe2eSMarkus Böck     exitBlock->erase();
8943b45fe2eSMarkus Böck   }
8953b45fe2eSMarkus Böck   return newSubRegions;
8963b45fe2eSMarkus Böck }
8973b45fe2eSMarkus Böck 
8983b45fe2eSMarkus Böck /// Makes sure the branch region only has a single exit. This is required by the
8993b45fe2eSMarkus Böck /// recursive part of the algorithm, as it expects the CFG to be single-entry
9003b45fe2eSMarkus Böck /// and single-exit. This is done by simply creating an empty block if there
9013b45fe2eSMarkus Böck /// is more than one block with an edge to the continuation block. All blocks
9023b45fe2eSMarkus Böck /// with edges to the continuation are then redirected to this block. A region
9033b45fe2eSMarkus Böck /// terminator is later placed into the block.
createSingleExitBranchRegion(ArrayRef<Block * > branchRegion,Block * continuation,SmallVectorImpl<std::pair<Block *,SmallVector<Value>>> & createdEmptyBlocks,Region & conditionalRegion)9043b45fe2eSMarkus Böck static void createSingleExitBranchRegion(
9053b45fe2eSMarkus Böck     ArrayRef<Block *> branchRegion, Block *continuation,
9063b45fe2eSMarkus Böck     SmallVectorImpl<std::pair<Block *, SmallVector<Value>>> &createdEmptyBlocks,
9073b45fe2eSMarkus Böck     Region &conditionalRegion) {
9083b45fe2eSMarkus Böck   Block *singleExitBlock = nullptr;
9093b45fe2eSMarkus Böck   std::optional<Edge> previousEdgeToContinuation;
9103b45fe2eSMarkus Böck   Region::BlockListType &parentBlockList =
9113b45fe2eSMarkus Böck       branchRegion.front()->getParent()->getBlocks();
9123b45fe2eSMarkus Böck   for (Block *block : branchRegion) {
9133b45fe2eSMarkus Böck     for (Edge edge : successorEdges(block)) {
9143b45fe2eSMarkus Böck       if (edge.getSuccessor() != continuation)
9153b45fe2eSMarkus Böck         continue;
9163b45fe2eSMarkus Böck 
9173b45fe2eSMarkus Böck       if (!previousEdgeToContinuation) {
9183b45fe2eSMarkus Böck         previousEdgeToContinuation = edge;
9193b45fe2eSMarkus Böck         continue;
9203b45fe2eSMarkus Böck       }
9213b45fe2eSMarkus Böck 
9223b45fe2eSMarkus Böck       // If this is not the first edge to the continuation we create the
9233b45fe2eSMarkus Böck       // single exit block and redirect the edges.
9243b45fe2eSMarkus Böck       if (!singleExitBlock) {
9253b45fe2eSMarkus Böck         singleExitBlock = new Block;
9263b45fe2eSMarkus Böck         addBlockArgumentsFromOther(singleExitBlock, continuation);
9273b45fe2eSMarkus Böck         previousEdgeToContinuation->setSuccessor(singleExitBlock);
9283b45fe2eSMarkus Böck         createdEmptyBlocks.emplace_back(singleExitBlock,
9293b45fe2eSMarkus Böck                                         singleExitBlock->getArguments());
9303b45fe2eSMarkus Böck       }
9313b45fe2eSMarkus Böck 
9323b45fe2eSMarkus Böck       edge.setSuccessor(singleExitBlock);
9333b45fe2eSMarkus Böck     }
9343b45fe2eSMarkus Böck 
9353b45fe2eSMarkus Böck     conditionalRegion.push_back(parentBlockList.remove(block));
9363b45fe2eSMarkus Böck   }
9373b45fe2eSMarkus Böck 
9383b45fe2eSMarkus Böck   if (singleExitBlock)
9393b45fe2eSMarkus Böck     conditionalRegion.push_back(singleExitBlock);
9403b45fe2eSMarkus Böck }
9413b45fe2eSMarkus Böck 
9423b45fe2eSMarkus Böck /// Returns true if this block is an exit block of the region.
isRegionExitBlock(Block * block)9433b45fe2eSMarkus Böck static bool isRegionExitBlock(Block *block) {
9443b45fe2eSMarkus Böck   return block->getNumSuccessors() == 0;
9453b45fe2eSMarkus Böck }
9463b45fe2eSMarkus Böck 
9473b45fe2eSMarkus Böck /// Transforms the first occurrence of conditional control flow in `regionEntry`
9483b45fe2eSMarkus Böck /// into conditionally executed regions. Returns the entry block of the created
9493b45fe2eSMarkus Böck /// regions and the region after the conditional control flow.
transformToStructuredCFBranches(Block * regionEntry,function_ref<Value (unsigned)> getSwitchValue,function_ref<Value (Type)> getUndefValue,CFGToSCFInterface & interface,DominanceInfo & dominanceInfo)9503b45fe2eSMarkus Böck static FailureOr<SmallVector<Block *>> transformToStructuredCFBranches(
9513b45fe2eSMarkus Böck     Block *regionEntry, function_ref<Value(unsigned)> getSwitchValue,
9523b45fe2eSMarkus Böck     function_ref<Value(Type)> getUndefValue, CFGToSCFInterface &interface,
9533b45fe2eSMarkus Böck     DominanceInfo &dominanceInfo) {
9543b45fe2eSMarkus Böck   // Trivial region.
9553b45fe2eSMarkus Böck   if (regionEntry->getNumSuccessors() == 0)
9563b45fe2eSMarkus Böck     return SmallVector<Block *>{};
9573b45fe2eSMarkus Böck 
9583b45fe2eSMarkus Böck   if (regionEntry->getNumSuccessors() == 1) {
9593b45fe2eSMarkus Böck     // Single successor we can just splice together.
9603b45fe2eSMarkus Böck     Block *successor = regionEntry->getSuccessor(0);
9616923a315SMatthias Springer     for (auto &&[oldValue, newValue] : llvm::zip(
9626923a315SMatthias Springer              successor->getArguments(), getSuccessorOperands(regionEntry, 0)))
9633b45fe2eSMarkus Böck       oldValue.replaceAllUsesWith(newValue);
9643b45fe2eSMarkus Böck     regionEntry->getTerminator()->erase();
9653b45fe2eSMarkus Böck 
9663b45fe2eSMarkus Böck     regionEntry->getOperations().splice(regionEntry->end(),
9673b45fe2eSMarkus Böck                                         successor->getOperations());
9683b45fe2eSMarkus Böck     successor->erase();
9693b45fe2eSMarkus Böck     return SmallVector<Block *>{regionEntry};
9703b45fe2eSMarkus Böck   }
9713b45fe2eSMarkus Böck 
9723b45fe2eSMarkus Böck   // Split the CFG into "#numSuccessor + 1" regions.
9733b45fe2eSMarkus Böck   // For every edge to a successor, the blocks it solely dominates are
9743b45fe2eSMarkus Böck   // determined and become the region following that edge.
9753b45fe2eSMarkus Böck   // The last region is the continuation that follows the branch regions.
9763b45fe2eSMarkus Böck   SmallPtrSet<Block *, 8> notContinuation;
9773b45fe2eSMarkus Böck   notContinuation.insert(regionEntry);
9783b45fe2eSMarkus Böck   SmallVector<SmallVector<Block *>> successorBranchRegions(
9793b45fe2eSMarkus Böck       regionEntry->getNumSuccessors());
9803b45fe2eSMarkus Böck   for (auto &&[blockList, succ] :
9813b45fe2eSMarkus Böck        llvm::zip(successorBranchRegions, regionEntry->getSuccessors())) {
9823b45fe2eSMarkus Böck     // If the region entry is not the only predecessor, then the edge does not
9833b45fe2eSMarkus Böck     // dominate the block it leads to.
9843b45fe2eSMarkus Böck     if (succ->getSinglePredecessor() != regionEntry)
9853b45fe2eSMarkus Böck       continue;
9863b45fe2eSMarkus Böck 
9873b45fe2eSMarkus Böck     // Otherwise get all blocks it dominates in DFS/pre-order.
9883b45fe2eSMarkus Böck     DominanceInfoNode *node = dominanceInfo.getNode(succ);
9893b45fe2eSMarkus Böck     for (DominanceInfoNode *curr : llvm::depth_first(node)) {
9903b45fe2eSMarkus Böck       blockList.push_back(curr->getBlock());
9913b45fe2eSMarkus Böck       notContinuation.insert(curr->getBlock());
9923b45fe2eSMarkus Böck     }
9933b45fe2eSMarkus Böck   }
9943b45fe2eSMarkus Böck 
9953b45fe2eSMarkus Böck   // Finds all relevant edges and checks the shape of the control flow graph at
9963b45fe2eSMarkus Böck   // this point.
9973b45fe2eSMarkus Böck   // Branch regions may either:
9983b45fe2eSMarkus Böck   // * Be post-dominated by the continuation
9993b45fe2eSMarkus Böck   // * Be post-dominated by a return-like op
10003b45fe2eSMarkus Böck   // * Dominate a return-like op and have an edge to the continuation.
10013b45fe2eSMarkus Böck   //
10023b45fe2eSMarkus Böck   // The control flow graph may then be one of three cases:
10033b45fe2eSMarkus Böck   // 1) All branch regions are post-dominated by the continuation. This is the
10043b45fe2eSMarkus Böck   // usual case. If there are multiple entry blocks into the continuation a
10053b45fe2eSMarkus Böck   // single entry block has to be created. A structured control flow op
10063b45fe2eSMarkus Böck   // can then be created from the branch regions.
10073b45fe2eSMarkus Böck   //
10083b45fe2eSMarkus Böck   // 2) No branch region has an edge to a continuation:
10093b45fe2eSMarkus Böck   //                                 +-----+
10103b45fe2eSMarkus Böck   //                           +-----+ bb0 +----+
10113b45fe2eSMarkus Böck   //                           v     +-----+    v
10123b45fe2eSMarkus Böck   //                Region 1 +-+--+    ...     +-+--+ Region n
10133b45fe2eSMarkus Böck   //                         |ret1|            |ret2|
10143b45fe2eSMarkus Böck   //                         +----+            +----+
10153b45fe2eSMarkus Böck   //
10163b45fe2eSMarkus Böck   // This can only occur if every region ends with a different kind of
10173b45fe2eSMarkus Böck   // return-like op. In that case the control flow operation must stay as we are
10183b45fe2eSMarkus Böck   // unable to create a single exit-block. We can nevertheless process all its
10193b45fe2eSMarkus Böck   // successors as they single-entry, single-exit regions.
10203b45fe2eSMarkus Böck   //
10213b45fe2eSMarkus Böck   // 3) Only some branch regions are post-dominated by the continuation.
10223b45fe2eSMarkus Böck   // The other branch regions may either be post-dominated by a return-like op
10233b45fe2eSMarkus Böck   // or lead to either the continuation or return-like op.
10243b45fe2eSMarkus Böck   // In this case we also create a single entry block like in 1) that also
10253b45fe2eSMarkus Böck   // includes all edges to the return-like op:
10263b45fe2eSMarkus Böck   //                                 +-----+
10273b45fe2eSMarkus Böck   //                           +-----+ bb0 +----+
10283b45fe2eSMarkus Böck   //                           v     +-----+    v
10293b45fe2eSMarkus Böck   //             Region 1    +-+-+    ...     +-+-+ Region n
10303b45fe2eSMarkus Böck   //                         +---+            +---+
10313b45fe2eSMarkus Böck   //                  +---+  |...              ...
10323b45fe2eSMarkus Böck   //                  |ret|<-+ |                |
10333b45fe2eSMarkus Böck   //                  +---+    |      +---+     |
10343b45fe2eSMarkus Böck   //                           +---->++   ++<---+
10353b45fe2eSMarkus Böck   //                                 |     |
10363b45fe2eSMarkus Böck   //                                 ++   ++ Region T
10373b45fe2eSMarkus Böck   //                                  +---+
10383b45fe2eSMarkus Böck   // This transforms to:
10393b45fe2eSMarkus Böck   //                                 +-----+
10403b45fe2eSMarkus Böck   //                           +-----+ bb0 +----+
10413b45fe2eSMarkus Böck   //                           v     +-----+    v
10423b45fe2eSMarkus Böck   //                Region 1 +-+-+    ...     +-+-+ Region n
10433b45fe2eSMarkus Böck   //                         +---+            +---+
10443b45fe2eSMarkus Böck   //                          ...    +-----+   ...
10453b45fe2eSMarkus Böck   //                           +---->+ bbM +<---+
10463b45fe2eSMarkus Böck   //                                 +-----+
10473b45fe2eSMarkus Böck   //                           +-----+  |
10483b45fe2eSMarkus Böck   //                           |        v
10493b45fe2eSMarkus Böck   //                  +---+    |      +---+
10503b45fe2eSMarkus Böck   //                  |ret+<---+     ++   ++
10513b45fe2eSMarkus Böck   //                  +---+          |     |
10523b45fe2eSMarkus Böck   //                                 ++   ++ Region T
10533b45fe2eSMarkus Böck   //                                  +---+
10543b45fe2eSMarkus Böck   //
10553b45fe2eSMarkus Böck   // bb0 to bbM is now a single-entry, single-exit region that applies to case
10563b45fe2eSMarkus Böck   // 1). The control flow op at the end of bbM will trigger case 2.
10573b45fe2eSMarkus Böck   SmallVector<Edge> continuationEdges;
10583b45fe2eSMarkus Böck   bool continuationPostDominatesAllRegions = true;
10593b45fe2eSMarkus Böck   bool noSuccessorHasContinuationEdge = true;
10603b45fe2eSMarkus Böck   for (auto &&[entryEdge, branchRegion] :
10613b45fe2eSMarkus Böck        llvm::zip(successorEdges(regionEntry), successorBranchRegions)) {
10623b45fe2eSMarkus Böck 
10633b45fe2eSMarkus Böck     // If the branch region is empty then the branch target itself is part of
10643b45fe2eSMarkus Böck     // the continuation.
10653b45fe2eSMarkus Böck     if (branchRegion.empty()) {
10663b45fe2eSMarkus Böck       continuationEdges.push_back(entryEdge);
10673b45fe2eSMarkus Böck       noSuccessorHasContinuationEdge = false;
10683b45fe2eSMarkus Böck       continue;
10693b45fe2eSMarkus Böck     }
10703b45fe2eSMarkus Böck 
10713b45fe2eSMarkus Böck     for (Block *block : branchRegion) {
10723b45fe2eSMarkus Böck       if (isRegionExitBlock(block)) {
10733b45fe2eSMarkus Böck         // If a return-like op is part of the branch region then the
10743b45fe2eSMarkus Böck         // continuation no longer post-dominates the branch region.
10753b45fe2eSMarkus Böck         // Add all its incoming edges to edge list to create the single-exit
10763b45fe2eSMarkus Böck         // block for all branch regions.
10773b45fe2eSMarkus Böck         continuationPostDominatesAllRegions = false;
10783b45fe2eSMarkus Böck         for (auto iter = block->pred_begin(); iter != block->pred_end();
10793b45fe2eSMarkus Böck              ++iter) {
10803b45fe2eSMarkus Böck           continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
10813b45fe2eSMarkus Böck         }
10823b45fe2eSMarkus Böck         continue;
10833b45fe2eSMarkus Böck       }
10843b45fe2eSMarkus Böck 
10853b45fe2eSMarkus Böck       for (Edge edge : successorEdges(block)) {
10863b45fe2eSMarkus Böck         if (notContinuation.contains(edge.getSuccessor()))
10873b45fe2eSMarkus Böck           continue;
10883b45fe2eSMarkus Böck 
10893b45fe2eSMarkus Böck         continuationEdges.push_back(edge);
10903b45fe2eSMarkus Böck         noSuccessorHasContinuationEdge = false;
10913b45fe2eSMarkus Böck       }
10923b45fe2eSMarkus Böck     }
10933b45fe2eSMarkus Böck   }
10943b45fe2eSMarkus Böck 
10953b45fe2eSMarkus Böck   // case 2) Keep the control flow op but process its successors further.
10963b45fe2eSMarkus Böck   if (noSuccessorHasContinuationEdge)
10973b45fe2eSMarkus Böck     return llvm::to_vector(regionEntry->getSuccessors());
10983b45fe2eSMarkus Böck 
10993b45fe2eSMarkus Böck   Block *continuation = llvm::find_singleton<Block>(
11003b45fe2eSMarkus Böck       continuationEdges, [](Edge edge, bool) { return edge.getSuccessor(); },
11013b45fe2eSMarkus Böck       /*AllowRepeats=*/true);
11023b45fe2eSMarkus Böck 
11033b45fe2eSMarkus Böck   // In case 3) or if not all continuation edges have the same entry block,
11043b45fe2eSMarkus Böck   // create a single entry block as continuation for all branch regions.
11053b45fe2eSMarkus Böck   if (!continuation || !continuationPostDominatesAllRegions) {
11063b45fe2eSMarkus Böck     EdgeMultiplexer multiplexer = createSingleEntryBlock(
11073b45fe2eSMarkus Böck         continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
11083b45fe2eSMarkus Böck         continuationEdges, getSwitchValue, getUndefValue, interface);
11093b45fe2eSMarkus Böck     continuation = multiplexer.getMultiplexerBlock();
11103b45fe2eSMarkus Böck   }
11113b45fe2eSMarkus Böck 
11123b45fe2eSMarkus Böck   // Trigger reprocess of case 3) after creating the single entry block.
11133b45fe2eSMarkus Böck   if (!continuationPostDominatesAllRegions) {
11143b45fe2eSMarkus Böck     // Unlike in the general case, we are explicitly revisiting the same region
11153b45fe2eSMarkus Böck     // entry again after having changed its control flow edges and dominance.
11163b45fe2eSMarkus Böck     // We have to therefore explicitly invalidate the dominance tree.
11173b45fe2eSMarkus Böck     dominanceInfo.invalidate(regionEntry->getParent());
11183b45fe2eSMarkus Böck     return SmallVector<Block *>{regionEntry};
11193b45fe2eSMarkus Böck   }
11203b45fe2eSMarkus Böck 
11213b45fe2eSMarkus Böck   SmallVector<Block *> newSubRegions;
11223b45fe2eSMarkus Böck 
11233b45fe2eSMarkus Böck   // Empty blocks with the values they return to the parent op.
11243b45fe2eSMarkus Böck   SmallVector<std::pair<Block *, SmallVector<Value>>> createdEmptyBlocks;
11253b45fe2eSMarkus Böck 
11263b45fe2eSMarkus Böck   // Create the branch regions.
11273b45fe2eSMarkus Böck   std::vector<Region> conditionalRegions(successorBranchRegions.size());
11283b45fe2eSMarkus Böck   for (auto &&[branchRegion, entryEdge, conditionalRegion] :
11293b45fe2eSMarkus Böck        llvm::zip(successorBranchRegions, successorEdges(regionEntry),
11303b45fe2eSMarkus Böck                  conditionalRegions)) {
11313b45fe2eSMarkus Böck     if (branchRegion.empty()) {
11323b45fe2eSMarkus Böck       // If no block is part of the branch region, we create a dummy block to
11333b45fe2eSMarkus Böck       // place the region terminator into.
11343b45fe2eSMarkus Böck       createdEmptyBlocks.emplace_back(
11353b45fe2eSMarkus Böck           new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
11363b45fe2eSMarkus Böck       conditionalRegion.push_back(createdEmptyBlocks.back().first);
11373b45fe2eSMarkus Böck       continue;
11383b45fe2eSMarkus Böck     }
11393b45fe2eSMarkus Böck 
11403b45fe2eSMarkus Böck     createSingleExitBranchRegion(branchRegion, continuation, createdEmptyBlocks,
11413b45fe2eSMarkus Böck                                  conditionalRegion);
11423b45fe2eSMarkus Böck 
11433b45fe2eSMarkus Böck     // The entries of the branch regions may only have redundant block arguments
11443b45fe2eSMarkus Böck     // since the edge to the branch region is always dominating.
11453b45fe2eSMarkus Böck     Block *subRegionEntryBlock = &conditionalRegion.front();
11463b45fe2eSMarkus Böck     for (auto &&[oldValue, newValue] :
11473b45fe2eSMarkus Böck          llvm::zip(subRegionEntryBlock->getArguments(),
11483b45fe2eSMarkus Böck                    entryEdge.getSuccessorOperands()))
11493b45fe2eSMarkus Böck       oldValue.replaceAllUsesWith(newValue);
11503b45fe2eSMarkus Böck 
11513b45fe2eSMarkus Böck     subRegionEntryBlock->eraseArguments(0,
11523b45fe2eSMarkus Böck                                         subRegionEntryBlock->getNumArguments());
11533b45fe2eSMarkus Böck     newSubRegions.push_back(subRegionEntryBlock);
11543b45fe2eSMarkus Böck   }
11553b45fe2eSMarkus Böck 
11563b45fe2eSMarkus Böck   Operation *structuredCondOp;
11573b45fe2eSMarkus Böck   {
11583b45fe2eSMarkus Böck     auto opBuilder = OpBuilder::atBlockTerminator(regionEntry);
11593b45fe2eSMarkus Böck     FailureOr<Operation *> result = interface.createStructuredBranchRegionOp(
11603b45fe2eSMarkus Böck         opBuilder, regionEntry->getTerminator(),
11613b45fe2eSMarkus Böck         continuation->getArgumentTypes(), conditionalRegions);
11623b45fe2eSMarkus Böck     if (failed(result))
11633b45fe2eSMarkus Böck       return failure();
11643b45fe2eSMarkus Böck     structuredCondOp = *result;
11653b45fe2eSMarkus Böck     regionEntry->getTerminator()->erase();
11663b45fe2eSMarkus Böck   }
11673b45fe2eSMarkus Böck 
11683b45fe2eSMarkus Böck   for (auto &&[block, valueRange] : createdEmptyBlocks) {
11693b45fe2eSMarkus Böck     auto builder = OpBuilder::atBlockEnd(block);
11703b45fe2eSMarkus Böck     LogicalResult result = interface.createStructuredBranchRegionTerminatorOp(
1171359ba0b0SMarkus Böck         structuredCondOp->getLoc(), builder, structuredCondOp, nullptr,
1172359ba0b0SMarkus Böck         valueRange);
11733b45fe2eSMarkus Böck     if (failed(result))
11743b45fe2eSMarkus Böck       return failure();
11753b45fe2eSMarkus Böck   }
11763b45fe2eSMarkus Böck 
11773b45fe2eSMarkus Böck   // Any leftover users of the continuation must be from unconditional branches
11783b45fe2eSMarkus Böck   // in a branch region. There can only be at most one per branch region as
11793b45fe2eSMarkus Böck   // all branch regions have been made single-entry single-exit above.
11803b45fe2eSMarkus Böck   // Replace them with the region terminator.
11813b45fe2eSMarkus Böck   for (Operation *user : llvm::make_early_inc_range(continuation->getUsers())) {
11823b45fe2eSMarkus Böck     assert(user->getNumSuccessors() == 1);
11833b45fe2eSMarkus Böck     auto builder = OpBuilder::atBlockTerminator(user->getBlock());
11843b45fe2eSMarkus Böck     LogicalResult result = interface.createStructuredBranchRegionTerminatorOp(
1185359ba0b0SMarkus Böck         user->getLoc(), builder, structuredCondOp, user,
1186*a9304edfSThomas Preud'homme         getMutableSuccessorOperands(user->getBlock(), 0).getAsOperandRange());
11873b45fe2eSMarkus Böck     if (failed(result))
11883b45fe2eSMarkus Böck       return failure();
11893b45fe2eSMarkus Böck     user->erase();
11903b45fe2eSMarkus Böck   }
11913b45fe2eSMarkus Böck 
11923b45fe2eSMarkus Böck   for (auto &&[oldValue, newValue] :
11933b45fe2eSMarkus Böck        llvm::zip(continuation->getArguments(), structuredCondOp->getResults()))
11943b45fe2eSMarkus Böck     oldValue.replaceAllUsesWith(newValue);
11953b45fe2eSMarkus Böck 
11963b45fe2eSMarkus Böck   // Splice together the continuations operations with the region entry.
11973b45fe2eSMarkus Böck   regionEntry->getOperations().splice(regionEntry->end(),
11983b45fe2eSMarkus Böck                                       continuation->getOperations());
11993b45fe2eSMarkus Böck 
12003b45fe2eSMarkus Böck   continuation->erase();
12013b45fe2eSMarkus Böck 
12023b45fe2eSMarkus Böck   // After splicing the continuation, the region has to be reprocessed as it has
12033b45fe2eSMarkus Böck   // new successors.
12043b45fe2eSMarkus Böck   newSubRegions.push_back(regionEntry);
12053b45fe2eSMarkus Böck 
12063b45fe2eSMarkus Böck   return newSubRegions;
12073b45fe2eSMarkus Böck }
12083b45fe2eSMarkus Böck 
12093b45fe2eSMarkus Böck /// Transforms the region to only have a single block for every kind of
12103b45fe2eSMarkus Böck /// return-like operation that all previous occurrences of the return-like op
12113b45fe2eSMarkus Böck /// branch to. If the region only contains a single kind of return-like
12123b45fe2eSMarkus Böck /// operation, it creates a single-entry and single-exit region.
createSingleExitBlocksForReturnLike(Region & region,function_ref<Value (unsigned)> getSwitchValue,CFGToSCFInterface & interface)12133b45fe2eSMarkus Böck static ReturnLikeExitCombiner createSingleExitBlocksForReturnLike(
12143b45fe2eSMarkus Böck     Region &region, function_ref<Value(unsigned)> getSwitchValue,
12153b45fe2eSMarkus Böck     CFGToSCFInterface &interface) {
12163b45fe2eSMarkus Böck   ReturnLikeExitCombiner exitCombiner(region, interface);
12173b45fe2eSMarkus Böck 
12183b45fe2eSMarkus Böck   for (Block &block : region.getBlocks()) {
12193b45fe2eSMarkus Böck     if (block.getNumSuccessors() != 0)
12203b45fe2eSMarkus Böck       continue;
12213b45fe2eSMarkus Böck     exitCombiner.combineExit(block.getTerminator(), getSwitchValue);
12223b45fe2eSMarkus Böck   }
12233b45fe2eSMarkus Böck 
12243b45fe2eSMarkus Böck   return exitCombiner;
12253b45fe2eSMarkus Böck }
12263b45fe2eSMarkus Böck 
12273b45fe2eSMarkus Böck /// Checks all preconditions of the transformation prior to any transformations.
12283b45fe2eSMarkus Böck /// Returns failure if any precondition is violated.
checkTransformationPreconditions(Region & region)12293b45fe2eSMarkus Böck static LogicalResult checkTransformationPreconditions(Region &region) {
12303b45fe2eSMarkus Böck   for (Block &block : region.getBlocks())
12313b45fe2eSMarkus Böck     if (block.hasNoPredecessors() && !block.isEntryBlock())
12323b45fe2eSMarkus Böck       return block.front().emitOpError(
12333b45fe2eSMarkus Böck           "transformation does not support unreachable blocks");
12343b45fe2eSMarkus Böck 
12353b45fe2eSMarkus Böck   WalkResult result = region.walk([](Operation *operation) {
12363b45fe2eSMarkus Böck     if (operation->getNumSuccessors() == 0)
12373b45fe2eSMarkus Böck       return WalkResult::advance();
12383b45fe2eSMarkus Böck 
12393b45fe2eSMarkus Böck     // This transformation requires all ops with successors to implement the
12403b45fe2eSMarkus Böck     // branch op interface. It is impossible to adjust their block arguments
12413b45fe2eSMarkus Böck     // otherwise.
12423b45fe2eSMarkus Böck     auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
12433b45fe2eSMarkus Böck     if (!branchOpInterface) {
12443b45fe2eSMarkus Böck       operation->emitOpError("transformation does not support terminators with "
12453b45fe2eSMarkus Böck                              "successors not implementing BranchOpInterface");
12463b45fe2eSMarkus Böck       return WalkResult::interrupt();
12473b45fe2eSMarkus Böck     }
12483b45fe2eSMarkus Böck     // Branch operations must have no side effects. Replacing them would not be
12493b45fe2eSMarkus Böck     // valid otherwise.
12503b45fe2eSMarkus Böck     if (!isMemoryEffectFree(branchOpInterface)) {
12513b45fe2eSMarkus Böck       branchOpInterface->emitOpError(
12523b45fe2eSMarkus Böck           "transformation does not support terminators with side effects");
12533b45fe2eSMarkus Böck       return WalkResult::interrupt();
12543b45fe2eSMarkus Böck     }
12553b45fe2eSMarkus Böck 
12563b45fe2eSMarkus Böck     for (unsigned index : llvm::seq(operation->getNumSuccessors())) {
12573b45fe2eSMarkus Böck       SuccessorOperands succOps = branchOpInterface.getSuccessorOperands(index);
12583b45fe2eSMarkus Böck 
12593b45fe2eSMarkus Böck       // We cannot support operations with operation-produced successor operands
12603b45fe2eSMarkus Böck       // as it is currently not possible to pass them to any block arguments
12613b45fe2eSMarkus Böck       // other than the first. This breaks creating multiplexer blocks and would
12623b45fe2eSMarkus Böck       // likely need special handling elsewhere too.
12633b45fe2eSMarkus Böck       if (succOps.getProducedOperandCount() == 0)
12643b45fe2eSMarkus Böck         continue;
12653b45fe2eSMarkus Böck 
12663b45fe2eSMarkus Böck       branchOpInterface->emitOpError("transformation does not support "
12673b45fe2eSMarkus Böck                                      "operations with operation-produced "
12683b45fe2eSMarkus Böck                                      "successor operands");
12693b45fe2eSMarkus Böck       return WalkResult::interrupt();
12703b45fe2eSMarkus Böck     }
12713b45fe2eSMarkus Böck     return WalkResult::advance();
12723b45fe2eSMarkus Böck   });
12733b45fe2eSMarkus Böck   return failure(result.wasInterrupted());
12743b45fe2eSMarkus Böck }
12753b45fe2eSMarkus Böck 
transformCFGToSCF(Region & region,CFGToSCFInterface & interface,DominanceInfo & dominanceInfo)12763b45fe2eSMarkus Böck FailureOr<bool> mlir::transformCFGToSCF(Region &region,
12773b45fe2eSMarkus Böck                                         CFGToSCFInterface &interface,
12783b45fe2eSMarkus Böck                                         DominanceInfo &dominanceInfo) {
12793b45fe2eSMarkus Böck   if (region.empty() || region.hasOneBlock())
12803b45fe2eSMarkus Böck     return false;
12813b45fe2eSMarkus Böck 
12823b45fe2eSMarkus Böck   if (failed(checkTransformationPreconditions(region)))
12833b45fe2eSMarkus Böck     return failure();
12843b45fe2eSMarkus Böck 
12853b45fe2eSMarkus Böck   DenseMap<Type, Value> typedUndefCache;
12863b45fe2eSMarkus Böck   auto getUndefValue = [&](Type type) {
12873b45fe2eSMarkus Böck     auto [iter, inserted] = typedUndefCache.insert({type, nullptr});
12883b45fe2eSMarkus Böck     if (!inserted)
12893b45fe2eSMarkus Böck       return iter->second;
12903b45fe2eSMarkus Böck 
12913b45fe2eSMarkus Böck     auto constantBuilder = OpBuilder::atBlockBegin(&region.front());
12923b45fe2eSMarkus Böck 
12933b45fe2eSMarkus Böck     iter->second =
12943b45fe2eSMarkus Böck         interface.getUndefValue(region.getLoc(), constantBuilder, type);
12953b45fe2eSMarkus Böck     return iter->second;
12963b45fe2eSMarkus Böck   };
12973b45fe2eSMarkus Böck 
12983b45fe2eSMarkus Böck   // The transformation only creates all values in the range of 0 to
12993b45fe2eSMarkus Böck   // max(#numSuccessors). Therefore using a vector instead of a map.
13003b45fe2eSMarkus Böck   SmallVector<Value> switchValueCache;
13013b45fe2eSMarkus Böck   auto getSwitchValue = [&](unsigned value) {
13023b45fe2eSMarkus Böck     if (value < switchValueCache.size())
13033b45fe2eSMarkus Böck       if (switchValueCache[value])
13043b45fe2eSMarkus Böck         return switchValueCache[value];
13053b45fe2eSMarkus Böck 
13063b45fe2eSMarkus Böck     auto constantBuilder = OpBuilder::atBlockBegin(&region.front());
13073b45fe2eSMarkus Böck 
13083b45fe2eSMarkus Böck     switchValueCache.resize(
13093b45fe2eSMarkus Böck         std::max<size_t>(switchValueCache.size(), value + 1));
13103b45fe2eSMarkus Böck 
13113b45fe2eSMarkus Böck     switchValueCache[value] =
13123b45fe2eSMarkus Böck         interface.getCFGSwitchValue(region.getLoc(), constantBuilder, value);
13133b45fe2eSMarkus Böck     return switchValueCache[value];
13143b45fe2eSMarkus Böck   };
13153b45fe2eSMarkus Böck 
13163b45fe2eSMarkus Böck   ReturnLikeExitCombiner exitCombiner =
13173b45fe2eSMarkus Böck       createSingleExitBlocksForReturnLike(region, getSwitchValue, interface);
13183b45fe2eSMarkus Böck 
13193b45fe2eSMarkus Böck   // Invalidate any dominance tree on the region as the exit combiner has
13203b45fe2eSMarkus Böck   // added new blocks and edges.
13213b45fe2eSMarkus Böck   dominanceInfo.invalidate(&region);
13223b45fe2eSMarkus Böck 
13233b45fe2eSMarkus Böck   SmallVector<Block *> workList = {&region.front()};
13243b45fe2eSMarkus Böck   while (!workList.empty()) {
13253b45fe2eSMarkus Böck     Block *current = workList.pop_back_val();
13263b45fe2eSMarkus Böck 
13273b45fe2eSMarkus Böck     // Turn all top-level cycles in the CFG to structured control flow first.
13283b45fe2eSMarkus Böck     // After this transformation, the remaining CFG ops form a DAG.
13293b45fe2eSMarkus Böck     FailureOr<SmallVector<Block *>> newRegions =
13303b45fe2eSMarkus Böck         transformCyclesToSCFLoops(current, getSwitchValue, getUndefValue,
13313b45fe2eSMarkus Böck                                   interface, dominanceInfo, exitCombiner);
13323b45fe2eSMarkus Böck     if (failed(newRegions))
13333b45fe2eSMarkus Böck       return failure();
13343b45fe2eSMarkus Böck 
13353b45fe2eSMarkus Böck     // Add the newly created subregions to the worklist. These are the
13363b45fe2eSMarkus Böck     // bodies of the loops.
13373b45fe2eSMarkus Böck     llvm::append_range(workList, *newRegions);
13383b45fe2eSMarkus Böck     // Invalidate the dominance tree as blocks have been moved, created and
13393b45fe2eSMarkus Böck     // added during the cycle to structured loop transformation.
13403b45fe2eSMarkus Böck     if (!newRegions->empty())
13413b45fe2eSMarkus Böck       dominanceInfo.invalidate(current->getParent());
13423b45fe2eSMarkus Böck 
13433b45fe2eSMarkus Böck     newRegions = transformToStructuredCFBranches(
13443b45fe2eSMarkus Böck         current, getSwitchValue, getUndefValue, interface, dominanceInfo);
13453b45fe2eSMarkus Böck     if (failed(newRegions))
13463b45fe2eSMarkus Böck       return failure();
13473b45fe2eSMarkus Böck     // Invalidating the dominance tree is generally not required by the
13483b45fe2eSMarkus Böck     // transformation above as the new region entries correspond to unaffected
13493b45fe2eSMarkus Böck     // subtrees in the dominator tree. Only its parent nodes have changed but
13503b45fe2eSMarkus Böck     // won't be visited again.
13513b45fe2eSMarkus Böck     llvm::append_range(workList, *newRegions);
13523b45fe2eSMarkus Böck   }
13533b45fe2eSMarkus Böck 
13543b45fe2eSMarkus Böck   return true;
13553b45fe2eSMarkus Böck }
1356