121 #include "llvm/ADT/DepthFirstIterator.h"
122 #include "llvm/ADT/MapVector.h"
123 #include "llvm/ADT/SCCIterator.h"
124 #include "llvm/ADT/SetVector.h"
125 #include "llvm/ADT/SmallPtrSet.h"
127 using namespace mlir;
134 auto branchOpInterface = cast<BranchOpInterface>(block->
getTerminator());
136 branchOpInterface.getSuccessorOperands(successorIndex);
143 unsigned successorIndex) {
161 unsigned successorIndex;
166 Edge(
Block *fromBlock,
unsigned int successorIndex)
167 : fromBlock(fromBlock), successorIndex(successorIndex) {}
170 Block *getFromBlock()
const {
return fromBlock; }
173 Block *getSuccessor()
const {
179 void setSuccessor(
Block *block)
const {
214 class EdgeMultiplexer {
231 assert(!entryBlocks.empty() &&
"Require at least one entry block");
233 auto *multiplexerBlock =
new Block;
234 multiplexerBlock->
insertAfter(entryBlocks.front());
241 llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
242 for (
Block *entryBlock : entryBlocks) {
243 auto [iter, inserted] = blockArgMapping.insert(
244 {entryBlock, multiplexerBlock->getNumArguments()});
254 if (blockArgMapping.size() > 1)
256 multiplexerBlock->addArgument(getSwitchValue(0).
getType(), loc);
258 multiplexerBlock->addArguments(
261 return EdgeMultiplexer(multiplexerBlock, getSwitchValue, getUndefValue,
262 std::move(blockArgMapping), discriminator);
266 Block *getMultiplexerBlock()
const {
return multiplexerBlock; }
273 void redirectEdge(Edge edge,
ValueRange extraArgs = {})
const {
274 const auto *result = blockArgMapping.find(edge.getSuccessor());
275 assert(result != blockArgMapping.end() &&
276 "Edge was not originally passed to `create` method.");
281 unsigned extraArgsBeginIndex =
282 multiplexerBlock->getNumArguments() - extraArgs.size();
284 std::optional<unsigned> discriminatorIndex =
285 discriminator ? extraArgsBeginIndex - 1 : std::optional<unsigned>{};
288 for (
BlockArgument argument : multiplexerBlock->getArguments()) {
289 unsigned index = argument.getArgNumber();
290 if (index >= result->second &&
291 index < result->second + edge.getSuccessor()->getNumArguments()) {
293 newSuccOperands[index] =
294 successorOperands[index - result->second].get();
299 if (index == discriminatorIndex) {
300 newSuccOperands[index] =
301 getSwitchValue(result - blockArgMapping.begin());
306 if (index >= extraArgsBeginIndex) {
307 newSuccOperands[index] = extraArgs[index - extraArgsBeginIndex];
313 newSuccOperands[index] = getUndefValue(argument.getType());
316 edge.setSuccessor(multiplexerBlock);
317 successorOperands.
assign(newSuccOperands);
335 auto &&[succ, offset] = pair;
336 if (excluded.contains(succ))
339 caseValues.push_back(index);
340 caseArguments.push_back(multiplexerBlock->getArguments().slice(
341 offset, succ->getNumArguments()));
342 caseDestinations.push_back(succ);
347 Value realDiscriminator = discriminator;
348 if (!realDiscriminator || caseArguments.size() == 1)
349 realDiscriminator = getSwitchValue(0);
351 caseValues.pop_back();
352 Block *defaultDest = caseDestinations.pop_back_val();
353 ValueRange defaultArgs = caseArguments.pop_back_val();
356 "Edges need to be redirected prior to creating switch.");
358 caseDestinations, caseArguments, defaultDest,
364 Block *multiplexerBlock;
375 llvm::SmallMapVector<Block *, unsigned, 4> blockArgMapping;
381 EdgeMultiplexer(
Block *multiplexerBlock,
384 llvm::SmallMapVector<Block *, unsigned, 4> &&entries,
386 : multiplexerBlock(multiplexerBlock), getSwitchValue(getSwitchValue),
387 getUndefValue(getUndefValue), blockArgMapping(std::move(entries)),
388 discriminator(dispatchFlag) {}
398 static unsigned getHashValue(
const Operation *opC) {
409 if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
410 rhs == getTombstoneKey() || rhs == getEmptyKey())
421 class ReturnLikeExitCombiner {
424 : topLevelRegion(topLevelRegion), interface(interface) {}
428 void combineExit(
Operation *returnLikeOp,
430 auto [iter, inserted] =
431 returnLikeToCombinedExit.insert({returnLikeOp,
nullptr});
432 if (!inserted && iter->first == returnLikeOp)
435 Block *exitBlock = iter->second;
437 exitBlock =
new Block;
438 iter->second = exitBlock;
448 getSwitchValue(0), exitBlock,
452 returnLikeOp->
erase();
464 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
465 returnLikeToCombinedExit;
475 [=](
unsigned index) { return Edge(block, index); });
486 for (
Block *block : cycles) {
488 if (cycles.contains(*pred))
491 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
492 entryBlocks.insert(block);
496 if (cycles.contains(succ))
499 result.exitEdges.emplace_back(block, succIndex);
504 for (
Block *block : cycles) {
506 if (!entryBlocks.contains(succ))
509 result.backEdges.emplace_back(block, succIndex);
518 static EdgeMultiplexer
523 auto result = EdgeMultiplexer::create(
524 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
525 getSwitchValue, getUndefValue);
529 for (Edge edge : entryEdges)
530 result.redirectEdge(edge);
533 result.createSwitch(loc, builder, interface);
543 struct StructuredLoopProperties {
559 ReturnLikeExitCombiner &exitCombiner) {
560 assert(llvm::all_equal(
561 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
562 "All repetition edges must lead to the single loop header");
571 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
573 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
575 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
578 auto *latchBlock = multiplexer.getMultiplexerBlock();
581 auto *exitBlock =
new Block;
585 Block *loopHeader = backEdges.front().getSuccessor();
591 for (Edge backEdge : backEdges)
592 multiplexer.redirectEdge(backEdge, getSwitchValue(1));
595 for (Edge exitEdge : exitEdges)
596 multiplexer.redirectEdge(exitEdge, getSwitchValue(0));
600 Value shouldRepeat = latchBlock->getArguments().back();
604 loc, builder, shouldRepeat, loopHeader,
612 if (!exitEdges.empty()) {
621 multiplexer.createSwitch(loc, builder, interface, excluded);
627 loc, builder, *latchBlock->getParent());
628 if (failed(terminator))
632 exitCombiner.combineExit(*terminator, getSwitchValue);
636 return StructuredLoopProperties{latchBlock, shouldRepeat,
659 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
664 "Exit block must have only latch as predecessor at this point");
666 "Exit block mustn't have any block arguments at this point");
668 unsigned loopHeaderIndex = 0;
669 unsigned exitBlockIndex = 1;
671 std::swap(loopHeaderIndex, exitBlockIndex);
673 assert(latch->
getSuccessor(loopHeaderIndex) == loopHeader);
674 assert(latch->
getSuccessor(exitBlockIndex) == exitBlock);
686 for (
Value arg : loopHeaderSuccessorOperands) {
688 exitBlockSuccessorOperands.
append(arg);
689 arg.replaceUsesWithIf(exitArg, [&](
OpOperand &use) {
706 for (
Block *loopBlock : loopBlocks) {
710 llvm::SmallDenseMap<Block *, bool> dominanceCache;
712 auto loopBlockDominates = [&](
Block *block) {
713 auto [iter, inserted] = dominanceCache.insert({block,
false});
716 iter->second = dominanceInfo.
dominates(loopBlock, block);
720 auto checkValue = [&](
Value value) {
722 for (
OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
726 Block *currBlock = use.getOwner()->getBlock();
729 if (loopBlocks.contains(currBlock))
733 if (!blockArgument) {
735 exitBlock->
addArgument(value.getType(), value.getLoc());
736 loopHeader->
addArgument(value.getType(), value.getLoc());
745 Value argument = value;
746 if (value.getParentBlock() != latch &&
748 return !loopBlockDominates(pred);
750 argument = latch->
addArgument(value.getType(), value.getLoc());
753 Value succOperand = value;
754 if (!loopBlockDominates(*iter))
755 succOperand = getUndefValue(value.getType());
762 loopHeaderSuccessorOperands.push_back(argument);
764 edge.getMutableSuccessorOperands().append(argument);
767 use.set(blockArgument);
771 if (loopBlock == latch)
772 llvm::for_each(latchBlockArgumentsPrior, checkValue);
773 else if (loopBlock == loopHeader)
774 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
776 llvm::for_each(loopBlock->getArguments(), checkValue);
779 llvm::for_each(op.getResults(), checkValue);
792 succOps.
append(llvm::map_to_vector(
794 [&](
BlockArgument arg) { return getUndefValue(arg.getType()); }));
797 return loopHeaderSuccessorOperands;
806 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
808 auto scc = llvm::scc_begin(regionEntry);
809 while (!scc.isAtEnd()) {
810 if (!scc.hasCycle()) {
817 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
824 if (edges.entryEdges.size() > 1) {
826 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
827 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
831 getSwitchValue, getUndefValue, interface);
833 loopHeader = multiplexer.getMultiplexerBlock();
835 cycleBlockSet.insert(loopHeader);
838 FailureOr<StructuredLoopProperties> loopProperties =
840 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
841 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
842 interface, exitCombiner);
843 if (failed(loopProperties))
846 Block *latchBlock = loopProperties->latch;
847 Block *exitBlock = loopProperties->exitBlock;
848 cycleBlockSet.insert(latchBlock);
849 cycleBlockSet.insert(loopHeader);
853 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
857 auto *newLoopParentBlock =
new Block;
864 loopBody.
push_back(blocks.remove(loopHeader));
865 for (
Block *block : cycleBlockSet)
866 if (block != latchBlock && block != loopHeader)
867 loopBody.
push_back(blocks.remove(block));
869 loopBody.
push_back(blocks.remove(latchBlock));
875 FailureOr<Operation *> structuredLoopOp =
877 builder, oldTerminator, newLoopParentBlock->getArguments(),
878 loopProperties->condition, iterationValues, std::move(loopBody));
879 if (failed(structuredLoopOp))
881 oldTerminator->
erase();
883 newSubRegions.push_back(loopHeader);
885 for (
auto &&[oldValue, newValue] : llvm::zip(
886 exitBlock->
getArguments(), (*structuredLoopOp)->getResults()))
887 oldValue.replaceAllUsesWith(newValue);
891 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
895 return newSubRegions;
907 Region &conditionalRegion) {
908 Block *singleExitBlock =
nullptr;
909 std::optional<Edge> previousEdgeToContinuation;
911 branchRegion.front()->getParent()->getBlocks();
912 for (
Block *block : branchRegion) {
914 if (edge.getSuccessor() != continuation)
917 if (!previousEdgeToContinuation) {
918 previousEdgeToContinuation = edge;
924 if (!singleExitBlock) {
925 singleExitBlock =
new Block;
927 previousEdgeToContinuation->setSuccessor(singleExitBlock);
928 createdEmptyBlocks.emplace_back(singleExitBlock,
932 edge.setSuccessor(singleExitBlock);
935 conditionalRegion.
push_back(parentBlockList.remove(block));
939 conditionalRegion.
push_back(singleExitBlock);
961 for (
auto &&[oldValue, newValue] : llvm::zip(
977 notContinuation.insert(regionEntry);
980 for (
auto &&[blockList, succ] :
981 llvm::zip(successorBranchRegions, regionEntry->
getSuccessors())) {
984 if (succ->getSinglePredecessor() != regionEntry)
990 blockList.push_back(curr->getBlock());
991 notContinuation.insert(curr->getBlock());
1058 bool continuationPostDominatesAllRegions =
true;
1059 bool noSuccessorHasContinuationEdge =
true;
1060 for (
auto &&[entryEdge, branchRegion] :
1061 llvm::zip(
successorEdges(regionEntry), successorBranchRegions)) {
1065 if (branchRegion.empty()) {
1066 continuationEdges.push_back(entryEdge);
1067 noSuccessorHasContinuationEdge =
false;
1071 for (
Block *block : branchRegion) {
1077 continuationPostDominatesAllRegions =
false;
1080 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1086 if (notContinuation.contains(edge.getSuccessor()))
1089 continuationEdges.push_back(edge);
1090 noSuccessorHasContinuationEdge =
false;
1096 if (noSuccessorHasContinuationEdge)
1099 Block *continuation = llvm::find_singleton<Block>(
1100 continuationEdges, [](Edge edge,
bool) {
return edge.getSuccessor(); },
1105 if (!continuation || !continuationPostDominatesAllRegions) {
1107 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1108 continuationEdges, getSwitchValue, getUndefValue, interface);
1109 continuation = multiplexer.getMultiplexerBlock();
1113 if (!continuationPostDominatesAllRegions) {
1127 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1128 for (
auto &&[branchRegion, entryEdge, conditionalRegion] :
1130 conditionalRegions)) {
1131 if (branchRegion.empty()) {
1134 createdEmptyBlocks.emplace_back(
1135 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1136 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1145 Block *subRegionEntryBlock = &conditionalRegion.
front();
1146 for (
auto &&[oldValue, newValue] :
1148 entryEdge.getSuccessorOperands()))
1153 newSubRegions.push_back(subRegionEntryBlock);
1164 structuredCondOp = *result;
1168 for (
auto &&[block, valueRange] : createdEmptyBlocks) {
1171 structuredCondOp->
getLoc(), builder, structuredCondOp,
nullptr,
1182 assert(user->getNumSuccessors() == 1);
1185 user->getLoc(), builder, structuredCondOp, user,
1192 for (
auto &&[oldValue, newValue] :
1194 oldValue.replaceAllUsesWith(newValue);
1200 continuation->
erase();
1204 newSubRegions.push_back(regionEntry);
1206 return newSubRegions;
1216 ReturnLikeExitCombiner exitCombiner(region, interface);
1221 exitCombiner.combineExit(block.
getTerminator(), getSwitchValue);
1224 return exitCombiner;
1233 "transformation does not support unreachable blocks");
1242 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1243 if (!branchOpInterface) {
1244 operation->
emitOpError(
"transformation does not support terminators with "
1245 "successors not implementing BranchOpInterface");
1251 branchOpInterface->emitOpError(
1252 "transformation does not support terminators with side effects");
1266 branchOpInterface->emitOpError(
"transformation does not support "
1267 "operations with operation-produced "
1268 "successor operands");
1286 auto getUndefValue = [&](
Type type) {
1287 auto [iter, inserted] = typedUndefCache.insert({type,
nullptr});
1289 return iter->second;
1295 return iter->second;
1301 auto getSwitchValue = [&](
unsigned value) {
1302 if (value < switchValueCache.size())
1303 if (switchValueCache[value])
1304 return switchValueCache[value];
1308 switchValueCache.resize(
1309 std::max<size_t>(switchValueCache.size(), value + 1));
1311 switchValueCache[value] =
1313 return switchValueCache[value];
1316 ReturnLikeExitCombiner exitCombiner =
1324 while (!workList.empty()) {
1325 Block *current = workList.pop_back_val();
1329 FailureOr<SmallVector<Block *>> newRegions =
1331 interface, dominanceInfo, exitCombiner);
1332 if (failed(newRegions))
1337 llvm::append_range(workList, *newRegions);
1340 if (!newRegions->empty())
1344 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1345 if (failed(newRegions))
1351 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 LogicalResult checkTransformationPreconditions(Region ®ion)
Checks all preconditions of the transformation prior to any transformations.
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 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 auto successorEdges(Block *block)
Returns a range of all edges from block to each of its successors.
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 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 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 * > > 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 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 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 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...
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()
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.
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.
iterator_range< pred_iterator > getPredecessors()
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'.
OpListType & getOperations()
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 * > createUnreachableTerminator(Location loc, OpBuilder &builder, Region ®ion)=0
Creates a return-like terminator indicating unreachable.
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.
void createSingleDestinationBranch(Location loc, OpBuilder &builder, Value dummyFlag, Block *destination, ValueRange arguments)
Helper function to create an unconditional branch using createCFGSwitchOp.
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 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 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...
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.
OperandRange getAsOperandRange() const
Explicit conversion to an OperandRange.
void assign(ValueRange values)
Assign this range to the given values.
void append(ValueRange values)
Append the given values to the range.
This class helps build Operations.
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.
Block * getSuccessor(unsigned index)
unsigned getNumSuccessors()
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Block * getBlock()
Returns the operation block that contains this operation.
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 setSuccessor(Block *block, unsigned index)
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)
BlockListType & getBlocks()
Location getLoc()
Return a location for this region.
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.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
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()
bool wasInterrupted() const
Returns true if the walk was interrupted.
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.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
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.
FailureOr< bool > transformCFGToSCF(Region ®ion, CFGToSCFInterface &interface, DominanceInfo &dominanceInfo)
Transformation lifting any dialect implementing control flow graph operations to a dialect implementi...
llvm::DomTreeNodeBase< Block > DominanceInfoNode
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.