b9624ef910b033cecb3edcb2f9d242a69a70537f
[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  *
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 #include "../test_and_set_t_is_ao_t.h"
19
20 #include "../standard_ao_double_t.h"
21
22 #ifndef AO_UNIPROCESSOR
23   AO_INLINE void
24   AO_nop_write(void)
25   {
26     __asm__ __volatile__("dmb st" : : : "memory");
27   }
28 # define AO_HAVE_nop_write
29 #endif
30
31 /* TODO: Adjust version check on fixing double-wide AO support in GCC. */
32 #if __GNUC__ >= 4
33
34   AO_INLINE AO_double_t
35   AO_double_load(const volatile AO_double_t *addr)
36   {
37     AO_double_t result;
38     int status;
39
40     /* Note that STXP cannot be discarded because LD[A]XP is not        */
41     /* single-copy atomic (unlike LDREXD for 32-bit ARM).               */
42     do {
43       __asm__ __volatile__("//AO_double_load\n"
44       "       ldxp  %0, %1, %3\n"
45       "       stxp %w2, %0, %1, %3"
46       : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
47       : "Q" (*addr));
48     } while (AO_EXPECT_FALSE(status));
49     return result;
50   }
51 # define AO_HAVE_double_load
52
53   AO_INLINE AO_double_t
54   AO_double_load_acquire(const volatile AO_double_t *addr)
55   {
56     AO_double_t result;
57     int status;
58
59     do {
60       __asm__ __volatile__("//AO_double_load_acquire\n"
61       "       ldaxp  %0, %1, %3\n"
62       "       stxp %w2, %0, %1, %3"
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_acquire
69
70   AO_INLINE void
71   AO_double_store(volatile AO_double_t *addr, AO_double_t value)
72   {
73     AO_double_t old_val;
74     int status;
75
76     do {
77       __asm__ __volatile__("//AO_double_store\n"
78       "       ldxp  %0, %1, %3\n"
79       "       stxp %w2, %4, %5, %3"
80       : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
81         "=Q" (*addr)
82       : "r" (value.AO_val1), "r" (value.AO_val2));
83       /* Compared to the arm.h implementation, the 'cc' (flags) are not */
84       /* clobbered because A64 has no concept of conditional execution. */
85     } while (AO_EXPECT_FALSE(status));
86   }
87 # define AO_HAVE_double_store
88
89   AO_INLINE void
90   AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
91   {
92     AO_double_t old_val;
93     int status;
94
95     do {
96       __asm__ __volatile__("//AO_double_store_release\n"
97       "       ldxp  %0, %1, %3\n"
98       "       stlxp %w2, %4, %5, %3"
99       : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
100         "=Q" (*addr)
101       : "r" (value.AO_val1), "r" (value.AO_val2));
102     } while (AO_EXPECT_FALSE(status));
103   }
104 # define AO_HAVE_double_store_release
105
106   AO_INLINE int
107   AO_double_compare_and_swap(volatile AO_double_t *addr,
108                              AO_double_t old_val, AO_double_t new_val)
109   {
110     AO_double_t tmp;
111     int result = 1;
112
113     do {
114       __asm__ __volatile__("//AO_double_compare_and_swap\n"
115         "       ldxp  %0, %1, %2\n"
116         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
117         : "Q" (*addr));
118       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
119         break;
120       __asm__ __volatile__(
121         "       stxp %w0, %2, %3, %1\n"
122         : "=&r" (result), "=Q" (*addr)
123         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
124     } while (AO_EXPECT_FALSE(result));
125     return !result;
126   }
127 # define AO_HAVE_double_compare_and_swap
128
129   AO_INLINE int
130   AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
131                                      AO_double_t old_val, AO_double_t new_val)
132   {
133     AO_double_t tmp;
134     int result = 1;
135
136     do {
137       __asm__ __volatile__("//AO_double_compare_and_swap_acquire\n"
138         "       ldaxp  %0, %1, %2\n"
139         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
140         : "Q" (*addr));
141       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
142         break;
143       __asm__ __volatile__(
144         "       stxp %w0, %2, %3, %1\n"
145         : "=&r" (result), "=Q" (*addr)
146         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
147     } while (AO_EXPECT_FALSE(result));
148     return !result;
149   }
150 # define AO_HAVE_double_compare_and_swap_acquire
151
152   AO_INLINE int
153   AO_double_compare_and_swap_release(volatile AO_double_t *addr,
154                                      AO_double_t old_val, AO_double_t new_val)
155   {
156     AO_double_t tmp;
157     int result = 1;
158
159     do {
160       __asm__ __volatile__("//AO_double_compare_and_swap_release\n"
161         "       ldxp  %0, %1, %2\n"
162         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
163         : "Q" (*addr));
164       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
165         break;
166       __asm__ __volatile__(
167         "       stlxp %w0, %2, %3, %1\n"
168         : "=&r" (result), "=Q" (*addr)
169         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
170     } while (AO_EXPECT_FALSE(result));
171     return !result;
172   }
173 # define AO_HAVE_double_compare_and_swap_release
174
175   AO_INLINE int
176   AO_double_compare_and_swap_full(volatile AO_double_t *addr,
177                                   AO_double_t old_val, AO_double_t new_val)
178   {
179     AO_double_t tmp;
180     int result = 1;
181
182     do {
183       __asm__ __volatile__("//AO_double_compare_and_swap_full\n"
184         "       ldaxp  %0, %1, %2\n"
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         "       stlxp %w0, %2, %3, %1\n"
191         : "=&r" (result), "=Q" (*addr)
192         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
193     } while (AO_EXPECT_FALSE(result));
194     return !result;
195   }
196 # define AO_HAVE_double_compare_and_swap_full
197 #endif /* __GNUC__ >= 4 */
198
199 #include "generic.h"