22#include "llvm/ADT/DepthFirstIterator.h"
23#include "llvm/ADT/PostOrderIterator.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SmallVectorExtras.h"
26#include "llvm/Support/DebugLog.h"
33#define DEBUG_TYPE "region-utils"
37 for (
auto &use : llvm::make_early_inc_range(orig.
getUses())) {
38 if (region.
isAncestor(use.getOwner()->getParentRegion()))
46 "expected isolation limit to be an ancestor of the given region");
53 properAncestors.insert(reg);
59 if (properAncestors.count(operand.get().getParentRegion()))
66 for (
Region ®ion : regions)
73 values.insert(operand->
get());
79 for (
Region ®ion : regions)
95 std::deque<Value> worklist(initialCapturedValues.begin(),
96 initialCapturedValues.end());
102 while (!worklist.empty()) {
103 Value currValue = worklist.front();
104 worklist.pop_front();
105 if (visited.count(currValue))
107 visited.insert(currValue);
110 if (!definingOp || visitedOps.count(definingOp)) {
111 finalCapturedValues.insert(currValue);
114 visitedOps.insert(definingOp);
116 if (!cloneOperationIntoRegion(definingOp)) {
119 finalCapturedValues.insert(currValue);
126 if (visited.count(operand))
128 worklist.push_back(operand);
130 clonedOperations.push_back(definingOp);
147 for (
auto value : finalCapturedValues) {
148 newArgTypes.push_back(value.getType());
149 newArgLocs.push_back(value.getLoc());
153 Block *newEntryBlock =
160 return region.
isAncestor(use.getOwner()->getParentRegion());
163 for (
auto [arg, capturedVal] :
164 llvm::zip(newEntryBlockArgs.take_back(finalCapturedValues.size()),
165 finalCapturedValues)) {
166 map.
map(capturedVal, arg);
170 for (
auto *clonedOp : clonedOperations) {
175 entryBlock, newEntryBlock,
177 return llvm::to_vector(finalCapturedValues);
189 LDBG() <<
"Starting eraseUnreachableBlocks with " << regions.size()
193 llvm::df_iterator_default_set<Block *, 16> reachable;
195 int erasedDeadBlocks = 0;
198 worklist.reserve(regions.size());
199 for (
Region ®ion : regions)
200 worklist.push_back(®ion);
202 LDBG(2) <<
"Initial worklist size: " << worklist.size();
204 while (!worklist.empty()) {
205 Region *region = worklist.pop_back_val();
206 if (region->
empty()) {
207 LDBG(2) <<
"Skipping empty region";
211 LDBG(2) <<
"Processing region with " << region->
getBlocks().size()
214 LDBG(2) <<
" -> for operation: "
221 for (
Region ®ion : op.getRegions())
222 worklist.push_back(®ion);
228 for (
Block *block : depth_first_ext(®ion->
front(), reachable))
231 LDBG(2) <<
"Found " << reachable.size() <<
" reachable blocks out of "
232 << region->
getBlocks().size() <<
" total blocks";
236 for (
Block &block : llvm::make_early_inc_range(*region)) {
237 if (!reachable.count(&block)) {
238 LDBG() <<
"Erasing unreachable block: " << █
239 block.dropAllDefinedValueUses();
247 for (
Region ®ion : op.getRegions())
248 worklist.push_back(®ion);
252 LDBG() <<
"Finished eraseUnreachableBlocks, erased " << erasedDeadBlocks
255 return success(erasedDeadBlocks > 0);
274 bool wasProvenLive(
Value value) {
278 return wasProvenLive(
result.getOwner());
279 return wasProvenLive(cast<BlockArgument>(value));
281 bool wasProvenLive(BlockArgument arg) {
return liveValues.count(arg); }
282 void setProvedLive(Value value) {
285 if (OpResult
result = dyn_cast<OpResult>(value))
286 return setProvedLive(
result.getOwner());
287 setProvedLive(cast<BlockArgument>(value));
289 void setProvedLive(BlockArgument arg) {
290 changed |= liveValues.insert(arg).second;
294 bool wasProvenLive(Operation *op) {
return liveOps.count(op); }
295 void setProvedLive(Operation *op) { changed |= liveOps.insert(op).second; }
298 void resetChanged() { changed =
false; }
299 bool hasChanged() {
return changed; }
302 bool changed =
false;
323 if (BranchOpInterface branchInterface = dyn_cast<BranchOpInterface>(owner))
324 if (
auto arg = branchInterface.getSuccessorBlockArgument(operandIndex))
325 return !liveMap.wasProvenLive(*arg);
333 if (isUseSpeciallyKnownDead(use, liveMap))
335 return liveMap.wasProvenLive(use.getOwner());
338 liveMap.setProvedLive(value);
345 liveMap.setProvedLive(op);
348 BranchOpInterface branchInterface = dyn_cast<BranchOpInterface>(op);
349 if (!branchInterface) {
352 liveMap.setProvedLive(arg);
360 branchInterface.getSuccessorOperands(i);
377 if (liveMap.wasProvenLive(op))
382 return liveMap.setProvedLive(op);
393 for (
Block *block : llvm::post_order(®ion.
front())) {
396 for (
Operation &op : llvm::reverse(block->getOperations()))
403 if (block->isEntryBlock())
406 for (
Value value : block->getArguments()) {
407 if (!liveMap.wasProvenLive(value))
415 BranchOpInterface branchOp = dyn_cast<BranchOpInterface>(terminator);
420 succI < succE; succI++) {
425 unsigned succ = succE - succI - 1;
429 for (
unsigned argI = 0, argE = succOperands.
size(); argI < argE; ++argI) {
432 unsigned arg = argE - argI - 1;
433 if (!liveMap.wasProvenLive(successor->
getArgument(arg)))
434 succOperands.
erase(arg);
442 bool erasedAnything =
false;
443 for (
Region ®ion : regions) {
453 for (
Block *block : llvm::post_order(®ion.
front())) {
457 llvm::make_early_inc_range(llvm::reverse(block->getOperations()))) {
458 if (!liveMap.wasProvenLive(&childOp)) {
459 erasedAnything =
true;
460 childOp.dropAllUses();
463 erasedAnything |= succeeded(
472 block.eraseArguments(
473 [&](
BlockArgument arg) {
return !liveMap.wasProvenLive(arg); });
476 return success(erasedAnything);
500 liveMap.resetChanged();
502 for (
Region ®ion : regions)
504 }
while (liveMap.hasChanged());
534struct BlockEquivalenceData {
535 BlockEquivalenceData(
Block *block);
539 unsigned getOrderOf(
Value value)
const;
544 llvm::hash_code
hash;
552BlockEquivalenceData::BlockEquivalenceData(
Block *block)
553 : block(block),
hash(0) {
556 if (
unsigned numResults = op.getNumResults()) {
557 opOrderIndex.try_emplace(&op, orderIt);
558 orderIt += numResults;
564 hash = llvm::hash_combine(
hash, opHash);
568unsigned BlockEquivalenceData::getOrderOf(
Value value)
const {
569 assert(value.
getParentBlock() == block &&
"expected value of this block");
572 if (BlockArgument arg = dyn_cast<BlockArgument>(value))
576 OpResult
result = cast<OpResult>(value);
577 auto opOrderIt = opOrderIndex.find(
result.getDefiningOp());
578 assert(opOrderIt != opOrderIndex.end() &&
"expected op to have an order");
579 return opOrderIt->second +
result.getResultNumber();
588class BlockMergeCluster {
590 BlockMergeCluster(BlockEquivalenceData &&leaderData)
591 : leaderData(std::move(leaderData)) {}
595 LogicalResult addToCluster(BlockEquivalenceData &blockData);
598 LogicalResult merge(RewriterBase &rewriter);
602 BlockEquivalenceData leaderData;
605 llvm::SmallSetVector<Block *, 1> blocksToMerge;
609 std::set<std::pair<int, int>> operandsToMerge;
613LogicalResult BlockMergeCluster::addToCluster(BlockEquivalenceData &blockData) {
614 if (leaderData.hash != blockData.hash)
616 Block *leaderBlock = leaderData.block, *mergeBlock = blockData.block;
621 SmallVector<std::pair<int, int>, 8> mismatchedOperands;
622 auto lhsIt = leaderBlock->
begin(), lhsE = leaderBlock->
end();
623 auto rhsIt = blockData.block->
begin(), rhsE = blockData.block->
end();
624 for (
int opI = 0; lhsIt != lhsE && rhsIt != rhsE; ++lhsIt, ++rhsIt, ++opI) {
629 OperationEquivalence::Flags::IgnoreLocations))
634 auto lhsOperands = lhsIt->getOperands(), rhsOperands = rhsIt->getOperands();
635 for (
int operand : llvm::seq<int>(0, lhsIt->getNumOperands())) {
636 Value lhsOperand = lhsOperands[operand];
637 Value rhsOperand = rhsOperands[operand];
638 if (lhsOperand == rhsOperand)
647 if (lhsIsInBlock != rhsIsInBlock)
657 auto isValidSuccessorArg = [](
Block *block, Value operand) {
658 if (operand.getDefiningOp() !=
659 operand.getParentBlock()->getTerminator())
662 operand.getParentBlock());
665 if (!isValidSuccessorArg(leaderBlock, lhsOperand) ||
666 !isValidSuccessorArg(mergeBlock, rhsOperand))
669 mismatchedOperands.emplace_back(opI, operand);
675 if (leaderData.getOrderOf(lhsOperand) != blockData.getOrderOf(rhsOperand))
685 if (rhsIt->isUsedOutsideOfBlock(mergeBlock) ||
686 lhsIt->isUsedOutsideOfBlock(leaderBlock)) {
691 if (lhsIt != lhsE || rhsIt != rhsE)
695 operandsToMerge.insert(mismatchedOperands.begin(), mismatchedOperands.end());
696 blocksToMerge.insert(blockData.block);
704 if (!isa<BranchOpInterface>((*it)->getTerminator()))
723 if (newArguments.empty())
727 unsigned numLists = newArguments.size();
728 unsigned numArgs = newArguments[0].size();
738 for (
unsigned j = 0;
j < numArgs; ++
j) {
739 Value newArg = newArguments[0][
j];
740 firstValueToIdx.try_emplace(newArg,
j);
744 for (
unsigned j = 0;
j < numArgs; ++
j) {
756 unsigned k = firstValueToIdx[newArguments[0][
j]];
760 bool shouldReplaceJ =
true;
765 for (
unsigned i = 1; i < numLists; ++i)
767 shouldReplaceJ && (newArguments[i][k] == newArguments[i][
j]);
774 for (
unsigned i = 0; i < numLists; ++i)
775 for (
unsigned j = 0;
j < numArgs; ++
j)
776 if (!idxToReplacement.contains(
j))
777 newArgumentsPruned[i].push_back(newArguments[i][
j]);
781 for (
auto [idx, arg] : llvm::enumerate(block->
getArguments())) {
782 if (idxToReplacement.contains(idx)) {
785 block->
getArgument(numOldArguments + idxToReplacement[idx]);
787 toErase.push_back(numOldArguments + idx);
792 for (
unsigned idxToErase : llvm::reverse(toErase))
794 return newArgumentsPruned;
797LogicalResult BlockMergeCluster::merge(RewriterBase &rewriter) {
799 if (blocksToMerge.empty())
802 Block *leaderBlock = leaderData.block;
803 if (!operandsToMerge.empty()) {
815 SmallVector<Block::iterator, 2> blockIterators;
816 blockIterators.reserve(blocksToMerge.size() + 1);
817 blockIterators.push_back(leaderBlock->
begin());
818 for (
Block *mergeBlock : blocksToMerge)
819 blockIterators.push_back(mergeBlock->begin());
822 SmallVector<SmallVector<Value, 8>, 2> newArguments(
823 1 + blocksToMerge.size(),
824 SmallVector<Value, 8>(operandsToMerge.size()));
825 unsigned curOpIndex = 0;
827 for (
const auto &it : llvm::enumerate(operandsToMerge)) {
828 unsigned nextOpOffset = it.value().first - curOpIndex;
829 curOpIndex = it.value().first;
832 for (
unsigned i = 0, e = blockIterators.size(); i != e; ++i) {
834 std::advance(blockIter, nextOpOffset);
835 auto &operand = blockIter->getOpOperand(it.value().second);
836 newArguments[i][it.index()] = operand.get();
840 Value operandVal = operand.get();
849 numOldArguments, leaderBlock);
852 auto updatePredecessors = [&](
Block *block,
unsigned clusterIndex) {
854 predIt != predE; ++predIt) {
855 auto branch = cast<BranchOpInterface>((*predIt)->getTerminator());
856 unsigned succIndex = predIt.getSuccessorIndex();
857 branch.getSuccessorOperands(succIndex).append(
858 newArguments[clusterIndex]);
861 updatePredecessors(leaderBlock, 0);
862 for (
unsigned i = 0, e = blocksToMerge.size(); i != e; ++i)
863 updatePredecessors(blocksToMerge[i], i + 1);
867 for (
Block *block : blocksToMerge) {
886 for (
Block &block : llvm::drop_begin(region, 1))
889 bool mergedAnyBlocks =
false;
891 if (blocks.size() == 1)
895 for (
Block *block : blocks) {
896 BlockEquivalenceData data(block);
900 bool hasNonEmptyRegion = llvm::any_of(*block, [](
Operation &op) {
902 [](
Region ®ion) { return !region.empty(); });
904 if (hasNonEmptyRegion)
909 bool argHasExternalUsers = llvm::any_of(
911 return arg.isUsedOutsideOfBlock(block);
913 if (argHasExternalUsers)
917 bool addedToCluster =
false;
918 for (
auto &cluster : clusters)
919 if ((addedToCluster = succeeded(cluster.addToCluster(data))))
922 clusters.emplace_back(std::move(data));
924 for (
auto &cluster : clusters)
925 mergedAnyBlocks |= succeeded(cluster.merge(rewriter));
928 return success(mergedAnyBlocks);
935 llvm::SmallSetVector<Region *, 1> worklist;
936 for (
auto ®ion : regions)
937 worklist.insert(®ion);
938 bool anyChanged =
false;
939 while (!worklist.empty()) {
940 Region *region = worklist.pop_back_val();
942 worklist.insert(region);
947 for (
Block &block : *region)
948 for (
auto &op : block)
949 for (
auto &nestedRegion : op.getRegions())
950 worklist.insert(&nestedRegion);
963 for (
auto [argIdx, blockOperand] : llvm::enumerate(block.
getArguments())) {
971 predIt != predE; ++predIt) {
972 auto branch = dyn_cast<BranchOpInterface>((*predIt)->getTerminator());
977 unsigned succIndex = predIt.getSuccessorIndex();
989 Value operandValue = succOperands[argIdx];
991 commonValue = operandValue;
994 if (operandValue != commonValue) {
1001 if (commonValue && sameArg) {
1002 argsToErase.push_back(argIdx);
1010 for (
size_t argIdx : llvm::reverse(argsToErase)) {
1015 predIt != predE; ++predIt) {
1016 auto branch = cast<BranchOpInterface>((*predIt)->getTerminator());
1017 unsigned succIndex = predIt.getSuccessorIndex();
1019 succOperands.
erase(argIdx);
1022 return success(!argsToErase.empty());
1052 llvm::SmallSetVector<Region *, 1> worklist;
1053 for (
Region ®ion : regions)
1054 worklist.insert(®ion);
1055 bool anyChanged =
false;
1056 while (!worklist.empty()) {
1057 Region *region = worklist.pop_back_val();
1060 for (
Block &block : *region) {
1065 for (
Region &nestedRegion : op.getRegions())
1066 worklist.insert(&nestedRegion);
1084 bool eliminatedOpsOrArgs = succeeded(
runRegionDCE(rewriter, regions));
1085 bool mergedIdenticalBlocks =
false;
1086 bool droppedRedundantArguments =
false;
1089 droppedRedundantArguments =
1092 return success(eliminatedBlocks || eliminatedOpsOrArgs ||
1093 mergedIdenticalBlocks || droppedRedundantArguments);
1118 bool dominates = argBlock == insertionBlock ||
1119 dominance.
dominates(argBlock, insertionBlock);
1120 if (!dominates && failingOp)
1127 for (
Value operand : op->getOperands()) {
1128 auto arg = dyn_cast<BlockArgument>(operand);
1131 if (!argDominates(arg, op))
1137 for (
Region ®ion : op->getRegions()) {
1140 for (
Value val : capturedValues) {
1141 auto arg = dyn_cast<BlockArgument>(val);
1144 if (!argDominates(arg, op))
1161 while (region && region != ancestorRegion) {
1183 "insertion point does not dominate op");
1189 op,
"cannot move operation across isolated-from-above region");
1197 options.omitUsesFromAbove =
false;
1199 options.omitBlockArguments =
true;
1200 bool dependsOnSideEffectingOp =
false;
1204 if (sliceBoundaryOp == op)
1212 if (!
isPure(sliceBoundaryOp)) {
1213 dependsOnSideEffectingOp =
true;
1220 assert(
result.succeeded() &&
"expected a backward slice");
1224 if (dependsOnSideEffectingOp) {
1226 op,
"cannot move operation with side-effecting dependencies");
1230 if (slice.contains(insertionPoint)) {
1233 "cannot move dependencies before operation in backward slice of op");
1242 badOp,
"moving op would break dominance for block argument operand");
1266 for (
auto value : values) {
1270 if (isa<BlockArgument>(value)) {
1273 "unsupported case of moving block argument before insertion point");
1284 "cannot move value definition across isolated-from-above region");
1290 if (!dominance.
dominates(insertionBlock, definingBlock)) {
1293 "insertion point block does not dominate the value's defining "
1296 prunedValues.push_back(value);
1304 options.omitUsesFromAbove =
false;
1308 options.omitBlockArguments =
true;
1309 bool dependsOnSideEffectingOp =
false;
1317 if (!
isPure(sliceBoundaryOp)) {
1318 dependsOnSideEffectingOp =
true;
1324 for (
auto value : prunedValues) {
1326 assert(
result.succeeded() &&
"expected a backward slice");
1331 if (dependsOnSideEffectingOp) {
1333 insertionPoint,
"cannot move value definitions with side-effecting "
1334 "operations in the slice");
1338 if (slice.contains(insertionPoint)) {
1341 "cannot move dependencies before operation in backward slice of op");
1355 badOp,
"moving op would break dominance for block argument operand");
static size_t hash(const T &value)
Local helper to compute std::hash for a value.
*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 the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static llvm::ManagedStatic< PassManagerOptions > options
static LogicalResult mergeIdenticalBlocks(RewriterBase &rewriter, Region ®ion)
Identify identical blocks within the given region and merge them, inserting new block arguments as ne...
static void propagateLiveness(Region ®ion, LiveMap &liveMap)
static SmallVector< SmallVector< Value, 8 >, 2 > pruneRedundantArguments(const SmallVector< SmallVector< Value, 8 >, 2 > &newArguments, RewriterBase &rewriter, unsigned numOldArguments, Block *block)
Prunes the redundant list of new arguments.
static void processValue(Value value, LiveMap &liveMap)
static bool ableToUpdatePredOperands(Block *block)
Returns true if the predecessor terminators of the given block can not have their operands updated.
static bool blockArgsDominateInsertionPoint(const llvm::SetVector< Operation * > &slice, Operation *insertionPoint, DominanceInfo &dominance, Operation **failingOp=nullptr)
Check if moving operations in the slice before insertionPoint would break dominance due to block argu...
static void eraseTerminatorSuccessorOperands(Operation *terminator, LiveMap &liveMap)
static LogicalResult dropRedundantArguments(RewriterBase &rewriter, Block &block)
If a block's argument is always the same across different invocations, then drop the argument and use...
static bool hasIsolatedRegionBetween(Operation *op, Block *ancestorBlock)
Check if any region between an operation and an ancestor block is isolated from above.
static void propagateTerminatorLiveness(Operation *op, LiveMap &liveMap)
static bool isUseSpeciallyKnownDead(OpOperand &use, LiveMap &liveMap)
static LogicalResult deleteDeadness(RewriterBase &rewriter, MutableArrayRef< Region > regions, LiveMap &liveMap)
This class represents an argument of a Block.
unsigned getArgNumber() const
Returns the number of this argument.
Block * getOwner() const
Returns the block that owns this argument.
Block represents an ordered list of Operations.
OpListType::iterator iterator
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
iterator_range< pred_iterator > getPredecessors()
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
pred_iterator pred_begin()
SuccessorRange getSuccessors()
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
BlockArgListType getArguments()
PredecessorIterator pred_iterator
void eraseArgument(unsigned index)
Erase the argument at 'index' and remove it from the argument list.
A class for computing basic dominance information.
bool properlyDominates(Operation *a, Operation *b, bool enclosingOpOk=true) const
Return true if operation A properly dominates operation B, i.e.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
This is a utility class for mapping one set of IR entities to another.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
void replaceAllUsesWith(ValueT &&newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
IRValueT get() const
Return the current value being used by this operand.
RAII guard to reset the insertion point of the builder when destroyed.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
This class represents an operand of an operation.
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
This is a value defined by a result of an operation.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
unsigned getNumSuccessors()
Block * getBlock()
Returns the operation block that contains this operation.
MutableArrayRef< OpOperand > getOpOperands()
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
operand_range getOperands()
Returns an iterator on the underlying Value's.
Block * getSuccessor(unsigned index)
SuccessorRange getSuccessors()
result_range getResults()
Region * getParentRegion()
Returns the region to which the instruction belongs.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
Operation * getParentOp()
Return the parent operation this region is attached to.
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 coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
void replaceOpUsesWithIf(Operation *from, ValueRange to, function_ref< bool(OpOperand &)> functor, bool *allUsesReplaced=nullptr)
virtual void eraseBlock(Block *block)
This method erases all operations in a block.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
virtual void replaceUsesWithIf(Value from, Value to, function_ref< bool(OpOperand &)> functor, bool *allUsesReplaced=nullptr)
Find uses of from and replace them with to if the functor returns true.
void moveOpBefore(Operation *op, Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
void mergeBlocks(Block *source, Block *dest, ValueRange argValues={})
Inline the operations of block 'source' into the end of block 'dest'.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
This class models how operands are forwarded to block arguments in control flow.
void erase(unsigned subStart, unsigned subLen=1)
Erase operands forwarded to the successor.
bool isOperandProduced(unsigned index) const
Returns true if the successor operand denoted by index is produced by the operation.
unsigned getProducedOperandCount() const
Returns the amount of operands that are produced internally by the operation.
unsigned size() const
Returns the amount of operands passed to the successor.
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...
Type getType() const
Return the type of this value.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
Block * getParentBlock()
Return the Block in which this Value is defined.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Operation * getOwner() const
Return the owner of this operand.
Include the generated interface declarations.
void replaceAllUsesInRegionWith(Value orig, Value replacement, Region ®ion)
Replace all uses of orig within the given region with replacement.
LogicalResult getBackwardSlice(Operation *op, SetVector< Operation * > *backwardSlice, const BackwardSliceOptions &options={})
Fills backwardSlice with the computed backward slice (i.e.
bool computeTopologicalSorting(MutableArrayRef< Operation * > ops, function_ref< bool(Value, Operation *)> isOperandReady=nullptr)
Compute a topological ordering of the given ops.
LogicalResult moveOperationDependencies(RewriterBase &rewriter, Operation *op, Operation *insertionPoint, DominanceInfo &dominance)
Move the operation dependencies (producers) of op before insertionPoint, so that op itself can subseq...
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
bool isPure(Operation *op)
Returns true if the given operation is pure, i.e., is speculatable that does not touch memory.
bool wouldOpBeTriviallyDead(Operation *op)
Return true if the given operation would be dead if unused, and has no side effects on memory that wo...
LogicalResult eraseUnreachableBlocks(RewriterBase &rewriter, MutableArrayRef< Region > regions)
Erase the unreachable blocks within the provided regions.
llvm::SetVector< T, Vector, Set, N > SetVector
SmallVector< Value > makeRegionIsolatedFromAbove(RewriterBase &rewriter, Region ®ion, llvm::function_ref< bool(Operation *)> cloneOperationIntoRegion=[](Operation *) { return false;})
Make a region isolated from above.
void getUsedValuesDefinedAbove(Region ®ion, Region &limit, SetVector< Value > &values)
Fill values with a list of values defined at the ancestors of the limit region and used within region...
LogicalResult runRegionDCE(RewriterBase &rewriter, MutableArrayRef< Region > regions)
This function returns success if any operations or arguments were deleted, failure otherwise.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
LogicalResult simplifyRegions(RewriterBase &rewriter, MutableArrayRef< Region > regions, bool mergeBlocks=true)
Run a set of structural simplifications over the given regions.
LogicalResult moveValueDefinitions(RewriterBase &rewriter, ValueRange values, Operation *insertionPoint, DominanceInfo &dominance)
Move definitions of values (and their transitive dependencies) before insertionPoint.
void visitUsedValuesDefinedAbove(Region ®ion, Region &limit, function_ref< void(OpOperand *)> callback)
Calls callback for each use of a value within region or its descendants that was defined at the ances...
llvm::function_ref< Fn > function_ref
SetVector< Operation * > topologicalSort(const SetVector< Operation * > &toSort)
Sorts all operations in toSort topologically while also considering region semantics.
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.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.