1
1
# Atomic Functions
2
2
3
- # TODO : support for 64-bit atomics via atom_cmpxchg (from cl_khr_int64_base_atomics)
3
+ # provides atomic functions that rely on the OpenCL base atomics, as well as the
4
+ # cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics extensions.
4
5
5
- # "atomic operations on 32-bit signed, unsigned integers and single precision
6
- # floating-point to locations in __global or __local memory"
7
-
8
- const atomic_integer_types = [UInt32, Int32]
9
- # TODO : 64-bit atomics with ZE_DEVICE_MODULE_FLAG_INT64_ATOMICS
10
- # TODO : additional floating-point atomics with ZE_extension_float_atomics
6
+ const atomic_integer_types = [UInt32, Int32, UInt64, Int64]
11
7
const atomic_memory_types = [AS. Workgroup, AS. CrossWorkgroup]
12
8
13
9
67
63
for as in atomic_memory_types
68
64
@eval begin
69
65
66
+ # There is native support for atomic_xchg on Float32, but not for Float64,
67
+ # so we always reinterpret for consistency.
70
68
@device_function atomic_xchg! (p:: LLVMPtr{Float32,$as} , val:: Float32 ) =
71
- @builtin_ccall (" atomic_xchg" , Float32, (LLVMPtr{Float32,$ as}, Float32,), p, val)
69
+ reinterpret (Float32, atomic_xchg! (reinterpret (LLVMPtr{UInt32,$ as}, p),
70
+ reinterpret (UInt32, val)))
71
+ @device_function atomic_xchg! (p:: LLVMPtr{Float64,$as} , val:: Float64 ) =
72
+ reinterpret (Float64, atomic_xchg! (reinterpret (LLVMPtr{UInt64,$ as}, p),
73
+ reinterpret (UInt64, val)))
72
74
73
- # XXX : why is only xchg supported on floats? isn't it safe for cmpxchg too,
74
- # which should only perform bitwise comparisons?
75
75
@device_function atomic_cmpxchg! (p:: LLVMPtr{Float32,$as} , cmp:: Float32 , val:: Float32 ) =
76
76
reinterpret (Float32, atomic_cmpxchg! (reinterpret (LLVMPtr{UInt32,$ as}, p),
77
77
reinterpret (UInt32, cmp),
78
78
reinterpret (UInt32, val)))
79
+ @device_function atomic_cmpxchg! (p:: LLVMPtr{Float64,$as} , cmp:: Float64 , val:: Float64 ) =
80
+ reinterpret (Float64, atomic_cmpxchg! (reinterpret (LLVMPtr{UInt64,$ as}, p),
81
+ reinterpret (UInt64, cmp),
82
+ reinterpret (UInt64, val)))
79
83
80
84
end
81
85
end
239
243
atomic_arrayset (A, Base. _to_linear_index (A, Is... ), op, convert (T, val))
240
244
241
245
# native atomics
246
+ # TODO : support inc/dec
247
+ # TODO : this depends on available extensions
248
+ # - UInt64: requires cl_khr_int64_base_atomics for add/sub/inc/dec,
249
+ # requires cl_khr_int64_extended_atomics for min/max/and/or/xor
250
+ # - Float64: always should hit the fallback
242
251
for (op,impl) in [(+ ) => atomic_add!,
243
252
(- ) => atomic_sub!,
244
253
(& ) => atomic_and!,
@@ -247,11 +256,12 @@ for (op,impl) in [(+) => atomic_add!,
247
256
Base. max => atomic_max!,
248
257
Base. min => atomic_min!]
249
258
@eval @inline atomic_arrayset (A:: AbstractArray{T} , I:: Integer , :: typeof ($ op),
250
- val:: T ) where {T <: Union{Int32,UInt32 } } =
259
+ val:: T ) where {T <: Union{atomic_integer_types... } } =
251
260
$ impl (pointer (A, I), val)
252
261
end
253
262
254
263
# fallback using compare-and-swap
264
+ # TODO : for 64-bit types, this depends on cl_khr_int64_base_atomics
255
265
function atomic_arrayset (A:: AbstractArray{T} , I:: Integer , op:: Function , val) where {T}
256
266
ptr = pointer (A, I)
257
267
old = Base. unsafe_load (ptr, 1 )
0 commit comments