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