#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 workList = rootValues; llvm::SmallDenseSet 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 getRegionPredecessorOperands(RegionBranchOpInterface regionOp, RegionSuccessor successor, unsigned operandNumber) { SmallVector predecessorOperands; // Returns true if `successors` contains `successor`. auto isContained = [](ArrayRef 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 operandAttributes(regionOp->getNumOperands()); SmallVector 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(block.getTerminator()); if (!terminatorOp) continue; SmallVector operandAttributes(terminatorOp->getNumOperands()); SmallVector 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> getBlockPredecessorOperands(BlockArgument blockArg) { Block *block = blockArg.getOwner(); // Search the predecessor operands for all predecessor terminators. SmallVector predecessorOperands; for (auto it = block->pred_begin(); it != block->pred_end(); ++it) { Block *predecessor = *it; auto branchOp = dyn_cast(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> mlir::getControlFlowPredecessors(Value value) { if (OpResult opResult = dyn_cast(value)) { if (auto selectOp = opResult.getDefiningOp()) return SmallVector( {selectOp.getTrueValue(), selectOp.getFalseValue()}); auto regionOp = opResult.getDefiningOp(); // 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 predecessorOperands = getRegionPredecessorOperands( regionOp, region, opResult.getResultNumber()); return predecessorOperands; } auto blockArg = cast(value); Block *block = blockArg.getOwner(); // Search the region predecessor operands for structured control flow. if (block->isEntryBlock()) { if (auto regionBranchOp = dyn_cast(block->getParentOp())) { RegionSuccessor region(blockArg.getParentRegion()); SmallVector 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); }