120 #include "llvm/ADT/DepthFirstIterator.h"
121 #include "llvm/ADT/MapVector.h"
122 #include "llvm/ADT/SCCIterator.h"
123 #include "llvm/ADT/SetVector.h"
125 using namespace mlir;
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 {
177 void setSuccessor(
Block *block)
const {
212 class EdgeMultiplexer {
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(
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.");
279 unsigned extraArgsBeginIndex =
280 multiplexerBlock->getNumArguments() - extraArgs.size();
282 std::optional<unsigned> discriminatorIndex =
283 discriminator ? extraArgsBeginIndex - 1 : std::optional<unsigned>{};
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);
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) {
407 if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
408 rhs == getTombstoneKey() || rhs == getEmptyKey())
419 class ReturnLikeExitCombiner {
422 : topLevelRegion(topLevelRegion), interface(interface) {}
426 void combineExit(
Operation *returnLikeOp,
428 auto [iter, inserted] = returnLikeToCombinedExit.try_emplace(returnLikeOp);
429 if (!inserted && iter->first == returnLikeOp)
432 Block *exitBlock = iter->second;
434 exitBlock =
new Block;
435 iter->second = exitBlock;
445 getSwitchValue(0), exitBlock,
449 returnLikeOp->
erase();
461 llvm::SmallDenseMap<Operation *, Block *, 4, ReturnLikeOpEquivalence>
462 returnLikeToCombinedExit;
472 [=](
unsigned index) { return Edge(block, index); });
483 for (
Block *block : cycles) {
485 if (cycles.contains(*pred))
488 result.entryEdges.emplace_back(*pred, pred.getSuccessorIndex());
489 entryBlocks.insert(block);
493 if (cycles.contains(succ))
496 result.exitEdges.emplace_back(block, succIndex);
501 for (
Block *block : cycles) {
503 if (!entryBlocks.contains(succ))
506 result.backEdges.emplace_back(block, succIndex);
515 static EdgeMultiplexer
520 auto result = EdgeMultiplexer::create(
521 loc, llvm::map_to_vector(entryEdges, std::mem_fn(&Edge::getSuccessor)),
522 getSwitchValue, getUndefValue);
526 for (Edge edge : entryEdges)
527 result.redirectEdge(edge);
530 result.createSwitch(loc, builder, interface);
540 struct StructuredLoopProperties {
556 ReturnLikeExitCombiner &exitCombiner) {
557 assert(llvm::all_equal(
558 llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor))) &&
559 "All repetition edges must lead to the single loop header");
568 successors, llvm::map_range(backEdges, std::mem_fn(&Edge::getSuccessor)));
570 successors, llvm::map_range(exitEdges, std::mem_fn(&Edge::getSuccessor)));
572 EdgeMultiplexer::create(loc, successors, getSwitchValue, getUndefValue,
575 auto *latchBlock = multiplexer.getMultiplexerBlock();
578 auto *exitBlock =
new Block;
582 Block *loopHeader = backEdges.front().getSuccessor();
588 for (Edge backEdge : backEdges)
589 multiplexer.redirectEdge(backEdge, getSwitchValue(1));
592 for (Edge exitEdge : exitEdges)
593 multiplexer.redirectEdge(exitEdge, getSwitchValue(0));
597 Value shouldRepeat = latchBlock->getArguments().back();
601 loc, builder, shouldRepeat, loopHeader,
609 if (!exitEdges.empty()) {
618 multiplexer.createSwitch(loc, builder, interface, excluded);
624 loc, builder, *latchBlock->getParent());
625 if (failed(terminator))
629 exitCombiner.combineExit(*terminator, getSwitchValue);
633 return StructuredLoopProperties{latchBlock, shouldRepeat,
656 const llvm::SmallSetVector<Block *, 4> &loopBlocks,
661 "Exit block must have only latch as predecessor at this point");
663 "Exit block mustn't have any block arguments at this point");
665 unsigned loopHeaderIndex = 0;
666 unsigned exitBlockIndex = 1;
668 std::swap(loopHeaderIndex, exitBlockIndex);
670 assert(latch->
getSuccessor(loopHeaderIndex) == loopHeader);
671 assert(latch->
getSuccessor(exitBlockIndex) == exitBlock);
683 for (
Value arg : loopHeaderSuccessorOperands) {
685 exitBlockSuccessorOperands.
append(arg);
686 arg.replaceUsesWithIf(exitArg, [&](
OpOperand &use) {
703 for (
Block *loopBlock : loopBlocks) {
707 llvm::SmallDenseMap<Block *, bool> dominanceCache;
709 auto loopBlockDominates = [&](
Block *block) {
710 auto [iter, inserted] = dominanceCache.try_emplace(block);
713 iter->second = dominanceInfo.
dominates(loopBlock, block);
717 auto checkValue = [&](
Value value) {
719 for (
OpOperand &use : llvm::make_early_inc_range(value.getUses())) {
723 Block *currBlock = use.getOwner()->getBlock();
726 if (loopBlocks.contains(currBlock))
730 if (!blockArgument) {
732 exitBlock->
addArgument(value.getType(), value.getLoc());
733 loopHeader->
addArgument(value.getType(), value.getLoc());
742 Value argument = value;
743 if (value.getParentBlock() != latch &&
745 return !loopBlockDominates(pred);
747 argument = latch->
addArgument(value.getType(), value.getLoc());
750 Value succOperand = value;
751 if (!loopBlockDominates(*iter))
752 succOperand = getUndefValue(value.getType());
759 loopHeaderSuccessorOperands.push_back(argument);
761 edge.getMutableSuccessorOperands().append(argument);
764 use.set(blockArgument);
768 if (loopBlock == latch)
769 llvm::for_each(latchBlockArgumentsPrior, checkValue);
770 else if (loopBlock == loopHeader)
771 llvm::for_each(loopHeaderArgumentsPrior, checkValue);
773 llvm::for_each(loopBlock->getArguments(), checkValue);
776 llvm::for_each(op.getResults(), checkValue);
789 succOps.
append(llvm::map_to_vector(
791 [&](
BlockArgument arg) { return getUndefValue(arg.getType()); }));
794 return loopHeaderSuccessorOperands;
803 DominanceInfo &dominanceInfo, ReturnLikeExitCombiner &exitCombiner) {
805 auto scc = llvm::scc_begin(regionEntry);
806 while (!scc.isAtEnd()) {
807 if (!scc.hasCycle()) {
814 llvm::SmallSetVector<Block *, 4> cycleBlockSet(scc->begin(), scc->end());
821 if (edges.entryEdges.size() > 1) {
823 llvm::append_range(edgesToEntryBlocks, edges.entryEdges);
824 llvm::append_range(edgesToEntryBlocks, edges.backEdges);
828 getSwitchValue, getUndefValue, interface);
830 loopHeader = multiplexer.getMultiplexerBlock();
832 cycleBlockSet.insert(loopHeader);
835 FailureOr<StructuredLoopProperties> loopProperties =
837 edges.backEdges.front().getFromBlock()->getTerminator()->getLoc(),
838 edges.backEdges, edges.exitEdges, getSwitchValue, getUndefValue,
839 interface, exitCombiner);
840 if (failed(loopProperties))
843 Block *latchBlock = loopProperties->latch;
844 Block *exitBlock = loopProperties->exitBlock;
845 cycleBlockSet.insert(latchBlock);
846 cycleBlockSet.insert(loopHeader);
850 loopHeader, exitBlock, cycleBlockSet, getUndefValue, dominanceInfo);
854 auto *newLoopParentBlock =
new Block;
861 loopBody.
push_back(blocks.remove(loopHeader));
862 for (
Block *block : cycleBlockSet)
863 if (block != latchBlock && block != loopHeader)
864 loopBody.
push_back(blocks.remove(block));
866 loopBody.
push_back(blocks.remove(latchBlock));
872 FailureOr<Operation *> structuredLoopOp =
874 builder, oldTerminator, newLoopParentBlock->getArguments(),
875 loopProperties->condition, iterationValues, std::move(loopBody));
876 if (failed(structuredLoopOp))
878 oldTerminator->
erase();
880 newSubRegions.push_back(loopHeader);
882 for (
auto &&[oldValue, newValue] : llvm::zip(
883 exitBlock->
getArguments(), (*structuredLoopOp)->getResults()))
884 oldValue.replaceAllUsesWith(newValue);
888 newLoopParentBlock->getOperations().splice(newLoopParentBlock->end(),
892 return newSubRegions;
904 Region &conditionalRegion) {
905 Block *singleExitBlock =
nullptr;
906 std::optional<Edge> previousEdgeToContinuation;
908 branchRegion.front()->getParent()->getBlocks();
909 for (
Block *block : branchRegion) {
911 if (edge.getSuccessor() != continuation)
914 if (!previousEdgeToContinuation) {
915 previousEdgeToContinuation = edge;
921 if (!singleExitBlock) {
922 singleExitBlock =
new Block;
924 previousEdgeToContinuation->setSuccessor(singleExitBlock);
925 createdEmptyBlocks.emplace_back(singleExitBlock,
929 edge.setSuccessor(singleExitBlock);
932 conditionalRegion.
push_back(parentBlockList.remove(block));
936 conditionalRegion.
push_back(singleExitBlock);
958 for (
auto &&[oldValue, newValue] : llvm::zip(
974 notContinuation.insert(regionEntry);
977 for (
auto &&[blockList, succ] :
978 llvm::zip(successorBranchRegions, regionEntry->
getSuccessors())) {
981 if (succ->getSinglePredecessor() != regionEntry)
987 blockList.push_back(curr->getBlock());
988 notContinuation.insert(curr->getBlock());
1055 bool continuationPostDominatesAllRegions =
true;
1056 bool noSuccessorHasContinuationEdge =
true;
1057 for (
auto &&[entryEdge, branchRegion] :
1058 llvm::zip(
successorEdges(regionEntry), successorBranchRegions)) {
1062 if (branchRegion.empty()) {
1063 continuationEdges.push_back(entryEdge);
1064 noSuccessorHasContinuationEdge =
false;
1068 for (
Block *block : branchRegion) {
1074 continuationPostDominatesAllRegions =
false;
1077 continuationEdges.emplace_back(*iter, iter.getSuccessorIndex());
1083 if (notContinuation.contains(edge.getSuccessor()))
1086 continuationEdges.push_back(edge);
1087 noSuccessorHasContinuationEdge =
false;
1093 if (noSuccessorHasContinuationEdge)
1096 Block *continuation = llvm::find_singleton<Block>(
1097 continuationEdges, [](Edge edge,
bool) {
return edge.getSuccessor(); },
1102 if (!continuation || !continuationPostDominatesAllRegions) {
1104 continuationEdges.front().getFromBlock()->getTerminator()->getLoc(),
1105 continuationEdges, getSwitchValue, getUndefValue, interface);
1106 continuation = multiplexer.getMultiplexerBlock();
1110 if (!continuationPostDominatesAllRegions) {
1124 std::vector<Region> conditionalRegions(successorBranchRegions.size());
1125 for (
auto &&[branchRegion, entryEdge, conditionalRegion] :
1127 conditionalRegions)) {
1128 if (branchRegion.empty()) {
1131 createdEmptyBlocks.emplace_back(
1132 new Block, llvm::to_vector(entryEdge.getSuccessorOperands()));
1133 conditionalRegion.push_back(createdEmptyBlocks.back().first);
1142 Block *subRegionEntryBlock = &conditionalRegion.
front();
1143 for (
auto &&[oldValue, newValue] :
1145 entryEdge.getSuccessorOperands()))
1150 newSubRegions.push_back(subRegionEntryBlock);
1161 structuredCondOp = *result;
1165 for (
auto &&[block, valueRange] : createdEmptyBlocks) {
1168 structuredCondOp->
getLoc(), builder, structuredCondOp,
nullptr,
1179 assert(user->getNumSuccessors() == 1);
1182 user->getLoc(), builder, structuredCondOp, user,
1189 for (
auto &&[oldValue, newValue] :
1191 oldValue.replaceAllUsesWith(newValue);
1197 continuation->
erase();
1201 newSubRegions.push_back(regionEntry);
1203 return newSubRegions;
1213 ReturnLikeExitCombiner exitCombiner(region, interface);
1218 exitCombiner.combineExit(block.
getTerminator(), getSwitchValue);
1221 return exitCombiner;
1230 "transformation does not support unreachable blocks");
1239 auto branchOpInterface = dyn_cast<BranchOpInterface>(operation);
1240 if (!branchOpInterface) {
1241 operation->
emitOpError(
"transformation does not support terminators with "
1242 "successors not implementing BranchOpInterface");
1248 branchOpInterface->emitOpError(
1249 "transformation does not support terminators with side effects");
1263 branchOpInterface->emitOpError(
"transformation does not support "
1264 "operations with operation-produced "
1265 "successor operands");
1283 auto getUndefValue = [&](
Type type) {
1284 auto [iter, inserted] = typedUndefCache.try_emplace(type);
1286 return iter->second;
1292 return iter->second;
1298 auto getSwitchValue = [&](
unsigned value) {
1299 if (value < switchValueCache.size())
1300 if (switchValueCache[value])
1301 return switchValueCache[value];
1305 switchValueCache.resize(
1306 std::max<size_t>(switchValueCache.size(), value + 1));
1308 switchValueCache[value] =
1310 return switchValueCache[value];
1313 ReturnLikeExitCombiner exitCombiner =
1321 while (!workList.empty()) {
1322 Block *current = workList.pop_back_val();
1326 FailureOr<SmallVector<Block *>> newRegions =
1328 interface, dominanceInfo, exitCombiner);
1329 if (failed(newRegions))
1334 llvm::append_range(workList, *newRegions);
1337 if (!newRegions->empty())
1341 current, getSwitchValue, getUndefValue, interface, dominanceInfo);
1342 if (failed(newRegions))
1348 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.