[Mlir-commits] [mlir] 7beba38 - [MLIR] Fix crash in ValueBoundsConstraintSet for non-entry block args (#185048)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Mar 11 06:21:26 PDT 2026
Author: Mehdi Amini
Date: 2026-03-11T14:21:22+01:00
New Revision: 7beba38aa3fda07fec3f3df7f84fcfbd0a46ffc4
URL: https://github.com/llvm/llvm-project/commit/7beba38aa3fda07fec3f3df7f84fcfbd0a46ffc4
DIFF: https://github.com/llvm/llvm-project/commit/7beba38aa3fda07fec3f3df7f84fcfbd0a46ffc4.diff
LOG: [MLIR] Fix crash in ValueBoundsConstraintSet for non-entry block args (#185048)
When two vector transfer ops share a non-entry block argument as an
index (e.g., in a loop with unstructured control flow), calling
`ValueBoundsConstraintSet::areEqual` on those values caused a crash.
The first `populateConstraints` call would insert the block argument
into the constraint set. The second call found it already mapped and
called `getPos`, which hit an assert requiring the value to be either an
OpResult or an entry-block argument.
Fix with two changes:
1. In `insert()`, suppress adding non-entry block arguments to the
worklist. `ValueBoundsOpInterface` cannot derive bounds for such values,
so the worklist push was a no-op and triggered the re-entrant `getPos`
call.
2. Remove the overly conservative assert in `getPos`. Looking up a
previously inserted non-entry block argument is valid; the assert was
preventing legitimate use after the value had already been inserted.
Fixes #119861
Assisted-by: Claude Code
Added:
mlir/test/Dialect/ControlFlow/value-bounds-op-interface-impl.mlir
Modified:
mlir/lib/Interfaces/ValueBoundsOpInterface.cpp
Removed:
################################################################################
diff --git a/mlir/lib/Interfaces/ValueBoundsOpInterface.cpp b/mlir/lib/Interfaces/ValueBoundsOpInterface.cpp
index 85a156efd9474..35e3e92b91176 100644
--- a/mlir/lib/Interfaces/ValueBoundsOpInterface.cpp
+++ b/mlir/lib/Interfaces/ValueBoundsOpInterface.cpp
@@ -282,7 +282,16 @@ int64_t ValueBoundsConstraintSet::insert(Value value,
if (positionToValueDim[i].has_value())
valueDimToPosition[*positionToValueDim[i]] = i;
- if (addToWorklist) {
+ // Do not add block arguments from non-entry blocks to the worklist. The
+ // ValueBoundsOpInterface cannot derive any bounds for such values (they
+ // arise from unstructured control flow), so putting them on the worklist
+ // would be a no-op. More importantly, suppressing the worklist push ensures
+ // that processWorklist never calls getExpr on such a value a second time,
+ // which would otherwise cause the same value to be looked up as already
+ // mapped (triggering an unintended bug path).
+ if (addToWorklist &&
+ (!isa<BlockArgument>(value) ||
+ cast<BlockArgument>(value).getOwner()->isEntryBlock())) {
LDBG() << "Push to worklist: " << value
<< " (dim: " << dim.value_or(kIndexValue) << ")";
worklist.push(pos);
@@ -334,9 +343,6 @@ int64_t ValueBoundsConstraintSet::getPos(Value value,
std::optional<int64_t> dim) const {
#ifndef NDEBUG
assertValidValueDim(value, dim);
- assert((isa<OpResult>(value) ||
- cast<BlockArgument>(value).getOwner()->isEntryBlock()) &&
- "unstructured control flow is not supported");
#endif // NDEBUG
LDBG() << "Getting pos for: " << value
<< " (dim: " << dim.value_or(kIndexValue)
diff --git a/mlir/test/Dialect/ControlFlow/value-bounds-op-interface-impl.mlir b/mlir/test/Dialect/ControlFlow/value-bounds-op-interface-impl.mlir
new file mode 100644
index 0000000000000..e391967c7f91f
--- /dev/null
+++ b/mlir/test/Dialect/ControlFlow/value-bounds-op-interface-impl.mlir
@@ -0,0 +1,26 @@
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(test-affine-reify-value-bounds))' \
+// RUN: -verify-diagnostics -split-input-file
+
+// Note: unstructured control flow (cf dialect) is not yet supported by the
+// ValueBoundsOpInterface. Block arguments from non-entry blocks cannot have
+// their bounds computed. The tests below verify that the infrastructure does
+// not crash on such inputs and fails gracefully instead.
+// See: https://github.com/llvm/llvm-project/issues/119861
+
+// Regression test: ValueBoundsConstraintSet must not crash when asked to
+// reify a bound for a non-entry block argument produced by unstructured
+// control flow.
+
+func.func @no_crash_non_entry_block_arg(%n: index) -> index {
+ %c0 = arith.constant 0 : index
+ cf.br ^bb1(%c0 : index)
+^bb1(%i: index):
+ // expected-error at +1 {{'test.reify_bound' op could not reify bound}}
+ %bound = "test.reify_bound"(%i) {type = "UB"} : (index) -> index
+ "test.some_use"(%bound) : (index) -> ()
+ %cond = arith.cmpi slt, %i, %n : index
+ %next = arith.addi %i, %c0 : index
+ cf.cond_br %cond, ^bb1(%next : index), ^bb2
+^bb2:
+ return %i : index
+}
More information about the Mlir-commits
mailing list