xref: /llvm-project/mlir/lib/Interfaces/ControlFlowInterfaces.cpp (revision dd450f08cfeb9da372cbe459058bc9ae9425f862)
17ce1e7abSRiver Riddle //===- ControlFlowInterfaces.cpp - ControlFlow Interfaces -----------------===//
27ce1e7abSRiver Riddle //
37ce1e7abSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47ce1e7abSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
57ce1e7abSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67ce1e7abSRiver Riddle //
77ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
87ce1e7abSRiver Riddle 
9f9735be7SMehdi Amini #include <utility>
10f9735be7SMehdi Amini 
11537f2208SMogball #include "mlir/IR/BuiltinTypes.h"
127ce1e7abSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.h"
13a3ad8f92SRahul Joshi #include "llvm/ADT/SmallPtrSet.h"
147ce1e7abSRiver Riddle 
157ce1e7abSRiver Riddle using namespace mlir;
167ce1e7abSRiver Riddle 
177ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
187ce1e7abSRiver Riddle // ControlFlowInterfaces
197ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
207ce1e7abSRiver Riddle 
217ce1e7abSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
227ce1e7abSRiver Riddle 
SuccessorOperands(MutableOperandRange forwardedOperands)230c789db5SMarkus Böck SuccessorOperands::SuccessorOperands(MutableOperandRange forwardedOperands)
24f9735be7SMehdi Amini     : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
25f9735be7SMehdi Amini }
260c789db5SMarkus Böck 
SuccessorOperands(unsigned int producedOperandCount,MutableOperandRange forwardedOperands)270c789db5SMarkus Böck SuccessorOperands::SuccessorOperands(unsigned int producedOperandCount,
280c789db5SMarkus Böck                                      MutableOperandRange forwardedOperands)
290c789db5SMarkus Böck     : producedOperandCount(producedOperandCount),
300c789db5SMarkus Böck       forwardedOperands(std::move(forwardedOperands)) {}
310c789db5SMarkus Böck 
327ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
337ce1e7abSRiver Riddle // BranchOpInterface
347ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
357ce1e7abSRiver Riddle 
367ce1e7abSRiver Riddle /// Returns the `BlockArgument` corresponding to operand `operandIndex` in some
37192d9dd7SKazu Hirata /// successor if 'operandIndex' is within the range of 'operands', or
38192d9dd7SKazu Hirata /// std::nullopt if `operandIndex` isn't a successor operand index.
3922426110SRamkumar Ramachandra std::optional<BlockArgument>
getBranchSuccessorArgument(const SuccessorOperands & operands,unsigned operandIndex,Block * successor)400c789db5SMarkus Böck detail::getBranchSuccessorArgument(const SuccessorOperands &operands,
41a3ad8f92SRahul Joshi                                    unsigned operandIndex, Block *successor) {
420c789db5SMarkus Böck   OperandRange forwardedOperands = operands.getForwardedOperands();
437ce1e7abSRiver Riddle   // Check that the operands are valid.
440c789db5SMarkus Böck   if (forwardedOperands.empty())
451a36588eSKazu Hirata     return std::nullopt;
467ce1e7abSRiver Riddle 
477ce1e7abSRiver Riddle   // Check to ensure that this operand is within the range.
480c789db5SMarkus Böck   unsigned operandsStart = forwardedOperands.getBeginOperandIndex();
497ce1e7abSRiver Riddle   if (operandIndex < operandsStart ||
500c789db5SMarkus Böck       operandIndex >= (operandsStart + forwardedOperands.size()))
511a36588eSKazu Hirata     return std::nullopt;
527ce1e7abSRiver Riddle 
537ce1e7abSRiver Riddle   // Index the successor.
540c789db5SMarkus Böck   unsigned argIndex =
550c789db5SMarkus Böck       operands.getProducedOperandCount() + operandIndex - operandsStart;
567ce1e7abSRiver Riddle   return successor->getArgument(argIndex);
577ce1e7abSRiver Riddle }
587ce1e7abSRiver Riddle 
597ce1e7abSRiver Riddle /// Verify that the given operands match those of the given successor block.
607ce1e7abSRiver Riddle LogicalResult
verifyBranchSuccessorOperands(Operation * op,unsigned succNo,const SuccessorOperands & operands)61a3ad8f92SRahul Joshi detail::verifyBranchSuccessorOperands(Operation *op, unsigned succNo,
620c789db5SMarkus Böck                                       const SuccessorOperands &operands) {
637ce1e7abSRiver Riddle   // Check the count.
640c789db5SMarkus Böck   unsigned operandCount = operands.size();
657ce1e7abSRiver Riddle   Block *destBB = op->getSuccessor(succNo);
667ce1e7abSRiver Riddle   if (operandCount != destBB->getNumArguments())
677ce1e7abSRiver Riddle     return op->emitError() << "branch has " << operandCount
687ce1e7abSRiver Riddle                            << " operands for successor #" << succNo
697ce1e7abSRiver Riddle                            << ", but target block has "
707ce1e7abSRiver Riddle                            << destBB->getNumArguments();
717ce1e7abSRiver Riddle 
727ce1e7abSRiver Riddle   // Check the types.
730c789db5SMarkus Böck   for (unsigned i = operands.getProducedOperandCount(); i != operandCount;
740c789db5SMarkus Böck        ++i) {
75e7c7b16aSMogball     if (!cast<BranchOpInterface>(op).areTypesCompatible(
760c789db5SMarkus Böck             operands[i].getType(), destBB->getArgument(i).getType()))
777ce1e7abSRiver Riddle       return op->emitError() << "type mismatch for bb argument #" << i
787ce1e7abSRiver Riddle                              << " of successor #" << succNo;
797ce1e7abSRiver Riddle   }
807ce1e7abSRiver Riddle   return success();
817ce1e7abSRiver Riddle }
82a3ad8f92SRahul Joshi 
83a3ad8f92SRahul Joshi //===----------------------------------------------------------------------===//
84a3ad8f92SRahul Joshi // RegionBranchOpInterface
85a3ad8f92SRahul Joshi //===----------------------------------------------------------------------===//
86a3ad8f92SRahul Joshi 
printRegionEdgeName(InFlightDiagnostic & diag,RegionBranchPoint sourceNo,RegionBranchPoint succRegionNo)874dd744acSMarkus Böck static InFlightDiagnostic &printRegionEdgeName(InFlightDiagnostic &diag,
884dd744acSMarkus Böck                                                RegionBranchPoint sourceNo,
894dd744acSMarkus Böck                                                RegionBranchPoint succRegionNo) {
90a3ad8f92SRahul Joshi   diag << "from ";
914dd744acSMarkus Böck   if (Region *region = sourceNo.getRegionOrNull())
924dd744acSMarkus Böck     diag << "Region #" << region->getRegionNumber();
93a3ad8f92SRahul Joshi   else
94be35264aSSean Silva     diag << "parent operands";
95a3ad8f92SRahul Joshi 
96a3ad8f92SRahul Joshi   diag << " to ";
974dd744acSMarkus Böck   if (Region *region = succRegionNo.getRegionOrNull())
984dd744acSMarkus Böck     diag << "Region #" << region->getRegionNumber();
99a3ad8f92SRahul Joshi   else
100be35264aSSean Silva     diag << "parent results";
101a3ad8f92SRahul Joshi   return diag;
1025b29f86bSMarkus Böck }
103a3ad8f92SRahul Joshi 
1045b29f86bSMarkus Böck /// Verify that types match along all region control flow edges originating from
105d56537a5SMatthias Springer /// `sourcePoint`. `getInputsTypesForRegion` is a function that returns the
106d56537a5SMatthias Springer /// types of the inputs that flow to a successor region.
1074dd744acSMarkus Böck static LogicalResult
verifyTypesAlongAllEdges(Operation * op,RegionBranchPoint sourcePoint,function_ref<FailureOr<TypeRange> (RegionBranchPoint)> getInputsTypesForRegion)1084dd744acSMarkus Böck verifyTypesAlongAllEdges(Operation *op, RegionBranchPoint sourcePoint,
1094dd744acSMarkus Böck                          function_ref<FailureOr<TypeRange>(RegionBranchPoint)>
1105b29f86bSMarkus Böck                              getInputsTypesForRegion) {
1115b29f86bSMarkus Böck   auto regionInterface = cast<RegionBranchOpInterface>(op);
1125b29f86bSMarkus Böck 
1135b29f86bSMarkus Böck   SmallVector<RegionSuccessor, 2> successors;
1144dd744acSMarkus Böck   regionInterface.getSuccessorRegions(sourcePoint, successors);
1155b29f86bSMarkus Böck 
1165b29f86bSMarkus Böck   for (RegionSuccessor &succ : successors) {
1174dd744acSMarkus Böck     FailureOr<TypeRange> sourceTypes = getInputsTypesForRegion(succ);
1185b29f86bSMarkus Böck     if (failed(sourceTypes))
1195b29f86bSMarkus Böck       return failure();
12079716559SAlex Zinenko 
121a3ad8f92SRahul Joshi     TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes();
12279716559SAlex Zinenko     if (sourceTypes->size() != succInputsTypes.size()) {
123a3ad8f92SRahul Joshi       InFlightDiagnostic diag = op->emitOpError(" region control flow edge ");
1244dd744acSMarkus Böck       return printRegionEdgeName(diag, sourcePoint, succ)
1255b29f86bSMarkus Böck              << ": source has " << sourceTypes->size()
126be35264aSSean Silva              << " operands, but target successor needs "
127a3ad8f92SRahul Joshi              << succInputsTypes.size();
128a3ad8f92SRahul Joshi     }
129a3ad8f92SRahul Joshi 
130e4853be2SMehdi Amini     for (const auto &typesIdx :
13179716559SAlex Zinenko          llvm::enumerate(llvm::zip(*sourceTypes, succInputsTypes))) {
132a3ad8f92SRahul Joshi       Type sourceType = std::get<0>(typesIdx.value());
133a3ad8f92SRahul Joshi       Type inputType = std::get<1>(typesIdx.value());
134e7c7b16aSMogball       if (!regionInterface.areTypesCompatible(sourceType, inputType)) {
135a3ad8f92SRahul Joshi         InFlightDiagnostic diag = op->emitOpError(" along control flow edge ");
1364dd744acSMarkus Böck         return printRegionEdgeName(diag, sourcePoint, succ)
137be35264aSSean Silva                << ": source type #" << typesIdx.index() << " " << sourceType
138be35264aSSean Silva                << " should match input type #" << typesIdx.index() << " "
139a3ad8f92SRahul Joshi                << inputType;
140a3ad8f92SRahul Joshi       }
141a3ad8f92SRahul Joshi     }
142a3ad8f92SRahul Joshi   }
143a3ad8f92SRahul Joshi   return success();
144a3ad8f92SRahul Joshi }
145a3ad8f92SRahul Joshi 
146a3ad8f92SRahul Joshi /// Verify that types match along control flow edges described the given op.
verifyTypesAlongControlFlowEdges(Operation * op)147a3ad8f92SRahul Joshi LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) {
148a3ad8f92SRahul Joshi   auto regionInterface = cast<RegionBranchOpInterface>(op);
149a3ad8f92SRahul Joshi 
150d56537a5SMatthias Springer   auto inputTypesFromParent = [&](RegionBranchPoint point) -> TypeRange {
151d56537a5SMatthias Springer     return regionInterface.getEntrySuccessorOperands(point).getTypes();
152a3ad8f92SRahul Joshi   };
153a3ad8f92SRahul Joshi 
154a3ad8f92SRahul Joshi   // Verify types along control flow edges originating from the parent.
1554dd744acSMarkus Böck   if (failed(verifyTypesAlongAllEdges(op, RegionBranchPoint::parent(),
1564dd744acSMarkus Böck                                       inputTypesFromParent)))
157a3ad8f92SRahul Joshi     return failure();
158a3ad8f92SRahul Joshi 
159e7c7b16aSMogball   auto areTypesCompatible = [&](TypeRange lhs, TypeRange rhs) {
160e7c7b16aSMogball     if (lhs.size() != rhs.size())
161e7c7b16aSMogball       return false;
162e7c7b16aSMogball     for (auto types : llvm::zip(lhs, rhs)) {
163e7c7b16aSMogball       if (!regionInterface.areTypesCompatible(std::get<0>(types),
164e7c7b16aSMogball                                               std::get<1>(types))) {
165e7c7b16aSMogball         return false;
166e7c7b16aSMogball       }
167e7c7b16aSMogball     }
168e7c7b16aSMogball     return true;
169e7c7b16aSMogball   };
170e7c7b16aSMogball 
171a3ad8f92SRahul Joshi   // Verify types along control flow edges originating from each region.
1724dd744acSMarkus Böck   for (Region &region : op->getRegions()) {
173a3ad8f92SRahul Joshi 
1745b29f86bSMarkus Böck     // Since there can be multiple terminators implementing the
1755b29f86bSMarkus Böck     // `RegionBranchTerminatorOpInterface`, all should have the same operand
1765b29f86bSMarkus Böck     // types when passing them to the same region.
177a3ad8f92SRahul Joshi 
1785b29f86bSMarkus Böck     SmallVector<RegionBranchTerminatorOpInterface> regionReturnOps;
1795b29f86bSMarkus Böck     for (Block &block : region)
180a0c19bd4SMaksim Levental       if (!block.empty())
181a0c19bd4SMaksim Levental         if (auto terminator =
182a0c19bd4SMaksim Levental                 dyn_cast<RegionBranchTerminatorOpInterface>(block.back()))
1835b29f86bSMarkus Böck           regionReturnOps.push_back(terminator);
1845b29f86bSMarkus Böck 
1855b29f86bSMarkus Böck     // If there is no return-like terminator, the op itself should verify
1865b29f86bSMarkus Böck     // type consistency.
1875b29f86bSMarkus Böck     if (regionReturnOps.empty())
188a3ad8f92SRahul Joshi       continue;
189a3ad8f92SRahul Joshi 
1905b29f86bSMarkus Böck     auto inputTypesForRegion =
191d56537a5SMatthias Springer         [&](RegionBranchPoint point) -> FailureOr<TypeRange> {
1925b29f86bSMarkus Böck       std::optional<OperandRange> regionReturnOperands;
1935b29f86bSMarkus Böck       for (RegionBranchTerminatorOpInterface regionReturnOp : regionReturnOps) {
194d56537a5SMatthias Springer         auto terminatorOperands = regionReturnOp.getSuccessorOperands(point);
1955b29f86bSMarkus Böck 
19604253320SMarcel Koester         if (!regionReturnOperands) {
19704253320SMarcel Koester           regionReturnOperands = terminatorOperands;
198a3ad8f92SRahul Joshi           continue;
199a3ad8f92SRahul Joshi         }
200a3ad8f92SRahul Joshi 
2015b29f86bSMarkus Böck         // Found more than one ReturnLike terminator. Make sure the operand
2025b29f86bSMarkus Böck         // types match with the first one.
203e7c7b16aSMogball         if (!areTypesCompatible(regionReturnOperands->getTypes(),
2045b29f86bSMarkus Böck                                 terminatorOperands.getTypes())) {
2055b29f86bSMarkus Böck           InFlightDiagnostic diag = op->emitOpError(" along control flow edge");
206d56537a5SMatthias Springer           return printRegionEdgeName(diag, region, point)
207a3ad8f92SRahul Joshi                  << " operands mismatch between return-like terminators";
208a3ad8f92SRahul Joshi         }
2095b29f86bSMarkus Böck       }
21079716559SAlex Zinenko 
21104253320SMarcel Koester       // All successors get the same set of operand types.
21204253320SMarcel Koester       return TypeRange(regionReturnOperands->getTypes());
213a3ad8f92SRahul Joshi     };
214a3ad8f92SRahul Joshi 
2154dd744acSMarkus Böck     if (failed(verifyTypesAlongAllEdges(op, region, inputTypesForRegion)))
216a3ad8f92SRahul Joshi       return failure();
217a3ad8f92SRahul Joshi   }
218a3ad8f92SRahul Joshi 
219a3ad8f92SRahul Joshi   return success();
220a3ad8f92SRahul Joshi }
22104253320SMarcel Koester 
222*dd450f08SMatthias Springer /// Stop condition for `traverseRegionGraph`. The traversal is interrupted if
223*dd450f08SMatthias Springer /// this function returns "true" for a successor region. The first parameter is
224*dd450f08SMatthias Springer /// the successor region. The second parameter indicates all already visited
225*dd450f08SMatthias Springer /// regions.
226*dd450f08SMatthias Springer using StopConditionFn = function_ref<bool(Region *, ArrayRef<bool> visited)>;
227*dd450f08SMatthias Springer 
228*dd450f08SMatthias Springer /// Traverse the region graph starting at `begin`. The traversal is interrupted
229*dd450f08SMatthias Springer /// if `stopCondition` evaluates to "true" for a successor region. In that case,
230*dd450f08SMatthias Springer /// this function returns "true". Otherwise, if the traversal was not
231*dd450f08SMatthias Springer /// interrupted, this function returns "false".
traverseRegionGraph(Region * begin,StopConditionFn stopConditionFn)232*dd450f08SMatthias Springer static bool traverseRegionGraph(Region *begin,
233*dd450f08SMatthias Springer                                 StopConditionFn stopConditionFn) {
234a3005a40SMatthias Springer   auto op = cast<RegionBranchOpInterface>(begin->getParentOp());
235a3005a40SMatthias Springer   SmallVector<bool> visited(op->getNumRegions(), false);
236a3005a40SMatthias Springer   visited[begin->getRegionNumber()] = true;
237a3005a40SMatthias Springer 
238a3005a40SMatthias Springer   // Retrieve all successors of the region and enqueue them in the worklist.
2394dd744acSMarkus Böck   SmallVector<Region *> worklist;
2404dd744acSMarkus Böck   auto enqueueAllSuccessors = [&](Region *region) {
241a3005a40SMatthias Springer     SmallVector<RegionSuccessor> successors;
2424dd744acSMarkus Böck     op.getSuccessorRegions(region, successors);
243a3005a40SMatthias Springer     for (RegionSuccessor successor : successors)
244a3005a40SMatthias Springer       if (!successor.isParent())
2454dd744acSMarkus Böck         worklist.push_back(successor.getSuccessor());
246a3005a40SMatthias Springer   };
2474dd744acSMarkus Böck   enqueueAllSuccessors(begin);
248a3005a40SMatthias Springer 
249a3005a40SMatthias Springer   // Process all regions in the worklist via DFS.
250a3005a40SMatthias Springer   while (!worklist.empty()) {
2514dd744acSMarkus Böck     Region *nextRegion = worklist.pop_back_val();
252*dd450f08SMatthias Springer     if (stopConditionFn(nextRegion, visited))
253a3005a40SMatthias Springer       return true;
2544dd744acSMarkus Böck     if (visited[nextRegion->getRegionNumber()])
255a3005a40SMatthias Springer       continue;
2564dd744acSMarkus Böck     visited[nextRegion->getRegionNumber()] = true;
257a3005a40SMatthias Springer     enqueueAllSuccessors(nextRegion);
258a3005a40SMatthias Springer   }
259a3005a40SMatthias Springer 
260a3005a40SMatthias Springer   return false;
261a3005a40SMatthias Springer }
262a3005a40SMatthias Springer 
263*dd450f08SMatthias Springer /// Return `true` if region `r` is reachable from region `begin` according to
264*dd450f08SMatthias Springer /// the RegionBranchOpInterface (by taking a branch).
isRegionReachable(Region * begin,Region * r)265*dd450f08SMatthias Springer static bool isRegionReachable(Region *begin, Region *r) {
266*dd450f08SMatthias Springer   assert(begin->getParentOp() == r->getParentOp() &&
267*dd450f08SMatthias Springer          "expected that both regions belong to the same op");
268*dd450f08SMatthias Springer   return traverseRegionGraph(begin,
269*dd450f08SMatthias Springer                              [&](Region *nextRegion, ArrayRef<bool> visited) {
270*dd450f08SMatthias Springer                                // Interrupt traversal if `r` was reached.
271*dd450f08SMatthias Springer                                return nextRegion == r;
272*dd450f08SMatthias Springer                              });
273*dd450f08SMatthias Springer }
274*dd450f08SMatthias Springer 
275a5c2f782SMatthias Springer /// Return `true` if `a` and `b` are in mutually exclusive regions.
276a5c2f782SMatthias Springer ///
277a5c2f782SMatthias Springer /// 1. Find the first common of `a` and `b` (ancestor) that implements
278a5c2f782SMatthias Springer ///    RegionBranchOpInterface.
279a5c2f782SMatthias Springer /// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are
280a5c2f782SMatthias Springer ///    contained.
281a5c2f782SMatthias Springer /// 3. Check if `regionA` and `regionB` are mutually exclusive. They are
282a5c2f782SMatthias Springer ///    mutually exclusive if they are not reachable from each other as per
283a5c2f782SMatthias Springer ///    RegionBranchOpInterface::getSuccessorRegions.
insideMutuallyExclusiveRegions(Operation * a,Operation * b)284a5c2f782SMatthias Springer bool mlir::insideMutuallyExclusiveRegions(Operation *a, Operation *b) {
285a5c2f782SMatthias Springer   assert(a && "expected non-empty operation");
286a5c2f782SMatthias Springer   assert(b && "expected non-empty operation");
287a5c2f782SMatthias Springer 
288a5c2f782SMatthias Springer   auto branchOp = a->getParentOfType<RegionBranchOpInterface>();
289a5c2f782SMatthias Springer   while (branchOp) {
290a5c2f782SMatthias Springer     // Check if b is inside branchOp. (We already know that a is.)
291a5c2f782SMatthias Springer     if (!branchOp->isProperAncestor(b)) {
292a5c2f782SMatthias Springer       // Check next enclosing RegionBranchOpInterface.
293a5c2f782SMatthias Springer       branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
294a5c2f782SMatthias Springer       continue;
295a5c2f782SMatthias Springer     }
296a5c2f782SMatthias Springer 
297a5c2f782SMatthias Springer     // b is contained in branchOp. Retrieve the regions in which `a` and `b`
298a5c2f782SMatthias Springer     // are contained.
299a5c2f782SMatthias Springer     Region *regionA = nullptr, *regionB = nullptr;
300a5c2f782SMatthias Springer     for (Region &r : branchOp->getRegions()) {
301a5c2f782SMatthias Springer       if (r.findAncestorOpInRegion(*a)) {
302a5c2f782SMatthias Springer         assert(!regionA && "already found a region for a");
303a5c2f782SMatthias Springer         regionA = &r;
304a5c2f782SMatthias Springer       }
305a5c2f782SMatthias Springer       if (r.findAncestorOpInRegion(*b)) {
306a5c2f782SMatthias Springer         assert(!regionB && "already found a region for b");
307a5c2f782SMatthias Springer         regionB = &r;
308a5c2f782SMatthias Springer       }
309a5c2f782SMatthias Springer     }
310a5c2f782SMatthias Springer     assert(regionA && regionB && "could not find region of op");
311a5c2f782SMatthias Springer 
312a3005a40SMatthias Springer     // `a` and `b` are in mutually exclusive regions if both regions are
313a3005a40SMatthias Springer     // distinct and neither region is reachable from the other region.
314a3005a40SMatthias Springer     return regionA != regionB && !isRegionReachable(regionA, regionB) &&
315a5c2f782SMatthias Springer            !isRegionReachable(regionB, regionA);
316a5c2f782SMatthias Springer   }
317a5c2f782SMatthias Springer 
318a5c2f782SMatthias Springer   // Could not find a common RegionBranchOpInterface among a's and b's
319a5c2f782SMatthias Springer   // ancestors.
320a5c2f782SMatthias Springer   return false;
321a5c2f782SMatthias Springer }
322a5c2f782SMatthias Springer 
isRepetitiveRegion(unsigned index)3230f4ba02dSMatthias Springer bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) {
324a3005a40SMatthias Springer   Region *region = &getOperation()->getRegion(index);
325a3005a40SMatthias Springer   return isRegionReachable(region, region);
3260f4ba02dSMatthias Springer }
3270f4ba02dSMatthias Springer 
hasLoop()328*dd450f08SMatthias Springer bool RegionBranchOpInterface::hasLoop() {
329*dd450f08SMatthias Springer   SmallVector<RegionSuccessor> entryRegions;
330*dd450f08SMatthias Springer   getSuccessorRegions(RegionBranchPoint::parent(), entryRegions);
331*dd450f08SMatthias Springer   for (RegionSuccessor successor : entryRegions)
332*dd450f08SMatthias Springer     if (!successor.isParent() &&
333*dd450f08SMatthias Springer         traverseRegionGraph(successor.getSuccessor(),
334*dd450f08SMatthias Springer                             [](Region *nextRegion, ArrayRef<bool> visited) {
335*dd450f08SMatthias Springer                               // Interrupt traversal if the region was already
336*dd450f08SMatthias Springer                               // visited.
337*dd450f08SMatthias Springer                               return visited[nextRegion->getRegionNumber()];
338*dd450f08SMatthias Springer                             }))
339*dd450f08SMatthias Springer       return true;
340*dd450f08SMatthias Springer   return false;
341*dd450f08SMatthias Springer }
342*dd450f08SMatthias Springer 
getEnclosingRepetitiveRegion(Operation * op)3430f4ba02dSMatthias Springer Region *mlir::getEnclosingRepetitiveRegion(Operation *op) {
3440f4ba02dSMatthias Springer   while (Region *region = op->getParentRegion()) {
3450f4ba02dSMatthias Springer     op = region->getParentOp();
3460f4ba02dSMatthias Springer     if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
3470f4ba02dSMatthias Springer       if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
3480f4ba02dSMatthias Springer         return region;
3490f4ba02dSMatthias Springer   }
3500f4ba02dSMatthias Springer   return nullptr;
3510f4ba02dSMatthias Springer }
3520f4ba02dSMatthias Springer 
getEnclosingRepetitiveRegion(Value value)3530f4ba02dSMatthias Springer Region *mlir::getEnclosingRepetitiveRegion(Value value) {
3540f4ba02dSMatthias Springer   Region *region = value.getParentRegion();
3550f4ba02dSMatthias Springer   while (region) {
3560f4ba02dSMatthias Springer     Operation *op = region->getParentOp();
3570f4ba02dSMatthias Springer     if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
3580f4ba02dSMatthias Springer       if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
3590f4ba02dSMatthias Springer         return region;
3600f4ba02dSMatthias Springer     region = op->getParentRegion();
3610f4ba02dSMatthias Springer   }
3620f4ba02dSMatthias Springer   return nullptr;
3630f4ba02dSMatthias Springer }
364