[Mlir-commits] [mlir] [MLIR][Operation] Fix `isBeforeInBlock` crash bug mentioned in https://github.com/llvm/llvm-project/issues/60909 (PR #101172)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Aug 2 00:07:31 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-core
@llvm/pr-subscribers-mlir
Author: wang-y-z (wang-y-z)
<details>
<summary>Changes</summary>
# summary
This MR fix `isBeforeInBlock` crash bug mentioned in https://github.com/llvm/llvm-project/issues/60909
# Trigger condition
1. A block only have one operation.
2. `block->isOpOrderValid()` is true.
3. call: `op->isBeforeInBlock(op)`, compared with op itself.
Will crash on `assert(blockFront != blockBack && "expected more than one operation");`
# Case study
Simplified repro case in `mlir/test/Pass/scf2cf-print-liveness-crash.mlir`
When put `-convert-scf-to-cf -test-print-liveness` together in one cmd line, the first pass will work normally and crash on the second pass.
Details please refer https://github.com/llvm/llvm-project/issues/60909
# Solutions
option1. in `isBeforeInBlock`, check if block only have one operation before step into `updateOrderIfNecessary`, if have only one, it must return false
option2. in `isBeforeInBlock`, check if `this == other`, if true return false
both OK for me.
# Other
> Why the `block->isOpOrderValid()` will be true? Why not find the root cause of this phenomenon?
I think `isBeforeInBlock` as a fundamental API in operation.cpp should should not make too many assumptions about the state of `block->isOpOrderValid()`
Let's think about this in IR:
```
op1 {
^bb0:
op2
}
```
When `block->isOpOrderValid() is true`, op2->isBeforeInBlock(op2) will crash on `updateOrderIfNecessary`
When `block->isOpOrderValid() is false`, `op2->isBeforeInBlock(op2)` will step into `recomputeOpOrder` and make `parentValidOpOrderPair.setInt(true);` , if user call `op2->isBeforeInBlock(op2)` again, it will crash on `updateOrderIfNecessary` too
So, I think fix on `isBeforeInBlock` is closer to the essence of the issue.
---
Full diff: https://github.com/llvm/llvm-project/pull/101172.diff
2 Files Affected:
- (modified) mlir/lib/IR/Operation.cpp (+6-1)
- (added) mlir/test/Pass/scf2cf-print-liveness-crash.mlir (+19)
``````````diff
diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp
index b51357198b1ca..235d6ac9873ab 100644
--- a/mlir/lib/IR/Operation.cpp
+++ b/mlir/lib/IR/Operation.cpp
@@ -391,6 +391,7 @@ bool Operation::isBeforeInBlock(Operation *other) {
// parent.
if (!block->isOpOrderValid()) {
block->recomputeOpOrder();
+ // } else if (!llvm::hasSingleElement(*block)) {
} else {
// Update the order either operation if necessary.
updateOrderIfNecessary();
@@ -502,10 +503,14 @@ Block *llvm::ilist_traits<::mlir::Operation>::getContainingBlock() {
/// keep the block pointer up to date.
void llvm::ilist_traits<::mlir::Operation>::addNodeToList(Operation *op) {
assert(!op->getBlock() && "already in an operation block!");
- op->block = getContainingBlock();
+
+ Block *curParent = getContainingBlock();
+ op->block = curParent;
// Invalidate the order on the operation.
op->orderIndex = Operation::kInvalidOrderIdx;
+ // Invalidate the ordering of the parent block.
+ curParent->invalidateOpOrder();
}
/// This is a trait method invoked when an operation is removed from a block.
diff --git a/mlir/test/Pass/scf2cf-print-liveness-crash.mlir b/mlir/test/Pass/scf2cf-print-liveness-crash.mlir
new file mode 100644
index 0000000000000..665e085cfedee
--- /dev/null
+++ b/mlir/test/Pass/scf2cf-print-liveness-crash.mlir
@@ -0,0 +1,19 @@
+// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(convert-scf-to-cf), func.func(test-print-liveness))"
+
+module {
+ func.func @for_if_for(%arg0: index, %arg1: index, %arg2: index, %arg3: i1) {
+ %cst = arith.constant dense<0.000000e+00> : tensor<128x32xf16>
+ %0 = scf.for %arg4 = %arg0 to %arg1 step %arg2 iter_args(%arg5 = %cst) -> (tensor<128x32xf16>) {
+ %1 = scf.if %arg3 -> (tensor<128x32xf16>) {
+ scf.yield %arg5 : tensor<128x32xf16>
+ } else {
+ %2 = scf.for %arg6 = %arg0 to %arg1 step %arg2 iter_args(%arg7 = %arg5) -> (tensor<128x32xf16>) {
+ scf.yield %arg7 : tensor<128x32xf16>
+ }
+ scf.yield %2 : tensor<128x32xf16>
+ }
+ scf.yield %1 : tensor<128x32xf16>
+ }
+ return
+ }
+}
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/101172
More information about the Mlir-commits
mailing list