This kernel should compile, but Metal fails while rewriting relocation slots:
using Metal
pick(i) = i == 1 ? Val(1) : i == 2 ? Val(2) : i == 3 ? Val(3) : i == 4 ? Val(4) : Val(5)
function kernel(a, i)
v = pick(i[1])
a[1] = v === Val(1) ? 1f0 : v === Val(2) ? 2f0 : 3f0
return
end
Metal.code_air(devnull, kernel, Tuple{MtlDeviceVector{Float32,1},MtlDeviceVector{Int,1}}; kernel = true)
# ERROR: Relocation slot '_Z6kernel…_jl_global_ffffffff176dc106' still has uses after redirection
Reproduced with Metal.jl 1.11.1, GPUCompiler 2.8.2, and Julia 1.12.7, and on the atomics branches from #942. The same kernel compiles and runs with CUDA.jl.
With five possible values, inference widens the Union to Val, so v is boxed. The === expressions compare its pointer with singleton addresses loaded from relocation slots. LLVM combines those loads into one load from a phi of slot addresses:
%value_phi.in.in = phi ptr [ @…_jl_global_ffffffff84dba5e4, %L23 ], [ @…_jl_global_…, … ], …
The rewrite in src/relocation.jl redirects only direct loads from a relocation slot. It does not rewrite the slot address used by this phi, so the slot retains a use and compilation fails.
This occurs when atomic orderings are selected at run time from MSL’s five memory orders, as in JuliaConcurrent/UnsafeAtomics.jl#30. Current workarounds are to branch explicitly and pass a constant in each branch, or to use a Union of at most three values so that Julia keeps it unboxed.
The relocation rewrite needs to handle slot addresses propagated through a phi.
This kernel should compile, but Metal fails while rewriting relocation slots:
Reproduced with Metal.jl 1.11.1, GPUCompiler 2.8.2, and Julia 1.12.7, and on the atomics branches from #942. The same kernel compiles and runs with CUDA.jl.
With five possible values, inference widens the
UniontoVal, sovis boxed. The===expressions compare its pointer with singleton addresses loaded from relocation slots. LLVM combines those loads into one load from aphiof slot addresses:The rewrite in
src/relocation.jlredirects only direct loads from a relocation slot. It does not rewrite the slot address used by thisphi, so the slot retains a use and compilation fails.This occurs when atomic orderings are selected at run time from MSL’s five memory orders, as in JuliaConcurrent/UnsafeAtomics.jl#30. Current workarounds are to branch explicitly and pass a constant in each branch, or to use a
Unionof at most three values so that Julia keeps it unboxed.The relocation rewrite needs to handle slot addresses propagated through a
phi.