v / thirdparty / libatomic_ops / atomic_ops.h
531 lines · 489 sloc · 22.15 KB · f53b5d737fd636890520101e736ad29e20d3c322
Raw
1/*
2 * Copyright (c) 2003-2011 Hewlett-Packard Development Company, L.P.
3 * Copyright (c) 2008-2022 Ivan Maidanski
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#ifndef AO_ATOMIC_OPS_H
25#define AO_ATOMIC_OPS_H
26
27#include "atomic_ops/ao_version.h"
28 /* Define version numbers here to allow */
29 /* test on build machines for cross-builds. */
30
31#include <assert.h>
32#include <stddef.h>
33
34/* We define various atomic operations on memory in a */
35/* machine-specific way. Unfortunately, this is complicated */
36/* by the fact that these may or may not be combined with */
37/* various memory barriers. Thus the actual operations we */
38/* define have the form AO_<atomic-op>_<barrier>, for all */
39/* plausible combinations of <atomic-op> and <barrier>. */
40/* This of course results in a mild combinatorial explosion. */
41/* To deal with it, we try to generate derived */
42/* definitions for as many of the combinations as we can, as */
43/* automatically as possible. */
44/* */
45/* Our assumption throughout is that the programmer will */
46/* specify the least demanding operation and memory barrier */
47/* that will guarantee correctness for the implementation. */
48/* Our job is to find the least expensive way to implement it */
49/* on the applicable hardware. In many cases that will */
50/* involve, for example, a stronger memory barrier, or a */
51/* combination of hardware primitives. */
52/* */
53/* Conventions: */
54/* "plain" atomic operations are not guaranteed to include */
55/* a barrier. The suffix in the name specifies the barrier */
56/* type. Suffixes are: */
57/* _release: Earlier operations may not be delayed past it. */
58/* _acquire: Later operations may not move ahead of it. */
59/* _read: Subsequent reads must follow this operation and */
60/* preceding reads. */
61/* _write: Earlier writes precede both this operation and */
62/* later writes. */
63/* _full: Ordered with respect to both earlier and later memory */
64/* operations. */
65/* _release_write: Ordered with respect to earlier writes. */
66/* _acquire_read: Ordered with respect to later reads. */
67/* */
68/* Currently we try to define the following atomic memory */
69/* operations, in combination with the above barriers: */
70/* AO_nop */
71/* AO_load */
72/* AO_store */
73/* AO_test_and_set (binary) */
74/* AO_fetch_and_add */
75/* AO_fetch_and_add1 */
76/* AO_fetch_and_sub1 */
77/* AO_and */
78/* AO_or */
79/* AO_xor */
80/* AO_compare_and_swap */
81/* AO_fetch_compare_and_swap */
82/* */
83/* Note that atomicity guarantees are valid only if both */
84/* readers and writers use AO_ operations to access the */
85/* shared value, while ordering constraints are intended to */
86/* apply all memory operations. If a location can potentially */
87/* be accessed simultaneously from multiple threads, and one of */
88/* those accesses may be a write access, then all such */
89/* accesses to that location should be through AO_ primitives. */
90/* However if AO_ operations enforce sufficient ordering to */
91/* ensure that a location x cannot be accessed concurrently, */
92/* or can only be read concurrently, then x can be accessed */
93/* via ordinary references and assignments. */
94/* */
95/* AO_compare_and_swap takes an address and an expected old */
96/* value and a new value, and returns an int. Non-zero result */
97/* indicates that it succeeded. */
98/* AO_fetch_compare_and_swap takes an address and an expected */
99/* old value and a new value, and returns the real old value. */
100/* The operation succeeded if and only if the expected old */
101/* value matches the old value returned. */
102/* */
103/* Test_and_set takes an address, atomically replaces it by */
104/* AO_TS_SET, and returns the prior value. */
105/* An AO_TS_t location can be reset with the */
106/* AO_CLEAR macro, which normally uses AO_store_release. */
107/* AO_fetch_and_add takes an address and an AO_t increment */
108/* value. The AO_fetch_and_add1 and AO_fetch_and_sub1 variants */
109/* are provided, since they allow faster implementations on */
110/* some hardware. AO_and, AO_or, AO_xor do atomically and, or, */
111/* xor (respectively) an AO_t value into a memory location, */
112/* but do not provide access to the original. */
113/* */
114/* We expect this list to grow slowly over time. */
115/* */
116/* Note that AO_nop_full is a full memory barrier. */
117/* */
118/* Note that if some data is initialized with */
119/* data.x = ...; data.y = ...; ... */
120/* AO_store_release_write(&data_is_initialized, 1) */
121/* then data is guaranteed to be initialized after the test */
122/* if (AO_load_acquire_read(&data_is_initialized)) ... */
123/* succeeds. Furthermore, this should generate near-optimal */
124/* code on all common platforms. */
125/* */
126/* All operations operate on unsigned AO_t, which */
127/* is the natural word size, and usually unsigned long. */
128/* It is possible to check whether a particular operation op */
129/* is available on a particular platform by checking whether */
130/* AO_HAVE_op is defined. We make heavy use of these macros */
131/* internally. */
132
133/* The rest of this file basically has three sections: */
134/* */
135/* Some utility and default definitions. */
136/* */
137/* The architecture dependent section: */
138/* This defines atomic operations that have direct hardware */
139/* support on a particular platform, mostly by including the */
140/* appropriate compiler- and hardware-dependent file. */
141/* */
142/* The synthesis section: */
143/* This tries to define other atomic operations in terms of */
144/* those that are explicitly available on the platform. */
145/* This section is hardware independent. */
146/* We make no attempt to synthesize operations in ways that */
147/* effectively introduce locks, except for the debugging/demo */
148/* pthread-based implementation at the beginning. A more */
149/* realistic implementation that falls back to locks could be */
150/* added as a higher layer. But that would sacrifice */
151/* usability from signal handlers. */
152/* The synthesis section is implemented almost entirely in */
153/* atomic_ops/generalize.h. */
154
155/* Some common defaults. Overridden for some architectures. */
156
157#define AO_t size_t
158
159#if defined(__SIZEOF_POINTER__) \
160 && (__SIZEOF_POINTER__ == 2 * __SIZEOF_SIZE_T__)
161 /* Pointers are twice bigger than the machine word. */
162# define AO_FAT_POINTER
163#endif
164
165#ifndef AO_FAT_POINTER
166# define AO_uintptr_t AO_t
167#elif defined(__e2k__)
168 /* For some reason uintptr_t is 64-bit on E2K in the protected mode. */
169 typedef unsigned __int128 AO_uintptr_t;
170#else
171# include <inttypes.h>
172# define AO_uintptr_t uintptr_t
173#endif
174
175/* A compile-time assertion for AO_uintptr_t size. */
176struct AO_uintptr_t_size_static_assert {
177 char dummy[sizeof(AO_uintptr_t) == sizeof(void *) ? 1 : -1];
178};
179
180/* The test_and_set primitive returns an AO_TS_VAL_t value. */
181/* AO_TS_t is the type of an in-memory test-and-set location. */
182
183#define AO_TS_INITIALIZER ((AO_TS_t)AO_TS_CLEAR)
184
185/* Convenient internal macro to test version of GCC. */
186#if defined(__GNUC__) && defined(__GNUC_MINOR__)
187# define AO_GNUC_PREREQ(major, minor) \
188 ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((major) << 16) + (minor))
189#else
190# define AO_GNUC_PREREQ(major, minor) 0 /* false */
191#endif
192
193/* Convenient internal macro to test version of Clang. */
194#if defined(__clang__) && defined(__clang_major__)
195# define AO_CLANG_PREREQ(major, minor) \
196 ((__clang_major__ << 16) + __clang_minor__ >= ((major) << 16) + (minor))
197#else
198# define AO_CLANG_PREREQ(major, minor) 0 /* false */
199#endif
200
201/* Platform-dependent stuff: */
202#if (defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER) \
203 || defined(__DMC__) || defined(__WATCOMC__)) && !defined(AO_NO_INLINE)
204# define AO_INLINE static __inline
205#elif defined(__sun) && !defined(AO_NO_INLINE)
206# define AO_INLINE static inline
207#else
208# define AO_INLINE static
209#endif
210
211#if AO_GNUC_PREREQ(3, 0) && !defined(LINT2)
212# define AO_EXPECT_FALSE(expr) __builtin_expect(expr, 0)
213 /* Equivalent to (expr) but predict that usually (expr) == 0. */
214#else
215# define AO_EXPECT_FALSE(expr) (expr)
216#endif /* !__GNUC__ */
217
218#if defined(__has_feature)
219 /* __has_feature() is supported. */
220# if __has_feature(address_sanitizer)
221# define AO_ADDRESS_SANITIZER
222# endif
223# if __has_feature(memory_sanitizer)
224# define AO_MEMORY_SANITIZER
225# endif
226# if __has_feature(thread_sanitizer)
227# define AO_THREAD_SANITIZER
228# endif
229#else
230# ifdef __SANITIZE_ADDRESS__
231 /* GCC v4.8+ */
232# define AO_ADDRESS_SANITIZER
233# endif
234#endif /* !__has_feature */
235
236#ifndef AO_ATTR_NO_SANITIZE_MEMORY
237# ifndef AO_MEMORY_SANITIZER
238# define AO_ATTR_NO_SANITIZE_MEMORY /* empty */
239# elif AO_CLANG_PREREQ(3, 8)
240# define AO_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
241# else
242# define AO_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
243# endif
244#endif /* !AO_ATTR_NO_SANITIZE_MEMORY */
245
246#ifndef AO_ATTR_NO_SANITIZE_THREAD
247# ifndef AO_THREAD_SANITIZER
248# define AO_ATTR_NO_SANITIZE_THREAD /* empty */
249# elif AO_CLANG_PREREQ(3, 8)
250# define AO_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
251# else
252# define AO_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
253# endif
254#endif /* !AO_ATTR_NO_SANITIZE_THREAD */
255
256#if (AO_GNUC_PREREQ(7, 5) || __STDC_VERSION__ >= 201112L) && !defined(LINT2)
257# define AO_ALIGNOF_SUPPORTED 1
258#endif
259
260#if defined(AO_DLL) && !defined(AO_API)
261# ifdef AO_BUILD
262# if defined(__CEGCC__) || (defined(__MINGW32__) && !defined(__cplusplus))
263# define AO_API __declspec(dllexport)
264# elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__) \
265 || defined(__DMC__) || defined(__MINGW32__) || defined(__WATCOMC__)
266# define AO_API extern __declspec(dllexport)
267# endif
268# else
269# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CEGCC__) \
270 || defined(__CYGWIN__) || defined(__DMC__)
271# define AO_API __declspec(dllimport)
272# elif defined(__MINGW32_DELAY_LOAD__)
273# define AO_API __declspec(dllexport)
274# elif defined(__MINGW32__) || defined(__WATCOMC__)
275# define AO_API extern __declspec(dllimport)
276# endif
277# endif
278#endif /* AO_DLL */
279
280#ifndef AO_API
281# define AO_API extern
282#endif
283
284#ifdef AO_ALIGNOF_SUPPORTED
285# define AO_ASSERT_ADDR_ALIGNED(addr) \
286 assert(((AO_uintptr_t)(addr) & (__alignof__(*(addr)) - 1)) == 0)
287#else
288# define AO_ASSERT_ADDR_ALIGNED(addr) \
289 assert(((AO_uintptr_t)(addr) & (sizeof(*(addr)) - 1)) == 0)
290#endif /* !AO_ALIGNOF_SUPPORTED */
291
292#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
293# define AO_compiler_barrier() __asm__ __volatile__("" : : : "memory")
294#elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
295 || defined(__WATCOMC__)
296# if defined(_AMD64_) || defined(_M_X64) || _MSC_VER >= 1400
297# if defined(_WIN32_WCE)
298/* # include <cmnintrin.h> */
299# elif defined(_MSC_VER)
300# include <intrin.h>
301# endif
302# pragma intrinsic(_ReadWriteBarrier)
303# define AO_compiler_barrier() _ReadWriteBarrier()
304 /* We assume this does not generate a fence instruction. */
305 /* The documentation is a bit unclear. */
306# else
307# define AO_compiler_barrier() __asm { }
308 /* The preceding implementation may be preferable here too. */
309 /* But the documentation warns about VC++ 2003 and earlier. */
310# endif
311#elif defined(__INTEL_COMPILER)
312# define AO_compiler_barrier() __memory_barrier()
313 /* FIXME: Too strong? IA64-only? */
314#elif defined(_HPUX_SOURCE)
315# if defined(__ia64)
316# include <machine/sys/inline.h>
317# define AO_compiler_barrier() _Asm_sched_fence()
318# else
319 /* FIXME - We do not know how to do this. This is a guess. */
320 /* And probably a bad one. */
321 static volatile int AO_barrier_dummy;
322# define AO_compiler_barrier() (void)(AO_barrier_dummy = AO_barrier_dummy)
323# endif
324#else
325 /* We conjecture that the following usually gives us the right */
326 /* semantics or an error. */
327# define AO_compiler_barrier() asm("")
328#endif
329
330#if defined(AO_USE_PTHREAD_DEFS)
331# include "atomic_ops/sysdeps/generic_pthread.h"
332#endif /* AO_USE_PTHREAD_DEFS */
333
334#if (defined(__CC_ARM) || defined(__ARMCC__)) && !defined(__GNUC__) \
335 && !defined(AO_USE_PTHREAD_DEFS)
336# include "atomic_ops/sysdeps/armcc/arm_v6.h"
337# define AO_GENERALIZE_TWICE
338#endif
339
340#if defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS) \
341 && !defined(__INTEL_COMPILER)
342# if defined(__i386__)
343 /* We don't define AO_USE_SYNC_CAS_BUILTIN for x86 here because */
344 /* it might require specifying additional options (like -march) */
345 /* or additional link libraries (if -march is not specified). */
346# include "atomic_ops/sysdeps/gcc/x86.h"
347# elif defined(__x86_64__)
348# if AO_GNUC_PREREQ(4, 2) && !defined(AO_USE_SYNC_CAS_BUILTIN)
349 /* It is safe to use __sync CAS built-in on this architecture. */
350# define AO_USE_SYNC_CAS_BUILTIN
351# endif
352# include "atomic_ops/sysdeps/gcc/x86.h"
353# elif defined(__ia64__)
354# include "atomic_ops/sysdeps/gcc/ia64.h"
355# define AO_GENERALIZE_TWICE
356# elif defined(__hppa__)
357# include "atomic_ops/sysdeps/gcc/hppa.h"
358# define AO_CAN_EMUL_CAS
359# elif defined(__alpha__)
360# include "atomic_ops/sysdeps/gcc/alpha.h"
361# define AO_GENERALIZE_TWICE
362# elif defined(__s390__)
363# include "atomic_ops/sysdeps/gcc/s390.h"
364# elif defined(__sparc__)
365# include "atomic_ops/sysdeps/gcc/sparc.h"
366# define AO_CAN_EMUL_CAS
367# elif defined(__m68k__)
368# include "atomic_ops/sysdeps/gcc/m68k.h"
369# elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \
370 || defined(__powerpc64__) || defined(__ppc64__) || defined(_ARCH_PPC)
371# include "atomic_ops/sysdeps/gcc/powerpc.h"
372# elif defined(__aarch64__)
373# include "atomic_ops/sysdeps/gcc/aarch64.h"
374# define AO_CAN_EMUL_CAS
375# elif defined(__arm__)
376# include "atomic_ops/sysdeps/gcc/arm.h"
377# define AO_CAN_EMUL_CAS
378# elif defined(__cris__) || defined(CRIS)
379# include "atomic_ops/sysdeps/gcc/cris.h"
380# define AO_CAN_EMUL_CAS
381# define AO_GENERALIZE_TWICE
382# elif defined(__mips__)
383# include "atomic_ops/sysdeps/gcc/mips.h"
384# elif defined(__sh__) || defined(SH4)
385# include "atomic_ops/sysdeps/gcc/sh.h"
386# define AO_CAN_EMUL_CAS
387# elif defined(__avr32__)
388# include "atomic_ops/sysdeps/gcc/avr32.h"
389# elif defined(__e2k__)
390# include "atomic_ops/sysdeps/gcc/e2k.h"
391# elif defined(__hexagon__)
392# include "atomic_ops/sysdeps/gcc/hexagon.h"
393# elif defined(__nios2__)
394# include "atomic_ops/sysdeps/gcc/generic.h"
395# define AO_CAN_EMUL_CAS
396# elif defined(__riscv)
397# include "atomic_ops/sysdeps/gcc/riscv.h"
398# elif defined(__tile__)
399# include "atomic_ops/sysdeps/gcc/tile.h"
400# else /* etc. */
401# include "atomic_ops/sysdeps/gcc/generic.h"
402# endif
403#endif /* __GNUC__ && !AO_USE_PTHREAD_DEFS */
404
405#if (defined(__IBMC__) || defined(__IBMCPP__)) && !defined(__GNUC__) \
406 && !defined(AO_USE_PTHREAD_DEFS)
407# if defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) \
408 || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) \
409 || defined(_ARCH_PWR)
410# include "atomic_ops/sysdeps/ibmc/powerpc.h"
411# define AO_GENERALIZE_TWICE
412# endif
413#endif
414
415#if defined(__INTEL_COMPILER) && !defined(AO_USE_PTHREAD_DEFS)
416# if defined(__ia64__)
417# include "atomic_ops/sysdeps/icc/ia64.h"
418# define AO_GENERALIZE_TWICE
419# endif
420# if defined(__GNUC__)
421 /* Intel Compiler in GCC compatible mode */
422# if defined(__i386__)
423# include "atomic_ops/sysdeps/gcc/x86.h"
424# endif /* __i386__ */
425# if defined(__x86_64__)
426# if (__INTEL_COMPILER > 1110) && !defined(AO_USE_SYNC_CAS_BUILTIN)
427# define AO_USE_SYNC_CAS_BUILTIN
428# endif
429# include "atomic_ops/sysdeps/gcc/x86.h"
430# endif /* __x86_64__ */
431# endif
432#endif
433
434#if defined(_HPUX_SOURCE) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)
435# if defined(__ia64)
436# include "atomic_ops/sysdeps/hpc/ia64.h"
437# define AO_GENERALIZE_TWICE
438# else
439# include "atomic_ops/sysdeps/hpc/hppa.h"
440# define AO_CAN_EMUL_CAS
441# endif
442#endif
443
444#if defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
445 || (defined(__WATCOMC__) && defined(__NT__))
446# if defined(_AMD64_) || defined(_M_X64)
447# include "atomic_ops/sysdeps/msftc/x86_64.h"
448# elif defined(_M_ARM64)
449# include "atomic_ops/sysdeps/msftc/arm64.h"
450# elif defined(_M_IX86) || defined(x86)
451# include "atomic_ops/sysdeps/msftc/x86.h"
452# elif defined(_M_ARM) || defined(ARM) || defined(_ARM_)
453# include "atomic_ops/sysdeps/msftc/arm.h"
454# define AO_GENERALIZE_TWICE
455# endif
456#endif
457
458#if defined(__sun) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)
459 /* Note: use -DAO_USE_PTHREAD_DEFS if Sun CC does not handle inline asm. */
460# if defined(__i386) || defined(__x86_64) || defined(__amd64)
461# include "atomic_ops/sysdeps/sunc/x86.h"
462# endif
463#endif
464
465#if !defined(__GNUC__) && (defined(sparc) || defined(__sparc)) \
466 && !defined(AO_USE_PTHREAD_DEFS)
467# include "atomic_ops/sysdeps/sunc/sparc.h"
468# define AO_CAN_EMUL_CAS
469#endif
470
471#if (defined(AO_REQUIRE_CAS) && !defined(AO_HAVE_compare_and_swap) \
472 && !defined(AO_HAVE_fetch_compare_and_swap) \
473 && !defined(AO_HAVE_compare_and_swap_full) \
474 && !defined(AO_HAVE_fetch_compare_and_swap_full) \
475 && !defined(AO_HAVE_compare_and_swap_acquire) \
476 && !defined(AO_HAVE_fetch_compare_and_swap_acquire)) || defined(CPPCHECK)
477# if defined(AO_CAN_EMUL_CAS)
478# include "atomic_ops/sysdeps/emul_cas.h"
479# elif !defined(CPPCHECK)
480# error Cannot implement AO_compare_and_swap_full on this architecture.
481# endif
482#endif /* AO_REQUIRE_CAS && !AO_HAVE_compare_and_swap ... */
483
484/* The most common way to clear a test-and-set location */
485/* at the end of a critical section. */
486#if defined(AO_AO_TS_T) && !defined(AO_HAVE_CLEAR)
487# define AO_CLEAR(addr) AO_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)
488# define AO_HAVE_CLEAR
489#endif
490#if defined(AO_CHAR_TS_T) && !defined(AO_HAVE_CLEAR)
491# define AO_CLEAR(addr) AO_char_store_release((AO_TS_t *)(addr), AO_TS_CLEAR)
492# define AO_HAVE_CLEAR
493#endif
494
495/* The generalization section. */
496#if !defined(AO_GENERALIZE_TWICE) && defined(AO_CAN_EMUL_CAS) \
497 && !defined(AO_HAVE_compare_and_swap_full) \
498 && !defined(AO_HAVE_fetch_compare_and_swap_full)
499# define AO_GENERALIZE_TWICE
500#endif
501
502/* Theoretically we should repeatedly include atomic_ops/generalize.h. */
503/* In fact, we observe that this converges after a small fixed number */
504/* of iterations, usually one. */
505#include "atomic_ops/generalize.h"
506
507#if !defined(AO_GENERALIZE_TWICE) \
508 && defined(AO_HAVE_compare_double_and_swap_double) \
509 && (!defined(AO_HAVE_double_load) || !defined(AO_HAVE_double_store))
510# define AO_GENERALIZE_TWICE
511#endif
512
513#ifdef AO_T_IS_INT
514 /* Included after the first generalization pass. */
515# include "atomic_ops/sysdeps/ao_t_is_int.h"
516# ifndef AO_GENERALIZE_TWICE
517 /* Always generalize again. */
518# define AO_GENERALIZE_TWICE
519# endif
520#endif /* AO_T_IS_INT */
521
522#ifdef AO_GENERALIZE_TWICE
523# include "atomic_ops/generalize.h"
524#endif
525
526/* For compatibility with version 0.4 and earlier */
527#define AO_TS_T AO_TS_t
528#define AO_T AO_t
529#define AO_TS_VAL AO_TS_VAL_t
530
531#endif /* !AO_ATOMIC_OPS_H */
532