[Mlir-commits] [mlir] bcd8819 - [mlir][transforms] Fix crash in remove-dead-values when function has non-call users (#183655)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Feb 27 07:44:13 PST 2026
Author: Mehdi Amini
Date: 2026-02-27T15:44:08Z
New Revision: bcd8819aee057f483c040743a6e8ccb2ecd7d44a
URL: https://github.com/llvm/llvm-project/commit/bcd8819aee057f483c040743a6e8ccb2ecd7d44a
DIFF: https://github.com/llvm/llvm-project/commit/bcd8819aee057f483c040743a6e8ccb2ecd7d44a.diff
LOG: [mlir][transforms] Fix crash in remove-dead-values when function has non-call users (#183655)
`processFuncOp` asserts that all symbol uses of a function are
`CallOpInterface` operations. This is violated when a function is
referenced by a non-call operation such as `spirv.EntryPoint`, which
uses the function symbol for metadata purposes without calling it.
Fix this by replacing the assertion with an early return: if any user of
the function symbol is not a `CallOpInterface`, skip the function
entirely. This is safe because the pass cannot determine the semantics
of arbitrary non-call references, so it should leave such functions
alone.
Fixes #180416
Added:
Modified:
mlir/lib/Transforms/RemoveDeadValues.cpp
mlir/test/Transforms/remove-dead-values.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Transforms/RemoveDeadValues.cpp b/mlir/lib/Transforms/RemoveDeadValues.cpp
index 12a47ba2fb65a..4c15fd46d581e 100644
--- a/mlir/lib/Transforms/RemoveDeadValues.cpp
+++ b/mlir/lib/Transforms/RemoveDeadValues.cpp
@@ -285,7 +285,15 @@ static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
<< funcOp.getOperation()->getName();
return;
}
-
+ SymbolTable::UseRange uses = *funcOp.getSymbolUses(module);
+ if (llvm::any_of(uses, [](SymbolTable::SymbolUse use) {
+ return !isa<CallOpInterface>(use.getUser());
+ })) {
+ // If a non-call operation references the function (e.g. spirv.EntryPoint),
+ // we cannot safely remove arguments or return values since we don't know
+ // what the user expects. Skip this function entirely.
+ return;
+ }
// Get the list of unnecessary (non-live) arguments in `nonLiveArgs`.
SmallVector<Value> arguments(funcOp.getArguments());
BitVector nonLiveArgs = markLives(arguments, nonLiveSet, la);
@@ -299,10 +307,8 @@ static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
// Do (2). (Skip creating generic operand cleanup entries for call ops.
// Call arguments will be removed in the call-site specific segment-aware
// cleanup, avoiding generic eraseOperands bitvector mechanics.)
- SymbolTable::UseRange uses = *funcOp.getSymbolUses(module);
for (SymbolTable::SymbolUse use : uses) {
Operation *callOp = use.getUser();
- assert(isa<CallOpInterface>(callOp) && "expected a call-like user");
// Push an empty operand cleanup entry so that call-site specific logic in
// cleanUpDeadVals runs (it keys off CallOpInterface). The BitVector is
// intentionally all false to avoid generic erasure.
@@ -614,8 +620,8 @@ static void cleanUpDeadVals(MLIRContext *ctx, RDVFinalCleanupList &list) {
// AttrSizedOperandSegments) in the next phase.
DenseMap<Operation *, BitVector> erasedFuncArgs;
for (auto &f : list.functions) {
- LDBG() << "Cleaning up function: " << f.funcOp.getOperation()->getName()
- << " (" << f.funcOp.getOperation() << ")";
+ LDBG() << "Cleaning up function: " << f.funcOp.getName() << " ("
+ << f.funcOp.getOperation() << ")";
LDBG_OS([&](raw_ostream &os) {
os << " Erasing non-live arguments [";
llvm::interleaveComma(f.nonLiveArgs.set_bits(), os);
@@ -634,6 +640,9 @@ static void cleanUpDeadVals(MLIRContext *ctx, RDVFinalCleanupList &list) {
// Record only if we actually erased something.
if (f.nonLiveArgs.any())
erasedFuncArgs.try_emplace(f.funcOp.getOperation(), f.nonLiveArgs);
+ } else {
+ LDBG() << "Failed to erase arguments for function: "
+ << f.funcOp.getName();
}
(void)f.funcOp.eraseResults(f.nonLiveRets);
}
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 87e77b2eb700f..19bc6b2fddd66 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -826,3 +826,24 @@ func.func @replace_dead_operation_results_with_poison(%0: vector<1xindex>) -> ve
}
return %2 : vector<1xindex>
}
+
+// -----
+
+// Verify that a referenced by a non-call op (spirv.EntryPoint),
+// while still having another usual call site is preserved as-is
+// since the pass cannot analyse non-call users.
+// CHECK-LABEL: module @func_with_non_call_users
+// CHECK-CANONICALIZE-LABEL: module @func_with_non_call_users
+module @func_with_non_call_users {
+// CHECK: func.func private @callee(%arg0: i32, %arg1: i32)
+// CHECK-CANONICALIZE: func.func private @callee(%arg0: i32, %arg1: i32)
+ func.func private @callee(%arg1 : i32, %arg2 : i32) {
+ func.return
+ }
+ func.func @main_func() {
+ %cst = llvm.mlir.constant(1 : i32) : i32
+ func.call @callee(%cst, %cst) : (i32, i32) -> ()
+ func.return
+ }
+ spirv.EntryPoint "GLCompute" @callee
+}
More information about the Mlir-commits
mailing list