| File: | build/source/mlir/include/mlir/IR/Value.h |
| Warning: | line 122, column 33 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 <utility> | |||
| 10 | ||||
| 11 | #include "mlir/IR/BuiltinTypes.h" | |||
| 12 | #include "mlir/Interfaces/ControlFlowInterfaces.h" | |||
| 13 | #include "llvm/ADT/SmallPtrSet.h" | |||
| 14 | ||||
| 15 | using namespace mlir; | |||
| 16 | ||||
| 17 | //===----------------------------------------------------------------------===// | |||
| 18 | // ControlFlowInterfaces | |||
| 19 | //===----------------------------------------------------------------------===// | |||
| 20 | ||||
| 21 | #include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc" | |||
| 22 | ||||
| 23 | SuccessorOperands::SuccessorOperands(MutableOperandRange forwardedOperands) | |||
| 24 | : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) { | |||
| 25 | } | |||
| 26 | ||||
| 27 | SuccessorOperands::SuccessorOperands(unsigned int producedOperandCount, | |||
| 28 | MutableOperandRange forwardedOperands) | |||
| 29 | : producedOperandCount(producedOperandCount), | |||
| 30 | forwardedOperands(std::move(forwardedOperands)) {} | |||
| 31 | ||||
| 32 | //===----------------------------------------------------------------------===// | |||
| 33 | // BranchOpInterface | |||
| 34 | //===----------------------------------------------------------------------===// | |||
| 35 | ||||
| 36 | /// Returns the `BlockArgument` corresponding to operand `operandIndex` in some | |||
| 37 | /// successor if 'operandIndex' is within the range of 'operands', or | |||
| 38 | /// std::nullopt if `operandIndex` isn't a successor operand index. | |||
| 39 | std::optional<BlockArgument> | |||
| 40 | detail::getBranchSuccessorArgument(const SuccessorOperands &operands, | |||
| 41 | unsigned operandIndex, Block *successor) { | |||
| 42 | OperandRange forwardedOperands = operands.getForwardedOperands(); | |||
| 43 | // Check that the operands are valid. | |||
| 44 | if (forwardedOperands.empty()) | |||
| 45 | return std::nullopt; | |||
| 46 | ||||
| 47 | // Check to ensure that this operand is within the range. | |||
| 48 | unsigned operandsStart = forwardedOperands.getBeginOperandIndex(); | |||
| 49 | if (operandIndex < operandsStart || | |||
| 50 | operandIndex >= (operandsStart + forwardedOperands.size())) | |||
| 51 | return std::nullopt; | |||
| 52 | ||||
| 53 | // Index the successor. | |||
| 54 | unsigned argIndex = | |||
| 55 | operands.getProducedOperandCount() + operandIndex - operandsStart; | |||
| 56 | return successor->getArgument(argIndex); | |||
| 57 | } | |||
| 58 | ||||
| 59 | /// Verify that the given operands match those of the given successor block. | |||
| 60 | LogicalResult | |||
| 61 | detail::verifyBranchSuccessorOperands(Operation *op, unsigned succNo, | |||
| 62 | const SuccessorOperands &operands) { | |||
| 63 | // Check the count. | |||
| 64 | unsigned operandCount = operands.size(); | |||
| 65 | Block *destBB = op->getSuccessor(succNo); | |||
| 66 | if (operandCount != destBB->getNumArguments()) | |||
| ||||
| 67 | return op->emitError() << "branch has " << operandCount | |||
| 68 | << " operands for successor #" << succNo | |||
| 69 | << ", but target block has " | |||
| 70 | << destBB->getNumArguments(); | |||
| 71 | ||||
| 72 | // Check the types. | |||
| 73 | for (unsigned i = operands.getProducedOperandCount(); i != operandCount; | |||
| 74 | ++i) { | |||
| 75 | if (!cast<BranchOpInterface>(op).areTypesCompatible( | |||
| 76 | operands[i].getType(), destBB->getArgument(i).getType())) | |||
| 77 | return op->emitError() << "type mismatch for bb argument #" << i | |||
| 78 | << " of successor #" << succNo; | |||
| 79 | } | |||
| 80 | return success(); | |||
| 81 | } | |||
| 82 | ||||
| 83 | //===----------------------------------------------------------------------===// | |||
| 84 | // RegionBranchOpInterface | |||
| 85 | //===----------------------------------------------------------------------===// | |||
| 86 | ||||
| 87 | /// Verify that types match along all region control flow edges originating from | |||
| 88 | /// `sourceNo` (region # if source is a region, std::nullopt if source is parent | |||
| 89 | /// op). `getInputsTypesForRegion` is a function that returns the types of the | |||
| 90 | /// inputs that flow from `sourceIndex' to the given region, or std::nullopt if | |||
| 91 | /// the exact type match verification is not necessary (e.g., if the Op verifies | |||
| 92 | /// the match itself). | |||
| 93 | static LogicalResult verifyTypesAlongAllEdges( | |||
| 94 | Operation *op, std::optional<unsigned> sourceNo, | |||
| 95 | function_ref<std::optional<TypeRange>(std::optional<unsigned>)> | |||
| 96 | getInputsTypesForRegion) { | |||
| 97 | auto regionInterface = cast<RegionBranchOpInterface>(op); | |||
| 98 | ||||
| 99 | SmallVector<RegionSuccessor, 2> successors; | |||
| 100 | regionInterface.getSuccessorRegions(sourceNo, successors); | |||
| 101 | ||||
| 102 | for (RegionSuccessor &succ : successors) { | |||
| 103 | std::optional<unsigned> succRegionNo; | |||
| 104 | if (!succ.isParent()) | |||
| 105 | succRegionNo = succ.getSuccessor()->getRegionNumber(); | |||
| 106 | ||||
| 107 | auto printEdgeName = [&](InFlightDiagnostic &diag) -> InFlightDiagnostic & { | |||
| 108 | diag << "from "; | |||
| 109 | if (sourceNo) | |||
| 110 | diag << "Region #" << sourceNo.value(); | |||
| 111 | else | |||
| 112 | diag << "parent operands"; | |||
| 113 | ||||
| 114 | diag << " to "; | |||
| 115 | if (succRegionNo) | |||
| 116 | diag << "Region #" << succRegionNo.value(); | |||
| 117 | else | |||
| 118 | diag << "parent results"; | |||
| 119 | return diag; | |||
| 120 | }; | |||
| 121 | ||||
| 122 | std::optional<TypeRange> sourceTypes = | |||
| 123 | getInputsTypesForRegion(succRegionNo); | |||
| 124 | if (!sourceTypes.has_value()) | |||
| 125 | continue; | |||
| 126 | ||||
| 127 | TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes(); | |||
| 128 | if (sourceTypes->size() != succInputsTypes.size()) { | |||
| 129 | InFlightDiagnostic diag = op->emitOpError(" region control flow edge "); | |||
| 130 | return printEdgeName(diag) << ": source has " << sourceTypes->size() | |||
| 131 | << " operands, but target successor needs " | |||
| 132 | << succInputsTypes.size(); | |||
| 133 | } | |||
| 134 | ||||
| 135 | for (const auto &typesIdx : | |||
| 136 | llvm::enumerate(llvm::zip(*sourceTypes, succInputsTypes))) { | |||
| 137 | Type sourceType = std::get<0>(typesIdx.value()); | |||
| 138 | Type inputType = std::get<1>(typesIdx.value()); | |||
| 139 | if (!regionInterface.areTypesCompatible(sourceType, inputType)) { | |||
| 140 | InFlightDiagnostic diag = op->emitOpError(" along control flow edge "); | |||
| 141 | return printEdgeName(diag) | |||
| 142 | << ": source type #" << typesIdx.index() << " " << sourceType | |||
| 143 | << " should match input type #" << typesIdx.index() << " " | |||
| 144 | << inputType; | |||
| 145 | } | |||
| 146 | } | |||
| 147 | } | |||
| 148 | return success(); | |||
| 149 | } | |||
| 150 | ||||
| 151 | /// Verify that types match along control flow edges described the given op. | |||
| 152 | LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) { | |||
| 153 | auto regionInterface = cast<RegionBranchOpInterface>(op); | |||
| 154 | ||||
| 155 | auto inputTypesFromParent = | |||
| 156 | [&](std::optional<unsigned> regionNo) -> TypeRange { | |||
| 157 | return regionInterface.getSuccessorEntryOperands(regionNo).getTypes(); | |||
| 158 | }; | |||
| 159 | ||||
| 160 | // Verify types along control flow edges originating from the parent. | |||
| 161 | if (failed(verifyTypesAlongAllEdges(op, std::nullopt, inputTypesFromParent))) | |||
| 162 | return failure(); | |||
| 163 | ||||
| 164 | auto areTypesCompatible = [&](TypeRange lhs, TypeRange rhs) { | |||
| 165 | if (lhs.size() != rhs.size()) | |||
| 166 | return false; | |||
| 167 | for (auto types : llvm::zip(lhs, rhs)) { | |||
| 168 | if (!regionInterface.areTypesCompatible(std::get<0>(types), | |||
| 169 | std::get<1>(types))) { | |||
| 170 | return false; | |||
| 171 | } | |||
| 172 | } | |||
| 173 | return true; | |||
| 174 | }; | |||
| 175 | ||||
| 176 | // Verify types along control flow edges originating from each region. | |||
| 177 | for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) { | |||
| 178 | Region ®ion = op->getRegion(regionNo); | |||
| 179 | ||||
| 180 | // Since there can be multiple `ReturnLike` terminators or others | |||
| 181 | // implementing the `RegionBranchTerminatorOpInterface`, all should have the | |||
| 182 | // same operand types when passing them to the same region. | |||
| 183 | ||||
| 184 | std::optional<OperandRange> regionReturnOperands; | |||
| 185 | for (Block &block : region) { | |||
| 186 | Operation *terminator = block.getTerminator(); | |||
| 187 | auto terminatorOperands = | |||
| 188 | getRegionBranchSuccessorOperands(terminator, regionNo); | |||
| 189 | if (!terminatorOperands) | |||
| 190 | continue; | |||
| 191 | ||||
| 192 | if (!regionReturnOperands) { | |||
| 193 | regionReturnOperands = terminatorOperands; | |||
| 194 | continue; | |||
| 195 | } | |||
| 196 | ||||
| 197 | // Found more than one ReturnLike terminator. Make sure the operand types | |||
| 198 | // match with the first one. | |||
| 199 | if (!areTypesCompatible(regionReturnOperands->getTypes(), | |||
| 200 | terminatorOperands->getTypes())) | |||
| 201 | return op->emitOpError("Region #") | |||
| 202 | << regionNo | |||
| 203 | << " operands mismatch between return-like terminators"; | |||
| 204 | } | |||
| 205 | ||||
| 206 | auto inputTypesFromRegion = | |||
| 207 | [&](std::optional<unsigned> regionNo) -> std::optional<TypeRange> { | |||
| 208 | // If there is no return-like terminator, the op itself should verify | |||
| 209 | // type consistency. | |||
| 210 | if (!regionReturnOperands) | |||
| 211 | return std::nullopt; | |||
| 212 | ||||
| 213 | // All successors get the same set of operand types. | |||
| 214 | return TypeRange(regionReturnOperands->getTypes()); | |||
| 215 | }; | |||
| 216 | ||||
| 217 | if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion))) | |||
| 218 | return failure(); | |||
| 219 | } | |||
| 220 | ||||
| 221 | return success(); | |||
| 222 | } | |||
| 223 | ||||
| 224 | /// Return `true` if region `r` is reachable from region `begin` according to | |||
| 225 | /// the RegionBranchOpInterface (by taking a branch). | |||
| 226 | static bool isRegionReachable(Region *begin, Region *r) { | |||
| 227 | assert(begin->getParentOp() == r->getParentOp() &&(static_cast <bool> (begin->getParentOp() == r->getParentOp () && "expected that both regions belong to the same op" ) ? void (0) : __assert_fail ("begin->getParentOp() == r->getParentOp() && \"expected that both regions belong to the same op\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 228, __extension__ __PRETTY_FUNCTION__)) | |||
| 228 | "expected that both regions belong to the same op")(static_cast <bool> (begin->getParentOp() == r->getParentOp () && "expected that both regions belong to the same op" ) ? void (0) : __assert_fail ("begin->getParentOp() == r->getParentOp() && \"expected that both regions belong to the same op\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 228, __extension__ __PRETTY_FUNCTION__)); | |||
| 229 | auto op = cast<RegionBranchOpInterface>(begin->getParentOp()); | |||
| 230 | SmallVector<bool> visited(op->getNumRegions(), false); | |||
| 231 | visited[begin->getRegionNumber()] = true; | |||
| 232 | ||||
| 233 | // Retrieve all successors of the region and enqueue them in the worklist. | |||
| 234 | SmallVector<unsigned> worklist; | |||
| 235 | auto enqueueAllSuccessors = [&](unsigned index) { | |||
| 236 | SmallVector<RegionSuccessor> successors; | |||
| 237 | op.getSuccessorRegions(index, successors); | |||
| 238 | for (RegionSuccessor successor : successors) | |||
| 239 | if (!successor.isParent()) | |||
| 240 | worklist.push_back(successor.getSuccessor()->getRegionNumber()); | |||
| 241 | }; | |||
| 242 | enqueueAllSuccessors(begin->getRegionNumber()); | |||
| 243 | ||||
| 244 | // Process all regions in the worklist via DFS. | |||
| 245 | while (!worklist.empty()) { | |||
| 246 | unsigned nextRegion = worklist.pop_back_val(); | |||
| 247 | if (nextRegion == r->getRegionNumber()) | |||
| 248 | return true; | |||
| 249 | if (visited[nextRegion]) | |||
| 250 | continue; | |||
| 251 | visited[nextRegion] = true; | |||
| 252 | enqueueAllSuccessors(nextRegion); | |||
| 253 | } | |||
| 254 | ||||
| 255 | return false; | |||
| 256 | } | |||
| 257 | ||||
| 258 | /// Return `true` if `a` and `b` are in mutually exclusive regions. | |||
| 259 | /// | |||
| 260 | /// 1. Find the first common of `a` and `b` (ancestor) that implements | |||
| 261 | /// RegionBranchOpInterface. | |||
| 262 | /// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are | |||
| 263 | /// contained. | |||
| 264 | /// 3. Check if `regionA` and `regionB` are mutually exclusive. They are | |||
| 265 | /// mutually exclusive if they are not reachable from each other as per | |||
| 266 | /// RegionBranchOpInterface::getSuccessorRegions. | |||
| 267 | bool mlir::insideMutuallyExclusiveRegions(Operation *a, Operation *b) { | |||
| 268 | assert(a && "expected non-empty operation")(static_cast <bool> (a && "expected non-empty operation" ) ? void (0) : __assert_fail ("a && \"expected non-empty operation\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 268, __extension__ __PRETTY_FUNCTION__)); | |||
| 269 | assert(b && "expected non-empty operation")(static_cast <bool> (b && "expected non-empty operation" ) ? void (0) : __assert_fail ("b && \"expected non-empty operation\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 269, __extension__ __PRETTY_FUNCTION__)); | |||
| 270 | ||||
| 271 | auto branchOp = a->getParentOfType<RegionBranchOpInterface>(); | |||
| 272 | while (branchOp) { | |||
| 273 | // Check if b is inside branchOp. (We already know that a is.) | |||
| 274 | if (!branchOp->isProperAncestor(b)) { | |||
| 275 | // Check next enclosing RegionBranchOpInterface. | |||
| 276 | branchOp = branchOp->getParentOfType<RegionBranchOpInterface>(); | |||
| 277 | continue; | |||
| 278 | } | |||
| 279 | ||||
| 280 | // b is contained in branchOp. Retrieve the regions in which `a` and `b` | |||
| 281 | // are contained. | |||
| 282 | Region *regionA = nullptr, *regionB = nullptr; | |||
| 283 | for (Region &r : branchOp->getRegions()) { | |||
| 284 | if (r.findAncestorOpInRegion(*a)) { | |||
| 285 | assert(!regionA && "already found a region for a")(static_cast <bool> (!regionA && "already found a region for a" ) ? void (0) : __assert_fail ("!regionA && \"already found a region for a\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 285, __extension__ __PRETTY_FUNCTION__)); | |||
| 286 | regionA = &r; | |||
| 287 | } | |||
| 288 | if (r.findAncestorOpInRegion(*b)) { | |||
| 289 | assert(!regionB && "already found a region for b")(static_cast <bool> (!regionB && "already found a region for b" ) ? void (0) : __assert_fail ("!regionB && \"already found a region for b\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 289, __extension__ __PRETTY_FUNCTION__)); | |||
| 290 | regionB = &r; | |||
| 291 | } | |||
| 292 | } | |||
| 293 | assert(regionA && regionB && "could not find region of op")(static_cast <bool> (regionA && regionB && "could not find region of op") ? void (0) : __assert_fail ("regionA && regionB && \"could not find region of op\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 293, __extension__ __PRETTY_FUNCTION__)); | |||
| 294 | ||||
| 295 | // `a` and `b` are in mutually exclusive regions if both regions are | |||
| 296 | // distinct and neither region is reachable from the other region. | |||
| 297 | return regionA != regionB && !isRegionReachable(regionA, regionB) && | |||
| 298 | !isRegionReachable(regionB, regionA); | |||
| 299 | } | |||
| 300 | ||||
| 301 | // Could not find a common RegionBranchOpInterface among a's and b's | |||
| 302 | // ancestors. | |||
| 303 | return false; | |||
| 304 | } | |||
| 305 | ||||
| 306 | bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) { | |||
| 307 | Region *region = &getOperation()->getRegion(index); | |||
| 308 | return isRegionReachable(region, region); | |||
| 309 | } | |||
| 310 | ||||
| 311 | void RegionBranchOpInterface::getSuccessorRegions( | |||
| 312 | std::optional<unsigned> index, SmallVectorImpl<RegionSuccessor> ®ions) { | |||
| 313 | unsigned numInputs = 0; | |||
| 314 | if (index) { | |||
| 315 | // If the predecessor is a region, get the number of operands from an | |||
| 316 | // exiting terminator in the region. | |||
| 317 | for (Block &block : getOperation()->getRegion(*index)) { | |||
| 318 | Operation *terminator = block.getTerminator(); | |||
| 319 | if (getRegionBranchSuccessorOperands(terminator, *index)) { | |||
| 320 | numInputs = terminator->getNumOperands(); | |||
| 321 | break; | |||
| 322 | } | |||
| 323 | } | |||
| 324 | } else { | |||
| 325 | // Otherwise, use the number of parent operation operands. | |||
| 326 | numInputs = getOperation()->getNumOperands(); | |||
| 327 | } | |||
| 328 | SmallVector<Attribute, 2> operands(numInputs, nullptr); | |||
| 329 | getSuccessorRegions(index, operands, regions); | |||
| 330 | } | |||
| 331 | ||||
| 332 | Region *mlir::getEnclosingRepetitiveRegion(Operation *op) { | |||
| 333 | while (Region *region = op->getParentRegion()) { | |||
| 334 | op = region->getParentOp(); | |||
| 335 | if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) | |||
| 336 | if (branchOp.isRepetitiveRegion(region->getRegionNumber())) | |||
| 337 | return region; | |||
| 338 | } | |||
| 339 | return nullptr; | |||
| 340 | } | |||
| 341 | ||||
| 342 | Region *mlir::getEnclosingRepetitiveRegion(Value value) { | |||
| 343 | Region *region = value.getParentRegion(); | |||
| 344 | while (region) { | |||
| 345 | Operation *op = region->getParentOp(); | |||
| 346 | if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) | |||
| 347 | if (branchOp.isRepetitiveRegion(region->getRegionNumber())) | |||
| 348 | return region; | |||
| 349 | region = op->getParentRegion(); | |||
| 350 | } | |||
| 351 | return nullptr; | |||
| 352 | } | |||
| 353 | ||||
| 354 | //===----------------------------------------------------------------------===// | |||
| 355 | // RegionBranchTerminatorOpInterface | |||
| 356 | //===----------------------------------------------------------------------===// | |||
| 357 | ||||
| 358 | /// Returns true if the given operation is either annotated with the | |||
| 359 | /// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`. | |||
| 360 | bool mlir::isRegionReturnLike(Operation *operation) { | |||
| 361 | return dyn_cast<RegionBranchTerminatorOpInterface>(operation) || | |||
| 362 | operation->hasTrait<OpTrait::ReturnLike>(); | |||
| 363 | } | |||
| 364 | ||||
| 365 | /// Returns the mutable operands that are passed to the region with the given | |||
| 366 | /// `regionIndex`. If the operation does not implement the | |||
| 367 | /// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the | |||
| 368 | /// result will be `std::nullopt`. In all other cases, the resulting | |||
| 369 | /// `OperandRange` represents all operands that are passed to the specified | |||
| 370 | /// successor region. If `regionIndex` is `std::nullopt`, all operands that are | |||
| 371 | /// passed to the parent operation will be returned. | |||
| 372 | std::optional<MutableOperandRange> | |||
| 373 | mlir::getMutableRegionBranchSuccessorOperands( | |||
| 374 | Operation *operation, std::optional<unsigned> regionIndex) { | |||
| 375 | // Try to query a RegionBranchTerminatorOpInterface to determine | |||
| 376 | // all successor operands that will be passed to the successor | |||
| 377 | // input arguments. | |||
| 378 | if (auto regionTerminatorInterface = | |||
| 379 | dyn_cast<RegionBranchTerminatorOpInterface>(operation)) | |||
| 380 | return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex); | |||
| 381 | ||||
| 382 | // TODO: The ReturnLike trait should imply a default implementation of the | |||
| 383 | // RegionBranchTerminatorOpInterface. This would make this code significantly | |||
| 384 | // easier. Furthermore, this may even make this function obsolete. | |||
| 385 | if (operation->hasTrait<OpTrait::ReturnLike>()) | |||
| 386 | return MutableOperandRange(operation); | |||
| 387 | return std::nullopt; | |||
| 388 | } | |||
| 389 | ||||
| 390 | /// Returns the read only operands that are passed to the region with the given | |||
| 391 | /// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more | |||
| 392 | /// information. | |||
| 393 | std::optional<OperandRange> | |||
| 394 | mlir::getRegionBranchSuccessorOperands(Operation *operation, | |||
| 395 | std::optional<unsigned> regionIndex) { | |||
| 396 | auto range = getMutableRegionBranchSuccessorOperands(operation, regionIndex); | |||
| 397 | if (range) | |||
| 398 | return range->operator OperandRange(); | |||
| 399 | return std::nullopt; | |||
| 400 | } |
| 1 | //===- ControlFlowInterfaces.h - ControlFlow Interfaces ---------*- C++ -*-===// |
| 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 | // This file contains the definitions of the branch interfaces defined in |
| 10 | // `ControlFlowInterfaces.td`. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef MLIR_INTERFACES_CONTROLFLOWINTERFACES_H |
| 15 | #define MLIR_INTERFACES_CONTROLFLOWINTERFACES_H |
| 16 | |
| 17 | #include "mlir/IR/OpDefinition.h" |
| 18 | |
| 19 | namespace mlir { |
| 20 | class BranchOpInterface; |
| 21 | class RegionBranchOpInterface; |
| 22 | |
| 23 | /// This class models how operands are forwarded to block arguments in control |
| 24 | /// flow. It consists of a number, denoting how many of the successors block |
| 25 | /// arguments are produced by the operation, followed by a range of operands |
| 26 | /// that are forwarded. The produced operands are passed to the first few |
| 27 | /// block arguments of the successor, followed by the forwarded operands. |
| 28 | /// It is unsupported to pass them in a different order. |
| 29 | /// |
| 30 | /// An example operation with both of these concepts would be a branch-on-error |
| 31 | /// operation, that internally produces an error object on the error path: |
| 32 | /// |
| 33 | /// invoke %function(%0) |
| 34 | /// label ^success ^error(%1 : i32) |
| 35 | /// |
| 36 | /// ^error(%e: !error, %arg0 : i32): |
| 37 | /// ... |
| 38 | /// |
| 39 | /// This operation would return an instance of SuccessorOperands with a produced |
| 40 | /// operand count of 1 (mapped to %e in the successor) and a forwarded |
| 41 | /// operands range consisting of %1 in the example above (mapped to %arg0 in the |
| 42 | /// successor). |
| 43 | class SuccessorOperands { |
| 44 | public: |
| 45 | /// Constructs a SuccessorOperands with no produced operands that simply |
| 46 | /// forwards operands to the successor. |
| 47 | explicit SuccessorOperands(MutableOperandRange forwardedOperands); |
| 48 | |
| 49 | /// Constructs a SuccessorOperands with the given amount of produced operands |
| 50 | /// and forwarded operands. |
| 51 | SuccessorOperands(unsigned producedOperandCount, |
| 52 | MutableOperandRange forwardedOperands); |
| 53 | |
| 54 | /// Returns the amount of operands passed to the successor. This consists both |
| 55 | /// of produced operands by the operation as well as forwarded ones. |
| 56 | unsigned size() const { |
| 57 | return producedOperandCount + forwardedOperands.size(); |
| 58 | } |
| 59 | |
| 60 | /// Returns true if there are no successor operands. |
| 61 | bool empty() const { return size() == 0; } |
| 62 | |
| 63 | /// Returns the amount of operands that are produced internally by the |
| 64 | /// operation. These are passed to the first few block arguments. |
| 65 | unsigned getProducedOperandCount() const { return producedOperandCount; } |
| 66 | |
| 67 | /// Returns true if the successor operand denoted by `index` is produced by |
| 68 | /// the operation. |
| 69 | bool isOperandProduced(unsigned index) const { |
| 70 | return index < producedOperandCount; |
| 71 | } |
| 72 | |
| 73 | /// Returns the Value that is passed to the successors block argument denoted |
| 74 | /// by `index`. If it is produced by the operation, no such value exists and |
| 75 | /// a null Value is returned. |
| 76 | Value operator[](unsigned index) const { |
| 77 | if (isOperandProduced(index)) |
| 78 | return Value(); |
| 79 | return forwardedOperands[index - producedOperandCount]; |
| 80 | } |
| 81 | |
| 82 | /// Get the range of operands that are simply forwarded to the successor. |
| 83 | OperandRange getForwardedOperands() const { return forwardedOperands; } |
| 84 | |
| 85 | /// Get a slice of the operands forwarded to the successor. The given range |
| 86 | /// must not contain any operands produced by the operation. |
| 87 | MutableOperandRange slice(unsigned subStart, unsigned subLen) const { |
| 88 | assert(!isOperandProduced(subStart) &&(static_cast <bool> (!isOperandProduced(subStart) && "can't slice operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't slice operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 89, __extension__ __PRETTY_FUNCTION__)) |
| 89 | "can't slice operands produced by the operation")(static_cast <bool> (!isOperandProduced(subStart) && "can't slice operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't slice operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 89, __extension__ __PRETTY_FUNCTION__)); |
| 90 | return forwardedOperands.slice(subStart - producedOperandCount, subLen); |
| 91 | } |
| 92 | |
| 93 | /// Erase operands forwarded to the successor. The given range must |
| 94 | /// not contain any operands produced by the operation. |
| 95 | void erase(unsigned subStart, unsigned subLen = 1) { |
| 96 | assert(!isOperandProduced(subStart) &&(static_cast <bool> (!isOperandProduced(subStart) && "can't erase operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't erase operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 97, __extension__ __PRETTY_FUNCTION__)) |
| 97 | "can't erase operands produced by the operation")(static_cast <bool> (!isOperandProduced(subStart) && "can't erase operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't erase operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 97, __extension__ __PRETTY_FUNCTION__)); |
| 98 | forwardedOperands.erase(subStart - producedOperandCount, subLen); |
| 99 | } |
| 100 | |
| 101 | /// Add new operands that are forwarded to the successor. |
| 102 | void append(ValueRange valueRange) { forwardedOperands.append(valueRange); } |
| 103 | |
| 104 | /// Gets the index of the forwarded operand within the operation which maps |
| 105 | /// to the block argument denoted by `blockArgumentIndex`. The block argument |
| 106 | /// must be mapped to a forwarded operand. |
| 107 | unsigned getOperandIndex(unsigned blockArgumentIndex) const { |
| 108 | assert(!isOperandProduced(blockArgumentIndex) &&(static_cast <bool> (!isOperandProduced(blockArgumentIndex ) && "can't map operand produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(blockArgumentIndex) && \"can't map operand produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 109 , __extension__ __PRETTY_FUNCTION__)) |
| 109 | "can't map operand produced by the operation")(static_cast <bool> (!isOperandProduced(blockArgumentIndex ) && "can't map operand produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(blockArgumentIndex) && \"can't map operand produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 109 , __extension__ __PRETTY_FUNCTION__)); |
| 110 | OperandRange operands = forwardedOperands; |
| 111 | return operands.getBeginOperandIndex() + |
| 112 | (blockArgumentIndex - producedOperandCount); |
| 113 | } |
| 114 | |
| 115 | private: |
| 116 | /// Amount of operands that are produced internally within the operation and |
| 117 | /// passed to the first few block arguments. |
| 118 | unsigned producedOperandCount; |
| 119 | /// Range of operands that are forwarded to the remaining block arguments. |
| 120 | MutableOperandRange forwardedOperands; |
| 121 | }; |
| 122 | |
| 123 | //===----------------------------------------------------------------------===// |
| 124 | // BranchOpInterface |
| 125 | //===----------------------------------------------------------------------===// |
| 126 | |
| 127 | namespace detail { |
| 128 | /// Return the `BlockArgument` corresponding to operand `operandIndex` in some |
| 129 | /// successor if `operandIndex` is within the range of `operands`, or |
| 130 | /// std::nullopt if `operandIndex` isn't a successor operand index. |
| 131 | std::optional<BlockArgument> |
| 132 | getBranchSuccessorArgument(const SuccessorOperands &operands, |
| 133 | unsigned operandIndex, Block *successor); |
| 134 | |
| 135 | /// Verify that the given operands match those of the given successor block. |
| 136 | LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo, |
| 137 | const SuccessorOperands &operands); |
| 138 | } // namespace detail |
| 139 | |
| 140 | //===----------------------------------------------------------------------===// |
| 141 | // RegionBranchOpInterface |
| 142 | //===----------------------------------------------------------------------===// |
| 143 | |
| 144 | namespace detail { |
| 145 | /// Verify that types match along control flow edges described the given op. |
| 146 | LogicalResult verifyTypesAlongControlFlowEdges(Operation *op); |
| 147 | } // namespace detail |
| 148 | |
| 149 | /// This class represents a successor of a region. A region successor can either |
| 150 | /// be another region, or the parent operation. If the successor is a region, |
| 151 | /// this class represents the destination region, as well as a set of arguments |
| 152 | /// from that region that will be populated when control flows into the region. |
| 153 | /// If the successor is the parent operation, this class represents an optional |
| 154 | /// set of results that will be populated when control returns to the parent |
| 155 | /// operation. |
| 156 | /// |
| 157 | /// This interface assumes that the values from the current region that are used |
| 158 | /// to populate the successor inputs are the operands of the return-like |
| 159 | /// terminator operations in the blocks within this region. |
| 160 | class RegionSuccessor { |
| 161 | public: |
| 162 | /// Initialize a successor that branches to another region of the parent |
| 163 | /// operation. |
| 164 | RegionSuccessor(Region *region, Block::BlockArgListType regionInputs = {}) |
| 165 | : region(region), inputs(regionInputs) {} |
| 166 | /// Initialize a successor that branches back to/out of the parent operation. |
| 167 | RegionSuccessor(Operation::result_range results) |
| 168 | : inputs(ValueRange(results)) {} |
| 169 | /// Constructor with no arguments. |
| 170 | RegionSuccessor() : inputs(ValueRange()) {} |
| 171 | |
| 172 | /// Return the given region successor. Returns nullptr if the successor is the |
| 173 | /// parent operation. |
| 174 | Region *getSuccessor() const { return region; } |
| 175 | |
| 176 | /// Return true if the successor is the parent operation. |
| 177 | bool isParent() const { return region == nullptr; } |
| 178 | |
| 179 | /// Return the inputs to the successor that are remapped by the exit values of |
| 180 | /// the current region. |
| 181 | ValueRange getSuccessorInputs() const { return inputs; } |
| 182 | |
| 183 | private: |
| 184 | Region *region{nullptr}; |
| 185 | ValueRange inputs; |
| 186 | }; |
| 187 | |
| 188 | /// This class represents upper and lower bounds on the number of times a region |
| 189 | /// of a `RegionBranchOpInterface` can be invoked. The lower bound is at least |
| 190 | /// zero, but the upper bound may not be known. |
| 191 | class InvocationBounds { |
| 192 | public: |
| 193 | /// Create invocation bounds. The lower bound must be at least 0 and only the |
| 194 | /// upper bound can be unknown. |
| 195 | InvocationBounds(unsigned lb, std::optional<unsigned> ub) |
| 196 | : lower(lb), upper(ub) { |
| 197 | assert((!ub || ub >= lb) && "upper bound cannot be less than lower bound")(static_cast <bool> ((!ub || ub >= lb) && "upper bound cannot be less than lower bound" ) ? void (0) : __assert_fail ("(!ub || ub >= lb) && \"upper bound cannot be less than lower bound\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 197 , __extension__ __PRETTY_FUNCTION__)); |
| 198 | } |
| 199 | |
| 200 | /// Return the lower bound. |
| 201 | unsigned getLowerBound() const { return lower; } |
| 202 | |
| 203 | /// Return the upper bound. |
| 204 | std::optional<unsigned> getUpperBound() const { return upper; } |
| 205 | |
| 206 | /// Returns the unknown invocation bounds, i.e., there is no information on |
| 207 | /// how many times a region may be invoked. |
| 208 | static InvocationBounds getUnknown() { return {0, std::nullopt}; } |
| 209 | |
| 210 | private: |
| 211 | /// The minimum number of times the successor region will be invoked. |
| 212 | unsigned lower; |
| 213 | /// The maximum number of times the successor region will be invoked or |
| 214 | /// `std::nullopt` if an upper bound is not known. |
| 215 | std::optional<unsigned> upper; |
| 216 | }; |
| 217 | |
| 218 | /// Return `true` if `a` and `b` are in mutually exclusive regions as per |
| 219 | /// RegionBranchOpInterface. |
| 220 | bool insideMutuallyExclusiveRegions(Operation *a, Operation *b); |
| 221 | |
| 222 | /// Return the first enclosing region of the given op that may be executed |
| 223 | /// repetitively as per RegionBranchOpInterface or `nullptr` if no such region |
| 224 | /// exists. |
| 225 | Region *getEnclosingRepetitiveRegion(Operation *op); |
| 226 | |
| 227 | /// Return the first enclosing region of the given Value that may be executed |
| 228 | /// repetitively as per RegionBranchOpInterface or `nullptr` if no such region |
| 229 | /// exists. |
| 230 | Region *getEnclosingRepetitiveRegion(Value value); |
| 231 | |
| 232 | //===----------------------------------------------------------------------===// |
| 233 | // RegionBranchTerminatorOpInterface |
| 234 | //===----------------------------------------------------------------------===// |
| 235 | |
| 236 | /// Returns true if the given operation is either annotated with the |
| 237 | /// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`. |
| 238 | bool isRegionReturnLike(Operation *operation); |
| 239 | |
| 240 | /// Returns the mutable operands that are passed to the region with the given |
| 241 | /// `regionIndex`. If the operation does not implement the |
| 242 | /// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the |
| 243 | /// result will be `std::nullopt`. In all other cases, the resulting |
| 244 | /// `OperandRange` represents all operands that are passed to the specified |
| 245 | /// successor region. If `regionIndex` is `std::nullopt`, all operands that are |
| 246 | /// passed to the parent operation will be returned. |
| 247 | std::optional<MutableOperandRange> |
| 248 | getMutableRegionBranchSuccessorOperands(Operation *operation, |
| 249 | std::optional<unsigned> regionIndex); |
| 250 | |
| 251 | /// Returns the read only operands that are passed to the region with the given |
| 252 | /// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more |
| 253 | /// information. |
| 254 | std::optional<OperandRange> |
| 255 | getRegionBranchSuccessorOperands(Operation *operation, |
| 256 | std::optional<unsigned> regionIndex); |
| 257 | |
| 258 | //===----------------------------------------------------------------------===// |
| 259 | // ControlFlow Traits |
| 260 | //===----------------------------------------------------------------------===// |
| 261 | |
| 262 | namespace OpTrait { |
| 263 | /// This trait indicates that a terminator operation is "return-like". This |
| 264 | /// means that it exits its current region and forwards its operands as "exit" |
| 265 | /// values to the parent region. Operations with this trait are not permitted to |
| 266 | /// contain successors or produce results. |
| 267 | template <typename ConcreteType> |
| 268 | struct ReturnLike : public TraitBase<ConcreteType, ReturnLike> { |
| 269 | static LogicalResult verifyTrait(Operation *op) { |
| 270 | static_assert(ConcreteType::template hasTrait<IsTerminator>(), |
| 271 | "expected operation to be a terminator"); |
| 272 | static_assert(ConcreteType::template hasTrait<ZeroResults>(), |
| 273 | "expected operation to have zero results"); |
| 274 | static_assert(ConcreteType::template hasTrait<ZeroSuccessors>(), |
| 275 | "expected operation to have zero successors"); |
| 276 | return success(); |
| 277 | } |
| 278 | }; |
| 279 | } // namespace OpTrait |
| 280 | |
| 281 | } // namespace mlir |
| 282 | |
| 283 | //===----------------------------------------------------------------------===// |
| 284 | // ControlFlow Interfaces |
| 285 | //===----------------------------------------------------------------------===// |
| 286 | |
| 287 | /// Include the generated interface declarations. |
| 288 | #include "mlir/Interfaces/ControlFlowInterfaces.h.inc" |
| 289 | |
| 290 | #endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES_H |
| 1 | //===- Value.h - Base of the SSA Value hierarchy ----------------*- C++ -*-===// | |||
| 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 | // This file defines generic Value type and manipulation utilities. | |||
| 10 | // | |||
| 11 | //===----------------------------------------------------------------------===// | |||
| 12 | ||||
| 13 | #ifndef MLIR_IR_VALUE_H | |||
| 14 | #define MLIR_IR_VALUE_H | |||
| 15 | ||||
| 16 | #include "mlir/IR/Types.h" | |||
| 17 | #include "mlir/IR/UseDefLists.h" | |||
| 18 | #include "mlir/Support/LLVM.h" | |||
| 19 | #include "llvm/Support/PointerLikeTypeTraits.h" | |||
| 20 | ||||
| 21 | namespace mlir { | |||
| 22 | class AsmState; | |||
| 23 | class Block; | |||
| 24 | class BlockArgument; | |||
| 25 | class Operation; | |||
| 26 | class OpOperand; | |||
| 27 | class OpPrintingFlags; | |||
| 28 | class OpResult; | |||
| 29 | class Region; | |||
| 30 | class Value; | |||
| 31 | ||||
| 32 | //===----------------------------------------------------------------------===// | |||
| 33 | // Value | |||
| 34 | //===----------------------------------------------------------------------===// | |||
| 35 | ||||
| 36 | namespace detail { | |||
| 37 | ||||
| 38 | /// The base class for all derived Value classes. It contains all of the | |||
| 39 | /// components that are shared across Value classes. | |||
| 40 | class alignas(8) ValueImpl : public IRObjectWithUseList<OpOperand> { | |||
| 41 | public: | |||
| 42 | /// The enumeration represents the various different kinds of values the | |||
| 43 | /// internal representation may take. We use all of the bits from Type that we | |||
| 44 | /// can to store indices inline. | |||
| 45 | enum class Kind { | |||
| 46 | /// The first N kinds are all inline operation results. An inline operation | |||
| 47 | /// result means that the kind represents the result number. This removes | |||
| 48 | /// the need to store an additional index value. The derived class here is | |||
| 49 | /// an `OpResultImpl`. | |||
| 50 | InlineOpResult = 0, | |||
| 51 | ||||
| 52 | /// The next kind represents a 'out-of-line' operation result. This is for | |||
| 53 | /// results with numbers larger than we can represent inline. The derived | |||
| 54 | /// class here is an `OpResultImpl`. | |||
| 55 | OutOfLineOpResult = 6, | |||
| 56 | ||||
| 57 | /// The last kind represents a block argument. The derived class here is an | |||
| 58 | /// `BlockArgumentImpl`. | |||
| 59 | BlockArgument = 7 | |||
| 60 | }; | |||
| 61 | ||||
| 62 | /// Return the type of this value. | |||
| 63 | Type getType() const { return typeAndKind.getPointer(); } | |||
| 64 | ||||
| 65 | /// Set the type of this value. | |||
| 66 | void setType(Type type) { return typeAndKind.setPointer(type); } | |||
| 67 | ||||
| 68 | /// Return the kind of this value. | |||
| 69 | Kind getKind() const { return typeAndKind.getInt(); } | |||
| 70 | ||||
| 71 | protected: | |||
| 72 | ValueImpl(Type type, Kind kind) : typeAndKind(type, kind) {} | |||
| 73 | ||||
| 74 | /// Expose a few methods explicitly for the debugger to call for | |||
| 75 | /// visualization. | |||
| 76 | #ifndef NDEBUG | |||
| 77 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) Type debug_getType() const { return getType(); } | |||
| 78 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) Kind debug_getKind() const { return getKind(); } | |||
| 79 | ||||
| 80 | #endif | |||
| 81 | ||||
| 82 | /// The type of this result and the kind. | |||
| 83 | llvm::PointerIntPair<Type, 3, Kind> typeAndKind; | |||
| 84 | }; | |||
| 85 | } // namespace detail | |||
| 86 | ||||
| 87 | /// This class represents an instance of an SSA value in the MLIR system, | |||
| 88 | /// representing a computable value that has a type and a set of users. An SSA | |||
| 89 | /// value is either a BlockArgument or the result of an operation. Note: This | |||
| 90 | /// class has value-type semantics and is just a simple wrapper around a | |||
| 91 | /// ValueImpl that is either owner by a block(in the case of a BlockArgument) or | |||
| 92 | /// an Operation(in the case of an OpResult). | |||
| 93 | class Value { | |||
| 94 | public: | |||
| 95 | constexpr Value(detail::ValueImpl *impl = nullptr) : impl(impl) {} | |||
| 96 | ||||
| 97 | template <typename U> | |||
| 98 | bool isa() const { | |||
| 99 | return llvm::isa<U>(*this); | |||
| 100 | } | |||
| 101 | ||||
| 102 | template <typename U> | |||
| 103 | U dyn_cast() const { | |||
| 104 | return llvm::dyn_cast<U>(*this); | |||
| 105 | } | |||
| 106 | ||||
| 107 | template <typename U> | |||
| 108 | U dyn_cast_or_null() const { | |||
| 109 | return llvm::dyn_cast_if_present<U>(*this); | |||
| 110 | } | |||
| 111 | ||||
| 112 | template <typename U> | |||
| 113 | U cast() const { | |||
| 114 | return llvm::cast<U>(*this); | |||
| 115 | } | |||
| 116 | ||||
| 117 | explicit operator bool() const { return impl; } | |||
| 118 | bool operator==(const Value &other) const { return impl == other.impl; } | |||
| 119 | bool operator!=(const Value &other) const { return !(*this == other); } | |||
| 120 | ||||
| 121 | /// Return the type of this value. | |||
| 122 | Type getType() const { return impl->getType(); } | |||
| ||||
| 123 | ||||
| 124 | /// Utility to get the associated MLIRContext that this value is defined in. | |||
| 125 | MLIRContext *getContext() const { return getType().getContext(); } | |||
| 126 | ||||
| 127 | /// Mutate the type of this Value to be of the specified type. | |||
| 128 | /// | |||
| 129 | /// Note that this is an extremely dangerous operation which can create | |||
| 130 | /// completely invalid IR very easily. It is strongly recommended that you | |||
| 131 | /// recreate IR objects with the right types instead of mutating them in | |||
| 132 | /// place. | |||
| 133 | void setType(Type newType) { impl->setType(newType); } | |||
| 134 | ||||
| 135 | /// If this value is the result of an operation, return the operation that | |||
| 136 | /// defines it. | |||
| 137 | Operation *getDefiningOp() const; | |||
| 138 | ||||
| 139 | /// If this value is the result of an operation of type OpTy, return the | |||
| 140 | /// operation that defines it. | |||
| 141 | template <typename OpTy> | |||
| 142 | OpTy getDefiningOp() const { | |||
| 143 | return llvm::dyn_cast_or_null<OpTy>(getDefiningOp()); | |||
| 144 | } | |||
| 145 | ||||
| 146 | /// Return the location of this value. | |||
| 147 | Location getLoc() const; | |||
| 148 | void setLoc(Location loc); | |||
| 149 | ||||
| 150 | /// Return the Region in which this Value is defined. | |||
| 151 | Region *getParentRegion(); | |||
| 152 | ||||
| 153 | /// Return the Block in which this Value is defined. | |||
| 154 | Block *getParentBlock(); | |||
| 155 | ||||
| 156 | //===--------------------------------------------------------------------===// | |||
| 157 | // UseLists | |||
| 158 | //===--------------------------------------------------------------------===// | |||
| 159 | ||||
| 160 | /// Drop all uses of this object from their respective owners. | |||
| 161 | void dropAllUses() const { return impl->dropAllUses(); } | |||
| 162 | ||||
| 163 | /// Replace all uses of 'this' value with the new value, updating anything in | |||
| 164 | /// the IR that uses 'this' to use the other value instead. When this returns | |||
| 165 | /// there are zero uses of 'this'. | |||
| 166 | void replaceAllUsesWith(Value newValue) const { | |||
| 167 | impl->replaceAllUsesWith(newValue); | |||
| 168 | } | |||
| 169 | ||||
| 170 | /// Replace all uses of 'this' value with 'newValue', updating anything in the | |||
| 171 | /// IR that uses 'this' to use the other value instead except if the user is | |||
| 172 | /// listed in 'exceptions' . | |||
| 173 | void | |||
| 174 | replaceAllUsesExcept(Value newValue, | |||
| 175 | const SmallPtrSetImpl<Operation *> &exceptions) const; | |||
| 176 | ||||
| 177 | /// Replace all uses of 'this' value with 'newValue', updating anything in the | |||
| 178 | /// IR that uses 'this' to use the other value instead except if the user is | |||
| 179 | /// 'exceptedUser'. | |||
| 180 | void replaceAllUsesExcept(Value newValue, Operation *exceptedUser) const; | |||
| 181 | ||||
| 182 | /// Replace all uses of 'this' value with 'newValue' if the given callback | |||
| 183 | /// returns true. | |||
| 184 | void replaceUsesWithIf(Value newValue, | |||
| 185 | function_ref<bool(OpOperand &)> shouldReplace); | |||
| 186 | ||||
| 187 | /// Returns true if the value is used outside of the given block. | |||
| 188 | bool isUsedOutsideOfBlock(Block *block); | |||
| 189 | ||||
| 190 | //===--------------------------------------------------------------------===// | |||
| 191 | // Uses | |||
| 192 | ||||
| 193 | /// This class implements an iterator over the uses of a value. | |||
| 194 | using use_iterator = ValueUseIterator<OpOperand>; | |||
| 195 | using use_range = iterator_range<use_iterator>; | |||
| 196 | ||||
| 197 | use_iterator use_begin() const { return impl->use_begin(); } | |||
| 198 | use_iterator use_end() const { return use_iterator(); } | |||
| 199 | ||||
| 200 | /// Returns a range of all uses, which is useful for iterating over all uses. | |||
| 201 | use_range getUses() const { return {use_begin(), use_end()}; } | |||
| 202 | ||||
| 203 | /// Returns true if this value has exactly one use. | |||
| 204 | bool hasOneUse() const { return impl->hasOneUse(); } | |||
| 205 | ||||
| 206 | /// Returns true if this value has no uses. | |||
| 207 | bool use_empty() const { return impl->use_empty(); } | |||
| 208 | ||||
| 209 | //===--------------------------------------------------------------------===// | |||
| 210 | // Users | |||
| 211 | ||||
| 212 | using user_iterator = ValueUserIterator<use_iterator, OpOperand>; | |||
| 213 | using user_range = iterator_range<user_iterator>; | |||
| 214 | ||||
| 215 | user_iterator user_begin() const { return use_begin(); } | |||
| 216 | user_iterator user_end() const { return use_end(); } | |||
| 217 | user_range getUsers() const { return {user_begin(), user_end()}; } | |||
| 218 | ||||
| 219 | //===--------------------------------------------------------------------===// | |||
| 220 | // Utilities | |||
| 221 | ||||
| 222 | void print(raw_ostream &os); | |||
| 223 | void print(raw_ostream &os, const OpPrintingFlags &flags); | |||
| 224 | void print(raw_ostream &os, AsmState &state); | |||
| 225 | void dump(); | |||
| 226 | ||||
| 227 | /// Print this value as if it were an operand. | |||
| 228 | void printAsOperand(raw_ostream &os, AsmState &state); | |||
| 229 | void printAsOperand(raw_ostream &os, const OpPrintingFlags &flags); | |||
| 230 | ||||
| 231 | /// Methods for supporting PointerLikeTypeTraits. | |||
| 232 | void *getAsOpaquePointer() const { return impl; } | |||
| 233 | static Value getFromOpaquePointer(const void *pointer) { | |||
| 234 | return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer)); | |||
| 235 | } | |||
| 236 | detail::ValueImpl *getImpl() const { return impl; } | |||
| 237 | ||||
| 238 | friend ::llvm::hash_code hash_value(Value arg); | |||
| 239 | ||||
| 240 | protected: | |||
| 241 | /// A pointer to the internal implementation of the value. | |||
| 242 | detail::ValueImpl *impl; | |||
| 243 | }; | |||
| 244 | ||||
| 245 | inline raw_ostream &operator<<(raw_ostream &os, Value value) { | |||
| 246 | value.print(os); | |||
| 247 | return os; | |||
| 248 | } | |||
| 249 | ||||
| 250 | //===----------------------------------------------------------------------===// | |||
| 251 | // OpOperand | |||
| 252 | //===----------------------------------------------------------------------===// | |||
| 253 | ||||
| 254 | /// This class represents an operand of an operation. Instances of this class | |||
| 255 | /// contain a reference to a specific `Value`. | |||
| 256 | class OpOperand : public IROperand<OpOperand, Value> { | |||
| 257 | public: | |||
| 258 | /// Provide the use list that is attached to the given value. | |||
| 259 | static IRObjectWithUseList<OpOperand> *getUseList(Value value) { | |||
| 260 | return value.getImpl(); | |||
| 261 | } | |||
| 262 | ||||
| 263 | /// Return which operand this is in the OpOperand list of the Operation. | |||
| 264 | unsigned getOperandNumber(); | |||
| 265 | ||||
| 266 | private: | |||
| 267 | /// Keep the constructor private and accessible to the OperandStorage class | |||
| 268 | /// only to avoid hard-to-debug typo/programming mistakes. | |||
| 269 | friend class OperandStorage; | |||
| 270 | using IROperand<OpOperand, Value>::IROperand; | |||
| 271 | }; | |||
| 272 | ||||
| 273 | //===----------------------------------------------------------------------===// | |||
| 274 | // BlockArgument | |||
| 275 | //===----------------------------------------------------------------------===// | |||
| 276 | ||||
| 277 | namespace detail { | |||
| 278 | /// The internal implementation of a BlockArgument. | |||
| 279 | class BlockArgumentImpl : public ValueImpl { | |||
| 280 | public: | |||
| 281 | static bool classof(const ValueImpl *value) { | |||
| 282 | return value->getKind() == ValueImpl::Kind::BlockArgument; | |||
| 283 | } | |||
| 284 | ||||
| 285 | private: | |||
| 286 | BlockArgumentImpl(Type type, Block *owner, int64_t index, Location loc) | |||
| 287 | : ValueImpl(type, Kind::BlockArgument), owner(owner), index(index), | |||
| 288 | loc(loc) {} | |||
| 289 | ||||
| 290 | /// The owner of this argument. | |||
| 291 | Block *owner; | |||
| 292 | ||||
| 293 | /// The position in the argument list. | |||
| 294 | int64_t index; | |||
| 295 | ||||
| 296 | /// The source location of this argument. | |||
| 297 | Location loc; | |||
| 298 | ||||
| 299 | /// Allow access to owner and constructor. | |||
| 300 | friend BlockArgument; | |||
| 301 | }; | |||
| 302 | } // namespace detail | |||
| 303 | ||||
| 304 | /// This class represents an argument of a Block. | |||
| 305 | class BlockArgument : public Value { | |||
| 306 | public: | |||
| 307 | using Value::Value; | |||
| 308 | ||||
| 309 | static bool classof(Value value) { | |||
| 310 | return llvm::isa<detail::BlockArgumentImpl>(value.getImpl()); | |||
| 311 | } | |||
| 312 | ||||
| 313 | /// Returns the block that owns this argument. | |||
| 314 | Block *getOwner() const { return getImpl()->owner; } | |||
| 315 | ||||
| 316 | /// Returns the number of this argument. | |||
| 317 | unsigned getArgNumber() const { return getImpl()->index; } | |||
| 318 | ||||
| 319 | /// Return the location for this argument. | |||
| 320 | Location getLoc() const { return getImpl()->loc; } | |||
| 321 | void setLoc(Location loc) { getImpl()->loc = loc; } | |||
| 322 | ||||
| 323 | private: | |||
| 324 | /// Allocate a new argument with the given type and owner. | |||
| 325 | static BlockArgument create(Type type, Block *owner, int64_t index, | |||
| 326 | Location loc) { | |||
| 327 | return new detail::BlockArgumentImpl(type, owner, index, loc); | |||
| 328 | } | |||
| 329 | ||||
| 330 | /// Destroy and deallocate this argument. | |||
| 331 | void destroy() { delete getImpl(); } | |||
| 332 | ||||
| 333 | /// Get a raw pointer to the internal implementation. | |||
| 334 | detail::BlockArgumentImpl *getImpl() const { | |||
| 335 | return reinterpret_cast<detail::BlockArgumentImpl *>(impl); | |||
| 336 | } | |||
| 337 | ||||
| 338 | /// Cache the position in the block argument list. | |||
| 339 | void setArgNumber(int64_t index) { getImpl()->index = index; } | |||
| 340 | ||||
| 341 | /// Allow access to `create`, `destroy` and `setArgNumber`. | |||
| 342 | friend Block; | |||
| 343 | ||||
| 344 | /// Allow access to 'getImpl'. | |||
| 345 | friend Value; | |||
| 346 | }; | |||
| 347 | ||||
| 348 | //===----------------------------------------------------------------------===// | |||
| 349 | // OpResult | |||
| 350 | //===----------------------------------------------------------------------===// | |||
| 351 | ||||
| 352 | namespace detail { | |||
| 353 | /// This class provides the implementation for an operation result. | |||
| 354 | class alignas(8) OpResultImpl : public ValueImpl { | |||
| 355 | public: | |||
| 356 | using ValueImpl::ValueImpl; | |||
| 357 | ||||
| 358 | static bool classof(const ValueImpl *value) { | |||
| 359 | return value->getKind() != ValueImpl::Kind::BlockArgument; | |||
| 360 | } | |||
| 361 | ||||
| 362 | /// Returns the parent operation of this result. | |||
| 363 | Operation *getOwner() const; | |||
| 364 | ||||
| 365 | /// Returns the result number of this op result. | |||
| 366 | unsigned getResultNumber() const; | |||
| 367 | ||||
| 368 | /// Returns the next operation result at `offset` after this result. This | |||
| 369 | /// method is useful when indexing the result storage of an operation, given | |||
| 370 | /// that there is more than one kind of operation result (with the different | |||
| 371 | /// kinds having different sizes) and that operations are stored in reverse | |||
| 372 | /// order. | |||
| 373 | OpResultImpl *getNextResultAtOffset(intptr_t offset); | |||
| 374 | ||||
| 375 | /// Returns the maximum number of results that can be stored inline. | |||
| 376 | static unsigned getMaxInlineResults() { | |||
| 377 | return static_cast<unsigned>(Kind::OutOfLineOpResult); | |||
| 378 | } | |||
| 379 | }; | |||
| 380 | ||||
| 381 | /// This class provides the implementation for an operation result whose index | |||
| 382 | /// can be represented "inline" in the underlying ValueImpl. | |||
| 383 | struct InlineOpResult : public OpResultImpl { | |||
| 384 | public: | |||
| 385 | InlineOpResult(Type type, unsigned resultNo) | |||
| 386 | : OpResultImpl(type, static_cast<ValueImpl::Kind>(resultNo)) { | |||
| 387 | assert(resultNo < getMaxInlineResults())(static_cast <bool> (resultNo < getMaxInlineResults( )) ? void (0) : __assert_fail ("resultNo < getMaxInlineResults()" , "mlir/include/mlir/IR/Value.h", 387, __extension__ __PRETTY_FUNCTION__ )); | |||
| 388 | } | |||
| 389 | ||||
| 390 | /// Return the result number of this op result. | |||
| 391 | unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); } | |||
| 392 | ||||
| 393 | static bool classof(const OpResultImpl *value) { | |||
| 394 | return value->getKind() != ValueImpl::Kind::OutOfLineOpResult; | |||
| 395 | } | |||
| 396 | }; | |||
| 397 | ||||
| 398 | /// This class provides the implementation for an operation result whose index | |||
| 399 | /// cannot be represented "inline", and thus requires an additional index field. | |||
| 400 | class OutOfLineOpResult : public OpResultImpl { | |||
| 401 | public: | |||
| 402 | OutOfLineOpResult(Type type, uint64_t outOfLineIndex) | |||
| 403 | : OpResultImpl(type, Kind::OutOfLineOpResult), | |||
| 404 | outOfLineIndex(outOfLineIndex) {} | |||
| 405 | ||||
| 406 | static bool classof(const OpResultImpl *value) { | |||
| 407 | return value->getKind() == ValueImpl::Kind::OutOfLineOpResult; | |||
| 408 | } | |||
| 409 | ||||
| 410 | /// Return the result number of this op result. | |||
| 411 | unsigned getResultNumber() const { | |||
| 412 | return outOfLineIndex + getMaxInlineResults(); | |||
| 413 | } | |||
| 414 | ||||
| 415 | /// The trailing result number, or the offset from the beginning of the | |||
| 416 | /// `OutOfLineOpResult` array. | |||
| 417 | uint64_t outOfLineIndex; | |||
| 418 | }; | |||
| 419 | ||||
| 420 | /// Return the result number of this op result. | |||
| 421 | inline unsigned OpResultImpl::getResultNumber() const { | |||
| 422 | if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(this)) | |||
| 423 | return outOfLineResult->getResultNumber(); | |||
| 424 | return cast<InlineOpResult>(this)->getResultNumber(); | |||
| 425 | } | |||
| 426 | ||||
| 427 | /// TypedValue is a Value with a statically know type. | |||
| 428 | /// TypedValue can be null/empty | |||
| 429 | template <typename Ty> | |||
| 430 | struct TypedValue : Value { | |||
| 431 | using Value::Value; | |||
| 432 | ||||
| 433 | static bool classof(Value value) { return llvm::isa<Ty>(value.getType()); } | |||
| 434 | ||||
| 435 | /// Return the known Type | |||
| 436 | Ty getType() { return Value::getType().template cast<Ty>(); } | |||
| 437 | void setType(Ty ty) { Value::setType(ty); } | |||
| 438 | }; | |||
| 439 | ||||
| 440 | } // namespace detail | |||
| 441 | ||||
| 442 | /// This is a value defined by a result of an operation. | |||
| 443 | class OpResult : public Value { | |||
| 444 | public: | |||
| 445 | using Value::Value; | |||
| 446 | ||||
| 447 | static bool classof(Value value) { | |||
| 448 | return llvm::isa<detail::OpResultImpl>(value.getImpl()); | |||
| 449 | } | |||
| 450 | ||||
| 451 | /// Returns the operation that owns this result. | |||
| 452 | Operation *getOwner() const { return getImpl()->getOwner(); } | |||
| 453 | ||||
| 454 | /// Returns the number of this result. | |||
| 455 | unsigned getResultNumber() const { return getImpl()->getResultNumber(); } | |||
| 456 | ||||
| 457 | private: | |||
| 458 | /// Get a raw pointer to the internal implementation. | |||
| 459 | detail::OpResultImpl *getImpl() const { | |||
| 460 | return reinterpret_cast<detail::OpResultImpl *>(impl); | |||
| 461 | } | |||
| 462 | ||||
| 463 | /// Given a number of operation results, returns the number that need to be | |||
| 464 | /// stored inline. | |||
| 465 | static unsigned getNumInline(unsigned numResults); | |||
| 466 | ||||
| 467 | /// Given a number of operation results, returns the number that need to be | |||
| 468 | /// stored as trailing. | |||
| 469 | static unsigned getNumTrailing(unsigned numResults); | |||
| 470 | ||||
| 471 | /// Allow access to constructor. | |||
| 472 | friend Operation; | |||
| 473 | }; | |||
| 474 | ||||
| 475 | /// Make Value hashable. | |||
| 476 | inline ::llvm::hash_code hash_value(Value arg) { | |||
| 477 | return ::llvm::hash_value(arg.getImpl()); | |||
| 478 | } | |||
| 479 | ||||
| 480 | template <typename Ty, typename Value = mlir::Value> | |||
| 481 | /// If Ty is mlir::Type this will select `Value` instead of having a wrapper | |||
| 482 | /// around it. This helps resolve ambiguous conversion issues. | |||
| 483 | using TypedValue = std::conditional_t<std::is_same_v<Ty, mlir::Type>, | |||
| 484 | mlir::Value, detail::TypedValue<Ty>>; | |||
| 485 | ||||
| 486 | } // namespace mlir | |||
| 487 | ||||
| 488 | namespace llvm { | |||
| 489 | ||||
| 490 | template <> | |||
| 491 | struct DenseMapInfo<mlir::Value> { | |||
| 492 | static mlir::Value getEmptyKey() { | |||
| 493 | void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); | |||
| 494 | return mlir::Value::getFromOpaquePointer(pointer); | |||
| 495 | } | |||
| 496 | static mlir::Value getTombstoneKey() { | |||
| 497 | void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); | |||
| 498 | return mlir::Value::getFromOpaquePointer(pointer); | |||
| 499 | } | |||
| 500 | static unsigned getHashValue(mlir::Value val) { | |||
| 501 | return mlir::hash_value(val); | |||
| 502 | } | |||
| 503 | static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; } | |||
| 504 | }; | |||
| 505 | template <> | |||
| 506 | struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> { | |||
| 507 | static mlir::BlockArgument getEmptyKey() { | |||
| 508 | void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); | |||
| 509 | return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer); | |||
| 510 | } | |||
| 511 | static mlir::BlockArgument getTombstoneKey() { | |||
| 512 | void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); | |||
| 513 | return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer); | |||
| 514 | } | |||
| 515 | }; | |||
| 516 | template <> | |||
| 517 | struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> { | |||
| 518 | static mlir::OpResult getEmptyKey() { | |||
| 519 | void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); | |||
| 520 | return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer); | |||
| 521 | } | |||
| 522 | static mlir::OpResult getTombstoneKey() { | |||
| 523 | void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); | |||
| 524 | return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer); | |||
| 525 | } | |||
| 526 | }; | |||
| 527 | ||||
| 528 | /// Allow stealing the low bits of a value. | |||
| 529 | template <> | |||
| 530 | struct PointerLikeTypeTraits<mlir::Value> { | |||
| 531 | public: | |||
| 532 | static inline void *getAsVoidPointer(mlir::Value value) { | |||
| 533 | return const_cast<void *>(value.getAsOpaquePointer()); | |||
| 534 | } | |||
| 535 | static inline mlir::Value getFromVoidPointer(void *pointer) { | |||
| 536 | return mlir::Value::getFromOpaquePointer(pointer); | |||
| 537 | } | |||
| 538 | enum { | |||
| 539 | NumLowBitsAvailable = | |||
| 540 | PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable | |||
| 541 | }; | |||
| 542 | }; | |||
| 543 | template <> | |||
| 544 | struct PointerLikeTypeTraits<mlir::BlockArgument> | |||
| 545 | : public PointerLikeTypeTraits<mlir::Value> { | |||
| 546 | public: | |||
| 547 | static inline mlir::BlockArgument getFromVoidPointer(void *pointer) { | |||
| 548 | return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer); | |||
| 549 | } | |||
| 550 | }; | |||
| 551 | template <> | |||
| 552 | struct PointerLikeTypeTraits<mlir::OpResult> | |||
| 553 | : public PointerLikeTypeTraits<mlir::Value> { | |||
| 554 | public: | |||
| 555 | static inline mlir::OpResult getFromVoidPointer(void *pointer) { | |||
| 556 | return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer); | |||
| 557 | } | |||
| 558 | }; | |||
| 559 | ||||
| 560 | /// Add support for llvm style casts. We provide a cast between To and From if | |||
| 561 | /// From is mlir::Value or derives from it. | |||
| 562 | template <typename To, typename From> | |||
| 563 | struct CastInfo< | |||
| 564 | To, From, | |||
| 565 | std::enable_if_t<std::is_same_v<mlir::Value, std::remove_const_t<From>> || | |||
| 566 | std::is_base_of_v<mlir::Value, From>>> | |||
| 567 | : NullableValueCastFailed<To>, | |||
| 568 | DefaultDoCastIfPossible<To, From, CastInfo<To, From>> { | |||
| 569 | /// Arguments are taken as mlir::Value here and not as `From`, because | |||
| 570 | /// when casting from an intermediate type of the hierarchy to one of its | |||
| 571 | /// children, the val.getKind() inside T::classof will use the static | |||
| 572 | /// getKind() of the parent instead of the non-static ValueImpl::getKind() | |||
| 573 | /// that returns the dynamic type. This means that T::classof would end up | |||
| 574 | /// comparing the static Kind of the children to the static Kind of its | |||
| 575 | /// parent, making it impossible to downcast from the parent to the child. | |||
| 576 | static inline bool isPossible(mlir::Value ty) { | |||
| 577 | /// Return a constant true instead of a dynamic true when casting to self or | |||
| 578 | /// up the hierarchy. | |||
| 579 | if constexpr (std::is_base_of_v<To, From>) { | |||
| 580 | (void)ty; | |||
| 581 | return true; | |||
| 582 | } else { | |||
| 583 | return To::classof(ty); | |||
| 584 | } | |||
| 585 | } | |||
| 586 | static inline To doCast(mlir::Value value) { return To(value.getImpl()); } | |||
| 587 | }; | |||
| 588 | ||||
| 589 | } // namespace llvm | |||
| 590 | ||||
| 591 | #endif |