16#include "llvm/ADT/EquivalenceClasses.h"
17#include "llvm/Support/DebugLog.h"
25#include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
28 : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
33 : producedOperandCount(producedOperandCount),
34 forwardedOperands(std::move(forwardedOperands)) {}
43std::optional<BlockArgument>
45 unsigned operandIndex,
Block *successor) {
46 LDBG() <<
"Getting branch successor argument for operand index "
47 << operandIndex <<
" in successor block";
51 if (forwardedOperands.empty()) {
52 LDBG() <<
"No forwarded operands, returning nullopt";
58 if (operandIndex < operandsStart ||
59 operandIndex >= (operandsStart + forwardedOperands.size())) {
60 LDBG() <<
"Operand index " << operandIndex <<
" out of range ["
61 << operandsStart <<
", "
62 << (operandsStart + forwardedOperands.size())
63 <<
"), returning nullopt";
70 LDBG() <<
"Computed argument index " << argIndex <<
" for successor block";
78 LDBG() <<
"Verifying branch successor operands for successor #" << succNo
79 <<
" in operation " << op->
getName();
82 unsigned operandCount = operands.
size();
84 LDBG() <<
"Branch has " << operandCount <<
" operands, target block has "
88 return op->
emitError() <<
"branch has " << operandCount
89 <<
" operands for successor #" << succNo
90 <<
", but target block has "
94 LDBG() <<
"Checking type compatibility for "
96 <<
" forwarded operands";
99 Type operandType = operands[i].getType();
101 LDBG() <<
"Checking type compatibility: operand type " << operandType
102 <<
" vs argument type " << argType;
104 if (!cast<BranchOpInterface>(op).areTypesCompatible(operandType, argType))
105 return op->
emitError() <<
"type mismatch for bb argument #" << i
106 <<
" of successor #" << succNo;
109 LDBG() <<
"Branch successor operand verification successful";
119 std::size_t expectedWeightsNum,
120 llvm::StringRef weightAnchorName,
121 llvm::StringRef weightRefName) {
125 if (weights.size() != expectedWeightsNum)
126 return op->
emitError() <<
"expects number of " << weightAnchorName
127 <<
" weights to match number of " << weightRefName
128 <<
": " << weights.size() <<
" vs "
129 << expectedWeightsNum;
131 if (llvm::all_of(weights, [](int32_t value) {
return value == 0; }))
132 return op->
emitError() <<
"branch weights cannot all be zero";
139 cast<WeightedBranchOpInterface>(op).getWeights();
150 cast<WeightedRegionBranchOpInterface>(op).getWeights();
160 auto regionInterface = cast<RegionBranchOpInterface>(op);
165 regionInterface.getAllRegionBranchPoints();
168 regionInterface.getSuccessorRegions(branchPoint, successors);
172 auto emitRegionEdgeError = [&]() {
174 regionInterface->emitOpError(
"along control flow edge from ");
175 if (branchPoint.isParent()) {
177 diag.attachNote(op->
getLoc()) <<
"region branch point";
180 << branchPoint.getTerminatorPredecessorOrNull()->getName();
182 branchPoint.getTerminatorPredecessorOrNull()->getLoc())
183 <<
"region branch point";
186 if (
Region *region = successor.getSuccessor()) {
187 diag <<
"Region #" << region->getRegionNumber();
196 regionInterface.getSuccessorOperands(branchPoint, successor);
197 ValueRange succInputs = regionInterface.getSuccessorInputs(successor);
198 if (succOperands.size() != succInputs.size()) {
199 return emitRegionEdgeError()
200 <<
": region branch point has " << succOperands.size()
201 <<
" operands, but region successor needs " << succInputs.size()
208 for (
const auto &typesIdx :
209 llvm::enumerate(llvm::zip(succOperandTypes, succInputTypes))) {
210 Type succOperandType = std::get<0>(typesIdx.value());
211 Type succInputType = std::get<1>(typesIdx.value());
212 if (!regionInterface.areTypesCompatible(succOperandType, succInputType))
213 return emitRegionEdgeError()
214 <<
": successor operand type #" << typesIdx.index() <<
" "
215 << succOperandType <<
" should match successor input type #"
216 << typesIdx.index() <<
" " << succInputType;
235 auto op = cast<RegionBranchOpInterface>(begin->
getParentOp());
236 LDBG() <<
"Starting region graph traversal from region #"
241 LDBG() <<
"Initialized visited array with " << op->getNumRegions()
246 auto enqueueAllSuccessors = [&](
Region *region) {
247 LDBG() <<
"Enqueuing successors for region #" << region->getRegionNumber();
249 for (
Block &block : *region) {
253 dyn_cast<RegionBranchTerminatorOpInterface>(block.back());
257 operandAttributes.resize(terminator->getNumOperands());
258 terminator.getSuccessorRegions(operandAttributes, successors);
259 LDBG() <<
"Found " << successors.size()
260 <<
" successors from terminator in block";
262 if (!successor.isParent()) {
263 worklist.push_back(successor.getSuccessor());
264 LDBG() <<
"Added region #"
265 << successor.getSuccessor()->getRegionNumber()
268 LDBG() <<
"Skipping parent successor";
273 enqueueAllSuccessors(begin);
274 LDBG() <<
"Initial worklist size: " << worklist.size();
277 while (!worklist.empty()) {
278 Region *nextRegion = worklist.pop_back_val();
280 <<
" from worklist (remaining: " << worklist.size() <<
")";
282 if (stopConditionFn(nextRegion, visited)) {
283 LDBG() <<
"Stop condition met for region #"
288 llvm::errs() <<
"Region " << *nextRegion <<
" has no parent op\n";
293 <<
" already visited, skipping";
299 enqueueAllSuccessors(nextRegion);
302 LDBG() <<
"Traversal completed, returning false";
310 "expected that both regions belong to the same op");
314 return nextRegion == r;
328 LDBG() <<
"Checking if operations are in mutually exclusive regions: "
329 << a->
getName() <<
" and " <<
b->getName();
331 assert(a &&
"expected non-empty operation");
332 assert(
b &&
"expected non-empty operation");
336 LDBG() <<
"Checking branch operation " << branchOp->getName();
339 if (!branchOp->isProperAncestor(
b)) {
340 LDBG() <<
"Operation b is not inside branchOp, checking next ancestor";
342 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
346 LDBG() <<
"Both operations are inside branchOp, finding their regions";
350 Region *regionA =
nullptr, *regionB =
nullptr;
351 for (
Region &r : branchOp->getRegions()) {
352 if (r.findAncestorOpInRegion(*a)) {
353 assert(!regionA &&
"already found a region for a");
355 LDBG() <<
"Found region #" << r.
getRegionNumber() <<
" for operation a";
357 if (r.findAncestorOpInRegion(*
b)) {
358 assert(!regionB &&
"already found a region for b");
360 LDBG() <<
"Found region #" << r.getRegionNumber() <<
" for operation b";
363 assert(regionA && regionB &&
"could not find region of op");
365 LDBG() <<
"Region A: #" << regionA->
getRegionNumber() <<
", Region B: #"
366 << regionB->getRegionNumber();
370 bool regionsAreDistinct = (regionA != regionB);
374 LDBG() <<
"Regions distinct: " << regionsAreDistinct
375 <<
", A not reachable from B: " << aNotReachableFromB
376 <<
", B not reachable from A: " << bNotReachableFromA;
378 bool mutuallyExclusive =
379 regionsAreDistinct && aNotReachableFromB && bNotReachableFromA;
380 LDBG() <<
"Operations are mutually exclusive: " << mutuallyExclusive;
382 return mutuallyExclusive;
387 LDBG() <<
"No common RegionBranchOpInterface found, operations are not "
388 "mutually exclusive";
392bool RegionBranchOpInterface::isRepetitiveRegion(
unsigned index) {
393 LDBG() <<
"Checking if region #" <<
index <<
" is repetitive in operation "
394 << getOperation()->getName();
396 Region *region = &getOperation()->getRegion(
index);
399 LDBG() <<
"Region #" <<
index <<
" is repetitive: " << isRepetitive;
403bool RegionBranchOpInterface::hasLoop() {
404 LDBG() <<
"Checking if operation " << getOperation()->getName()
409 LDBG() <<
"Found " << entryRegions.size() <<
" entry regions";
412 if (!successor.isParent()) {
413 LDBG() <<
"Checking entry region #"
414 << successor.getSuccessor()->getRegionNumber() <<
" for loops";
421 return visited[nextRegion->getRegionNumber()];
425 LDBG() <<
"Found loop in entry region #"
426 << successor.getSuccessor()->getRegionNumber();
430 LDBG() <<
"Skipping parent successor";
434 LDBG() <<
"No loops found in operation";
442 return getEntrySuccessorOperands(dest);
447RegionBranchOpInterface::getNonSuccessorInputs(
RegionSuccessor successor) {
452 ValueRange successorInputs = getSuccessorInputs(successor);
453 if (!successorInputs.empty()) {
454 unsigned inputBegin =
456 ? cast<OpResult>(successorInputs.front()).getResultNumber()
457 : cast<BlockArgument>(successorInputs.front()).getArgNumber();
458 results.erase(results.begin() + inputBegin,
459 results.begin() + inputBegin + successorInputs.size());
473 branchOp.getSuccessorRegions(src, successors);
475 OperandRange operands = branchOp.getSuccessorOperands(src, dst);
476 assert(operands.size() == branchOp.getSuccessorInputs(dst).size() &&
477 "expected the same number of operands and inputs");
478 for (
const auto &[operand, input] : llvm::zip_equal(
480 mapping[&operand].push_back(input);
483void RegionBranchOpInterface::getSuccessorOperandInputMapping(
485 std::optional<RegionBranchPoint> src) {
486 if (src.has_value()) {
499 for (
const auto &[operand, inputs] : operandToInputs) {
500 for (
Value input : inputs)
501 inputToOperands[input].push_back(operand);
503 return inputToOperands;
506void RegionBranchOpInterface::getSuccessorInputOperandMapping(
514RegionBranchOpInterface::getAllRegionBranchPoints() {
517 for (
Region ®ion : getOperation()->getRegions()) {
518 for (
Block &block : region) {
521 if (
auto terminator =
522 dyn_cast<RegionBranchTerminatorOpInterface>(block.back()))
530 LDBG() <<
"Finding enclosing repetitive region for operation "
534 LDBG() <<
"Checking region #" << region->getRegionNumber()
535 <<
" in operation " << region->getParentOp()->getName();
538 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
540 <<
"Found RegionBranchOpInterface, checking if region is repetitive";
541 if (branchOp.isRepetitiveRegion(region->getRegionNumber())) {
542 LDBG() <<
"Found repetitive region #" << region->getRegionNumber();
546 LDBG() <<
"Parent operation does not implement RegionBranchOpInterface";
550 LDBG() <<
"No enclosing repetitive region found";
555 LDBG() <<
"Finding enclosing repetitive region for value";
563 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
565 <<
"Found RegionBranchOpInterface, checking if region is repetitive";
571 LDBG() <<
"Parent operation does not implement RegionBranchOpInterface";
576 LDBG() <<
"No enclosing repetitive region found for value";
585 assert((
b.getDefiningOp() == regionBranchOp ||
586 b.getParentRegion()->getParentOp() == regionBranchOp) &&
587 "b must be a region successor input");
600 if (isa<OpResult>(
b))
610 assert(isa<BlockArgument>(
b) &&
"b must be a block argument");
611 return isa<BlockArgument>(a) && cast<BlockArgument>(a).getOwner() ==
612 cast<BlockArgument>(
b).getOwner();
657 assert(inputToOperands.contains(value) &&
"value must be a successor input");
662 llvm::SmallDenseSet<Value> reachableValues;
663 llvm::SmallDenseSet<Value> visited;
665 worklist.push_back(value);
666 while (!worklist.empty()) {
667 Value next = worklist.pop_back_val();
668 auto it = inputToOperands.find(next);
669 if (it == inputToOperands.end()) {
670 reachableValues.insert(next);
674 if (visited.insert(operand->
get()).second)
675 worklist.push_back(operand->
get());
679 return reachableValues;
708struct MakeRegionBranchOpSuccessorInputsDead :
public RewritePattern {
709 MakeRegionBranchOpSuccessorInputsDead(MLIRContext *context, StringRef name,
710 PatternBenefit benefit = 1)
711 : RewritePattern(name, benefit, context) {}
713 LogicalResult matchAndRewrite(Operation *op,
714 PatternRewriter &rewriter)
const override {
715 assert(!op->
hasTrait<OpTrait::IsIsolatedFromAbove>() &&
716 "isolated-from-above ops are not supported");
719 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
721 regionBranchOp.getSuccessorInputOperandMapping(inputToOperands);
725 for (Value value : inputToOperands.keys()) {
727 if (value.use_empty())
731 llvm::SmallDenseSet<Value> reachableValues =
733 if (reachableValues.size() != 1)
735 assert(*reachableValues.begin() != value &&
736 "successor inputs are supposed to be excluded");
758template <
typename MappingTy,
typename KeyTy>
759static BitVector &lookupOrCreateBitVector(MappingTy &mapping, KeyTy key,
761 return mapping.try_emplace(key, size,
false).first->second;
774static llvm::EquivalenceClasses<Value> computeTiedSuccessorInputs(
776 llvm::EquivalenceClasses<Value> tiedSuccessorInputs;
777 for (
const auto &[operand, inputs] : operandToInputs) {
778 assert(!inputs.empty() &&
"expected non-empty inputs");
779 Value firstInput = inputs.front();
780 tiedSuccessorInputs.insert(firstInput);
781 for (
Value nextInput : llvm::drop_begin(inputs)) {
784 tiedSuccessorInputs.unionSets(firstInput, nextInput);
787 return tiedSuccessorInputs;
829struct RemoveDeadRegionBranchOpSuccessorInputs :
public RewritePattern {
830 RemoveDeadRegionBranchOpSuccessorInputs(MLIRContext *context, StringRef name,
831 PatternBenefit benefit = 1)
832 : RewritePattern(name, benefit, context) {}
834 LogicalResult matchAndRewrite(Operation *op,
835 PatternRewriter &rewriter)
const override {
836 assert(!op->
hasTrait<OpTrait::IsIsolatedFromAbove>() &&
837 "isolated-from-above ops are not supported");
842 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
844 regionBranchOp.getSuccessorOperandInputMapping(operandToInputs);
845 llvm::EquivalenceClasses<Value> tiedSuccessorInputs =
846 computeTiedSuccessorInputs(operandToInputs);
849 SmallVector<Value> valuesToRemove;
851 BitVector resultsToRemove(regionBranchOp->getNumResults(),
false);
853 for (
auto it = tiedSuccessorInputs.begin(), e = tiedSuccessorInputs.end();
855 if (!(*it)->isLeader())
861 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
862 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
864 if (!memberIt->use_empty()) {
874 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
875 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
876 if (
auto arg = dyn_cast<BlockArgument>(*memberIt)) {
879 lookupOrCreateBitVector(blockArgsToRemove, arg.getOwner(),
880 arg.getOwner()->getNumArguments());
881 vector.set(arg.getArgNumber());
884 OpResult
result = cast<OpResult>(*memberIt);
885 assert(
result.getDefiningOp() == regionBranchOp &&
886 "result must be a region branch op result");
887 resultsToRemove.set(
result.getResultNumber());
889 valuesToRemove.push_back(*memberIt);
893 if (valuesToRemove.empty())
900 for (Value value : valuesToRemove) {
901 for (OpOperand *operand : inputsToOperands[value]) {
904 lookupOrCreateBitVector(operandsToRemove, operand->getOwner(),
905 operand->getOwner()->getNumOperands());
906 vector.set(operand->getOperandNumber());
911 for (
auto &pair : operandsToRemove) {
912 Operation *op = pair.first;
913 BitVector &operands = pair.second;
918 for (
auto &pair : blockArgsToRemove) {
919 Block *block = pair.first;
920 BitVector &blockArg = pair.second;
922 [&]() { block->eraseArguments(blockArg); });
926 if (resultsToRemove.any())
935 void *aOwner, *bOwner;
936 if (
auto arg = dyn_cast<BlockArgument>(a))
937 aOwner = arg.getOwner();
940 if (
auto arg = dyn_cast<BlockArgument>(
b))
941 bOwner = arg.getOwner();
943 bOwner =
b.getDefiningOp();
944 return aOwner == bOwner;
948static unsigned getArgOrResultNumber(
Value value) {
949 if (
auto opResult = llvm::dyn_cast<OpResult>(value))
950 return opResult.getResultNumber();
951 return llvm::cast<BlockArgument>(value).getArgNumber();
986 RemoveDuplicateSuccessorInputUses(MLIRContext *context, StringRef name,
987 PatternBenefit benefit = 1)
988 : RewritePattern(name, benefit, context) {}
990 LogicalResult matchAndRewrite(Operation *op,
991 PatternRewriter &rewriter)
const override {
992 assert(!op->
hasTrait<OpTrait::IsIsolatedFromAbove>() &&
993 "isolated-from-above ops are not supported");
1001 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
1003 regionBranchOp.getSuccessorInputOperandMapping(inputsToOperands);
1004 SmallVector<Value> inputs = llvm::to_vector(inputsToOperands.keys());
1005 llvm::sort(inputs, [](Value a, Value
b) {
1006 return getArgOrResultNumber(a) < getArgOrResultNumber(
b);
1012 unsigned numInputs = inputs.size();
1013 for (
auto i : llvm::seq<unsigned>(0, numInputs)) {
1014 Value input1 = inputs[i];
1015 for (
auto j : llvm::seq<unsigned>(i + 1, numInputs)) {
1016 Value input2 = inputs[j];
1023 if (!haveSameOwner(input1, input2))
1029 llvm::SmallDenseMap<Operation *, Value> operands1, operands2;
1030 for (OpOperand *operand : inputsToOperands[input1]) {
1031 assert(!operands1.contains(operand->getOwner()));
1032 operands1[operand->getOwner()] = operand->get();
1034 for (OpOperand *operand : inputsToOperands[input2]) {
1035 assert(!operands2.contains(operand->getOwner()));
1036 operands2[operand->getOwner()] = operand->get();
1038 if (operands1 == operands2) {
1052 return llvm::map_to_vector(values, [](
Value value) {
1063getSuccessorRegionsWithAttrs(RegionBranchOpInterface op,
1067 op.getEntrySuccessorRegions(extractConstants(op->getOperands()),
1071 RegionBranchTerminatorOpInterface terminator =
1073 terminator.getSuccessorRegions(extractConstants(terminator->getOperands()),
1098computeSingleAcyclicRegionBranchPath(RegionBranchOpInterface op) {
1099 llvm::SmallDenseSet<Region *> visited;
1106 getSuccessorRegionsWithAttrs(op, next);
1107 if (successors.size() != 1) {
1112 path.push_back(successors.front());
1113 if (successors.front().isParent()) {
1117 Region *region = successors.front().getSuccessor();
1123 if (!visited.insert(region).second) {
1128 dyn_cast<RegionBranchTerminatorOpInterface>(®ion->
front().
back());
1136 llvm_unreachable(
"expected to return from loop");
1174 InlineRegionBranchOp(MLIRContext *context, StringRef name,
1177 : RewritePattern(name, benefit, context), replBuilderFn(replBuilderFn),
1178 matcherFn(matcherFn) {}
1180 LogicalResult matchAndRewrite(Operation *op,
1181 PatternRewriter &rewriter)
const override {
1183 if (
failed(matcherFn(op)))
1188 if (!op->
hasTrait<OpTrait::HasRecursiveMemoryEffects>())
1190 op,
"pattern not applicable to ops without recursive memory effects");
1193 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
1194 SmallVector<RegionSuccessor> path =
1195 computeSingleAcyclicRegionBranchPath(regionBranchOp);
1198 op,
"failed to find acyclic region branch path");
1202 ArrayRef remainingPath = path;
1203 SmallVector<Value> successorOperands = llvm::to_vector(
1204 regionBranchOp.getEntrySuccessorOperands(remainingPath.front()));
1205 while (!remainingPath.empty()) {
1206 RegionSuccessor nextSuccessor = remainingPath.consume_front();
1208 regionBranchOp.getSuccessorInputs(nextSuccessor);
1209 assert(successorInputs.size() == successorOperands.size() &&
1213 unsigned firstSuccessorInputIdx = 0;
1214 if (!successorInputs.empty())
1215 firstSuccessorInputIdx =
1217 ? cast<OpResult>(successorInputs.front()).getResultNumber()
1218 : cast<BlockArgument>(successorInputs.front()).getArgNumber();
1220 unsigned numValues =
1225 SmallVector<Value> replacements;
1227 auto getValue = [&](
unsigned idx) {
1230 : Value(nextSuccessor.getSuccessor()->getArgument(idx));
1234 for (
unsigned i = 0; i < firstSuccessorInputIdx; ++i)
1235 replacements.push_back(
1236 replBuilderFn(rewriter, op->
getLoc(), getValue(i)));
1239 llvm::append_range(replacements, successorOperands);
1242 for (
unsigned i = replacements.size(); i < numValues; ++i)
1243 replacements.push_back(
1244 replBuilderFn(rewriter, op->
getLoc(), getValue(i)));
1248 assert(remainingPath.empty() &&
"expected that the path ended");
1255 auto terminator = cast<RegionBranchTerminatorOpInterface>(
1260 successorOperands = llvm::to_vector(
1261 terminator.getSuccessorOperands(remainingPath.front()));
1265 llvm_unreachable(
"expected that paths ends with parent");
1275 patterns.add<MakeRegionBranchOpSuccessorInputsDead,
1276 RemoveDuplicateSuccessorInputUses,
1277 RemoveDeadRegionBranchOpSuccessorInputs>(
patterns.getContext(),
1286 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 void getSuccessorOperandInputMapping(RegionBranchOpInterface branchOp, RegionBranchSuccessorMapping &mapping, RegionBranchPoint src)
static bool traverseRegionGraph(Region *begin, StopConditionFn stopConditionFn)
Traverse the region graph starting at begin.
static llvm::SmallDenseSet< Value > computeReachableValuesFromSuccessorInput(Value value, const RegionBranchInverseSuccessorMapping &inputToOperands)
Compute all non-successor-input values that a successor input could have based on the given successor...
static RegionBranchInverseSuccessorMapping invertRegionBranchSuccessorMapping(const RegionBranchSuccessorMapping &operandToInputs)
function_ref< bool(Region *, ArrayRef< bool > visited)> StopConditionFn
Stop condition for traverseRegionGraph.
static bool isRegionReachable(Region *begin, Region *r)
Return true if region r is reachable from region begin according to the RegionBranchOpInterface (by t...
static std::string diag(const llvm::Value &value)
static MutableArrayRef< OpOperand > operandsToOpOperands(OperandRange &operands)
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()
void eraseOperands(unsigned idx, unsigned length=1)
Erase the operands starting at position idx and ending at position 'idx'+'length'.
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)
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.
bool isParent() const
Return true if the successor is the parent operation.
Region * getSuccessor() const
Return the given region 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.
RewritePattern is the common base class for all DAG to DAG replacements.
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...
bool use_empty() const
Returns true if this value has no uses.
Type getType() const
Return the type of this value.
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...
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.
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
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...
const FrozenRewritePatternSet & patterns
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