44@inline UnsafeAtomics. modify!(ptr, op, x) = UnsafeAtomics. modify!(ptr, op, x, seq_cst)
55@inline UnsafeAtomics. fence() = UnsafeAtomics. fence(seq_cst)
66
7+ @inline UnsafeAtomics. load(x, ord) = UnsafeAtomics. load(x, ord, none)
8+ @inline UnsafeAtomics. store!(x, v, ord) = UnsafeAtomics. store!(x, v, ord, none)
9+ @inline UnsafeAtomics. cas!(x, cmp, new, ord) = UnsafeAtomics. cas!(x, cmp, new, ord, ord, none)
10+ @inline UnsafeAtomics. modify!(ptr, op, x, ord) = UnsafeAtomics. modify!(ptr, op, x, ord, none)
11+ @inline UnsafeAtomics. fence(ord) = UnsafeAtomics. fence(ord, none)
12+
713# ! format: off
814# https://github.com/JuliaLang/julia/blob/v1.6.3/base/atomics.jl#L23-L30
915if Sys. ARCH == :i686 || startswith(string(Sys. ARCH), " arm" ) ||
@@ -45,8 +51,9 @@ const OP_RMW_TABLE = [
4551for (op, rmwop) in OP_RMW_TABLE
4652 fn = Symbol(rmwop, " !" )
4753 @eval @inline UnsafeAtomics.$ fn(x, v) = UnsafeAtomics.$ fn(x, v, seq_cst)
48- @eval @inline UnsafeAtomics.$ fn(ptr, x, ord) =
49- first(UnsafeAtomics. modify!(ptr, $ op, x, ord))
54+ @eval @inline UnsafeAtomics.$ fn(x, v, ord) = UnsafeAtomics.$ fn(x, v, ord, none)
55+ @eval @inline UnsafeAtomics.$ fn(ptr, x, ord, scope) =
56+ first(UnsafeAtomics. modify!(ptr, $ op, x, ord, scope))
5057end
5158
5259const ATOMIC_INTRINSICS = isdefined(Core. Intrinsics, :atomic_pointerref)
@@ -67,47 +74,51 @@ for typ in (inttypes..., floattypes...)
6774 for ord in orderings
6875 ord in (release, acq_rel) && continue
6976
70- if ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE
71- @eval function UnsafeAtomics. load(x:: Ptr{$typ} , :: $ (typeof(ord)))
72- return Core. Intrinsics. atomic_pointerref(x, base_ordering($ ord))
73- end
74- else
75- @eval function UnsafeAtomics. load(x:: Ptr{$typ} , :: $ (typeof(ord)))
76- return llvmcall(
77- $ ("""
78- %ptr = inttoptr i$WORD_SIZE %0 to $lt *
79- %rv = load atomic $rt %ptr $ord , align $(sizeof(typ))
80- ret $lt %rv
81- """ ),
82- $ typ,
83- Tuple{Ptr{$ typ}},
84- x,
85- )
77+ for sync in syncscopes
78+ if ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE && sync == none
79+ @eval function UnsafeAtomics. load(x:: Ptr{$typ} , :: $ (typeof(ord)), :: $ (typeof(sync)))
80+ return Core. Intrinsics. atomic_pointerref(x, base_ordering($ ord))
81+ end
82+ else
83+ @eval function UnsafeAtomics. load(x:: Ptr{$typ} , :: $ (typeof(ord)), :: $ (typeof(sync)))
84+ return llvmcall(
85+ $ ("""
86+ %ptr = inttoptr i$WORD_SIZE %0 to $lt *
87+ %rv = load atomic $rt %ptr $ord , align $(sizeof(typ))
88+ ret $lt %rv
89+ """ ),
90+ $ typ,
91+ Tuple{Ptr{$ typ}},
92+ x,
93+ )
94+ end
8695 end
8796 end
8897 end
8998
9099 for ord in orderings
91100 ord in (acquire, acq_rel) && continue
92-
93- if ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE
94- @eval function UnsafeAtomics. store!(x:: Ptr{$typ} , v:: $typ , :: $ (typeof(ord)))
95- Core. Intrinsics. atomic_pointerset(x, v, base_ordering($ ord))
96- return nothing
97- end
98- else
99- @eval function UnsafeAtomics. store!(x:: Ptr{$typ} , v:: $typ , :: $ (typeof(ord)))
100- return llvmcall(
101- $ ("""
102- %ptr = inttoptr i$WORD_SIZE %0 to $lt *
103- store atomic $lt %1, $lt * %ptr $ord , align $(sizeof(typ))
104- ret void
105- """ ),
106- Cvoid,
107- Tuple{Ptr{$ typ},$ typ},
108- x,
109- v,
110- )
101+
102+ for sync in syncscopes
103+ if ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE && sync == none
104+ @eval function UnsafeAtomics. store!(x:: Ptr{$typ} , v:: $typ , :: $ (typeof(ord)), :: $ (typeof(sync)))
105+ Core. Intrinsics. atomic_pointerset(x, v, base_ordering($ ord))
106+ return nothing
107+ end
108+ else
109+ @eval function UnsafeAtomics. store!(x:: Ptr{$typ} , v:: $typ , :: $ (typeof(ord)), :: $ (typeof(sync)))
110+ return llvmcall(
111+ $ ("""
112+ %ptr = inttoptr i$WORD_SIZE %0 to $lt *
113+ store atomic $lt %1, $lt * %ptr $ord , align $(sizeof(typ))
114+ ret void
115+ """ ),
116+ Cvoid,
117+ Tuple{Ptr{$ typ},$ typ},
118+ x,
119+ v,
120+ )
121+ end
111122 end
112123 end
113124 end
@@ -117,54 +128,58 @@ for typ in (inttypes..., floattypes...)
117128
118129 typ <: AbstractFloat && break
119130
120- if ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE
121- @eval function UnsafeAtomics. cas!(
122- x:: Ptr{$typ} ,
123- cmp:: $typ ,
124- new:: $typ ,
125- :: $ (typeof(success_ordering)),
126- :: $ (typeof(failure_ordering)),
127- )
128- return Core. Intrinsics. atomic_pointerreplace(
129- x,
130- cmp,
131- new,
132- base_ordering($ success_ordering),
133- base_ordering($ failure_ordering)
131+ for sync in syncscopes
132+ if ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE && sync == none
133+ @eval function UnsafeAtomics. cas!(
134+ x:: Ptr{$typ} ,
135+ cmp:: $typ ,
136+ new:: $typ ,
137+ :: $ (typeof(success_ordering)),
138+ :: $ (typeof(failure_ordering)),
139+ :: $ (typeof(sync)),
134140 )
135- end
136- else
137- @eval function UnsafeAtomics. cas!(
138- x:: Ptr{$typ} ,
139- cmp:: $typ ,
140- new:: $typ ,
141- :: $ (typeof(success_ordering)),
142- :: $ (typeof(failure_ordering)),
143- )
144- success = Ref{Int8}()
145- GC. @preserve success begin
146- old = llvmcall(
147- $ (
148- """
149- %ptr = inttoptr i$WORD_SIZE %0 to $lt *
150- %rs = cmpxchg $lt * %ptr, $lt %1, $lt %2 $success_ordering $failure_ordering
151- %rv = extractvalue { $lt , i1 } %rs, 0
152- %s1 = extractvalue { $lt , i1 } %rs, 1
153- %s8 = zext i1 %s1 to i8
154- %sptr = inttoptr i$WORD_SIZE %3 to i8*
155- store i8 %s8, i8* %sptr
156- ret $lt %rv
157- """
158- ),
159- $ typ,
160- Tuple{Ptr{$ typ},$ typ,$ typ,Ptr{Int8}},
141+ return Core. Intrinsics. atomic_pointerreplace(
161142 x,
162143 cmp,
163144 new,
164- Ptr{Int8}(pointer_from_objref(success)),
145+ base_ordering($ success_ordering),
146+ base_ordering($ failure_ordering)
165147 )
166148 end
167- return (old = old, success = ! iszero(success[]))
149+ else
150+ @eval function UnsafeAtomics. cas!(
151+ x:: Ptr{$typ} ,
152+ cmp:: $typ ,
153+ new:: $typ ,
154+ :: $ (typeof(success_ordering)),
155+ :: $ (typeof(failure_ordering)),
156+ :: $ (typeof(sync)),
157+ )
158+ success = Ref{Int8}()
159+ GC. @preserve success begin
160+ old = llvmcall(
161+ $ (
162+ """
163+ %ptr = inttoptr i$WORD_SIZE %0 to $lt *
164+ %rs = cmpxchg $lt * %ptr, $lt %1, $lt %2 $success_ordering $failure_ordering
165+ %rv = extractvalue { $lt , i1 } %rs, 0
166+ %s1 = extractvalue { $lt , i1 } %rs, 1
167+ %s8 = zext i1 %s1 to i8
168+ %sptr = inttoptr i$WORD_SIZE %3 to i8*
169+ store i8 %s8, i8* %sptr
170+ ret $lt %rv
171+ """
172+ ),
173+ $ typ,
174+ Tuple{Ptr{$ typ},$ typ,$ typ,Ptr{Int8}},
175+ x,
176+ cmp,
177+ new,
178+ Ptr{Int8}(pointer_from_objref(success)),
179+ )
180+ end
181+ return (old = old, success = ! iszero(success[]))
182+ end
168183 end
169184 end
170185 end
@@ -186,60 +201,81 @@ for typ in (inttypes..., floattypes...)
186201 end
187202 end
188203 for ord in orderings
189- # Enable this code iff https://github.com/JuliaLang/julia/pull/45122 get's merged
190- if false && ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE
191- @eval function UnsafeAtomics. modify!(
204+ for sync in syncscopes
205+ # Enable this code iff https://github.com/JuliaLang/julia/pull/45122 get's merged
206+ if false && ATOMIC_INTRINSICS && sizeof(typ) <= MAX_POINTERATOMIC_SIZE && sync == none
207+ @eval function UnsafeAtomics. modify!(
208+ x:: Ptr{$typ} ,
209+ op:: typeof ($ op),
210+ v:: $typ ,
211+ :: $ (typeof(ord)),
212+ :: $ (typeof(sync)),
213+ )
214+ return Core. Intrinsics. atomic_pointermodify(x, op, v, base_ordering($ ord))
215+ end
216+ else
217+ @eval function UnsafeAtomics. modify!(
192218 x:: Ptr{$typ} ,
193- op :: typeof ($ op),
219+ :: typeof ($ op),
194220 v:: $typ ,
195221 :: $ (typeof(ord)),
222+ :: $ (typeof(sync)),
196223 )
197- return Core. Intrinsics. atomic_pointermodify(x, op, v, base_ordering($ ord))
198- end
199- else
200- @eval function UnsafeAtomics. modify!(
201- x:: Ptr{$typ} ,
202- :: typeof ($ op),
203- v:: $typ ,
204- :: $ (typeof(ord)),
205- )
206- old = llvmcall(
207- $ ("""
208- %ptr = inttoptr i$WORD_SIZE %0 to $lt *
209- %rv = atomicrmw $rmw $lt * %ptr, $lt %1 $ord
210- ret $lt %rv
211- """ ),
212- $ typ,
213- Tuple{Ptr{$ typ},$ typ},
214- x,
215- v,
216- )
217- return old => $ op(old, v)
224+ old = llvmcall(
225+ $ ("""
226+ %ptr = inttoptr i$WORD_SIZE %0 to $lt *
227+ %rv = atomicrmw $rmw $lt * %ptr, $lt %1 $ord
228+ ret $lt %rv
229+ """ ),
230+ $ typ,
231+ Tuple{Ptr{$ typ},$ typ},
232+ x,
233+ v,
234+ )
235+ return old => $ op(old, v)
236+ end
218237 end
219238 end
220239 end
221240 end
222241end
223242
224- # Core.Intrinsics.atomic_fence was introduced in 1.10
225- function UnsafeAtomics. fence(ord:: Ordering )
226- Core. Intrinsics. atomic_fence(base_ordering(ord))
227- return nothing
228- end
229- if Sys. ARCH == :x86_64
230- # FIXME : Disable this once on LLVM 19
231- # This is unfortunatly required for good-performance on AMD
232- # https://github.com/llvm/llvm-project/pull/106555
233- function UnsafeAtomics. fence(:: typeof (seq_cst))
234- Base. llvmcall(
235- (raw """
236- define void @fence() #0 {
237- entry:
238- tail call void asm sideeffect "lock orq $$0 , (%rsp)", ""(); should this have ~{memory}
239- ret void
240- }
241- attributes #0 = { alwaysinline }
242- """ , " fence" ), Nothing, Tuple{})
243+ for sync in syncscopes
244+ if sync == none
245+ # Core.Intrinsics.atomic_fence was introduced in 1.10
246+ @eval function UnsafeAtomics. fence(ord:: Ordering , :: $ (typeof(sync)))
247+ Core. Intrinsics. atomic_fence(base_ordering(ord))
248+ return nothing
249+ end
250+ if Sys. ARCH == :x86_64
251+ # FIXME : Disable this once on LLVM 19
252+ # This is unfortunatly required for good-performance on AMD
253+ # https://github.com/llvm/llvm-project/pull/106555
254+ @eval function UnsafeAtomics. fence(:: typeof (seq_cst), :: $ (typeof(sync)))
255+ Base. llvmcall(
256+ (raw """
257+ define void @fence() #0 {
258+ entry:
259+ tail call void asm sideeffect "lock orq $$0 , (%rsp)", ""(); should this have ~{memory}
260+ ret void
261+ }
262+ attributes #0 = { alwaysinline }
263+ """ , " fence" ), Nothing, Tuple{})
264+ end
265+ end
266+ else
267+ for ord in orderings
268+ @eval function UnsafeAtomics. fence(:: $ (typeof(ord)), :: $ (typeof(sync)))
269+ return llvmcall(
270+ $ ("""
271+ fence $sync $ord
272+ ret void
273+ """ ),
274+ Cvoid,
275+ Tuple{},
276+ )
277+ end
278+ end
243279 end
244280end
245281
0 commit comments