15#include "llvm/ADT/EquivalenceClasses.h"
16#include "llvm/Support/DebugLog.h"
24#include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
27 : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
32 : producedOperandCount(producedOperandCount),
33 forwardedOperands(std::move(forwardedOperands)) {}
42std::optional<BlockArgument>
44 unsigned operandIndex,
Block *successor) {
45 LDBG() <<
"Getting branch successor argument for operand index "
46 << operandIndex <<
" in successor block";
50 if (forwardedOperands.empty()) {
51 LDBG() <<
"No forwarded operands, returning nullopt";
57 if (operandIndex < operandsStart ||
58 operandIndex >= (operandsStart + forwardedOperands.size())) {
59 LDBG() <<
"Operand index " << operandIndex <<
" out of range ["
60 << operandsStart <<
", "
61 << (operandsStart + forwardedOperands.size())
62 <<
"), returning nullopt";
69 LDBG() <<
"Computed argument index " << argIndex <<
" for successor block";
77 LDBG() <<
"Verifying branch successor operands for successor #" << succNo
78 <<
" in operation " << op->
getName();
81 unsigned operandCount = operands.
size();
83 LDBG() <<
"Branch has " << operandCount <<
" operands, target block has "
87 return op->
emitError() <<
"branch has " << operandCount
88 <<
" operands for successor #" << succNo
89 <<
", but target block has "
93 LDBG() <<
"Checking type compatibility for "
95 <<
" forwarded operands";
98 Type operandType = operands[i].getType();
100 LDBG() <<
"Checking type compatibility: operand type " << operandType
101 <<
" vs argument type " << argType;
103 if (!cast<BranchOpInterface>(op).areTypesCompatible(operandType, argType))
104 return op->
emitError() <<
"type mismatch for bb argument #" << i
105 <<
" of successor #" << succNo;
108 LDBG() <<
"Branch successor operand verification successful";
118 std::size_t expectedWeightsNum,
119 llvm::StringRef weightAnchorName,
120 llvm::StringRef weightRefName) {
124 if (weights.size() != expectedWeightsNum)
125 return op->
emitError() <<
"expects number of " << weightAnchorName
126 <<
" weights to match number of " << weightRefName
127 <<
": " << weights.size() <<
" vs "
128 << expectedWeightsNum;
130 if (llvm::all_of(weights, [](int32_t value) {
return value == 0; }))
131 return op->
emitError() <<
"branch weights cannot all be zero";
138 cast<WeightedBranchOpInterface>(op).getWeights();
149 cast<WeightedRegionBranchOpInterface>(op).getWeights();
159 auto regionInterface = cast<RegionBranchOpInterface>(op);
164 regionInterface.getAllRegionBranchPoints();
167 regionInterface.getSuccessorRegions(branchPoint, successors);
171 auto emitRegionEdgeError = [&]() {
173 regionInterface->emitOpError(
"along control flow edge from ");
174 if (branchPoint.isParent()) {
176 diag.attachNote(op->
getLoc()) <<
"region branch point";
179 << branchPoint.getTerminatorPredecessorOrNull()->getName();
181 branchPoint.getTerminatorPredecessorOrNull()->getLoc())
182 <<
"region branch point";
185 if (
Region *region = successor.getSuccessor()) {
186 diag <<
"Region #" << region->getRegionNumber();
195 regionInterface.getSuccessorOperands(branchPoint, successor);
196 ValueRange succInputs = regionInterface.getSuccessorInputs(successor);
197 if (succOperands.size() != succInputs.size()) {
198 return emitRegionEdgeError()
199 <<
": region branch point has " << succOperands.size()
200 <<
" operands, but region successor needs " << succInputs.size()
207 for (
const auto &typesIdx :
208 llvm::enumerate(llvm::zip(succOperandTypes, succInputTypes))) {
209 Type succOperandType = std::get<0>(typesIdx.value());
210 Type succInputType = std::get<1>(typesIdx.value());
211 if (!regionInterface.areTypesCompatible(succOperandType, succInputType))
212 return emitRegionEdgeError()
213 <<
": successor operand type #" << typesIdx.index() <<
" "
214 << succOperandType <<
" should match successor input type #"
215 << typesIdx.index() <<
" " << succInputType;
234 auto op = cast<RegionBranchOpInterface>(begin->
getParentOp());
235 LDBG() <<
"Starting region graph traversal from region #"
240 LDBG() <<
"Initialized visited array with " << op->getNumRegions()
245 auto enqueueAllSuccessors = [&](
Region *region) {
246 LDBG() <<
"Enqueuing successors for region #" << region->getRegionNumber();
248 for (
Block &block : *region) {
252 dyn_cast<RegionBranchTerminatorOpInterface>(block.back());
256 operandAttributes.resize(terminator->getNumOperands());
257 terminator.getSuccessorRegions(operandAttributes, successors);
258 LDBG() <<
"Found " << successors.size()
259 <<
" successors from terminator in block";
261 if (!successor.isParent()) {
262 worklist.push_back(successor.getSuccessor());
263 LDBG() <<
"Added region #"
264 << successor.getSuccessor()->getRegionNumber()
267 LDBG() <<
"Skipping parent successor";
272 enqueueAllSuccessors(begin);
273 LDBG() <<
"Initial worklist size: " << worklist.size();
276 while (!worklist.empty()) {
277 Region *nextRegion = worklist.pop_back_val();
279 <<
" from worklist (remaining: " << worklist.size() <<
")";
281 if (stopConditionFn(nextRegion, visited)) {
282 LDBG() <<
"Stop condition met for region #"
287 llvm::errs() <<
"Region " << *nextRegion <<
" has no parent op\n";
292 <<
" already visited, skipping";
298 enqueueAllSuccessors(nextRegion);
301 LDBG() <<
"Traversal completed, returning false";
309 "expected that both regions belong to the same op");
313 return nextRegion == r;
327 LDBG() <<
"Checking if operations are in mutually exclusive regions: "
328 << a->
getName() <<
" and " <<
b->getName();
330 assert(a &&
"expected non-empty operation");
331 assert(
b &&
"expected non-empty operation");
335 LDBG() <<
"Checking branch operation " << branchOp->getName();
338 if (!branchOp->isProperAncestor(
b)) {
339 LDBG() <<
"Operation b is not inside branchOp, checking next ancestor";
341 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
345 LDBG() <<
"Both operations are inside branchOp, finding their regions";
349 Region *regionA =
nullptr, *regionB =
nullptr;
350 for (
Region &r : branchOp->getRegions()) {
351 if (r.findAncestorOpInRegion(*a)) {
352 assert(!regionA &&
"already found a region for a");
354 LDBG() <<
"Found region #" << r.
getRegionNumber() <<
" for operation a";
356 if (r.findAncestorOpInRegion(*
b)) {
357 assert(!regionB &&
"already found a region for b");
359 LDBG() <<
"Found region #" << r.getRegionNumber() <<
" for operation b";
362 assert(regionA && regionB &&
"could not find region of op");
364 LDBG() <<
"Region A: #" << regionA->
getRegionNumber() <<
", Region B: #"
365 << regionB->getRegionNumber();
369 bool regionsAreDistinct = (regionA != regionB);
373 LDBG() <<
"Regions distinct: " << regionsAreDistinct
374 <<
", A not reachable from B: " << aNotReachableFromB
375 <<
", B not reachable from A: " << bNotReachableFromA;
377 bool mutuallyExclusive =
378 regionsAreDistinct && aNotReachableFromB && bNotReachableFromA;
379 LDBG() <<
"Operations are mutually exclusive: " << mutuallyExclusive;
381 return mutuallyExclusive;
386 LDBG() <<
"No common RegionBranchOpInterface found, operations are not "
387 "mutually exclusive";
391bool RegionBranchOpInterface::isRepetitiveRegion(
unsigned index) {
392 LDBG() <<
"Checking if region #" <<
index <<
" is repetitive in operation "
393 << getOperation()->getName();
395 Region *region = &getOperation()->getRegion(
index);
398 LDBG() <<
"Region #" <<
index <<
" is repetitive: " << isRepetitive;
402bool RegionBranchOpInterface::hasLoop() {
403 LDBG() <<
"Checking if operation " << getOperation()->getName()
408 LDBG() <<
"Found " << entryRegions.size() <<
" entry regions";
411 if (!successor.isParent()) {
412 LDBG() <<
"Checking entry region #"
413 << successor.getSuccessor()->getRegionNumber() <<
" for loops";
420 return visited[nextRegion->getRegionNumber()];
424 LDBG() <<
"Found loop in entry region #"
425 << successor.getSuccessor()->getRegionNumber();
429 LDBG() <<
"Skipping parent successor";
433 LDBG() <<
"No loops found in operation";
441 return getEntrySuccessorOperands(dest);
442 auto terminator = cast<RegionBranchTerminatorOpInterface>(
444 return terminator.getSuccessorOperands(dest);
456 branchOp.getSuccessorRegions(src, successors);
458 OperandRange operands = branchOp.getSuccessorOperands(src, dst);
459 assert(operands.size() == branchOp.getSuccessorInputs(dst).size() &&
460 "expected the same number of operands and inputs");
461 for (
const auto &[operand, input] : llvm::zip_equal(
463 mapping[&operand].push_back(input);
466void RegionBranchOpInterface::getSuccessorOperandInputMapping(
468 std::optional<RegionBranchPoint> src) {
469 if (src.has_value()) {
482 for (
const auto &[operand, inputs] : operandToInputs) {
483 for (
Value input : inputs)
484 inputToOperands[input].push_back(operand);
486 return inputToOperands;
489void RegionBranchOpInterface::getSuccessorInputOperandMapping(
497RegionBranchOpInterface::getAllRegionBranchPoints() {
500 for (
Region ®ion : getOperation()->getRegions()) {
501 for (
Block &block : region) {
504 if (
auto terminator =
505 dyn_cast<RegionBranchTerminatorOpInterface>(block.back()))
513 LDBG() <<
"Finding enclosing repetitive region for operation "
517 LDBG() <<
"Checking region #" << region->getRegionNumber()
518 <<
" in operation " << region->getParentOp()->getName();
521 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
523 <<
"Found RegionBranchOpInterface, checking if region is repetitive";
524 if (branchOp.isRepetitiveRegion(region->getRegionNumber())) {
525 LDBG() <<
"Found repetitive region #" << region->getRegionNumber();
529 LDBG() <<
"Parent operation does not implement RegionBranchOpInterface";
533 LDBG() <<
"No enclosing repetitive region found";
538 LDBG() <<
"Finding enclosing repetitive region for value";
546 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
548 <<
"Found RegionBranchOpInterface, checking if region is repetitive";
554 LDBG() <<
"Parent operation does not implement RegionBranchOpInterface";
559 LDBG() <<
"No enclosing repetitive region found for value";
568 assert((
b.getDefiningOp() == regionBranchOp ||
569 b.getParentRegion()->getParentOp() == regionBranchOp) &&
570 "b must be a region successor input");
583 if (isa<OpResult>(
b))
593 assert(isa<BlockArgument>(
b) &&
"b must be a block argument");
594 return isa<BlockArgument>(a) && cast<BlockArgument>(a).getOwner() ==
595 cast<BlockArgument>(
b).getOwner();
640 assert(inputToOperands.contains(value) &&
"value must be a successor input");
645 llvm::SmallDenseSet<Value> reachableValues;
646 llvm::SmallDenseSet<Value> visited;
648 worklist.push_back(value);
649 while (!worklist.empty()) {
650 Value next = worklist.pop_back_val();
651 auto it = inputToOperands.find(next);
652 if (it == inputToOperands.end()) {
653 reachableValues.insert(next);
657 if (visited.insert(operand->
get()).second)
658 worklist.push_back(operand->
get());
662 return reachableValues;
691struct MakeRegionBranchOpSuccessorInputsDead :
public RewritePattern {
692 MakeRegionBranchOpSuccessorInputsDead(MLIRContext *context, StringRef name,
693 PatternBenefit benefit = 1)
694 : RewritePattern(name, benefit, context) {}
696 LogicalResult matchAndRewrite(Operation *op,
697 PatternRewriter &rewriter)
const override {
698 assert(!op->
hasTrait<OpTrait::IsIsolatedFromAbove>() &&
699 "isolated-from-above ops are not supported");
702 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
704 regionBranchOp.getSuccessorInputOperandMapping(inputToOperands);
708 for (Value value : inputToOperands.keys()) {
710 if (value.use_empty())
714 llvm::SmallDenseSet<Value> reachableValues =
716 if (reachableValues.size() != 1)
718 assert(*reachableValues.begin() != value &&
719 "successor inputs are supposed to be excluded");
741template <
typename MappingTy,
typename KeyTy>
742static BitVector &lookupOrCreateBitVector(MappingTy &mapping, KeyTy key,
744 return mapping.try_emplace(key, size,
false).first->second;
757static llvm::EquivalenceClasses<Value> computeTiedSuccessorInputs(
759 llvm::EquivalenceClasses<Value> tiedSuccessorInputs;
760 for (
const auto &[operand, inputs] : operandToInputs) {
761 assert(!inputs.empty() &&
"expected non-empty inputs");
762 Value firstInput = inputs.front();
763 tiedSuccessorInputs.insert(firstInput);
764 for (
Value nextInput : llvm::drop_begin(inputs)) {
767 tiedSuccessorInputs.unionSets(firstInput, nextInput);
770 return tiedSuccessorInputs;
812struct RemoveDeadRegionBranchOpSuccessorInputs :
public RewritePattern {
813 RemoveDeadRegionBranchOpSuccessorInputs(MLIRContext *context, StringRef name,
814 PatternBenefit benefit = 1)
815 : RewritePattern(name, benefit, context) {}
817 LogicalResult matchAndRewrite(Operation *op,
818 PatternRewriter &rewriter)
const override {
819 assert(!op->
hasTrait<OpTrait::IsIsolatedFromAbove>() &&
820 "isolated-from-above ops are not supported");
825 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
827 regionBranchOp.getSuccessorOperandInputMapping(operandToInputs);
828 llvm::EquivalenceClasses<Value> tiedSuccessorInputs =
829 computeTiedSuccessorInputs(operandToInputs);
832 SmallVector<Value> valuesToRemove;
834 BitVector resultsToRemove(regionBranchOp->getNumResults(),
false);
836 for (
auto it = tiedSuccessorInputs.begin(), e = tiedSuccessorInputs.end();
838 if (!(*it)->isLeader())
844 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
845 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
847 if (!memberIt->use_empty()) {
857 for (
auto memberIt = tiedSuccessorInputs.member_begin(**it);
858 memberIt != tiedSuccessorInputs.member_end(); ++memberIt) {
859 if (
auto arg = dyn_cast<BlockArgument>(*memberIt)) {
862 lookupOrCreateBitVector(blockArgsToRemove, arg.getOwner(),
863 arg.getOwner()->getNumArguments());
864 vector.set(arg.getArgNumber());
867 OpResult
result = cast<OpResult>(*memberIt);
868 assert(
result.getDefiningOp() == regionBranchOp &&
869 "result must be a region branch op result");
870 resultsToRemove.set(
result.getResultNumber());
872 valuesToRemove.push_back(*memberIt);
876 if (valuesToRemove.empty())
883 for (Value value : valuesToRemove) {
884 for (OpOperand *operand : inputsToOperands[value]) {
887 lookupOrCreateBitVector(operandsToRemove, operand->getOwner(),
888 operand->getOwner()->getNumOperands());
889 vector.set(operand->getOperandNumber());
894 for (
auto &pair : operandsToRemove) {
895 Operation *op = pair.first;
896 BitVector &operands = pair.second;
901 for (
auto &pair : blockArgsToRemove) {
902 Block *block = pair.first;
903 BitVector &blockArg = pair.second;
905 [&]() { block->eraseArguments(blockArg); });
909 if (resultsToRemove.any())
918 void *aOwner, *bOwner;
919 if (
auto arg = dyn_cast<BlockArgument>(a))
920 aOwner = arg.getOwner();
923 if (
auto arg = dyn_cast<BlockArgument>(
b))
924 bOwner = arg.getOwner();
926 bOwner =
b.getDefiningOp();
927 return aOwner == bOwner;
931static unsigned getArgOrResultNumber(
Value value) {
932 if (
auto opResult = llvm::dyn_cast<OpResult>(value))
933 return opResult.getResultNumber();
934 return llvm::cast<BlockArgument>(value).getArgNumber();
969 RemoveDuplicateSuccessorInputUses(MLIRContext *context, StringRef name,
970 PatternBenefit benefit = 1)
971 : RewritePattern(name, benefit, context) {}
973 LogicalResult matchAndRewrite(Operation *op,
974 PatternRewriter &rewriter)
const override {
975 assert(!op->
hasTrait<OpTrait::IsIsolatedFromAbove>() &&
976 "isolated-from-above ops are not supported");
984 auto regionBranchOp = cast<RegionBranchOpInterface>(op);
986 regionBranchOp.getSuccessorInputOperandMapping(inputsToOperands);
987 SmallVector<Value> inputs = llvm::to_vector(inputsToOperands.keys());
988 llvm::sort(inputs, [](Value a, Value
b) {
989 return getArgOrResultNumber(a) < getArgOrResultNumber(
b);
995 unsigned numInputs = inputs.size();
996 for (
auto i : llvm::seq<unsigned>(0, numInputs)) {
997 Value input1 = inputs[i];
998 for (
auto j : llvm::seq<unsigned>(i + 1, numInputs)) {
999 Value input2 = inputs[j];
1006 if (!haveSameOwner(input1, input2))
1012 llvm::SmallDenseMap<Operation *, Value> operands1, operands2;
1013 for (OpOperand *operand : inputsToOperands[input1]) {
1014 assert(!operands1.contains(operand->getOwner()));
1015 operands1[operand->getOwner()] = operand->get();
1017 for (OpOperand *operand : inputsToOperands[input2]) {
1018 assert(!operands2.contains(operand->getOwner()));
1019 operands2[operand->getOwner()] = operand->get();
1021 if (operands1 == operands2) {
1034 patterns.add<MakeRegionBranchOpSuccessorInputsDead,
1035 RemoveDuplicateSuccessorInputUses,
1036 RemoveDeadRegionBranchOpSuccessorInputs>(
patterns.getContext(),
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)
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.
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'.
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.
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.
Operation * getTerminatorPredecessorOrNull() const
Returns the terminator if branching from a region.
static constexpr RegionBranchPoint parent()
Returns an instance of RegionBranchPoint representing the parent operation.
This class represents a successor of a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Operation * getParentOp()
Return the parent operation this region is attached to.
RewritePattern is the common base class for all DAG to DAG replacements.
Operation * eraseOpResults(Operation *op, const BitVector &eraseIndices)
Erase the specified results of the given operation.
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.
DenseMap< OpOperand *, SmallVector< Value > > RegionBranchSuccessorMapping
A mapping from successor operands to successor inputs.
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
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 populateRegionBranchOpInterfaceCanonicalizationPatterns(RewritePatternSet &patterns, StringRef opName, PatternBenefit benefit=1)
Populate canonicalization patterns that simplify successor operands/inputs of region branch operation...
llvm::function_ref< Fn > function_ref