ae2f_docs
c89atomic.h
1/*
2C89 compatible atomics. Choice of public domain or MIT-0. See license statements at the end of this file.
3
4David Reid - mackron@gmail.com
5*/
6
7/*
8Introduction
9============
10This library aims to implement an equivalent to the C11 atomics library. It's intended to be used as a way to
11enable the use of atomics in a mostly consistent manner to modern C, while still enabling compatibility with
12older compilers. This is *not* a drop-in replacement for C11 atomics, but is very similar. Only limited testing
13has been done so use at your own risk. I'm happy to accept feedback and pull requests with bug fixes.
14
15The following compilers are supported:
16
17 - Visual Studio from VC6 (Earlier versions may work, but are untested.)
18 - GCC starting from 2.7 (Earlier versions lack support for extended inline assembly.)
19 - Clang
20 - Intel oneAPI (Tested with 2025.0.4. Intel C++ Compiler Classic has not been tested.)
21 - TinyCC/TCC (Tested with 0.9.27)
22 - OpenWatcom (Tested with 2.0)
23 - Digital Mars
24 - Borland C++ (Tested with 5.02)
25
26New compilers will use intrinsics. GCC-likes, such as GCC and Clang, will use `__atomic_*` intrinsics through a
27pre-processor define and should have no overhead. This uses `__GNUC__` to detect GCC-likes.
28
29Old compilers, or compilers lacking support for intrinsics, will use inlined assembly. There are two inlined
30assembly paths: GCC-style (GAS syntax) and MSVC-style. For an old compiler to be supported, it must support one
31of these two paths. Note that only 32- and 64-bit x86 is supported for inlined assembly. I have not thouroughly
32tested the inlined assembly paths. It passes basics tests, but things like memory ordering may have some issues.
33Advice welcome on how to improve this.
34
35
36Differences With C11
37--------------------
38For practicality, this is not a drop-in replacement for C11's `stdatomic.h`. Below are the main differences
39between c89atomic and stdatomic.
40
41 * All operations require an explicit size which is specified by the name of the function, and only 8-,
42 16-, 32- and 64-bit operations are supported. Objects of an arbitrary sizes are not supported.
43 * All APIs are namespaced with `c89`.
44 * `c89atomic_*` data types are undecorated (there is no `_Atomic` decoration).
45
46
47Types and Functions
48-------------------
49The following types and functions are implemented:
50
51+-----------------------------------------+-----------------------------------------------+
52| C11 Atomics | C89 Atomics |
53+-----------------------------------------+-----------------------------------------------+
54| #include <stdatomic.h> | #include "c89atomic.h" |
55+-----------------------------------------+-----------------------------------------------+
56| memory_order | c89atomic_memory_order |
57| memory_order_relaxed | c89atomic_memory_order_relaxed |
58| memory_order_consume | c89atomic_memory_order_consume |
59| memory_order_acquire | c89atomic_memory_order_acquire |
60| memory_order_release | c89atomic_memory_order_release |
61| memory_order_acq_rel | c89atomic_memory_order_acq_rel |
62| memory_order_seq_cst | c89atomic_memory_order_seq_cst |
63+-----------------------------------------+-----------------------------------------------+
64| atomic_flag | c89atomic_flag |
65| atomic_bool | c89atomic_bool |
66| atomic_int8 | c89atomic_int8 |
67| atomic_uint8 | c89atomic_uint8 |
68| atomic_int16 | c89atomic_int16 |
69| atomic_uint16 | c89atomic_uint16 |
70| atomic_int32 | c89atomic_int32 |
71| atomic_uint32 | c89atomic_uint32 |
72| atomic_int64 | c89atomic_int64 |
73| atomic_uint64 | c89atomic_uint64 |
74+-----------------------------------------+-----------------------------------------------+
75| atomic_flag_test_and_set | c89atomic_flag_test_and_set |
76| atomic_flag_test_and_set_explicit | c89atomic_flag_test_and_set_explicit |
77+-----------------------------------------+-----------------------------------------------+
78| atomic_flag_clear | c89atomic_flag_clear |
79| atomic_flag_clear_explicit | c89atomic_flag_clear_explicit |
80+-----------------------------------------+-----------------------------------------------+
81| atomic_store | c89atomic_store_8 |
82| atomic_store_explicit | c89atomic_store_16 |
83| | c89atomic_store_32 |
84| | c89atomic_store_64 |
85| | c89atomic_store_explicit_8 |
86| | c89atomic_store_explicit_16 |
87| | c89atomic_store_explicit_32 |
88| | c89atomic_store_explicit_64 |
89+-----------------------------------------+-----------------------------------------------+
90| atomic_load | c89atomic_load_8 |
91| atomic_load_explicit | c89atomic_load_16 |
92| | c89atomic_load_32 |
93| | c89atomic_load_64 |
94| | c89atomic_load_explicit_8 |
95| | c89atomic_load_explicit_16 |
96| | c89atomic_load_explicit_32 |
97| | c89atomic_load_explicit_64 |
98+-----------------------------------------+-----------------------------------------------+
99| atomic_exchange | c89atomic_exchange_8 |
100| atomic_exchange_explicit | c89atomic_exchange_16 |
101| | c89atomic_exchange_32 |
102| | c89atomic_exchange_64 |
103| | c89atomic_exchange_explicit_8 |
104| | c89atomic_exchange_explicit_16 |
105| | c89atomic_exchange_explicit_32 |
106| | c89atomic_exchange_explicit_64 |
107+-----------------------------------------+-----------------------------------------------+
108| atomic_compare_exchange_weak | c89atomic_compare_exchange_weak_8 |
109| atomic_compare_exchange_weak_explicit | c89atomic_compare_exchange_weak_16 |
110| atomic_compare_exchange_strong | c89atomic_compare_exchange_weak_32 |
111| atomic_compare_exchange_strong_explicit | c89atomic_compare_exchange_weak_64 |
112| | c89atomic_compare_exchange_weak_explicit_8 |
113| | c89atomic_compare_exchange_weak_explicit_16 |
114| | c89atomic_compare_exchange_weak_explicit_32 |
115| | c89atomic_compare_exchange_weak_explicit_64 |
116| | c89atomic_compare_exchange_strong_8 |
117| | c89atomic_compare_exchange_strong_16 |
118| | c89atomic_compare_exchange_strong_32 |
119| | c89atomic_compare_exchange_strong_64 |
120| | c89atomic_compare_exchange_strong_explicit_8 |
121| | c89atomic_compare_exchange_strong_explicit_16 |
122| | c89atomic_compare_exchange_strong_explicit_32 |
123| | c89atomic_compare_exchange_strong_explicit_64 |
124+-----------------------------------------+-----------------------------------------------+
125| atomic_fetch_add | c89atomic_fetch_add_8 |
126| atomic_fetch_add_explicit | c89atomic_fetch_add_16 |
127| | c89atomic_fetch_add_32 |
128| | c89atomic_fetch_add_64 |
129| | c89atomic_fetch_add_explicit_8 |
130| | c89atomic_fetch_add_explicit_16 |
131| | c89atomic_fetch_add_explicit_32 |
132| | c89atomic_fetch_add_explicit_64 |
133+-----------------------------------------+-----------------------------------------------+
134| atomic_fetch_sub | c89atomic_fetch_sub_8 |
135| atomic_fetch_sub_explicit | c89atomic_fetch_sub_16 |
136| | c89atomic_fetch_sub_32 |
137| | c89atomic_fetch_sub_64 |
138| | c89atomic_fetch_sub_explicit_8 |
139| | c89atomic_fetch_sub_explicit_16 |
140| | c89atomic_fetch_sub_explicit_32 |
141| | c89atomic_fetch_sub_explicit_64 |
142+-----------------------------------------+-----------------------------------------------+
143| atomic_fetch_or | c89atomic_fetch_or_8 |
144| atomic_fetch_or_explicit | c89atomic_fetch_or_16 |
145| | c89atomic_fetch_or_32 |
146| | c89atomic_fetch_or_64 |
147| | c89atomic_fetch_or_explicit_8 |
148| | c89atomic_fetch_or_explicit_16 |
149| | c89atomic_fetch_or_explicit_32 |
150| | c89atomic_fetch_or_explicit_64 |
151+-----------------------------------------+-----------------------------------------------+
152| atomic_fetch_xor | c89atomic_fetch_xor_8 |
153| atomic_fetch_xor_explicit | c89atomic_fetch_xor_16 |
154| | c89atomic_fetch_xor_32 |
155| | c89atomic_fetch_xor_64 |
156| | c89atomic_fetch_xor_explicit_8 |
157| | c89atomic_fetch_xor_explicit_16 |
158| | c89atomic_fetch_xor_explicit_32 |
159| | c89atomic_fetch_xor_explicit_64 |
160+-----------------------------------------+-----------------------------------------------+
161| atomic_fetch_and | c89atomic_fetch_and_8 |
162| atomic_fetch_and_explicit | c89atomic_fetch_and_16 |
163| | c89atomic_fetch_and_32 |
164| | c89atomic_fetch_and_64 |
165| | c89atomic_fetch_and_explicit_8 |
166| | c89atomic_fetch_and_explicit_16 |
167| | c89atomic_fetch_and_explicit_32 |
168| | c89atomic_fetch_and_explicit_64 |
169+-----------------------------------------+-----------------------------------------------+
170| atomic_thread_fence() | c89atomic_thread_fence |
171| atomic_signal_fence() | c89atomic_signal_fence |
172+-----------------------------------------+-----------------------------------------------+
173| atomic_is_lock_free | c89atomic_is_lock_free_8 |
174| | c89atomic_is_lock_free_16 |
175| | c89atomic_is_lock_free_32 |
176| | c89atomic_is_lock_free_64 |
177+-----------------------------------------+-----------------------------------------------+
178| (Not Defined) | c89atomic_compare_and_swap_8 |
179| | c89atomic_compare_and_swap_16 |
180| | c89atomic_compare_and_swap_32 |
181| | c89atomic_compare_and_swap_64 |
182| | c89atomic_compare_and_swap_ptr |
183+-----------------------------------------+-----------------------------------------------+
184*/
185
186#ifndef c89atomic_h
187#define c89atomic_h
188
189#if defined(__cplusplus)
190extern "C" {
191#endif
192
193#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
194 #pragma GCC diagnostic push
195 #pragma GCC diagnostic ignored "-Wlong-long"
196 #if defined(__clang__)
197 #pragma GCC diagnostic ignored "-Wc++11-long-long"
198 #endif
199#endif
200
201typedef int c89atomic_memory_order;
202
203/* Sized Types */
204typedef signed char c89atomic_int8;
205typedef unsigned char c89atomic_uint8;
206typedef signed short c89atomic_int16;
207typedef unsigned short c89atomic_uint16;
208typedef signed int c89atomic_int32;
209typedef unsigned int c89atomic_uint32;
210#if (defined(_MSC_VER) && !defined(__clang__)) || defined(__BORLANDC__)
211 typedef signed __int64 c89atomic_int64;
212 typedef unsigned __int64 c89atomic_uint64;
213#else
214 typedef signed long long c89atomic_int64;
215 typedef unsigned long long c89atomic_uint64;
216#endif
217
218/*
219The boolean data type is 32-bit here because it's the most reliable size for ensuring atomic operations
220are lock-free. For example, on Visual Studio 2010 and older, 8-bit and 16-bit atomics are not lock-free
221on the 64-bit build because those compilers lack support for intrinsics for those sizes, and since there
222is no support for inlined assembly on 64-bit builds in any version of Visual Studio, there's no practical
223way to implement a fallback outside of external linkage.
224*/
225typedef c89atomic_uint32 c89atomic_bool;
226/* End Sized Types */
227
228
229/* Architecture Detection */
230#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
231 #ifdef _WIN32
232 #ifdef _WIN64
233 #define C89ATOMIC_64BIT
234 #else
235 #define C89ATOMIC_32BIT
236 #endif
237 #endif
238#endif
239
240#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
241 #ifdef __GNUC__
242 #ifdef __LP64__
243 #define C89ATOMIC_64BIT
244 #else
245 #define C89ATOMIC_32BIT
246 #endif
247 #endif
248#endif
249
250#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
251#include <stdint.h>
252#if INTPTR_MAX == INT64_MAX
253#define C89ATOMIC_64BIT
254#else
255#define C89ATOMIC_32BIT
256#endif
257#endif
258
259#if defined(__x86_64__) || defined(_M_X64)
260#define C89ATOMIC_X64
261#elif defined(__i386) || defined(_M_IX86) || defined(__i386__)
262#define C89ATOMIC_X86
263#elif defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
264#define C89ATOMIC_ARM64
265#elif defined(__arm__) || defined(_M_ARM)
266#define C89ATOMIC_ARM32
267#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || defined(_ARCH_PPC64)
268#define C89ATOMIC_PPC64
269#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__powerpc) || defined(__ppc) || defined(_ARCH_PPC)
270#define C89ATOMIC_PPC32
271#endif
272
273#if defined(C89ATOMIC_ARM32) || defined(C89ATOMIC_ARM64)
274#define C89ATOMIC_ARM
275#endif
276/* End Architecture Detection */
277
278/* Inline */
279/* We want to encourage the compiler to inline. When adding support for a new compiler, make sure it's handled here. */
280#if defined(_MSC_VER)
281 #define C89ATOMIC_INLINE __forceinline
282#elif defined(__GNUC__)
283 /*
284 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
285 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
286 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
287 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
288 I am using "__inline__" only when we're compiling in strict ANSI mode.
289 */
290 #if defined(__STRICT_ANSI__) || !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
291 #define C89ATOMIC_INLINE __inline__ __attribute__((always_inline))
292 #else
293 #define C89ATOMIC_INLINE inline __attribute__((always_inline))
294 #endif
295#elif defined(__WATCOMC__) || defined(__DMC__)
296 #define C89ATOMIC_INLINE __inline
297#else
298 #define C89ATOMIC_INLINE
299#endif
300/* End Inline */
301
302
303/* BEG c89atomic_codepath.h */
304/*
305Here is where we need to determine the code path we're going to take. This can get complicated
306due to the myriad of different compiler versions and available APIs.
307
308If you need to add support for a new (or old!) compiler, try figuring out which code path is
309most appropriate and try to plug it into the code path selection logic below. If none of the
310existing code paths are appropriate, you'll need to add a new code path and implement it.
311*/
312#if !defined(C89ATOMIC_MODERN_MSVC) &&
313 !defined(C89ATOMIC_LEGACY_MSVC) &&
314 !defined(C89ATOMIC_LEGACY_MSVC_ASM) &&
315 !defined(C89ATOMIC_MODERN_GCC) &&
316 !defined(C89ATOMIC_LEGACY_GCC) &&
317 !defined(C89ATOMIC_LEGACY_GCC_ASM)
318 #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) || defined(__BORLANDC__)
319 #if (defined(_MSC_VER) && _MSC_VER > 1600)
320 /* Visual Studio 2010 and later. This path uses _Interlocked* intrinsics. */
321 #define C89ATOMIC_MODERN_MSVC
322 #else
323 /* Old MSVC, or non-MSVC compilers with support for MSVC-style inlined assembly. */
324 #if defined(C89ATOMIC_X64)
325 /*
326 We cannot use inlined assembly for the 64-bit build because 64-bit inlined assembly is not supported
327 by any version of Visual Studio.
328 */
329 #define C89ATOMIC_LEGACY_MSVC
330 #else
331 /* This path uses MSVC-style inlined assembly. */
332 #define C89ATOMIC_LEGACY_MSVC_ASM
333 #endif
334 #endif
335 #elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || defined(__clang__)
336 /* Modern GCC-compatible compilers. This path uses __atomic_* intrinsics. */
337 #define C89ATOMIC_MODERN_GCC
338 #else
339 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
340 /* Legacy GCC-compatible compilers. This path uses __sync_* intrinsics. */
341 #define C89ATOMIC_LEGACY_GCC
342 #else
343 /* Ancient GCC compilers, or non-GCC compilers with support for GCC-style inlined assembly (Gas syntax). */
344 #define C89ATOMIC_LEGACY_GCC_ASM
345 #endif
346 #endif
347#endif
348/* END c89atomic_codepath.h */
349
350/* BEG c89atomic_flag.h */
351/*
352This section implements the c89atomic_flag type and the following functions:
353
354 - c89atomic_flag_test_and_set_explicit
355 - c89atomic_flag_clear_explicit
356 - c89atomic_flag_load_explicit
357
358These functions are mandatory. If they cannot be implemented a compile time error must be thrown.
359*/
360#if defined(C89ATOMIC_MODERN_MSVC) || defined(C89ATOMIC_LEGACY_MSVC)
361 #include <intrin.h>
362
363 #define c89atomic_memory_order_relaxed 1
364 #define c89atomic_memory_order_consume 2
365 #define c89atomic_memory_order_acquire 3
366 #define c89atomic_memory_order_release 4
367 #define c89atomic_memory_order_acq_rel 5
368 #define c89atomic_memory_order_seq_cst 6
369
370 #define C89ATOMIC_MSVC_ARM_INTRINSIC_NORETURN(dst, src, order, intrin, c89atomicType, msvcType)
371 switch (order)
372 {
373 case c89atomic_memory_order_relaxed:
374 {
375 intrin##_nf((volatile msvcType*)dst, (msvcType)src);
376 } break;
377 case c89atomic_memory_order_consume:
378 case c89atomic_memory_order_acquire:
379 {
380 intrin##_acq((volatile msvcType*)dst, (msvcType)src);
381 } break;
382 case c89atomic_memory_order_release:
383 {
384 intrin##_rel((volatile msvcType*)dst, (msvcType)src);
385 } break;
386 case c89atomic_memory_order_acq_rel:
387 case c89atomic_memory_order_seq_cst:
388 default:
389 {
390 intrin((volatile msvcType*)dst, (msvcType)src);
391 } break;
392 }
393
394 #define C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, c89atomicType, msvcType)
395 c89atomicType result;
396 switch (order)
397 {
398 case c89atomic_memory_order_relaxed:
399 {
400 result = (c89atomicType)intrin##_nf((volatile msvcType*)dst, (msvcType)src);
401 } break;
402 case c89atomic_memory_order_consume:
403 case c89atomic_memory_order_acquire:
404 {
405 result = (c89atomicType)intrin##_acq((volatile msvcType*)dst, (msvcType)src);
406 } break;
407 case c89atomic_memory_order_release:
408 {
409 result = (c89atomicType)intrin##_rel((volatile msvcType*)dst, (msvcType)src);
410 } break;
411 case c89atomic_memory_order_acq_rel:
412 case c89atomic_memory_order_seq_cst:
413 default:
414 {
415 result = (c89atomicType)intrin((volatile msvcType*)dst, (msvcType)src);
416 } break;
417 }
418 return result;
419
420 typedef c89atomic_uint32 c89atomic_flag;
421
422 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_test_and_set_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
423 {
424 #if defined(C89ATOMIC_ARM)
425 {
426 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, 1, order, _InterlockedExchange, c89atomic_flag, long);
427 }
428 #else
429 {
430 (void)order; /* Always using the strongest memory order. */
431 return (c89atomic_flag)_InterlockedExchange((volatile long*)dst, (long)1);
432 }
433 #endif
434 }
435
436 static C89ATOMIC_INLINE void c89atomic_flag_clear_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
437 {
438 #if defined(C89ATOMIC_ARM)
439 {
440 C89ATOMIC_MSVC_ARM_INTRINSIC_NORETURN(dst, 0, order, _InterlockedExchange, c89atomic_flag, long);
441 }
442 #else
443 {
444 (void)order; /* Always using the strongest memory order. */
445 _InterlockedExchange((volatile long*)dst, (long)0);
446 }
447 #endif
448 }
449
450 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_load_explicit(volatile const c89atomic_flag* dst, c89atomic_memory_order order)
451 {
452 (void)order;
453 return (c89atomic_uint32)_InterlockedCompareExchange((volatile long*)dst, 0, 0);
454 }
455#endif
456
457#if defined(C89ATOMIC_LEGACY_MSVC_ASM)
458 #define c89atomic_memory_order_relaxed 1
459 #define c89atomic_memory_order_consume 2
460 #define c89atomic_memory_order_acquire 3
461 #define c89atomic_memory_order_release 4
462 #define c89atomic_memory_order_acq_rel 5
463 #define c89atomic_memory_order_seq_cst 6
464
465 typedef c89atomic_uint32 c89atomic_flag;
466
467 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_test_and_set_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
468 {
469 c89atomic_flag result = 0;
470
471 (void)order;
472 __asm {
473 mov ecx, dst
474 mov eax, 1
475 xchg [ecx], eax
476 mov result, eax
477 }
478
479 return result;
480 }
481
482 static C89ATOMIC_INLINE void c89atomic_flag_clear_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
483 {
484 if (order == c89atomic_memory_order_relaxed) {
485 __asm {
486 mov esi, dst
487 mov dword ptr [esi], 0
488 }
489 } else {
490 __asm {
491 mov esi, dst
492 mov eax, 0
493 xchg [esi], eax
494 }
495 }
496 }
497
498 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_load_explicit(volatile const c89atomic_flag* dst, c89atomic_memory_order order)
499 {
500 c89atomic_flag result = 0;
501
502 if (order == c89atomic_memory_order_relaxed) {
503 __asm {
504 mov esi, dst
505 mov eax, [esi]
506 mov result, eax
507 }
508 } else if (order <= c89atomic_memory_order_release) {
509 __asm {
510 mov esi, dst
511 mov eax, [esi]
512 lock add dword ptr [esp], 0 /* fence. */
513 mov result, eax
514 }
515 } else {
516 __asm {
517 lock add dword ptr [esp], 0 /* fence. */
518 mov esi, dst
519 mov eax, [esi]
520 mov result, eax
521 lock add dword ptr [esp], 0 /* fence. */
522 }
523 }
524
525 return result;
526 }
527#endif
528
529#if defined(C89ATOMIC_MODERN_GCC)
530 #define c89atomic_memory_order_relaxed __ATOMIC_RELAXED
531 #define c89atomic_memory_order_consume __ATOMIC_CONSUME
532 #define c89atomic_memory_order_acquire __ATOMIC_ACQUIRE
533 #define c89atomic_memory_order_release __ATOMIC_RELEASE
534 #define c89atomic_memory_order_acq_rel __ATOMIC_ACQ_REL
535 #define c89atomic_memory_order_seq_cst __ATOMIC_SEQ_CST
536
537 typedef c89atomic_uint32 c89atomic_flag;
538
539 #define c89atomic_flag_test_and_set_explicit(dst, order) __atomic_exchange_n(dst, 1, order)
540 #define c89atomic_flag_clear_explicit(dst, order) __atomic_store_n(dst, 0, order)
541 #define c89atomic_flag_load_explicit(dst, order) __atomic_load_n(dst, order)
542#endif
543
544#if defined(C89ATOMIC_LEGACY_GCC)
545 #define c89atomic_memory_order_relaxed 1
546 #define c89atomic_memory_order_consume 2
547 #define c89atomic_memory_order_acquire 3
548 #define c89atomic_memory_order_release 4
549 #define c89atomic_memory_order_acq_rel 5
550 #define c89atomic_memory_order_seq_cst 6
551
552 typedef c89atomic_uint32 c89atomic_flag;
553
554 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_test_and_set_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
555 {
556 if (order > c89atomic_memory_order_acquire) {
557 __sync_synchronize();
558 }
559
560 return __sync_lock_test_and_set(dst, 1);
561 }
562
563 static C89ATOMIC_INLINE void c89atomic_flag_clear_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
564 {
565 if (order > c89atomic_memory_order_release) {
566 __sync_synchronize();
567 }
568
569 __sync_lock_release(dst);
570 }
571
572 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_load_explicit(volatile const c89atomic_flag* dst, c89atomic_memory_order order)
573 {
574 (void)order;
575 return __sync_val_compare_and_swap((c89atomic_flag*)dst, 0, 0);
576 }
577#endif
578
579#if defined(C89ATOMIC_LEGACY_GCC_ASM)
580 #define c89atomic_memory_order_relaxed 1
581 #define c89atomic_memory_order_consume 2
582 #define c89atomic_memory_order_acquire 3
583 #define c89atomic_memory_order_release 4
584 #define c89atomic_memory_order_acq_rel 5
585 #define c89atomic_memory_order_seq_cst 6
586
587 /*
588 It's actually kind of confusing as to the best way to implement a memory barrier on x86/64. From my quick research, it looks like
589 there's a few options:
590 - SFENCE/LFENCE/MFENCE
591 - LOCK ADD
592 - XCHG (with a memory operand, not two register operands)
593
594 It looks like the SFENCE instruction was added in the Pentium III series, whereas the LFENCE and MFENCE instructions were added in
595 the Pentium 4 series. It's not clear how this actually differs to a LOCK-prefixed instruction or an XCHG instruction with a memory
596 operand. For simplicity and compatibility, I'm just using a LOCK-prefixed ADD instruction which adds 0 to the value pointed to by
597 the ESP register. The use of the ESP register is that it should theoretically have a high likelyhood to be in cache. For now, just
598 to keep things simple, this is always doing a full memory barrier which means the `order` parameter is ignored on x86/64.
599 */
600 #if defined(C89ATOMIC_X86)
601 #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory")
602 #elif defined(C89ATOMIC_X64)
603 #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory")
604 #else
605 #error Unsupported architecture.
606 #endif
607
608
609 #define C89ATOMIC_XCHG_GCC_X86(instructionSizeSuffix, result, dst, src)
610 __asm__ __volatile__(
611 "xchg"instructionSizeSuffix" %0, %1"
612 : "=r"(result), /* %0 */
613 "=m"(*dst) /* %1 */
614 : "0"(src), /* %2 */
615 "m"(*dst) /* %3 */
616 : "memory"
617 )
618
619
620 #define C89ATOMIC_LOAD_RELAXED_GCC_X86(instructionSizeSuffix, result, dst)
621 __asm__ __volatile__(
622 "mov"instructionSizeSuffix" %1, %0"
623 : "=r"(result) /* %0 */
624 : "m"(*dst) /* %1 */
625 )
626
627 #define C89ATOMIC_LOAD_RELEASE_GCC_X86(instructionSizeSuffix, result, dst)
628 c89atomic_thread_fence(c89atomic_memory_order_release);
629 __asm__ __volatile__(
630 "mov"instructionSizeSuffix" %1, %0"
631 : "=r"(result) /* %0 */
632 : "m"(*dst) /* %1 */
633 : "memory"
634 )
635
636 #define C89ATOMIC_LOAD_SEQ_CST_GCC_X86(instructionSizeSuffix, result, dst)
637 c89atomic_thread_fence(c89atomic_memory_order_seq_cst);
638 __asm__ __volatile__(
639 "mov"instructionSizeSuffix" %1, %0"
640 : "=r"(result) /* %0 */
641 : "m"(*dst) /* %1 */
642 : "memory"
643 );
644 c89atomic_thread_fence(c89atomic_memory_order_seq_cst)
645
646
647 typedef c89atomic_uint32 c89atomic_flag;
648
649 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_test_and_set_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
650 {
651 c89atomic_flag result;
652 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
653 {
654 (void)order;
655 C89ATOMIC_XCHG_GCC_X86("l", result, dst, 1);
656 }
657 #else
658 {
659 #error Unsupported architecture.
660 }
661 #endif
662 return result;
663 }
664
665 static C89ATOMIC_INLINE void c89atomic_flag_clear_explicit(volatile c89atomic_flag* dst, c89atomic_memory_order order)
666 {
667 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
668 {
669 /* The compiler should optimize this branch away because in practice the order is always specified as a constant. */
670 if (order == c89atomic_memory_order_relaxed) {
671 __asm__ __volatile__(
672 "movl $0, %0"
673 : "=m"(*dst) /* %0 */
674 );
675 } else if (order == c89atomic_memory_order_release) {
676 __asm__ __volatile__(
677 "movl $0, %0"
678 : "=m"(*dst) /* %0 */
679 :
680 : "memory"
681 );
682 } else {
683 c89atomic_flag tmp = 0;
684 __asm__ __volatile__(
685 "xchgl %0, %1"
686 : "=r"(tmp), /* %0 */
687 "=m"(*dst) /* %1 */
688 : "0"(tmp), /* %2 */
689 "m"(*dst) /* %3 */
690 : "memory"
691 );
692 }
693 }
694 #else
695 {
696 #error Unsupported architecture.
697 }
698 #endif
699 }
700
701 static C89ATOMIC_INLINE c89atomic_flag c89atomic_flag_load_explicit(volatile const c89atomic_flag* dst, c89atomic_memory_order order)
702 {
703 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
704 {
705 c89atomic_flag result;
706
707 if (order == c89atomic_memory_order_relaxed) {
708 C89ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst);
709 } else if (order <= c89atomic_memory_order_release) {
710 C89ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst);
711 } else {
712 C89ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst);
713 }
714
715 return result;
716 }
717 #else
718 {
719 #error Unsupported architecture.
720 }
721 #endif
722 }
723#endif
724
725#define c89atomic_flag_test_and_set(dst) c89atomic_flag_test_and_set_explicit(dst, c89atomic_memory_order_acquire)
726#define c89atomic_flag_clear(dst) c89atomic_flag_clear_explicit(dst, c89atomic_memory_order_release)
727/* END c89atomic_flag.h */
728
729/* BEG c89atomic_spinlock.h */
730/*
731At this point we should have our c89atomic_flag type. We can now define our spinlock. With this
732spinlock, any architecture will be able to implement a full API set.
733*/
734typedef c89atomic_flag c89atomic_spinlock;
735
736static C89ATOMIC_INLINE void c89atomic_spinlock_lock(volatile c89atomic_spinlock* pSpinlock)
737{
738 for (;;) {
739 if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) {
740 break;
741 }
742
743 while (c89atomic_flag_load_explicit(pSpinlock, c89atomic_memory_order_relaxed) == 1) {
744 /* Do nothing. */
745 }
746 }
747}
748
749static C89ATOMIC_INLINE void c89atomic_spinlock_unlock(volatile c89atomic_spinlock* pSpinlock)
750{
751 c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release);
752}
753/* END c89atomic_spinlock.h */
754
755/* BEG c89atomic_global_lock.h */
756extern c89atomic_spinlock c89atomic_global_lock;
757/* END c89atomic_global_lock.h */
758
759
760/* BEG c89atomic_main.h */
761/*
762We define our c89atomic_is_lock_free functions here where applicable because there's a non-trivial
763logic in determining whether or not things are lock-free on a given architecture. I'd rather do this
764in one place than repeat it in each code path.
765
766Some code paths have their own implementation of these functions in which case those code paths are
767not represented here.
768*/
769#if defined(C89ATOMIC_MODERN_MSVC) || defined(C89ATOMIC_LEGACY_MSVC) || defined(C89ATOMIC_LEGACY_MSVC_ASM) || defined(C89ATOMIC_LEGACY_GCC) || defined(C89ATOMIC_LEGACY_GCC_ASM)
770 #if defined(C89ATOMIC_X64) || (defined(C89ATOMIC_X86) && ((defined(__GNUC__) && defined(__i486__)) || (defined(_M_IX86) && _M_IX86 >= 400))) /* 400 = i486 */
771 #if defined(C89ATOMIC_LEGACY_MSVC) && defined(C89ATOMIC_X64)
772 /* 64-bit builds on old MSVC do not have access to 8- and 16- bit atomic intrinsics nor an inline assembly. */
773 #else
774 #define C89ATOMIC_IS_LOCK_FREE_8 1
775 #define C89ATOMIC_IS_LOCK_FREE_16 1
776 #endif
777 #define C89ATOMIC_IS_LOCK_FREE_32 1
778 #if defined(C89ATOMIC_X64) || (defined(C89ATOMIC_X86) && ((defined(__GNUC__) && defined(__i586__)) || (defined(_M_IX86) && _M_IX86 >= 500))) /* 500 = i586 (Pentium) */
779 #define C89ATOMIC_IS_LOCK_FREE_64 1
780 #else
781 /* 64-bit atomics cannot be lock-free on i486 and below because it lacks CMPXCHG8B. */
782 #endif
783 #else
784 /* Atomics cannot be lock-free on i386 because it lacks CMPXCHG. */
785 #endif
786
787 #if defined(C89ATOMIC_ARM32) || defined(C89ATOMIC_ARM64)
788 #define C89ATOMIC_IS_LOCK_FREE_8 1
789 #define C89ATOMIC_IS_LOCK_FREE_16 1
790 #define C89ATOMIC_IS_LOCK_FREE_32 1
791 #if defined(C89ATOMIC_ARM64) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
792 #define C89ATOMIC_IS_LOCK_FREE_64 1
793 #endif
794 #endif
795
796 #if defined(C89ATOMIC_PPC32) || defined(C89ATOMIC_PPC64)
797 /*
798 I've had a report that on GCC 4.2 it's possible for some 8-bit and 16-bit __sync* intrinsics to
799 not work correctly. To work around this, I'm going to make them use a spinlock instead. I do not
800 know which specific versions of GCC this affects, but it certainly is not happening with GCC 4.9 on
801 my PowerPC VM running Debian 8. I'm going to be concervative and lock this down to any version of
802 GCC that lacks support for the newer __atomic* intrinsics. The reason for this specific boundary is
803 that I'm assuming that with those versions of GCC that support the newer __atomic* intrinsics, the
804 __sync* intrinsics are just wrappers around __atomic* and should therefore not have the error.
805 */
806 #if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7))) && !defined(__clang__)
807 /* Old GCC. Use a spinlock for 8 and 16-bit atomics. */
808 #else
809 #define C89ATOMIC_IS_LOCK_FREE_8 1
810 #define C89ATOMIC_IS_LOCK_FREE_16 1
811 #endif
812 #define C89ATOMIC_IS_LOCK_FREE_32 1
813 #if defined(C89ATOMIC_PPC64)
814 #define C89ATOMIC_IS_LOCK_FREE_64 1
815 #endif
816 #endif
817
818 static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_8(volatile void* ptr)
819 {
820 (void)ptr;
821 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
822 return 1;
823 #else
824 return 0;
825 #endif
826 }
827
828 static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_16(volatile void* ptr)
829 {
830 (void)ptr;
831 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
832 return 1;
833 #else
834 return 0;
835 #endif
836 }
837
838 static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_32(volatile void* ptr)
839 {
840 (void)ptr;
841 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
842 return 1;
843 #else
844 return 0;
845 #endif
846 }
847
848 static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_64(volatile void* ptr)
849 {
850 (void)ptr;
851 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
852 return 1;
853 #else
854 return 0;
855 #endif
856 }
857#endif
858
859
860#define C89ATOMIC_COMPARE_AND_SWAP_LOCK(sizeInBits, dst, expected, replacement)
861 c89atomic_uint##sizeInBits result;
862 c89atomic_spinlock_lock(&c89atomic_global_lock);
863 {
864 result = *dst;
865 if (result == expected) {
866 *dst = replacement;
867 }
868 }
869 c89atomic_spinlock_unlock(&c89atomic_global_lock);
870 return result
871
872
873#define C89ATOMIC_LOAD_EXPLICIT_LOCK(sizeInBits, ptr, order)
874 c89atomic_uint##sizeInBits result;
875 c89atomic_spinlock_lock(&c89atomic_global_lock);
876 {
877 result = *ptr;
878 (void)order;
879 }
880 c89atomic_spinlock_unlock(&c89atomic_global_lock);
881 return result
882
883
884#define C89ATOMIC_STORE_EXPLICIT_LOCK(sizeInBits, dst, src, order)
885 c89atomic_spinlock_lock(&c89atomic_global_lock);
886 {
887 *dst = src;
888 (void)order;
889 }
890 c89atomic_spinlock_unlock(&c89atomic_global_lock)
891
892#define C89ATOMIC_STORE_EXPLICIT_CAS(sizeInBits, dst, src, order)
893 c89atomic_uint##sizeInBits oldValue;
894 do {
895 oldValue = c89atomic_load_explicit_##sizeInBits(dst, c89atomic_memory_order_relaxed);
896 } while (c89atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue);
897 (void)order
898
899
900#define C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(sizeInBits, dst, src, order)
901 c89atomic_uint##sizeInBits result;
902 c89atomic_spinlock_lock(&c89atomic_global_lock);
903 {
904 result = *dst;
905 *dst = src;
906 (void)order;
907 }
908 c89atomic_spinlock_unlock(&c89atomic_global_lock);
909 return result
910
911#define C89ATOMIC_EXCHANGE_EXPLICIT_CAS(sizeInBits, dst, src, order)
912 c89atomic_uint##sizeInBits oldValue;
913 do {
914 oldValue = c89atomic_load_explicit_##sizeInBits(dst, c89atomic_memory_order_relaxed);
915 } while (c89atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue);
916 (void)order;
917 return oldValue
918
919
920#define C89ATOMIC_FETCH_ADD_LOCK(sizeInBits, dst, src, order)
921 c89atomic_uint##sizeInBits result;
922 c89atomic_spinlock_lock(&c89atomic_global_lock);
923 {
924 result = *dst;
925 *dst += src;
926 (void)order;
927 }
928 c89atomic_spinlock_unlock(&c89atomic_global_lock);
929 return result
930
931#define C89ATOMIC_FETCH_ADD_CAS(sizeInBits, dst, src, order)
932 c89atomic_uint##sizeInBits oldValue;
933 c89atomic_uint##sizeInBits newValue;
934 do {
935 oldValue = c89atomic_load_explicit_##sizeInBits(dst, c89atomic_memory_order_relaxed);
936 newValue = oldValue + src;
937 } while (c89atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue);
938 (void)order;
939 return oldValue
940
941
942#define C89ATOMIC_FETCH_AND_CAS(sizeInBits, dst, src, order)
943 c89atomic_uint##sizeInBits oldValue;
944 c89atomic_uint##sizeInBits newValue;
945 do {
946 oldValue = c89atomic_load_explicit_##sizeInBits(dst, c89atomic_memory_order_relaxed);
947 newValue = (c89atomic_uint##sizeInBits)(oldValue & src);
948 } while (c89atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue);
949 (void)order;
950 return oldValue
951
952
953#define C89ATOMIC_FETCH_OR_CAS(sizeInBits, dst, src, order)
954 c89atomic_uint##sizeInBits oldValue;
955 c89atomic_uint##sizeInBits newValue;
956 do {
957 oldValue = c89atomic_load_explicit_##sizeInBits(dst, c89atomic_memory_order_relaxed);
958 newValue = (c89atomic_uint##sizeInBits)(oldValue | src);
959 } while (c89atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue);
960 (void)order;
961 return oldValue
962
963
964#define C89ATOMIC_FETCH_XOR_CAS(sizeInBits, dst, src, order)
965 c89atomic_uint##sizeInBits oldValue;
966 c89atomic_uint##sizeInBits newValue;
967 do {
968 oldValue = c89atomic_load_explicit_##sizeInBits(dst, c89atomic_memory_order_relaxed);
969 newValue = (c89atomic_uint##sizeInBits)(oldValue ^ src);
970 } while (c89atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue);
971 (void)order;
972 return oldValue
973
974
975#if defined(C89ATOMIC_MODERN_MSVC) || defined(C89ATOMIC_LEGACY_MSVC)
976 /*
977 The modern and legacy MSVC paths are basically the same except that with the legacy path, 8-
978 and 16-bit atomics are not lock-free on x86_64.
979 */
980 #define C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, replacement, order, intrin, c89atomicType, msvcType)
981 c89atomicType result;
982 switch (order)
983 {
984 case c89atomic_memory_order_relaxed:
985 {
986 result = (c89atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement);
987 } break;
988 case c89atomic_memory_order_consume:
989 case c89atomic_memory_order_acquire:
990 {
991 result = (c89atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement);
992 } break;
993 case c89atomic_memory_order_release:
994 {
995 result = (c89atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement);
996 } break;
997 case c89atomic_memory_order_acq_rel:
998 case c89atomic_memory_order_seq_cst:
999 default:
1000 {
1001 result = (c89atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement);
1002 } break;
1003 }
1004 return result;
1005
1006
1007 /* compare_and_swap() */
1008 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1009 #define c89atomic_compare_and_swap_8( dst, expected, replacement) (c89atomic_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)replacement, (char)expected)
1010 #else
1011 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 replacement)
1012 {
1013 C89ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement);
1014 }
1015 #endif
1016
1017 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1018 #define c89atomic_compare_and_swap_16(dst, expected, replacement) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)replacement, (short)expected)
1019 #else
1020 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 replacement)
1021 {
1022 C89ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement);
1023 }
1024 #endif
1025
1026 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1027 #define c89atomic_compare_and_swap_32(dst, expected, replacement) (c89atomic_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)replacement, (long)expected)
1028 #else
1029 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 replacement)
1030 {
1031 C89ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement);
1032 }
1033 #endif
1034
1035 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1036 #define c89atomic_compare_and_swap_64(dst, expected, replacement) (c89atomic_uint64)_InterlockedCompareExchange64((volatile c89atomic_int64*)dst, (c89atomic_int64)replacement, (c89atomic_int64)expected)
1037 #else
1038 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 replacement)
1039 {
1040 C89ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement);
1041 }
1042 #endif
1043
1044
1045 /* load() */
1046 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
1047 {
1048 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1049 {
1050 #if defined(C89ATOMIC_ARM)
1051 {
1052 C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, c89atomic_uint8, char);
1053 }
1054 #else
1055 {
1056 (void)order; /* Always using the strongest memory order. */
1057 return c89atomic_compare_and_swap_8((volatile c89atomic_uint8*)ptr, 0, 0);
1058 }
1059 #endif
1060 }
1061 #else
1062 {
1063 C89ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order);
1064 }
1065 #endif
1066 }
1067
1068 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
1069 {
1070 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1071 {
1072 #if defined(C89ATOMIC_ARM)
1073 {
1074 C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, c89atomic_uint16, short);
1075 }
1076 #else
1077 {
1078 (void)order; /* Always using the strongest memory order. */
1079 return c89atomic_compare_and_swap_16((volatile c89atomic_uint16*)ptr, 0, 0);
1080 }
1081 #endif
1082 }
1083 #else
1084 {
1085 C89ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order);
1086 }
1087 #endif
1088 }
1089
1090 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order)
1091 {
1092 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1093 {
1094 #if defined(C89ATOMIC_ARM)
1095 {
1096 C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, c89atomic_uint32, long);
1097 }
1098 #else
1099 {
1100 (void)order; /* Always using the strongest memory order. */
1101 return c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)ptr, 0, 0);
1102 }
1103 #endif
1104 }
1105 #else
1106 {
1107 C89ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order);
1108 }
1109 #endif
1110 }
1111
1112 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order)
1113 {
1114 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1115 {
1116 #if defined(C89ATOMIC_ARM)
1117 {
1118 C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, c89atomic_uint64, long long);
1119 }
1120 #else
1121 {
1122 (void)order; /* Always using the strongest memory order. */
1123 return c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)ptr, 0, 0);
1124 }
1125 #endif
1126 }
1127 #else
1128 {
1129 C89ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order);
1130 }
1131 #endif
1132 }
1133
1134
1135 /* exchange() */
1136 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1137 {
1138 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1139 {
1140 #if defined(C89ATOMIC_ARM)
1141 {
1142 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, c89atomic_uint8, char);
1143 }
1144 #else
1145 {
1146 (void)order; /* Always using the strongest memory order. */
1147 return (c89atomic_uint8)_InterlockedExchange8((volatile char*)dst, (char)src);
1148 }
1149 #endif
1150 }
1151 #else
1152 {
1153 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order);
1154 }
1155 #endif
1156 }
1157
1158 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1159 {
1160 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1161 {
1162 #if defined(C89ATOMIC_ARM)
1163 {
1164 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, c89atomic_uint16, short);
1165 }
1166 #else
1167 {
1168 (void)order; /* Always using the strongest memory order. */
1169 return (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src);
1170 }
1171 #endif
1172 }
1173 #else
1174 {
1175 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order);
1176 }
1177 #endif
1178 }
1179
1180 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1181 {
1182 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1183 {
1184 #if defined(C89ATOMIC_ARM)
1185 {
1186 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, c89atomic_uint32, long);
1187 }
1188 #else
1189 {
1190 (void)order; /* Always using the strongest memory order. */
1191 return (c89atomic_uint32)_InterlockedExchange((volatile long*)dst, (long)src);
1192 }
1193 #endif
1194 }
1195 #else
1196 {
1197 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order);
1198 }
1199 #endif
1200 }
1201
1202 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1203 {
1204 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
1205 {
1206 /* atomic_exchange_explicit_64() must be implemented in terms of atomic_compare_and_swap() on 32-bit builds, no matter the version of Visual Studio. */
1207 #if defined(C89ATOMIC_32BIT)
1208 {
1209 C89ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order);
1210 }
1211 #else
1212 {
1213 #if defined(C89ATOMIC_ARM)
1214 {
1215 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, c89atomic_uint64, long long);
1216 }
1217 #else
1218 {
1219 (void)order; /* Always using the strongest memory order. */
1220 return (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src);
1221 }
1222 #endif
1223 }
1224 #endif
1225 }
1226 #else
1227 {
1228 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order);
1229 }
1230 #endif
1231 }
1232
1233
1234 /* fetch_add() */
1235 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1236 {
1237 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1238 {
1239 #if defined(C89ATOMIC_ARM)
1240 {
1241 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, c89atomic_uint8, char);
1242 }
1243 #else
1244 {
1245 (void)order; /* Always using the strongest memory order. */
1246 return (c89atomic_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src);
1247 }
1248 #endif
1249 }
1250 #else
1251 {
1252 C89ATOMIC_FETCH_ADD_LOCK(8, dst, src, order);
1253 }
1254 #endif
1255 }
1256
1257 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1258 {
1259 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1260 {
1261 #if defined(C89ATOMIC_ARM)
1262 {
1263 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, c89atomic_uint16, short);
1264 }
1265 #else
1266 {
1267 (void)order; /* Always using the strongest memory order. */
1268 return (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src);
1269 }
1270 #endif
1271 }
1272 #else
1273 {
1274 C89ATOMIC_FETCH_ADD_LOCK(16, dst, src, order);
1275 }
1276 #endif
1277 }
1278
1279 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1280 {
1281 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1282 {
1283 #if defined(C89ATOMIC_ARM)
1284 {
1285 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, c89atomic_uint32, long);
1286 }
1287 #else
1288 {
1289 (void)order; /* Always using the strongest memory order. */
1290 return (c89atomic_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src);
1291 }
1292 #endif
1293 }
1294 #else
1295 {
1296 C89ATOMIC_FETCH_ADD_LOCK(32, dst, src, order);
1297 }
1298 #endif
1299 }
1300
1301 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1302 {
1303 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
1304 {
1305 /* c89atomic_fetch_add_explicit_64() must be implemented in terms of atomic_compare_and_swap() on 32-bit builds, no matter the version of Visual Studio. */
1306 #if defined(C89ATOMIC_32BIT)
1307 {
1308 C89ATOMIC_FETCH_ADD_CAS(64, dst, src, order);
1309 }
1310 #else
1311 {
1312 #if defined(C89ATOMIC_ARM)
1313 {
1314 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, c89atomic_uint64, long long);
1315 }
1316 #else
1317 {
1318 (void)order; /* Always using the strongest memory order. */
1319 return (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src);
1320 }
1321 #endif
1322 }
1323 #endif
1324 }
1325 #else
1326 {
1327 C89ATOMIC_FETCH_ADD_LOCK(64, dst, src, order);
1328 }
1329 #endif
1330 }
1331
1332
1333 /* fetch_sub() */
1334 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1335 {
1336 return c89atomic_fetch_add_explicit_8(dst, (c89atomic_uint8)(-(c89atomic_int8)src), order);
1337 }
1338
1339 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1340 {
1341 return c89atomic_fetch_add_explicit_16(dst, (c89atomic_uint16)(-(c89atomic_int16)src), order);
1342 }
1343
1344 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1345 {
1346 return c89atomic_fetch_add_explicit_32(dst, (c89atomic_uint32)(-(c89atomic_int32)src), order);
1347 }
1348
1349 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1350 {
1351 return c89atomic_fetch_add_explicit_64(dst, (c89atomic_uint64)(-(c89atomic_int64)src), order);
1352 }
1353
1354
1355 /* fetch_and() */
1356 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1357 {
1358 #if defined(C89ATOMIC_ARM)
1359 {
1360 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, c89atomic_uint8, char);
1361 }
1362 #else
1363 {
1364 C89ATOMIC_FETCH_AND_CAS(8, dst, src, order);
1365 }
1366 #endif
1367 }
1368
1369 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1370 {
1371 #if defined(C89ATOMIC_ARM)
1372 {
1373 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, c89atomic_uint16, short);
1374 }
1375 #else
1376 {
1377 C89ATOMIC_FETCH_AND_CAS(16, dst, src, order);
1378 }
1379 #endif
1380 }
1381
1382 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1383 {
1384 #if defined(C89ATOMIC_ARM)
1385 {
1386 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, c89atomic_uint32, long);
1387 }
1388 #else
1389 {
1390 C89ATOMIC_FETCH_AND_CAS(32, dst, src, order);
1391 }
1392 #endif
1393 }
1394
1395 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1396 {
1397 #if defined(C89ATOMIC_ARM)
1398 {
1399 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, c89atomic_uint64, long long);
1400 }
1401 #else
1402 {
1403 C89ATOMIC_FETCH_AND_CAS(64, dst, src, order);
1404 }
1405 #endif
1406 }
1407
1408
1409 /* fetch_or() */
1410 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1411 {
1412 #if defined(C89ATOMIC_ARM)
1413 {
1414 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, c89atomic_uint8, char);
1415 }
1416 #else
1417 {
1418 C89ATOMIC_FETCH_OR_CAS(8, dst, src, order);
1419 }
1420 #endif
1421 }
1422
1423 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1424 {
1425 #if defined(C89ATOMIC_ARM)
1426 {
1427 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, c89atomic_uint16, short);
1428 }
1429 #else
1430 {
1431 C89ATOMIC_FETCH_OR_CAS(16, dst, src, order);
1432 }
1433 #endif
1434 }
1435
1436 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1437 {
1438 #if defined(C89ATOMIC_ARM)
1439 {
1440 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, c89atomic_uint32, long);
1441 }
1442 #else
1443 {
1444 C89ATOMIC_FETCH_OR_CAS(32, dst, src, order);
1445 }
1446 #endif
1447 }
1448
1449 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1450 {
1451 #if defined(C89ATOMIC_ARM)
1452 {
1453 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, c89atomic_uint64, long long);
1454 }
1455 #else
1456 {
1457 C89ATOMIC_FETCH_OR_CAS(64, dst, src, order);
1458 }
1459 #endif
1460 }
1461
1462
1463 /* fetch_xor() */
1464 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1465 {
1466 #if defined(C89ATOMIC_ARM)
1467 {
1468 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, c89atomic_uint8, char);
1469 }
1470 #else
1471 {
1472 C89ATOMIC_FETCH_XOR_CAS(8, dst, src, order);
1473 }
1474 #endif
1475 }
1476
1477 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1478 {
1479 #if defined(C89ATOMIC_ARM)
1480 {
1481 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, c89atomic_uint16, short);
1482 }
1483 #else
1484 {
1485 C89ATOMIC_FETCH_XOR_CAS(16, dst, src, order);
1486 }
1487 #endif
1488 }
1489
1490 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1491 {
1492 #if defined(C89ATOMIC_ARM)
1493 {
1494 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, c89atomic_uint32, long);
1495 }
1496 #else
1497 {
1498 C89ATOMIC_FETCH_XOR_CAS(32, dst, src, order);
1499 }
1500 #endif
1501 }
1502
1503 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1504 {
1505 #if defined(C89ATOMIC_ARM)
1506 {
1507 C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, c89atomic_uint64, long long);
1508 }
1509 #else
1510 {
1511 C89ATOMIC_FETCH_XOR_CAS(64, dst, src, order);
1512 }
1513 #endif
1514 }
1515
1516
1517 /* atomic_store() is the same as atomic_exchange() but returns void. */
1518 #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order)
1519 #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order)
1520 #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order)
1521 #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order)
1522
1523
1524 /* thread_fence() */
1525 /* Can't use MemoryBarrier() for this as it require Windows headers which we want to avoid in the header section of c89atomic. */
1526 #if defined(C89ATOMIC_X64)
1527 #define c89atomic_thread_fence(order) __faststorefence(), (void)order
1528 #elif defined(C89ATOMIC_ARM64)
1529 #define c89atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order
1530 #else
1531 static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order)
1532 {
1533 volatile c89atomic_uint32 barrier = 0;
1534 c89atomic_fetch_add_explicit_32(&barrier, 0, order);
1535 }
1536 #endif /* C89ATOMIC_X64 */
1537
1538 /* signal_fence() */
1539 #define c89atomic_signal_fence(order) _ReadWriteBarrier(), (void)order
1540#endif
1541
1542
1543#if defined(C89ATOMIC_LEGACY_MSVC_ASM)
1544 /*
1545 Visual Studio 2003 (_MSC_VER 1300) and earlier have no support for sized atomic operations.
1546 We'll need to use inlined assembly for these compilers.
1547
1548 I've also had a report that 8-bit and 16-bit interlocked intrinsics were only added in Visual
1549 Studio 2010 (_MSC_VER 1600). We'll need to disable these on the 64-bit build because there's
1550 no way to implement them with inlined assembly since Microsoft has decided to drop support for
1551 it from their 64-bit compilers.
1552
1553 To simplify the implementation, any older MSVC compilers targeting 32-bit will use inlined
1554 assembly for everything. I'm not going to use inlined assembly wholesale for all 32-bit builds
1555 regardless of the age of the compiler because I don't trust the compiler will optimize the
1556 inlined assembly properly.
1557
1558 The inlined assembly path supports MSVC, Digital Mars and OpenWatcom. OpenWatcom is a little
1559 bit too pedantic with it's warnings. A few notes:
1560
1561 - The return value of these functions are defined by the AL/AX/EAX/EAX:EDX registers which
1562 means an explicit return statement is not actually necessary. This is helpful for performance
1563 reasons because it means we can avoid the cost of a declaring a local variable and moving the
1564 value in EAX into that variable, only to then return it. However, unfortunately OpenWatcom
1565 thinks this is a mistake and tries to be helpful by throwing a warning. To work around we're
1566 going to declare a "result" variable and incur this theoretical cost. Most likely the
1567 compiler will optimize this away and make it a non-issue.
1568
1569 - Variables that are assigned within the inline assembly will not be detected as such, and
1570 OpenWatcom will throw a warning about the variable being used without being assigned. To work
1571 around this we just initialize our local variables to 0.
1572 */
1573
1574 /* atomic_compare_and_swap() */
1575 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 replacement)
1576 {
1577 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1578 {
1579 c89atomic_uint8 result = 0;
1580
1581 __asm {
1582 mov ecx, dst
1583 mov al, expected
1584 mov dl, replacement
1585 lock cmpxchg [ecx], dl /* Writes to EAX which MSVC will treat as the return value. */
1586 mov result, al
1587 }
1588
1589 return result;
1590 }
1591 #else
1592 {
1593 C89ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement);
1594 }
1595 #endif
1596 }
1597
1598 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 replacement)
1599 {
1600 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1601 {
1602 c89atomic_uint16 result = 0;
1603
1604 __asm {
1605 mov ecx, dst
1606 mov ax, expected
1607 mov dx, replacement
1608 lock cmpxchg [ecx], dx /* Writes to EAX which MSVC will treat as the return value. */
1609 mov result, ax
1610 }
1611
1612 return result;
1613 }
1614 #else
1615 {
1616 C89ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement);
1617 }
1618 #endif
1619 }
1620
1621 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 replacement)
1622 {
1623 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1624 {
1625 c89atomic_uint32 result = 0;
1626
1627 __asm {
1628 mov ecx, dst
1629 mov eax, expected
1630 mov edx, replacement
1631 lock cmpxchg [ecx], edx /* Writes to EAX which MSVC will treat as the return value. */
1632 mov result, eax
1633 }
1634
1635 return result;
1636 }
1637 #else
1638 {
1639 C89ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement);
1640 }
1641 #endif
1642 }
1643
1644 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 replacement)
1645 {
1646 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
1647 {
1648 c89atomic_uint32 resultEAX = 0;
1649 c89atomic_uint32 resultEDX = 0;
1650
1651 __asm {
1652 mov esi, dst /* From Microsoft documentation: "... you don't need to preserve the EAX, EBX, ECX, EDX, ESI, or EDI registers." Choosing ESI since it's the next available one in their list. */
1653 mov eax, dword ptr expected
1654 mov edx, dword ptr expected + 4
1655 mov ebx, dword ptr replacement
1656 mov ecx, dword ptr replacement + 4
1657 lock cmpxchg8b qword ptr [esi] /* Writes to EAX:EDX which MSVC will treat as the return value. */
1658 mov resultEAX, eax
1659 mov resultEDX, edx
1660 }
1661
1662 return ((c89atomic_uint64)resultEDX << 32) | resultEAX;
1663 }
1664 #else
1665 {
1666 C89ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement);
1667 }
1668 #endif
1669 }
1670
1671
1672 /* load_explicit() */
1673 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* dst, c89atomic_memory_order order)
1674 {
1675 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1676 {
1677 c89atomic_uint8 result = 0;
1678
1679 if (order == c89atomic_memory_order_relaxed) {
1680 __asm {
1681 mov esi, dst
1682 mov al, [esi]
1683 mov result, al
1684 }
1685 } else if (order <= c89atomic_memory_order_release) {
1686 __asm {
1687 mov esi, dst
1688 mov al, [esi]
1689 lock add dword ptr [esp], 0 /* fence. */
1690 mov result, al
1691 }
1692 } else {
1693 __asm {
1694 lock add dword ptr [esp], 0 /* fence. */
1695 mov esi, dst
1696 mov al, [esi]
1697 mov result, al
1698 lock add dword ptr [esp], 0 /* fence. */
1699 }
1700 }
1701
1702 return result;
1703 }
1704 #else
1705 {
1706 C89ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order);
1707 }
1708 #endif
1709 }
1710
1711 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* dst, c89atomic_memory_order order)
1712 {
1713 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1714 {
1715 c89atomic_uint16 result = 0;
1716
1717 if (order == c89atomic_memory_order_relaxed) {
1718 __asm {
1719 mov esi, dst
1720 mov ax, [esi]
1721 mov result, ax
1722 }
1723 } else if (order <= c89atomic_memory_order_release) {
1724 __asm {
1725 mov esi, dst
1726 mov ax, [esi]
1727 lock add dword ptr [esp], 0 /* fence. */
1728 mov result, ax
1729 }
1730 } else {
1731 __asm {
1732 lock add dword ptr [esp], 0 /* fence. */
1733 mov esi, dst
1734 mov ax, [esi]
1735 mov result, ax
1736 lock add dword ptr [esp], 0 /* fence. */
1737 }
1738 }
1739
1740 return result;
1741 }
1742 #else
1743 {
1744 C89ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order);
1745 }
1746 #endif
1747 }
1748
1749 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* dst, c89atomic_memory_order order)
1750 {
1751 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1752 {
1753 c89atomic_uint32 result = 0;
1754
1755 if (order == c89atomic_memory_order_relaxed) {
1756 __asm {
1757 mov esi, dst
1758 mov eax, [esi]
1759 mov result, eax
1760 }
1761 } else if (order <= c89atomic_memory_order_release) {
1762 __asm {
1763 mov esi, dst
1764 mov eax, [esi]
1765 lock add dword ptr [esp], 0 /* fence. */
1766 mov result, eax
1767 }
1768 } else {
1769 __asm {
1770 lock add dword ptr [esp], 0 /* fence. */
1771 mov esi, dst
1772 mov eax, [esi]
1773 mov result, eax
1774 lock add dword ptr [esp], 0 /* fence. */
1775 }
1776 }
1777
1778 return result;
1779 }
1780 #else
1781 {
1782 C89ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order);
1783 }
1784 #endif
1785 }
1786
1787 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* dst, c89atomic_memory_order order)
1788 {
1789 (void)order;
1790 return c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, 0, 0);
1791 }
1792
1793
1794 /* atomic_store() */
1795 static C89ATOMIC_INLINE void __stdcall c89atomic_store_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1796 {
1797 /* With memory_order_relaxed we can just do a straight mov with x86. */
1798 if (order == c89atomic_memory_order_relaxed) {
1799 __asm {
1800 mov esi, dst
1801 mov al, src
1802 mov [esi], al
1803 }
1804 } else {
1805 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1806 {
1807 __asm {
1808 mov esi, dst
1809 mov al, src
1810 xchg [esi], al
1811 }
1812 }
1813 #else
1814 {
1815 C89ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order);
1816 }
1817 #endif
1818 }
1819 }
1820
1821 static C89ATOMIC_INLINE void __stdcall c89atomic_store_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1822 {
1823 /* With memory_order_relaxed we can just do a straight mov with x86. */
1824 if (order == c89atomic_memory_order_relaxed) {
1825 __asm {
1826 mov esi, dst
1827 mov ax, src
1828 mov [esi], ax
1829 }
1830 } else {
1831 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1832 {
1833 __asm {
1834 mov esi, dst
1835 mov ax, src
1836 xchg [esi], ax
1837 }
1838 }
1839 #else
1840 {
1841 C89ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order);
1842 }
1843 #endif
1844 }
1845 }
1846
1847 static C89ATOMIC_INLINE void __stdcall c89atomic_store_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1848 {
1849 /* With memory_order_relaxed we can just do a straight mov with x86. */
1850 if (order == c89atomic_memory_order_relaxed) {
1851 __asm {
1852 mov esi, dst
1853 mov eax, src
1854 mov [esi], eax
1855 }
1856 } else {
1857 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1858 {
1859 __asm {
1860 mov esi, dst
1861 mov eax, src
1862 xchg [esi], eax
1863 }
1864 }
1865 #else
1866 {
1867 C89ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order);
1868 }
1869 #endif
1870 }
1871 }
1872
1873 static C89ATOMIC_INLINE void __stdcall c89atomic_store_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1874 {
1875 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
1876 {
1877 C89ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order);
1878 }
1879 #else
1880 {
1881 C89ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order);
1882 }
1883 #endif
1884 }
1885
1886
1887 /* exchange_explicit() */
1888 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1889 {
1890 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1891 {
1892 c89atomic_uint8 result = 0;
1893
1894 (void)order;
1895 __asm {
1896 mov ecx, dst
1897 mov al, src
1898 lock xchg [ecx], al
1899 mov result, al
1900 }
1901
1902 return result;
1903 }
1904 #else
1905 {
1906 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order);
1907 }
1908 #endif
1909 }
1910
1911 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1912 {
1913 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1914 {
1915 c89atomic_uint16 result = 0;
1916
1917 (void)order;
1918 __asm {
1919 mov ecx, dst
1920 mov ax, src
1921 lock xchg [ecx], ax
1922 mov result, ax
1923 }
1924
1925 return result;
1926 }
1927 #else
1928 {
1929 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order);
1930 }
1931 #endif
1932 }
1933
1934 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
1935 {
1936 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
1937 {
1938 c89atomic_uint32 result = 0;
1939
1940 (void)order;
1941 __asm {
1942 mov ecx, dst
1943 mov eax, src
1944 xchg [ecx], eax
1945 mov result, eax
1946 }
1947
1948 return result;
1949 }
1950 #else
1951 {
1952 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order);
1953 }
1954 #endif
1955 }
1956
1957 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
1958 {
1959 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
1960 {
1961 C89ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order);
1962 }
1963 #else
1964 {
1965 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order);
1966 }
1967 #endif
1968 }
1969
1970
1971 /* atomic_fetch_add */
1972 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
1973 {
1974 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
1975 {
1976 c89atomic_uint8 result = 0;
1977
1978 (void)order;
1979 __asm {
1980 mov ecx, dst
1981 mov al, src
1982 lock xadd [ecx], al
1983 mov result, al
1984 }
1985
1986 return result;
1987 }
1988 #else
1989 {
1990 C89ATOMIC_FETCH_ADD_LOCK(8, dst, src, order);
1991 }
1992 #endif
1993 }
1994
1995 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
1996 {
1997 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
1998 {
1999 c89atomic_uint16 result = 0;
2000
2001 (void)order;
2002 __asm {
2003 mov ecx, dst
2004 mov ax, src
2005 lock xadd [ecx], ax
2006 mov result, ax
2007 }
2008
2009 return result;
2010 }
2011 #else
2012 {
2013 C89ATOMIC_FETCH_ADD_LOCK(16, dst, src, order);
2014 }
2015 #endif
2016 }
2017
2018 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2019 {
2020 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2021 {
2022 c89atomic_uint32 result = 0;
2023
2024 (void)order;
2025 __asm {
2026 mov ecx, dst
2027 mov eax, src
2028 lock xadd [ecx], eax
2029 mov result, eax
2030 }
2031
2032 return result;
2033 }
2034 #else
2035 {
2036 C89ATOMIC_FETCH_ADD_LOCK(32, dst, src, order);
2037 }
2038 #endif
2039 }
2040
2041 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2042 {
2043 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2044 {
2045 C89ATOMIC_FETCH_ADD_CAS(64, dst, src, order);
2046 }
2047 #else
2048 {
2049 C89ATOMIC_FETCH_ADD_LOCK(64, dst, src, order);
2050 }
2051 #endif
2052 }
2053
2054
2055 /* fetch_sub() */
2056 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2057 {
2058 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2059 {
2060 c89atomic_uint8 result = 0;
2061
2062 (void)order;
2063 __asm {
2064 mov ecx, dst
2065 mov al, src
2066 neg al
2067 lock xadd [ecx], al
2068 mov result, al
2069 }
2070
2071 return result;
2072 }
2073 #else
2074 {
2075 C89ATOMIC_FETCH_ADD_LOCK(8, dst, (c89atomic_uint8)(-(c89atomic_int8)src), order);
2076 }
2077 #endif
2078 }
2079
2080 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2081 {
2082 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2083 {
2084 c89atomic_uint16 result = 0;
2085
2086 (void)order;
2087 __asm {
2088 mov ecx, dst
2089 mov ax, src
2090 neg ax
2091 lock xadd [ecx], ax
2092 mov result, ax
2093 }
2094
2095 return result;
2096 }
2097 #else
2098 {
2099 C89ATOMIC_FETCH_ADD_LOCK(16, dst, (c89atomic_uint16)(-(c89atomic_int16)src), order);
2100 }
2101 #endif
2102 }
2103
2104 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2105 {
2106 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2107 {
2108 c89atomic_uint32 result = 0;
2109
2110 (void)order;
2111 __asm {
2112 mov ecx, dst
2113 mov eax, src
2114 neg eax
2115 lock xadd [ecx], eax
2116 mov result, eax
2117 }
2118
2119 return result;
2120 }
2121 #else
2122 {
2123 C89ATOMIC_FETCH_ADD_LOCK(32, dst, (c89atomic_uint32)(-(c89atomic_int32)src), order);
2124 }
2125 #endif
2126 }
2127
2128 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2129 {
2130 C89ATOMIC_FETCH_ADD_CAS(64, dst, (c89atomic_uint64)(-(c89atomic_int64)src), order);
2131 }
2132
2133
2134 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2135 {
2136 C89ATOMIC_FETCH_AND_CAS(8, dst, src, order);
2137 }
2138
2139 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2140 {
2141 C89ATOMIC_FETCH_AND_CAS(16, dst, src, order);
2142 }
2143
2144 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2145 {
2146 C89ATOMIC_FETCH_AND_CAS(32, dst, src, order);
2147 }
2148
2149 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2150 {
2151 C89ATOMIC_FETCH_AND_CAS(64, dst, src, order);
2152 }
2153
2154
2155 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2156 {
2157 C89ATOMIC_FETCH_OR_CAS(8, dst, src, order);
2158 }
2159
2160 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2161 {
2162 C89ATOMIC_FETCH_OR_CAS(16, dst, src, order);
2163 }
2164
2165 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2166 {
2167 C89ATOMIC_FETCH_OR_CAS(32, dst, src, order);
2168 }
2169
2170 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2171 {
2172 C89ATOMIC_FETCH_OR_CAS(64, dst, src, order);
2173 }
2174
2175
2176 static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2177 {
2178 C89ATOMIC_FETCH_XOR_CAS(8, dst, src, order);
2179 }
2180
2181 static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2182 {
2183 C89ATOMIC_FETCH_XOR_CAS(16, dst, src, order);
2184 }
2185
2186 static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2187 {
2188 C89ATOMIC_FETCH_XOR_CAS(32, dst, src, order);
2189 }
2190
2191 static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2192 {
2193 C89ATOMIC_FETCH_XOR_CAS(64, dst, src, order);
2194 }
2195
2196
2197 /* atomic_thread_fence */
2198 static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(c89atomic_memory_order order)
2199 {
2200 (void)order;
2201 __asm {
2202 lock add dword ptr [esp], 0
2203 }
2204 }
2205
2206 /* atomic_signal_fence */
2207 #define c89atomic_signal_fence(order) __asm {}; (void)order
2208#endif
2209
2210#if defined(C89ATOMIC_MODERN_GCC)
2211 #define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
2212
2213 #define c89atomic_thread_fence(order) __atomic_thread_fence(order)
2214 #define c89atomic_signal_fence(order) __atomic_signal_fence(order)
2215
2216 #define c89atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr)
2217 #define c89atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr)
2218 #define c89atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr)
2219 #define c89atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr)
2220
2221 #define c89atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order)
2222 #define c89atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order)
2223 #define c89atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order)
2224 #define c89atomic_store_explicit_64(dst, src, order) __atomic_store_n(dst, src, order)
2225
2226 #define c89atomic_load_explicit_8( dst, order) __atomic_load_n(dst, order)
2227 #define c89atomic_load_explicit_16(dst, order) __atomic_load_n(dst, order)
2228 #define c89atomic_load_explicit_32(dst, order) __atomic_load_n(dst, order)
2229 #define c89atomic_load_explicit_64(dst, order) __atomic_load_n(dst, order)
2230
2231 #define c89atomic_exchange_explicit_8( dst, src, order) __atomic_exchange_n(dst, src, order)
2232 #define c89atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order)
2233 #define c89atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order)
2234 #define c89atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order)
2235
2236 #define c89atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder)
2237 #define c89atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder)
2238 #define c89atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder)
2239 #define c89atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder)
2240
2241 #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder)
2242 #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder)
2243 #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder)
2244 #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder)
2245
2246 #define c89atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order)
2247 #define c89atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order)
2248 #define c89atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order)
2249 #define c89atomic_fetch_add_explicit_64(dst, src, order) __atomic_fetch_add(dst, src, order)
2250
2251 #define c89atomic_fetch_sub_explicit_8( dst, src, order) __atomic_fetch_sub(dst, src, order)
2252 #define c89atomic_fetch_sub_explicit_16(dst, src, order) __atomic_fetch_sub(dst, src, order)
2253 #define c89atomic_fetch_sub_explicit_32(dst, src, order) __atomic_fetch_sub(dst, src, order)
2254 #define c89atomic_fetch_sub_explicit_64(dst, src, order) __atomic_fetch_sub(dst, src, order)
2255
2256 #define c89atomic_fetch_or_explicit_8( dst, src, order) __atomic_fetch_or(dst, src, order)
2257 #define c89atomic_fetch_or_explicit_16(dst, src, order) __atomic_fetch_or(dst, src, order)
2258 #define c89atomic_fetch_or_explicit_32(dst, src, order) __atomic_fetch_or(dst, src, order)
2259 #define c89atomic_fetch_or_explicit_64(dst, src, order) __atomic_fetch_or(dst, src, order)
2260
2261 #define c89atomic_fetch_xor_explicit_8( dst, src, order) __atomic_fetch_xor(dst, src, order)
2262 #define c89atomic_fetch_xor_explicit_16(dst, src, order) __atomic_fetch_xor(dst, src, order)
2263 #define c89atomic_fetch_xor_explicit_32(dst, src, order) __atomic_fetch_xor(dst, src, order)
2264 #define c89atomic_fetch_xor_explicit_64(dst, src, order) __atomic_fetch_xor(dst, src, order)
2265
2266 #define c89atomic_fetch_and_explicit_8( dst, src, order) __atomic_fetch_and(dst, src, order)
2267 #define c89atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order)
2268 #define c89atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order)
2269 #define c89atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order)
2270
2271 /* CAS needs to be implemented as a function because _atomic_compare_exchange_n() needs to take the address of the expected value. */
2272 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 replacement)
2273 {
2274 __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
2275 return expected;
2276 }
2277
2278 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 replacement)
2279 {
2280 __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
2281 return expected;
2282 }
2283
2284 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 replacement)
2285 {
2286 __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
2287 return expected;
2288 }
2289
2290 /*
2291 The compare_and_swap function below will result in the following warning when compiling via Android Studio
2292 which uses Clang:
2293
2294 warning: misaligned atomic operation may incur significant performance penalty [-Watomic-alignment]
2295
2296 What I think is happening is that Clang is looking at this function in a bubble and not considering the
2297 broader context in which the function is being used, which is surprising to me considering the function is
2298 marked as force-inlined. So I think this warning is being reported incorrectly.
2299
2300 I've only seen this warning with compare_and_swap_64(). If this is happening with compare_and_swap_32/16/8(),
2301 just move the pragmas up to encapsulate the affected functions.
2302 */
2303 #if defined(__clang__)
2304 #pragma clang diagnostic push
2305 #if __clang_major__ >= 8 /* <-- I don't know the exact version of Clang -Watomic-alignment was introduced, but it's definitely available in version 8. With my version of TrueOS2 I have Clang version 6 installed, but I'm getting a warning about an unknown warning group. */
2306 #pragma clang diagnostic ignored "-Watomic-alignment"
2307 #endif
2308 #endif
2309 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 replacement)
2310 {
2311 __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
2312 return expected;
2313 }
2314 #if defined(__clang__)
2315 #pragma clang diagnostic pop
2316 #endif
2317#endif
2318
2319#if defined(C89ATOMIC_LEGACY_GCC) || defined(C89ATOMIC_LEGACY_GCC_ASM)
2320 #define c89atomic_signal_fence(order) __asm__ __volatile__("":::"memory")
2321
2322 #if defined(C89ATOMIC_LEGACY_GCC)
2323 /* Legacy GCC atomic built-ins. Everything is a full memory barrier. */
2324 #define c89atomic_thread_fence(order) __sync_synchronize(), (void)order
2325
2326
2327 /* compare_and_swap() */
2328 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 replacement)
2329 {
2330 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2331 {
2332 return __sync_val_compare_and_swap(dst, expected, replacement);
2333 }
2334 #else
2335 {
2336 C89ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement);
2337 }
2338 #endif
2339 }
2340
2341 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 replacement)
2342 {
2343 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2344 {
2345 return __sync_val_compare_and_swap(dst, expected, replacement);
2346 }
2347 #else
2348 {
2349 C89ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement);
2350 }
2351 #endif
2352 }
2353
2354 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 replacement)
2355 {
2356 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2357 {
2358 return __sync_val_compare_and_swap(dst, expected, replacement);
2359 }
2360 #else
2361 {
2362 C89ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement);
2363 }
2364 #endif
2365 }
2366
2367 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 replacement)
2368 {
2369 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2370 {
2371 return __sync_val_compare_and_swap(dst, expected, replacement);
2372 }
2373 #else
2374 {
2375 C89ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement);
2376 }
2377 #endif
2378 }
2379
2380
2381 /* Atomic loads can be implemented in terms of a compare-and-swap. Need to implement as functions to silence warnings about `order` being unused. */
2382 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
2383 {
2384 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2385 {
2386 (void)order; /* Always using the strongest memory order. */
2387 return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0);
2388 }
2389 #else
2390 {
2391 C89ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order);
2392 }
2393 #endif
2394 }
2395
2396 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
2397 {
2398 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2399 {
2400 (void)order; /* Always using the strongest memory order. */
2401 return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0);
2402 }
2403 #else
2404 {
2405 C89ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order);
2406 }
2407 #endif
2408 }
2409
2410 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order)
2411 {
2412 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2413 {
2414 (void)order; /* Always using the strongest memory order. */
2415 return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0);
2416 }
2417 #else
2418 {
2419 C89ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order);
2420 }
2421 #endif
2422 }
2423
2424 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order)
2425 {
2426 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2427 {
2428 (void)order; /* Always using the strongest memory order. */
2429 return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0);
2430 }
2431 #else
2432 {
2433 C89ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order);
2434 }
2435 #endif
2436 }
2437
2438
2439
2440 /* exchange() */
2441 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2442 {
2443 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2444 {
2445 if (order > c89atomic_memory_order_acquire) {
2446 __sync_synchronize();
2447 }
2448
2449 return __sync_lock_test_and_set(dst, src);
2450 }
2451 #else
2452 {
2453 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order);
2454 }
2455 #endif
2456 }
2457
2458 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2459 {
2460 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2461 {
2462 if (order > c89atomic_memory_order_acquire) {
2463 __sync_synchronize();
2464 }
2465
2466 return __sync_lock_test_and_set(dst, src);
2467 }
2468 #else
2469 {
2470 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order);
2471 }
2472 #endif
2473 }
2474
2475 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2476 {
2477 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2478 {
2479 if (order > c89atomic_memory_order_acquire) {
2480 __sync_synchronize();
2481 }
2482
2483 return __sync_lock_test_and_set(dst, src);
2484 }
2485 #else
2486 {
2487 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order);
2488 }
2489 #endif
2490 }
2491
2492 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2493 {
2494 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2495 {
2496 if (order > c89atomic_memory_order_acquire) {
2497 __sync_synchronize();
2498 }
2499
2500 return __sync_lock_test_and_set(dst, src);
2501 }
2502 #else
2503 {
2504 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order);
2505 }
2506 #endif
2507 }
2508
2509
2510 /* store() */
2511 #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order)
2512 #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order)
2513 #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order)
2514 #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order)
2515
2516
2517 /* fetch_add() */
2518 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2519 {
2520 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2521 {
2522 (void)order;
2523 return __sync_fetch_and_add(dst, src);
2524 }
2525 #else
2526 {
2527 C89ATOMIC_FETCH_ADD_LOCK(8, dst, src, order);
2528 }
2529 #endif
2530 }
2531
2532 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2533 {
2534 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2535 {
2536 (void)order;
2537 return __sync_fetch_and_add(dst, src);
2538 }
2539 #else
2540 {
2541 C89ATOMIC_FETCH_ADD_LOCK(16, dst, src, order);
2542 }
2543 #endif
2544 }
2545
2546 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2547 {
2548 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2549 {
2550 (void)order;
2551 return __sync_fetch_and_add(dst, src);
2552 }
2553 #else
2554 {
2555 C89ATOMIC_FETCH_ADD_LOCK(32, dst, src, order);
2556 }
2557 #endif
2558 }
2559
2560 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2561 {
2562 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2563 {
2564 (void)order;
2565 return __sync_fetch_and_add(dst, src);
2566 }
2567 #else
2568 {
2569 C89ATOMIC_FETCH_ADD_LOCK(64, dst, src, order);
2570 }
2571 #endif
2572 }
2573
2574
2575 /* fetch_sub() */
2576 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2577 {
2578 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2579 {
2580 (void)order;
2581 return __sync_fetch_and_sub(dst, src);
2582 }
2583 #else
2584 {
2585 C89ATOMIC_FETCH_ADD_LOCK(8, dst, (c89atomic_uint8)(-(c89atomic_int8)src), order);
2586 }
2587 #endif
2588 }
2589
2590 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2591 {
2592 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2593 {
2594 (void)order;
2595 return __sync_fetch_and_sub(dst, src);
2596 }
2597 #else
2598 {
2599 C89ATOMIC_FETCH_ADD_LOCK(16, dst, (c89atomic_uint16)(-(c89atomic_int16)src), order);
2600 }
2601 #endif
2602 }
2603
2604 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2605 {
2606 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2607 {
2608 (void)order;
2609 return __sync_fetch_and_sub(dst, src);
2610 }
2611 #else
2612 {
2613 C89ATOMIC_FETCH_ADD_LOCK(32, dst, (c89atomic_uint32)(-(c89atomic_int32)src), order);
2614 }
2615 #endif
2616 }
2617
2618 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2619 {
2620 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2621 {
2622 (void)order;
2623 return __sync_fetch_and_sub(dst, src);
2624 }
2625 #else
2626 {
2627 C89ATOMIC_FETCH_ADD_LOCK(64, dst, (c89atomic_uint64)(-(c89atomic_int64)src), order);
2628 }
2629 #endif
2630 }
2631
2632
2633 /* fetch_and() */
2634 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2635 {
2636 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2637 {
2638 (void)order;
2639 return __sync_fetch_and_and(dst, src);
2640 }
2641 #else
2642 {
2643 C89ATOMIC_FETCH_AND_CAS(8, dst, src, order);
2644 }
2645 #endif
2646 }
2647
2648 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2649 {
2650 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2651 {
2652 (void)order;
2653 return __sync_fetch_and_and(dst, src);
2654 }
2655 #else
2656 {
2657 C89ATOMIC_FETCH_AND_CAS(16, dst, src, order);
2658 }
2659 #endif
2660 }
2661
2662 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2663 {
2664 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2665 {
2666 (void)order;
2667 return __sync_fetch_and_and(dst, src);
2668 }
2669 #else
2670 {
2671 C89ATOMIC_FETCH_AND_CAS(32, dst, src, order);
2672 }
2673 #endif
2674 }
2675
2676 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2677 {
2678 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2679 {
2680 (void)order;
2681 return __sync_fetch_and_and(dst, src);
2682 }
2683 #else
2684 {
2685 C89ATOMIC_FETCH_AND_CAS(64, dst, src, order);
2686 }
2687 #endif
2688 }
2689
2690
2691 /* fetch_or() */
2692 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2693 {
2694 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2695 {
2696 (void)order;
2697 return __sync_fetch_and_or(dst, src);
2698 }
2699 #else
2700 {
2701 C89ATOMIC_FETCH_OR_CAS(8, dst, src, order);
2702 }
2703 #endif
2704 }
2705
2706 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2707 {
2708 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2709 {
2710 (void)order;
2711 return __sync_fetch_and_or(dst, src);
2712 }
2713 #else
2714 {
2715 C89ATOMIC_FETCH_OR_CAS(16, dst, src, order);
2716 }
2717 #endif
2718 }
2719
2720 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2721 {
2722 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2723 {
2724 (void)order;
2725 return __sync_fetch_and_or(dst, src);
2726 }
2727 #else
2728 {
2729 C89ATOMIC_FETCH_OR_CAS(32, dst, src, order);
2730 }
2731 #endif
2732 }
2733
2734 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2735 {
2736 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2737 {
2738 (void)order;
2739 return __sync_fetch_and_or(dst, src);
2740 }
2741 #else
2742 {
2743 C89ATOMIC_FETCH_OR_CAS(64, dst, src, order);
2744 }
2745 #endif
2746 }
2747
2748
2749 /* fetch_xor() */
2750 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
2751 {
2752 #if defined(C89ATOMIC_IS_LOCK_FREE_8)
2753 {
2754 (void)order;
2755 return __sync_fetch_and_xor(dst, src);
2756 }
2757 #else
2758 {
2759 C89ATOMIC_FETCH_XOR_CAS(8, dst, src, order);
2760 }
2761 #endif
2762 }
2763
2764 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
2765 {
2766 #if defined(C89ATOMIC_IS_LOCK_FREE_16)
2767 {
2768 (void)order;
2769 return __sync_fetch_and_xor(dst, src);
2770 }
2771 #else
2772 {
2773 C89ATOMIC_FETCH_XOR_CAS(16, dst, src, order);
2774 }
2775 #endif
2776 }
2777
2778 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
2779 {
2780 #if defined(C89ATOMIC_IS_LOCK_FREE_32)
2781 {
2782 (void)order;
2783 return __sync_fetch_and_xor(dst, src);
2784 }
2785 #else
2786 {
2787 C89ATOMIC_FETCH_XOR_CAS(32, dst, src, order);
2788 }
2789 #endif
2790 }
2791
2792 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
2793 {
2794 #if defined(C89ATOMIC_IS_LOCK_FREE_64)
2795 {
2796 (void)order;
2797 return __sync_fetch_and_xor(dst, src);
2798 }
2799 #else
2800 {
2801 C89ATOMIC_FETCH_XOR_CAS(64, dst, src, order);
2802 }
2803 #endif
2804 }
2805 #elif defined(C89ATOMIC_LEGACY_GCC_ASM)
2806 /* Old GCC, or non-GCC compilers supporting GCC-style inlined assembly. The inlined assembly below uses Gas syntax. */
2807 #define C89ATOMIC_CMPXCHG_GCC_X86(instructionSizeSuffix, result, dst, expected, replacement)
2808 __asm__ __volatile__(
2809 "lock; cmpxchg"instructionSizeSuffix" %2, %1"
2810 : "=a"(result), /* %0 */
2811 "=m"(*dst) /* %1 */
2812 : "r"(replacement), /* %2 */
2813 "0"(expected), /* %3 */
2814 "m"(*dst) /* %4 */
2815 : "cc", "memory")
2816
2817 #define C89ATOMIC_XADD_GCC_X86(instructionSizeSuffix, result, dst, src)
2818 __asm__ __volatile__(
2819 "lock; xadd"instructionSizeSuffix" %0, %1"
2820 : "=a"(result), /* %0 */
2821 "=m"(*dst) /* %1 */
2822 : "0"(src), /* %2 */
2823 "m"(*dst) /* %3 */
2824 : "cc", "memory")
2825
2826
2827 /* compare_and_swap() */
2828 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 replacement)
2829 {
2830 #if defined(C89ATOMIC_IS_LOCK_FREE_8) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
2831 {
2832 c89atomic_uint8 result;
2833 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
2834 {
2835 C89ATOMIC_CMPXCHG_GCC_X86("b", result, dst, expected, replacement);
2836 }
2837 #else
2838 {
2839 #error Unsupported architecture.
2840 }
2841 #endif
2842 return result;
2843 }
2844 #else
2845 {
2846 C89ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement);
2847 }
2848 #endif
2849 }
2850
2851 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 replacement)
2852 {
2853 #if defined(C89ATOMIC_IS_LOCK_FREE_16) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
2854 {
2855 c89atomic_uint16 result;
2856 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
2857 {
2858 C89ATOMIC_CMPXCHG_GCC_X86("w", result, dst, expected, replacement);
2859 }
2860 #else
2861 {
2862 #error Unsupported architecture.
2863 }
2864 #endif
2865 return result;
2866 }
2867 #else
2868 {
2869 C89ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement);
2870 }
2871 #endif
2872 }
2873
2874 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 replacement)
2875 {
2876 #if defined(C89ATOMIC_IS_LOCK_FREE_32) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
2877 {
2878 c89atomic_uint32 result;
2879 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
2880 {
2881 C89ATOMIC_CMPXCHG_GCC_X86("l", result, dst, expected, replacement);
2882 }
2883 #else
2884 {
2885 #error Unsupported architecture.
2886 }
2887 #endif
2888 return result;
2889 }
2890 #else
2891 {
2892 C89ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement);
2893 }
2894 #endif
2895 }
2896
2897 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 replacement)
2898 {
2899 #if defined(C89ATOMIC_IS_LOCK_FREE_64) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
2900 {
2901 c89atomic_uint64 result;
2902 #if defined(C89ATOMIC_X86)
2903 {
2904 /*
2905 We can't use the standard CMPXCHG here because x86 does not support it with 64-bit values. We need to instead use CMPXCHG8B
2906 which is a bit harder to use. The annoying part with this is the use of the -fPIC compiler switch which requires the EBX
2907 register never be modified. The problem is that CMPXCHG8B requires us to write our replacement value to it. I'm resolving this
2908 by just pushing and popping the EBX register manually.
2909 */
2910 c89atomic_uint32 resultEAX;
2911 c89atomic_uint32 resultEDX;
2912 __asm__ __volatile__(
2913 "pushl %%ebx\n"
2914 "movl %4, %%ebx\n"
2915 "lock cmpxchg8b (%%edi)\n"
2916 "popl %%ebx\n"
2917 : "=a"(resultEAX),
2918 "=d"(resultEDX)
2919 : "a"((c89atomic_uint32)(expected & 0xFFFFFFFF)), /* EAX */
2920 "d"((c89atomic_uint32)(expected >> 32)), /* EDX */
2921 "r"((c89atomic_uint32)(replacement & 0xFFFFFFFF)), /* %4 */
2922 "c"((c89atomic_uint32)(replacement >> 32)), /* ECX */
2923 "D"(dst) /* EDI */
2924 : "memory", "cc");
2925 result = ((c89atomic_uint64)resultEDX << 32) | resultEAX;
2926 }
2927 #elif defined(C89ATOMIC_X64)
2928 {
2929 C89ATOMIC_CMPXCHG_GCC_X86("q", result, dst, expected, replacement);
2930 }
2931 #else
2932 {
2933 #error Unsupported architecture.
2934 }
2935 #endif
2936 return result;
2937 }
2938 #else
2939 {
2940 C89ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement);
2941 }
2942 #endif
2943 }
2944
2945
2946 /* Atomic loads can be implemented in terms of a compare-and-swap. Need to implement as functions to silence warnings about `order` being unused. */
2947 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* dst, c89atomic_memory_order order)
2948 {
2949 #if defined(C89ATOMIC_IS_LOCK_FREE_8) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
2950 {
2951 c89atomic_uint8 result;
2952 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
2953 {
2954 if (order == c89atomic_memory_order_relaxed) {
2955 C89ATOMIC_LOAD_RELAXED_GCC_X86("b", result, dst);
2956 } else if (order <= c89atomic_memory_order_release) {
2957 C89ATOMIC_LOAD_RELEASE_GCC_X86("b", result, dst);
2958 } else {
2959 C89ATOMIC_LOAD_SEQ_CST_GCC_X86("b", result, dst);
2960 }
2961 }
2962 #else
2963 {
2964 #error Unsupported architecture.
2965 }
2966 #endif
2967 return result;
2968 }
2969 #else
2970 {
2971 C89ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order);
2972 }
2973 #endif
2974 }
2975
2976 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* dst, c89atomic_memory_order order)
2977 {
2978 #if defined(C89ATOMIC_IS_LOCK_FREE_16) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
2979 {
2980 c89atomic_uint16 result;
2981 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
2982 {
2983 if (order == c89atomic_memory_order_relaxed) {
2984 C89ATOMIC_LOAD_RELAXED_GCC_X86("w", result, dst);
2985 } else if (order <= c89atomic_memory_order_release) {
2986 C89ATOMIC_LOAD_RELEASE_GCC_X86("w", result, dst);
2987 } else {
2988 C89ATOMIC_LOAD_SEQ_CST_GCC_X86("w", result, dst);
2989 }
2990 }
2991 #else
2992 {
2993 #error Unsupported architecture.
2994 }
2995 #endif
2996 return result;
2997 }
2998 #else
2999 {
3000 C89ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order);
3001 }
3002 #endif
3003 }
3004
3005 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* dst, c89atomic_memory_order order)
3006 {
3007 #if defined(C89ATOMIC_IS_LOCK_FREE_32) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3008 {
3009 c89atomic_uint32 result;
3010 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3011 {
3012 if (order == c89atomic_memory_order_relaxed) {
3013 C89ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst);
3014 } else if (order <= c89atomic_memory_order_release) {
3015 C89ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst);
3016 } else {
3017 C89ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst);
3018 }
3019 }
3020 #else
3021 {
3022 #error Unsupported architecture.
3023 }
3024 #endif
3025 return result;
3026 }
3027 #else
3028 {
3029 C89ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order);
3030 }
3031 #endif
3032 }
3033
3034 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* dst, c89atomic_memory_order order)
3035 {
3036 #if defined(C89ATOMIC_IS_LOCK_FREE_64) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3037 {
3038 c89atomic_uint64 result;
3039 #if defined(C89ATOMIC_X64)
3040 {
3041 if (order == c89atomic_memory_order_relaxed) {
3042 C89ATOMIC_LOAD_RELAXED_GCC_X86("q", result, dst);
3043 } else if (order <= c89atomic_memory_order_release) {
3044 C89ATOMIC_LOAD_RELEASE_GCC_X86("q", result, dst);
3045 } else {
3046 C89ATOMIC_LOAD_SEQ_CST_GCC_X86("q", result, dst);
3047 }
3048 }
3049 #elif defined(C89ATOMIC_X86)
3050 {
3051 (void)order;
3052 return c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, 0, 0);
3053 }
3054 #else
3055 {
3056 #error Unsupported architecture.
3057 }
3058 #endif
3059 return result;
3060 }
3061 #else
3062 {
3063 C89ATOMIC_LOAD_EXPLICIT_LOCK(64, dst, order);
3064 }
3065 #endif
3066 }
3067
3068
3069 /* exchange() */
3070 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3071 {
3072 #if defined(C89ATOMIC_IS_LOCK_FREE_8) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3073 {
3074 c89atomic_uint8 result;
3075 (void)order;
3076 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3077 {
3078 C89ATOMIC_XCHG_GCC_X86("b", result, dst, src);
3079 }
3080 #else
3081 {
3082 #error Unsupported architecture.
3083 }
3084 #endif
3085 return result;
3086 }
3087 #else
3088 {
3089 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order);
3090 }
3091 #endif
3092 }
3093
3094 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3095 {
3096 #if defined(C89ATOMIC_IS_LOCK_FREE_16) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3097 {
3098 c89atomic_uint16 result;
3099 (void)order;
3100 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3101 {
3102 C89ATOMIC_XCHG_GCC_X86("w", result, dst, src);
3103 }
3104 #else
3105 {
3106 #error Unsupported architecture.
3107 }
3108 #endif
3109 return result;
3110 }
3111 #else
3112 {
3113 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order);
3114 }
3115 #endif
3116 }
3117
3118 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3119 {
3120 #if defined(C89ATOMIC_IS_LOCK_FREE_32) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3121 {
3122 c89atomic_uint32 result;
3123 (void)order;
3124 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3125 {
3126 C89ATOMIC_XCHG_GCC_X86("l", result, dst, src);
3127 }
3128 #else
3129 {
3130 #error Unsupported architecture.
3131 }
3132 #endif
3133 return result;
3134 }
3135 #else
3136 {
3137 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order);
3138 }
3139 #endif
3140 }
3141
3142 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3143 {
3144 #if defined(C89ATOMIC_IS_LOCK_FREE_64) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3145 {
3146 c89atomic_uint64 result;
3147 (void)order;
3148 #if defined(C89ATOMIC_X86)
3149 {
3150 C89ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order);
3151 }
3152 #elif defined(C89ATOMIC_X64)
3153 {
3154 C89ATOMIC_XCHG_GCC_X86("q", result, dst, src);
3155 }
3156 #else
3157 {
3158 #error Unsupported architecture.
3159 }
3160 #endif
3161 return result;
3162 }
3163 #else
3164 {
3165 C89ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order);
3166 }
3167 #endif
3168 }
3169
3170
3171 /* store() */
3172 static C89ATOMIC_INLINE void c89atomic_store_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3173 {
3174 #if defined(C89ATOMIC_IS_LOCK_FREE_8) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3175 {
3176 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3177 {
3178 if (order == c89atomic_memory_order_relaxed) {
3179 __asm__ __volatile__ (
3180 "movb %1, %0"
3181 : "=m"(*dst) /* %0 */
3182 : "r"(src) /* %1 */
3183 );
3184 } else {
3185 __asm__ __volatile__ (
3186 "xchgb %1, %0"
3187 : "=m"(*dst) /* %0 */
3188 : "r"(src) /* %1 */
3189 : "memory"
3190 );
3191 }
3192 }
3193 #else
3194 {
3195 #error Unsupported architecture.
3196 }
3197 #endif
3198 }
3199 #else
3200 {
3201 C89ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order);
3202 }
3203 #endif
3204 }
3205
3206 static C89ATOMIC_INLINE void c89atomic_store_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3207 {
3208 #if defined(C89ATOMIC_IS_LOCK_FREE_16) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3209 {
3210 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3211 {
3212 if (order == c89atomic_memory_order_relaxed) {
3213 __asm__ __volatile__ (
3214 "movw %1, %0"
3215 : "=m"(*dst) /* %0 */
3216 : "r"(src) /* %1 */
3217 );
3218 } else {
3219 __asm__ __volatile__ (
3220 "xchgw %1, %0"
3221 : "=m"(*dst) /* %0 */
3222 : "r"(src) /* %1 */
3223 : "memory"
3224 );
3225 }
3226 }
3227 #else
3228 {
3229 #error Unsupported architecture.
3230 }
3231 #endif
3232 }
3233 #else
3234 {
3235 C89ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order);
3236 }
3237 #endif
3238 }
3239
3240 static C89ATOMIC_INLINE void c89atomic_store_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3241 {
3242 #if defined(C89ATOMIC_IS_LOCK_FREE_32) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3243 {
3244 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3245 {
3246 if (order == c89atomic_memory_order_relaxed) {
3247 __asm__ __volatile__ (
3248 "movl %1, %0"
3249 : "=m"(*dst) /* %0 */
3250 : "r"(src) /* %1 */
3251 );
3252 } else {
3253 __asm__ __volatile__ (
3254 "xchgl %1, %0"
3255 : "=m"(*dst) /* %0 */
3256 : "r"(src) /* %1 */
3257 : "memory"
3258 );
3259 }
3260 }
3261 #else
3262 {
3263 #error Unsupported architecture.
3264 }
3265 #endif
3266 }
3267 #else
3268 {
3269 C89ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order);
3270 }
3271 #endif
3272 }
3273
3274 static C89ATOMIC_INLINE void c89atomic_store_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3275 {
3276 #if defined(C89ATOMIC_IS_LOCK_FREE_64) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3277 {
3278 #if defined(C89ATOMIC_X64)
3279 {
3280 if (order == c89atomic_memory_order_relaxed) {
3281 __asm__ __volatile__ (
3282 "movq %1, %0"
3283 : "=m"(*dst) /* %0 */
3284 : "r"(src) /* %1 */
3285 );
3286 } else {
3287 __asm__ __volatile__ (
3288 "xchgq %1, %0"
3289 : "=m"(*dst) /* %0 */
3290 : "r"(src) /* %1 */
3291 : "memory"
3292 );
3293 }
3294 }
3295 #else
3296 {
3297 C89ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order);
3298 }
3299 #endif
3300 }
3301 #else
3302 {
3303 C89ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order);
3304 }
3305 #endif
3306 }
3307
3308
3309 /* fetch_add() */
3310 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3311 {
3312 #if defined(C89ATOMIC_IS_LOCK_FREE_8) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3313 {
3314 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3315 {
3316 c89atomic_uint8 result;
3317
3318 (void)order;
3319 C89ATOMIC_XADD_GCC_X86("b", result, dst, src);
3320
3321 return result;
3322 }
3323 #else
3324 {
3325 #error Unsupported architecture.
3326 }
3327 #endif
3328 }
3329 #else
3330 {
3331 C89ATOMIC_FETCH_ADD_LOCK(8, dst, src, order);
3332 }
3333 #endif
3334 }
3335
3336 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3337 {
3338 #if defined(C89ATOMIC_IS_LOCK_FREE_16) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3339 {
3340 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3341 {
3342 c89atomic_uint16 result;
3343
3344 (void)order;
3345 C89ATOMIC_XADD_GCC_X86("w", result, dst, src);
3346
3347 return result;
3348 }
3349 #else
3350 {
3351 #error Unsupported architecture.
3352 }
3353 #endif
3354 }
3355 #else
3356 {
3357 C89ATOMIC_FETCH_ADD_LOCK(16, dst, src, order);
3358 }
3359 #endif
3360 }
3361
3362 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3363 {
3364 #if defined(C89ATOMIC_IS_LOCK_FREE_32) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3365 {
3366 #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
3367 {
3368 c89atomic_uint32 result;
3369
3370 (void)order;
3371 C89ATOMIC_XADD_GCC_X86("l", result, dst, src);
3372
3373 return result;
3374 }
3375 #else
3376 {
3377 #error Unsupported architecture.
3378 }
3379 #endif
3380 }
3381 #else
3382 {
3383 C89ATOMIC_FETCH_ADD_LOCK(32, dst, src, order);
3384 }
3385 #endif
3386 }
3387
3388 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3389 {
3390 #if defined(C89ATOMIC_IS_LOCK_FREE_64) && (defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64))
3391 {
3392 #if defined(C89ATOMIC_X86)
3393 {
3394 C89ATOMIC_FETCH_ADD_CAS(64, dst, src, order);
3395 }
3396 #elif defined(C89ATOMIC_X64)
3397 {
3398 c89atomic_uint64 result;
3399
3400 C89ATOMIC_XADD_GCC_X86("q", result, dst, src);
3401
3402 (void)order;
3403 return result;
3404 }
3405 #else
3406 {
3407 #error Unsupported architecture.
3408 }
3409 #endif
3410 }
3411 #else
3412 {
3413 C89ATOMIC_FETCH_ADD_LOCK(64, dst, src, order);
3414 }
3415 #endif
3416 }
3417
3418
3419 /* fetch_sub() */
3420 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3421 {
3422 return c89atomic_fetch_add_explicit_8(dst, (c89atomic_uint8)(-(c89atomic_int8)src), order);
3423 }
3424
3425 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3426 {
3427 return c89atomic_fetch_add_explicit_16(dst, (c89atomic_uint16)(-(c89atomic_int16)src), order);
3428 }
3429
3430 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3431 {
3432 return c89atomic_fetch_add_explicit_32(dst, (c89atomic_uint32)(-(c89atomic_int32)src), order);
3433 }
3434
3435 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3436 {
3437 return c89atomic_fetch_add_explicit_64(dst, (c89atomic_uint64)(-(c89atomic_int64)src), order);
3438 }
3439
3440
3441 /* fetch_and() */
3442 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3443 {
3444 C89ATOMIC_FETCH_AND_CAS(8, dst, src, order);
3445 }
3446
3447 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3448 {
3449 C89ATOMIC_FETCH_AND_CAS(16, dst, src, order);
3450 }
3451
3452 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3453 {
3454 C89ATOMIC_FETCH_AND_CAS(32, dst, src, order);
3455 }
3456
3457 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3458 {
3459 C89ATOMIC_FETCH_AND_CAS(64, dst, src, order);
3460 }
3461
3462
3463 /* fetch_or() */
3464 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3465 {
3466 C89ATOMIC_FETCH_OR_CAS(8, dst, src, order);
3467 }
3468
3469 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3470 {
3471 C89ATOMIC_FETCH_OR_CAS(16, dst, src, order);
3472 }
3473
3474 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3475 {
3476 C89ATOMIC_FETCH_OR_CAS(32, dst, src, order);
3477 }
3478
3479 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3480 {
3481 C89ATOMIC_FETCH_OR_CAS(64, dst, src, order);
3482 }
3483
3484
3485 /* fetch_xor() */
3486 static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
3487 {
3488 C89ATOMIC_FETCH_XOR_CAS(8, dst, src, order);
3489 }
3490
3491 static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
3492 {
3493 C89ATOMIC_FETCH_XOR_CAS(16, dst, src, order);
3494 }
3495
3496 static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
3497 {
3498 C89ATOMIC_FETCH_XOR_CAS(32, dst, src, order);
3499 }
3500
3501 static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
3502 {
3503 C89ATOMIC_FETCH_XOR_CAS(64, dst, src, order);
3504 }
3505 #else
3506 #error Unsupported compiler.
3507 #endif
3508#endif
3509
3510
3511/*
3512Everything below this point is stuff that is implemented in terms of the functions defined above.
3513*/
3514
3515/* compare_exchange() */
3516#if !defined(C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE)
3517 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8* expected, c89atomic_uint8 replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3518 {
3519 c89atomic_uint8 result;
3520
3521 (void)successOrder;
3522 (void)failureOrder;
3523
3524 result = c89atomic_compare_and_swap_8(dst, *expected, replacement);
3525 if (result == *expected) {
3526 return 1;
3527 } else {
3528 *expected = result;
3529 return 0;
3530 }
3531 }
3532
3533 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16* expected, c89atomic_uint16 replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3534 {
3535 c89atomic_uint16 result;
3536
3537 (void)successOrder;
3538 (void)failureOrder;
3539
3540 result = c89atomic_compare_and_swap_16(dst, *expected, replacement);
3541 if (result == *expected) {
3542 return 1;
3543 } else {
3544 *expected = result;
3545 return 0;
3546 }
3547 }
3548
3549 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32* expected, c89atomic_uint32 replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3550 {
3551 c89atomic_uint32 result;
3552
3553 (void)successOrder;
3554 (void)failureOrder;
3555
3556 result = c89atomic_compare_and_swap_32(dst, *expected, replacement);
3557 if (result == *expected) {
3558 return 1;
3559 } else {
3560 *expected = result;
3561 return 0;
3562 }
3563 }
3564
3565 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_64(volatile c89atomic_uint64* dst, volatile c89atomic_uint64* expected, c89atomic_uint64 replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3566 {
3567 c89atomic_uint64 result;
3568
3569 (void)successOrder;
3570 (void)failureOrder;
3571
3572 result = c89atomic_compare_and_swap_64(dst, *expected, replacement);
3573 if (result == *expected) {
3574 return 1;
3575 } else {
3576 *expected = result;
3577 return 0;
3578 }
3579 }
3580
3581 #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8 (dst, expected, replacement, successOrder, failureOrder)
3582 #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder)
3583 #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder)
3584 #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder)
3585#endif /* C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE */
3586/* END c89atomic_main.h */
3587
3588/* BEG c89atomic_ptr.h */
3589/*
3590Pointer versions of relevant operations. Note that some functions cannot be implemented as #defines because for some reason, some compilers
3591complain with a warning if you don't use the return value. I'm not fully sure why this happens, but to work around this, those particular
3592functions are just implemented as inlined functions.
3593*/
3594#if defined(C89ATOMIC_64BIT)
3595 static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr)
3596 {
3597 return c89atomic_is_lock_free_64((volatile c89atomic_uint64*)ptr);
3598 }
3599
3600 static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order)
3601 {
3602 return (void*)c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order);
3603 }
3604
3605 static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
3606 {
3607 c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order);
3608 }
3609
3610 static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
3611 {
3612 return (void*)c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order);
3613 }
3614
3615 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3616 {
3617 return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)replacement, successOrder, failureOrder);
3618 }
3619
3620 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3621 {
3622 return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)replacement, successOrder, failureOrder);
3623 }
3624
3625 static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement)
3626 {
3627 return (void*)c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)replacement);
3628 }
3629#elif defined(C89ATOMIC_32BIT)
3630 static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr)
3631 {
3632 return c89atomic_is_lock_free_32((volatile c89atomic_uint32*)ptr);
3633 }
3634
3635 static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order)
3636 {
3637 return (void*)c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order);
3638 }
3639
3640 static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
3641 {
3642 c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order);
3643 }
3644
3645 static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
3646 {
3647 return (void*)c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order);
3648 }
3649
3650 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3651 {
3652 return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)replacement, successOrder, failureOrder);
3653 }
3654
3655 static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3656 {
3657 return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)replacement, successOrder, failureOrder);
3658 }
3659
3660 static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement)
3661 {
3662 return (void*)c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)replacement);
3663 }
3664#else
3665 #error Unsupported architecture.
3666#endif
3667
3668/* Implicit Pointer. */
3669#define c89atomic_store_ptr(dst, src) c89atomic_store_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst)
3670#define c89atomic_load_ptr(ptr) c89atomic_load_explicit_ptr((volatile void**)ptr, c89atomic_memory_order_seq_cst)
3671#define c89atomic_exchange_ptr(dst, src) c89atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst)
3672#define c89atomic_compare_exchange_strong_ptr(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3673#define c89atomic_compare_exchange_weak_ptr(dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3674/* END c89atomic_ptr.h */
3675
3676/* BEG c89atomic_unsigned.h */
3677/* Implicit Unsigned Integer. */
3678#define c89atomic_store_8( dst, src) c89atomic_store_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
3679#define c89atomic_store_16(dst, src) c89atomic_store_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3680#define c89atomic_store_32(dst, src) c89atomic_store_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3681#define c89atomic_store_64(dst, src) c89atomic_store_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3682
3683#define c89atomic_load_8( ptr) c89atomic_load_explicit_8( ptr, c89atomic_memory_order_seq_cst)
3684#define c89atomic_load_16(ptr) c89atomic_load_explicit_16(ptr, c89atomic_memory_order_seq_cst)
3685#define c89atomic_load_32(ptr) c89atomic_load_explicit_32(ptr, c89atomic_memory_order_seq_cst)
3686#define c89atomic_load_64(ptr) c89atomic_load_explicit_64(ptr, c89atomic_memory_order_seq_cst)
3687
3688#define c89atomic_exchange_8( dst, src) c89atomic_exchange_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
3689#define c89atomic_exchange_16(dst, src) c89atomic_exchange_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3690#define c89atomic_exchange_32(dst, src) c89atomic_exchange_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3691#define c89atomic_exchange_64(dst, src) c89atomic_exchange_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3692
3693#define c89atomic_compare_exchange_strong_8( dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3694#define c89atomic_compare_exchange_strong_16(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3695#define c89atomic_compare_exchange_strong_32(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3696#define c89atomic_compare_exchange_strong_64(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3697
3698#define c89atomic_compare_exchange_weak_8( dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3699#define c89atomic_compare_exchange_weak_16( dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3700#define c89atomic_compare_exchange_weak_32( dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3701#define c89atomic_compare_exchange_weak_64( dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3702
3703#define c89atomic_fetch_add_8( dst, src) c89atomic_fetch_add_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
3704#define c89atomic_fetch_add_16(dst, src) c89atomic_fetch_add_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3705#define c89atomic_fetch_add_32(dst, src) c89atomic_fetch_add_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3706#define c89atomic_fetch_add_64(dst, src) c89atomic_fetch_add_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3707
3708#define c89atomic_fetch_sub_8( dst, src) c89atomic_fetch_sub_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
3709#define c89atomic_fetch_sub_16(dst, src) c89atomic_fetch_sub_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3710#define c89atomic_fetch_sub_32(dst, src) c89atomic_fetch_sub_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3711#define c89atomic_fetch_sub_64(dst, src) c89atomic_fetch_sub_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3712
3713#define c89atomic_fetch_or_8( dst, src) c89atomic_fetch_or_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
3714#define c89atomic_fetch_or_16(dst, src) c89atomic_fetch_or_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3715#define c89atomic_fetch_or_32(dst, src) c89atomic_fetch_or_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3716#define c89atomic_fetch_or_64(dst, src) c89atomic_fetch_or_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3717
3718#define c89atomic_fetch_xor_8( dst, src) c89atomic_fetch_xor_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
3719#define c89atomic_fetch_xor_16(dst, src) c89atomic_fetch_xor_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3720#define c89atomic_fetch_xor_32(dst, src) c89atomic_fetch_xor_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3721#define c89atomic_fetch_xor_64(dst, src) c89atomic_fetch_xor_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3722
3723#define c89atomic_fetch_and_8( dst, src) c89atomic_fetch_and_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
3724#define c89atomic_fetch_and_16(dst, src) c89atomic_fetch_and_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
3725#define c89atomic_fetch_and_32(dst, src) c89atomic_fetch_and_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
3726#define c89atomic_fetch_and_64(dst, src) c89atomic_fetch_and_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
3727/* END c89atomic_unsigned.h */
3728
3729
3730/* BEG c89atomic_signed.h */
3731/* Explicit Signed Integer. */
3732#define c89atomic_store_explicit_i8( dst, src, order) c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3733#define c89atomic_store_explicit_i16(dst, src, order) c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3734#define c89atomic_store_explicit_i32(dst, src, order) c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3735#define c89atomic_store_explicit_i64(dst, src, order) c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3736
3737#define c89atomic_load_explicit_i8( ptr, order) (c89atomic_int8 )c89atomic_load_explicit_8( (c89atomic_uint8* )ptr, order)
3738#define c89atomic_load_explicit_i16(ptr, order) (c89atomic_int16)c89atomic_load_explicit_16((c89atomic_uint16*)ptr, order)
3739#define c89atomic_load_explicit_i32(ptr, order) (c89atomic_int32)c89atomic_load_explicit_32((c89atomic_uint32*)ptr, order)
3740#define c89atomic_load_explicit_i64(ptr, order) (c89atomic_int64)c89atomic_load_explicit_64((c89atomic_uint64*)ptr, order)
3741
3742#define c89atomic_exchange_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_exchange_explicit_8 ((c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3743#define c89atomic_exchange_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_exchange_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3744#define c89atomic_exchange_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_exchange_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3745#define c89atomic_exchange_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_exchange_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3746
3747#define c89atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )replacement, successOrder, failureOrder)
3748#define c89atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)replacement, successOrder, failureOrder)
3749#define c89atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)replacement, successOrder, failureOrder)
3750#define c89atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)replacement, successOrder, failureOrder)
3751
3752#define c89atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )replacement, successOrder, failureOrder)
3753#define c89atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)replacement, successOrder, failureOrder)
3754#define c89atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)replacement, successOrder, failureOrder)
3755#define c89atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, successOrder, failureOrder) c89atomic_compare_exchange_weak_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)replacement, successOrder, failureOrder)
3756
3757#define c89atomic_fetch_add_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_add_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3758#define c89atomic_fetch_add_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_add_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3759#define c89atomic_fetch_add_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_add_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3760#define c89atomic_fetch_add_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_add_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3761
3762#define c89atomic_fetch_sub_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_sub_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3763#define c89atomic_fetch_sub_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_sub_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3764#define c89atomic_fetch_sub_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_sub_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3765#define c89atomic_fetch_sub_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_sub_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3766
3767#define c89atomic_fetch_or_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_or_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3768#define c89atomic_fetch_or_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_or_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3769#define c89atomic_fetch_or_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_or_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3770#define c89atomic_fetch_or_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_or_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3771
3772#define c89atomic_fetch_xor_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_xor_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3773#define c89atomic_fetch_xor_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_xor_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3774#define c89atomic_fetch_xor_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_xor_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3775#define c89atomic_fetch_xor_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_xor_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3776
3777#define c89atomic_fetch_and_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_fetch_and_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
3778#define c89atomic_fetch_and_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_fetch_and_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
3779#define c89atomic_fetch_and_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_fetch_and_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
3780#define c89atomic_fetch_and_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_fetch_and_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
3781
3782
3783/* Implicit Signed Integer. */
3784#define c89atomic_store_i8( dst, src) c89atomic_store_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3785#define c89atomic_store_i16(dst, src) c89atomic_store_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3786#define c89atomic_store_i32(dst, src) c89atomic_store_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3787#define c89atomic_store_i64(dst, src) c89atomic_store_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3788
3789#define c89atomic_load_i8( ptr) c89atomic_load_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
3790#define c89atomic_load_i16(ptr) c89atomic_load_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
3791#define c89atomic_load_i32(ptr) c89atomic_load_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
3792#define c89atomic_load_i64(ptr) c89atomic_load_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
3793
3794#define c89atomic_exchange_i8( dst, src) c89atomic_exchange_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3795#define c89atomic_exchange_i16(dst, src) c89atomic_exchange_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3796#define c89atomic_exchange_i32(dst, src) c89atomic_exchange_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3797#define c89atomic_exchange_i64(dst, src) c89atomic_exchange_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3798
3799#define c89atomic_compare_exchange_strong_i8( dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3800#define c89atomic_compare_exchange_strong_i16(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3801#define c89atomic_compare_exchange_strong_i32(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3802#define c89atomic_compare_exchange_strong_i64(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3803
3804#define c89atomic_compare_exchange_weak_i8( dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3805#define c89atomic_compare_exchange_weak_i16(dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3806#define c89atomic_compare_exchange_weak_i32(dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3807#define c89atomic_compare_exchange_weak_i64(dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
3808
3809#define c89atomic_fetch_add_i8( dst, src) c89atomic_fetch_add_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3810#define c89atomic_fetch_add_i16(dst, src) c89atomic_fetch_add_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3811#define c89atomic_fetch_add_i32(dst, src) c89atomic_fetch_add_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3812#define c89atomic_fetch_add_i64(dst, src) c89atomic_fetch_add_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3813
3814#define c89atomic_fetch_sub_i8( dst, src) c89atomic_fetch_sub_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3815#define c89atomic_fetch_sub_i16(dst, src) c89atomic_fetch_sub_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3816#define c89atomic_fetch_sub_i32(dst, src) c89atomic_fetch_sub_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3817#define c89atomic_fetch_sub_i64(dst, src) c89atomic_fetch_sub_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3818
3819#define c89atomic_fetch_or_i8( dst, src) c89atomic_fetch_or_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3820#define c89atomic_fetch_or_i16(dst, src) c89atomic_fetch_or_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3821#define c89atomic_fetch_or_i32(dst, src) c89atomic_fetch_or_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3822#define c89atomic_fetch_or_i64(dst, src) c89atomic_fetch_or_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3823
3824#define c89atomic_fetch_xor_i8( dst, src) c89atomic_fetch_xor_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3825#define c89atomic_fetch_xor_i16(dst, src) c89atomic_fetch_xor_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3826#define c89atomic_fetch_xor_i32(dst, src) c89atomic_fetch_xor_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3827#define c89atomic_fetch_xor_i64(dst, src) c89atomic_fetch_xor_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3828
3829#define c89atomic_fetch_and_i8( dst, src) c89atomic_fetch_and_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
3830#define c89atomic_fetch_and_i16(dst, src) c89atomic_fetch_and_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
3831#define c89atomic_fetch_and_i32(dst, src) c89atomic_fetch_and_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
3832#define c89atomic_fetch_and_i64(dst, src) c89atomic_fetch_and_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
3833
3834#define c89atomic_compare_and_swap_i8( dst, expected, dedsired) (c89atomic_int8 )c89atomic_compare_and_swap_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )expected, (c89atomic_uint8 )dedsired)
3835#define c89atomic_compare_and_swap_i16(dst, expected, dedsired) (c89atomic_int16)c89atomic_compare_and_swap_16((c89atomic_uint16*)dst, (c89atomic_uint16)expected, (c89atomic_uint16)dedsired)
3836#define c89atomic_compare_and_swap_i32(dst, expected, dedsired) (c89atomic_int32)c89atomic_compare_and_swap_32((c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)dedsired)
3837#define c89atomic_compare_and_swap_i64(dst, expected, dedsired) (c89atomic_int64)c89atomic_compare_and_swap_64((c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)dedsired)
3838/* END c89atomic_signed.h */
3839
3840
3841/* BEG c89atomic_float.h */
3842/* Floating Point Explicit. */
3843typedef union
3844{
3845 c89atomic_uint32 i;
3846 float f;
3847} c89atomic_if32;
3848
3849typedef union
3850{
3851 c89atomic_uint64 i;
3852 double f;
3853} c89atomic_if64;
3854
3855#define c89atomic_clear_explicit_f32(ptr, order) c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order)
3856#define c89atomic_clear_explicit_f64(ptr, order) c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order)
3857
3858static C89ATOMIC_INLINE void c89atomic_store_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
3859{
3860 c89atomic_if32 x;
3861 x.f = src;
3862 c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
3863}
3864
3865static C89ATOMIC_INLINE void c89atomic_store_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
3866{
3867 c89atomic_if64 x;
3868 x.f = src;
3869 c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
3870}
3871
3872
3873static C89ATOMIC_INLINE float c89atomic_load_explicit_f32(volatile const float* ptr, c89atomic_memory_order order)
3874{
3875 c89atomic_if32 r;
3876 r.i = c89atomic_load_explicit_32((volatile const c89atomic_uint32*)ptr, order);
3877 return r.f;
3878}
3879
3880static C89ATOMIC_INLINE double c89atomic_load_explicit_f64(volatile const double* ptr, c89atomic_memory_order order)
3881{
3882 c89atomic_if64 r;
3883 r.i = c89atomic_load_explicit_64((volatile const c89atomic_uint64*)ptr, order);
3884 return r.f;
3885}
3886
3887
3888static C89ATOMIC_INLINE float c89atomic_exchange_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
3889{
3890 c89atomic_if32 r;
3891 c89atomic_if32 x;
3892 x.f = src;
3893 r.i = c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
3894 return r.f;
3895}
3896
3897static C89ATOMIC_INLINE double c89atomic_exchange_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
3898{
3899 c89atomic_if64 r;
3900 c89atomic_if64 x;
3901 x.f = src;
3902 r.i = c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
3903 return r.f;
3904}
3905
3906
3907static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3908{
3909 c89atomic_if32 d;
3910 d.f = replacement;
3911 return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, d.i, successOrder, failureOrder);
3912}
3913
3914static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3915{
3916 c89atomic_if64 d;
3917 d.f = replacement;
3918 return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, d.i, successOrder, failureOrder);
3919}
3920
3921
3922static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3923{
3924 c89atomic_if32 d;
3925 d.f = replacement;
3926 return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, d.i, successOrder, failureOrder);
3927}
3928
3929static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double replacement, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
3930{
3931 c89atomic_if64 d;
3932 d.f = replacement;
3933 return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, d.i, successOrder, failureOrder);
3934}
3935
3936
3937static C89ATOMIC_INLINE float c89atomic_fetch_add_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
3938{
3939 c89atomic_if32 r;
3940 c89atomic_if32 x;
3941 x.f = src;
3942 r.i = c89atomic_fetch_add_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
3943 return r.f;
3944}
3945
3946static C89ATOMIC_INLINE double c89atomic_fetch_add_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
3947{
3948 c89atomic_if64 r;
3949 c89atomic_if64 x;
3950 x.f = src;
3951 r.i = c89atomic_fetch_add_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
3952 return r.f;
3953}
3954
3955
3956static C89ATOMIC_INLINE float c89atomic_fetch_sub_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
3957{
3958 c89atomic_if32 r;
3959 c89atomic_if32 x;
3960 x.f = src;
3961 r.i = c89atomic_fetch_sub_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
3962 return r.f;
3963}
3964
3965static C89ATOMIC_INLINE double c89atomic_fetch_sub_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
3966{
3967 c89atomic_if64 r;
3968 c89atomic_if64 x;
3969 x.f = src;
3970 r.i = c89atomic_fetch_sub_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
3971 return r.f;
3972}
3973
3974
3975static C89ATOMIC_INLINE float c89atomic_fetch_or_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
3976{
3977 c89atomic_if32 r;
3978 c89atomic_if32 x;
3979 x.f = src;
3980 r.i = c89atomic_fetch_or_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
3981 return r.f;
3982}
3983
3984static C89ATOMIC_INLINE double c89atomic_fetch_or_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
3985{
3986 c89atomic_if64 r;
3987 c89atomic_if64 x;
3988 x.f = src;
3989 r.i = c89atomic_fetch_or_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
3990 return r.f;
3991}
3992
3993
3994static C89ATOMIC_INLINE float c89atomic_fetch_xor_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
3995{
3996 c89atomic_if32 r;
3997 c89atomic_if32 x;
3998 x.f = src;
3999 r.i = c89atomic_fetch_xor_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
4000 return r.f;
4001}
4002
4003static C89ATOMIC_INLINE double c89atomic_fetch_xor_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
4004{
4005 c89atomic_if64 r;
4006 c89atomic_if64 x;
4007 x.f = src;
4008 r.i = c89atomic_fetch_xor_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
4009 return r.f;
4010}
4011
4012
4013static C89ATOMIC_INLINE float c89atomic_fetch_and_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
4014{
4015 c89atomic_if32 r;
4016 c89atomic_if32 x;
4017 x.f = src;
4018 r.i = c89atomic_fetch_and_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
4019 return r.f;
4020}
4021
4022static C89ATOMIC_INLINE double c89atomic_fetch_and_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
4023{
4024 c89atomic_if64 r;
4025 c89atomic_if64 x;
4026 x.f = src;
4027 r.i = c89atomic_fetch_and_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
4028 return r.f;
4029}
4030
4031
4032
4033/* Float Point Implicit */
4034#define c89atomic_clear_f32(ptr) (float )c89atomic_clear_explicit_f32(ptr, c89atomic_memory_order_seq_cst)
4035#define c89atomic_clear_f64(ptr) (double)c89atomic_clear_explicit_f64(ptr, c89atomic_memory_order_seq_cst)
4036
4037#define c89atomic_store_f32(dst, src) c89atomic_store_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4038#define c89atomic_store_f64(dst, src) c89atomic_store_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4039
4040#define c89atomic_load_f32(ptr) (float )c89atomic_load_explicit_f32(ptr, c89atomic_memory_order_seq_cst)
4041#define c89atomic_load_f64(ptr) (double)c89atomic_load_explicit_f64(ptr, c89atomic_memory_order_seq_cst)
4042
4043#define c89atomic_exchange_f32(dst, src) (float )c89atomic_exchange_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4044#define c89atomic_exchange_f64(dst, src) (double)c89atomic_exchange_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4045
4046#define c89atomic_compare_exchange_strong_f32(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_f32(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
4047#define c89atomic_compare_exchange_strong_f64(dst, expected, replacement) c89atomic_compare_exchange_strong_explicit_f64(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
4048
4049#define c89atomic_compare_exchange_weak_f32(dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_f32(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
4050#define c89atomic_compare_exchange_weak_f64(dst, expected, replacement) c89atomic_compare_exchange_weak_explicit_f64(dst, expected, replacement, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
4051
4052#define c89atomic_fetch_add_f32(dst, src) c89atomic_fetch_add_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4053#define c89atomic_fetch_add_f64(dst, src) c89atomic_fetch_add_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4054
4055#define c89atomic_fetch_sub_f32(dst, src) c89atomic_fetch_sub_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4056#define c89atomic_fetch_sub_f64(dst, src) c89atomic_fetch_sub_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4057
4058#define c89atomic_fetch_or_f32(dst, src) c89atomic_fetch_or_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4059#define c89atomic_fetch_or_f64(dst, src) c89atomic_fetch_or_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4060
4061#define c89atomic_fetch_xor_f32(dst, src) c89atomic_fetch_xor_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4062#define c89atomic_fetch_xor_f64(dst, src) c89atomic_fetch_xor_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4063
4064#define c89atomic_fetch_and_f32(dst, src) c89atomic_fetch_and_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
4065#define c89atomic_fetch_and_f64(dst, src) c89atomic_fetch_and_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
4066
4067static C89ATOMIC_INLINE float c89atomic_compare_and_swap_f32(volatile float* dst, float expected, float replacement)
4068{
4069 c89atomic_if32 r;
4070 c89atomic_if32 e, d;
4071 e.f = expected;
4072 d.f = replacement;
4073 r.i = c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, e.i, d.i);
4074 return r.f;
4075}
4076
4077static C89ATOMIC_INLINE double c89atomic_compare_and_swap_f64(volatile double* dst, double expected, double replacement)
4078{
4079 c89atomic_if64 r;
4080 c89atomic_if64 e, d;
4081 e.f = expected;
4082 d.f = replacement;
4083 r.i = c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, e.i, d.i);
4084 return r.f;
4085}
4086/* END c89atomic_float.h */
4087
4088
4089#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
4090 #pragma GCC diagnostic pop /* long long warnings with Clang. */
4091#endif
4092
4093#if defined(__cplusplus)
4094}
4095#endif
4096#endif /* c89atomic_h */
4097
4098/*
4099This software is available as a choice of the following licenses. Choose
4100whichever you prefer.
4101
4102===============================================================================
4103ALTERNATIVE 1 - Public Domain (www.unlicense.org)
4104===============================================================================
4105This is free and unencumbered software released into the public domain.
4106
4107Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
4108software, either in source code form or as a compiled binary, for any purpose,
4109commercial or non-commercial, and by any means.
4110
4111In jurisdictions that recognize copyright laws, the author or authors of this
4112software dedicate any and all copyright interest in the software to the public
4113domain. We make this dedication for the benefit of the public at large and to
4114the detriment of our heirs and successors. We intend this dedication to be an
4115overt act of relinquishment in perpetuity of all present and future rights to
4116this software under copyright law.
4117
4118THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4119IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4120FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4121AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
4122ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4123WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4124
4125For more information, please refer to <http://unlicense.org/>
4126
4127===============================================================================
4128ALTERNATIVE 2 - MIT No Attribution
4129===============================================================================
4130Copyright 2025 David Reid
4131
4132Permission is hereby granted, free of charge, to any person obtaining a copy of
4133this software and associated documentation files (the "Software"), to deal in
4134the Software without restriction, including without limitation the rights to
4135use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
4136of the Software, and to permit persons to whom the Software is furnished to do
4137so.
4138
4139THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4140IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4141FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4142AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4143LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4144OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4145SOFTWARE.
4146*/
#define c89atomic_fetch_xor_explicit_i64(dst, src, order)
Definition c89atomic.h:3775
#define c89atomic_memory_order_release
Definition c89atomic.h:583
#define c89atomic_memory_order_seq_cst
Definition c89atomic.h:585
#define c89atomic_fetch_add_explicit_i32(dst, src, order)
Definition c89atomic.h:3759
#define c89atomic_clear_explicit_f64(ptr, order)
Definition c89atomic.h:3856
#define c89atomic_memory_order_acquire
Definition c89atomic.h:582
#define c89atomic_fetch_sub_explicit_i32(dst, src, order)
Definition c89atomic.h:3764
#define c89atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3753
#define c89atomic_fetch_xor_explicit_i32(dst, src, order)
Definition c89atomic.h:3774
#define c89atomic_exchange_explicit_i16(dst, src, order)
Definition c89atomic.h:3743
#define c89atomic_load_explicit_i16(ptr, order)
Definition c89atomic.h:3738
#define c89atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3584
#define c89atomic_load_explicit_i32(ptr, order)
Definition c89atomic.h:3739
#define c89atomic_fetch_add_explicit_i8(dst, src, order)
Definition c89atomic.h:3757
#define c89atomic_compare_exchange_weak_explicit_i8(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3752
#define c89atomic_fetch_or_explicit_i8(dst, src, order)
Definition c89atomic.h:3767
#define c89atomic_exchange_explicit_i64(dst, src, order)
Definition c89atomic.h:3745
#define c89atomic_fetch_and_explicit_i32(dst, src, order)
Definition c89atomic.h:3779
#define c89atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3582
#define c89atomic_fetch_or_explicit_i32(dst, src, order)
Definition c89atomic.h:3769
#define c89atomic_fetch_and_explicit_i16(dst, src, order)
Definition c89atomic.h:3778
#define c89atomic_memory_order_relaxed
Definition c89atomic.h:580
#define c89atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3754
#define c89atomic_fetch_add_explicit_i16(dst, src, order)
Definition c89atomic.h:3758
#define c89atomic_load_explicit_i64(ptr, order)
Definition c89atomic.h:3740
#define c89atomic_exchange_explicit_i8(dst, src, order)
Definition c89atomic.h:3742
#define c89atomic_fetch_xor_explicit_i8(dst, src, order)
Definition c89atomic.h:3772
#define c89atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3750
#define c89atomic_compare_exchange_strong_explicit_i8(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3747
#define c89atomic_fetch_sub_explicit_i16(dst, src, order)
Definition c89atomic.h:3763
#define c89atomic_load_explicit_i8(ptr, order)
Definition c89atomic.h:3737
#define c89atomic_fetch_sub_explicit_i8(dst, src, order)
Definition c89atomic.h:3762
#define c89atomic_fetch_xor_explicit_i16(dst, src, order)
Definition c89atomic.h:3773
#define c89atomic_clear_explicit_f32(ptr, order)
Definition c89atomic.h:3855
#define c89atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3748
#define c89atomic_store_explicit_i64(dst, src, order)
Definition c89atomic.h:3735
#define c89atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3749
#define c89atomic_fetch_add_explicit_i64(dst, src, order)
Definition c89atomic.h:3760
#define c89atomic_store_explicit_i16(dst, src, order)
Definition c89atomic.h:3733
#define C89ATOMIC_64BIT
Definition c89atomic.h:253
#define c89atomic_store_explicit_i32(dst, src, order)
Definition c89atomic.h:3734
#define c89atomic_fetch_and_explicit_i64(dst, src, order)
Definition c89atomic.h:3780
#define C89ATOMIC_INLINE
Definition c89atomic.h:298
#define c89atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3755
#define c89atomic_compare_exchange_weak_explicit_8(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3581
#define c89atomic_fetch_sub_explicit_i64(dst, src, order)
Definition c89atomic.h:3765
#define c89atomic_fetch_and_explicit_i8(dst, src, order)
Definition c89atomic.h:3777
#define c89atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder)
Definition c89atomic.h:3583
#define c89atomic_exchange_explicit_i32(dst, src, order)
Definition c89atomic.h:3744
#define c89atomic_fetch_or_explicit_i64(dst, src, order)
Definition c89atomic.h:3770
#define c89atomic_store_explicit_i8(dst, src, order)
Definition c89atomic.h:3732
#define c89atomic_fetch_or_explicit_i16(dst, src, order)
Definition c89atomic.h:3768