| #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 operands from all predecessor regions that match `operandNumber` |
| /// for the `successor` region within `regionOp`. |
| static SmallVector<Value> |
| getRegionPredecessorOperands(RegionBranchOpInterface regionOp, |
| RegionSuccessor successor, |
| unsigned operandNumber) { |
| SmallVector<Value> predecessorOperands; |
| |
| // Returns true if `successors` contains `successor`. |
| auto isContained = [](ArrayRef<RegionSuccessor> successors, |
| RegionSuccessor successor) { |
| auto *it = llvm::find_if(successors, [&successor](RegionSuccessor curr) { |
| return curr.getSuccessor() == successor.getSuccessor(); |
| }); |
| return it != successors.end(); |
| }; |
| |
| // Search the operand ranges on the region operation itself. |
| SmallVector<Attribute> operandAttributes(regionOp->getNumOperands()); |
| SmallVector<RegionSuccessor> successors; |
| regionOp.getEntrySuccessorRegions(operandAttributes, successors); |
| if (isContained(successors, successor)) { |
| OperandRange operands = regionOp.getEntrySuccessorOperands(successor); |
| predecessorOperands.push_back(operands[operandNumber]); |
| } |
| |
| // Search the operand ranges on region terminators. |
| for (Region ®ion : regionOp->getRegions()) { |
| for (Block &block : region) { |
| auto terminatorOp = |
| dyn_cast<RegionBranchTerminatorOpInterface>(block.getTerminator()); |
| if (!terminatorOp) |
| continue; |
| SmallVector<Attribute> operandAttributes(terminatorOp->getNumOperands()); |
| SmallVector<RegionSuccessor> successors; |
| terminatorOp.getSuccessorRegions(operandAttributes, successors); |
| if (isContained(successors, successor)) { |
| OperandRange operands = terminatorOp.getSuccessorOperands(successor); |
| predecessorOperands.push_back(operands[operandNumber]); |
| } |
| } |
| } |
| |
| return predecessorOperands; |
| } |
| |
| /// 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(regionOp->getResults()); |
| SmallVector<Value> predecessorOperands = getRegionPredecessorOperands( |
| regionOp, region, opResult.getResultNumber()); |
| 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 region(blockArg.getParentRegion()); |
| SmallVector<Value> predecessorOperands = getRegionPredecessorOperands( |
| regionBranchOp, region, blockArg.getArgNumber()); |
| 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); |
| } |