Repository navigation
Complete the GPU extensions: atomic get/set, swap, float min/max - #80
Merged
Merged
Conversation
The CUDA, oneAPI, OpenCL and Metal extensions implemented `Atomix.get`
and `Atomix.set!` as `error("not implemented")`, and `modify!` errored
for any operation without a listed backend intrinsic. As a result
`@atomic A[i]`, `@atomic A[i] = v`, `@atomicswap`, and float `max`/`min`
threw inside kernels (silently, on backends that do not report device
exceptions).
- `get`/`set!` now use the generic implementation: an LLVM atomic
load/store through UnsafeAtomicsLLVM, honoring the ordering. Metal uses
its `atomic_load_explicit`/`atomic_store_explicit` intrinsics instead.
- Swap dispatches to the backend's exchange intrinsic; floats on CUDA go
through their integer representation.
- Operations without a native instruction (float min/max where the
backend lacks them, arbitrary functions) use a compare-and-swap loop
that compares bitwise, so NaN and signed zeros cannot make it spin.
- Native dispatch is by element type, so unsupported types fall back
instead of hitting a MethodError.
Adds get/set, swap, ordering and floating-point tests for each backend.
Assisted-by: Claude Code (Fable 5.1)
This was referenced Sep 8, 2026
vchuravy
added a commit
to JuliaGPU/KernelAbstractions.jl
that referenced
this pull request
Sep 8, 2026
Atomix 1.2 completes its GPU extensions (JuliaConcurrent/Atomix.jl#80): atomic load/store, swap, and a compare-and-swap fallback for operations without a native instruction, such as floating-point min/max on CUDA. With that, float min/max is portable again, so run the min/max testsuite cases for floats as well and update the "Supported operations" table. Assisted-by: Claude Code (Fable 5.1)
Contributor
|
@vchuravy I compiled a list of PRs/issues I think this may have closed: |
This was referenced Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The CUDA, oneAPI, OpenCL and Metal extensions implemented
Atomix.getandAtomix.set!aserror("not implemented"), andmodify!errored for any operation without a listed backend intrinsic. So inside kernels@atomic A[i],@atomic A[i] = v,@atomicswap A[i] = v(which ismodify!withright) and float@atomic max(A[i], x)/minall threw — silently on backends that do not surface device exceptions (pocl leaves the array untouched), and with aMethodErroron CUDA, whoseatomic_max!/atomic_min!only exist for integers. This surfaced in JuliaGPU/KernelAbstractions.jl#726 and #737.Changes
get/set!: the overrides are removed, so Atomix's generic implementation applies: an LLVM atomic load/store on the device pointer through UnsafeAtomicsLLVM, which honors the requested ordering. Metal uses itsatomic_load_explicit/atomic_store_explicitintrinsics instead, since Metal.jl does not lower LLVM atomics.modify!withrightdispatches to the backend's exchange intrinsic. On CUDA, floats are exchanged through their integer representation (atomic_xchg!is integer-only there).*): a compare-and-swap loop on the backend's CAS. It compares bitwise (===), so a stored NaN or a signed zero cannot make it spin. On OpenCL/oneAPI the float min/max intrinsics are used when the installed SPIRVIntrinsics provides them (checked withhasmethodat extension load), otherwise the loop.Int32/Int64/UInt32/UInt64,Float32/Float64;Int32/UInt32/Float32on Metal), everything else takes the CAS path instead of aMethodError. Float64 add on CUDA checks the compute capability, as CUDA.jl's ownatomic_arraysetdoes.TODO.Tests
Each backend test file gains
test_get_set(including the@atomic A[i]/@atomic :monotonic A[i] = vsugar),test_swap(Atomix.swap!and@atomicswap),test_ordering, andtest_float(add, sub, max, min, and*via the CAS loop). The stale "Not implemented" comment blocks are gone.Run locally on Julia 1.10:
--CUDA(CUDA v6.3.1, Quadro RTX 4000): 8/8 testsets pass.--OpenCL(OpenCL v0.10.11, pocl 7.1): 8/8 testsets pass.OpenCLBackend/pocl: 38/38 pass, where 5 failed before.🤖 Generated with Claude Code
https://claude.ai/code/session_01DnYMbgSmZQr7KtRUwei63a