1 //===- ControlFlowInterfaces.cpp - ControlFlow Interfaces -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "mlir/Interfaces/ControlFlowInterfaces.h" 10 #include "mlir/IR/StandardTypes.h" 11 #include "llvm/ADT/SmallPtrSet.h" 12 13 using namespace mlir; 14 15 //===----------------------------------------------------------------------===// 16 // ControlFlowInterfaces 17 //===----------------------------------------------------------------------===// 18 19 #include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc" 20 21 //===----------------------------------------------------------------------===// 22 // BranchOpInterface 23 //===----------------------------------------------------------------------===// 24 25 /// Returns the `BlockArgument` corresponding to operand `operandIndex` in some 26 /// successor if 'operandIndex' is within the range of 'operands', or None if 27 /// `operandIndex` isn't a successor operand index. 28 Optional<BlockArgument> 29 detail::getBranchSuccessorArgument(Optional<OperandRange> operands, 30 unsigned operandIndex, Block *successor) { 31 // Check that the operands are valid. 32 if (!operands || operands->empty()) 33 return llvm::None; 34 35 // Check to ensure that this operand is within the range. 36 unsigned operandsStart = operands->getBeginOperandIndex(); 37 if (operandIndex < operandsStart || 38 operandIndex >= (operandsStart + operands->size())) 39 return llvm::None; 40 41 // Index the successor. 42 unsigned argIndex = operandIndex - operandsStart; 43 return successor->getArgument(argIndex); 44 } 45 46 /// Verify that the given operands match those of the given successor block. 47 LogicalResult 48 detail::verifyBranchSuccessorOperands(Operation *op, unsigned succNo, 49 Optional<OperandRange> operands) { 50 if (!operands) 51 return success(); 52 53 // Check the count. 54 unsigned operandCount = operands->size(); 55 Block *destBB = op->getSuccessor(succNo); 56 if (operandCount != destBB->getNumArguments()) 57 return op->emitError() << "branch has " << operandCount 58 << " operands for successor #" << succNo 59 << ", but target block has " 60 << destBB->getNumArguments(); 61 62 // Check the types. 63 auto operandIt = operands->begin(); 64 for (unsigned i = 0; i != operandCount; ++i, ++operandIt) { 65 if ((*operandIt).getType() != destBB->getArgument(i).getType()) 66 return op->emitError() << "type mismatch for bb argument #" << i 67 << " of successor #" << succNo; 68 } 69 return success(); 70 } 71 72 //===----------------------------------------------------------------------===// 73 // RegionBranchOpInterface 74 //===----------------------------------------------------------------------===// 75 76 /// Verify that types match along all region control flow edges originating from 77 /// `sourceNo` (region # if source is a region, llvm::None if source is parent 78 /// op). `getInputsTypesForRegion` is a function that returns the types of the 79 /// inputs that flow from `sourceIndex' to the given region. 80 static LogicalResult verifyTypesAlongAllEdges( 81 Operation *op, Optional<unsigned> sourceNo, 82 function_ref<TypeRange(Optional<unsigned>)> getInputsTypesForRegion) { 83 auto regionInterface = cast<RegionBranchOpInterface>(op); 84 85 SmallVector<RegionSuccessor, 2> successors; 86 unsigned numInputs; 87 if (sourceNo) { 88 Region &srcRegion = op->getRegion(sourceNo.getValue()); 89 numInputs = srcRegion.getNumArguments(); 90 } else { 91 numInputs = op->getNumOperands(); 92 } 93 SmallVector<Attribute, 2> operands(numInputs, nullptr); 94 regionInterface.getSuccessorRegions(sourceNo, operands, successors); 95 96 for (RegionSuccessor &succ : successors) { 97 Optional<unsigned> succRegionNo; 98 if (!succ.isParent()) 99 succRegionNo = succ.getSuccessor()->getRegionNumber(); 100 101 auto printEdgeName = [&](InFlightDiagnostic &diag) -> InFlightDiagnostic & { 102 diag << "from "; 103 if (sourceNo) 104 diag << "Region #" << sourceNo.getValue(); 105 else 106 diag << op->getName(); 107 108 diag << " to "; 109 if (succRegionNo) 110 diag << "Region #" << succRegionNo.getValue(); 111 else 112 diag << op->getName(); 113 return diag; 114 }; 115 116 TypeRange sourceTypes = getInputsTypesForRegion(succRegionNo); 117 TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes(); 118 if (sourceTypes.size() != succInputsTypes.size()) { 119 InFlightDiagnostic diag = op->emitOpError(" region control flow edge "); 120 return printEdgeName(diag) 121 << " has " << sourceTypes.size() 122 << " source operands, but target successor needs " 123 << succInputsTypes.size(); 124 } 125 126 for (auto typesIdx : 127 llvm::enumerate(llvm::zip(sourceTypes, succInputsTypes))) { 128 Type sourceType = std::get<0>(typesIdx.value()); 129 Type inputType = std::get<1>(typesIdx.value()); 130 if (sourceType != inputType) { 131 InFlightDiagnostic diag = op->emitOpError(" along control flow edge "); 132 return printEdgeName(diag) 133 << " source #" << typesIdx.index() << " type " << sourceType 134 << " should match input #" << typesIdx.index() << " type " 135 << inputType; 136 } 137 } 138 } 139 return success(); 140 } 141 142 /// Verify that types match along control flow edges described the given op. 143 LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) { 144 auto regionInterface = cast<RegionBranchOpInterface>(op); 145 146 auto inputTypesFromParent = [&](Optional<unsigned> regionNo) -> TypeRange { 147 if (regionNo.hasValue()) { 148 return regionInterface.getSuccessorEntryOperands(regionNo.getValue()) 149 .getTypes(); 150 } 151 152 // If the successor of a parent op is the parent itself 153 // RegionBranchOpInterface does not have an API to query what the entry 154 // operands will be in that case. Vend out the result types of the op in 155 // that case so that type checking succeeds for this case. 156 return op->getResultTypes(); 157 }; 158 159 // Verify types along control flow edges originating from the parent. 160 if (failed(verifyTypesAlongAllEdges(op, llvm::None, inputTypesFromParent))) 161 return failure(); 162 163 // RegionBranchOpInterface should not be implemented by Ops that do not have 164 // attached regions. 165 assert(op->getNumRegions() != 0); 166 167 // Verify types along control flow edges originating from each region. 168 for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) { 169 Region ®ion = op->getRegion(regionNo); 170 171 // Since the interface cannnot distinguish between different ReturnLike 172 // ops within the region branching to different successors, all ReturnLike 173 // ops in this region should have the same operand types. We will then use 174 // one of them as the representative for type matching. 175 176 Operation *regionReturn = nullptr; 177 for (Block &block : region) { 178 Operation *terminator = block.getTerminator(); 179 if (!terminator->hasTrait<OpTrait::ReturnLike>()) 180 continue; 181 182 if (!regionReturn) { 183 regionReturn = terminator; 184 continue; 185 } 186 187 // Found more than one ReturnLike terminator. Make sure the operand types 188 // match with the first one. 189 if (regionReturn->getOperandTypes() != terminator->getOperandTypes()) 190 return op->emitOpError("Region #") 191 << regionNo 192 << " operands mismatch between return-like terminators"; 193 } 194 195 auto inputTypesFromRegion = [&](Optional<unsigned> regionNo) -> TypeRange { 196 // All successors get the same set of operands. 197 return regionReturn ? TypeRange(regionReturn->getOperands().getTypes()) 198 : TypeRange(); 199 }; 200 201 if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion))) 202 return failure(); 203 } 204 205 return success(); 206 } 207