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) {
407 if (
lhs == getEmptyKey() ||
rhs == getEmptyKey())
410 const_cast<Operation *
>(
lhs),
const_cast<Operation *
>(
rhs),
418class ReturnLikeExitCombiner {
420 ReturnLikeExitCombiner(Region &topLevelRegion, CFGToSCFInterface &interface)
421 : topLevelRegion(topLevelRegion), interface(interface) {}
425 void combineExit(Operation *returnLikeOp,
427 auto [iter,
inserted] = returnLikeToCombinedExit.try_emplace(returnLikeOp);
428 if (!
inserted && iter->first == returnLikeOp)
431 Block *exitBlock = iter->second;
433 exitBlock =
new Block;
434 iter->second = exitBlock;
443 interface.createSingleDestinationBranch(returnLikeOp->
getLoc(), builder,
444 getSwitchValue(0), exitBlock,
448 returnLikeOp->
erase();
460 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
461 returnLikeToCombinedExit;
462 Region &topLevelRegion;
463 CFGToSCFInterface &interface;
471 [=](
unsigned index) { return Edge(block, index); });
482 for (
Block *block : cycles) {
484 if (cycles.contains(*pred))
487 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
488 entryBlocks.insert(block);
491 for (
auto &&[succIndex, succ] : llvm::enumerate(block->
getSuccessors())) {
492 if (cycles.contains(succ))
495 result.exitEdges.emplace_back(block, succIndex);
500 for (
Block *block : cycles) {
501 for (
auto &&[succIndex, succ] : llvm::enumerate(block->
getSuccessors())) {
502 if (!entryBlocks.contains(succ))
505 result.backEdges.emplace_back(block, succIndex);
514static EdgeMultiplexer
519 auto result = EdgeMultiplexer::create(
520 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
521 getSwitchValue, getUndefValue);
525 for (Edge edge : entryEdges)
526 result.redirectEdge(edge);
529 result.createSwitch(loc, builder, interface);
539struct StructuredLoopProperties {
555 ReturnLikeExitCombiner &exitCombiner) {
556 assert(llvm::all_equal(
557 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
558 "All repetition edges must lead to the single loop header");
567 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
569 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
571 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
574 auto *latchBlock = multiplexer.getMultiplexerBlock();
577 auto *exitBlock =
new Block;
581 Block *loopHeader = backEdges.front().getSuccessor();
587 for (Edge backEdge : backEdges)
588 multiplexer.redirectEdge(backEdge, getSwitchValue(1));
591 for (Edge exitEdge : exitEdges)
592 multiplexer.redirectEdge(exitEdge, getSwitchValue(0));
596 Value shouldRepeat = latchBlock->getArguments().back();
600 loc, builder, shouldRepeat, loopHeader,
608 if (!exitEdges.empty()) {
617 multiplexer.createSwitch(loc, builder, interface, excluded);
623 loc, builder, *latchBlock->getParent());
624 if (failed(terminator))
628 exitCombiner.combineExit(*terminator, getSwitchValue);
632 return StructuredLoopProperties{latchBlock, shouldRepeat,
655 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
660 "Exit block must have only latch as predecessor at this point");
662 "Exit block mustn't have any block arguments at this point");
664 unsigned loopHeaderIndex = 0;
665 unsigned exitBlockIndex = 1;
667 std::swap(loopHeaderIndex, exitBlockIndex);
669 assert(latch->
getSuccessor(loopHeaderIndex) == loopHeader);
670 assert(latch->
getSuccessor(exitBlockIndex) == exitBlock);
682 for (
Value arg : loopHeaderSuccessorOperands) {
684 exitBlockSuccessorOperands.
append(arg);
685 arg.replaceUsesWithIf(exitArg, [&](
OpOperand &use) {
702 for (
Block *loopBlock : loopBlocks) {
706 llvm::SmallDenseMap<Block *, bool> dominanceCache;
708 auto loopBlockDominates = [&](
Block *block) {
709 auto [iter,
inserted] = dominanceCache.try_emplace(block);
712 iter->second = dominanceInfo.
dominates(loopBlock, block);
716 auto checkValue = [&](
Value value) {
718 for (
OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
722 Block *currBlock = use.getOwner()->getBlock();
725 if (loopBlocks.contains(currBlock))
729 if (!blockArgument) {
731 exitBlock->
addArgument(value.getType(), value.getLoc());
732 loopHeader->
addArgument(value.getType(), value.getLoc());
741 Value argument = value;
742 if (value.getParentBlock() != latch &&
744 return !loopBlockDominates(pred);
746 argument = latch->
addArgument(value.getType(), value.getLoc());
749 Value succOperand = value;
750 if (!loopBlockDominates(*iter))
751 succOperand = getUndefValue(value.getType());
758 loopHeaderSuccessorOperands.push_back(argument);
760 edge.getMutableSuccessorOperands().append(argument);
763 use.set(blockArgument);
767 if (loopBlock == latch)
768 llvm::for_each(latchBlockArgumentsPrior, checkValue);
769 else if (loopBlock == loopHeader)
770 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
772 llvm::for_each(loopBlock->getArguments(), checkValue);
775 llvm::for_each(op.getResults(), checkValue);
788 succOps.
append(llvm::map_to_vector(
790 [&](
BlockArgument arg) { return getUndefValue(arg.getType()); }));
793 return loopHeaderSuccessorOperands;
802 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
804 auto scc = llvm::scc_begin(regionEntry);
805 while (!scc.isAtEnd()) {
806 if (!scc.hasCycle()) {
813 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
817 Block *loopHeader = edges.entryEdges.front().getSuccessor();
820 if (edges.entryEdges.size() > 1) {
822 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
823 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
827 getSwitchValue, getUndefValue, interface);
829 loopHeader = multiplexer.getMultiplexerBlock();
831 cycleBlockSet.insert(loopHeader);
834 FailureOr<StructuredLoopProperties> loopProperties =
836 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
837 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
838 interface, exitCombiner);
839 if (failed(loopProperties))
842 Block *latchBlock = loopProperties->latch;
843 Block *exitBlock = loopProperties->exitBlock;
844 cycleBlockSet.insert(latchBlock);
845 cycleBlockSet.insert(loopHeader);
849 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
853 auto *newLoopParentBlock =
new Block;
860 loopBody.
push_back(blocks.remove(loopHeader));
861 for (
Block *block : cycleBlockSet)
862 if (block != latchBlock && block != loopHeader)
863 loopBody.
push_back(blocks.remove(block));
865 loopBody.
push_back(blocks.remove(latchBlock));
871 FailureOr<Operation *> structuredLoopOp =
873 builder, oldTerminator, newLoopParentBlock->getArguments(),
874 loopProperties->condition, iterationValues, std::move(loopBody));
875 if (failed(structuredLoopOp))
877 oldTerminator->
erase();
879 newSubRegions.push_back(loopHeader);
881 for (
auto &&[oldValue, newValue] : llvm::zip(
882 exitBlock->
getArguments(), (*structuredLoopOp)->getResults()))
883 oldValue.replaceAllUsesWith(newValue);
887 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
891 return newSubRegions;
903 Region &conditionalRegion) {
904 Block *singleExitBlock =
nullptr;
905 std::optional<Edge> previousEdgeToContinuation;
907 branchRegion.front()->getParent()->getBlocks();
908 for (
Block *block : branchRegion) {
910 if (edge.getSuccessor() != continuation)
913 if (!previousEdgeToContinuation) {
914 previousEdgeToContinuation = edge;
920 if (!singleExitBlock) {
921 singleExitBlock =
new Block;
923 previousEdgeToContinuation->setSuccessor(singleExitBlock);
924 createdEmptyBlocks.emplace_back(singleExitBlock,
928 edge.setSuccessor(singleExitBlock);
931 conditionalRegion.
push_back(parentBlockList.remove(block));
935 conditionalRegion.
push_back(singleExitBlock);
957 for (
auto &&[oldValue, newValue] : llvm::zip(
973 notContinuation.insert(regionEntry);
976 for (
auto &&[blockList, succ] :
977 llvm::zip(successorBranchRegions, regionEntry->
getSuccessors())) {
980 if (succ->getSinglePredecessor() != regionEntry)
986 blockList.push_back(curr->getBlock());
987 notContinuation.insert(curr->getBlock());
1054 bool continuationPostDominatesAllRegions =
true;
1055 bool noSuccessorHasContinuationEdge =
true;
1056 for (
auto &&[entryEdge, branchRegion] :
1057 llvm::zip(
successorEdges(regionEntry), successorBranchRegions)) {
1061 if (branchRegion.empty()) {
1062 continuationEdges.push_back(entryEdge);
1063 noSuccessorHasContinuationEdge =
false;
1067 for (
Block *block : branchRegion) {
1073 continuationPostDominatesAllRegions =
false;
1076 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1082 if (notContinuation.contains(edge.getSuccessor()))
1085 continuationEdges.push_back(edge);
1086 noSuccessorHasContinuationEdge =
false;
1092 if (noSuccessorHasContinuationEdge)
1095 Block *continuation = llvm::find_singleton<Block>(
1096 continuationEdges, [](Edge edge,
bool) {
return edge.getSuccessor(); },
1101 if (!continuation || !continuationPostDominatesAllRegions) {
1103 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1104 continuationEdges, getSwitchValue, getUndefValue, interface);
1105 continuation = multiplexer.getMultiplexerBlock();
1109 if (!continuationPostDominatesAllRegions) {
1123 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1124 for (
auto &&[branchRegion, entryEdge, conditionalRegion] :
1126 conditionalRegions)) {
1127 if (branchRegion.empty()) {
1130 createdEmptyBlocks.emplace_back(
1131 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1132 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1141 Block *subRegionEntryBlock = &conditionalRegion.
front();
1142 for (
auto &&[oldValue, newValue] :
1144 entryEdge.getSuccessorOperands()))
1149 newSubRegions.push_back(subRegionEntryBlock);
1167 for (
Region &conditionalRegion : conditionalRegions)
1169 conditionalRegion.getBlocks());
1172 structuredCondOp = *
result;
1176 for (
auto &&[block, valueRange] : createdEmptyBlocks) {
1179 structuredCondOp->
getLoc(), builder, structuredCondOp,
nullptr,
1190 assert(user->getNumSuccessors() == 1);
1193 user->getLoc(), builder, structuredCondOp, user,
1200 for (
auto &&[oldValue, newValue] :
1208 continuation->
erase();
1212 newSubRegions.push_back(regionEntry);
1214 return newSubRegions;
1224 ReturnLikeExitCombiner exitCombiner(region, interface);
1229 exitCombiner.combineExit(block.
getTerminator(), getSwitchValue);
1232 return exitCombiner;
1242 "transformation does not support unreachable blocks");
1251 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1252 if (!branchOpInterface) {
1253 operation->
emitOpError(
"transformation does not support terminators with "
1254 "successors not implementing BranchOpInterface");
1260 branchOpInterface->emitOpError(
1261 "transformation does not support terminators with side effects");
1275 branchOpInterface->emitOpError(
"transformation does not support "
1276 "operations with operation-produced "
1277 "successor operands");
1282 if (
result.wasInterrupted())
1292 "cannot convert unknown control flow op to structured control flow");
1309 auto getUndefValue = [&](
Type type) {
1310 auto [iter,
inserted] = typedUndefCache.try_emplace(type);
1312 return iter->second;
1318 return iter->second;
1324 auto getSwitchValue = [&](
unsigned value) {
1325 if (value < switchValueCache.size())
1326 if (switchValueCache[value])
1327 return switchValueCache[value];
1331 switchValueCache.resize(
1332 std::max<size_t>(switchValueCache.size(), value + 1));
1334 switchValueCache[value] =
1336 return switchValueCache[value];
1339 ReturnLikeExitCombiner exitCombiner =
1347 while (!workList.empty()) {
1348 Block *current = workList.pop_back_val();
1352 FailureOr<SmallVector<Block *>> newRegions =
1354 interface, dominanceInfo, exitCombiner);
1355 if (failed(newRegions))
1360 llvm::append_range(workList, *newRegions);
1363 if (!newRegions->empty())
1367 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1368 if (failed(newRegions))
1374 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.