[Mlir-commits] [mlir] [mlir][transforms] Fix crash in remove-dead-values when function has non-call users (PR #183655)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Feb 26 17:00:08 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

<details>
<summary>Changes</summary>

`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

---
Full diff: https://github.com/llvm/llvm-project/pull/183655.diff


2 Files Affected:

- (modified) mlir/lib/Transforms/RemoveDeadValues.cpp (+5-1) 
- (modified) mlir/test/Transforms/remove-dead-values.mlir (+13) 


``````````diff
diff --git a/mlir/lib/Transforms/RemoveDeadValues.cpp b/mlir/lib/Transforms/RemoveDeadValues.cpp
index 12a47ba2fb65a..c70cd8d6beb68 100644
--- a/mlir/lib/Transforms/RemoveDeadValues.cpp
+++ b/mlir/lib/Transforms/RemoveDeadValues.cpp
@@ -302,7 +302,11 @@ static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
   SymbolTable::UseRange uses = *funcOp.getSymbolUses(module);
   for (SymbolTable::SymbolUse use : uses) {
     Operation *callOp = use.getUser();
-    assert(isa<CallOpInterface>(callOp) && "expected a call-like user");
+    // 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.
+    if (!isa<CallOpInterface>(callOp))
+      return;
     // 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.
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 87e77b2eb700f..7a08b2c94f0a8 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -826,3 +826,16 @@ func.func @replace_dead_operation_results_with_poison(%0: vector<1xindex>) -> ve
   }
   return %2 : vector<1xindex>
 }
+
+// -----
+
+// Verify no crash when a function is referenced by a non-call op (spirv.EntryPoint).
+// The function should be preserved as-is since the pass cannot analyse non-call users.
+// CHECK: spirv.EntryPoint "GLCompute" @main_func
+// CHECK: llvm.func @main_func()
+module {
+  spirv.EntryPoint "GLCompute" @main_func
+  llvm.func @main_func() attributes {sym_visibility = "private"} {
+    llvm.return
+  }
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/183655


More information about the Mlir-commits mailing list