Add Atomix and UnsafeAtomics atomics tests - #726
Conversation
| if !(backend() isa CPU) | ||
| @test_skip "UnsafeAtomics tests only run on the CPU backend" | ||
| return | ||
| end |
There was a problem hiding this comment.
| if !(backend() isa CPU) | |
| @test_skip "UnsafeAtomics tests only run on the CPU backend" | |
| return | |
| end |
There was a problem hiding this comment.
Done in 291db15 — the CPU-only gate is removed, so the UnsafeAtomics tests now run on every backend.
vchuravy
left a comment
There was a problem hiding this comment.
Missing:
- fences
- orderings
- scopes
Benchmark ResultsShow table
Benchmark PlotsA plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR. |
| @testset "Atomix" begin | ||
| # Float32 is excluded since atomic float add requires the SPIR-V | ||
| # extension SPV_EXT_shader_atomic_float_add, unavailable with PoCL. | ||
| @testset "atomic add ($T)" for T in (Int32, UInt32) |
There was a problem hiding this comment.
We should implement fallbacks for this JuliaGPU/GPUCompiler.jl#652
There was a problem hiding this comment.
Added a TODO comment referencing JuliaGPU/GPUCompiler.jl#652 next to the Float32 exclusion (291db15).
I just tested it, PoCL supports julia> using OpenCL, KernelAbstractions, SPIRVIntrinsics, pocl_jll
julia> gentype = Float32; as = 1
1
julia> @eval SPIRVIntrinsics @device_function atomic_max!(p::LLVMPtr{$gentype,$as}, val::$gentype) =
@builtin_ccall("__spirv_AtomicFMaxEXT", $gentype,
(LLVMPtr{$gentype,$as}, UInt32, UInt32, $gentype),
p, UInt32(atomic_scope),
UInt32(atomic_memory_semantics(Val($as))), val)
julia> function atomix_max!(A)
@inbounds KernelAbstractions.@atomic max(A[1], eltype(A)(get_global_id()))
return nothing
end
atomix_max! (generic function with 4 methods)
julia> a = OpenCL.zeros(T)
0-dimensional CLArray{Float32, 0, OpenCL.cl.UnifiedDeviceMemory}:
0.0
julia> @opencl global_size = 1000 extensions = ["SPV_EXT_shader_atomic_float_min_max"] atomix_max!(a)
OpenCL.HostKernel{typeof(atomix_max!), Tuple{CLDeviceArray{Float32, 0, 1}}}(atomix_max!, OpenCL.Kernel("_Z11atomix_max_13CLDeviceArrayI7Float32Li0ELi1EE" nargs=2), false)
julia> a
0-dimensional CLArray{Float32, 0, OpenCL.cl.UnifiedDeviceMemory}:
1000.0Probably makes sense to enable by default for PoCLBackend, or what do you think? |
|
Addressed the review in 291db15:
25 tests passing on the CPU backend. |
The SPIR-V backend refuses to translate a module containing an atomic fadd
unless the extension guarding it has been listed:
LLVM ERROR: The atomic float instruction requires the following SPIR-V
extension: SPV_EXT_shader_atomic_float_add
Enzyme's reverse mode runs into this because it accumulates gradients with
atomic fadd, so reverse-mode AD over a POCL kernel fails to compile outright.
Derive the extension list from the device the way `supports_fp16`/`supports_fp64`
already are, keyed off the corresponding OpenCL extension (`cl_ext_float_atomics`,
which PoCL advertises). Listing an extension only permits it -- nothing is
emitted unless a module needs those instructions -- so kernels that do not use
float atomics are unaffected. An explicit `extensions=` keyword still wins, and
`default_spirv_extensions` gives later extensions an obvious home.
Verified end-to-end: with this change, reverse-mode Enzyme over a POCL kernel
compiles, runs and produces correct gradients.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…pabilities Atomix lowers `@atomic A[i] += x` and `@atomic max(A[i], x)` on floats to LLVM `atomicrmw fadd`/`fmin`/`fmax`, which the SPIR-V backend only translates when SPV_EXT_shader_atomic_float_add resp. SPV_EXT_shader_atomic_float_min_max is permitted. Derive both from the per-precision cl_ext_float_atomics capability bitfields instead of the bare extension string, requiring the global and local memory bits like OpenCL.jl does, and expose the bitfields as device properties. Adds an `Atomics` testsuite entry exercising add/min/max for Int32, UInt32, Float32 and (where supported) Float64 on all backends, and a POCL-specific check that both extensions are permitted on pocl's CPU device while an explicit `extensions=` still wins. Assisted-by: Claude Code (Fable 5.1)
Adds an Atomics testsuite exercising @atomic/@atomicswap/@atomicreplace (via Atomix) in kernels on all backends, plus UnsafeAtomics pointer-based atomics on the CPU backend. UnsafeAtomics becomes a direct test dependency. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gs, fences, and syncscopes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nsions Run the Atomix and UnsafeAtomics add and min/max tests for Float32 and, where the backend supports it, Float64 in addition to the integer types. Assisted-by: Claude Code (Fable 5.1)
291db15 to
f7698e2
Compare
Adds an
Atomicstestset to the shared testsuite covering the atomics functionality KernelAbstractions re-exports from Atomix, plus raw-pointer atomics from UnsafeAtomics.Atomix (all backends, gated on
supports_atomics(backend()))@atomic +=forInt32/UInt32/Float32/Float64@atomic max/@atomic minreductions across the ndrange@atomic A[i]) and store (@atomic A[i] = v)@atomicswap@atomicreplacewith both succeeding and failing CASUnsafeAtomics (CPU backend only,
@test_skipelsewhere)add!histogram forInt32/UInt32/Float32/Float64max!/min!store!/modify!/cas!/xchg!/loadsequenceadd!with explicitseq_cstorderingNotes:
SPV_EXT_shader_atomic_float_{add,min_max}extensions based oncl_ext_float_atomics. This PR is rebased on top of it and extends thetest/atomics.jlit introduces: add and min/max run forFloat32and, wheresupports_float64,Float64, for both Atomix and UnsafeAtomics. Merge [pocl] Enable float add and min/max atomics via cl_ext_float_atomics #737 first.skip_tests = Set(["Atomics"]).🤖 Generated with Claude Code