Update copyright information in README and some header files
[platform/upstream/libatomic_ops.git] / src / atomic_ops / sysdeps / gcc / aarch64.h
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
24   AO_nop_write(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(__clang__) || defined(AO_AARCH64_ASM_LOAD_STORE_CAS)
43
44 # ifndef AO_PREFER_GENERALIZED
45     AO_INLINE AO_double_t
46     AO_double_load(const volatile AO_double_t *addr)
47     {
48       AO_double_t result;
49       int status;
50
51       /* Note that STXP cannot be discarded because LD[A]XP is not      */
52       /* single-copy atomic (unlike LDREXD for 32-bit ARM).             */
53       do {
54         __asm__ __volatile__("//AO_double_load\n"
55         "       ldxp  %0, %1, %3\n"
56         "       stxp %w2, %0, %1, %3"
57         : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
58         : "Q" (*addr));
59       } while (AO_EXPECT_FALSE(status));
60       return result;
61     }
62 #   define AO_HAVE_double_load
63
64     AO_INLINE AO_double_t
65     AO_double_load_acquire(const volatile AO_double_t *addr)
66     {
67       AO_double_t result;
68       int status;
69
70       do {
71         __asm__ __volatile__("//AO_double_load_acquire\n"
72         "       ldaxp  %0, %1, %3\n"
73         "       stxp %w2, %0, %1, %3"
74         : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
75         : "Q" (*addr));
76       } while (AO_EXPECT_FALSE(status));
77       return result;
78     }
79 #   define AO_HAVE_double_load_acquire
80
81     AO_INLINE void
82     AO_double_store(volatile AO_double_t *addr, AO_double_t value)
83     {
84       AO_double_t old_val;
85       int status;
86
87       do {
88         __asm__ __volatile__("//AO_double_store\n"
89         "       ldxp  %0, %1, %3\n"
90         "       stxp %w2, %4, %5, %3"
91         : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
92           "=Q" (*addr)
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      */
96         /* execution.                                                   */
97       } while (AO_EXPECT_FALSE(status));
98     }
99 #   define AO_HAVE_double_store
100
101     AO_INLINE void
102     AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
103     {
104       AO_double_t old_val;
105       int status;
106
107       do {
108         __asm__ __volatile__("//AO_double_store_release\n"
109         "       ldxp  %0, %1, %3\n"
110         "       stlxp %w2, %4, %5, %3"
111         : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
112           "=Q" (*addr)
113         : "r" (value.AO_val1), "r" (value.AO_val2));
114       } while (AO_EXPECT_FALSE(status));
115     }
116 #   define AO_HAVE_double_store_release
117 # endif /* !AO_PREFER_GENERALIZED */
118
119   AO_INLINE int
120   AO_double_compare_and_swap(volatile AO_double_t *addr,
121                              AO_double_t old_val, AO_double_t new_val)
122   {
123     AO_double_t tmp;
124     int result = 1;
125
126     do {
127       __asm__ __volatile__("//AO_double_compare_and_swap\n"
128         "       ldxp  %0, %1, %2\n"
129         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
130         : "Q" (*addr));
131       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
132         break;
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));
138     return !result;
139   }
140 # define AO_HAVE_double_compare_and_swap
141
142   AO_INLINE int
143   AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
144                                      AO_double_t old_val, AO_double_t new_val)
145   {
146     AO_double_t tmp;
147     int result = 1;
148
149     do {
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)
153         : "Q" (*addr));
154       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
155         break;
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));
161     return !result;
162   }
163 # define AO_HAVE_double_compare_and_swap_acquire
164
165   AO_INLINE int
166   AO_double_compare_and_swap_release(volatile AO_double_t *addr,
167                                      AO_double_t old_val, AO_double_t new_val)
168   {
169     AO_double_t tmp;
170     int result = 1;
171
172     do {
173       __asm__ __volatile__("//AO_double_compare_and_swap_release\n"
174         "       ldxp  %0, %1, %2\n"
175         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
176         : "Q" (*addr));
177       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
178         break;
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));
184     return !result;
185   }
186 # define AO_HAVE_double_compare_and_swap_release
187
188   AO_INLINE int
189   AO_double_compare_and_swap_full(volatile AO_double_t *addr,
190                                   AO_double_t old_val, AO_double_t new_val)
191   {
192     AO_double_t tmp;
193     int result = 1;
194
195     do {
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)
199         : "Q" (*addr));
200       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
201         break;
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));
207     return !result;
208   }
209 # define AO_HAVE_double_compare_and_swap_full
210
211 #endif /* !__clang__ || AO_AARCH64_ASM_LOAD_STORE_CAS */
212
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
216
217 #endif /* !__clang__ || AO_CLANG_PREREQ(3, 9) */
218
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
222 #endif
223
224 #include "generic.h"
225
226 #undef AO_GCC_FORCE_HAVE_CAS
227 #undef AO_GCC_HAVE_double_SYNC_CAS