[Mlir-commits] [mlir] [MLIR, LLVM]: Add an IR utility to perform slice walking (PR #103053)
Tobias Gysi
llvmlistbot at llvm.org
Wed Aug 14 05:32:38 PDT 2024
================
@@ -0,0 +1,140 @@
+#include "mlir/IR/SliceSupport.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`. Returns a
+/// nullopt when 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) {
+ SmallVector<Value> result;
+ if (OpResult opResult = dyn_cast<OpResult>(value)) {
+ auto regionOp = dyn_cast<RegionBranchOpInterface>(opResult.getOwner());
+ // 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;
+ }
+ // Unclear how to deal with this operation, conservatively return a
+ // failure.
----------------
gysit wrote:
```suggestion
// If the interface is not implemented, there are no known control flow predecessors.
```
nit: I prefer a comment similar to the one above.
https://github.com/llvm/llvm-project/pull/103053
More information about the Mlir-commits
mailing list