| Issue |
202861
|
| Summary |
SPIR-V output contains OpFunctionCall to inline function with no definition
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
Lurie97
|
When building libclc for SPIR-V targets (`spirv-mesa3d-` / `spirv64-mesa3d-`), the resulting `.spv` file contains `OpFunctionCall` instructions referencing `__clc_flush_denormal_if_not_supported`, but this function only has an `OpFunction` **declaration** (no basic blocks / no body) in the SPIR-V output.
This causes Mesa's `nir_link_shader_functions` to fail to resolve the call, leaving unresolved call instructions in the final shader, which leads to a crash at runtime.
- LLVM version: 21.1.3 (release/21.x branch)
- SPIRV-LLVM-Translator branch: llvm_release_210
- libclc targets: `spirv-mesa3d-`, `spirv64-mesa3d-`
- Mesa version: 26.1.0-devel
- GPU: Mali G310 (Valhall, Panfrost driver)
- Reproducer test: opencv_test_core --gtest_filter=OCL_Arithm/PolarToCart.angleInDegree/0
### How libclc is compiled
clang -target spir64-- -O0 -finline-hint-functions -DCLC_SPIRV \
-cl-std=CL3.0 -emit-llvm -o <output>.bc -x cl <input>.cl
llvm-link --internalize --only-needed -o builtins.bc <opencl_builtins>.bc <clc_builtins>.bc
llvm-spirv --spirv-max-version=1.1 -o spirv64-mesa3d-.spv builtins.bc
### The function in question
Defined in `libclc/clc/include/clc/math/math.h:68`:
```c
_CLC_OVERLOAD _CLC_INLINE float __clc_flush_denormal_if_not_supported(float x) {
int ix = __clc_as_int(x);
if (!__clc_fp32_subnormals_supported() && ((ix & EXPBITS_SP32) == 0) &&
((ix & MANTBITS_SP32) != 0)) {
ix &= SIGNBIT_SP32;
x = __clc_as_float(ix);
}
return x;
}
Where _CLC_INLINE expands to inline (clcfunc.h:14).
This function is called from:
- clc/lib/generic/math/clc_sw_fma.cl (lines 39-41)
- clc/lib/generic/math/clc_remquo.inc (lines 11-12)
Expected behavior
With -O0 -finline-hint-functions, the inline-hinted function should be inlined into its callers (__clc_sw_fma, __clc_remquo). Since __clc_fp32_subnormals_supported() returns a constant false for SPIR-V targets, after inlining and constant folding the function body should reduce to return x (identity / no-op) and be fully absorbed into the callers.
The final SPIR-V should not contain any reference to __clc_flush_denormal_if_not_supported.
Actual behavior
The SPIR-V output contains:
; Declaration only (no body):
OpName %_Z37__clc_flush_denormal_if_not_supportedf "_Z37__clc_flush_denormal_if_not_supportedf"
; But callers still reference it:
%113252 = OpFunctionCall %float %_Z37__clc_flush_denormal_if_not_supportedf %113249
%113254 = OpFunctionCall %float %_Z37__clc_flush_denormal_if_not_supportedf %113253
%113256 = OpFunctionCall %float %_Z37__clc_flush_denormal_if_not_supportedf %113255
...
The function was inlined at the LLVM IR level (so no standalone definition survives), but OpFunctionCall references to it still exist in the SPIR-V output. This creates an inconsistency: calls exist but the callee has no body.
Impact on consumers (Mesa)
When Mesa loads this SPIR-V via spirv_to_nir():
1. __clc_flush_denormal_if_not_supported becomes a nir_function with impl == NULL
2. nir_link_shader_functions cannot find an implementation to clone
3. nir_inline_functions skips the unresolved calls
4. nir_remove_non_entrypoints removes the declaration from the function list
5. nir_sweep frees the memory
6. Remaining nir_call_instr pointers become dangling → use-after-free / Bus error
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs