100 |
* Include the rest of the atomic ops macros which are common to both |
* Include the rest of the atomic ops macros which are common to both |
101 |
* powerpc32 and powerpc64. |
* powerpc32 and powerpc64. |
102 |
*/ |
*/ |
103 |
|
#ifdef _LIBC |
104 |
#include_next <bits/atomic.h> |
#include_next <bits/atomic.h> |
105 |
|
#else |
106 |
|
/* Atomic operations. PowerPC Common version. |
107 |
|
Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
108 |
|
This file is part of the GNU C Library. |
109 |
|
Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. |
110 |
|
|
111 |
|
The GNU C Library is free software; you can redistribute it and/or |
112 |
|
modify it under the terms of the GNU Lesser General Public |
113 |
|
License as published by the Free Software Foundation; either |
114 |
|
version 2.1 of the License, or (at your option) any later version. |
115 |
|
|
116 |
|
The GNU C Library is distributed in the hope that it will be useful, |
117 |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
118 |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
119 |
|
Lesser General Public License for more details. |
120 |
|
|
121 |
|
You should have received a copy of the GNU Lesser General Public |
122 |
|
License along with the GNU C Library; if not, write to the Free |
123 |
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
124 |
|
02111-1307 USA. */ |
125 |
|
|
126 |
|
/* |
127 |
|
* Never include sysdeps/powerpc/bits/atomic.h directly. |
128 |
|
* Alway use include/atomic.h which will include either |
129 |
|
* sysdeps/powerpc/powerpc32/bits/atomic.h |
130 |
|
* or |
131 |
|
* sysdeps/powerpc/powerpc64/bits/atomic.h |
132 |
|
* as appropriate and which in turn include this file. |
133 |
|
*/ |
134 |
|
|
135 |
|
#include <stdint.h> |
136 |
|
|
137 |
|
typedef int32_t atomic32_t; |
138 |
|
typedef uint32_t uatomic32_t; |
139 |
|
typedef int_fast32_t atomic_fast32_t; |
140 |
|
typedef uint_fast32_t uatomic_fast32_t; |
141 |
|
|
142 |
|
typedef int64_t atomic64_t; |
143 |
|
typedef uint64_t uatomic64_t; |
144 |
|
typedef int_fast64_t atomic_fast64_t; |
145 |
|
typedef uint_fast64_t uatomic_fast64_t; |
146 |
|
|
147 |
|
typedef intptr_t atomicptr_t; |
148 |
|
typedef uintptr_t uatomicptr_t; |
149 |
|
typedef intmax_t atomic_max_t; |
150 |
|
typedef uintmax_t uatomic_max_t; |
151 |
|
|
152 |
|
/* |
153 |
|
* Powerpc does not have byte and halfword forms of load and reserve and |
154 |
|
* store conditional. So for powerpc we stub out the 8- and 16-bit forms. |
155 |
|
*/ |
156 |
|
#define __arch_compare_and_exchange_bool_8_acq(mem, newval, oldval) \ |
157 |
|
(abort (), 0) |
158 |
|
|
159 |
|
#define __arch_compare_and_exchange_bool_16_acq(mem, newval, oldval) \ |
160 |
|
(abort (), 0) |
161 |
|
|
162 |
|
#define __arch_compare_and_exchange_bool_8_rel(mem, newval, oldval) \ |
163 |
|
(abort (), 0) |
164 |
|
|
165 |
|
#define __arch_compare_and_exchange_bool_16_rel(mem, newval, oldval) \ |
166 |
|
(abort (), 0) |
167 |
|
|
168 |
|
#ifdef UP |
169 |
|
# define __ARCH_ACQ_INSTR "" |
170 |
|
# define __ARCH_REL_INSTR "" |
171 |
|
#else |
172 |
|
# define __ARCH_ACQ_INSTR "isync" |
173 |
|
# ifndef __ARCH_REL_INSTR |
174 |
|
# define __ARCH_REL_INSTR "sync" |
175 |
|
# endif |
176 |
|
#endif |
177 |
|
|
178 |
|
#define atomic_full_barrier() __asm ("sync" ::: "memory") |
179 |
|
#define atomic_write_barrier() __asm ("eieio" ::: "memory") |
180 |
|
|
181 |
|
#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ |
182 |
|
({ \ |
183 |
|
__typeof (*(mem)) __tmp; \ |
184 |
|
__typeof (mem) __memp = (mem); \ |
185 |
|
__asm __volatile ( \ |
186 |
|
"1: lwarx %0,0,%1\n" \ |
187 |
|
" cmpw %0,%2\n" \ |
188 |
|
" bne 2f\n" \ |
189 |
|
" stwcx. %3,0,%1\n" \ |
190 |
|
" bne- 1b\n" \ |
191 |
|
"2: " __ARCH_ACQ_INSTR \ |
192 |
|
: "=&r" (__tmp) \ |
193 |
|
: "b" (__memp), "r" (oldval), "r" (newval) \ |
194 |
|
: "cr0", "memory"); \ |
195 |
|
__tmp; \ |
196 |
|
}) |
197 |
|
|
198 |
|
#define __arch_compare_and_exchange_val_32_rel(mem, newval, oldval) \ |
199 |
|
({ \ |
200 |
|
__typeof (*(mem)) __tmp; \ |
201 |
|
__typeof (mem) __memp = (mem); \ |
202 |
|
__asm __volatile (__ARCH_REL_INSTR "\n" \ |
203 |
|
"1: lwarx %0,0,%1\n" \ |
204 |
|
" cmpw %0,%2\n" \ |
205 |
|
" bne 2f\n" \ |
206 |
|
" stwcx. %3,0,%1\n" \ |
207 |
|
" bne- 1b\n" \ |
208 |
|
"2: " \ |
209 |
|
: "=&r" (__tmp) \ |
210 |
|
: "b" (__memp), "r" (oldval), "r" (newval) \ |
211 |
|
: "cr0", "memory"); \ |
212 |
|
__tmp; \ |
213 |
|
}) |
214 |
|
|
215 |
|
#define __arch_atomic_exchange_32_acq(mem, value) \ |
216 |
|
({ \ |
217 |
|
__typeof (*mem) __val; \ |
218 |
|
__asm __volatile ( \ |
219 |
|
"1: lwarx %0,0,%2\n" \ |
220 |
|
" stwcx. %3,0,%2\n" \ |
221 |
|
" bne- 1b\n" \ |
222 |
|
" " __ARCH_ACQ_INSTR \ |
223 |
|
: "=&r" (__val), "=m" (*mem) \ |
224 |
|
: "b" (mem), "r" (value), "m" (*mem) \ |
225 |
|
: "cr0", "memory"); \ |
226 |
|
__val; \ |
227 |
|
}) |
228 |
|
|
229 |
|
#define __arch_atomic_exchange_32_rel(mem, value) \ |
230 |
|
({ \ |
231 |
|
__typeof (*mem) __val; \ |
232 |
|
__asm __volatile (__ARCH_REL_INSTR "\n" \ |
233 |
|
"1: lwarx %0,0,%2\n" \ |
234 |
|
" stwcx. %3,0,%2\n" \ |
235 |
|
" bne- 1b" \ |
236 |
|
: "=&r" (__val), "=m" (*mem) \ |
237 |
|
: "b" (mem), "r" (value), "m" (*mem) \ |
238 |
|
: "cr0", "memory"); \ |
239 |
|
__val; \ |
240 |
|
}) |
241 |
|
|
242 |
|
#define __arch_atomic_exchange_and_add_32(mem, value) \ |
243 |
|
({ \ |
244 |
|
__typeof (*mem) __val, __tmp; \ |
245 |
|
__asm __volatile ("1: lwarx %0,0,%3\n" \ |
246 |
|
" add %1,%0,%4\n" \ |
247 |
|
" stwcx. %1,0,%3\n" \ |
248 |
|
" bne- 1b" \ |
249 |
|
: "=&b" (__val), "=&r" (__tmp), "=m" (*mem) \ |
250 |
|
: "b" (mem), "r" (value), "m" (*mem) \ |
251 |
|
: "cr0", "memory"); \ |
252 |
|
__val; \ |
253 |
|
}) |
254 |
|
|
255 |
|
#define __arch_atomic_increment_val_32(mem) \ |
256 |
|
({ \ |
257 |
|
__typeof (*(mem)) __val; \ |
258 |
|
__asm __volatile ("1: lwarx %0,0,%2\n" \ |
259 |
|
" addi %0,%0,1\n" \ |
260 |
|
" stwcx. %0,0,%2\n" \ |
261 |
|
" bne- 1b" \ |
262 |
|
: "=&b" (__val), "=m" (*mem) \ |
263 |
|
: "b" (mem), "m" (*mem) \ |
264 |
|
: "cr0", "memory"); \ |
265 |
|
__val; \ |
266 |
|
}) |
267 |
|
|
268 |
|
#define __arch_atomic_decrement_val_32(mem) \ |
269 |
|
({ \ |
270 |
|
__typeof (*(mem)) __val; \ |
271 |
|
__asm __volatile ("1: lwarx %0,0,%2\n" \ |
272 |
|
" subi %0,%0,1\n" \ |
273 |
|
" stwcx. %0,0,%2\n" \ |
274 |
|
" bne- 1b" \ |
275 |
|
: "=&b" (__val), "=m" (*mem) \ |
276 |
|
: "b" (mem), "m" (*mem) \ |
277 |
|
: "cr0", "memory"); \ |
278 |
|
__val; \ |
279 |
|
}) |
280 |
|
|
281 |
|
#define __arch_atomic_decrement_if_positive_32(mem) \ |
282 |
|
({ int __val, __tmp; \ |
283 |
|
__asm __volatile ("1: lwarx %0,0,%3\n" \ |
284 |
|
" cmpwi 0,%0,0\n" \ |
285 |
|
" addi %1,%0,-1\n" \ |
286 |
|
" ble 2f\n" \ |
287 |
|
" stwcx. %1,0,%3\n" \ |
288 |
|
" bne- 1b\n" \ |
289 |
|
"2: " __ARCH_ACQ_INSTR \ |
290 |
|
: "=&b" (__val), "=&r" (__tmp), "=m" (*mem) \ |
291 |
|
: "b" (mem), "m" (*mem) \ |
292 |
|
: "cr0", "memory"); \ |
293 |
|
__val; \ |
294 |
|
}) |
295 |
|
|
296 |
|
#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ |
297 |
|
({ \ |
298 |
|
__typeof (*(mem)) __result; \ |
299 |
|
if (sizeof (*mem) == 4) \ |
300 |
|
__result = __arch_compare_and_exchange_val_32_acq(mem, newval, oldval); \ |
301 |
|
else if (sizeof (*mem) == 8) \ |
302 |
|
__result = __arch_compare_and_exchange_val_64_acq(mem, newval, oldval); \ |
303 |
|
else \ |
304 |
|
abort (); \ |
305 |
|
__result; \ |
306 |
|
}) |
307 |
|
|
308 |
|
#define atomic_compare_and_exchange_val_rel(mem, newval, oldval) \ |
309 |
|
({ \ |
310 |
|
__typeof (*(mem)) __result; \ |
311 |
|
if (sizeof (*mem) == 4) \ |
312 |
|
__result = __arch_compare_and_exchange_val_32_rel(mem, newval, oldval); \ |
313 |
|
else if (sizeof (*mem) == 8) \ |
314 |
|
__result = __arch_compare_and_exchange_val_64_rel(mem, newval, oldval); \ |
315 |
|
else \ |
316 |
|
abort (); \ |
317 |
|
__result; \ |
318 |
|
}) |
319 |
|
|
320 |
|
#define atomic_exchange_acq(mem, value) \ |
321 |
|
({ \ |
322 |
|
__typeof (*(mem)) __result; \ |
323 |
|
if (sizeof (*mem) == 4) \ |
324 |
|
__result = __arch_atomic_exchange_32_acq (mem, value); \ |
325 |
|
else if (sizeof (*mem) == 8) \ |
326 |
|
__result = __arch_atomic_exchange_64_acq (mem, value); \ |
327 |
|
else \ |
328 |
|
abort (); \ |
329 |
|
__result; \ |
330 |
|
}) |
331 |
|
|
332 |
|
#define atomic_exchange_rel(mem, value) \ |
333 |
|
({ \ |
334 |
|
__typeof (*(mem)) __result; \ |
335 |
|
if (sizeof (*mem) == 4) \ |
336 |
|
__result = __arch_atomic_exchange_32_rel (mem, value); \ |
337 |
|
else if (sizeof (*mem) == 8) \ |
338 |
|
__result = __arch_atomic_exchange_64_rel (mem, value); \ |
339 |
|
else \ |
340 |
|
abort (); \ |
341 |
|
__result; \ |
342 |
|
}) |
343 |
|
|
344 |
|
#define atomic_exchange_and_add(mem, value) \ |
345 |
|
({ \ |
346 |
|
__typeof (*(mem)) __result; \ |
347 |
|
if (sizeof (*mem) == 4) \ |
348 |
|
__result = __arch_atomic_exchange_and_add_32 (mem, value); \ |
349 |
|
else if (sizeof (*mem) == 8) \ |
350 |
|
__result = __arch_atomic_exchange_and_add_64 (mem, value); \ |
351 |
|
else \ |
352 |
|
abort (); \ |
353 |
|
__result; \ |
354 |
|
}) |
355 |
|
|
356 |
|
#define atomic_increment_val(mem) \ |
357 |
|
({ \ |
358 |
|
__typeof (*(mem)) __result; \ |
359 |
|
if (sizeof (*(mem)) == 4) \ |
360 |
|
__result = __arch_atomic_increment_val_32 (mem); \ |
361 |
|
else if (sizeof (*(mem)) == 8) \ |
362 |
|
__result = __arch_atomic_increment_val_64 (mem); \ |
363 |
|
else \ |
364 |
|
abort (); \ |
365 |
|
__result; \ |
366 |
|
}) |
367 |
|
|
368 |
|
#define atomic_increment(mem) ({ atomic_increment_val (mem); (void) 0; }) |
369 |
|
|
370 |
|
#define atomic_decrement_val(mem) \ |
371 |
|
({ \ |
372 |
|
__typeof (*(mem)) __result; \ |
373 |
|
if (sizeof (*(mem)) == 4) \ |
374 |
|
__result = __arch_atomic_decrement_val_32 (mem); \ |
375 |
|
else if (sizeof (*(mem)) == 8) \ |
376 |
|
__result = __arch_atomic_decrement_val_64 (mem); \ |
377 |
|
else \ |
378 |
|
abort (); \ |
379 |
|
__result; \ |
380 |
|
}) |
381 |
|
|
382 |
|
#define atomic_decrement(mem) ({ atomic_decrement_val (mem); (void) 0; }) |
383 |
|
|
384 |
|
|
385 |
|
/* Decrement *MEM if it is > 0, and return the old value. */ |
386 |
|
#define atomic_decrement_if_positive(mem) \ |
387 |
|
({ __typeof (*(mem)) __result; \ |
388 |
|
if (sizeof (*mem) == 4) \ |
389 |
|
__result = __arch_atomic_decrement_if_positive_32 (mem); \ |
390 |
|
else if (sizeof (*mem) == 8) \ |
391 |
|
__result = __arch_atomic_decrement_if_positive_64 (mem); \ |
392 |
|
else \ |
393 |
|
abort (); \ |
394 |
|
__result; \ |
395 |
|
}) |
396 |
|
#endif |