PoCL: SPIR-V vector math fails to link on Windows
Maintainers usually reply within 1 day
A pull request for this has already been merged.
- #2381 by @maleadt — merged
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 42/100
Research direction
The issue points to PoCL’s generate_spir_wrapper.py and lib/kernel/host/CMakeLists.txt, where host kernel wrappers are generated. First read the wrapper’s calling-convention rewrites and how CMake selects generation modes for Windows targets. Done means Windows-target wrappers avoid the incompatible coercion, byval, and sret rewrites, with the reported vector math cases linking successfully.
Written by the indexing model from the issue text.
Description
On Windows, kernels compiled through SPIR-V fail to link when they call a math builtin on a vector wider than the CPU's vector registers. This is the cause of #415, and why the SIMD tests are partially skipped on Windows (#533):
using OpenCL, pocl_jll, SIMD
function kernel(out, v)
out[] = sin(v)
return
end
v = Vec{16,Float64}(ntuple(Float64, 16))
out = CLArray{Vec{16,Float64},0}(undef)
@opencl kernel(out, v)
println(OpenCL.@allowscalar out[])
JIT session error: Symbols not found: [ _Z7_cl_sinDv16_d ]
JIT session error: Symbols not found: [ _Z7_cl_sinDv16_d ]
<16 x Float64>[1.304637681984e-311, 1.69759663277e-313, ...]
(That the launch failure then goes unnoticed, and the read returns uninitialized memory, is a separate problem: #535.)
PoCL links SPIR-V kernels against its kernel library through generated wrappers (generate_spir_wrapper.py), which hardcode the x86-64 System V calling convention: vectors wider than the CPU's vector registers are passed byval and returned sret (tables from line 384), and <2 x float> is coerced to double. The Windows kernel library (target triple x86_64-w64-windows-gnu) takes these vectors directly, so the call doesn't match the definition. From the pocl_jll 7.2.2 bitcode:
; kernel-x86_64-linux-gnu-avx512.bc
define <16 x double> @_Z7_cl_sinDv16_d(ptr noundef byval(<16 x double>) align 128 %0)
; kernel-x86_64-w64-mingw32-avx512.bc
define dso_local <16 x double> @_Z7_cl_sinDv16_d(<16 x double> noundef %0)
define spir_func <16 x double> @_Z3sinDv16_d(<16 x double> %a) {
%1 = alloca <16 x double>, align 128
store <16 x double> %a, ptr %1, align 128
%call = tail call <16 x double> @_Z7_cl_sinDv16_d(ptr %1)
ret <16 x double> %call
}
The 2-wide case (call double @_Z7_cl_sinDv2_f(double) against define <2 x float> @_Z7_cl_sinDv2_f(<2 x float>)) is just as wrong, but happens to work because the types have the same size.
Which widths break depends on the register size of the kernel library variant PoCL picks for the CPU. Testing sin and fma with each variant forced through POCL_KERNELLIB_NAME:
| variant | failing |
|---|---|
| avx512 | 16 x Float64 |
| avx2 | 8 x Float64, 16 x Float32, 16 x Float64 |
| sse2 | 16 x Float16, 8 and 16 x Float32, 3 to 16 x Float64 |
That is exactly the variant's byval table. Everything passes through the OpenCL C path (spirv2clc), which doesn't use these wrappers.
The fix in PoCL is to generate the wrappers without the coercion, byval and sret rewrites when targeting Windows, where the backend lowers vector arguments itself: a Windows mode for the script, selected for *-windows-* triples where lib/kernel/host/CMakeLists.txt generates the wrapper. Generating the wrappers with clang for the actual target triple would avoid duplicating calling-convention rules altogether, but is a larger change.
pocl_jll 7.2.2+0, OpenCL.jl #533, Julia 1.13.1, Windows Server 2022 (VM on an AMD Ryzen 9 9950X).
- Dominant language
- Julia
- Stars
- 315
- Forks
- 50
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 36
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from JuliaGPU/OpenCL.jl
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
Maintainers usually reply within 1 day
-
A failed SVM allocation returns a CLArray at address 0, and kernels that write to it fault the GPUOpen
Difficulty 3/5 1-2 days Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
kernels latency regression
Difficulty 4/5 3-5 days Newbie friendliness 52/100
Maintainers usually reply within 1 day
All issues in JuliaGPU/OpenCL.jl
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
backport 1.14 GC
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 1 day