-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[MLIR] Change getBackwardSlice to return a logicalresult rather than crash #140961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,41 +80,43 @@ void mlir::getForwardSlice(Value root, SetVector<Operation *> *forwardSlice, | |
forwardSlice->insert(v.rbegin(), v.rend()); | ||
} | ||
|
||
static void getBackwardSliceImpl(Operation *op, | ||
SetVector<Operation *> *backwardSlice, | ||
const BackwardSliceOptions &options) { | ||
static LogicalResult getBackwardSliceImpl(Operation *op, | ||
SetVector<Operation *> *backwardSlice, | ||
const BackwardSliceOptions &options) { | ||
if (!op || op->hasTrait<OpTrait::IsIsolatedFromAbove>()) | ||
return; | ||
return success(); | ||
|
||
// Evaluate whether we should keep this def. | ||
// This is useful in particular to implement scoping; i.e. return the | ||
// transitive backwardSlice in the current scope. | ||
if (options.filter && !options.filter(op)) | ||
return; | ||
return success(); | ||
|
||
auto processValue = [&](Value value) { | ||
if (auto *definingOp = value.getDefiningOp()) { | ||
if (backwardSlice->count(definingOp) == 0) | ||
getBackwardSliceImpl(definingOp, backwardSlice, options); | ||
return getBackwardSliceImpl(definingOp, backwardSlice, options); | ||
} else if (auto blockArg = dyn_cast<BlockArgument>(value)) { | ||
if (options.omitBlockArguments) | ||
return; | ||
return success(); | ||
|
||
Block *block = blockArg.getOwner(); | ||
Operation *parentOp = block->getParentOp(); | ||
// TODO: determine whether we want to recurse backward into the other | ||
// blocks of parentOp, which are not technically backward unless they flow | ||
// into us. For now, just bail. | ||
if (parentOp && backwardSlice->count(parentOp) == 0) { | ||
assert(parentOp->getNumRegions() == 1 && | ||
llvm::hasSingleElement(parentOp->getRegion(0).getBlocks())); | ||
getBackwardSliceImpl(parentOp, backwardSlice, options); | ||
if (parentOp->getNumRegions() == 1 && | ||
llvm::hasSingleElement(parentOp->getRegion(0).getBlocks())) { | ||
return getBackwardSliceImpl(parentOp, backwardSlice, options); | ||
} | ||
} | ||
} else { | ||
llvm_unreachable("No definingOp and not a block argument."); | ||
} | ||
return failure(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @IanWood1 shared a fix with me, and I think it may be reasonable. The original check could be false, and it is not a failure. Should it return if (parentOp && backwardSlice->count(parentOp) == 0) {
assert(parentOp->getNumRegions() == 1 &&
llvm::hasSingleElement(parentOp->getRegion(0).getBlocks()));
getBackwardSliceImpl(parentOp, backwardSlice, options);
} EDIT: To be more specific, should we return |
||
}; | ||
|
||
bool succeeded = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is always true? |
||
|
||
if (!options.omitUsesFromAbove) { | ||
llvm::for_each(op->getRegions(), [&](Region ®ion) { | ||
// Walk this region recursively to collect the regions that descend from | ||
|
@@ -125,36 +127,41 @@ static void getBackwardSliceImpl(Operation *op, | |
region.walk([&](Operation *op) { | ||
for (OpOperand &operand : op->getOpOperands()) { | ||
if (!descendents.contains(operand.get().getParentRegion())) | ||
processValue(operand.get()); | ||
if (!processValue(operand.get()).succeeded()) { | ||
return WalkResult::interrupt(); | ||
} | ||
} | ||
return WalkResult::advance(); | ||
Comment on lines
+130
to
+134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This breaks some integration tests in a downstream project, and I think you should not interrupt when there is a failure. The below patch fixes our issue. I don't have a clean repro now, but I'd like to share this information first. --- a/mlir/lib/Analysis/SliceAnalysis.cpp
+++ b/mlir/lib/Analysis/SliceAnalysis.cpp
@@ -127,11 +127,8 @@ static LogicalResult getBackwardSliceImpl(Operation *op,
region.walk([&](Operation *op) {
for (OpOperand &operand : op->getOpOperands()) {
if (!descendents.contains(operand.get().getParentRegion()))
- if (!processValue(operand.get()).succeeded()) {
- return WalkResult::interrupt();
- }
+ (void)processValue(operand.get());
}
- return WalkResult::advance();
});
});
} I don't fully follow what the PR is doing, and I'll follow up when I have cycles. |
||
}); | ||
}); | ||
} | ||
llvm::for_each(op->getOperands(), processValue); | ||
|
||
backwardSlice->insert(op); | ||
return success(succeeded); | ||
} | ||
|
||
void mlir::getBackwardSlice(Operation *op, | ||
SetVector<Operation *> *backwardSlice, | ||
const BackwardSliceOptions &options) { | ||
getBackwardSliceImpl(op, backwardSlice, options); | ||
LogicalResult mlir::getBackwardSlice(Operation *op, | ||
SetVector<Operation *> *backwardSlice, | ||
const BackwardSliceOptions &options) { | ||
LogicalResult result = getBackwardSliceImpl(op, backwardSlice, options); | ||
|
||
if (!options.inclusive) { | ||
// Don't insert the top level operation, we just queried on it and don't | ||
// want it in the results. | ||
backwardSlice->remove(op); | ||
} | ||
return result; | ||
} | ||
|
||
void mlir::getBackwardSlice(Value root, SetVector<Operation *> *backwardSlice, | ||
const BackwardSliceOptions &options) { | ||
LogicalResult mlir::getBackwardSlice(Value root, | ||
SetVector<Operation *> *backwardSlice, | ||
const BackwardSliceOptions &options) { | ||
if (Operation *definingOp = root.getDefiningOp()) { | ||
getBackwardSlice(definingOp, backwardSlice, options); | ||
return; | ||
return getBackwardSlice(definingOp, backwardSlice, options); | ||
} | ||
Operation *bbAargOwner = cast<BlockArgument>(root).getOwner()->getParentOp(); | ||
getBackwardSlice(bbAargOwner, backwardSlice, options); | ||
return getBackwardSlice(bbAargOwner, backwardSlice, options); | ||
} | ||
|
||
SetVector<Operation *> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We may want to return |
||
|
@@ -170,7 +177,9 @@ mlir::getSlice(Operation *op, const BackwardSliceOptions &backwardSliceOptions, | |
auto *currentOp = (slice)[currentIndex]; | ||
// Compute and insert the backwardSlice starting from currentOp. | ||
backwardSlice.clear(); | ||
getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions); | ||
LogicalResult result = | ||
getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions); | ||
assert(result.succeeded()); | ||
slice.insert_range(backwardSlice); | ||
|
||
// Compute and insert the forwardSlice starting from currentOp. | ||
|
@@ -193,7 +202,8 @@ static bool dependsOnCarriedVals(Value value, | |
sliceOptions.filter = [&](Operation *op) { | ||
return !ancestorOp->isAncestor(op); | ||
}; | ||
getBackwardSlice(value, &slice, sliceOptions); | ||
LogicalResult result = getBackwardSlice(value, &slice, sliceOptions); | ||
assert(result.succeeded()); | ||
|
||
// Check that none of the operands of the operations in the backward slice are | ||
// loop iteration arguments, and neither is the value itself. | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That isn't a helpful comment IMO: just seeing the LogicalResult I understand that "this can fail".
What I'd expect is describe the failure condition here. What is a prerequisite of the API (which you documented in the PR description now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah sorry for delay, fell of my stack. addressed here: #142223