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 ®ion = 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> ®ions) { 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