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 
117ce1e7abSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.h"
12a3ad8f92SRahul Joshi #include "llvm/ADT/SmallPtrSet.h"
137ce1e7abSRiver Riddle 
147ce1e7abSRiver Riddle using namespace mlir;
157ce1e7abSRiver Riddle 
167ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
177ce1e7abSRiver Riddle // ControlFlowInterfaces
187ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
197ce1e7abSRiver Riddle 
207ce1e7abSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
217ce1e7abSRiver Riddle 
220c789db5SMarkus Böck SuccessorOperands::SuccessorOperands(MutableOperandRange forwardedOperands)
23f9735be7SMehdi Amini     : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
24f9735be7SMehdi Amini }
250c789db5SMarkus Böck 
260c789db5SMarkus Böck SuccessorOperands::SuccessorOperands(unsigned int producedOperandCount,
270c789db5SMarkus Böck                                      MutableOperandRange forwardedOperands)
280c789db5SMarkus Böck     : producedOperandCount(producedOperandCount),
290c789db5SMarkus Böck       forwardedOperands(std::move(forwardedOperands)) {}
300c789db5SMarkus Böck 
317ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
327ce1e7abSRiver Riddle // BranchOpInterface
337ce1e7abSRiver Riddle //===----------------------------------------------------------------------===//
347ce1e7abSRiver Riddle 
357ce1e7abSRiver Riddle /// Returns the `BlockArgument` corresponding to operand `operandIndex` in some
367ce1e7abSRiver Riddle /// successor if 'operandIndex' is within the range of 'operands', or None if
377ce1e7abSRiver Riddle /// `operandIndex` isn't a successor operand index.
38a3ad8f92SRahul Joshi Optional<BlockArgument>
390c789db5SMarkus Böck detail::getBranchSuccessorArgument(const SuccessorOperands &operands,
40a3ad8f92SRahul Joshi                                    unsigned operandIndex, Block *successor) {
410c789db5SMarkus Böck   OperandRange forwardedOperands = operands.getForwardedOperands();
427ce1e7abSRiver Riddle   // Check that the operands are valid.
430c789db5SMarkus Böck   if (forwardedOperands.empty())
447ce1e7abSRiver Riddle     return llvm::None;
457ce1e7abSRiver Riddle 
467ce1e7abSRiver Riddle   // Check to ensure that this operand is within the range.
470c789db5SMarkus Böck   unsigned operandsStart = forwardedOperands.getBeginOperandIndex();
487ce1e7abSRiver Riddle   if (operandIndex < operandsStart ||
490c789db5SMarkus Böck       operandIndex >= (operandsStart + forwardedOperands.size()))
507ce1e7abSRiver Riddle     return llvm::None;
517ce1e7abSRiver Riddle 
527ce1e7abSRiver Riddle   // Index the successor.
530c789db5SMarkus Böck   unsigned argIndex =
540c789db5SMarkus Böck       operands.getProducedOperandCount() + operandIndex - operandsStart;
557ce1e7abSRiver Riddle   return successor->getArgument(argIndex);
567ce1e7abSRiver Riddle }
577ce1e7abSRiver Riddle 
587ce1e7abSRiver Riddle /// Verify that the given operands match those of the given successor block.
597ce1e7abSRiver Riddle LogicalResult
60a3ad8f92SRahul Joshi detail::verifyBranchSuccessorOperands(Operation *op, unsigned succNo,
610c789db5SMarkus Böck                                       const SuccessorOperands &operands) {
627ce1e7abSRiver Riddle   // Check the count.
630c789db5SMarkus Böck   unsigned operandCount = operands.size();
647ce1e7abSRiver Riddle   Block *destBB = op->getSuccessor(succNo);
657ce1e7abSRiver Riddle   if (operandCount != destBB->getNumArguments())
667ce1e7abSRiver Riddle     return op->emitError() << "branch has " << operandCount
677ce1e7abSRiver Riddle                            << " operands for successor #" << succNo
687ce1e7abSRiver Riddle                            << ", but target block has "
697ce1e7abSRiver Riddle                            << destBB->getNumArguments();
707ce1e7abSRiver Riddle 
717ce1e7abSRiver Riddle   // Check the types.
720c789db5SMarkus Böck   for (unsigned i = operands.getProducedOperandCount(); i != operandCount;
730c789db5SMarkus Böck        ++i) {
74e7c7b16aSMogball     if (!cast<BranchOpInterface>(op).areTypesCompatible(
750c789db5SMarkus Böck             operands[i].getType(), destBB->getArgument(i).getType()))
767ce1e7abSRiver Riddle       return op->emitError() << "type mismatch for bb argument #" << i
777ce1e7abSRiver Riddle                              << " of successor #" << succNo;
787ce1e7abSRiver Riddle   }
797ce1e7abSRiver Riddle   return success();
807ce1e7abSRiver Riddle }
81a3ad8f92SRahul Joshi 
82a3ad8f92SRahul Joshi //===----------------------------------------------------------------------===//
83a3ad8f92SRahul Joshi // RegionBranchOpInterface
84a3ad8f92SRahul Joshi //===----------------------------------------------------------------------===//
85a3ad8f92SRahul Joshi 
86a3ad8f92SRahul Joshi /// Verify that types match along all region control flow edges originating from
87a3ad8f92SRahul Joshi /// `sourceNo` (region # if source is a region, llvm::None if source is parent
88a3ad8f92SRahul Joshi /// op). `getInputsTypesForRegion` is a function that returns the types of the
8979716559SAlex Zinenko /// inputs that flow from `sourceIndex' to the given region, or llvm::None if
9079716559SAlex Zinenko /// the exact type match verification is not necessary (e.g., if the Op verifies
9179716559SAlex Zinenko /// the match itself).
9279716559SAlex Zinenko static LogicalResult
9379716559SAlex Zinenko verifyTypesAlongAllEdges(Operation *op, Optional<unsigned> sourceNo,
9479716559SAlex Zinenko                          function_ref<Optional<TypeRange>(Optional<unsigned>)>
9579716559SAlex Zinenko                              getInputsTypesForRegion) {
96a3ad8f92SRahul Joshi   auto regionInterface = cast<RegionBranchOpInterface>(op);
97a3ad8f92SRahul Joshi 
98a3ad8f92SRahul Joshi   SmallVector<RegionSuccessor, 2> successors;
99*ee70039aSMogball   regionInterface.getSuccessorRegions(sourceNo, successors);
100a3ad8f92SRahul Joshi 
101a3ad8f92SRahul Joshi   for (RegionSuccessor &succ : successors) {
102a3ad8f92SRahul Joshi     Optional<unsigned> succRegionNo;
103a3ad8f92SRahul Joshi     if (!succ.isParent())
104a3ad8f92SRahul Joshi       succRegionNo = succ.getSuccessor()->getRegionNumber();
105a3ad8f92SRahul Joshi 
106a3ad8f92SRahul Joshi     auto printEdgeName = [&](InFlightDiagnostic &diag) -> InFlightDiagnostic & {
107a3ad8f92SRahul Joshi       diag << "from ";
108a3ad8f92SRahul Joshi       if (sourceNo)
109a3ad8f92SRahul Joshi         diag << "Region #" << sourceNo.getValue();
110a3ad8f92SRahul Joshi       else
111be35264aSSean Silva         diag << "parent operands";
112a3ad8f92SRahul Joshi 
113a3ad8f92SRahul Joshi       diag << " to ";
114a3ad8f92SRahul Joshi       if (succRegionNo)
115a3ad8f92SRahul Joshi         diag << "Region #" << succRegionNo.getValue();
116a3ad8f92SRahul Joshi       else
117be35264aSSean Silva         diag << "parent results";
118a3ad8f92SRahul Joshi       return diag;
119a3ad8f92SRahul Joshi     };
120a3ad8f92SRahul Joshi 
12179716559SAlex Zinenko     Optional<TypeRange> sourceTypes = getInputsTypesForRegion(succRegionNo);
12279716559SAlex Zinenko     if (!sourceTypes.hasValue())
12379716559SAlex Zinenko       continue;
12479716559SAlex Zinenko 
125a3ad8f92SRahul Joshi     TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes();
12679716559SAlex Zinenko     if (sourceTypes->size() != succInputsTypes.size()) {
127a3ad8f92SRahul Joshi       InFlightDiagnostic diag = op->emitOpError(" region control flow edge ");
12879716559SAlex Zinenko       return printEdgeName(diag) << ": source has " << sourceTypes->size()
129be35264aSSean Silva                                  << " operands, but target successor needs "
130a3ad8f92SRahul Joshi                                  << succInputsTypes.size();
131a3ad8f92SRahul Joshi     }
132a3ad8f92SRahul Joshi 
133e4853be2SMehdi Amini     for (const auto &typesIdx :
13479716559SAlex Zinenko          llvm::enumerate(llvm::zip(*sourceTypes, succInputsTypes))) {
135a3ad8f92SRahul Joshi       Type sourceType = std::get<0>(typesIdx.value());
136a3ad8f92SRahul Joshi       Type inputType = std::get<1>(typesIdx.value());
137e7c7b16aSMogball       if (!regionInterface.areTypesCompatible(sourceType, inputType)) {
138a3ad8f92SRahul Joshi         InFlightDiagnostic diag = op->emitOpError(" along control flow edge ");
139a3ad8f92SRahul Joshi         return printEdgeName(diag)
140be35264aSSean Silva                << ": source type #" << typesIdx.index() << " " << sourceType
141be35264aSSean Silva                << " should match input type #" << typesIdx.index() << " "
142a3ad8f92SRahul Joshi                << inputType;
143a3ad8f92SRahul Joshi       }
144a3ad8f92SRahul Joshi     }
145a3ad8f92SRahul Joshi   }
146a3ad8f92SRahul Joshi   return success();
147a3ad8f92SRahul Joshi }
148a3ad8f92SRahul Joshi 
149a3ad8f92SRahul Joshi /// Verify that types match along control flow edges described the given op.
150a3ad8f92SRahul Joshi LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) {
151a3ad8f92SRahul Joshi   auto regionInterface = cast<RegionBranchOpInterface>(op);
152a3ad8f92SRahul Joshi 
153a3ad8f92SRahul Joshi   auto inputTypesFromParent = [&](Optional<unsigned> regionNo) -> TypeRange {
154a3ad8f92SRahul Joshi     if (regionNo.hasValue()) {
155a3ad8f92SRahul Joshi       return regionInterface.getSuccessorEntryOperands(regionNo.getValue())
156a3ad8f92SRahul Joshi           .getTypes();
157a3ad8f92SRahul Joshi     }
158a3ad8f92SRahul Joshi 
159a3ad8f92SRahul Joshi     // If the successor of a parent op is the parent itself
160a3ad8f92SRahul Joshi     // RegionBranchOpInterface does not have an API to query what the entry
161a3ad8f92SRahul Joshi     // operands will be in that case. Vend out the result types of the op in
162a3ad8f92SRahul Joshi     // that case so that type checking succeeds for this case.
163a3ad8f92SRahul Joshi     return op->getResultTypes();
164a3ad8f92SRahul Joshi   };
165a3ad8f92SRahul Joshi 
166a3ad8f92SRahul Joshi   // Verify types along control flow edges originating from the parent.
167a3ad8f92SRahul Joshi   if (failed(verifyTypesAlongAllEdges(op, llvm::None, inputTypesFromParent)))
168a3ad8f92SRahul Joshi     return failure();
169a3ad8f92SRahul Joshi 
170a3ad8f92SRahul Joshi   // RegionBranchOpInterface should not be implemented by Ops that do not have
171a3ad8f92SRahul Joshi   // attached regions.
172a3ad8f92SRahul Joshi   assert(op->getNumRegions() != 0);
173a3ad8f92SRahul Joshi 
174e7c7b16aSMogball   auto areTypesCompatible = [&](TypeRange lhs, TypeRange rhs) {
175e7c7b16aSMogball     if (lhs.size() != rhs.size())
176e7c7b16aSMogball       return false;
177e7c7b16aSMogball     for (auto types : llvm::zip(lhs, rhs)) {
178e7c7b16aSMogball       if (!regionInterface.areTypesCompatible(std::get<0>(types),
179e7c7b16aSMogball                                               std::get<1>(types))) {
180e7c7b16aSMogball         return false;
181e7c7b16aSMogball       }
182e7c7b16aSMogball     }
183e7c7b16aSMogball     return true;
184e7c7b16aSMogball   };
185e7c7b16aSMogball 
186a3ad8f92SRahul Joshi   // Verify types along control flow edges originating from each region.
187a3ad8f92SRahul Joshi   for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) {
188a3ad8f92SRahul Joshi     Region &region = op->getRegion(regionNo);
189a3ad8f92SRahul Joshi 
19004253320SMarcel Koester     // Since there can be multiple `ReturnLike` terminators or others
19104253320SMarcel Koester     // implementing the `RegionBranchTerminatorOpInterface`, all should have the
19204253320SMarcel Koester     // same operand types when passing them to the same region.
193a3ad8f92SRahul Joshi 
19404253320SMarcel Koester     Optional<OperandRange> regionReturnOperands;
195a3ad8f92SRahul Joshi     for (Block &block : region) {
196a3ad8f92SRahul Joshi       Operation *terminator = block.getTerminator();
19704253320SMarcel Koester       auto terminatorOperands =
19804253320SMarcel Koester           getRegionBranchSuccessorOperands(terminator, regionNo);
19904253320SMarcel Koester       if (!terminatorOperands)
200a3ad8f92SRahul Joshi         continue;
201a3ad8f92SRahul Joshi 
20204253320SMarcel Koester       if (!regionReturnOperands) {
20304253320SMarcel Koester         regionReturnOperands = terminatorOperands;
204a3ad8f92SRahul Joshi         continue;
205a3ad8f92SRahul Joshi       }
206a3ad8f92SRahul Joshi 
207a3ad8f92SRahul Joshi       // Found more than one ReturnLike terminator. Make sure the operand types
208a3ad8f92SRahul Joshi       // match with the first one.
209e7c7b16aSMogball       if (!areTypesCompatible(regionReturnOperands->getTypes(),
210e7c7b16aSMogball                               terminatorOperands->getTypes()))
211a3ad8f92SRahul Joshi         return op->emitOpError("Region #")
212a3ad8f92SRahul Joshi                << regionNo
213a3ad8f92SRahul Joshi                << " operands mismatch between return-like terminators";
214a3ad8f92SRahul Joshi     }
215a3ad8f92SRahul Joshi 
21679716559SAlex Zinenko     auto inputTypesFromRegion =
21779716559SAlex Zinenko         [&](Optional<unsigned> regionNo) -> Optional<TypeRange> {
21879716559SAlex Zinenko       // If there is no return-like terminator, the op itself should verify
21979716559SAlex Zinenko       // type consistency.
22004253320SMarcel Koester       if (!regionReturnOperands)
22179716559SAlex Zinenko         return llvm::None;
22279716559SAlex Zinenko 
22304253320SMarcel Koester       // All successors get the same set of operand types.
22404253320SMarcel Koester       return TypeRange(regionReturnOperands->getTypes());
225a3ad8f92SRahul Joshi     };
226a3ad8f92SRahul Joshi 
227a3ad8f92SRahul Joshi     if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion)))
228a3ad8f92SRahul Joshi       return failure();
229a3ad8f92SRahul Joshi   }
230a3ad8f92SRahul Joshi 
231a3ad8f92SRahul Joshi   return success();
232a3ad8f92SRahul Joshi }
23304253320SMarcel Koester 
234a3005a40SMatthias Springer /// Return `true` if region `r` is reachable from region `begin` according to
235a3005a40SMatthias Springer /// the RegionBranchOpInterface (by taking a branch).
236a3005a40SMatthias Springer static bool isRegionReachable(Region *begin, Region *r) {
237a3005a40SMatthias Springer   assert(begin->getParentOp() == r->getParentOp() &&
238a3005a40SMatthias Springer          "expected that both regions belong to the same op");
239a3005a40SMatthias Springer   auto op = cast<RegionBranchOpInterface>(begin->getParentOp());
240a3005a40SMatthias Springer   SmallVector<bool> visited(op->getNumRegions(), false);
241a3005a40SMatthias Springer   visited[begin->getRegionNumber()] = true;
242a3005a40SMatthias Springer 
243a3005a40SMatthias Springer   // Retrieve all successors of the region and enqueue them in the worklist.
244a3005a40SMatthias Springer   SmallVector<unsigned> worklist;
245a3005a40SMatthias Springer   auto enqueueAllSuccessors = [&](unsigned index) {
246a3005a40SMatthias Springer     SmallVector<RegionSuccessor> successors;
247a3005a40SMatthias Springer     op.getSuccessorRegions(index, successors);
248a3005a40SMatthias Springer     for (RegionSuccessor successor : successors)
249a3005a40SMatthias Springer       if (!successor.isParent())
250a3005a40SMatthias Springer         worklist.push_back(successor.getSuccessor()->getRegionNumber());
251a3005a40SMatthias Springer   };
252a3005a40SMatthias Springer   enqueueAllSuccessors(begin->getRegionNumber());
253a3005a40SMatthias Springer 
254a3005a40SMatthias Springer   // Process all regions in the worklist via DFS.
255a3005a40SMatthias Springer   while (!worklist.empty()) {
256a3005a40SMatthias Springer     unsigned nextRegion = worklist.pop_back_val();
257a3005a40SMatthias Springer     if (nextRegion == r->getRegionNumber())
258a3005a40SMatthias Springer       return true;
259a3005a40SMatthias Springer     if (visited[nextRegion])
260a3005a40SMatthias Springer       continue;
261a3005a40SMatthias Springer     visited[nextRegion] = true;
262a3005a40SMatthias Springer     enqueueAllSuccessors(nextRegion);
263a3005a40SMatthias Springer   }
264a3005a40SMatthias Springer 
265a3005a40SMatthias Springer   return false;
266a3005a40SMatthias Springer }
267a3005a40SMatthias Springer 
268a5c2f782SMatthias Springer /// Return `true` if `a` and `b` are in mutually exclusive regions.
269a5c2f782SMatthias Springer ///
270a5c2f782SMatthias Springer /// 1. Find the first common of `a` and `b` (ancestor) that implements
271a5c2f782SMatthias Springer ///    RegionBranchOpInterface.
272a5c2f782SMatthias Springer /// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are
273a5c2f782SMatthias Springer ///    contained.
274a5c2f782SMatthias Springer /// 3. Check if `regionA` and `regionB` are mutually exclusive. They are
275a5c2f782SMatthias Springer ///    mutually exclusive if they are not reachable from each other as per
276a5c2f782SMatthias Springer ///    RegionBranchOpInterface::getSuccessorRegions.
277a5c2f782SMatthias Springer bool mlir::insideMutuallyExclusiveRegions(Operation *a, Operation *b) {
278a5c2f782SMatthias Springer   assert(a && "expected non-empty operation");
279a5c2f782SMatthias Springer   assert(b && "expected non-empty operation");
280a5c2f782SMatthias Springer 
281a5c2f782SMatthias Springer   auto branchOp = a->getParentOfType<RegionBranchOpInterface>();
282a5c2f782SMatthias Springer   while (branchOp) {
283a5c2f782SMatthias Springer     // Check if b is inside branchOp. (We already know that a is.)
284a5c2f782SMatthias Springer     if (!branchOp->isProperAncestor(b)) {
285a5c2f782SMatthias Springer       // Check next enclosing RegionBranchOpInterface.
286a5c2f782SMatthias Springer       branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
287a5c2f782SMatthias Springer       continue;
288a5c2f782SMatthias Springer     }
289a5c2f782SMatthias Springer 
290a5c2f782SMatthias Springer     // b is contained in branchOp. Retrieve the regions in which `a` and `b`
291a5c2f782SMatthias Springer     // are contained.
292a5c2f782SMatthias Springer     Region *regionA = nullptr, *regionB = nullptr;
293a5c2f782SMatthias Springer     for (Region &r : branchOp->getRegions()) {
294a5c2f782SMatthias Springer       if (r.findAncestorOpInRegion(*a)) {
295a5c2f782SMatthias Springer         assert(!regionA && "already found a region for a");
296a5c2f782SMatthias Springer         regionA = &r;
297a5c2f782SMatthias Springer       }
298a5c2f782SMatthias Springer       if (r.findAncestorOpInRegion(*b)) {
299a5c2f782SMatthias Springer         assert(!regionB && "already found a region for b");
300a5c2f782SMatthias Springer         regionB = &r;
301a5c2f782SMatthias Springer       }
302a5c2f782SMatthias Springer     }
303a5c2f782SMatthias Springer     assert(regionA && regionB && "could not find region of op");
304a5c2f782SMatthias Springer 
305a3005a40SMatthias Springer     // `a` and `b` are in mutually exclusive regions if both regions are
306a3005a40SMatthias Springer     // distinct and neither region is reachable from the other region.
307a3005a40SMatthias Springer     return regionA != regionB && !isRegionReachable(regionA, regionB) &&
308a5c2f782SMatthias Springer            !isRegionReachable(regionB, regionA);
309a5c2f782SMatthias Springer   }
310a5c2f782SMatthias Springer 
311a5c2f782SMatthias Springer   // Could not find a common RegionBranchOpInterface among a's and b's
312a5c2f782SMatthias Springer   // ancestors.
313a5c2f782SMatthias Springer   return false;
314a5c2f782SMatthias Springer }
315a5c2f782SMatthias Springer 
3160f4ba02dSMatthias Springer bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) {
317a3005a40SMatthias Springer   Region *region = &getOperation()->getRegion(index);
318a3005a40SMatthias Springer   return isRegionReachable(region, region);
3190f4ba02dSMatthias Springer }
3200f4ba02dSMatthias Springer 
321*ee70039aSMogball void RegionBranchOpInterface::getSuccessorRegions(
322*ee70039aSMogball     Optional<unsigned> index, SmallVectorImpl<RegionSuccessor> &regions) {
323*ee70039aSMogball   unsigned numInputs = 0;
324*ee70039aSMogball   if (index) {
325*ee70039aSMogball     // If the predecessor is a region, get the number of operands from an
326*ee70039aSMogball     // exiting terminator in the region.
327*ee70039aSMogball     for (Block &block : getOperation()->getRegion(*index)) {
328*ee70039aSMogball       Operation *terminator = block.getTerminator();
329*ee70039aSMogball       if (getRegionBranchSuccessorOperands(terminator, *index)) {
330*ee70039aSMogball         numInputs = terminator->getNumOperands();
331*ee70039aSMogball         break;
332*ee70039aSMogball       }
333*ee70039aSMogball     }
334*ee70039aSMogball   } else {
335*ee70039aSMogball     // Otherwise, use the number of parent operation operands.
336*ee70039aSMogball     numInputs = getOperation()->getNumOperands();
337*ee70039aSMogball   }
338*ee70039aSMogball   SmallVector<Attribute, 2> operands(numInputs, nullptr);
339*ee70039aSMogball   getSuccessorRegions(index, operands, regions);
340*ee70039aSMogball }
341*ee70039aSMogball 
3420f4ba02dSMatthias Springer Region *mlir::getEnclosingRepetitiveRegion(Operation *op) {
3430f4ba02dSMatthias Springer   while (Region *region = op->getParentRegion()) {
3440f4ba02dSMatthias Springer     op = region->getParentOp();
3450f4ba02dSMatthias Springer     if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
3460f4ba02dSMatthias Springer       if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
3470f4ba02dSMatthias Springer         return region;
3480f4ba02dSMatthias Springer   }
3490f4ba02dSMatthias Springer   return nullptr;
3500f4ba02dSMatthias Springer }
3510f4ba02dSMatthias Springer 
3520f4ba02dSMatthias Springer Region *mlir::getEnclosingRepetitiveRegion(Value value) {
3530f4ba02dSMatthias Springer   Region *region = value.getParentRegion();
3540f4ba02dSMatthias Springer   while (region) {
3550f4ba02dSMatthias Springer     Operation *op = region->getParentOp();
3560f4ba02dSMatthias Springer     if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
3570f4ba02dSMatthias Springer       if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
3580f4ba02dSMatthias Springer         return region;
3590f4ba02dSMatthias Springer     region = op->getParentRegion();
3600f4ba02dSMatthias Springer   }
3610f4ba02dSMatthias Springer   return nullptr;
3620f4ba02dSMatthias Springer }
3630f4ba02dSMatthias Springer 
36404253320SMarcel Koester //===----------------------------------------------------------------------===//
36504253320SMarcel Koester // RegionBranchTerminatorOpInterface
36604253320SMarcel Koester //===----------------------------------------------------------------------===//
36704253320SMarcel Koester 
36804253320SMarcel Koester /// Returns true if the given operation is either annotated with the
36904253320SMarcel Koester /// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`.
37004253320SMarcel Koester bool mlir::isRegionReturnLike(Operation *operation) {
37104253320SMarcel Koester   return dyn_cast<RegionBranchTerminatorOpInterface>(operation) ||
37204253320SMarcel Koester          operation->hasTrait<OpTrait::ReturnLike>();
37304253320SMarcel Koester }
37404253320SMarcel Koester 
37504253320SMarcel Koester /// Returns the mutable operands that are passed to the region with the given
37604253320SMarcel Koester /// `regionIndex`. If the operation does not implement the
37704253320SMarcel Koester /// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the
37804253320SMarcel Koester /// result will be `llvm::None`. In all other cases, the resulting
37904253320SMarcel Koester /// `OperandRange` represents all operands that are passed to the specified
38004253320SMarcel Koester /// successor region. If `regionIndex` is `llvm::None`, all operands that are
38104253320SMarcel Koester /// passed to the parent operation will be returned.
38204253320SMarcel Koester Optional<MutableOperandRange>
38304253320SMarcel Koester mlir::getMutableRegionBranchSuccessorOperands(Operation *operation,
38404253320SMarcel Koester                                               Optional<unsigned> regionIndex) {
38504253320SMarcel Koester   // Try to query a RegionBranchTerminatorOpInterface to determine
38604253320SMarcel Koester   // all successor operands that will be passed to the successor
38704253320SMarcel Koester   // input arguments.
38804253320SMarcel Koester   if (auto regionTerminatorInterface =
38904253320SMarcel Koester           dyn_cast<RegionBranchTerminatorOpInterface>(operation))
39004253320SMarcel Koester     return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex);
39104253320SMarcel Koester 
39204253320SMarcel Koester   // TODO: The ReturnLike trait should imply a default implementation of the
39304253320SMarcel Koester   // RegionBranchTerminatorOpInterface. This would make this code significantly
39404253320SMarcel Koester   // easier. Furthermore, this may even make this function obsolete.
39504253320SMarcel Koester   if (operation->hasTrait<OpTrait::ReturnLike>())
39604253320SMarcel Koester     return MutableOperandRange(operation);
39704253320SMarcel Koester   return llvm::None;
39804253320SMarcel Koester }
39904253320SMarcel Koester 
40004253320SMarcel Koester /// Returns the read only operands that are passed to the region with the given
40104253320SMarcel Koester /// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more
40204253320SMarcel Koester /// information.
40304253320SMarcel Koester Optional<OperandRange>
40404253320SMarcel Koester mlir::getRegionBranchSuccessorOperands(Operation *operation,
40504253320SMarcel Koester                                        Optional<unsigned> regionIndex) {
40604253320SMarcel Koester   auto range = getMutableRegionBranchSuccessorOperands(operation, regionIndex);
40704253320SMarcel Koester   return range ? Optional<OperandRange>(*range) : llvm::None;
40804253320SMarcel Koester }
409