17#include "llvm/ADT/EquivalenceClasses.h"
18#include "llvm/ADT/PointerIntPair.h"
19#include "llvm/Support/DebugLog.h"
27#include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
30 : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
35 : producedOperandCount(producedOperandCount),
36 forwardedOperands(std::move(forwardedOperands)) {}
45std::optional<BlockArgument>
47 unsigned operandIndex,
Block *successor) {
48 LDBG() <<
"Getting branch successor argument for operand index "
49 << operandIndex <<
" in successor block";
53 if (forwardedOperands.empty()) {
54 LDBG() <<
"No forwarded operands, returning nullopt";
60 if (operandIndex < operandsStart ||
61 operandIndex >= (operandsStart + forwardedOperands.size())) {
62 LDBG() <<
"Operand index " << operandIndex <<
" out of range ["
63 << operandsStart <<
", "
64 << (operandsStart + forwardedOperands.size())
65 <<
"), returning nullopt";
72 LDBG() <<
"Computed argument index " << argIndex <<
" for successor block";
80 LDBG() <<
"Verifying branch successor operands for successor #" << succNo
81 <<
" in operation " << op->
getName();
84 unsigned operandCount = operands.
size();
86 LDBG() <<
"Branch has " << operandCount <<
" operands, target block has "
90 return op->
emitError() <<
"branch has " << operandCount
91 <<
" operands for successor #" << succNo
92 <<
", but target block has "
96 LDBG() <<
"Checking type compatibility for "
98 <<
" forwarded operands";
101 Type operandType = operands[i].getType();
103 LDBG() <<
"Checking type compatibility: operand type " << operandType
104 <<
" vs argument type " << argType;
106 if (!cast<BranchOpInterface>(op).areTypesCompatible(operandType, argType))
107 return op->
emitError() <<
"type mismatch for bb argument #" << i
108 <<
" of successor #" << succNo;
111 LDBG() <<
"Branch successor operand verification successful";
121 std::size_t expectedWeightsNum,
122 llvm::StringRef weightAnchorName,
123 llvm::StringRef weightRefName) {
127 if (weights.size() != expectedWeightsNum)
128 return op->
emitError() <<
"expects number of " << weightAnchorName
129 <<
" weights to match number of " << weightRefName
130 <<
": " << weights.size() <<
" vs "
131 << expectedWeightsNum;
133 if (llvm::all_of(weights, [](int32_t value) {
return value == 0; }))
134 return op->
emitError() <<
"branch weights cannot all be zero";
141 cast<WeightedBranchOpInterface>(op).getWeights();
152 cast<WeightedRegionBranchOpInterface>(op).getWeights();
162 auto regionInterface = cast<RegionBranchOpInterface>(op);
167 regionInterface.getAllRegionBranchPoints();
170 regionInterface.getSuccessorRegions(branchPoint, successors);
174 auto emitRegionEdgeError = [&]() {
176 regionInterface->emitOpError(
"along control flow edge from ");
177 if (branchPoint.isParent()) {
179 diag.attachNote(op->
getLoc()) <<
"region branch point";
182 << branchPoint.getTerminatorPredecessorOrNull()->getName();
184 branchPoint.getTerminatorPredecessorOrNull()->getLoc())
185 <<
"region branch point";
188 if (
Region *region = successor.getSuccessor()) {
189 diag <<
"Region #" << region->getRegionNumber();
191 diag <<
"Operation " << successor.getSuccessorOp()->getName();
198 regionInterface.getSuccessorOperands(branchPoint, successor);
199 ValueRange succInputs = regionInterface.getSuccessorInputs(successor);
200 if (succOperands.size() != succInputs.size()) {
201 return emitRegionEdgeError()
202 <<
": region branch point has " << succOperands.size()
203 <<
" operands, but region successor needs " << succInputs.size()
210 for (
const auto &typesIdx :
211 llvm::enumerate(llvm::zip(succOperandTypes, succInputTypes))) {
212 Type succOperandType = std::get<0>(typesIdx.value());
213 Type succInputType = std::get<1>(typesIdx.value());
214 if (!regionInterface.areTypesCompatible(succOperandType, succInputType))
215 return emitRegionEdgeError()
216 <<
": successor operand type #" << typesIdx.index() <<
" "
217 << succOperandType <<
" should match successor input type #"
218 << typesIdx.index() <<
" " << succInputType;
231 if (successor.isRegion())
232 regions.push_back(successor.getSuccessor());
243 cast<RegionBranchOpInterface>(region->
getParentOp())
244 .getSuccessorRegions(*region, successors);
246 << successors.size() <<
" successors";
260 auto op = cast<RegionBranchOpInterface>(begin->
getParentOp());
261 LDBG() <<
"Starting region graph traversal from region #"
266 LDBG() <<
"Initialized visited array with " << op->getNumRegions()
270 LDBG() <<
"Initial worklist size: " << worklist.size();
273 while (!worklist.empty()) {
274 Region *nextRegion = worklist.pop_back_val();
276 <<
" from worklist (remaining: " << worklist.size() <<
")";
280 if (stopConditionFn(nextRegion)) {
281 LDBG() <<
"Stop condition met for region #"
286 llvm::errs() <<
"Region " << *nextRegion <<
" has no parent op\n";
291 <<
" already visited, skipping";
300 LDBG() <<
"Traversal completed, returning false";
308 "expected that both regions belong to the same op");
311 return nextRegion == r;
325 LDBG() <<
"Checking if operations are in mutually exclusive regions: "
326 << a->
getName() <<
" and " <<
b->getName();
328 assert(a &&
"expected non-empty operation");
329 assert(
b &&
"expected non-empty operation");
333 LDBG() <<
"Checking branch operation " << branchOp->getName();
336 if (!branchOp->isProperAncestor(
b)) {
337 LDBG() <<
"Operation b is not inside branchOp, checking next ancestor";
339 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
343 LDBG() <<
"Both operations are inside branchOp, finding their regions";
347 Region *regionA =
nullptr, *regionB =
nullptr;
348 for (
Region &r : branchOp->getRegions()) {
349 if (r.findAncestorOpInRegion(*a)) {
350 assert(!regionA &&
"already found a region for a");
352 LDBG() <<
"Found region #" << r.
getRegionNumber() <<
" for operation a";
354 if (r.findAncestorOpInRegion(*
b)) {
355 assert(!regionB &&
"already found a region for b");
357 LDBG() <<
"Found region #" << r.getRegionNumber() <<
" for operation b";
360 assert(regionA && regionB &&
"could not find region of op");
362 LDBG() <<
"Region A: #" << regionA->
getRegionNumber() <<
", Region B: #"
363 << regionB->getRegionNumber();
367 bool regionsAreDistinct = (regionA != regionB);
371 LDBG() <<
"Regions distinct: " << regionsAreDistinct
372 <<
", A not reachable from B: " << aNotReachableFromB
373 <<
", B not reachable from A: " << bNotReachableFromA;
375 bool mutuallyExclusive =
376 regionsAreDistinct && aNotReachableFromB && bNotReachableFromA;
377 LDBG() <<
"Operations are mutually exclusive: " << mutuallyExclusive;
379 return mutuallyExclusive;
384 LDBG() <<
"No common RegionBranchOpInterface found, operations are not "
385 "mutually exclusive";
389bool RegionBranchOpInterface::isRepetitiveRegion(
unsigned index) {
390 LDBG() <<
"Checking if region #" <<
index <<
" is repetitive in operation "
391 << getOperation()->getName();
393 Region *region = &getOperation()->getRegion(
index);
396 LDBG() <<
"Region #" <<
index <<
" is repetitive: " << isRepetitive;
411 if (entryRegions.empty())
413 enum class State : uint8_t { Unvisited, OnPath, Finished };
415 entryRegions.front()->getParentOp()->getNumRegions(), State::Unvisited);
421 using StackItem = llvm::PointerIntPair<Region *, 1, bool>;
423 for (
Region *region : entryRegions)
424 stack.push_back(StackItem(region,
false));
425 while (!stack.empty()) {
426 StackItem item = stack.pop_back_val();
427 Region *region = item.getPointer();
428 bool isLeave = item.getInt();
431 state = State::Finished;
434 if (state == State::OnPath) {
438 if (state == State::Finished)
441 state = State::OnPath;
442 stack.push_back(StackItem(region,
true));
444 stack.push_back(StackItem(successor,
false));
449bool RegionBranchOpInterface::hasLoop() {
450 LDBG() <<
"Checking if operation " << getOperation()->getName()
456 LDBG() <<
"Found " << entryRegions.size() <<
" entry regions";
459 LDBG() <<
"Operation " << (hasLoop ?
"has" :
"has no") <<
" loops";
467 return getEntrySuccessorOperands(dest);
472RegionBranchOpInterface::getNonSuccessorInputs(
RegionSuccessor successor) {
477 ValueRange successorInputs = getSuccessorInputs(successor);
478 if (!successorInputs.empty()) {
479 unsigned inputBegin =
481 ? cast<OpResult>(successorInputs.front()).getResultNumber()
482 : cast<BlockArgument>(successorInputs.front()).getArgNumber();
483 results.erase(results.begin() + inputBegin,
484 results.begin() + inputBegin + successorInputs.size());
498 branchOp.getSuccessorRegions(src, successors);
500 OperandRange operands = branchOp.getSuccessorOperands(src, dst);
501 assert(operands.size() == branchOp.getSuccessorInputs(dst).size() &&
502 "expected the same number of operands and inputs");
503 for (
const auto &[operand, input] : llvm::zip_equal(
505 mapping[&operand].push_back(input);
508void RegionBranchOpInterface::getSuccessorOperandInputMapping(
510 std::optional<RegionBranchPoint> src) {
511 if (src.has_value()) {
524 for (
const auto &[operand, inputs] : operandToInputs) {
525 for (
Value input : inputs)
526 inputToOperands[input].push_back(operand);
528 return inputToOperands;
531void RegionBranchOpInterface::getSuccessorInputOperandMapping(
539RegionBranchOpInterface::getAllRegionBranchPoints() {
542 for (
Region ®ion : getOperation()->getRegions()) {
543 for (
Block &block : region) {
546 if (
auto terminator =
547 dyn_cast<RegionBranchTerminatorOpInterface>(block.back()))
555 LDBG() <<
"Finding enclosing repetitive region for operation "
559 LDBG() <<
"Checking region #" << region->getRegionNumber()
560 <<
" in operation " << region->getParentOp()->getName();
563 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
565 <<
"Found RegionBranchOpInterface, checking if region is repetitive";
566 if (branchOp.isRepetitiveRegion(region->getRegionNumber())) {
567 LDBG() <<
"Found repetitive region #" << region->getRegionNumber();
571 LDBG() <<
"Parent operation does not implement RegionBranchOpInterface";
575 LDBG() <<
"No enclosing repetitive region found";
580 LDBG() <<
"Finding enclosing repetitive region for value";
588 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
590 <<
"Found RegionBranchOpInterface, checking if region is repetitive";
596 LDBG() <<
"Parent operation does not implement RegionBranchOpInterface";
601 LDBG() <<
"No enclosing repetitive region found for value";
610 assert((
b.getDefiningOp() == regionBranchOp ||
611 b.getParentRegion()->getParentOp() == regionBranchOp) &&
612 "b must be a region successor input");
625 if (isa<OpResult>(
b))
635 assert(isa<BlockArgument>(
b) &&
"b must be a block argument");
636 return isa<BlockArgument>(a) && cast<BlockArgument>(a).getOwner() ==
637 cast<BlockArgument>(
b).getOwner();
693 std::optional<unsigned> maxReachableValues = std::nullopt) {
694 assert(inputToOperands.contains(value) &&
"value must be a successor input");
695 llvm::SmallDenseSet<Value> visited;
697 worklist.push_back(value);
698 while (!worklist.empty()) {
699 Value next = worklist.pop_back_val();
700 auto it = inputToOperands.find(next);
701 if (it == inputToOperands.end()) {
703 if (maxReachableValues &&
result.size() > *maxReachableValues)
708 if (visited.insert(operand->
get()).second)
709 worklist.push_back(operand->
get());
742struct MakeRegionBranchOpSuccessorInputsDead :
public RewritePattern {
743 MakeRegionBranchOpSuccessorInputsDead(MLIRContext *context, StringRef name,
744 PatternBenefit benefit = 1)
745 : RewritePattern(name, benefit, context) {}
747 LogicalResult matchAndRewrite(Operation *op,
748 PatternRewriter &rewriter)
const override {
750 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
752 regionBranchOp.getSuccessorInputOperandMapping(inputToOperands);
755 bool changed =
false;
756 const bool isIsolated = op->
hasTrait<OpTrait::IsIsolatedFromAbove>();
757 for (Value value : inputToOperands.keys()) {
759 if (value.use_empty())
763 llvm::SmallDenseSet<Value> reachableValues;
765 reachableValues, value, inputToOperands,
767 reachableValues.empty())
771 "successor inputs are supposed to be excluded");
787 Region *valueRegion = value.getParentRegion();
788 if (isIsolated && valueRegion->
getParentOp() == op &&
812template <
typename MappingTy,
typename KeyTy>
813static BitVector &lookupOrCreateBitVector(MappingTy &mapping, KeyTy key,
815 return mapping.try_emplace(key, size,
false).first->second;
828static llvm::EquivalenceClasses<Value> computeTiedSuccessorInputs(
830 llvm::EquivalenceClasses<Value> tiedSuccessorInputs;
831 for (
const auto &[operand, inputs] : operandToInputs) {
832 assert(!inputs.empty() &&
"expected non-empty inputs");
833 Value firstInput = inputs.front();
834 tiedSuccessorInputs.insert(firstInput);
835 for (
Value nextInput : llvm::drop_begin(inputs)) {
838 tiedSuccessorInputs.unionSets(firstInput, nextInput);
841 return tiedSuccessorInputs;
883struct RemoveDeadRegionBranchOpSuccessorInputs :
public RewritePattern {
884 RemoveDeadRegionBranchOpSuccessorInputs(MLIRContext *context, StringRef name,
885 PatternBenefit benefit = 1)
886 : RewritePattern(name, benefit, context) {}
888 LogicalResult matchAndRewrite(Operation *op,
889 PatternRewriter &rewriter)
const override {
893 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
895 regionBranchOp.getSuccessorOperandInputMapping(operandToInputs);
896 llvm::EquivalenceClasses<Value> tiedSuccessorInputs =
897 computeTiedSuccessorInputs(operandToInputs);
900 SmallVector<Value> valuesToRemove;
902 BitVector resultsToRemove(regionBranchOp->getNumResults(),
false);
904 for (
auto it = tiedSuccessorInputs.begin(), e = tiedSuccessorInputs.end();
906 if (!(*it)->isLeader())
912 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
913 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
915 if (!memberIt->use_empty()) {
925 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
926 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
927 if (
auto arg = dyn_cast<BlockArgument>(*memberIt)) {
930 lookupOrCreateBitVector(blockArgsToRemove, arg.getOwner(),
931 arg.getOwner()->getNumArguments());
932 vector.set(arg.getArgNumber());
935 OpResult
result = cast<OpResult>(*memberIt);
936 assert(
result.getDefiningOp() == regionBranchOp &&
937 "result must be a region branch op result");
938 resultsToRemove.set(
result.getResultNumber());
940 valuesToRemove.push_back(*memberIt);
944 if (valuesToRemove.empty())
951 for (Value value : valuesToRemove) {
952 for (OpOperand *operand : inputsToOperands[value]) {
955 lookupOrCreateBitVector(operandsToRemove, operand->getOwner(),
956 operand->getOwner()->getNumOperands());
957 vector.set(operand->getOperandNumber());
962 for (
auto &pair : operandsToRemove) {
963 Operation *op = pair.first;
964 BitVector &operands = pair.second;
969 for (
auto &pair : blockArgsToRemove) {
970 Block *block = pair.first;
971 BitVector &blockArg = pair.second;
973 [&]() { block->eraseArguments(blockArg); });
977 if (resultsToRemove.any())
987 if (
auto arg = dyn_cast<BlockArgument>(value))
988 return arg.getOwner();
993static unsigned getArgOrResultNumber(
Value value) {
994 if (
auto opResult = llvm::dyn_cast<OpResult>(value))
995 return opResult.getResultNumber();
996 return llvm::cast<BlockArgument>(value).getArgNumber();
1030struct RemoveDuplicateSuccessorInputUses :
public RewritePattern {
1031 RemoveDuplicateSuccessorInputUses(MLIRContext *context, StringRef name,
1032 PatternBenefit benefit = 1)
1033 : RewritePattern(name, benefit, context) {}
1035 LogicalResult matchAndRewrite(Operation *op,
1036 PatternRewriter &rewriter)
const override {
1043 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
1045 regionBranchOp.getSuccessorInputOperandMapping(inputsToOperands);
1046 SmallVector<Value> inputs = llvm::to_vector(inputsToOperands.keys());
1047 llvm::sort(inputs, [](Value a, Value
b) {
1048 return getArgOrResultNumber(a) < getArgOrResultNumber(
b);
1061 using SigEntry = std::pair<Operation *, Value>;
1062 using Signature = SmallVector<SigEntry>;
1063 auto sigEntryLess = [](
const SigEntry &a,
const SigEntry &
b) {
1064 if (a.first !=
b.first)
1065 return a.first <
b.first;
1071 using MapKey = std::pair<Signature, void *>;
1072 auto mapKeyLess = [&](
const MapKey &a,
const MapKey &
b) {
1073 if (a.second !=
b.second)
1074 return a.second <
b.second;
1075 return std::lexicographical_compare(a.first.begin(), a.first.end(),
1076 b.first.begin(),
b.first.end(),
1079 std::map<MapKey, Value,
decltype(mapKeyLess)> signatureToCanonical(
1081 bool changed =
false;
1084 for (Value input : inputs) {
1088 for (OpOperand *operand : inputsToOperands[input])
1089 sig.emplace_back(operand->getOwner(), operand->get());
1090 llvm::sort(sig, sigEntryLess);
1094 auto [it,
inserted] = signatureToCanonical.try_emplace(
1095 MapKey{std::move(sig), owner}, input);
1097 Value canonical = it->second;
1099 if (input.use_empty())
1113 return llvm::map_to_vector(values, [](
Value value) {
1124getSuccessorRegionsWithAttrs(RegionBranchOpInterface op,
1128 op.getEntrySuccessorRegions(extractConstants(op->getOperands()),
1132 RegionBranchTerminatorOpInterface terminator =
1134 terminator.getSuccessorRegions(extractConstants(terminator->getOperands()),
1160computeSingleAcyclicRegionBranchPath(RegionBranchOpInterface op) {
1161 llvm::SmallDenseSet<Region *> visited;
1168 getSuccessorRegionsWithAttrs(op, next);
1169 if (successors.size() != 1) {
1174 path.push_back(successors.front());
1175 if (successors.front().isOperation()) {
1179 Region *region = successors.front().getSuccessor();
1185 if (!visited.insert(region).second) {
1190 dyn_cast<RegionBranchTerminatorOpInterface>(®ion->
front().
back());
1198 llvm_unreachable(
"expected to return from loop");
1236 InlineRegionBranchOp(MLIRContext *context, StringRef name,
1239 : RewritePattern(name, benefit, context), replBuilderFn(replBuilderFn),
1240 matcherFn(matcherFn) {}
1242 LogicalResult matchAndRewrite(Operation *op,
1243 PatternRewriter &rewriter)
const override {
1245 if (
failed(matcherFn(op)))
1250 if (!op->
hasTrait<OpTrait::HasRecursiveMemoryEffects>())
1252 op,
"pattern not applicable to ops without recursive memory effects");
1255 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
1256 SmallVector<RegionSuccessor> path =
1257 computeSingleAcyclicRegionBranchPath(regionBranchOp);
1260 op,
"failed to find acyclic region branch path");
1264 ArrayRef remainingPath = path;
1265 SmallVector<Value> successorOperands = llvm::to_vector(
1266 regionBranchOp.getEntrySuccessorOperands(remainingPath.front()));
1267 while (!remainingPath.empty()) {
1268 RegionSuccessor nextSuccessor = remainingPath.consume_front();
1270 regionBranchOp.getSuccessorInputs(nextSuccessor);
1271 assert(successorInputs.size() == successorOperands.size() &&
1275 unsigned firstSuccessorInputIdx = 0;
1276 if (!successorInputs.empty())
1277 firstSuccessorInputIdx =
1279 ? cast<OpResult>(successorInputs.front()).getResultNumber()
1280 : cast<BlockArgument>(successorInputs.front()).getArgNumber();
1282 unsigned numValues =
1287 SmallVector<Value> replacements;
1289 auto getValue = [&](
unsigned idx) {
1292 : Value(nextSuccessor.getSuccessor()->getArgument(idx));
1296 for (
unsigned i = 0; i < firstSuccessorInputIdx; ++i)
1297 replacements.push_back(
1298 replBuilderFn(rewriter, op->
getLoc(), getValue(i)));
1301 llvm::append_range(replacements, successorOperands);
1304 for (
unsigned i = replacements.size(); i < numValues; ++i)
1305 replacements.push_back(
1306 replBuilderFn(rewriter, op->
getLoc(), getValue(i)));
1312 op,
"path ends after a different operation");
1313 assert(remainingPath.empty() &&
"expected that the path ended");
1320 auto terminator = cast<RegionBranchTerminatorOpInterface>(
1325 successorOperands = llvm::to_vector(
1326 terminator.getSuccessorOperands(remainingPath.front()));
1330 llvm_unreachable(
"expected that path ends with an operation");
1340 patterns.
add<MakeRegionBranchOpSuccessorInputsDead,
1341 RemoveDuplicateSuccessorInputUses,
1342 RemoveDeadRegionBranchOpSuccessorInputs>(patterns.
getContext(),
1350 patterns.
add<InlineRegionBranchOp>(patterns.
getContext(), opName,
1351 replBuilderFn, matcherFn, benefit);
static LogicalResult verifyWeights(Operation *op, llvm::ArrayRef< int32_t > weights, std::size_t expectedWeightsNum, llvm::StringRef weightAnchorName, llvm::StringRef weightRefName)
static bool isDefinedBefore(Operation *regionBranchOp, Value a, Value b)
Return "true" if a can be used in lieu of b, where b is a region successor input and a is a "reachabl...
static SmallVector< Region * > getSuccessorRegionsOf(Region *region)
Return the regions that the terminators of region may branch to.
static void getSuccessorOperandInputMapping(RegionBranchOpInterface branchOp, RegionBranchSuccessorMapping &mapping, RegionBranchPoint src)
static bool traverseRegionGraph(Region *begin, StopConditionFn stopConditionFn)
Traverse the region graph starting at begin.
static LogicalResult computeReachableValuesFromSuccessorInput(llvm::SmallDenseSet< Value > &result, Value value, const RegionBranchInverseSuccessorMapping &inputToOperands, std::optional< unsigned > maxReachableValues=std::nullopt)
Compute all non-successor-input values that a successor input could have based on the given successor...
static bool canReachCycle(ArrayRef< Region * > entryRegions)
Return "true" if a cycle in the region graph is reachable from one of entryRegions,...
static RegionBranchInverseSuccessorMapping invertRegionBranchSuccessorMapping(const RegionBranchSuccessorMapping &operandToInputs)
function_ref< bool(Region *)> StopConditionFn
Stop condition for traverseRegionGraph.
static SmallVector< Region * > filterRegionSuccessors(ArrayRef< RegionSuccessor > successors)
Return the regions in successors.
static bool isRegionReachable(Region *begin, Region *r)
Return true if region r is reachable from region begin according to the RegionBranchOpInterface (by t...
*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
*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 MutableArrayRef< OpOperand > operandsToOpOperands(OperandRange &operands)
static Operation * getOwnerOfValue(Value value)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
IRValueT get() const
Return the current value being used by this operand.
This class represents a diagnostic that is inflight and set to be reported.
This class provides a mutable adaptor for a range of operands.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
This class represents an operand of an operation.
This class implements the operand iterators for the Operation class.
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
type_range getTypes() const
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.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
OperationName getName()
The name of an operation is the key identifier for it.
Block * getSuccessor(unsigned index)
result_range getResults()
Region * getParentRegion()
Returns the region to which the instruction belongs.
unsigned getNumResults()
Return the number of results held by this operation.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
static constexpr RegionBranchPoint parent()
Returns an instance of RegionBranchPoint representing the parent operation.
RegionBranchTerminatorOpInterface getTerminatorPredecessorOrNull() const
Returns the terminator if branching from a region.
This class represents a successor of a region.
Region * getSuccessor() const
Return the given region successor.
bool isOperation() const
Return true if the successor is an operation.
Operation * getSuccessorOp() const
Return the given operation successor.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
BlockArgListType getArguments()
unsigned getRegionNumber()
Return the number of this region in the parent operation.
unsigned getNumArguments()
Operation * getParentOp()
Return the parent operation this region is attached to.
bool hasOneBlock()
Return true if this region has exactly one block.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
RewritePattern is the common base class for all DAG to DAG replacements.
void eraseOperands(Operation *op, const BitVector &eraseIndices)
Erase the operands selected by eraseIndices and update operandSegmentSizes if the operation has AttrS...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
Operation * eraseOpResults(Operation *op, const BitVector &eraseIndices)
Erase the specified results of the given operation.
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
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,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
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.
SuccessorOperands(MutableOperandRange forwardedOperands)
Constructs a SuccessorOperands with no produced operands that simply forwards operands to the success...
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.
OperandRange getForwardedOperands() const
Get the range of operands that are simply forwarded to the successor.
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.
type_range getTypes() const
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.
void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Region * getParentRegion()
Return the Region in which this Value is defined.
std::optional< BlockArgument > getBranchSuccessorArgument(const SuccessorOperands &operands, unsigned operandIndex, Block *successor)
Return the BlockArgument corresponding to operand operandIndex in some successor if operandIndex is w...
LogicalResult verifyRegionBranchWeights(Operation *op)
Verify that the region weights attached to an operation implementing WeightedRegiobBranchOpInterface ...
LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo, const SuccessorOperands &operands)
Verify that the given operands match those of the given successor block.
LogicalResult verifyRegionBranchOpInterface(Operation *op)
Verify that types match along control flow edges described the given op.
LogicalResult verifyBranchWeights(Operation *op)
Verify that the branch weights attached to an operation implementing WeightedBranchOpInterface are co...
InFlightDiagnostic & next(InFlightDiagnostic &diag)
Starts a new message part in an in-flight diagnostic.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
DenseMap< OpOperand *, SmallVector< Value > > RegionBranchSuccessorMapping
A mapping from successor operands to successor inputs.
std::function< LogicalResult(Operation *)> PatternMatcherFn
Helper function for the region branch op inlining pattern that checks if the pattern is applicable to...
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
std::function< Value(OpBuilder &, Location, Value)> NonSuccessorInputReplacementBuilderFn
Helper function for the region branch op inlining pattern that builds replacement values for non-succ...
Region * getEnclosingRepetitiveRegion(Operation *op)
Return the first enclosing region of the given op that may be executed repetitively as per RegionBran...
DenseMap< Value, SmallVector< OpOperand * > > RegionBranchInverseSuccessorMapping
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
void populateRegionBranchOpInterfaceInliningPattern(RewritePatternSet &patterns, StringRef opName, NonSuccessorInputReplacementBuilderFn replBuilderFn=detail::defaultReplBuilderFn, PatternMatcherFn matcherFn=detail::defaultMatcherFn, PatternBenefit benefit=1)
Populate a pattern that inlines the body of region branch ops when there is a single acyclic path thr...
void populateRegionBranchOpInterfaceCanonicalizationPatterns(RewritePatternSet &patterns, StringRef opName, PatternBenefit benefit=1)
Populate canonicalization patterns that simplify successor operands/inputs of region branch operation...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
llvm::function_ref< Fn > function_ref