blob: c7756bfac91c6d288941c5abfa526fe8b37d22e4 [file] [edit]
#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);
}