| #include "mlir/Analysis/SliceWalk.h" |
| #include "mlir/Interfaces/ControlFlowInterfaces.h" |
| |
| using namespace mlir; |
| |
| WalkContinuation mlir::walkSlice(ValueRange rootValues, |
| WalkCallback walkCallback) { |
| // Search the backward slice starting from the root values. |
| SmallVector<Value> workList = rootValues; |
| llvm::SmallDenseSet<Value, 16> seenValues; |
| while (!workList.empty()) { |
| // Search the backward slice of the current value. |
| Value current = workList.pop_back_val(); |
| |
| // Skip the current value if it has already been seen. |
| if (!seenValues.insert(current).second) |
| continue; |
| |
| // Call the walk callback with the current value. |
| WalkContinuation continuation = walkCallback(current); |
| if (continuation.wasInterrupted()) |
| return continuation; |
| if (continuation.wasSkipped()) |
| continue; |
| |
| assert(continuation.wasAdvancedTo()); |
| // Add the next values to the work list if the walk should continue. |
| workList.append(continuation.getNextValues().begin(), |
| continuation.getNextValues().end()); |
| } |
| |
| return WalkContinuation::skip(); |
| } |
| |
| /// Returns the predecessor branch operands that match `blockArg`, or nullopt if |
| /// some of the predecessor terminators do not implement the BranchOpInterface. |
| static std::optional<SmallVector<Value>> |
| getBlockPredecessorOperands(BlockArgument blockArg) { |
| Block *block = blockArg.getOwner(); |
| |
| // Search the predecessor operands for all predecessor terminators. |
| SmallVector<Value> predecessorOperands; |
| for (auto it = block->pred_begin(); it != block->pred_end(); ++it) { |
| Block *predecessor = *it; |
| auto branchOp = dyn_cast<BranchOpInterface>(predecessor->getTerminator()); |
| if (!branchOp) |
| return std::nullopt; |
| SuccessorOperands successorOperands = |
| branchOp.getSuccessorOperands(it.getSuccessorIndex()); |
| // Store the predecessor operand if the block argument matches an operand |
| // and is not produced by the terminator. |
| if (Value operand = successorOperands[blockArg.getArgNumber()]) |
| predecessorOperands.push_back(operand); |
| } |
| |
| return predecessorOperands; |
| } |
| |
| std::optional<SmallVector<Value>> |
| mlir::getControlFlowPredecessors(Value value) { |
| if (OpResult opResult = dyn_cast<OpResult>(value)) { |
| if (auto selectOp = opResult.getDefiningOp<SelectLikeOpInterface>()) |
| return SmallVector<Value>( |
| {selectOp.getTrueValue(), selectOp.getFalseValue()}); |
| auto regionOp = opResult.getDefiningOp<RegionBranchOpInterface>(); |
| // If the interface is not implemented, there are no control flow |
| // predecessors to work with. |
| if (!regionOp) |
| return std::nullopt; |
| // Add the control flow predecessor operands to the work list. |
| RegionSuccessor region = RegionSuccessor(regionOp.getOperation()); |
| // Find the position of `opResult` in the successor inputs of the parent. |
| // `getPredecessorValues` indexes into the successor inputs, not into the |
| // op results directly, since some results may not be successor inputs. |
| ValueRange successorInputs = regionOp.getSuccessorInputs(region); |
| auto it = llvm::find(successorInputs, opResult); |
| if (it == successorInputs.end()) |
| return std::nullopt; |
| SmallVector<Value> predecessorOperands; |
| regionOp.getPredecessorValues(region, |
| std::distance(successorInputs.begin(), it), |
| predecessorOperands); |
| return predecessorOperands; |
| } |
| |
| auto blockArg = cast<BlockArgument>(value); |
| Block *block = blockArg.getOwner(); |
| // Search the region predecessor operands for structured control flow. |
| if (block->isEntryBlock()) { |
| if (auto regionBranchOp = |
| dyn_cast<RegionBranchOpInterface>(block->getParentOp())) { |
| RegionSuccessor regionSuccessor(blockArg.getParentRegion()); |
| // Find the position of `blockArg` in the successor inputs of the region. |
| // `getPredecessorValues` indexes into the successor inputs, not into the |
| // block arguments directly, since some block arguments may not be |
| // successor inputs (e.g., block arguments produced by the terminator). |
| ValueRange successorInputs = |
| regionBranchOp.getSuccessorInputs(regionSuccessor); |
| auto it = llvm::find(successorInputs, blockArg); |
| if (it == successorInputs.end()) |
| return std::nullopt; |
| SmallVector<Value> predecessorOperands; |
| regionBranchOp.getPredecessorValues( |
| regionSuccessor, std::distance(successorInputs.begin(), it), |
| predecessorOperands); |
| return predecessorOperands; |
| } |
| // If the interface is not implemented, there are no control flow |
| // predecessors to work with. |
| return std::nullopt; |
| } |
| |
| // Search the block predecessor operands for unstructured control flow. |
| return getBlockPredecessorOperands(blockArg); |
| } |