-
Notifications
You must be signed in to change notification settings - Fork 46
Add atomic float support #399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Your PR requires formatting changes to meet the project's style guidelines. Click here to view the suggested changes.diff --git a/lib/intrinsics/src/atomic.jl b/lib/intrinsics/src/atomic.jl
index a93f926..d627741 100644
--- a/lib/intrinsics/src/atomic.jl
+++ b/lib/intrinsics/src/atomic.jl
@@ -47,17 +47,21 @@ for gentype in atomic_types, as in atomic_memory_types
@device_function atomic_xor!(p::LLVMPtr{$gentype,$as}, val::$gentype) =
@builtin_ccall("atomic_xor", $gentype,
(LLVMPtr{$gentype,$as}, $gentype), p, val)
-end
-if gentype in atomic_integer_types
- @eval begin
- @device_function atomic_xchg!(p::LLVMPtr{$gentype,$as}, val::$gentype) =
- @builtin_ccall("atomic_xchg", $gentype,
- (LLVMPtr{$gentype,$as}, $gentype), p, val)
-
- @device_function atomic_cmpxchg!(p::LLVMPtr{$gentype,$as}, cmp::$gentype, val::$gentype) =
- @builtin_ccall("atomic_cmpxchg", $gentype,
- (LLVMPtr{$gentype,$as}, $gentype, $gentype), p, cmp, val)
end
+ if gentype in atomic_integer_types
+ @eval begin
+ @device_function atomic_xchg!(p::LLVMPtr{$gentype, $as}, val::$gentype) =
+ @builtin_ccall(
+ "atomic_xchg", $gentype,
+ (LLVMPtr{$gentype, $as}, $gentype), p, val
+ )
+
+ @device_function atomic_cmpxchg!(p::LLVMPtr{$gentype, $as}, cmp::$gentype, val::$gentype) =
+ @builtin_ccall(
+ "atomic_cmpxchg", $gentype,
+ (LLVMPtr{$gentype, $as}, $gentype, $gentype), p, cmp, val
+ )
+ end
end
end
diff --git a/test/atomics.jl b/test/atomics.jl
index bcfaa14..339d263 100644
--- a/test/atomics.jl
+++ b/test/atomics.jl
@@ -20,129 +20,129 @@ atomic_operations = [
(:atomic_cas!, 0, 1),
]
@testset "atomics" begin
-for (op, init_val, expected_val) in atomic_operations
- for T in all_types
- # Skip Int64/UInt64 if not supported
- if sizeof(T) == 8 && T <: Integer && !("cl_khr_int64_extended_atomics" in dev.extensions)
- continue
- end
+ for (op, init_val, expected_val) in atomic_operations
+ for T in all_types
+ # Skip Int64/UInt64 if not supported
+ if sizeof(T) == 8 && T <: Integer && !("cl_khr_int64_extended_atomics" in dev.extensions)
+ continue
+ end
- # Skip Float64 if not supported
- if T == Float64 && !("cl_khr_fp64" in dev.extensions)
- continue
- end
+ # Skip Float64 if not supported
+ if T == Float64 && !("cl_khr_fp64" in dev.extensions)
+ continue
+ end
- # Bitwise operations (only valid for integers)
- if op in [:atomic_and!, :atomic_or!, :atomic_xor!] && T <: AbstractFloat
- continue
- end
+ # Bitwise operations (only valid for integers)
+ if op in [:atomic_and!, :atomic_or!, :atomic_xor!] && T <: AbstractFloat
+ continue
+ end
- # Min/max operations (only supported for 32-bit integers in OpenCL)
- if op in [:atomic_min!, :atomic_max!] && !(T in [Int32, UInt32])
- continue
- end
+ # Min/max operations (only supported for 32-bit integers in OpenCL)
+ if op in [:atomic_min!, :atomic_max!] && !(T in [Int32, UInt32])
+ continue
+ end
- test_name = Symbol("test_", op, "_", T)
+ test_name = Symbol("test_", op, "_", T)
- if op in [:atomic_add!, :atomic_sub!]
- # Arithmetic operations
- if op == :atomic_add!
- @eval function $test_name(counter)
- OpenCL.@atomic counter[] += one($T)
- return
+ if op in [:atomic_add!, :atomic_sub!]
+ # Arithmetic operations
+ if op == :atomic_add!
+ @eval function $test_name(counter)
+ OpenCL.@atomic counter[] += one($T)
+ return
+ end
+ else
+ @eval function $test_name(counter)
+ OpenCL.@atomic counter[] -= one($T)
+ return
+ end
end
- else
- @eval function $test_name(counter)
- OpenCL.@atomic counter[] -= one($T)
- return
+ elseif op in [:atomic_and!, :atomic_or!, :atomic_xor!]
+ # Bitwise operations
+ if op == :atomic_and!
+ @eval function $test_name(counter)
+ OpenCL.@atomic counter[] &= one($T)
+ return
+ end
+ elseif op == :atomic_or!
+ @eval function $test_name(counter)
+ OpenCL.@atomic counter[] |= one($T)
+ return
+ end
+ else # xor
+ @eval function $test_name(counter)
+ OpenCL.@atomic counter[] ⊻= one($T)
+ return
+ end
end
- end
- elseif op in [:atomic_and!, :atomic_or!, :atomic_xor!]
- # Bitwise operations
- if op == :atomic_and!
- @eval function $test_name(counter)
- OpenCL.@atomic counter[] &= one($T)
- return
- end
- elseif op == :atomic_or!
- @eval function $test_name(counter)
- OpenCL.@atomic counter[] |= one($T)
- return
+ elseif op in [:atomic_max!, :atomic_min!]
+ # Min/max operations - use low-level API directly
+ if op == :atomic_max!
+ @eval function $test_name(counter)
+ ptr = OpenCL.pointer(counter, 1)
+ OpenCL.atomic_max!(ptr, one($T))
+ return
+ end
+ else
+ @eval function $test_name(counter)
+ ptr = OpenCL.pointer(counter, 1)
+ OpenCL.atomic_min!(ptr, one($T))
+ return
+ end
end
- else # xor
- @eval function $test_name(counter)
- OpenCL.@atomic counter[] ⊻= one($T)
- return
- end
- end
- elseif op in [:atomic_max!, :atomic_min!]
- # Min/max operations - use low-level API directly
- if op == :atomic_max!
+ elseif op == :atomic_xchg!
+ # Exchange operation - use low-level API directly
@eval function $test_name(counter)
ptr = OpenCL.pointer(counter, 1)
- OpenCL.atomic_max!(ptr, one($T))
+ OpenCL.atomic_xchg!(ptr, one($T))
return
end
- else
+ elseif op == :atomic_cas!
+ # CAS operation - use low-level API directly (it's called atomic_cmpxchg!)
@eval function $test_name(counter)
ptr = OpenCL.pointer(counter, 1)
- OpenCL.atomic_min!(ptr, one($T))
+ OpenCL.atomic_cmpxchg!(ptr, $T(0), one($T))
return
end
+ else
+ error("Unknown operation: $op")
end
- elseif op == :atomic_xchg!
- # Exchange operation - use low-level API directly
- @eval function $test_name(counter)
- ptr = OpenCL.pointer(counter, 1)
- OpenCL.atomic_xchg!(ptr, one($T))
- return
- end
- elseif op == :atomic_cas!
- # CAS operation - use low-level API directly (it's called atomic_cmpxchg!)
- @eval function $test_name(counter)
- ptr = OpenCL.pointer(counter, 1)
- OpenCL.atomic_cmpxchg!(ptr, $T(0), one($T))
- return
- end
- else
- error("Unknown operation: $op")
- end
- # Try to compile the kernel - this is the key test
+ # Try to compile the kernel - this is the key test
a = OpenCL.zeros(T)
- OpenCL.fill!(a, init_val)
- kernel_func = @eval $test_name
- OpenCL.@opencl global_size=1000 kernel_func(a)
- result_val = Array(a)[1]
- @test typeof(result_val) == T
- @test result_val == T(expected_val)
+ OpenCL.fill!(a, init_val)
+ kernel_func = @eval $test_name
+ OpenCL.@opencl global_size = 1000 kernel_func(a)
+ result_val = Array(a)[1]
+ @test typeof(result_val) == T
+ @test result_val == T(expected_val)
end
end
-@testset "atomic_add! ($T)" for T in [Float32, Float64]
- # Float64 requires cl_khr_fp64 extension
- if T == Float64 && !("cl_khr_fp64" in cl.device().extensions)
- continue
- end
+ @testset "atomic_add! ($T)" for T in [Float32, Float64]
+ # Float64 requires cl_khr_fp64 extension
+ if T == Float64 && !("cl_khr_fp64" in cl.device().extensions)
+ continue
+ end
if "cl_ext_float_atomics" in cl.device().extensions
- @eval function atomic_float_add(counter, val::$T)
+ @eval function atomic_float_add(counter, val::$T)
@builtin_ccall(
- "atomic_add", $T,
- (LLVMPtr{$T, AS.CrossWorkgroup}, $T),
+ "atomic_add", $T,
+ (LLVMPtr{$T, AS.CrossWorkgroup}, $T),
pointer(counter), val,
)
return
end
@testset "SPV_EXT_shader_atomic_float_add extension" begin
- a = OpenCL.zeros(T)
- @opencl global_size = 1000 extensions = ["SPV_EXT_shader_atomic_float_add"] atomic_float_add(a, one(T))
- @test OpenCL.@allowscalar a[] == T(1000.0)
+ a = OpenCL.zeros(T)
+ @opencl global_size = 1000 extensions = ["SPV_EXT_shader_atomic_float_add"] atomic_float_add(a, one(T))
+ @test OpenCL.@allowscalar a[] == T(1000.0)
spv = sprint() do io
- OpenCL.code_native(io, atomic_float_add, Tuple{CLDeviceArray{T, 0, 1}, T}; extensions = ["SPV_EXT_shader_atomic_float_add"])
+ OpenCL.code_native(io, atomic_float_add, Tuple{CLDeviceArray{T, 0, 1}, T}; extensions = ["SPV_EXT_shader_atomic_float_add"])
end
@test occursin("OpExtension \"SPV_EXT_shader_atomic_float_add\"", spv)
@test occursin("OpAtomicFAddEXT", spv) |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #399 +/- ##
==========================================
+ Coverage 80.27% 80.68% +0.41%
==========================================
Files 12 12
Lines 730 730
==========================================
+ Hits 586 589 +3
+ Misses 144 141 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Bump. Can someone take a look? @vchuravy ? I don't see how the failing tests are connected to the changes here. |
|
Thanks. Can you add a test that works here too? |
1ac8383 to
e962893
Compare
|
@maleadt Added tests and rebased. |
simeonschaub
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test can now be modified to actually call the atomic_add! method from SPIRVIntrinsics instead of defining its own function. It is also not exercising the Float64 path ATM, since Float32 is hard coded inside the test.
Ideally, we would also be testing the other atomic intrinsics that have been defined for Float32 and Float64 now. (Are the bitwise intrinsics like atomic_or! and friends even defined for floats?)
|
@simeonschaub I tried to add more tests, but except for Can we remove the |
|
A restful night resolved the issues. This should pass now. A few comments:
|
|
@simeonschaub @maleadt @vchuravy Bump. I don't think the errors are related to my code changes. |
8d36d26 to
58f3b27
Compare
JuliaGPU/oneAPI.jl#544 Adding the
SPV_EXT_shader_atomic_float_addextension in oneAPI.jl seems to work.