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 &&
826template <
typename MappingTy,
typename KeyTy>
827static BitVector &lookupOrCreateBitVector(MappingTy &mapping, KeyTy key,
829 return mapping.try_emplace(key, size,
false).first->second;
842static llvm::EquivalenceClasses<Value> computeTiedSuccessorInputs(
844 llvm::EquivalenceClasses<Value> tiedSuccessorInputs;
845 for (
const auto &[operand, inputs] : operandToInputs) {
846 assert(!inputs.empty() &&
"expected non-empty inputs");
847 Value firstInput = inputs.front();
848 tiedSuccessorInputs.insert(firstInput);
849 for (
Value nextInput : llvm::drop_begin(inputs)) {
852 tiedSuccessorInputs.unionSets(firstInput, nextInput);
855 return tiedSuccessorInputs;
897struct RemoveDeadRegionBranchOpSuccessorInputs :
public RewritePattern {
898 RemoveDeadRegionBranchOpSuccessorInputs(MLIRContext *context, StringRef name,
899 PatternBenefit benefit = 1)
900 : RewritePattern(name, benefit, context) {}
902 LogicalResult matchAndRewrite(Operation *op,
903 PatternRewriter &rewriter)
const override {
907 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
909 regionBranchOp.getSuccessorOperandInputMapping(operandToInputs);
910 llvm::EquivalenceClasses<Value> tiedSuccessorInputs =
911 computeTiedSuccessorInputs(operandToInputs);
914 SmallVector<Value> valuesToRemove;
916 BitVector resultsToRemove(regionBranchOp->getNumResults(),
false);
918 for (
auto it = tiedSuccessorInputs.begin(), e = tiedSuccessorInputs.end();
920 if (!(*it)->isLeader())
926 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
927 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
929 if (!memberIt->use_empty()) {
939 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
940 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
941 if (
auto arg = dyn_cast<BlockArgument>(*memberIt)) {
944 lookupOrCreateBitVector(blockArgsToRemove, arg.getOwner(),
945 arg.getOwner()->getNumArguments());
946 vector.set(arg.getArgNumber());
949 OpResult
result = cast<OpResult>(*memberIt);
950 assert(
result.getDefiningOp() == regionBranchOp &&
951 "result must be a region branch op result");
952 resultsToRemove.set(
result.getResultNumber());
954 valuesToRemove.push_back(*memberIt);
958 if (valuesToRemove.empty())
965 for (Value value : valuesToRemove) {
966 for (OpOperand *operand : inputsToOperands[value]) {
969 lookupOrCreateBitVector(operandsToRemove, operand->getOwner(),
970 operand->getOwner()->getNumOperands());
971 vector.set(operand->getOperandNumber());
976 for (
auto &pair : operandsToRemove) {
977 Operation *op = pair.first;
978 BitVector &operands = pair.second;
983 for (
auto &pair : blockArgsToRemove) {
984 Block *block = pair.first;
985 BitVector &blockArg = pair.second;
987 [&]() { block->eraseArguments(blockArg); });
991 if (resultsToRemove.any())
1001 if (
auto arg = dyn_cast<BlockArgument>(value))
1002 return arg.getOwner();
1007static unsigned getArgOrResultNumber(
Value value) {
1008 if (
auto opResult = llvm::dyn_cast<OpResult>(value))
1009 return opResult.getResultNumber();
1010 return llvm::cast<BlockArgument>(value).getArgNumber();
1044struct RemoveDuplicateSuccessorInputUses :
public RewritePattern {
1045 RemoveDuplicateSuccessorInputUses(MLIRContext *context, StringRef name,
1046 PatternBenefit benefit = 1)
1047 : RewritePattern(name, benefit, context) {}
1049 LogicalResult matchAndRewrite(Operation *op,
1050 PatternRewriter &rewriter)
const override {
1057 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
1059 regionBranchOp.getSuccessorInputOperandMapping(inputsToOperands);
1060 SmallVector<Value> inputs = llvm::to_vector(inputsToOperands.keys());
1061 llvm::sort(inputs, [](Value a, Value
b) {
1062 return getArgOrResultNumber(a) < getArgOrResultNumber(
b);
1075 using SigEntry = std::pair<Operation *, Value>;
1076 using Signature = SmallVector<SigEntry>;
1077 auto sigEntryLess = [](
const SigEntry &a,
const SigEntry &
b) {
1078 if (a.first !=
b.first)
1079 return a.first <
b.first;
1088 using MapKey = std::tuple<Signature, void *, Type>;
1089 auto mapKeyLess = [&](
const MapKey &a,
const MapKey &
b) {
1090 if (std::get<1>(a) != std::get<1>(
b))
1091 return std::get<1>(a) < std::get<1>(
b);
1092 if (std::get<2>(a) != std::get<2>(
b))
1093 return std::get<2>(a).getAsOpaquePointer() <
1094 std::get<2>(
b).getAsOpaquePointer();
1095 return std::lexicographical_compare(
1096 std::get<0>(a).begin(), std::get<0>(a).end(), std::get<0>(
b).begin(),
1097 std::get<0>(
b).end(), sigEntryLess);
1099 std::map<MapKey, Value,
decltype(mapKeyLess)> signatureToCanonical(
1101 bool changed =
false;
1104 for (Value input : inputs) {
1108 for (OpOperand *operand : inputsToOperands[input])
1109 sig.emplace_back(operand->getOwner(), operand->get());
1110 llvm::sort(sig, sigEntryLess);
1114 auto [it,
inserted] = signatureToCanonical.try_emplace(
1115 MapKey{std::move(sig), owner, input.getType()}, input);
1117 Value canonical = it->second;
1119 if (input.use_empty())
1133 return llvm::map_to_vector(values, [](
Value value) {
1144getSuccessorRegionsWithAttrs(RegionBranchOpInterface op,
1148 op.getEntrySuccessorRegions(extractConstants(op->getOperands()),
1152 RegionBranchTerminatorOpInterface terminator =
1154 terminator.getSuccessorRegions(extractConstants(terminator->getOperands()),
1180computeSingleAcyclicRegionBranchPath(RegionBranchOpInterface op) {
1181 llvm::SmallDenseSet<Region *> visited;
1188 getSuccessorRegionsWithAttrs(op, next);
1189 if (successors.size() != 1) {
1194 path.push_back(successors.front());
1195 if (successors.front().isOperation()) {
1199 Region *region = successors.front().getSuccessor();
1205 if (!visited.insert(region).second) {
1210 dyn_cast<RegionBranchTerminatorOpInterface>(®ion->
front().
back());
1218 llvm_unreachable(
"expected to return from loop");
1256 InlineRegionBranchOp(MLIRContext *context, StringRef name,
1259 : RewritePattern(name, benefit, context), replBuilderFn(replBuilderFn),
1260 matcherFn(matcherFn) {}
1262 LogicalResult matchAndRewrite(Operation *op,
1263 PatternRewriter &rewriter)
const override {
1265 if (
failed(matcherFn(op)))
1270 if (!op->
hasTrait<OpTrait::HasRecursiveMemoryEffects>())
1272 op,
"pattern not applicable to ops without recursive memory effects");
1275 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
1276 SmallVector<RegionSuccessor> path =
1277 computeSingleAcyclicRegionBranchPath(regionBranchOp);
1280 op,
"failed to find acyclic region branch path");
1284 ArrayRef remainingPath = path;
1285 SmallVector<Value> successorOperands = llvm::to_vector(
1286 regionBranchOp.getEntrySuccessorOperands(remainingPath.front()));
1287 while (!remainingPath.empty()) {
1288 RegionSuccessor nextSuccessor = remainingPath.consume_front();
1290 regionBranchOp.getSuccessorInputs(nextSuccessor);
1291 assert(successorInputs.size() == successorOperands.size() &&
1295 unsigned firstSuccessorInputIdx = 0;
1296 if (!successorInputs.empty())
1297 firstSuccessorInputIdx =
1299 ? cast<OpResult>(successorInputs.front()).getResultNumber()
1300 : cast<BlockArgument>(successorInputs.front()).getArgNumber();
1302 unsigned numValues =
1307 SmallVector<Value> replacements;
1309 auto getValue = [&](
unsigned idx) {
1312 : Value(nextSuccessor.getSuccessor()->getArgument(idx));
1316 for (
unsigned i = 0; i < firstSuccessorInputIdx; ++i)
1317 replacements.push_back(
1318 replBuilderFn(rewriter, op->
getLoc(), getValue(i)));
1321 llvm::append_range(replacements, successorOperands);
1324 for (
unsigned i = replacements.size(); i < numValues; ++i)
1325 replacements.push_back(
1326 replBuilderFn(rewriter, op->
getLoc(), getValue(i)));
1332 op,
"path ends after a different operation");
1333 assert(remainingPath.empty() &&
"expected that the path ended");
1340 auto terminator = cast<RegionBranchTerminatorOpInterface>(
1345 successorOperands = llvm::to_vector(
1346 terminator.getSuccessorOperands(remainingPath.front()));
1350 llvm_unreachable(
"expected that path ends with an operation");
1360 patterns.
add<MakeRegionBranchOpSuccessorInputsDead,
1361 RemoveDuplicateSuccessorInputUses,
1362 RemoveDeadRegionBranchOpSuccessorInputs>(patterns.
getContext(),
1370 patterns.
add<InlineRegionBranchOp>(patterns.
getContext(), opName,
1371 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