]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/x86/atomic-machine.h
i386: Explain why __HAVE_64B_ATOMICS has to be 0
[thirdparty/glibc.git] / sysdeps / x86 / atomic-machine.h
CommitLineData
cd815050 1/* Atomic operations. X86 version.
2b778ceb 2 Copyright (C) 2018-2021 Free Software Foundation, Inc.
c10c099c 3 This file is part of the GNU C Library.
c10c099c
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
c10c099c 18
cd815050
L
19#ifndef _X86_ATOMIC_MACHINE_H
20#define _X86_ATOMIC_MACHINE_H 1
c10c099c 21
9090848d 22#include <stdint.h>
cd815050
L
23#include <tls.h> /* For tcbhead_t. */
24#include <libc-pointer-arith.h> /* For cast_to_integer. */
c10c099c
UD
25
26typedef int8_t atomic8_t;
27typedef uint8_t uatomic8_t;
28typedef int_fast8_t atomic_fast8_t;
29typedef uint_fast8_t uatomic_fast8_t;
30
31typedef int16_t atomic16_t;
32typedef uint16_t uatomic16_t;
33typedef int_fast16_t atomic_fast16_t;
34typedef uint_fast16_t uatomic_fast16_t;
35
36typedef int32_t atomic32_t;
37typedef uint32_t uatomic32_t;
38typedef int_fast32_t atomic_fast32_t;
39typedef uint_fast32_t uatomic_fast32_t;
40
41typedef int64_t atomic64_t;
42typedef uint64_t uatomic64_t;
43typedef int_fast64_t atomic_fast64_t;
44typedef uint_fast64_t uatomic_fast64_t;
45
46typedef intptr_t atomicptr_t;
47typedef uintptr_t uatomicptr_t;
48typedef intmax_t atomic_max_t;
49typedef uintmax_t uatomic_max_t;
50
51
0f34d426 52#define LOCK_PREFIX "lock;"
c10c099c 53
cd815050
L
54#define USE_ATOMIC_COMPILER_BUILTINS 1
55
56#ifdef __x86_64__
57# define __HAVE_64B_ATOMICS 1
58# define SP_REG "rsp"
59# define SEG_REG "fs"
60# define BR_CONSTRAINT "q"
61# define IBR_CONSTRAINT "iq"
62#else
cca75bd8
FW
63/* Since the Pentium, i386 CPUs have supported 64-bit atomics, but the
64 i386 psABI supplement provides only 4-byte alignment for uint64_t
65 inside structs, so it is currently not possible to use 64-bit
66 atomics on this platform. */
cd815050
L
67# define __HAVE_64B_ATOMICS 0
68# define SP_REG "esp"
69# define SEG_REG "gs"
70# define BR_CONSTRAINT "r"
71# define IBR_CONSTRAINT "ir"
72#endif
73#define ATOMIC_EXCHANGE_USES_CAS 0
c10c099c 74
bc957d53 75#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
038a1a9f 76 __sync_val_compare_and_swap (mem, oldval, newval)
bc957d53 77#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
038a1a9f 78 (! __sync_bool_compare_and_swap (mem, oldval, newval))
11bf311e
UD
79
80
81#define __arch_c_compare_and_exchange_val_8_acq(mem, newval, oldval) \
82 ({ __typeof (*mem) ret; \
cd815050
L
83 __asm __volatile ("cmpl $0, %%" SEG_REG ":%P5\n\t" \
84 "je 0f\n\t" \
85 "lock\n" \
11bf311e
UD
86 "0:\tcmpxchgb %b2, %1" \
87 : "=a" (ret), "=m" (*mem) \
cd815050 88 : BR_CONSTRAINT (newval), "m" (*mem), "0" (oldval), \
11bf311e
UD
89 "i" (offsetof (tcbhead_t, multiple_threads))); \
90 ret; })
91
92#define __arch_c_compare_and_exchange_val_16_acq(mem, newval, oldval) \
93 ({ __typeof (*mem) ret; \
cd815050
L
94 __asm __volatile ("cmpl $0, %%" SEG_REG ":%P5\n\t" \
95 "je 0f\n\t" \
96 "lock\n" \
11bf311e
UD
97 "0:\tcmpxchgw %w2, %1" \
98 : "=a" (ret), "=m" (*mem) \
cd815050 99 : BR_CONSTRAINT (newval), "m" (*mem), "0" (oldval), \
11bf311e
UD
100 "i" (offsetof (tcbhead_t, multiple_threads))); \
101 ret; })
102
103#define __arch_c_compare_and_exchange_val_32_acq(mem, newval, oldval) \
104 ({ __typeof (*mem) ret; \
cd815050
L
105 __asm __volatile ("cmpl $0, %%" SEG_REG ":%P5\n\t" \
106 "je 0f\n\t" \
107 "lock\n" \
11bf311e
UD
108 "0:\tcmpxchgl %2, %1" \
109 : "=a" (ret), "=m" (*mem) \
cd815050
L
110 : BR_CONSTRAINT (newval), "m" (*mem), "0" (oldval), \
111 "i" (offsetof (tcbhead_t, multiple_threads))); \
11bf311e
UD
112 ret; })
113
cd815050
L
114#ifdef __x86_64__
115# define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \
11bf311e
UD
116 ({ __typeof (*mem) ret; \
117 __asm __volatile ("cmpl $0, %%fs:%P5\n\t" \
118 "je 0f\n\t" \
119 "lock\n" \
120 "0:\tcmpxchgq %q2, %1" \
121 : "=a" (ret), "=m" (*mem) \
c515fb51
L
122 : "q" ((atomic64_t) cast_to_integer (newval)), \
123 "m" (*mem), \
124 "0" ((atomic64_t) cast_to_integer (oldval)), \
11bf311e 125 "i" (offsetof (tcbhead_t, multiple_threads))); \
8099361e 126 ret; })
cd815050
L
127# define do_exchange_and_add_val_64_acq(pfx, mem, value) 0
128# define do_add_val_64_acq(pfx, mem, value) do { } while (0)
129#else
130/* XXX We do not really need 64-bit compare-and-exchange. At least
131 not in the moment. Using it would mean causing portability
132 problems since not many other 32-bit architectures have support for
133 such an operation. So don't define any code for now. If it is
134 really going to be used the code below can be used on Intel Pentium
135 and later, but NOT on i486. */
136# define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \
137 ({ __typeof (*mem) ret = *(mem); \
138 __atomic_link_error (); \
139 ret = (newval); \
140 ret = (oldval); \
141 ret; })
142
143# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
144 ({ __typeof (*mem) ret = *(mem); \
145 __atomic_link_error (); \
146 ret = (newval); \
147 ret = (oldval); \
148 ret; })
149
150# define do_exchange_and_add_val_64_acq(pfx, mem, value) \
151 ({ __typeof (value) __addval = (value); \
152 __typeof (*mem) __result; \
153 __typeof (mem) __memp = (mem); \
154 __typeof (*mem) __tmpval; \
155 __result = *__memp; \
156 do \
157 __tmpval = __result; \
158 while ((__result = pfx##_compare_and_exchange_val_64_acq \
159 (__memp, __result + __addval, __result)) == __tmpval); \
160 __result; })
161
162# define do_add_val_64_acq(pfx, mem, value) \
163 { \
164 __typeof (value) __addval = (value); \
165 __typeof (mem) __memp = (mem); \
166 __typeof (*mem) __oldval = *__memp; \
167 __typeof (*mem) __tmpval; \
168 do \
169 __tmpval = __oldval; \
170 while ((__oldval = pfx##_compare_and_exchange_val_64_acq \
171 (__memp, __oldval + __addval, __oldval)) == __tmpval); \
172 }
173#endif
8099361e
UD
174
175
f79466a8 176/* Note that we need no lock prefix. */
949ec764 177#define atomic_exchange_acq(mem, newvalue) \
f79466a8
UD
178 ({ __typeof (*mem) result; \
179 if (sizeof (*mem) == 1) \
180 __asm __volatile ("xchgb %b0, %1" \
a810e68c 181 : "=q" (result), "=m" (*mem) \
abfd53d1 182 : "0" (newvalue), "m" (*mem)); \
f79466a8
UD
183 else if (sizeof (*mem) == 2) \
184 __asm __volatile ("xchgw %w0, %1" \
185 : "=r" (result), "=m" (*mem) \
abfd53d1 186 : "0" (newvalue), "m" (*mem)); \
f79466a8
UD
187 else if (sizeof (*mem) == 4) \
188 __asm __volatile ("xchgl %0, %1" \
189 : "=r" (result), "=m" (*mem) \
abfd53d1 190 : "0" (newvalue), "m" (*mem)); \
cd815050 191 else if (__HAVE_64B_ATOMICS) \
f79466a8
UD
192 __asm __volatile ("xchgq %q0, %1" \
193 : "=r" (result), "=m" (*mem) \
c515fb51
L
194 : "0" ((atomic64_t) cast_to_integer (newvalue)), \
195 "m" (*mem)); \
cd815050
L
196 else \
197 { \
198 result = 0; \
199 __atomic_link_error (); \
200 } \
f79466a8
UD
201 result; })
202
203
cd815050
L
204#define __arch_exchange_and_add_body(lock, pfx, mem, value) \
205 ({ __typeof (*mem) __result; \
206 __typeof (value) __addval = (value); \
c10c099c 207 if (sizeof (*mem) == 1) \
11bf311e 208 __asm __volatile (lock "xaddb %b0, %1" \
cd815050
L
209 : "=q" (__result), "=m" (*mem) \
210 : "0" (__addval), "m" (*mem), \
11bf311e 211 "i" (offsetof (tcbhead_t, multiple_threads))); \
c10c099c 212 else if (sizeof (*mem) == 2) \
11bf311e 213 __asm __volatile (lock "xaddw %w0, %1" \
cd815050
L
214 : "=r" (__result), "=m" (*mem) \
215 : "0" (__addval), "m" (*mem), \
11bf311e 216 "i" (offsetof (tcbhead_t, multiple_threads))); \
c10c099c 217 else if (sizeof (*mem) == 4) \
11bf311e 218 __asm __volatile (lock "xaddl %0, %1" \
cd815050
L
219 : "=r" (__result), "=m" (*mem) \
220 : "0" (__addval), "m" (*mem), \
11bf311e 221 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050 222 else if (__HAVE_64B_ATOMICS) \
11bf311e 223 __asm __volatile (lock "xaddq %q0, %1" \
cd815050
L
224 : "=r" (__result), "=m" (*mem) \
225 : "0" ((atomic64_t) cast_to_integer (__addval)), \
c515fb51 226 "m" (*mem), \
11bf311e 227 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050
L
228 else \
229 __result = do_exchange_and_add_val_64_acq (pfx, (mem), __addval); \
230 __result; })
c10c099c 231
bc957d53 232#define atomic_exchange_and_add(mem, value) \
038a1a9f 233 __sync_fetch_and_add (mem, value)
11bf311e
UD
234
235#define __arch_exchange_and_add_cprefix \
cd815050 236 "cmpl $0, %%" SEG_REG ":%P4\n\tje 0f\n\tlock\n0:\t"
11bf311e
UD
237
238#define catomic_exchange_and_add(mem, value) \
cd815050
L
239 __arch_exchange_and_add_body (__arch_exchange_and_add_cprefix, __arch_c, \
240 mem, value)
11bf311e
UD
241
242
cd815050 243#define __arch_add_body(lock, pfx, apfx, mem, value) \
11bf311e
UD
244 do { \
245 if (__builtin_constant_p (value) && (value) == 1) \
246 pfx##_increment (mem); \
247 else if (__builtin_constant_p (value) && (value) == -1) \
248 pfx##_decrement (mem); \
249 else if (sizeof (*mem) == 1) \
250 __asm __volatile (lock "addb %b1, %0" \
251 : "=m" (*mem) \
cd815050 252 : IBR_CONSTRAINT (value), "m" (*mem), \
11bf311e
UD
253 "i" (offsetof (tcbhead_t, multiple_threads))); \
254 else if (sizeof (*mem) == 2) \
255 __asm __volatile (lock "addw %w1, %0" \
256 : "=m" (*mem) \
257 : "ir" (value), "m" (*mem), \
258 "i" (offsetof (tcbhead_t, multiple_threads))); \
259 else if (sizeof (*mem) == 4) \
260 __asm __volatile (lock "addl %1, %0" \
261 : "=m" (*mem) \
262 : "ir" (value), "m" (*mem), \
263 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050 264 else if (__HAVE_64B_ATOMICS) \
11bf311e
UD
265 __asm __volatile (lock "addq %q1, %0" \
266 : "=m" (*mem) \
c515fb51
L
267 : "ir" ((atomic64_t) cast_to_integer (value)), \
268 "m" (*mem), \
11bf311e 269 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050
L
270 else \
271 do_add_val_64_acq (apfx, (mem), (value)); \
11bf311e 272 } while (0)
c10c099c 273
cd815050
L
274# define atomic_add(mem, value) \
275 __arch_add_body (LOCK_PREFIX, atomic, __arch, mem, value)
11bf311e
UD
276
277#define __arch_add_cprefix \
cd815050 278 "cmpl $0, %%" SEG_REG ":%P3\n\tje 0f\n\tlock\n0:\t"
11bf311e
UD
279
280#define catomic_add(mem, value) \
cd815050 281 __arch_add_body (__arch_add_cprefix, atomic, __arch_c, mem, value)
c10c099c
UD
282
283
284#define atomic_add_negative(mem, value) \
285 ({ unsigned char __result; \
286 if (sizeof (*mem) == 1) \
bd4f43b4 287 __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1" \
c10c099c 288 : "=m" (*mem), "=qm" (__result) \
cd815050 289 : IBR_CONSTRAINT (value), "m" (*mem)); \
c10c099c 290 else if (sizeof (*mem) == 2) \
bd4f43b4 291 __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1" \
c10c099c 292 : "=m" (*mem), "=qm" (__result) \
abfd53d1 293 : "ir" (value), "m" (*mem)); \
c10c099c 294 else if (sizeof (*mem) == 4) \
bd4f43b4 295 __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1" \
c10c099c 296 : "=m" (*mem), "=qm" (__result) \
abfd53d1 297 : "ir" (value), "m" (*mem)); \
cd815050 298 else if (__HAVE_64B_ATOMICS) \
bd4f43b4 299 __asm __volatile (LOCK_PREFIX "addq %q2, %0; sets %1" \
c10c099c 300 : "=m" (*mem), "=qm" (__result) \
c515fb51
L
301 : "ir" ((atomic64_t) cast_to_integer (value)), \
302 "m" (*mem)); \
cd815050
L
303 else \
304 __atomic_link_error (); \
c10c099c
UD
305 __result; })
306
307
308#define atomic_add_zero(mem, value) \
309 ({ unsigned char __result; \
310 if (sizeof (*mem) == 1) \
bd4f43b4 311 __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1" \
c10c099c 312 : "=m" (*mem), "=qm" (__result) \
cd815050 313 : IBR_CONSTRAINT (value), "m" (*mem)); \
c10c099c 314 else if (sizeof (*mem) == 2) \
bd4f43b4 315 __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1" \
c10c099c 316 : "=m" (*mem), "=qm" (__result) \
abfd53d1 317 : "ir" (value), "m" (*mem)); \
c10c099c 318 else if (sizeof (*mem) == 4) \
bd4f43b4 319 __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1" \
c10c099c 320 : "=m" (*mem), "=qm" (__result) \
abfd53d1 321 : "ir" (value), "m" (*mem)); \
cd815050 322 else if (__HAVE_64B_ATOMICS) \
bd4f43b4 323 __asm __volatile (LOCK_PREFIX "addq %q2, %0; setz %1" \
c10c099c 324 : "=m" (*mem), "=qm" (__result) \
c515fb51
L
325 : "ir" ((atomic64_t) cast_to_integer (value)), \
326 "m" (*mem)); \
cd815050
L
327 else \
328 __atomic_link_error (); \
c10c099c
UD
329 __result; })
330
331
cd815050 332#define __arch_increment_body(lock, pfx, mem) \
11bf311e
UD
333 do { \
334 if (sizeof (*mem) == 1) \
335 __asm __volatile (lock "incb %b0" \
336 : "=m" (*mem) \
337 : "m" (*mem), \
338 "i" (offsetof (tcbhead_t, multiple_threads))); \
339 else if (sizeof (*mem) == 2) \
340 __asm __volatile (lock "incw %w0" \
341 : "=m" (*mem) \
342 : "m" (*mem), \
343 "i" (offsetof (tcbhead_t, multiple_threads))); \
344 else if (sizeof (*mem) == 4) \
345 __asm __volatile (lock "incl %0" \
346 : "=m" (*mem) \
347 : "m" (*mem), \
348 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050 349 else if (__HAVE_64B_ATOMICS) \
11bf311e
UD
350 __asm __volatile (lock "incq %q0" \
351 : "=m" (*mem) \
352 : "m" (*mem), \
353 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050
L
354 else \
355 do_add_val_64_acq (pfx, mem, 1); \
11bf311e
UD
356 } while (0)
357
cd815050 358#define atomic_increment(mem) __arch_increment_body (LOCK_PREFIX, __arch, mem)
11bf311e
UD
359
360#define __arch_increment_cprefix \
cd815050 361 "cmpl $0, %%" SEG_REG ":%P2\n\tje 0f\n\tlock\n0:\t"
11bf311e
UD
362
363#define catomic_increment(mem) \
cd815050 364 __arch_increment_body (__arch_increment_cprefix, __arch_c, mem)
8099361e 365
c10c099c
UD
366
367#define atomic_increment_and_test(mem) \
368 ({ unsigned char __result; \
369 if (sizeof (*mem) == 1) \
cd815050 370 __asm __volatile (LOCK_PREFIX "incb %b0; sete %b1" \
c10c099c 371 : "=m" (*mem), "=qm" (__result) \
abfd53d1 372 : "m" (*mem)); \
c10c099c 373 else if (sizeof (*mem) == 2) \
cd815050 374 __asm __volatile (LOCK_PREFIX "incw %w0; sete %w1" \
c10c099c 375 : "=m" (*mem), "=qm" (__result) \
abfd53d1 376 : "m" (*mem)); \
c10c099c 377 else if (sizeof (*mem) == 4) \
bd4f43b4 378 __asm __volatile (LOCK_PREFIX "incl %0; sete %1" \
c10c099c 379 : "=m" (*mem), "=qm" (__result) \
abfd53d1 380 : "m" (*mem)); \
cd815050 381 else if (__HAVE_64B_ATOMICS) \
bd4f43b4 382 __asm __volatile (LOCK_PREFIX "incq %q0; sete %1" \
c10c099c 383 : "=m" (*mem), "=qm" (__result) \
abfd53d1 384 : "m" (*mem)); \
cd815050
L
385 else \
386 __atomic_link_error (); \
c10c099c
UD
387 __result; })
388
389
cd815050 390#define __arch_decrement_body(lock, pfx, mem) \
11bf311e
UD
391 do { \
392 if (sizeof (*mem) == 1) \
393 __asm __volatile (lock "decb %b0" \
394 : "=m" (*mem) \
395 : "m" (*mem), \
396 "i" (offsetof (tcbhead_t, multiple_threads))); \
397 else if (sizeof (*mem) == 2) \
398 __asm __volatile (lock "decw %w0" \
399 : "=m" (*mem) \
400 : "m" (*mem), \
401 "i" (offsetof (tcbhead_t, multiple_threads))); \
402 else if (sizeof (*mem) == 4) \
403 __asm __volatile (lock "decl %0" \
404 : "=m" (*mem) \
405 : "m" (*mem), \
406 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050 407 else if (__HAVE_64B_ATOMICS) \
11bf311e
UD
408 __asm __volatile (lock "decq %q0" \
409 : "=m" (*mem) \
410 : "m" (*mem), \
411 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050
L
412 else \
413 do_add_val_64_acq (pfx, mem, -1); \
11bf311e
UD
414 } while (0)
415
cd815050 416#define atomic_decrement(mem) __arch_decrement_body (LOCK_PREFIX, __arch, mem)
11bf311e
UD
417
418#define __arch_decrement_cprefix \
cd815050 419 "cmpl $0, %%" SEG_REG ":%P2\n\tje 0f\n\tlock\n0:\t"
11bf311e
UD
420
421#define catomic_decrement(mem) \
cd815050 422 __arch_decrement_body (__arch_decrement_cprefix, __arch_c, mem)
8099361e 423
c10c099c
UD
424
425#define atomic_decrement_and_test(mem) \
426 ({ unsigned char __result; \
427 if (sizeof (*mem) == 1) \
bd4f43b4 428 __asm __volatile (LOCK_PREFIX "decb %b0; sete %1" \
c10c099c 429 : "=m" (*mem), "=qm" (__result) \
abfd53d1 430 : "m" (*mem)); \
c10c099c 431 else if (sizeof (*mem) == 2) \
bd4f43b4 432 __asm __volatile (LOCK_PREFIX "decw %w0; sete %1" \
c10c099c 433 : "=m" (*mem), "=qm" (__result) \
abfd53d1 434 : "m" (*mem)); \
c10c099c 435 else if (sizeof (*mem) == 4) \
bd4f43b4 436 __asm __volatile (LOCK_PREFIX "decl %0; sete %1" \
c10c099c 437 : "=m" (*mem), "=qm" (__result) \
abfd53d1 438 : "m" (*mem)); \
c10c099c 439 else \
bd4f43b4 440 __asm __volatile (LOCK_PREFIX "decq %q0; sete %1" \
c10c099c 441 : "=m" (*mem), "=qm" (__result) \
abfd53d1 442 : "m" (*mem)); \
c10c099c
UD
443 __result; })
444
445
446#define atomic_bit_set(mem, bit) \
11bf311e
UD
447 do { \
448 if (sizeof (*mem) == 1) \
449 __asm __volatile (LOCK_PREFIX "orb %b2, %0" \
450 : "=m" (*mem) \
cd815050 451 : "m" (*mem), IBR_CONSTRAINT (1L << (bit))); \
11bf311e
UD
452 else if (sizeof (*mem) == 2) \
453 __asm __volatile (LOCK_PREFIX "orw %w2, %0" \
454 : "=m" (*mem) \
455 : "m" (*mem), "ir" (1L << (bit))); \
456 else if (sizeof (*mem) == 4) \
457 __asm __volatile (LOCK_PREFIX "orl %2, %0" \
458 : "=m" (*mem) \
459 : "m" (*mem), "ir" (1L << (bit))); \
460 else if (__builtin_constant_p (bit) && (bit) < 32) \
461 __asm __volatile (LOCK_PREFIX "orq %2, %0" \
462 : "=m" (*mem) \
463 : "m" (*mem), "i" (1L << (bit))); \
cd815050 464 else if (__HAVE_64B_ATOMICS) \
11bf311e
UD
465 __asm __volatile (LOCK_PREFIX "orq %q2, %0" \
466 : "=m" (*mem) \
467 : "m" (*mem), "r" (1UL << (bit))); \
cd815050
L
468 else \
469 __atomic_link_error (); \
11bf311e 470 } while (0)
c10c099c
UD
471
472
473#define atomic_bit_test_set(mem, bit) \
474 ({ unsigned char __result; \
475 if (sizeof (*mem) == 1) \
bd4f43b4 476 __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0" \
c10c099c 477 : "=q" (__result), "=m" (*mem) \
cd815050 478 : "m" (*mem), IBR_CONSTRAINT (bit)); \
c10c099c 479 else if (sizeof (*mem) == 2) \
bd4f43b4 480 __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0" \
c10c099c 481 : "=q" (__result), "=m" (*mem) \
002ff853 482 : "m" (*mem), "ir" (bit)); \
c10c099c 483 else if (sizeof (*mem) == 4) \
bd4f43b4 484 __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0" \
c10c099c 485 : "=q" (__result), "=m" (*mem) \
002ff853 486 : "m" (*mem), "ir" (bit)); \
cd815050 487 else if (__HAVE_64B_ATOMICS) \
bd4f43b4 488 __asm __volatile (LOCK_PREFIX "btsq %3, %1; setc %0" \
c10c099c 489 : "=q" (__result), "=m" (*mem) \
002ff853 490 : "m" (*mem), "ir" (bit)); \
cd815050
L
491 else \
492 __atomic_link_error (); \
c10c099c 493 __result; })
f377d022
UD
494
495
6c03cd11 496#define __arch_and_body(lock, mem, mask) \
11bf311e
UD
497 do { \
498 if (sizeof (*mem) == 1) \
6c03cd11 499 __asm __volatile (lock "andb %b1, %0" \
11bf311e 500 : "=m" (*mem) \
cd815050 501 : IBR_CONSTRAINT (mask), "m" (*mem), \
6c03cd11 502 "i" (offsetof (tcbhead_t, multiple_threads))); \
11bf311e 503 else if (sizeof (*mem) == 2) \
6c03cd11 504 __asm __volatile (lock "andw %w1, %0" \
11bf311e 505 : "=m" (*mem) \
6c03cd11
UD
506 : "ir" (mask), "m" (*mem), \
507 "i" (offsetof (tcbhead_t, multiple_threads))); \
11bf311e 508 else if (sizeof (*mem) == 4) \
6c03cd11 509 __asm __volatile (lock "andl %1, %0" \
11bf311e 510 : "=m" (*mem) \
6c03cd11
UD
511 : "ir" (mask), "m" (*mem), \
512 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050 513 else if (__HAVE_64B_ATOMICS) \
6c03cd11 514 __asm __volatile (lock "andq %q1, %0" \
11bf311e 515 : "=m" (*mem) \
6c03cd11
UD
516 : "ir" (mask), "m" (*mem), \
517 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050
L
518 else \
519 __atomic_link_error (); \
11bf311e
UD
520 } while (0)
521
6c03cd11 522#define __arch_cprefix \
cd815050 523 "cmpl $0, %%" SEG_REG ":%P3\n\tje 0f\n\tlock\n0:\t"
6c03cd11
UD
524
525#define atomic_and(mem, mask) __arch_and_body (LOCK_PREFIX, mem, mask)
526
527#define catomic_and(mem, mask) __arch_and_body (__arch_cprefix, mem, mask)
528
11bf311e 529
cd815050 530#define __arch_or_body(lock, mem, mask) \
11bf311e
UD
531 do { \
532 if (sizeof (*mem) == 1) \
a810e68c 533 __asm __volatile (lock "orb %b1, %0" \
11bf311e 534 : "=m" (*mem) \
cd815050 535 : IBR_CONSTRAINT (mask), "m" (*mem), \
11bf311e
UD
536 "i" (offsetof (tcbhead_t, multiple_threads))); \
537 else if (sizeof (*mem) == 2) \
77151937 538 __asm __volatile (lock "orw %w1, %0" \
11bf311e
UD
539 : "=m" (*mem) \
540 : "ir" (mask), "m" (*mem), \
541 "i" (offsetof (tcbhead_t, multiple_threads))); \
542 else if (sizeof (*mem) == 4) \
543 __asm __volatile (lock "orl %1, %0" \
544 : "=m" (*mem) \
545 : "ir" (mask), "m" (*mem), \
546 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050 547 else if (__HAVE_64B_ATOMICS) \
77151937 548 __asm __volatile (lock "orq %q1, %0" \
11bf311e
UD
549 : "=m" (*mem) \
550 : "ir" (mask), "m" (*mem), \
551 "i" (offsetof (tcbhead_t, multiple_threads))); \
cd815050
L
552 else \
553 __atomic_link_error (); \
11bf311e
UD
554 } while (0)
555
556#define atomic_or(mem, mask) __arch_or_body (LOCK_PREFIX, mem, mask)
557
6c03cd11 558#define catomic_or(mem, mask) __arch_or_body (__arch_cprefix, mem, mask)
c47ca964
TR
559
560/* We don't use mfence because it is supposedly slower due to having to
561 provide stronger guarantees (e.g., regarding self-modifying code). */
562#define atomic_full_barrier() \
cd815050 563 __asm __volatile (LOCK_PREFIX "orl $0, (%%" SP_REG ")" ::: "memory")
c47ca964
TR
564#define atomic_read_barrier() __asm ("" ::: "memory")
565#define atomic_write_barrier() __asm ("" ::: "memory")
9090848d 566
cd815050
L
567#define atomic_spin_nop() __asm ("pause")
568
9090848d 569#endif /* atomic-machine.h */