Support ILP32 in AArch64 assembly routines (GCC)
[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 #       ifdef __ILP32__
45           "       ldxp  %w0, %w1, %3\n"
46           "       stxp %w2, %w0, %w1, %3"
47 #       else
48           "       ldxp  %0, %1, %3\n"
49           "       stxp %w2, %0, %1, %3"
50 #       endif
51       : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
52       : "Q" (*addr));
53     } while (AO_EXPECT_FALSE(status));
54     return result;
55   }
56 # define AO_HAVE_double_load
57
58   AO_INLINE AO_double_t
59   AO_double_load_acquire(const volatile AO_double_t *addr)
60   {
61     AO_double_t result;
62     int status;
63
64     do {
65       __asm__ __volatile__("//AO_double_load_acquire\n"
66 #       ifdef __ILP32__
67           "       ldaxp  %w0, %w1, %3\n"
68           "       stxp %w2, %w0, %w1, %3"
69 #       else
70           "       ldaxp  %0, %1, %3\n"
71           "       stxp %w2, %0, %1, %3"
72 #       endif
73       : "=&r" (result.AO_val1), "=&r" (result.AO_val2), "=&r" (status)
74       : "Q" (*addr));
75     } while (AO_EXPECT_FALSE(status));
76     return result;
77   }
78 # define AO_HAVE_double_load_acquire
79
80   AO_INLINE void
81   AO_double_store(volatile AO_double_t *addr, AO_double_t value)
82   {
83     AO_double_t old_val;
84     int status;
85
86     do {
87       __asm__ __volatile__("//AO_double_store\n"
88 #       ifdef __ILP32__
89           "       ldxp  %w0, %w1, %3\n"
90           "       stxp %w2, %w4, %w5, %3"
91 #       else
92           "       ldxp  %0, %1, %3\n"
93           "       stxp %w2, %4, %5, %3"
94 #       endif
95       : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
96         "=Q" (*addr)
97       : "r" (value.AO_val1), "r" (value.AO_val2));
98       /* Compared to the arm.h implementation, the 'cc' (flags) are not */
99       /* clobbered because A64 has no concept of conditional execution. */
100     } while (AO_EXPECT_FALSE(status));
101   }
102 # define AO_HAVE_double_store
103
104   AO_INLINE void
105   AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
106   {
107     AO_double_t old_val;
108     int status;
109
110     do {
111       __asm__ __volatile__("//AO_double_store_release\n"
112 #       ifdef __ILP32__
113           "       ldxp  %w0, %w1, %3\n"
114           "       stlxp %w2, %w4, %w5, %3"
115 #       else
116           "       ldxp  %0, %1, %3\n"
117           "       stlxp %w2, %4, %5, %3"
118 #       endif
119       : "=&r" (old_val.AO_val1), "=&r" (old_val.AO_val2), "=&r" (status),
120         "=Q" (*addr)
121       : "r" (value.AO_val1), "r" (value.AO_val2));
122     } while (AO_EXPECT_FALSE(status));
123   }
124 # define AO_HAVE_double_store_release
125
126   AO_INLINE int
127   AO_double_compare_and_swap(volatile AO_double_t *addr,
128                              AO_double_t old_val, AO_double_t new_val)
129   {
130     AO_double_t tmp;
131     int result = 1;
132
133     do {
134       __asm__ __volatile__("//AO_double_compare_and_swap\n"
135 #       ifdef __ILP32__
136           "       ldxp  %w0, %w1, %2\n"
137 #       else
138           "       ldxp  %0, %1, %2\n"
139 #       endif
140         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
141         : "Q" (*addr));
142       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
143         break;
144       __asm__ __volatile__(
145 #       ifdef __ILP32__
146           "       stxp %w0, %w2, %w3, %1\n"
147 #       else
148           "       stxp %w0, %2, %3, %1\n"
149 #       endif
150         : "=&r" (result), "=Q" (*addr)
151         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
152     } while (AO_EXPECT_FALSE(result));
153     return !result;
154   }
155 # define AO_HAVE_double_compare_and_swap
156
157   AO_INLINE int
158   AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
159                                      AO_double_t old_val, AO_double_t new_val)
160   {
161     AO_double_t tmp;
162     int result = 1;
163
164     do {
165       __asm__ __volatile__("//AO_double_compare_and_swap_acquire\n"
166 #       ifdef __ILP32__
167           "       ldaxp  %w0, %w1, %2\n"
168 #       else
169           "       ldaxp  %0, %1, %2\n"
170 #       endif
171         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
172         : "Q" (*addr));
173       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
174         break;
175       __asm__ __volatile__(
176 #       ifdef __ILP32__
177           "       stxp %w0, %w2, %w3, %1\n"
178 #       else
179           "       stxp %w0, %2, %3, %1\n"
180 #       endif
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_acquire
187
188   AO_INLINE int
189   AO_double_compare_and_swap_release(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_release\n"
197 #       ifdef __ILP32__
198           "       ldxp  %w0, %w1, %2\n"
199 #       else
200           "       ldxp  %0, %1, %2\n"
201 #       endif
202         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
203         : "Q" (*addr));
204       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
205         break;
206       __asm__ __volatile__(
207 #       ifdef __ILP32__
208           "       stlxp %w0, %w2, %w3, %1\n"
209 #       else
210           "       stlxp %w0, %2, %3, %1\n"
211 #       endif
212         : "=&r" (result), "=Q" (*addr)
213         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
214     } while (AO_EXPECT_FALSE(result));
215     return !result;
216   }
217 # define AO_HAVE_double_compare_and_swap_release
218
219   AO_INLINE int
220   AO_double_compare_and_swap_full(volatile AO_double_t *addr,
221                                   AO_double_t old_val, AO_double_t new_val)
222   {
223     AO_double_t tmp;
224     int result = 1;
225
226     do {
227       __asm__ __volatile__("//AO_double_compare_and_swap_full\n"
228 #       ifdef __ILP32__
229           "       ldaxp  %w0, %w1, %2\n"
230 #       else
231           "       ldaxp  %0, %1, %2\n"
232 #       endif
233         : "=&r" (tmp.AO_val1), "=&r" (tmp.AO_val2)
234         : "Q" (*addr));
235       if (tmp.AO_val1 != old_val.AO_val1 || tmp.AO_val2 != old_val.AO_val2)
236         break;
237       __asm__ __volatile__(
238 #       ifdef __ILP32__
239           "       stlxp %w0, %w2, %w3, %1\n"
240 #       else
241           "       stlxp %w0, %2, %3, %1\n"
242 #       endif
243         : "=&r" (result), "=Q" (*addr)
244         : "r" (new_val.AO_val1), "r" (new_val.AO_val2));
245     } while (AO_EXPECT_FALSE(result));
246     return !result;
247   }
248 # define AO_HAVE_double_compare_and_swap_full
249 #endif /* __GNUC__ >= 4 */
250
251 #include "generic.h"