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] = getUndefValue(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 getUndefValue(getUndefValue), 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,
425 auto [iter,
inserted] = returnLikeToCombinedExit.try_emplace(returnLikeOp);
426 if (!
inserted && iter->first == returnLikeOp)
429 Block *exitBlock = iter->second;
431 exitBlock =
new Block;
432 iter->second = exitBlock;
441 interface.createSingleDestinationBranch(returnLikeOp->
getLoc(), builder,
442 getSwitchValue(0), exitBlock,
446 returnLikeOp->
erase();
458 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
459 returnLikeToCombinedExit;
460 Region &topLevelRegion;
461 CFGToSCFInterface &interface;
469 [=](
unsigned index) { return Edge(block, index); });
480 for (
Block *block : cycles) {
482 if (cycles.contains(*pred))
485 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
486 entryBlocks.insert(block);
489 for (
auto &&[succIndex, succ] : llvm::enumerate(block->
getSuccessors())) {
490 if (cycles.contains(succ))
493 result.exitEdges.emplace_back(block, succIndex);
498 for (
Block *block : cycles) {
499 for (
auto &&[succIndex, succ] : llvm::enumerate(block->
getSuccessors())) {
500 if (!entryBlocks.contains(succ))
503 result.backEdges.emplace_back(block, succIndex);
512static EdgeMultiplexer
517 auto result = EdgeMultiplexer::create(
518 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
519 getSwitchValue, getUndefValue);
523 for (Edge edge : entryEdges)
524 result.redirectEdge(edge);
527 result.createSwitch(loc, builder, interface);
537struct StructuredLoopProperties {
553 ReturnLikeExitCombiner &exitCombiner) {
554 assert(llvm::all_equal(
555 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
556 "All repetition edges must lead to the single loop header");
565 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
567 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
569 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
572 auto *latchBlock = multiplexer.getMultiplexerBlock();
575 auto *exitBlock =
new Block;
579 Block *loopHeader = backEdges.front().getSuccessor();
585 for (Edge backEdge : backEdges)
586 multiplexer.redirectEdge(backEdge, getSwitchValue(1));
589 for (Edge exitEdge : exitEdges)
590 multiplexer.redirectEdge(exitEdge, getSwitchValue(0));
594 Value shouldRepeat = latchBlock->getArguments().back();
598 loc, builder, shouldRepeat, loopHeader,
606 if (!exitEdges.empty()) {
615 multiplexer.createSwitch(loc, builder, interface, excluded);
621 loc, builder, *latchBlock->getParent());
622 if (failed(terminator))
626 exitCombiner.combineExit(*terminator, getSwitchValue);
630 return StructuredLoopProperties{latchBlock, shouldRepeat,
653 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
658 "Exit block must have only latch as predecessor at this point");
660 "Exit block mustn't have any block arguments at this point");
662 unsigned loopHeaderIndex = 0;
663 unsigned exitBlockIndex = 1;
665 std::swap(loopHeaderIndex, exitBlockIndex);
667 assert(latch->
getSuccessor(loopHeaderIndex) == loopHeader);
668 assert(latch->
getSuccessor(exitBlockIndex) == exitBlock);
680 for (
Value arg : loopHeaderSuccessorOperands) {
682 exitBlockSuccessorOperands.
append(arg);
683 arg.replaceUsesWithIf(exitArg, [&](
OpOperand &use) {
700 for (
Block *loopBlock : loopBlocks) {
704 llvm::SmallDenseMap<Block *, bool> dominanceCache;
706 auto loopBlockDominates = [&](
Block *block) {
707 auto [iter,
inserted] = dominanceCache.try_emplace(block);
710 iter->second = dominanceInfo.
dominates(loopBlock, block);
714 auto checkValue = [&](
Value value) {
716 for (
OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
720 Block *currBlock = use.getOwner()->getBlock();
723 if (loopBlocks.contains(currBlock))
727 if (!blockArgument) {
729 exitBlock->
addArgument(value.getType(), value.getLoc());
730 loopHeader->
addArgument(value.getType(), value.getLoc());
739 Value argument = value;
740 if (value.getParentBlock() != latch &&
742 return !loopBlockDominates(pred);
744 argument = latch->
addArgument(value.getType(), value.getLoc());
747 Value succOperand = value;
748 if (!loopBlockDominates(*iter))
749 succOperand = getUndefValue(value.getType());
756 loopHeaderSuccessorOperands.push_back(argument);
758 edge.getMutableSuccessorOperands().append(argument);
761 use.set(blockArgument);
765 if (loopBlock == latch)
766 llvm::for_each(latchBlockArgumentsPrior, checkValue);
767 else if (loopBlock == loopHeader)
768 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
770 llvm::for_each(loopBlock->getArguments(), checkValue);
773 llvm::for_each(op.getResults(), checkValue);
786 succOps.
append(llvm::map_to_vector(
788 [&](
BlockArgument arg) { return getUndefValue(arg.getType()); }));
791 return loopHeaderSuccessorOperands;
800 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
802 auto scc = llvm::scc_begin(regionEntry);
803 while (!scc.isAtEnd()) {
804 if (!scc.hasCycle()) {
811 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
815 Block *loopHeader = edges.entryEdges.front().getSuccessor();
818 if (edges.entryEdges.size() > 1) {
820 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
821 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
825 getSwitchValue, getUndefValue, interface);
827 loopHeader = multiplexer.getMultiplexerBlock();
829 cycleBlockSet.insert(loopHeader);
832 FailureOr<StructuredLoopProperties> loopProperties =
834 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
835 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
836 interface, exitCombiner);
837 if (failed(loopProperties))
840 Block *latchBlock = loopProperties->latch;
841 Block *exitBlock = loopProperties->exitBlock;
842 cycleBlockSet.insert(latchBlock);
843 cycleBlockSet.insert(loopHeader);
847 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
851 auto *newLoopParentBlock =
new Block;
858 loopBody.
push_back(blocks.remove(loopHeader));
859 for (
Block *block : cycleBlockSet)
860 if (block != latchBlock && block != loopHeader)
861 loopBody.
push_back(blocks.remove(block));
863 loopBody.
push_back(blocks.remove(latchBlock));
869 FailureOr<Operation *> structuredLoopOp =
871 builder, oldTerminator, newLoopParentBlock->getArguments(),
872 loopProperties->condition, iterationValues, std::move(loopBody));
873 if (failed(structuredLoopOp))
875 oldTerminator->
erase();
877 newSubRegions.push_back(loopHeader);
879 for (
auto &&[oldValue, newValue] : llvm::zip(
880 exitBlock->
getArguments(), (*structuredLoopOp)->getResults()))
881 oldValue.replaceAllUsesWith(newValue);
885 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
889 return newSubRegions;
901 Region &conditionalRegion) {
902 Block *singleExitBlock =
nullptr;
903 std::optional<Edge> previousEdgeToContinuation;
905 branchRegion.front()->getParent()->getBlocks();
906 for (
Block *block : branchRegion) {
908 if (edge.getSuccessor() != continuation)
911 if (!previousEdgeToContinuation) {
912 previousEdgeToContinuation = edge;
918 if (!singleExitBlock) {
919 singleExitBlock =
new Block;
921 previousEdgeToContinuation->setSuccessor(singleExitBlock);
922 createdEmptyBlocks.emplace_back(singleExitBlock,
926 edge.setSuccessor(singleExitBlock);
929 conditionalRegion.
push_back(parentBlockList.remove(block));
933 conditionalRegion.
push_back(singleExitBlock);
955 for (
auto &&[oldValue, newValue] : llvm::zip(
971 notContinuation.insert(regionEntry);
974 for (
auto &&[blockList, succ] :
975 llvm::zip(successorBranchRegions, regionEntry->
getSuccessors())) {
978 if (succ->getSinglePredecessor() != regionEntry)
984 blockList.push_back(curr->getBlock());
985 notContinuation.insert(curr->getBlock());
1052 bool continuationPostDominatesAllRegions =
true;
1053 bool noSuccessorHasContinuationEdge =
true;
1054 for (
auto &&[entryEdge, branchRegion] :
1055 llvm::zip(
successorEdges(regionEntry), successorBranchRegions)) {
1059 if (branchRegion.empty()) {
1060 continuationEdges.push_back(entryEdge);
1061 noSuccessorHasContinuationEdge =
false;
1065 for (
Block *block : branchRegion) {
1071 continuationPostDominatesAllRegions =
false;
1074 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1080 if (notContinuation.contains(edge.getSuccessor()))
1083 continuationEdges.push_back(edge);
1084 noSuccessorHasContinuationEdge =
false;
1090 if (noSuccessorHasContinuationEdge)
1093 Block *continuation = llvm::find_singleton<Block>(
1094 continuationEdges, [](Edge edge,
bool) {
return edge.getSuccessor(); },
1099 if (!continuation || !continuationPostDominatesAllRegions) {
1101 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1102 continuationEdges, getSwitchValue, getUndefValue, interface);
1103 continuation = multiplexer.getMultiplexerBlock();
1107 if (!continuationPostDominatesAllRegions) {
1121 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1122 for (
auto &&[branchRegion, entryEdge, conditionalRegion] :
1124 conditionalRegions)) {
1125 if (branchRegion.empty()) {
1128 createdEmptyBlocks.emplace_back(
1129 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1130 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1139 Block *subRegionEntryBlock = &conditionalRegion.
front();
1140 for (
auto &&[oldValue, newValue] :
1142 entryEdge.getSuccessorOperands()))
1147 newSubRegions.push_back(subRegionEntryBlock);
1165 for (
Region &conditionalRegion : conditionalRegions)
1167 conditionalRegion.getBlocks());
1170 structuredCondOp = *
result;
1174 for (
auto &&[block, valueRange] : createdEmptyBlocks) {
1177 structuredCondOp->
getLoc(), builder, structuredCondOp,
nullptr,
1188 assert(user->getNumSuccessors() == 1);
1191 user->getLoc(), builder, structuredCondOp, user,
1198 for (
auto &&[oldValue, newValue] :
1206 continuation->
erase();
1210 newSubRegions.push_back(regionEntry);
1212 return newSubRegions;
1222 ReturnLikeExitCombiner exitCombiner(region, interface);
1227 exitCombiner.combineExit(block.
getTerminator(), getSwitchValue);
1230 return exitCombiner;
1240 "transformation does not support unreachable blocks");
1249 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1250 if (!branchOpInterface) {
1251 operation->
emitOpError(
"transformation does not support terminators with "
1252 "successors not implementing BranchOpInterface");
1258 branchOpInterface->emitOpError(
1259 "transformation does not support terminators with side effects");
1273 branchOpInterface->emitOpError(
"transformation does not support "
1274 "operations with operation-produced "
1275 "successor operands");
1280 if (
result.wasInterrupted())
1290 "cannot convert unknown control flow op to structured control flow");
1307 auto getUndefValue = [&](
Type type) {
1308 auto [iter,
inserted] = typedUndefCache.try_emplace(type);
1310 return iter->second;
1316 return iter->second;
1322 auto getSwitchValue = [&](
unsigned value) {
1323 if (value < switchValueCache.size())
1324 if (switchValueCache[value])
1325 return switchValueCache[value];
1329 switchValueCache.resize(
1330 std::max<size_t>(switchValueCache.size(), value + 1));
1332 switchValueCache[value] =
1334 return switchValueCache[value];
1337 ReturnLikeExitCombiner exitCombiner =
1345 while (!workList.empty()) {
1346 Block *current = workList.pop_back_val();
1350 FailureOr<SmallVector<Block *>> newRegions =
1352 interface, dominanceInfo, exitCombiner);
1353 if (failed(newRegions))
1358 llvm::append_range(workList, *newRegions);
1361 if (!newRegions->empty())
1365 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1366 if (failed(newRegions))
1372 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 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.
static ReturnLikeExitCombiner createSingleExitBlocksForReturnLike(Region ®ion, function_ref< Value(unsigned)> getSwitchValue, CFGToSCFInterface &interface)
Transforms the region to only have a single block for every kind of return-like operation that all pr...
*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)
bool isEntryBlock()
Return if this block is the entry block in the parent region.
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 ...
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.