2 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
4 * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
5 * Copyright (c) 2013-2017 Ivan Maidanski
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 * Permission is hereby granted to use or copy this program
11 * for any purpose, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
18 /* As of clang-5.0 (and gcc-5.4), __atomic_thread_fence is always */
19 /* translated to DMB (which is inefficient for AO_nop_write). */
20 /* TODO: Update it for newer Clang and GCC releases. */
21 #if !defined(AO_PREFER_BUILTIN_ATOMICS) && !defined(AO_THREAD_SANITIZER) \
22 && !defined(AO_UNIPROCESSOR)
26 __asm__ __volatile__("dmb ishst" : : : "memory");
28 # define AO_HAVE_nop_write
31 /* There were some bugs in the older clang releases (related to */
32 /* optimization of functions dealing with __int128 values, supposedly), */
33 /* so even asm-based implementation did not work correctly. */
34 #if !defined(__clang__) || AO_CLANG_PREREQ(3, 9)
36 # include "../standard_ao_double_t.h"
38 /* As of gcc-5.4, all built-in load/store and CAS atomics for double */
39 /* word require -latomic, are not lock-free and cause test_stack */
40 /* failure, so the asm-based implementation is used for now. */
41 /* TODO: Update it for newer GCC releases. */
42 #if !defined(__clang__) || defined(AO_AARCH64_ASM_LOAD_STORE_CAS)
44 # ifndef AO_PREFER_GENERALIZED
46 AO_double_load(const volatile AO_double_t *addr)
51 /* Note that STXP cannot be discarded because LD[A]XP is not */
52 /* single-copy atomic (unlike LDREXD for 32-bit ARM). */
54 __asm__ __volatile__("//AO_double_load\n"
56 " stxp %w2, %0, %1, %3"
57 : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
59 } while (AO_EXPECT_FALSE(status));
62 # define AO_HAVE_double_load
65 AO_double_load_acquire(const volatile AO_double_t *addr)
71 __asm__ __volatile__("//AO_double_load_acquire\n"
73 " stxp %w2, %0, %1, %3"
74 : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
76 } while (AO_EXPECT_FALSE(status));
79 # define AO_HAVE_double_load_acquire
82 AO_double_store(volatile AO_double_t *addr, AO_double_t value)
88 __asm__ __volatile__("//AO_double_store\n"
90 " stxp %w2, %4, %5, %3"
91 : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
93 : "r" (value.AO_val1), "r" (value.AO_val2));
94 /* Compared to the arm.h implementation, the 'cc' (flags) are */
95 /* not clobbered because A64 has no concept of conditional */
97 } while (AO_EXPECT_FALSE(status));
99 # define AO_HAVE_double_store
102 AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
108 __asm__ __volatile__("//AO_double_store_release\n"
110 " stlxp %w2, %4, %5, %3"
111 : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
113 : "r" (value.AO_val1), "r" (value.AO_val2));
114 } while (AO_EXPECT_FALSE(status));
116 # define AO_HAVE_double_store_release
117 # endif /* !AO_PREFER_GENERALIZED */
120 AO_double_compare_and_swap(volatile AO_double_t *addr,
121 AO_double_t old_val, AO_double_t new_val)
127 __asm__ __volatile__("//AO_double_compare_and_swap\n"
129 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
131 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
133 __asm__ __volatile__(
134 " stxp %w0, %2, %3, %1\n"
135 : "=&r" (result), "=Q" (*addr)
136 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
137 } while (AO_EXPECT_FALSE(result));
140 # define AO_HAVE_double_compare_and_swap
143 AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
144 AO_double_t old_val, AO_double_t new_val)
150 __asm__ __volatile__("//AO_double_compare_and_swap_acquire\n"
151 " ldaxp %0, %1, %2\n"
152 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
154 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
156 __asm__ __volatile__(
157 " stxp %w0, %2, %3, %1\n"
158 : "=&r" (result), "=Q" (*addr)
159 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
160 } while (AO_EXPECT_FALSE(result));
163 # define AO_HAVE_double_compare_and_swap_acquire
166 AO_double_compare_and_swap_release(volatile AO_double_t *addr,
167 AO_double_t old_val, AO_double_t new_val)
173 __asm__ __volatile__("//AO_double_compare_and_swap_release\n"
175 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
177 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
179 __asm__ __volatile__(
180 " stlxp %w0, %2, %3, %1\n"
181 : "=&r" (result), "=Q" (*addr)
182 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
183 } while (AO_EXPECT_FALSE(result));
186 # define AO_HAVE_double_compare_and_swap_release
189 AO_double_compare_and_swap_full(volatile AO_double_t *addr,
190 AO_double_t old_val, AO_double_t new_val)
196 __asm__ __volatile__("//AO_double_compare_and_swap_full\n"
197 " ldaxp %0, %1, %2\n"
198 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
200 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
202 __asm__ __volatile__(
203 " stlxp %w0, %2, %3, %1\n"
204 : "=&r" (result), "=Q" (*addr)
205 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
206 } while (AO_EXPECT_FALSE(result));
209 # define AO_HAVE_double_compare_and_swap_full
211 #endif /* !__clang__ || AO_AARCH64_ASM_LOAD_STORE_CAS */
213 /* As of clang-5.0 and gcc-5.4, __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 */
214 /* macro is still missing (while the double-word CAS is available). */
215 # define AO_GCC_HAVE_double_SYNC_CAS
217 #endif /* !__clang__ || AO_CLANG_PREREQ(3, 9) */
219 #if (defined(__clang__) && !AO_CLANG_PREREQ(3, 8)) || defined(__APPLE_CC__)
220 /* __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros are missing. */
221 # define AO_GCC_FORCE_HAVE_CAS
226 #undef AO_GCC_FORCE_HAVE_CAS
227 #undef AO_GCC_HAVE_double_SYNC_CAS