1#[cfg(target_arch = "spirv")]
2use core::arch::asm;
3
4use crate::{
5 float::Float,
6 integer::{Integer, SignedInteger, UnsignedInteger},
7 number::Number,
8};
9
10#[spirv_std_macros::gpu_only]
14#[doc(alias = "OpAtomicLoad")]
15#[inline]
16pub unsafe fn atomic_load<N: Number, const SCOPE: u32, const SEMANTICS: u32>(ptr: &N) -> N {
17 let mut result = N::default();
18
19 asm! {
20 "%u32 = OpTypeInt 32 0",
21 "%scope = OpConstant %u32 {scope}",
22 "%semantics = OpConstant %u32 {semantics}",
23 "%result = OpAtomicLoad _ {ptr} %scope %semantics",
24 "OpStore {result} %result",
25 scope = const SCOPE,
26 semantics = const SEMANTICS,
27 ptr = in(reg) ptr,
28 result = in(reg) &mut result
29 }
30
31 result
32}
33
34#[spirv_std_macros::gpu_only]
38#[doc(alias = "OpAtomicStore")]
39#[inline]
40pub unsafe fn atomic_store<N: Number, const SCOPE: u32, const SEMANTICS: u32>(
41 ptr: &mut N,
42 value: N,
43) {
44 asm! {
45 "%u32 = OpTypeInt 32 0",
46 "%scope = OpConstant %u32 {scope}",
47 "%semantics = OpConstant %u32 {semantics}",
48 "%value = OpLoad _ {value}",
49 "OpAtomicStore {ptr} %scope %semantics %value",
50 scope = const SCOPE,
51 semantics = const SEMANTICS,
52 ptr = in(reg) ptr,
53 value = in(reg) &value
54 }
55}
56
57#[spirv_std_macros::gpu_only]
66#[doc(alias = "OpAtomicExchange")]
67#[inline]
68pub unsafe fn atomic_exchange<N: Number, const SCOPE: u32, const SEMANTICS: u32>(
69 ptr: &mut N,
70 value: N,
71) -> N {
72 let mut old = N::default();
73
74 asm! {
75 "%u32 = OpTypeInt 32 0",
76 "%scope = OpConstant %u32 {scope}",
77 "%semantics = OpConstant %u32 {semantics}",
78 "%value = OpLoad _ {value}",
79 "%old = OpAtomicExchange _ {ptr} %scope %semantics %value",
80 "OpStore {old} %old",
81 scope = const SCOPE,
82 semantics = const SEMANTICS,
83 ptr = in(reg) ptr,
84 old = in(reg) &mut old,
85 value = in(reg) &value
86 }
87
88 old
89}
90
91#[spirv_std_macros::gpu_only]
102#[doc(alias = "OpAtomicCompareExchange")]
103#[inline]
104pub unsafe fn atomic_compare_exchange<
105 I: Integer,
106 const SCOPE: u32,
107 const EQUAL: u32,
108 const UNEQUAL: u32,
109>(
110 ptr: &mut I,
111 value: I,
112 comparator: I,
113) -> I {
114 let mut old = I::default();
115
116 asm! {
117 "%u32 = OpTypeInt 32 0",
118 "%scope = OpConstant %u32 {scope}",
119 "%equal = OpConstant %u32 {equal}",
120 "%unequal = OpConstant %u32 {unequal}",
121 "%value = OpLoad _ {value}",
122 "%comparator = OpLoad _ {comparator}",
123 "%old = OpAtomicCompareExchange _ {ptr} %scope %equal %unequal %value %comparator",
124 "OpStore {old} %old",
125 scope = const SCOPE,
126 equal = const EQUAL,
127 unequal = const UNEQUAL,
128 ptr = in(reg) ptr,
129 value = in(reg) &value,
130 comparator = in(reg) &comparator,
131 old = in(reg) &mut old,
132 }
133
134 old
135}
136
137#[spirv_std_macros::gpu_only]
146#[doc(alias = "OpAtomicIIncrement")]
147#[inline]
148pub unsafe fn atomic_i_increment<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
149 ptr: &mut I,
150) -> I {
151 let mut old = I::default();
152
153 asm! {
154 "%u32 = OpTypeInt 32 0",
155 "%scope = OpConstant %u32 {scope}",
156 "%semantics = OpConstant %u32 {semantics}",
157 "%old = OpAtomicIIncrement _ {ptr} %scope %semantics",
158 "OpStore {old} %old",
159 scope = const SCOPE,
160 semantics = const SEMANTICS,
161 ptr = in(reg) ptr,
162 old = in(reg) &mut old
163 }
164
165 old
166}
167
168#[spirv_std_macros::gpu_only]
177#[doc(alias = "OpAtomicIDecrement")]
178#[inline]
179pub unsafe fn atomic_i_decrement<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
180 ptr: &mut I,
181) -> I {
182 let mut old = I::default();
183
184 asm! {
185 "%u32 = OpTypeInt 32 0",
186 "%scope = OpConstant %u32 {scope}",
187 "%semantics = OpConstant %u32 {semantics}",
188 "%old = OpAtomicIDecrement _ {ptr} %scope %semantics",
189 "OpStore {old} %old",
190 scope = const SCOPE,
191 semantics = const SEMANTICS,
192 ptr = in(reg) ptr,
193 old = in(reg) &mut old
194 }
195
196 old
197}
198
199#[spirv_std_macros::gpu_only]
208#[doc(alias = "OpAtomicIAdd")]
209#[inline]
210pub unsafe fn atomic_i_add<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
211 ptr: &mut I,
212 value: I,
213) -> I {
214 let mut old = I::default();
215
216 asm! {
217 "%u32 = OpTypeInt 32 0",
218 "%scope = OpConstant %u32 {scope}",
219 "%semantics = OpConstant %u32 {semantics}",
220 "%value = OpLoad _ {value}",
221 "%old = OpAtomicIAdd _ {ptr} %scope %semantics %value",
222 "OpStore {old} %old",
223 scope = const SCOPE,
224 semantics = const SEMANTICS,
225 ptr = in(reg) ptr,
226 old = in(reg) &mut old,
227 value = in(reg) &value
228 }
229
230 old
231}
232
233#[spirv_std_macros::gpu_only]
242#[doc(alias = "OpAtomicISub")]
243#[inline]
244pub unsafe fn atomic_i_sub<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
245 ptr: &mut I,
246 value: I,
247) -> I {
248 let mut old = I::default();
249
250 asm! {
251 "%u32 = OpTypeInt 32 0",
252 "%scope = OpConstant %u32 {scope}",
253 "%semantics = OpConstant %u32 {semantics}",
254 "%value = OpLoad _ {value}",
255 "%old = OpAtomicISub _ {ptr} %scope %semantics %value",
256 "OpStore {old} %old",
257 scope = const SCOPE,
258 semantics = const SEMANTICS,
259 ptr = in(reg) ptr,
260 old = in(reg) &mut old,
261 value = in(reg) &value
262 }
263
264 old
265}
266
267#[spirv_std_macros::gpu_only]
277#[doc(alias = "OpAtomicSMin")]
278#[inline]
279pub unsafe fn atomic_s_min<S: SignedInteger, const SCOPE: u32, const SEMANTICS: u32>(
280 ptr: &mut S,
281 value: S,
282) -> S {
283 let mut old = S::default();
284
285 asm! {
286 "%u32 = OpTypeInt 32 0",
287 "%scope = OpConstant %u32 {scope}",
288 "%semantics = OpConstant %u32 {semantics}",
289 "%value = OpLoad _ {value}",
290 "%old = OpAtomicSMin _ {ptr} %scope %semantics %value",
291 "OpStore {old} %old",
292 scope = const SCOPE,
293 semantics = const SEMANTICS,
294 ptr = in(reg) ptr,
295 old = in(reg) &mut old,
296 value = in(reg) &value
297 }
298
299 old
300}
301
302#[spirv_std_macros::gpu_only]
312#[doc(alias = "OpAtomicUMin")]
313#[inline]
314pub unsafe fn atomic_u_min<U: UnsignedInteger, const SCOPE: u32, const SEMANTICS: u32>(
315 ptr: &mut U,
316 value: U,
317) -> U {
318 let mut old = U::default();
319
320 asm! {
321 "%u32 = OpTypeInt 32 0",
322 "%scope = OpConstant %u32 {scope}",
323 "%semantics = OpConstant %u32 {semantics}",
324 "%value = OpLoad _ {value}",
325 "%old = OpAtomicUMin _ {ptr} %scope %semantics %value",
326 "OpStore {old} %old",
327 scope = const SCOPE,
328 semantics = const SEMANTICS,
329 ptr = in(reg) ptr,
330 old = in(reg) &mut old,
331 value = in(reg) &value
332 }
333
334 old
335}
336
337#[spirv_std_macros::gpu_only]
347#[doc(alias = "OpAtomicSMax")]
348#[inline]
349pub unsafe fn atomic_s_max<S: SignedInteger, const SCOPE: u32, const SEMANTICS: u32>(
350 ptr: &mut S,
351 value: S,
352) -> S {
353 let mut old = S::default();
354
355 asm! {
356 "%u32 = OpTypeInt 32 0",
357 "%scope = OpConstant %u32 {scope}",
358 "%semantics = OpConstant %u32 {semantics}",
359 "%value = OpLoad _ {value}",
360 "%old = OpAtomicSMax _ {ptr} %scope %semantics %value",
361 "OpStore {old} %old",
362 scope = const SCOPE,
363 semantics = const SEMANTICS,
364 ptr = in(reg) ptr,
365 old = in(reg) &mut old,
366 value = in(reg) &value
367 }
368
369 old
370}
371
372#[spirv_std_macros::gpu_only]
382#[doc(alias = "OpAtomicUMax")]
383#[inline]
384pub unsafe fn atomic_u_max<U: UnsignedInteger, const SCOPE: u32, const SEMANTICS: u32>(
385 ptr: &mut U,
386 value: U,
387) -> U {
388 let mut old = U::default();
389
390 asm! {
391 "%u32 = OpTypeInt 32 0",
392 "%scope = OpConstant %u32 {scope}",
393 "%semantics = OpConstant %u32 {semantics}",
394 "%value = OpLoad _ {value}",
395 "%old = OpAtomicUMax _ {ptr} %scope %semantics %value",
396 "OpStore {old} %old",
397 scope = const SCOPE,
398 semantics = const SEMANTICS,
399 ptr = in(reg) ptr,
400 old = in(reg) &mut old,
401 value = in(reg) &value
402 }
403
404 old
405}
406
407#[spirv_std_macros::gpu_only]
416#[doc(alias = "OpAtomicAnd")]
417#[inline]
418pub unsafe fn atomic_and<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
419 ptr: &mut I,
420 value: I,
421) -> I {
422 let mut old = I::default();
423
424 asm! {
425 "%u32 = OpTypeInt 32 0",
426 "%scope = OpConstant %u32 {scope}",
427 "%semantics = OpConstant %u32 {semantics}",
428 "%value = OpLoad _ {value}",
429 "%old = OpAtomicAnd _ {ptr} %scope %semantics %value",
430 "OpStore {old} %old",
431 scope = const SCOPE,
432 semantics = const SEMANTICS,
433 ptr = in(reg) ptr,
434 old = in(reg) &mut old,
435 value = in(reg) &value
436 }
437
438 old
439}
440
441#[spirv_std_macros::gpu_only]
450#[doc(alias = "OpAtomicOr")]
451#[inline]
452pub unsafe fn atomic_or<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
453 ptr: &mut I,
454 value: I,
455) -> I {
456 let mut old = I::default();
457
458 asm! {
459 "%u32 = OpTypeInt 32 0",
460 "%scope = OpConstant %u32 {scope}",
461 "%semantics = OpConstant %u32 {semantics}",
462 "%value = OpLoad _ {value}",
463 "%old = OpAtomicOr _ {ptr} %scope %semantics %value",
464 "OpStore {old} %old",
465 scope = const SCOPE,
466 semantics = const SEMANTICS,
467 ptr = in(reg) ptr,
468 old = in(reg) &mut old,
469 value = in(reg) &value
470 }
471
472 old
473}
474
475#[spirv_std_macros::gpu_only]
484#[doc(alias = "OpAtomicXor")]
485#[inline]
486pub unsafe fn atomic_xor<I: Integer, const SCOPE: u32, const SEMANTICS: u32>(
487 ptr: &mut I,
488 value: I,
489) -> I {
490 let mut old = I::default();
491
492 asm! {
493 "%u32 = OpTypeInt 32 0",
494 "%scope = OpConstant %u32 {scope}",
495 "%semantics = OpConstant %u32 {semantics}",
496 "%value = OpLoad _ {value}",
497 "%old = OpAtomicXor _ {ptr} %scope %semantics %value",
498 "OpStore {old} %old",
499 scope = const SCOPE,
500 semantics = const SEMANTICS,
501 ptr = in(reg) ptr,
502 old = in(reg) &mut old,
503 value = in(reg) &value
504 }
505
506 old
507}
508
509#[spirv_std_macros::gpu_only]
519#[doc(alias = "OpAtomicFMinEXT")]
520#[inline]
521pub unsafe fn atomic_f_min<F: Float, const SCOPE: u32, const SEMANTICS: u32>(
522 ptr: &mut F,
523 value: F,
524) -> F {
525 let mut old = F::default();
526
527 asm! {
528 "%u32 = OpTypeInt 32 0",
529 "%scope = OpConstant %u32 {scope}",
530 "%semantics = OpConstant %u32 {semantics}",
531 "%value = OpLoad _ {value}",
532 "%old = OpAtomicFMinEXT _ {ptr} %scope %semantics %value",
533 "OpStore {old} %old",
534 scope = const SCOPE,
535 semantics = const SEMANTICS,
536 ptr = in(reg) ptr,
537 old = in(reg) &mut old,
538 value = in(reg) &value
539 }
540
541 old
542}
543
544#[spirv_std_macros::gpu_only]
554#[doc(alias = "OpAtomicFMaxEXT")]
555#[inline]
556pub unsafe fn atomic_f_max<F: Float, const SCOPE: u32, const SEMANTICS: u32>(
557 ptr: &mut F,
558 value: F,
559) -> F {
560 let mut old = F::default();
561
562 asm! {
563 "%u32 = OpTypeInt 32 0",
564 "%scope = OpConstant %u32 {scope}",
565 "%semantics = OpConstant %u32 {semantics}",
566 "%value = OpLoad _ {value}",
567 "%old = OpAtomicFMaxEXT _ {ptr} %scope %semantics %value",
568 "OpStore {old} %old",
569 scope = const SCOPE,
570 semantics = const SEMANTICS,
571 ptr = in(reg) ptr,
572 old = in(reg) &mut old,
573 value = in(reg) &value
574 }
575
576 old
577}
578
579#[spirv_std_macros::gpu_only]
588#[doc(alias = "OpAtomicFAddEXT")]
589#[inline]
590pub unsafe fn atomic_f_add<F: Float, const SCOPE: u32, const SEMANTICS: u32>(
591 ptr: &mut F,
592 value: F,
593) -> F {
594 let mut old = F::default();
595
596 asm! {
597 "%u32 = OpTypeInt 32 0",
598 "%scope = OpConstant %u32 {scope}",
599 "%semantics = OpConstant %u32 {semantics}",
600 "%value = OpLoad _ {value}",
601 "%old = OpAtomicFAddEXT _ {ptr} %scope %semantics %value",
602 "OpStore {old} %old",
603 scope = const SCOPE,
604 semantics = const SEMANTICS,
605 ptr = in(reg) ptr,
606 old = in(reg) &mut old,
607 value = in(reg) &value
608 }
609
610 old
611}