120#include "llvm/ADT/DepthFirstIterator.h"
121#include "llvm/ADT/MapVector.h"
122#include "llvm/ADT/SCCIterator.h"
123#include "llvm/ADT/SetVector.h"
132 auto branchOpInterface = cast<BranchOpInterface>(block->
getTerminator());
134 branchOpInterface.getSuccessorOperands(successorIndex);
141 unsigned successorIndex) {
159 unsigned successorIndex;
164 Edge(
Block *fromBlock,
unsigned int successorIndex)
165 : fromBlock(fromBlock), successorIndex(successorIndex) {}
168 Block *getFromBlock()
const {
return fromBlock; }
171 Block *getSuccessor()
const {
172 return fromBlock->getSuccessor(successorIndex);
177 void setSuccessor(
Block *block)
const {
178 fromBlock->getTerminator()->setSuccessor(block, successorIndex);
184 return ::getMutableSuccessorOperands(fromBlock, successorIndex);
190 return ::getSuccessorOperands(fromBlock, successorIndex);
200 SmallVector<Edge> entryEdges;
202 SmallVector<Edge> exitEdges;
204 SmallVector<Edge> backEdges;
212class EdgeMultiplexer {
225 static EdgeMultiplexer create(Location loc, ArrayRef<Block *> entryBlocks,
229 assert(!entryBlocks.empty() &&
"Require at least one entry block");
231 auto *multiplexerBlock =
new Block;
232 multiplexerBlock->insertAfter(entryBlocks.front());
239 llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
240 for (
Block *entryBlock : entryBlocks) {
241 auto [iter,
inserted] = blockArgMapping.insert(
242 {entryBlock, multiplexerBlock->getNumArguments()});
252 if (blockArgMapping.size() > 1)
254 multiplexerBlock->addArgument(getSwitchValue(0).
getType(), loc);
256 multiplexerBlock->addArguments(
257 extraArgs, SmallVector<Location>(extraArgs.size(), loc));
259 return EdgeMultiplexer(multiplexerBlock, getSwitchValue, getUndefValue,
260 std::move(blockArgMapping), discriminator);
264 Block *getMultiplexerBlock()
const {
return multiplexerBlock; }
271 void redirectEdge(Edge edge,
ValueRange extraArgs = {})
const {
272 const auto *
result = blockArgMapping.find(edge.getSuccessor());
273 assert(
result != blockArgMapping.end() &&
274 "Edge was not originally passed to `create` method.");
276 MutableOperandRange successorOperands = edge.getMutableSuccessorOperands();
279 unsigned extraArgsBeginIndex =
280 multiplexerBlock->getNumArguments() - extraArgs.size();
282 std::optional<unsigned> discriminatorIndex =
283 discriminator ? extraArgsBeginIndex - 1 : std::optional<unsigned>{};
285 SmallVector<Value> newSuccOperands(multiplexerBlock->getNumArguments());
286 for (BlockArgument argument : multiplexerBlock->getArguments()) {
287 unsigned index = argument.getArgNumber();
288 if (index >=
result->second &&
289 index < result->second + edge.getSuccessor()->getNumArguments()) {
291 newSuccOperands[index] =
292 successorOperands[index -
result->second].get();
297 if (index == discriminatorIndex) {
298 newSuccOperands[index] =
299 getSwitchValue(
result - blockArgMapping.begin());
304 if (index >= extraArgsBeginIndex) {
305 newSuccOperands[index] = extraArgs[index - extraArgsBeginIndex];
311 newSuccOperands[index] = getPoisonValue(argument.getType());
314 edge.setSuccessor(multiplexerBlock);
315 successorOperands.
assign(newSuccOperands);
324 Location loc, OpBuilder &builder, CFGToSCFInterface &interface,
325 const SmallPtrSetImpl<Block *> &excluded = SmallPtrSet<Block *, 1>{}) {
329 SmallVector<ValueRange> caseArguments;
330 SmallVector<unsigned> caseValues;
331 SmallVector<Block *> caseDestinations;
332 for (
auto &&[index, pair] : llvm::enumerate(blockArgMapping)) {
333 auto &&[succ, offset] = pair;
334 if (excluded.contains(succ))
337 caseValues.push_back(index);
338 caseArguments.push_back(multiplexerBlock->getArguments().slice(
339 offset, succ->getNumArguments()));
340 caseDestinations.push_back(succ);
345 Value realDiscriminator = discriminator;
346 if (!realDiscriminator || caseArguments.size() == 1)
347 realDiscriminator = getSwitchValue(0);
349 caseValues.pop_back();
350 Block *defaultDest = caseDestinations.pop_back_val();
351 ValueRange defaultArgs = caseArguments.pop_back_val();
354 "Edges need to be redirected prior to creating switch.");
356 caseDestinations, caseArguments, defaultDest,
362 Block *multiplexerBlock;
373 llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
379 EdgeMultiplexer(
Block *multiplexerBlock,
382 llvm::SmallMapVector<Block *, unsigned, 4> &&entries,
384 : multiplexerBlock(multiplexerBlock), getSwitchValue(getSwitchValue),
385 getPoisonValue(getPoisonValue), blockArgMapping(std::move(entries)),
386 discriminator(dispatchFlag) {}
396 static unsigned getHashValue(
const Operation *opC) {
398 const_cast<Operation *
>(opC),
404 static bool isEqual(
const Operation *
lhs,
const Operation *
rhs) {
408 const_cast<Operation *
>(
lhs),
const_cast<Operation *
>(
rhs),
416class ReturnLikeExitCombiner {
418 ReturnLikeExitCombiner(Region &topLevelRegion, CFGToSCFInterface &interface)
419 : topLevelRegion(topLevelRegion), interface(interface) {}
423 void combineExit(Operation *returnLikeOp,
426 auto existing = returnLikeToCombinedExit.find(returnLikeOp);
427 if (existing != returnLikeToCombinedExit.end() &&
428 existing->first == returnLikeOp)
435 if (interface.isUnreachableTerminator(returnLikeOp) &&
436 !orderedExitBlocks.empty()) {
437 Block *exitBlock = orderedExitBlocks.front();
439 interface.createSingleDestinationBranch(
440 returnLikeOp->
getLoc(), builder, getSwitchValue(0), exitBlock,
442 returnLikeOp->
erase();
446 auto [iter,
inserted] = returnLikeToCombinedExit.try_emplace(returnLikeOp);
448 Block *exitBlock = iter->second;
450 exitBlock =
new Block;
451 iter->second = exitBlock;
453 topLevelRegion.push_back(exitBlock);
461 interface.createSingleDestinationBranch(returnLikeOp->
getLoc(), builder,
462 getSwitchValue(0), exitBlock,
466 returnLikeOp->
erase();
478 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
479 returnLikeToCombinedExit;
481 SmallVector<Block *, 4> orderedExitBlocks;
482 Region &topLevelRegion;
483 CFGToSCFInterface &interface;
491 [=](
unsigned index) { return Edge(block, index); });
502 for (
Block *block : cycles) {
504 if (cycles.contains(*pred))
507 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
508 entryBlocks.insert(block);
511 for (
auto &&[succIndex, succ] : llvm::enumerate(block->
getSuccessors())) {
512 if (cycles.contains(succ))
515 result.exitEdges.emplace_back(block, succIndex);
520 for (
Block *block : cycles) {
521 for (
auto &&[succIndex, succ] : llvm::enumerate(block->
getSuccessors())) {
522 if (!entryBlocks.contains(succ))
525 result.backEdges.emplace_back(block, succIndex);
534static EdgeMultiplexer
539 auto result = EdgeMultiplexer::create(
540 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
541 getSwitchValue, getUndefValue);
545 for (Edge edge : entryEdges)
546 result.redirectEdge(edge);
549 result.createSwitch(loc, builder, interface);
559struct StructuredLoopProperties {
575 ReturnLikeExitCombiner &exitCombiner) {
576 assert(llvm::all_equal(
577 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
578 "All repetition edges must lead to the single loop header");
587 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
589 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
591 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
594 auto *latchBlock = multiplexer.getMultiplexerBlock();
597 auto *exitBlock =
new Block;
601 Block *loopHeader = backEdges.front().getSuccessor();
607 for (Edge backEdge : backEdges)
608 multiplexer.redirectEdge(backEdge, getSwitchValue(1));
611 for (Edge exitEdge : exitEdges)
612 multiplexer.redirectEdge(exitEdge, getSwitchValue(0));
616 Value shouldRepeat = latchBlock->getArguments().back();
620 loc, builder, shouldRepeat, loopHeader,
628 if (!exitEdges.empty()) {
637 multiplexer.createSwitch(loc, builder, interface, excluded);
643 loc, builder, *latchBlock->getParent());
644 if (failed(terminator))
648 exitCombiner.combineExit(*terminator, getSwitchValue, getUndefValue);
652 return StructuredLoopProperties{latchBlock, shouldRepeat,
675 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
680 "Exit block must have only latch as predecessor at this point");
682 "Exit block mustn't have any block arguments at this point");
684 unsigned loopHeaderIndex = 0;
685 unsigned exitBlockIndex = 1;
687 std::swap(loopHeaderIndex, exitBlockIndex);
689 assert(latch->
getSuccessor(loopHeaderIndex) == loopHeader);
690 assert(latch->
getSuccessor(exitBlockIndex) == exitBlock);
702 for (
Value arg : loopHeaderSuccessorOperands) {
704 exitBlockSuccessorOperands.
append(arg);
705 arg.replaceUsesWithIf(exitArg, [&](
OpOperand &use) {
722 for (
Block *loopBlock : loopBlocks) {
726 llvm::SmallDenseMap<Block *, bool> dominanceCache;
728 auto loopBlockDominates = [&](
Block *block) {
729 auto [iter,
inserted] = dominanceCache.try_emplace(block);
732 iter->second = dominanceInfo.
dominates(loopBlock, block);
736 auto checkValue = [&](
Value value) {
738 for (
OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
742 Block *currBlock = use.getOwner()->getBlock();
745 if (loopBlocks.contains(currBlock))
749 if (!blockArgument) {
751 exitBlock->
addArgument(value.getType(), value.getLoc());
752 loopHeader->
addArgument(value.getType(), value.getLoc());
761 Value argument = value;
762 if (value.getParentBlock() != latch &&
764 return !loopBlockDominates(pred);
766 argument = latch->
addArgument(value.getType(), value.getLoc());
769 Value succOperand = value;
770 if (!loopBlockDominates(*iter))
771 succOperand = getUndefValue(value.getType());
778 loopHeaderSuccessorOperands.push_back(argument);
780 edge.getMutableSuccessorOperands().append(argument);
783 use.set(blockArgument);
787 if (loopBlock == latch)
788 llvm::for_each(latchBlockArgumentsPrior, checkValue);
789 else if (loopBlock == loopHeader)
790 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
792 llvm::for_each(loopBlock->getArguments(), checkValue);
795 llvm::for_each(op.getResults(), checkValue);
808 succOps.
append(llvm::map_to_vector(
810 [&](
BlockArgument arg) { return getUndefValue(arg.getType()); }));
813 return loopHeaderSuccessorOperands;
822 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
824 auto scc = llvm::scc_begin(regionEntry);
825 while (!scc.isAtEnd()) {
826 if (!scc.hasCycle()) {
833 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
837 Block *loopHeader = edges.entryEdges.front().getSuccessor();
840 if (edges.entryEdges.size() > 1) {
842 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
843 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
847 getSwitchValue, getUndefValue, interface);
849 loopHeader = multiplexer.getMultiplexerBlock();
851 cycleBlockSet.insert(loopHeader);
854 FailureOr<StructuredLoopProperties> loopProperties =
856 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
857 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
858 interface, exitCombiner);
859 if (failed(loopProperties))
862 Block *latchBlock = loopProperties->latch;
863 Block *exitBlock = loopProperties->exitBlock;
864 cycleBlockSet.insert(latchBlock);
865 cycleBlockSet.insert(loopHeader);
869 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
873 auto *newLoopParentBlock =
new Block;
880 loopBody.
push_back(blocks.remove(loopHeader));
881 for (
Block *block : cycleBlockSet)
882 if (block != latchBlock && block != loopHeader)
883 loopBody.
push_back(blocks.remove(block));
885 loopBody.
push_back(blocks.remove(latchBlock));
891 FailureOr<Operation *> structuredLoopOp =
893 builder, oldTerminator, newLoopParentBlock->getArguments(),
894 loopProperties->condition, iterationValues, std::move(loopBody));
895 if (failed(structuredLoopOp))
897 oldTerminator->
erase();
899 newSubRegions.push_back(loopHeader);
901 for (
auto &&[oldValue, newValue] : llvm::zip(
902 exitBlock->
getArguments(), (*structuredLoopOp)->getResults()))
903 oldValue.replaceAllUsesWith(newValue);
907 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
911 return newSubRegions;
923 Region &conditionalRegion) {
924 Block *singleExitBlock =
nullptr;
925 std::optional<Edge> previousEdgeToContinuation;
927 branchRegion.front()->getParent()->getBlocks();
928 for (
Block *block : branchRegion) {
930 if (edge.getSuccessor() != continuation)
933 if (!previousEdgeToContinuation) {
934 previousEdgeToContinuation = edge;
940 if (!singleExitBlock) {
941 singleExitBlock =
new Block;
943 previousEdgeToContinuation->setSuccessor(singleExitBlock);
944 createdEmptyBlocks.emplace_back(singleExitBlock,
948 edge.setSuccessor(singleExitBlock);
951 conditionalRegion.
push_back(parentBlockList.remove(block));
955 conditionalRegion.
push_back(singleExitBlock);
977 for (
auto &&[oldValue, newValue] : llvm::zip(
993 notContinuation.insert(regionEntry);
996 for (
auto &&[blockList, succ] :
997 llvm::zip(successorBranchRegions, regionEntry->
getSuccessors())) {
1000 if (succ->getSinglePredecessor() != regionEntry)
1006 blockList.push_back(curr->getBlock());
1007 notContinuation.insert(curr->getBlock());
1074 bool continuationPostDominatesAllRegions =
true;
1075 bool noSuccessorHasContinuationEdge =
true;
1076 for (
auto &&[entryEdge, branchRegion] :
1077 llvm::zip(
successorEdges(regionEntry), successorBranchRegions)) {
1081 if (branchRegion.empty()) {
1082 continuationEdges.push_back(entryEdge);
1083 noSuccessorHasContinuationEdge =
false;
1087 for (
Block *block : branchRegion) {
1093 continuationPostDominatesAllRegions =
false;
1096 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1102 if (notContinuation.contains(edge.getSuccessor()))
1105 continuationEdges.push_back(edge);
1106 noSuccessorHasContinuationEdge =
false;
1112 if (noSuccessorHasContinuationEdge)
1115 Block *continuation = llvm::find_singleton<Block>(
1116 continuationEdges, [](Edge edge,
bool) {
return edge.getSuccessor(); },
1121 if (!continuation || !continuationPostDominatesAllRegions) {
1123 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1124 continuationEdges, getSwitchValue, getUndefValue, interface);
1125 continuation = multiplexer.getMultiplexerBlock();
1129 if (!continuationPostDominatesAllRegions) {
1143 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1144 for (
auto &&[branchRegion, entryEdge, conditionalRegion] :
1146 conditionalRegions)) {
1147 if (branchRegion.empty()) {
1150 createdEmptyBlocks.emplace_back(
1151 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1152 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1161 Block *subRegionEntryBlock = &conditionalRegion.
front();
1162 for (
auto &&[oldValue, newValue] :
1164 entryEdge.getSuccessorOperands()))
1169 newSubRegions.push_back(subRegionEntryBlock);
1187 for (
Region &conditionalRegion : conditionalRegions)
1189 conditionalRegion.getBlocks());
1192 structuredCondOp = *
result;
1196 for (
auto &&[block, valueRange] : createdEmptyBlocks) {
1199 structuredCondOp->
getLoc(), builder, structuredCondOp,
nullptr,
1210 assert(user->getNumSuccessors() == 1);
1213 user->getLoc(), builder, structuredCondOp, user,
1220 for (
auto &&[oldValue, newValue] :
1228 continuation->
erase();
1232 newSubRegions.push_back(regionEntry);
1234 return newSubRegions;
1244 ReturnLikeExitCombiner exitCombiner(region, interface);
1253 exitCombiner.combineExit(block.
getTerminator(), getSwitchValue,
1260 exitCombiner.combineExit(block.
getTerminator(), getSwitchValue,
1264 return exitCombiner;
1271 llvm::df_iterator_default_set<Block *, 16> reachable;
1273 for (
Block *block : depth_first_ext(®ion.
front(), reachable))
1277 if (!reachable.contains(&block))
1279 "transformation does not support unreachable blocks");
1288 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1289 if (!branchOpInterface) {
1290 operation->
emitOpError(
"transformation does not support terminators with "
1291 "successors not implementing BranchOpInterface");
1297 branchOpInterface->emitOpError(
1298 "transformation does not support terminators with side effects");
1312 branchOpInterface->emitOpError(
"transformation does not support "
1313 "operations with operation-produced "
1314 "successor operands");
1319 if (
result.wasInterrupted())
1329 "cannot convert unknown control flow op to structured control flow");
1346 auto getUndefValue = [&](
Type type) {
1347 auto [iter,
inserted] = typedUndefCache.try_emplace(type);
1349 return iter->second;
1355 return iter->second;
1361 auto getSwitchValue = [&](
unsigned value) {
1362 if (value < switchValueCache.size())
1363 if (switchValueCache[value])
1364 return switchValueCache[value];
1368 switchValueCache.resize(
1369 std::max<size_t>(switchValueCache.size(), value + 1));
1371 switchValueCache[value] =
1373 return switchValueCache[value];
1377 region, getSwitchValue, getUndefValue, interface);
1384 while (!workList.empty()) {
1385 Block *current = workList.pop_back_val();
1389 FailureOr<SmallVector<Block *>> newRegions =
1391 interface, dominanceInfo, exitCombiner);
1392 if (failed(newRegions))
1397 llvm::append_range(workList, *newRegions);
1400 if (!newRegions->empty())
1404 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1405 if (failed(newRegions))
1411 llvm::append_range(workList, *newRegions);
static EdgeMultiplexer createSingleEntryBlock(Location loc, ArrayRef< Edge > entryEdges, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface)
Creates a single entry block out of multiple entry edges using an edge multiplexer and returns it.
static bool isRegionExitBlock(Block *block)
Returns true if this block is an exit block of the region.
static FailureOr< SmallVector< Block * > > transformToStructuredCFBranches(Block *regionEntry, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo)
Transforms the first occurrence of conditional control flow in regionEntry into conditionally execute...
static SmallVector< Value > transformToReduceLoop(Block *loopHeader, Block *exitBlock, const llvm::SmallSetVector< Block *, 4 > &loopBlocks, function_ref< Value(Type)> getUndefValue, DominanceInfo &dominanceInfo)
Transforms a structured loop into a loop in reduce form.
static MutableOperandRange getMutableSuccessorOperands(Block *block, unsigned successorIndex)
Returns the mutable operand range used to transfer operands from block to its successor with the give...
static auto successorEdges(Block *block)
Returns a range of all edges from block to each of its successors.
static FailureOr< StructuredLoopProperties > createSingleExitingLatch(Location loc, ArrayRef< Edge > backEdges, ArrayRef< Edge > exitEdges, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface, ReturnLikeExitCombiner &exitCombiner)
Transforms a loop into a structured loop with only a single back edge and exiting edge,...
static void addBlockArgumentsFromOther(Block *block, Block *other)
Appends all the block arguments from other to the block arguments of block, copying their types and l...
static void createSingleExitBranchRegion(ArrayRef< Block * > branchRegion, Block *continuation, SmallVectorImpl< std::pair< Block *, SmallVector< Value > > > &createdEmptyBlocks, Region &conditionalRegion)
Makes sure the branch region only has a single exit.
static ReturnLikeExitCombiner createSingleExitBlocksForReturnLike(Region ®ion, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface)
Transforms the region to only have a single block for every kind of return-like operation that all pr...
static LogicalResult checkTransformationPreconditions(Region ®ion, CFGToSCFInterface &interface)
Checks all preconditions of the transformation prior to any transformations.
static OperandRange getSuccessorOperands(Block *block, unsigned successorIndex)
Return the operand range used to transfer operands from block to its successor with the given index.
static FailureOr< SmallVector< Block * > > transformCyclesToSCFLoops(Block *regionEntry, function_ref< Value(unsigned)> getSwitchValue, function_ref< Value(Type)> getUndefValue, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner)
Transforms all outer-most cycles in the region with the region entry regionEntry into structured loop...
static CycleEdges calculateCycleEdges(const llvm::SmallSetVector< Block *, 4 > &cycles)
Calculates entry, exit and back edges of the given cycle.
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
This class represents an argument of a Block.
Block represents an ordered list of Operations.
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
unsigned getNumSuccessors()
unsigned getNumArguments()
iterator_range< pred_iterator > getPredecessors()
void erase()
Unlink this Block from its parent region and delete it.
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
pred_iterator pred_begin()
SuccessorRange getSuccessors()
Block * getSinglePredecessor()
If this block has exactly one predecessor, return it.
void insertAfter(Block *block)
Insert this block (which must not already be in a region) right after the specified block.
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
void eraseArguments(unsigned start, unsigned num)
Erases 'num' arguments from the index 'start'.
BlockArgListType getArguments()
Block * getSuccessor(unsigned i)
void insertBefore(Block *block)
Insert this block (which must not already be in a region) right before the specified block.
void push_back(Operation *op)
bool hasNoPredecessors()
Return true if this block has no predecessors.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Interface that should be implemented by any caller of transformCFGToSCF.
virtual FailureOr< Operation * > createStructuredBranchRegionOp(OpBuilder &builder, Operation *controlFlowCondOp, TypeRange resultTypes, MutableArrayRef< Region > regions)=0
Creates a structured control flow operation branching to one of regions.
virtual FailureOr< Operation * > createUnreachableTerminator(Location loc, OpBuilder &builder, Region ®ion)=0
Creates a return-like terminator indicating unreachable.
virtual FailureOr< Operation * > createStructuredDoWhileLoopOp(OpBuilder &builder, Operation *replacedOp, ValueRange loopValuesInit, Value condition, ValueRange loopValuesNextIter, Region &&loopBody)=0
Creates a structured control flow operation representing a do-while loop.
virtual Value getCFGSwitchValue(Location loc, OpBuilder &builder, unsigned value)=0
Creates a constant operation with a result representing value that is suitable as flag for createCFGS...
void createConditionalBranch(Location loc, OpBuilder &builder, Value condition, Block *trueDest, ValueRange trueArgs, Block *falseDest, ValueRange falseArgs)
Helper function to create a conditional branch using createCFGSwitchOp.
virtual void createCFGSwitchOp(Location loc, OpBuilder &builder, Value flag, ArrayRef< unsigned > caseValues, BlockRange caseDestinations, ArrayRef< ValueRange > caseArguments, Block *defaultDest, ValueRange defaultArgs)=0
Creates a switch CFG branch operation branching to one of caseDestinations or defaultDest.
virtual Value getUndefValue(Location loc, OpBuilder &builder, Type type)=0
Creates a constant operation returning an undefined instance of type.
virtual LogicalResult createStructuredBranchRegionTerminatorOp(Location loc, OpBuilder &builder, Operation *branchRegionOp, Operation *replacedControlFlowOp, ValueRange results)=0
Creates a return-like terminator for a branch region of the op returned by createStructuredBranchRegi...
virtual bool canConvertMultiSuccessorBranchOp(Operation *op)
Returns true if this operation (which has >1 successors) can be converted to structured control flow ...
virtual bool isUnreachableTerminator(Operation *op)
Returns true if the given terminator is unreachable.
A class for computing basic dominance information.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
user_range getUsers() const
Returns a range of all users.
void replaceAllUsesWith(ValueT &&newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class provides a mutable adaptor for a range of operands.
unsigned size() const
Returns the current size of the range.
void assign(ValueRange values)
Assign this range to the given values.
void append(ValueRange values)
Append the given values to the range.
static OpBuilder atBlockBegin(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to before the first operation in the block but still ins...
static OpBuilder atBlockEnd(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to after the last operation in the block but still insid...
static OpBuilder atBlockTerminator(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to before the block terminator.
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
This class represents an operand of an operation.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
unsigned getNumSuccessors()
Block * getBlock()
Returns the operation block that contains this operation.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
void remove()
Remove the operation from its parent block, but don't delete it.
operand_type_range getOperandTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
void replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this operation with the provided 'values'.
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
void erase()
Remove this operation from its parent block and delete it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
llvm::iplist< Block > BlockListType
void push_back(Block *block)
Location getLoc()
Return a location for this region.
BlockListType & getBlocks()
bool hasOneBlock()
Return true if this region has exactly one block.
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
This class models how operands are forwarded to block arguments in control flow.
MutableOperandRange getMutableForwardedOperands() const
Get the range of operands that are simply forwarded to the successor.
unsigned getProducedOperandCount() const
Returns the amount of operands that are produced internally by the operation.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
static WalkResult interrupt()
DominanceInfoNode * getNode(Block *a)
Return the dominance node from the Region containing block A.
void invalidate()
Invalidate dominance info.
Operation * getOwner() const
Return the owner of this operand.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
llvm::DomTreeNodeBase< Block > DominanceInfoNode
FailureOr< bool > transformCFGToSCF(Region ®ion, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo)
Transformation lifting any dialect implementing control flow graph operations to a dialect implementi...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref
static llvm::hash_code ignoreHashValue(Value)
Helper that can be used with computeHash above to ignore operation operands/result mapping.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two operations (including their regions) and return if they are equivalent.
static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs)
Helper that can be used with isEquivalentTo above to consider ops equivalent even if their operands a...
static llvm::hash_code computeHash(Operation *op, function_ref< llvm::hash_code(Value)> hashOperands=[](Value v) { return hash_value(v);}, function_ref< llvm::hash_code(Value)> hashResults=[](Value v) { return hash_value(v);}, Flags flags=Flags::None)
Compute a hash for the given operation.