]>
Commit | Line | Data |
---|---|---|
0a9d1b3b | 1 | /* Atomic operations. sparc32 version. |
5f4318d1 | 2 | Copyright (C) 2003, 2004, 2006, 2011 Free Software Foundation, Inc. |
0a9d1b3b RM |
3 | This file is part of the GNU C Library. |
4 | Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Lesser General Public | |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
10 | ||
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
0a9d1b3b RM |
19 | |
20 | #ifndef _BITS_ATOMIC_H | |
21 | #define _BITS_ATOMIC_H 1 | |
22 | ||
b01fe5f7 UD |
23 | #include <stdint.h> |
24 | ||
25 | typedef int8_t atomic8_t; | |
26 | typedef uint8_t uatomic8_t; | |
27 | typedef int_fast8_t atomic_fast8_t; | |
28 | typedef uint_fast8_t uatomic_fast8_t; | |
29 | ||
30 | typedef int16_t atomic16_t; | |
31 | typedef uint16_t uatomic16_t; | |
32 | typedef int_fast16_t atomic_fast16_t; | |
33 | typedef uint_fast16_t uatomic_fast16_t; | |
34 | ||
35 | typedef int32_t atomic32_t; | |
36 | typedef uint32_t uatomic32_t; | |
37 | typedef int_fast32_t atomic_fast32_t; | |
38 | typedef uint_fast32_t uatomic_fast32_t; | |
39 | ||
40 | typedef int64_t atomic64_t; | |
41 | typedef uint64_t uatomic64_t; | |
42 | typedef int_fast64_t atomic_fast64_t; | |
43 | typedef uint_fast64_t uatomic_fast64_t; | |
44 | ||
45 | typedef intptr_t atomicptr_t; | |
46 | typedef uintptr_t uatomicptr_t; | |
47 | typedef intmax_t atomic_max_t; | |
48 | typedef uintmax_t uatomic_max_t; | |
49 | ||
50 | ||
0a9d1b3b | 51 | /* We have no compare and swap, just test and set. |
d57a3f0e | 52 | The following implementation contends on 64 global locks |
0a9d1b3b RM |
53 | per library and assumes no variable will be accessed using atomic.h |
54 | macros from two different libraries. */ | |
55 | ||
1be3130e UD |
56 | __make_section_unallocated |
57 | (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits"); | |
58 | ||
d57a3f0e | 59 | volatile unsigned char __sparc32_atomic_locks[64] |
1be3130e UD |
60 | __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks" |
61 | __sec_comment), | |
0a9d1b3b RM |
62 | visibility ("hidden"))); |
63 | ||
d57a3f0e | 64 | #define __sparc32_atomic_do_lock(addr) \ |
0a9d1b3b RM |
65 | do \ |
66 | { \ | |
67 | unsigned int __old_lock; \ | |
d57a3f0e UD |
68 | unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \ |
69 | & 63; \ | |
0a9d1b3b | 70 | do \ |
b01fe5f7 UD |
71 | __asm __volatile ("ldstub %1, %0" \ |
72 | : "=r" (__old_lock), \ | |
73 | "=m" (__sparc32_atomic_locks[__idx]) \ | |
74 | : "m" (__sparc32_atomic_locks[__idx]) \ | |
75 | : "memory"); \ | |
0a9d1b3b RM |
76 | while (__old_lock); \ |
77 | } \ | |
78 | while (0) | |
79 | ||
d57a3f0e UD |
80 | #define __sparc32_atomic_do_unlock(addr) \ |
81 | do \ | |
b01fe5f7 UD |
82 | { \ |
83 | __sparc32_atomic_locks[(((long) addr >> 2) \ | |
84 | ^ ((long) addr >> 12)) & 63] = 0; \ | |
85 | __asm __volatile ("" ::: "memory"); \ | |
86 | } \ | |
87 | while (0) | |
88 | ||
89 | #define __sparc32_atomic_do_lock24(addr) \ | |
90 | do \ | |
91 | { \ | |
92 | unsigned int __old_lock; \ | |
93 | do \ | |
94 | __asm __volatile ("ldstub %1, %0" \ | |
95 | : "=r" (__old_lock), "=m" (*(addr)) \ | |
96 | : "m" (*(addr)) \ | |
97 | : "memory"); \ | |
98 | while (__old_lock); \ | |
99 | } \ | |
d57a3f0e | 100 | while (0) |
0a9d1b3b | 101 | |
b01fe5f7 UD |
102 | #define __sparc32_atomic_do_unlock24(addr) \ |
103 | do \ | |
104 | { \ | |
105 | *(char *) (addr) = 0; \ | |
106 | __asm __volatile ("" ::: "memory"); \ | |
107 | } \ | |
108 | while (0) | |
109 | ||
110 | ||
111 | #ifndef SHARED | |
112 | # define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \ | |
113 | ({ \ | |
114 | register __typeof (*(mem)) __acev_tmp __asm ("%g6"); \ | |
115 | register __typeof (mem) __acev_mem __asm ("%g1") = (mem); \ | |
116 | register __typeof (*(mem)) __acev_oldval __asm ("%g5"); \ | |
117 | __acev_tmp = (newval); \ | |
118 | __acev_oldval = (oldval); \ | |
119 | /* .word 0xcde05005 is cas [%g1], %g5, %g6. Can't use cas here though, \ | |
120 | because as will then mark the object file as V8+ arch. */ \ | |
121 | __asm __volatile (".word 0xcde05005" \ | |
122 | : "+r" (__acev_tmp), "=m" (*__acev_mem) \ | |
123 | : "r" (__acev_oldval), "m" (*__acev_mem), \ | |
c8e82b4a | 124 | "r" (__acev_mem) : "memory"); \ |
b01fe5f7 UD |
125 | __acev_tmp; }) |
126 | #endif | |
127 | ||
0a9d1b3b | 128 | /* The only basic operation needed is compare and exchange. */ |
b01fe5f7 | 129 | #define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \ |
0a9d1b3b RM |
130 | ({ __typeof (mem) __acev_memp = (mem); \ |
131 | __typeof (*mem) __acev_ret; \ | |
132 | __typeof (*mem) __acev_newval = (newval); \ | |
133 | \ | |
d57a3f0e | 134 | __sparc32_atomic_do_lock (__acev_memp); \ |
0a9d1b3b RM |
135 | __acev_ret = *__acev_memp; \ |
136 | if (__acev_ret == (oldval)) \ | |
137 | *__acev_memp = __acev_newval; \ | |
d57a3f0e | 138 | __sparc32_atomic_do_unlock (__acev_memp); \ |
0a9d1b3b RM |
139 | __acev_ret; }) |
140 | ||
b01fe5f7 | 141 | #define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \ |
0a9d1b3b RM |
142 | ({ __typeof (mem) __aceb_memp = (mem); \ |
143 | int __aceb_ret; \ | |
144 | __typeof (*mem) __aceb_newval = (newval); \ | |
145 | \ | |
d57a3f0e | 146 | __sparc32_atomic_do_lock (__aceb_memp); \ |
0a9d1b3b RM |
147 | __aceb_ret = 0; \ |
148 | if (*__aceb_memp == (oldval)) \ | |
149 | *__aceb_memp = __aceb_newval; \ | |
150 | else \ | |
151 | __aceb_ret = 1; \ | |
d57a3f0e | 152 | __sparc32_atomic_do_unlock (__aceb_memp); \ |
0a9d1b3b RM |
153 | __aceb_ret; }) |
154 | ||
b01fe5f7 UD |
155 | #define __v7_exchange_acq(mem, newval) \ |
156 | ({ __typeof (mem) __acev_memp = (mem); \ | |
157 | __typeof (*mem) __acev_ret; \ | |
158 | __typeof (*mem) __acev_newval = (newval); \ | |
159 | \ | |
160 | __sparc32_atomic_do_lock (__acev_memp); \ | |
161 | __acev_ret = *__acev_memp; \ | |
162 | *__acev_memp = __acev_newval; \ | |
163 | __sparc32_atomic_do_unlock (__acev_memp); \ | |
164 | __acev_ret; }) | |
165 | ||
166 | #define __v7_exchange_and_add(mem, value) \ | |
167 | ({ __typeof (mem) __acev_memp = (mem); \ | |
168 | __typeof (*mem) __acev_ret; \ | |
169 | \ | |
170 | __sparc32_atomic_do_lock (__acev_memp); \ | |
171 | __acev_ret = *__acev_memp; \ | |
172 | *__acev_memp = __acev_ret + (value); \ | |
173 | __sparc32_atomic_do_unlock (__acev_memp); \ | |
174 | __acev_ret; }) | |
175 | ||
176 | /* Special versions, which guarantee that top 8 bits of all values | |
177 | are cleared and use those bits as the ldstub lock. */ | |
178 | #define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \ | |
179 | ({ __typeof (mem) __acev_memp = (mem); \ | |
180 | __typeof (*mem) __acev_ret; \ | |
181 | __typeof (*mem) __acev_newval = (newval); \ | |
182 | \ | |
183 | __sparc32_atomic_do_lock24 (__acev_memp); \ | |
184 | __acev_ret = *__acev_memp & 0xffffff; \ | |
185 | if (__acev_ret == (oldval)) \ | |
186 | *__acev_memp = __acev_newval; \ | |
187 | else \ | |
188 | __sparc32_atomic_do_unlock24 (__acev_memp); \ | |
189 | __asm __volatile ("" ::: "memory"); \ | |
190 | __acev_ret; }) | |
191 | ||
192 | #define __v7_exchange_24_rel(mem, newval) \ | |
193 | ({ __typeof (mem) __acev_memp = (mem); \ | |
194 | __typeof (*mem) __acev_ret; \ | |
195 | __typeof (*mem) __acev_newval = (newval); \ | |
196 | \ | |
197 | __sparc32_atomic_do_lock24 (__acev_memp); \ | |
198 | __acev_ret = *__acev_memp & 0xffffff; \ | |
199 | *__acev_memp = __acev_newval; \ | |
200 | __asm __volatile ("" ::: "memory"); \ | |
201 | __acev_ret; }) | |
202 | ||
203 | #ifdef SHARED | |
204 | ||
205 | /* When dynamically linked, we assume pre-v9 libraries are only ever | |
206 | used on pre-v9 CPU. */ | |
207 | # define __atomic_is_v9 0 | |
208 | ||
209 | # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ | |
210 | __v7_compare_and_exchange_val_acq (mem, newval, oldval) | |
211 | ||
212 | # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ | |
213 | __v7_compare_and_exchange_bool_acq (mem, newval, oldval) | |
214 | ||
215 | # define atomic_exchange_acq(mem, newval) \ | |
216 | __v7_exchange_acq (mem, newval) | |
217 | ||
218 | # define atomic_exchange_and_add(mem, value) \ | |
219 | __v7_exchange_and_add (mem, value) | |
220 | ||
221 | # define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ | |
222 | ({ \ | |
223 | if (sizeof (*mem) != 4) \ | |
224 | abort (); \ | |
225 | __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); }) | |
226 | ||
227 | # define atomic_exchange_24_rel(mem, newval) \ | |
228 | ({ \ | |
229 | if (sizeof (*mem) != 4) \ | |
230 | abort (); \ | |
231 | __v7_exchange_24_rel (mem, newval); }) | |
232 | ||
cfa1f3e8 DM |
233 | # define atomic_full_barrier() __asm ("" ::: "memory") |
234 | # define atomic_read_barrier() atomic_full_barrier () | |
235 | # define atomic_write_barrier() atomic_full_barrier () | |
236 | ||
b01fe5f7 UD |
237 | #else |
238 | ||
239 | /* In libc.a/libpthread.a etc. we don't know if we'll be run on | |
240 | pre-v9 or v9 CPU. To be interoperable with dynamically linked | |
241 | apps on v9 CPUs e.g. with process shared primitives, use cas insn | |
242 | on v9 CPUs and ldstub on pre-v9. */ | |
243 | ||
b01fe5f7 | 244 | extern uint64_t _dl_hwcap __attribute__((weak)); |
b01fe5f7 UD |
245 | # define __atomic_is_v9 \ |
246 | (__builtin_expect (&_dl_hwcap != 0, 1) \ | |
5f4318d1 | 247 | && __builtin_expect (_dl_hwcap & HWCAP_SPARC_V9, HWCAP_SPARC_V9)) |
b01fe5f7 UD |
248 | |
249 | # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ | |
250 | ({ \ | |
251 | __typeof (*mem) __acev_wret; \ | |
252 | if (sizeof (*mem) != 4) \ | |
253 | abort (); \ | |
254 | if (__atomic_is_v9) \ | |
255 | __acev_wret \ | |
256 | = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ | |
257 | else \ | |
258 | __acev_wret \ | |
259 | = __v7_compare_and_exchange_val_acq (mem, newval, oldval); \ | |
260 | __acev_wret; }) | |
261 | ||
262 | # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ | |
263 | ({ \ | |
264 | int __acev_wret; \ | |
265 | if (sizeof (*mem) != 4) \ | |
266 | abort (); \ | |
267 | if (__atomic_is_v9) \ | |
268 | { \ | |
269 | __typeof (oldval) __acev_woldval = (oldval); \ | |
270 | __acev_wret \ | |
271 | = __v9_compare_and_exchange_val_32_acq (mem, newval, \ | |
272 | __acev_woldval) \ | |
273 | != __acev_woldval; \ | |
274 | } \ | |
275 | else \ | |
276 | __acev_wret \ | |
277 | = __v7_compare_and_exchange_bool_acq (mem, newval, oldval); \ | |
278 | __acev_wret; }) | |
279 | ||
280 | # define atomic_exchange_rel(mem, newval) \ | |
281 | ({ \ | |
282 | __typeof (*mem) __acev_wret; \ | |
283 | if (sizeof (*mem) != 4) \ | |
284 | abort (); \ | |
285 | if (__atomic_is_v9) \ | |
286 | { \ | |
287 | __typeof (mem) __acev_wmemp = (mem); \ | |
288 | __typeof (*(mem)) __acev_wval = (newval); \ | |
289 | do \ | |
290 | __acev_wret = *__acev_wmemp; \ | |
291 | while (__builtin_expect \ | |
292 | (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\ | |
293 | __acev_wval, \ | |
294 | __acev_wret) \ | |
295 | != __acev_wret, 0)); \ | |
296 | } \ | |
297 | else \ | |
298 | __acev_wret = __v7_exchange_acq (mem, newval); \ | |
299 | __acev_wret; }) | |
300 | ||
301 | # define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ | |
302 | ({ \ | |
303 | __typeof (*mem) __acev_wret; \ | |
304 | if (sizeof (*mem) != 4) \ | |
305 | abort (); \ | |
306 | if (__atomic_is_v9) \ | |
307 | __acev_wret \ | |
308 | = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ | |
309 | else \ | |
310 | __acev_wret \ | |
311 | = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\ | |
312 | __acev_wret; }) | |
313 | ||
314 | # define atomic_exchange_24_rel(mem, newval) \ | |
315 | ({ \ | |
316 | __typeof (*mem) __acev_w24ret; \ | |
317 | if (sizeof (*mem) != 4) \ | |
318 | abort (); \ | |
319 | if (__atomic_is_v9) \ | |
320 | __acev_w24ret = atomic_exchange_rel (mem, newval); \ | |
321 | else \ | |
322 | __acev_w24ret = __v7_exchange_24_rel (mem, newval); \ | |
323 | __acev_w24ret; }) | |
324 | ||
cfa1f3e8 DM |
325 | #define atomic_full_barrier() \ |
326 | do { \ | |
327 | if (__atomic_is_v9) \ | |
328 | /* membar #LoadLoad | #LoadStore | #StoreLoad | #StoreStore */ \ | |
329 | __asm __volatile (".word 0x8143e00f" : : : "memory"); \ | |
330 | else \ | |
331 | __asm __volatile ("" : : : "memory"); \ | |
332 | } while (0) | |
333 | ||
334 | #define atomic_read_barrier() \ | |
335 | do { \ | |
336 | if (__atomic_is_v9) \ | |
337 | /* membar #LoadLoad | #LoadStore */ \ | |
338 | __asm __volatile (".word 0x8143e005" : : : "memory"); \ | |
339 | else \ | |
340 | __asm __volatile ("" : : : "memory"); \ | |
341 | } while (0) | |
342 | ||
343 | #define atomic_write_barrier() \ | |
344 | do { \ | |
345 | if (__atomic_is_v9) \ | |
346 | /* membar #StoreLoad | #StoreStore */ \ | |
347 | __asm __volatile (".word 0x8143e00a" : : : "memory"); \ | |
348 | else \ | |
349 | __asm __volatile ("" : : : "memory"); \ | |
350 | } while (0) | |
351 | ||
b01fe5f7 UD |
352 | #endif |
353 | ||
cfa1f3e8 DM |
354 | #include <sysdep.h> |
355 | ||
0a9d1b3b | 356 | #endif /* bits/atomic.h */ |