PAPI 7.1.0.0
Loading...
Searching...
No Matches
aarch64.h
Go to the documentation of this file.
1/*
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
6 *
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9 *
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.
15 *
16 */
17
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)
23 AO_INLINE void
25 {
26 __asm__ __volatile__("dmb ishst" : : : "memory");
27 }
28# define AO_HAVE_nop_write
29#endif
30
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)
35
36# include "../standard_ao_double_t.h"
37
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(__ILP32__) && !defined(__clang__)) \
43 || defined(AO_AARCH64_ASM_LOAD_STORE_CAS)
44
45# ifndef AO_PREFER_GENERALIZED
47 AO_double_load(const volatile AO_double_t *addr)
48 {
50 int status;
51
52 /* Note that STXP cannot be discarded because LD[A]XP is not */
53 /* single-copy atomic (unlike LDREXD for 32-bit ARM). */
54 do {
55 __asm__ __volatile__("//AO_double_load\n"
56# ifdef __ILP32__
57 " ldxp %w0, %w1, %3\n"
58 " stxp %w2, %w0, %w1, %3"
59# else
60 " ldxp %0, %1, %3\n"
61 " stxp %w2, %0, %1, %3"
62# endif
63 : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
64 : "Q" (*addr));
65 } while (AO_EXPECT_FALSE(status));
66 return result;
67 }
68# define AO_HAVE_double_load
69
71 AO_double_load_acquire(const volatile AO_double_t *addr)
72 {
74 int status;
75
76 do {
77 __asm__ __volatile__("//AO_double_load_acquire\n"
78# ifdef __ILP32__
79 " ldaxp %w0, %w1, %3\n"
80 " stxp %w2, %w0, %w1, %3"
81# else
82 " ldaxp %0, %1, %3\n"
83 " stxp %w2, %0, %1, %3"
84# endif
85 : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
86 : "Q" (*addr));
87 } while (AO_EXPECT_FALSE(status));
88 return result;
89 }
90# define AO_HAVE_double_load_acquire
91
92 AO_INLINE void
94 {
95 AO_double_t old_val;
96 int status;
97
98 do {
99 __asm__ __volatile__("//AO_double_store\n"
100# ifdef __ILP32__
101 " ldxp %w0, %w1, %3\n"
102 " stxp %w2, %w4, %w5, %3"
103# else
104 " ldxp %0, %1, %3\n"
105 " stxp %w2, %4, %5, %3"
106# endif
107 : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
108 "=Q" (*addr)
109 : "r" (value.AO_val1), "r" (value.AO_val2));
110 /* Compared to the arm.h implementation, the 'cc' (flags) are */
111 /* not clobbered because A64 has no concept of conditional */
112 /* execution. */
113 } while (AO_EXPECT_FALSE(status));
114 }
115# define AO_HAVE_double_store
116
117 AO_INLINE void
119 {
120 AO_double_t old_val;
121 int status;
122
123 do {
124 __asm__ __volatile__("//AO_double_store_release\n"
125# ifdef __ILP32__
126 " ldxp %w0, %w1, %3\n"
127 " stlxp %w2, %w4, %w5, %3"
128# else
129 " ldxp %0, %1, %3\n"
130 " stlxp %w2, %4, %5, %3"
131# endif
132 : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
133 "=Q" (*addr)
134 : "r" (value.AO_val1), "r" (value.AO_val2));
135 } while (AO_EXPECT_FALSE(status));
136 }
137# define AO_HAVE_double_store_release
138# endif /* !AO_PREFER_GENERALIZED */
139
140 AO_INLINE int
142 AO_double_t old_val, AO_double_t new_val)
143 {
145 int result = 1;
146
147 do {
148 __asm__ __volatile__("//AO_double_compare_and_swap\n"
149# ifdef __ILP32__
150 " ldxp %w0, %w1, %2\n"
151# else
152 " ldxp %0, %1, %2\n"
153# endif
154 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
155 : "Q" (*addr));
156 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
157 break;
158 __asm__ __volatile__(
159# ifdef __ILP32__
160 " stxp %w0, %w2, %w3, %1\n"
161# else
162 " stxp %w0, %2, %3, %1\n"
163# endif
164 : "=&r" (result), "=Q" (*addr)
165 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
166 } while (AO_EXPECT_FALSE(result));
167 return !result;
168 }
169# define AO_HAVE_double_compare_and_swap
170
171 AO_INLINE int
173 AO_double_t old_val, AO_double_t new_val)
174 {
176 int result = 1;
177
178 do {
179 __asm__ __volatile__("//AO_double_compare_and_swap_acquire\n"
180# ifdef __ILP32__
181 " ldaxp %w0, %w1, %2\n"
182# else
183 " ldaxp %0, %1, %2\n"
184# endif
185 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
186 : "Q" (*addr));
187 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
188 break;
189 __asm__ __volatile__(
190# ifdef __ILP32__
191 " stxp %w0, %w2, %w3, %1\n"
192# else
193 " stxp %w0, %2, %3, %1\n"
194# endif
195 : "=&r" (result), "=Q" (*addr)
196 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
197 } while (AO_EXPECT_FALSE(result));
198 return !result;
199 }
200# define AO_HAVE_double_compare_and_swap_acquire
201
202 AO_INLINE int
204 AO_double_t old_val, AO_double_t new_val)
205 {
207 int result = 1;
208
209 do {
210 __asm__ __volatile__("//AO_double_compare_and_swap_release\n"
211# ifdef __ILP32__
212 " ldxp %w0, %w1, %2\n"
213# else
214 " ldxp %0, %1, %2\n"
215# endif
216 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
217 : "Q" (*addr));
218 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
219 break;
220 __asm__ __volatile__(
221# ifdef __ILP32__
222 " stlxp %w0, %w2, %w3, %1\n"
223# else
224 " stlxp %w0, %2, %3, %1\n"
225# endif
226 : "=&r" (result), "=Q" (*addr)
227 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
228 } while (AO_EXPECT_FALSE(result));
229 return !result;
230 }
231# define AO_HAVE_double_compare_and_swap_release
232
233 AO_INLINE int
235 AO_double_t old_val, AO_double_t new_val)
236 {
238 int result = 1;
239
240 do {
241 __asm__ __volatile__("//AO_double_compare_and_swap_full\n"
242# ifdef __ILP32__
243 " ldaxp %w0, %w1, %2\n"
244# else
245 " ldaxp %0, %1, %2\n"
246# endif
247 : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
248 : "Q" (*addr));
249 if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
250 break;
251 __asm__ __volatile__(
252# ifdef __ILP32__
253 " stlxp %w0, %w2, %w3, %1\n"
254# else
255 " stlxp %w0, %2, %3, %1\n"
256# endif
257 : "=&r" (result), "=Q" (*addr)
258 : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
259 } while (AO_EXPECT_FALSE(result));
260 return !result;
261 }
262# define AO_HAVE_double_compare_and_swap_full
263
264#endif /* !__ILP32__ && !__clang__ || AO_AARCH64_ASM_LOAD_STORE_CAS */
265
266/* As of clang-5.0 and gcc-8.1, __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 */
267/* macro is still missing (while the double-word CAS is available). */
268# ifndef __ILP32__
269# define AO_GCC_HAVE_double_SYNC_CAS
270# endif
271
272#endif /* !__clang__ || AO_CLANG_PREREQ(3, 9) */
273
274#if (defined(__clang__) && !AO_CLANG_PREREQ(3, 8)) || defined(__APPLE_CC__)
275 /* __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros are missing. */
276# define AO_GCC_FORCE_HAVE_CAS
277#endif
278
279#include "generic.h"
280
281#undef AO_GCC_FORCE_HAVE_CAS
282#undef AO_GCC_HAVE_double_SYNC_CAS
volatile int result
double tmp
AO_INLINE void AO_nop_write(void)
Definition: aarch64.h:24
AO_INLINE int AO_double_compare_and_swap(volatile AO_double_t *addr, AO_double_t old_val, AO_double_t new_val)
Definition: aarch64.h:141
AO_INLINE int AO_double_compare_and_swap_release(volatile AO_double_t *addr, AO_double_t old_val, AO_double_t new_val)
Definition: aarch64.h:203
AO_INLINE void AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
Definition: aarch64.h:118
AO_INLINE int AO_double_compare_and_swap_acquire(volatile AO_double_t *addr, AO_double_t old_val, AO_double_t new_val)
Definition: aarch64.h:172
AO_INLINE AO_double_t AO_double_load_acquire(const volatile AO_double_t *addr)
Definition: aarch64.h:71
AO_INLINE int AO_double_compare_and_swap_full(volatile AO_double_t *addr, AO_double_t old_val, AO_double_t new_val)
Definition: aarch64.h:234
AO_INLINE AO_double_t AO_double_load(const volatile AO_double_t *addr)
Definition: aarch64.h:47
AO_INLINE void AO_double_store(volatile AO_double_t *addr, AO_double_t value)
Definition: aarch64.h:93
#define AO_INLINE
Definition: atomic_ops.h:186
#define AO_EXPECT_FALSE(expr)
Definition: atomic_ops.h:193