[Mlir-commits] [llvm] [mlir] Fix remove dead values poison crash (PR #205966)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Jun 25 20:40:27 PDT 2026
https://github.com/LouisLu060211 created https://github.com/llvm/llvm-project/pull/205966
Add a single-value poison creation helper for RemoveDeadValues, while keeping
the existing ValueRange helper for multi-result cleanup.
RemoveDeadValues used `createPoisonedValues` for both ranges of values and a
single operand value. The single-operand call site passed
`o.op->getOperand(deadIdx)` to a helper taking `ValueRange`, which could create
an invalid temporary range. The pass then crashed when the range was iterated
and `value.use_empty()` was called on the invalid value.
By spliting the poison creation logic into `createPoisonedValue` for one `Value` and
keep `createPoisonedValues` as the range wrapper, this result the single-operand cleanup
path now calls the single-value helper directly instead of constructing a
`ValueRange` from one operand.
Add a regression test to `remove-dead-values.mlir` covering the crash case with
a private function returning a `memref` through `scf.if`, including a
`bufferization.clone` branch.
Assisted-by: Codex
>From d0025a31adc57d20b85540ae85a963c9fc49ffa2 Mon Sep 17 00:00:00 2001
From: LouisLu0602 <yaolu0602 at gmail.com>
Date: Wed, 24 Jun 2026 15:09:36 +0800
Subject: [PATCH 1/4] Fix crash in vectorizeOpPrecondition when vector sizes
array is too short
[MLIR][Vector] Add regression test for bug #204100 (mixed static/dynamic vector sizes)
Remove accidentally created file vectorize-dynamic-mixed-sizes.mlir
Remove mlir_venv/ from .gitignore (directory already deleted)
Fix comment about regression test location in Vectorization.cpp
Correct the path in the comment from .../Linalg/transform/... to .../Linalg/...
(the test actually lives directly under Linalg). Also update the
related vector-to-llvm test for consistency.
remove venv
Remove lldb/python_api from .gitignore
Fix emitSilenceableFailure to use target->getLoc()
---
.gitignore | 2 +
.gitignorees | 92 +++++++++++++++++++
a.mlir | 13 +++
.../TransformOps/LinalgTransformOps.cpp | 1 -
.../Linalg/Transforms/Vectorization.cpp | 12 +++
.../Vector/transform-op-vector-to-llvm.mlir | 26 ++++++
.../Vector/transform-op-vector-to-llvm.mlires | 43 +++++++++
7 files changed, 188 insertions(+), 1 deletion(-)
create mode 100644 .gitignorees
create mode 100644 a.mlir
create mode 100644 mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlires
diff --git a/.gitignore b/.gitignore
index a4382c9ea7390..ac57b104aa4e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,3 +90,5 @@ pythonenv*
/clang/utils/analyzer/projects/*/RefScanBuildResults
# automodapi puts generated documentation files here.
/lldb/docs/python_api/
+<<<<<<< HEAD
+<<<<<<< HEAD
diff --git a/.gitignorees b/.gitignorees
new file mode 100644
index 0000000000000..a4382c9ea7390
--- /dev/null
+++ b/.gitignorees
@@ -0,0 +1,92 @@
+#==============================================================================#
+# This file specifies intentionally untracked files that git should ignore.
+# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
+#
+# This file is intentionally different from the output of `git svn show-ignore`,
+# as most of those are useless.
+#==============================================================================#
+
+#==============================================================================#
+# File extensions to be ignored anywhere in the tree.
+#==============================================================================#
+# Temp files created by most text editors.
+*~
+# Emacs lock files
+.#*
+# Merge files created by git.
+*.orig
+# Reject files created by patch.
+*.rej
+# Byte compiled python modules.
+*.pyc
+# vim swap files
+.*.sw?
+.sw?
+#macOS specific
+.DS_Store
+
+# Ignore the user specified CMake presets in subproject directories.
+/*/CMakeUserPresets.json
+
+# Nested build directory
+/build*
+
+#==============================================================================#
+# Explicit files to ignore (only matches one).
+#==============================================================================#
+# Various tag programs
+/tags
+/TAGS
+/GPATH
+/GRTAGS
+/GSYMS
+/GTAGS
+/ID
+.gitusers
+autom4te.cache
+cscope.files
+cscope.out
+autoconf/aclocal.m4
+autoconf/autom4te.cache
+/compile_commands.json
+/tablegen_compile_commands.yml
+# Visual Studio built-in CMake configuration
+/CMakeSettings.json
+# CLion project configuration
+/.idea
+/cmake-build*
+# Coding assistants' stuff
+.agents/
+/CLAUDE.md
+/instructions.md
+.claude/
+/GEMINI.md
+.gemini/
+AGENTS.md
+.codex/
+# Cursor specific files
+.cursor
+.cursorignore
+.cursorindexingignore
+
+#==============================================================================#
+# Directories to ignore (do not add trailing '/'s, they skip symlinks).
+#==============================================================================#
+# VS2017 and VSCode config files.
+.vscode
+.vs
+#zed config files
+.zed
+# pythonenv for github Codespaces
+pythonenv*
+# clangd index. (".clangd" is a config file now, thus trailing slash)
+.clangd/
+.cache
+.clangd
+# static analyzer regression testing project files
+/clang/utils/analyzer/projects/*/CachedSource
+/clang/utils/analyzer/projects/*/PatchedSource
+/clang/utils/analyzer/projects/*/ScanBuildResults
+/clang/utils/analyzer/projects/*/RefScanBuildResults
+# automodapi puts generated documentation files here.
+/lldb/docs/python_api/
diff --git a/a.mlir b/a.mlir
new file mode 100644
index 0000000000000..17b8861438a17
--- /dev/null
+++ b/a.mlir
@@ -0,0 +1,13 @@
+module {
+ func.func @add_dynamic(%arg0: memref<?x?bf16>, %arg1: memref<?x?bf16>, %arg2: memref<?x?bf16>) {
+ linalg.add ins(%arg0, %arg1 : memref<?x?bf16>, memref<?x?bf16>) outs(%arg2 : memref<?x?bf16>)
+ return
+ }
+ module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.add"]} in %arg0 : (!transform.any_op) -> !transform.any_op
+ transform.structured.vectorize %0 vector_sizes [8, 16, 4] : !transform.any_op
+ transform.yield
+ }
+ }
+}
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index f44693096b26b..4f9eb70d661e2 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -4174,7 +4174,6 @@ DiagnosedSilenceableFailure transform::VectorizeOp::apply(
return mlir::emitSilenceableFailure(target->getLoc())
<< "Unsupported Op, cannot vectorize";
}
- FailureOr<VectorizationResult> vectorResults =
linalg::vectorize(rewriter, target, vectorSizes, getScalableSizes(),
getVectorizeNdExtract().value_or(false),
/*flatten1DDepthwiseConv=*/false,
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index b57e66a1c3580..95b05be723d7e 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -2381,6 +2381,18 @@ vectorizeScalableVectorPrecondition(Operation *op,
return success(isa<linalg::UnPackOp>(op));
}
+ // Ensure that the number of vector sizes and scalable flags provided by the
+ // user does not exceed the number of loops in the target Linalg op.
+ // Accessing iterator types with an out-of-bounds index would cause an
+ // assertion failure (SmallVector::operator[]). This check converts such a
+ // crash into a clean failure, allowing the transform interpreter to report
+ // an error gracefully.
+ // Regression test:
+ // mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlir
+ if (inputScalableVecDims.size() > linalgOp.getNumLoops() ||
+ inputVectorSizes.size() > linalgOp.getNumLoops())
+ return failure();
+
// Cond 2: There's been no need for more than 2 scalable dims so far
if (numOfScalableDims > 2)
return failure();
diff --git a/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlir b/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlir
index 271cdf0e059f4..a74e52dfd4bdb 100644
--- a/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlir
+++ b/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlir
@@ -19,3 +19,29 @@ module attributes {transform.with_named_sequence} {
transform.yield
}
}
+
+// -----
+
+// RUN: mlir-opt %s -transform-interpreter -verify-diagnostics
+// Regression test for bug #204100.
+// Assertion idx < size() in SmallVector.h used to happen here.
+// CHECK-LABEL: func @add_dynamic
+module {
+ func.func @add_dynamic(%arg0: memref<?x?xbf16>, %arg1: memref<?x?xbf16>, %arg2: memref<?x?xbf16>) {
+ linalg.add ins(%arg0, %arg1 : memref<?x?xbf16>, memref<?x?xbf16>) outs(%arg2 : memref<?x?xbf16>)
+ return
+ }
+ module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.add"]} in %arg0 : (!transform.any_op) -> !transform.any_op
+ // This combination was crashing (static/dynamic mismatch)
+ transform.structured.vectorize %0 vector_sizes [8, [16], 4] : !transform.any_op
+ // expected-error @above {{Attempted to vectorize, but failed}}
+ transform.yield
+ }
+ }
+}
+
+
+
+
diff --git a/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlires b/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlires
new file mode 100644
index 0000000000000..0ef5c7efaeab9
--- /dev/null
+++ b/mlir/test/Dialect/Vector/transform-op-vector-to-llvm.mlires
@@ -0,0 +1,43 @@
+// RUN: mlir-opt %s -transform-interpreter -verify-diagnostics -allow-unregistered-dialect -split-input-file | FileCheck %s
+
+// CHECK-LABEL: func @lower_to_llvm
+// CHECK-NOT: vector.bitcast
+// CHECK: llvm.bitcast
+func.func @lower_to_llvm(%input: vector<f32>) -> vector<i32> {
+ %0 = vector.bitcast %input : vector<f32> to vector<i32>
+ return %0 : vector<i32>
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ transform.apply_conversion_patterns to %0 {
+ transform.apply_conversion_patterns.vector.vector_to_llvm
+ } with type_converter {
+ transform.apply_conversion_patterns.memref.memref_to_llvm_type_converter
+ } {legal_dialects = ["func", "llvm"]} : !transform.any_op
+ transform.yield
+ }
+}
+
+// RUN: mlir-opt %s -transform-interpreter -verify-diagnostics
+// Regression test for bug #204100.
+// Assertion idx < size() in SmallVector.h used to happen here.
+// CHECK-LABEL: func @add_dynamic
+module {
+ func.func @add_dynamic(%arg0: memref<?x?xbf16>, %arg1: memref<?x?xbf16>, %arg2: memref<?x?xbf16>) {
+ linalg.add ins(%arg0, %arg1 : memref<?x?xbf16>, memref<?x?xbf16>) outs(%arg2 : memref<?x?xbf16>)
+ return
+ }
+ module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.add"]} in %arg0 : (!transform.any_op) -> !transform.any_op
+ // This combination was crashing (static/dynamic mismatch)
+ transform.structured.vectorize %0 vector_sizes [8, [16], 4] : !transform.any_op
+ // expected-error @above {{Attempted to vectorize, but failed}}
+ transform.yield
+ }
+ }
+}
+
+
>From 694f9e08f507a61d7f22d881bca8e5894227d9bc Mon Sep 17 00:00:00 2001
From: LouisLu0602 <yaolu0602 at gmail.com>
Date: Thu, 25 Jun 2026 09:38:02 +0800
Subject: [PATCH 2/4] Fixing comments
---
.gitignorees | 92 -------------------
a.mlir | 13 ---
.../TransformOps/LinalgTransformOps.cpp | 1 +
3 files changed, 1 insertion(+), 105 deletions(-)
delete mode 100644 .gitignorees
delete mode 100644 a.mlir
diff --git a/.gitignorees b/.gitignorees
deleted file mode 100644
index a4382c9ea7390..0000000000000
--- a/.gitignorees
+++ /dev/null
@@ -1,92 +0,0 @@
-#==============================================================================#
-# This file specifies intentionally untracked files that git should ignore.
-# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
-#
-# This file is intentionally different from the output of `git svn show-ignore`,
-# as most of those are useless.
-#==============================================================================#
-
-#==============================================================================#
-# File extensions to be ignored anywhere in the tree.
-#==============================================================================#
-# Temp files created by most text editors.
-*~
-# Emacs lock files
-.#*
-# Merge files created by git.
-*.orig
-# Reject files created by patch.
-*.rej
-# Byte compiled python modules.
-*.pyc
-# vim swap files
-.*.sw?
-.sw?
-#macOS specific
-.DS_Store
-
-# Ignore the user specified CMake presets in subproject directories.
-/*/CMakeUserPresets.json
-
-# Nested build directory
-/build*
-
-#==============================================================================#
-# Explicit files to ignore (only matches one).
-#==============================================================================#
-# Various tag programs
-/tags
-/TAGS
-/GPATH
-/GRTAGS
-/GSYMS
-/GTAGS
-/ID
-.gitusers
-autom4te.cache
-cscope.files
-cscope.out
-autoconf/aclocal.m4
-autoconf/autom4te.cache
-/compile_commands.json
-/tablegen_compile_commands.yml
-# Visual Studio built-in CMake configuration
-/CMakeSettings.json
-# CLion project configuration
-/.idea
-/cmake-build*
-# Coding assistants' stuff
-.agents/
-/CLAUDE.md
-/instructions.md
-.claude/
-/GEMINI.md
-.gemini/
-AGENTS.md
-.codex/
-# Cursor specific files
-.cursor
-.cursorignore
-.cursorindexingignore
-
-#==============================================================================#
-# Directories to ignore (do not add trailing '/'s, they skip symlinks).
-#==============================================================================#
-# VS2017 and VSCode config files.
-.vscode
-.vs
-#zed config files
-.zed
-# pythonenv for github Codespaces
-pythonenv*
-# clangd index. (".clangd" is a config file now, thus trailing slash)
-.clangd/
-.cache
-.clangd
-# static analyzer regression testing project files
-/clang/utils/analyzer/projects/*/CachedSource
-/clang/utils/analyzer/projects/*/PatchedSource
-/clang/utils/analyzer/projects/*/ScanBuildResults
-/clang/utils/analyzer/projects/*/RefScanBuildResults
-# automodapi puts generated documentation files here.
-/lldb/docs/python_api/
diff --git a/a.mlir b/a.mlir
deleted file mode 100644
index 17b8861438a17..0000000000000
--- a/a.mlir
+++ /dev/null
@@ -1,13 +0,0 @@
-module {
- func.func @add_dynamic(%arg0: memref<?x?bf16>, %arg1: memref<?x?bf16>, %arg2: memref<?x?bf16>) {
- linalg.add ins(%arg0, %arg1 : memref<?x?bf16>, memref<?x?bf16>) outs(%arg2 : memref<?x?bf16>)
- return
- }
- module attributes {transform.with_named_sequence} {
- transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
- %0 = transform.structured.match ops{["linalg.add"]} in %arg0 : (!transform.any_op) -> !transform.any_op
- transform.structured.vectorize %0 vector_sizes [8, 16, 4] : !transform.any_op
- transform.yield
- }
- }
-}
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index 4f9eb70d661e2..f44693096b26b 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -4174,6 +4174,7 @@ DiagnosedSilenceableFailure transform::VectorizeOp::apply(
return mlir::emitSilenceableFailure(target->getLoc())
<< "Unsupported Op, cannot vectorize";
}
+ FailureOr<VectorizationResult> vectorResults =
linalg::vectorize(rewriter, target, vectorSizes, getScalableSizes(),
getVectorizeNdExtract().value_or(false),
/*flatten1DDepthwiseConv=*/false,
>From 2bb60d6d637499273788e3e4ca8efd8c5149ca80 Mon Sep 17 00:00:00 2001
From: LouisLu0602 <yaolu0602 at gmail.com>
Date: Fri, 26 Jun 2026 11:22:47 +0800
Subject: [PATCH 3/4] Fix a.mlir crash
---
.gitignore | 2 --
a.mlir | 17 +++++++++++++++++
mlir/lib/Transforms/RemoveDeadValues.cpp | 20 +++++++++++++-------
3 files changed, 30 insertions(+), 9 deletions(-)
create mode 100644 a.mlir
diff --git a/.gitignore b/.gitignore
index ac57b104aa4e0..a4382c9ea7390 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,5 +90,3 @@ pythonenv*
/clang/utils/analyzer/projects/*/RefScanBuildResults
# automodapi puts generated documentation files here.
/lldb/docs/python_api/
-<<<<<<< HEAD
-<<<<<<< HEAD
diff --git a/a.mlir b/a.mlir
new file mode 100644
index 0000000000000..d1c10b8e82117
--- /dev/null
+++ b/a.mlir
@@ -0,0 +1,17 @@
+module {
+ pdl_interp.func private @matcher(%arg0: !llvm.ptr) {
+ pdl_interp.finalize
+ }
+ module @rewriters {
+ }
+ func.func private @callee(%arg0: memref<f32>) -> memref<f32> {
+ %false = arith.constant false
+ %0 = scf.if %false -> (memref<f32>) {
+ scf.yield %arg0 : memref<f32>
+ } else {
+ %1 = bufferization.clone %arg0 : memref<f32> to memref<f32>
+ scf.yield %1 : memref<f32>
+ }
+ return %0 : memref<f32>
+ }
+}
diff --git a/mlir/lib/Transforms/RemoveDeadValues.cpp b/mlir/lib/Transforms/RemoveDeadValues.cpp
index f0a210a2ededb..ae46630c949de 100644
--- a/mlir/lib/Transforms/RemoveDeadValues.cpp
+++ b/mlir/lib/Transforms/RemoveDeadValues.cpp
@@ -520,14 +520,20 @@ static void processBranchOp(BranchOpInterface branchOp, RunLivenessAnalysis &la,
}
}
+/// Create ub.poison ops for the given values. If a value has no uses, return
+/// an "empty" value.
+static Value createPoisonedValue(OpBuilder &b, Value value) {
+ if (!value || value.use_empty())
+ return Value();
+ return ub::PoisonOp::create(b, value.getLoc(), value.getType()).getResult();
+}
+
/// Create ub.poison ops for the given values. If a value has no uses, return
/// an "empty" value.
static SmallVector<Value> createPoisonedValues(OpBuilder &b,
ValueRange values) {
- return llvm::map_to_vector(values, [&](Value value) {
- if (value.use_empty())
- return Value();
- return ub::PoisonOp::create(b, value.getLoc(), value.getType()).getResult();
+ return llvm::map_to_vector(values, [&](Value value) -> Value {
+ return createPoisonedValue(b, value);
});
}
@@ -689,9 +695,9 @@ static void cleanUpDeadVals(MLIRContext *ctx, RDVFinalCleanupList &list) {
if (o.replaceWithPoison) {
rewriter.setInsertionPoint(o.op);
for (auto deadIdx : o.nonLive.set_bits()) {
- o.op->setOperand(
- deadIdx, createPoisonedValues(rewriter, o.op->getOperand(deadIdx))
- .front());
+ Value poisoned = createPoisonedValue(rewriter, o.op->getOperand(deadIdx));
+ if (poisoned)
+ o.op->setOperand(deadIdx, poisoned);
}
} else {
o.op->eraseOperands(o.nonLive);
>From 56fd51b485a0db272593687577ead5b9251718fd Mon Sep 17 00:00:00 2001
From: LouisLu0602 <yaolu0602 at gmail.com>
Date: Fri, 26 Jun 2026 11:32:11 +0800
Subject: [PATCH 4/4] [mlir][RemoveDeadValues] Fix crash replacing dead operand
with poison
---
mlir/test/Transforms/remove-dead-values.mlir | 23 ++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 64088ce15cd48..bbed2dc2e2feb 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -868,3 +868,26 @@ module @func_with_non_call_users {
}
spirv.EntryPoint "GLCompute" @callee
}
+
+// -----
+
+// CHECK: pdl_interp.func private @matcher()
+// CHECK-LABEL: func.func private @callee()
+// CHECK: return
+module {
+ pdl_interp.func private @matcher(%arg0: !llvm.ptr) {
+ pdl_interp.finalize
+ }
+ module @rewriters {
+ }
+ func.func private @callee(%arg0: memref<f32>) -> memref<f32> {
+ %false = arith.constant false
+ %0 = scf.if %false -> (memref<f32>) {
+ scf.yield %arg0 : memref<f32>
+ } else {
+ %1 = bufferization.clone %arg0 : memref<f32> to memref<f32>
+ scf.yield %1 : memref<f32>
+ }
+ return %0 : memref<f32>
+ }
+}
More information about the Mlir-commits
mailing list