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 9*f9735be7SMehdi Amini #include <utility> 10*f9735be7SMehdi Amini 117ce1e7abSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.h" 1209f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.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 230c789db5SMarkus Böck SuccessorOperands::SuccessorOperands(MutableOperandRange forwardedOperands) 24*f9735be7SMehdi Amini : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) { 25*f9735be7SMehdi Amini } 260c789db5SMarkus Böck 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 377ce1e7abSRiver Riddle /// successor if 'operandIndex' is within the range of 'operands', or None if 387ce1e7abSRiver Riddle /// `operandIndex` isn't a successor operand index. 39a3ad8f92SRahul Joshi Optional<BlockArgument> 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()) 457ce1e7abSRiver Riddle return llvm::None; 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())) 517ce1e7abSRiver Riddle return llvm::None; 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 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 87a3ad8f92SRahul Joshi /// Verify that types match along all region control flow edges originating from 88a3ad8f92SRahul Joshi /// `sourceNo` (region # if source is a region, llvm::None if source is parent 89a3ad8f92SRahul Joshi /// op). `getInputsTypesForRegion` is a function that returns the types of the 9079716559SAlex Zinenko /// inputs that flow from `sourceIndex' to the given region, or llvm::None if 9179716559SAlex Zinenko /// the exact type match verification is not necessary (e.g., if the Op verifies 9279716559SAlex Zinenko /// the match itself). 9379716559SAlex Zinenko static LogicalResult 9479716559SAlex Zinenko verifyTypesAlongAllEdges(Operation *op, Optional<unsigned> sourceNo, 9579716559SAlex Zinenko function_ref<Optional<TypeRange>(Optional<unsigned>)> 9679716559SAlex Zinenko getInputsTypesForRegion) { 97a3ad8f92SRahul Joshi auto regionInterface = cast<RegionBranchOpInterface>(op); 98a3ad8f92SRahul Joshi 99a3ad8f92SRahul Joshi SmallVector<RegionSuccessor, 2> successors; 100a3ad8f92SRahul Joshi unsigned numInputs; 101a3ad8f92SRahul Joshi if (sourceNo) { 102a3ad8f92SRahul Joshi Region &srcRegion = op->getRegion(sourceNo.getValue()); 103a3ad8f92SRahul Joshi numInputs = srcRegion.getNumArguments(); 104a3ad8f92SRahul Joshi } else { 105a3ad8f92SRahul Joshi numInputs = op->getNumOperands(); 106a3ad8f92SRahul Joshi } 107a3ad8f92SRahul Joshi SmallVector<Attribute, 2> operands(numInputs, nullptr); 108a3ad8f92SRahul Joshi regionInterface.getSuccessorRegions(sourceNo, operands, successors); 109a3ad8f92SRahul Joshi 110a3ad8f92SRahul Joshi for (RegionSuccessor &succ : successors) { 111a3ad8f92SRahul Joshi Optional<unsigned> succRegionNo; 112a3ad8f92SRahul Joshi if (!succ.isParent()) 113a3ad8f92SRahul Joshi succRegionNo = succ.getSuccessor()->getRegionNumber(); 114a3ad8f92SRahul Joshi 115a3ad8f92SRahul Joshi auto printEdgeName = [&](InFlightDiagnostic &diag) -> InFlightDiagnostic & { 116a3ad8f92SRahul Joshi diag << "from "; 117a3ad8f92SRahul Joshi if (sourceNo) 118a3ad8f92SRahul Joshi diag << "Region #" << sourceNo.getValue(); 119a3ad8f92SRahul Joshi else 120be35264aSSean Silva diag << "parent operands"; 121a3ad8f92SRahul Joshi 122a3ad8f92SRahul Joshi diag << " to "; 123a3ad8f92SRahul Joshi if (succRegionNo) 124a3ad8f92SRahul Joshi diag << "Region #" << succRegionNo.getValue(); 125a3ad8f92SRahul Joshi else 126be35264aSSean Silva diag << "parent results"; 127a3ad8f92SRahul Joshi return diag; 128a3ad8f92SRahul Joshi }; 129a3ad8f92SRahul Joshi 13079716559SAlex Zinenko Optional<TypeRange> sourceTypes = getInputsTypesForRegion(succRegionNo); 13179716559SAlex Zinenko if (!sourceTypes.hasValue()) 13279716559SAlex Zinenko continue; 13379716559SAlex Zinenko 134a3ad8f92SRahul Joshi TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes(); 13579716559SAlex Zinenko if (sourceTypes->size() != succInputsTypes.size()) { 136a3ad8f92SRahul Joshi InFlightDiagnostic diag = op->emitOpError(" region control flow edge "); 13779716559SAlex Zinenko return printEdgeName(diag) << ": source has " << sourceTypes->size() 138be35264aSSean Silva << " operands, but target successor needs " 139a3ad8f92SRahul Joshi << succInputsTypes.size(); 140a3ad8f92SRahul Joshi } 141a3ad8f92SRahul Joshi 142e4853be2SMehdi Amini for (const auto &typesIdx : 14379716559SAlex Zinenko llvm::enumerate(llvm::zip(*sourceTypes, succInputsTypes))) { 144a3ad8f92SRahul Joshi Type sourceType = std::get<0>(typesIdx.value()); 145a3ad8f92SRahul Joshi Type inputType = std::get<1>(typesIdx.value()); 146e7c7b16aSMogball if (!regionInterface.areTypesCompatible(sourceType, inputType)) { 147a3ad8f92SRahul Joshi InFlightDiagnostic diag = op->emitOpError(" along control flow edge "); 148a3ad8f92SRahul Joshi return printEdgeName(diag) 149be35264aSSean Silva << ": source type #" << typesIdx.index() << " " << sourceType 150be35264aSSean Silva << " should match input type #" << typesIdx.index() << " " 151a3ad8f92SRahul Joshi << inputType; 152a3ad8f92SRahul Joshi } 153a3ad8f92SRahul Joshi } 154a3ad8f92SRahul Joshi } 155a3ad8f92SRahul Joshi return success(); 156a3ad8f92SRahul Joshi } 157a3ad8f92SRahul Joshi 158a3ad8f92SRahul Joshi /// Verify that types match along control flow edges described the given op. 159a3ad8f92SRahul Joshi LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) { 160a3ad8f92SRahul Joshi auto regionInterface = cast<RegionBranchOpInterface>(op); 161a3ad8f92SRahul Joshi 162a3ad8f92SRahul Joshi auto inputTypesFromParent = [&](Optional<unsigned> regionNo) -> TypeRange { 163a3ad8f92SRahul Joshi if (regionNo.hasValue()) { 164a3ad8f92SRahul Joshi return regionInterface.getSuccessorEntryOperands(regionNo.getValue()) 165a3ad8f92SRahul Joshi .getTypes(); 166a3ad8f92SRahul Joshi } 167a3ad8f92SRahul Joshi 168a3ad8f92SRahul Joshi // If the successor of a parent op is the parent itself 169a3ad8f92SRahul Joshi // RegionBranchOpInterface does not have an API to query what the entry 170a3ad8f92SRahul Joshi // operands will be in that case. Vend out the result types of the op in 171a3ad8f92SRahul Joshi // that case so that type checking succeeds for this case. 172a3ad8f92SRahul Joshi return op->getResultTypes(); 173a3ad8f92SRahul Joshi }; 174a3ad8f92SRahul Joshi 175a3ad8f92SRahul Joshi // Verify types along control flow edges originating from the parent. 176a3ad8f92SRahul Joshi if (failed(verifyTypesAlongAllEdges(op, llvm::None, inputTypesFromParent))) 177a3ad8f92SRahul Joshi return failure(); 178a3ad8f92SRahul Joshi 179a3ad8f92SRahul Joshi // RegionBranchOpInterface should not be implemented by Ops that do not have 180a3ad8f92SRahul Joshi // attached regions. 181a3ad8f92SRahul Joshi assert(op->getNumRegions() != 0); 182a3ad8f92SRahul Joshi 183e7c7b16aSMogball auto areTypesCompatible = [&](TypeRange lhs, TypeRange rhs) { 184e7c7b16aSMogball if (lhs.size() != rhs.size()) 185e7c7b16aSMogball return false; 186e7c7b16aSMogball for (auto types : llvm::zip(lhs, rhs)) { 187e7c7b16aSMogball if (!regionInterface.areTypesCompatible(std::get<0>(types), 188e7c7b16aSMogball std::get<1>(types))) { 189e7c7b16aSMogball return false; 190e7c7b16aSMogball } 191e7c7b16aSMogball } 192e7c7b16aSMogball return true; 193e7c7b16aSMogball }; 194e7c7b16aSMogball 195a3ad8f92SRahul Joshi // Verify types along control flow edges originating from each region. 196a3ad8f92SRahul Joshi for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) { 197a3ad8f92SRahul Joshi Region ®ion = op->getRegion(regionNo); 198a3ad8f92SRahul Joshi 19904253320SMarcel Koester // Since there can be multiple `ReturnLike` terminators or others 20004253320SMarcel Koester // implementing the `RegionBranchTerminatorOpInterface`, all should have the 20104253320SMarcel Koester // same operand types when passing them to the same region. 202a3ad8f92SRahul Joshi 20304253320SMarcel Koester Optional<OperandRange> regionReturnOperands; 204a3ad8f92SRahul Joshi for (Block &block : region) { 205a3ad8f92SRahul Joshi Operation *terminator = block.getTerminator(); 20604253320SMarcel Koester auto terminatorOperands = 20704253320SMarcel Koester getRegionBranchSuccessorOperands(terminator, regionNo); 20804253320SMarcel Koester if (!terminatorOperands) 209a3ad8f92SRahul Joshi continue; 210a3ad8f92SRahul Joshi 21104253320SMarcel Koester if (!regionReturnOperands) { 21204253320SMarcel Koester regionReturnOperands = terminatorOperands; 213a3ad8f92SRahul Joshi continue; 214a3ad8f92SRahul Joshi } 215a3ad8f92SRahul Joshi 216a3ad8f92SRahul Joshi // Found more than one ReturnLike terminator. Make sure the operand types 217a3ad8f92SRahul Joshi // match with the first one. 218e7c7b16aSMogball if (!areTypesCompatible(regionReturnOperands->getTypes(), 219e7c7b16aSMogball terminatorOperands->getTypes())) 220a3ad8f92SRahul Joshi return op->emitOpError("Region #") 221a3ad8f92SRahul Joshi << regionNo 222a3ad8f92SRahul Joshi << " operands mismatch between return-like terminators"; 223a3ad8f92SRahul Joshi } 224a3ad8f92SRahul Joshi 22579716559SAlex Zinenko auto inputTypesFromRegion = 22679716559SAlex Zinenko [&](Optional<unsigned> regionNo) -> Optional<TypeRange> { 22779716559SAlex Zinenko // If there is no return-like terminator, the op itself should verify 22879716559SAlex Zinenko // type consistency. 22904253320SMarcel Koester if (!regionReturnOperands) 23079716559SAlex Zinenko return llvm::None; 23179716559SAlex Zinenko 23204253320SMarcel Koester // All successors get the same set of operand types. 23304253320SMarcel Koester return TypeRange(regionReturnOperands->getTypes()); 234a3ad8f92SRahul Joshi }; 235a3ad8f92SRahul Joshi 236a3ad8f92SRahul Joshi if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion))) 237a3ad8f92SRahul Joshi return failure(); 238a3ad8f92SRahul Joshi } 239a3ad8f92SRahul Joshi 240a3ad8f92SRahul Joshi return success(); 241a3ad8f92SRahul Joshi } 24204253320SMarcel Koester 243a3005a40SMatthias Springer /// Return `true` if region `r` is reachable from region `begin` according to 244a3005a40SMatthias Springer /// the RegionBranchOpInterface (by taking a branch). 245a3005a40SMatthias Springer static bool isRegionReachable(Region *begin, Region *r) { 246a3005a40SMatthias Springer assert(begin->getParentOp() == r->getParentOp() && 247a3005a40SMatthias Springer "expected that both regions belong to the same op"); 248a3005a40SMatthias Springer auto op = cast<RegionBranchOpInterface>(begin->getParentOp()); 249a3005a40SMatthias Springer SmallVector<bool> visited(op->getNumRegions(), false); 250a3005a40SMatthias Springer visited[begin->getRegionNumber()] = true; 251a3005a40SMatthias Springer 252a3005a40SMatthias Springer // Retrieve all successors of the region and enqueue them in the worklist. 253a3005a40SMatthias Springer SmallVector<unsigned> worklist; 254a3005a40SMatthias Springer auto enqueueAllSuccessors = [&](unsigned index) { 255a3005a40SMatthias Springer SmallVector<RegionSuccessor> successors; 256a3005a40SMatthias Springer op.getSuccessorRegions(index, successors); 257a3005a40SMatthias Springer for (RegionSuccessor successor : successors) 258a3005a40SMatthias Springer if (!successor.isParent()) 259a3005a40SMatthias Springer worklist.push_back(successor.getSuccessor()->getRegionNumber()); 260a3005a40SMatthias Springer }; 261a3005a40SMatthias Springer enqueueAllSuccessors(begin->getRegionNumber()); 262a3005a40SMatthias Springer 263a3005a40SMatthias Springer // Process all regions in the worklist via DFS. 264a3005a40SMatthias Springer while (!worklist.empty()) { 265a3005a40SMatthias Springer unsigned nextRegion = worklist.pop_back_val(); 266a3005a40SMatthias Springer if (nextRegion == r->getRegionNumber()) 267a3005a40SMatthias Springer return true; 268a3005a40SMatthias Springer if (visited[nextRegion]) 269a3005a40SMatthias Springer continue; 270a3005a40SMatthias Springer visited[nextRegion] = true; 271a3005a40SMatthias Springer enqueueAllSuccessors(nextRegion); 272a3005a40SMatthias Springer } 273a3005a40SMatthias Springer 274a3005a40SMatthias Springer return false; 275a3005a40SMatthias Springer } 276a3005a40SMatthias Springer 277a5c2f782SMatthias Springer /// Return `true` if `a` and `b` are in mutually exclusive regions. 278a5c2f782SMatthias Springer /// 279a5c2f782SMatthias Springer /// 1. Find the first common of `a` and `b` (ancestor) that implements 280a5c2f782SMatthias Springer /// RegionBranchOpInterface. 281a5c2f782SMatthias Springer /// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are 282a5c2f782SMatthias Springer /// contained. 283a5c2f782SMatthias Springer /// 3. Check if `regionA` and `regionB` are mutually exclusive. They are 284a5c2f782SMatthias Springer /// mutually exclusive if they are not reachable from each other as per 285a5c2f782SMatthias Springer /// RegionBranchOpInterface::getSuccessorRegions. 286a5c2f782SMatthias Springer bool mlir::insideMutuallyExclusiveRegions(Operation *a, Operation *b) { 287a5c2f782SMatthias Springer assert(a && "expected non-empty operation"); 288a5c2f782SMatthias Springer assert(b && "expected non-empty operation"); 289a5c2f782SMatthias Springer 290a5c2f782SMatthias Springer auto branchOp = a->getParentOfType<RegionBranchOpInterface>(); 291a5c2f782SMatthias Springer while (branchOp) { 292a5c2f782SMatthias Springer // Check if b is inside branchOp. (We already know that a is.) 293a5c2f782SMatthias Springer if (!branchOp->isProperAncestor(b)) { 294a5c2f782SMatthias Springer // Check next enclosing RegionBranchOpInterface. 295a5c2f782SMatthias Springer branchOp = branchOp->getParentOfType<RegionBranchOpInterface>(); 296a5c2f782SMatthias Springer continue; 297a5c2f782SMatthias Springer } 298a5c2f782SMatthias Springer 299a5c2f782SMatthias Springer // b is contained in branchOp. Retrieve the regions in which `a` and `b` 300a5c2f782SMatthias Springer // are contained. 301a5c2f782SMatthias Springer Region *regionA = nullptr, *regionB = nullptr; 302a5c2f782SMatthias Springer for (Region &r : branchOp->getRegions()) { 303a5c2f782SMatthias Springer if (r.findAncestorOpInRegion(*a)) { 304a5c2f782SMatthias Springer assert(!regionA && "already found a region for a"); 305a5c2f782SMatthias Springer regionA = &r; 306a5c2f782SMatthias Springer } 307a5c2f782SMatthias Springer if (r.findAncestorOpInRegion(*b)) { 308a5c2f782SMatthias Springer assert(!regionB && "already found a region for b"); 309a5c2f782SMatthias Springer regionB = &r; 310a5c2f782SMatthias Springer } 311a5c2f782SMatthias Springer } 312a5c2f782SMatthias Springer assert(regionA && regionB && "could not find region of op"); 313a5c2f782SMatthias Springer 314a3005a40SMatthias Springer // `a` and `b` are in mutually exclusive regions if both regions are 315a3005a40SMatthias Springer // distinct and neither region is reachable from the other region. 316a3005a40SMatthias Springer return regionA != regionB && !isRegionReachable(regionA, regionB) && 317a5c2f782SMatthias Springer !isRegionReachable(regionB, regionA); 318a5c2f782SMatthias Springer } 319a5c2f782SMatthias Springer 320a5c2f782SMatthias Springer // Could not find a common RegionBranchOpInterface among a's and b's 321a5c2f782SMatthias Springer // ancestors. 322a5c2f782SMatthias Springer return false; 323a5c2f782SMatthias Springer } 324a5c2f782SMatthias Springer 3250f4ba02dSMatthias Springer bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) { 326a3005a40SMatthias Springer Region *region = &getOperation()->getRegion(index); 327a3005a40SMatthias Springer return isRegionReachable(region, region); 3280f4ba02dSMatthias Springer } 3290f4ba02dSMatthias Springer 3300f4ba02dSMatthias Springer Region *mlir::getEnclosingRepetitiveRegion(Operation *op) { 3310f4ba02dSMatthias Springer while (Region *region = op->getParentRegion()) { 3320f4ba02dSMatthias Springer op = region->getParentOp(); 3330f4ba02dSMatthias Springer if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) 3340f4ba02dSMatthias Springer if (branchOp.isRepetitiveRegion(region->getRegionNumber())) 3350f4ba02dSMatthias Springer return region; 3360f4ba02dSMatthias Springer } 3370f4ba02dSMatthias Springer return nullptr; 3380f4ba02dSMatthias Springer } 3390f4ba02dSMatthias Springer 3400f4ba02dSMatthias Springer Region *mlir::getEnclosingRepetitiveRegion(Value value) { 3410f4ba02dSMatthias Springer Region *region = value.getParentRegion(); 3420f4ba02dSMatthias Springer while (region) { 3430f4ba02dSMatthias Springer Operation *op = region->getParentOp(); 3440f4ba02dSMatthias Springer if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) 3450f4ba02dSMatthias Springer if (branchOp.isRepetitiveRegion(region->getRegionNumber())) 3460f4ba02dSMatthias Springer return region; 3470f4ba02dSMatthias Springer region = op->getParentRegion(); 3480f4ba02dSMatthias Springer } 3490f4ba02dSMatthias Springer return nullptr; 3500f4ba02dSMatthias Springer } 3510f4ba02dSMatthias Springer 35204253320SMarcel Koester //===----------------------------------------------------------------------===// 35304253320SMarcel Koester // RegionBranchTerminatorOpInterface 35404253320SMarcel Koester //===----------------------------------------------------------------------===// 35504253320SMarcel Koester 35604253320SMarcel Koester /// Returns true if the given operation is either annotated with the 35704253320SMarcel Koester /// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`. 35804253320SMarcel Koester bool mlir::isRegionReturnLike(Operation *operation) { 35904253320SMarcel Koester return dyn_cast<RegionBranchTerminatorOpInterface>(operation) || 36004253320SMarcel Koester operation->hasTrait<OpTrait::ReturnLike>(); 36104253320SMarcel Koester } 36204253320SMarcel Koester 36304253320SMarcel Koester /// Returns the mutable operands that are passed to the region with the given 36404253320SMarcel Koester /// `regionIndex`. If the operation does not implement the 36504253320SMarcel Koester /// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the 36604253320SMarcel Koester /// result will be `llvm::None`. In all other cases, the resulting 36704253320SMarcel Koester /// `OperandRange` represents all operands that are passed to the specified 36804253320SMarcel Koester /// successor region. If `regionIndex` is `llvm::None`, all operands that are 36904253320SMarcel Koester /// passed to the parent operation will be returned. 37004253320SMarcel Koester Optional<MutableOperandRange> 37104253320SMarcel Koester mlir::getMutableRegionBranchSuccessorOperands(Operation *operation, 37204253320SMarcel Koester Optional<unsigned> regionIndex) { 37304253320SMarcel Koester // Try to query a RegionBranchTerminatorOpInterface to determine 37404253320SMarcel Koester // all successor operands that will be passed to the successor 37504253320SMarcel Koester // input arguments. 37604253320SMarcel Koester if (auto regionTerminatorInterface = 37704253320SMarcel Koester dyn_cast<RegionBranchTerminatorOpInterface>(operation)) 37804253320SMarcel Koester return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex); 37904253320SMarcel Koester 38004253320SMarcel Koester // TODO: The ReturnLike trait should imply a default implementation of the 38104253320SMarcel Koester // RegionBranchTerminatorOpInterface. This would make this code significantly 38204253320SMarcel Koester // easier. Furthermore, this may even make this function obsolete. 38304253320SMarcel Koester if (operation->hasTrait<OpTrait::ReturnLike>()) 38404253320SMarcel Koester return MutableOperandRange(operation); 38504253320SMarcel Koester return llvm::None; 38604253320SMarcel Koester } 38704253320SMarcel Koester 38804253320SMarcel Koester /// Returns the read only operands that are passed to the region with the given 38904253320SMarcel Koester /// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more 39004253320SMarcel Koester /// information. 39104253320SMarcel Koester Optional<OperandRange> 39204253320SMarcel Koester mlir::getRegionBranchSuccessorOperands(Operation *operation, 39304253320SMarcel Koester Optional<unsigned> regionIndex) { 39404253320SMarcel Koester auto range = getMutableRegionBranchSuccessorOperands(operation, regionIndex); 39504253320SMarcel Koester return range ? Optional<OperandRange>(*range) : llvm::None; 39604253320SMarcel Koester } 397