summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux
diff options
context:
space:
mode:
author"Steven J. Hill" <sjhill@realitydiluted.com>2005-05-12 03:27:36 +0000
committer"Steven J. Hill" <sjhill@realitydiluted.com>2005-05-12 03:27:36 +0000
commitf122662e19bfb4d529d0b3d8f812bef44fb2d2f6 (patch)
tree10fc9933b640ea05e237b3afc57d492d8c6c72fa /libc/sysdeps/linux
parent03196f15d10064639691c25fb7ed0d2924ec8d5b (diff)
Added new 'bits/atomic.h' for most of the architectures and the top-level 'include/atomic.h' to add in new atomic operations for use by NPTL. There are multiple files for PowerPC and Sparc for 'atomic.h'. I will let those architecture maintainers choose the correct file. The files come from glibc in 'sysdeps/ARCH/bits'.
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r--libc/sysdeps/linux/alpha/bits/atomic.h369
-rw-r--r--libc/sysdeps/linux/common/bits/atomic.h43
-rw-r--r--libc/sysdeps/linux/i386/bits/atomic.h366
-rw-r--r--libc/sysdeps/linux/mips/bits/atomic.h303
-rw-r--r--libc/sysdeps/linux/sh/bits/atomic.h419
-rw-r--r--libc/sysdeps/linux/x86_64/bits/atomic.h324
6 files changed, 1824 insertions, 0 deletions
diff --git a/libc/sysdeps/linux/alpha/bits/atomic.h b/libc/sysdeps/linux/alpha/bits/atomic.h
new file mode 100644
index 000000000..36a740c75
--- /dev/null
+++ b/libc/sysdeps/linux/alpha/bits/atomic.h
@@ -0,0 +1,369 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdint.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifdef UP
+# define __MB /* nothing */
+#else
+# define __MB " mb\n"
+#endif
+
+
+/* Compare and exchange. For all of the "xxx" routines, we expect a
+ "__prev" and a "__cmp" variable to be provided by the enclosing scope,
+ in which values are returned. */
+
+#define __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2) \
+({ \
+ unsigned long __tmp, __snew, __addr64; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ " andnot %[__addr8],7,%[__addr64]\n" \
+ " insbl %[__new],%[__addr8],%[__snew]\n" \
+ "1: ldq_l %[__tmp],0(%[__addr64])\n" \
+ " extbl %[__tmp],%[__addr8],%[__prev]\n" \
+ " cmpeq %[__prev],%[__old],%[__cmp]\n" \
+ " beq %[__cmp],2f\n" \
+ " mskbl %[__tmp],%[__addr8],%[__tmp]\n" \
+ " or %[__snew],%[__tmp],%[__tmp]\n" \
+ " stq_c %[__tmp],0(%[__addr64])\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ "2:" \
+ : [__prev] "=&r" (__prev), \
+ [__snew] "=&r" (__snew), \
+ [__tmp] "=&r" (__tmp), \
+ [__cmp] "=&r" (__cmp), \
+ [__addr64] "=&r" (__addr64) \
+ : [__addr8] "r" (mem), \
+ [__old] "Ir" ((uint64_t)(uint8_t)(uint64_t)(old)), \
+ [__new] "r" (new) \
+ : "memory"); \
+})
+
+#define __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2) \
+({ \
+ unsigned long __tmp, __snew, __addr64; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ " andnot %[__addr16],7,%[__addr64]\n" \
+ " inswl %[__new],%[__addr16],%[__snew]\n" \
+ "1: ldq_l %[__tmp],0(%[__addr64])\n" \
+ " extwl %[__tmp],%[__addr16],%[__prev]\n" \
+ " cmpeq %[__prev],%[__old],%[__cmp]\n" \
+ " beq %[__cmp],2f\n" \
+ " mskwl %[__tmp],%[__addr16],%[__tmp]\n" \
+ " or %[__snew],%[__tmp],%[__tmp]\n" \
+ " stq_c %[__tmp],0(%[__addr64])\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ "2:" \
+ : [__prev] "=&r" (__prev), \
+ [__snew] "=&r" (__snew), \
+ [__tmp] "=&r" (__tmp), \
+ [__cmp] "=&r" (__cmp), \
+ [__addr64] "=&r" (__addr64) \
+ : [__addr16] "r" (mem), \
+ [__old] "Ir" ((uint64_t)(uint16_t)(uint64_t)(old)), \
+ [__new] "r" (new) \
+ : "memory"); \
+})
+
+#define __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2) \
+({ \
+ __asm__ __volatile__ ( \
+ mb1 \
+ "1: ldl_l %[__prev],%[__mem]\n" \
+ " cmpeq %[__prev],%[__old],%[__cmp]\n" \
+ " beq %[__cmp],2f\n" \
+ " mov %[__new],%[__cmp]\n" \
+ " stl_c %[__cmp],%[__mem]\n" \
+ " beq %[__cmp],1b\n" \
+ mb2 \
+ "2:" \
+ : [__prev] "=&r" (__prev), \
+ [__cmp] "=&r" (__cmp) \
+ : [__mem] "m" (*(mem)), \
+ [__old] "Ir" ((uint64_t)(atomic32_t)(uint64_t)(old)), \
+ [__new] "Ir" (new) \
+ : "memory"); \
+})
+
+#define __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2) \
+({ \
+ __asm__ __volatile__ ( \
+ mb1 \
+ "1: ldq_l %[__prev],%[__mem]\n" \
+ " cmpeq %[__prev],%[__old],%[__cmp]\n" \
+ " beq %[__cmp],2f\n" \
+ " mov %[__new],%[__cmp]\n" \
+ " stq_c %[__cmp],%[__mem]\n" \
+ " beq %[__cmp],1b\n" \
+ mb2 \
+ "2:" \
+ : [__prev] "=&r" (__prev), \
+ [__cmp] "=&r" (__cmp) \
+ : [__mem] "m" (*(mem)), \
+ [__old] "Ir" ((uint64_t)(old)), \
+ [__new] "Ir" (new) \
+ : "memory"); \
+})
+
+/* For all "bool" routines, we return FALSE if exchange succesful. */
+
+#define __arch_compare_and_exchange_bool_8_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2); \
+ !__cmp; })
+
+#define __arch_compare_and_exchange_bool_16_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2); \
+ !__cmp; })
+
+#define __arch_compare_and_exchange_bool_32_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2); \
+ !__cmp; })
+
+#define __arch_compare_and_exchange_bool_64_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2); \
+ !__cmp; })
+
+/* For all "val" routines, return the old value whether exchange
+ successful or not. */
+
+#define __arch_compare_and_exchange_val_8_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2); \
+ (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_16_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2); \
+ (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_32_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2); \
+ (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_64_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2); \
+ (typeof (*mem))__prev; })
+
+/* Compare and exchange with "acquire" semantics, ie barrier after. */
+
+#define atomic_compare_and_exchange_bool_acq(mem, new, old) \
+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+ mem, new, old, "", __MB)
+
+#define atomic_compare_and_exchange_val_acq(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, "", __MB)
+
+/* Compare and exchange with "release" semantics, ie barrier before. */
+
+#define atomic_compare_and_exchange_bool_rel(mem, new, old) \
+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+ mem, new, old, __MB, "")
+
+#define atomic_compare_and_exchange_val_rel(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, __MB, "")
+
+
+/* Atomically store value and return the previous value. */
+
+#define __arch_exchange_8_int(mem, value, mb1, mb2) \
+({ \
+ unsigned long __ret, __tmp, __addr64, __sval; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ " andnot %[__addr8],7,%[__addr64]\n" \
+ " insbl %[__value],%[__addr8],%[__sval]\n" \
+ "1: ldq_l %[__tmp],0(%[__addr64])\n" \
+ " extbl %[__tmp],%[__addr8],%[__ret]\n" \
+ " mskbl %[__tmp],%[__addr8],%[__tmp]\n" \
+ " or %[__sval],%[__tmp],%[__tmp]\n" \
+ " stq_c %[__tmp],0(%[__addr64])\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ : [__ret] "=&r" (__ret), \
+ [__sval] "=&r" (__sval), \
+ [__tmp] "=&r" (__tmp), \
+ [__addr64] "=&r" (__addr64) \
+ : [__addr8] "r" (mem), \
+ [__value] "r" (value) \
+ : "memory"); \
+ __ret; })
+
+#define __arch_exchange_16_int(mem, value, mb1, mb2) \
+({ \
+ unsigned long __ret, __tmp, __addr64, __sval; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ " andnot %[__addr16],7,%[__addr64]\n" \
+ " inswl %[__value],%[__addr16],%[__sval]\n" \
+ "1: ldq_l %[__tmp],0(%[__addr64])\n" \
+ " extwl %[__tmp],%[__addr16],%[__ret]\n" \
+ " mskwl %[__tmp],%[__addr16],%[__tmp]\n" \
+ " or %[__sval],%[__tmp],%[__tmp]\n" \
+ " stq_c %[__tmp],0(%[__addr64])\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ : [__ret] "=&r" (__ret), \
+ [__sval] "=&r" (__sval), \
+ [__tmp] "=&r" (__tmp), \
+ [__addr64] "=&r" (__addr64) \
+ : [__addr16] "r" (mem), \
+ [__value] "r" (value) \
+ : "memory"); \
+ __ret; })
+
+#define __arch_exchange_32_int(mem, value, mb1, mb2) \
+({ \
+ signed int __ret, __tmp; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ "1: ldl_l %[__ret],%[__mem]\n" \
+ " mov %[__val],%[__tmp]\n" \
+ " stl_c %[__tmp],%[__mem]\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ : [__ret] "=&r" (__ret), \
+ [__tmp] "=&r" (__tmp) \
+ : [__mem] "m" (*(mem)), \
+ [__val] "Ir" (value) \
+ : "memory"); \
+ __ret; })
+
+#define __arch_exchange_64_int(mem, value, mb1, mb2) \
+({ \
+ unsigned long __ret, __tmp; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ "1: ldq_l %[__ret],%[__mem]\n" \
+ " mov %[__val],%[__tmp]\n" \
+ " stq_c %[__tmp],%[__mem]\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ : [__ret] "=&r" (__ret), \
+ [__tmp] "=&r" (__tmp) \
+ : [__mem] "m" (*(mem)), \
+ [__val] "Ir" (value) \
+ : "memory"); \
+ __ret; })
+
+#define atomic_exchange_acq(mem, value) \
+ __atomic_val_bysize (__arch_exchange, int, mem, value, "", __MB)
+
+#define atomic_exchange_rel(mem, value) \
+ __atomic_val_bysize (__arch_exchange, int, mem, value, __MB, "")
+
+
+/* Atomically add value and return the previous (unincremented) value. */
+
+#define __arch_exchange_and_add_8_int(mem, value, mb1, mb2) \
+ ({ __builtin_trap (); 0; })
+
+#define __arch_exchange_and_add_16_int(mem, value, mb1, mb2) \
+ ({ __builtin_trap (); 0; })
+
+#define __arch_exchange_and_add_32_int(mem, value, mb1, mb2) \
+({ \
+ signed int __ret, __tmp; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ "1: ldl_l %[__ret],%[__mem]\n" \
+ " addl %[__ret],%[__val],%[__tmp]\n" \
+ " stl_c %[__tmp],%[__mem]\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ : [__ret] "=&r" (__ret), \
+ [__tmp] "=&r" (__tmp) \
+ : [__mem] "m" (*(mem)), \
+ [__val] "Ir" ((signed int)(value)) \
+ : "memory"); \
+ __ret; })
+
+#define __arch_exchange_and_add_64_int(mem, value, mb1, mb2) \
+({ \
+ unsigned long __ret, __tmp; \
+ __asm__ __volatile__ ( \
+ mb1 \
+ "1: ldq_l %[__ret],%[__mem]\n" \
+ " addq %[__ret],%[__val],%[__tmp]\n" \
+ " stq_c %[__tmp],%[__mem]\n" \
+ " beq %[__tmp],1b\n" \
+ mb2 \
+ : [__ret] "=&r" (__ret), \
+ [__tmp] "=&r" (__tmp) \
+ : [__mem] "m" (*(mem)), \
+ [__val] "Ir" ((unsigned long)(value)) \
+ : "memory"); \
+ __ret; })
+
+/* ??? Barrier semantics for atomic_exchange_and_add appear to be
+ undefined. Use full barrier for now, as that's safe. */
+#define atomic_exchange_and_add(mem, value) \
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, __MB, __MB)
+
+
+/* ??? Blah, I'm lazy. Implement these later. Can do better than the
+ compare-and-exchange loop provided by generic code.
+
+#define atomic_decrement_if_positive(mem)
+#define atomic_bit_test_set(mem, bit)
+
+*/
+
+#ifndef UP
+# define atomic_full_barrier() __asm ("mb" : : : "memory");
+# define atomic_read_barrier() __asm ("mb" : : : "memory");
+# define atomic_write_barrier() __asm ("wmb" : : : "memory");
+#endif
diff --git a/libc/sysdeps/linux/common/bits/atomic.h b/libc/sysdeps/linux/common/bits/atomic.h
new file mode 100644
index 000000000..6245130a9
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/atomic.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+/* We have by default no support for atomic operations. So define
+ them non-atomic. If this is a problem somebody will have to come
+ up with real definitions. */
+
+/* The only basic operation needed is compare and exchange. */
+#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+ ({ __typeof (mem) __gmemp = (mem); \
+ __typeof (*mem) __gret = *__gmemp; \
+ __typeof (*mem) __gnewval = (newval); \
+ \
+ if (__gret == (oldval)) \
+ *__gmemp = __gnewval; \
+ __gret; })
+
+#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+ ({ __typeof (mem) __gmemp = (mem); \
+ __typeof (*mem) __gnewval = (newval); \
+ \
+ *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })
+
+#endif /* bits/atomic.h */
diff --git a/libc/sysdeps/linux/i386/bits/atomic.h b/libc/sysdeps/linux/i386/bits/atomic.h
new file mode 100644
index 000000000..c74876175
--- /dev/null
+++ b/libc/sysdeps/linux/i386/bits/atomic.h
@@ -0,0 +1,366 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+# define LOCK_PREFIX /* nothing */
+# else
+# define LOCK_PREFIX "lock;"
+# endif
+#endif
+
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgb %b2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "q" (newval), "m" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgw %w2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" (newval), "m" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgl %2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" (newval), "m" (*mem), "0" (oldval)); \
+ ret; })
+
+/* XXX We do not really need 64-bit compare-and-exchange. At least
+ not in the moment. Using it would mean causing portability
+ problems since not many other 32-bit architectures have support for
+ such an operation. So don't define any code for now. If it is
+ really going to be used the code below can be used on Intel Pentium
+ and later, but NOT on i486. */
+#if 1
+# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret = *(mem); abort (); ret = (newval); ret = (oldval); })
+#else
+# ifdef __PIC__
+# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile ("xchgl %2, %%ebx\n\t" \
+ LOCK_PREFIX "cmpxchg8b %1\n\t" \
+ "xchgl %2, %%ebx" \
+ : "=A" (ret), "=m" (*mem) \
+ : "DS" (((unsigned long long int) (newval)) \
+ & 0xffffffff), \
+ "c" (((unsigned long long int) (newval)) >> 32), \
+ "m" (*mem), "a" (((unsigned long long int) (oldval)) \
+ & 0xffffffff), \
+ "d" (((unsigned long long int) (oldval)) >> 32)); \
+ ret; })
+# else
+# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchg8b %1" \
+ : "=A" (ret), "=m" (*mem) \
+ : "b" (((unsigned long long int) (newval)) \
+ & 0xffffffff), \
+ "c" (((unsigned long long int) (newval)) >> 32), \
+ "m" (*mem), "a" (((unsigned long long int) (oldval)) \
+ & 0xffffffff), \
+ "d" (((unsigned long long int) (oldval)) >> 32)); \
+ ret; })
+# endif
+#endif
+
+
+/* Note that we need no lock prefix. */
+#define atomic_exchange_acq(mem, newvalue) \
+ ({ __typeof (*mem) result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile ("xchgb %b0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (newvalue), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile ("xchgw %w0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (newvalue), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile ("xchgl %0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (newvalue), "m" (*mem)); \
+ else \
+ { \
+ result = 0; \
+ abort (); \
+ } \
+ result; })
+
+
+#define atomic_exchange_and_add(mem, value) \
+ ({ __typeof (*mem) __result; \
+ __typeof (value) __addval = (value); \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "xaddb %b0, %1" \
+ : "=r" (__result), "=m" (*mem) \
+ : "0" (__addval), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "xaddw %w0, %1" \
+ : "=r" (__result), "=m" (*mem) \
+ : "0" (__addval), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "xaddl %0, %1" \
+ : "=r" (__result), "=m" (*mem) \
+ : "0" (__addval), "m" (*mem)); \
+ else \
+ { \
+ __typeof (mem) __memp = (mem); \
+ __typeof (*mem) __tmpval; \
+ __result = *__memp; \
+ do \
+ __tmpval = __result; \
+ while ((__result = __arch_compare_and_exchange_val_64_acq \
+ (__memp, __result + __addval, __result)) == __tmpval); \
+ } \
+ __result; })
+
+
+#define atomic_add(mem, value) \
+ (void) ({ if (__builtin_constant_p (value) && (value) == 1) \
+ atomic_increment (mem); \
+ else if (__builtin_constant_p (value) && (value) == -1) \
+ atomic_decrement (mem); \
+ else if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "addb %b1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "addw %w1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "addl %1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "m" (*mem)); \
+ else \
+ { \
+ __typeof (value) __addval = (value); \
+ __typeof (mem) __memp = (mem); \
+ __typeof (*mem) __oldval = *__memp; \
+ __typeof (*mem) __tmpval; \
+ do \
+ __tmpval = __oldval; \
+ while ((__oldval = __arch_compare_and_exchange_val_64_acq \
+ (__memp, __oldval + __addval, __oldval)) == __tmpval); \
+ } \
+ })
+
+
+#define atomic_add_negative(mem, value) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "iq" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_add_zero(mem, value) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_increment(mem) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "incb %b0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "incw %w0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "incl %0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else \
+ { \
+ __typeof (mem) __memp = (mem); \
+ __typeof (*mem) __oldval = *__memp; \
+ __typeof (*mem) __tmpval; \
+ do \
+ __tmpval = __oldval; \
+ while ((__oldval = __arch_compare_and_exchange_val_64_acq \
+ (__memp, __oldval + 1, __oldval)) == __tmpval); \
+ } \
+ })
+
+
+#define atomic_increment_and_test(mem) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "incb %0; sete %b1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "incw %0; sete %w1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "incl %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_decrement(mem) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "decb %b0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "decw %w0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "decl %0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else \
+ { \
+ __typeof (mem) __memp = (mem); \
+ __typeof (*mem) __oldval = *__memp; \
+ __typeof (*mem) __tmpval; \
+ do \
+ __tmpval = __oldval; \
+ while ((__oldval = __arch_compare_and_exchange_val_64_acq \
+ (__memp, __oldval - 1, __oldval)) == __tmpval); \
+ } \
+ })
+
+
+#define atomic_decrement_and_test(mem) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "decb %b0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "decw %w0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "decl %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_bit_set(mem, bit) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "orb %b2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "ir" (1 << (bit))); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "orw %w2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "ir" (1 << (bit))); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "orl %2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "ir" (1 << (bit))); \
+ else \
+ abort (); \
+ })
+
+
+#define atomic_bit_test_set(mem, bit) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_delay() asm ("rep; nop")
diff --git a/libc/sysdeps/linux/mips/bits/atomic.h b/libc/sysdeps/linux/mips/bits/atomic.h
new file mode 100644
index 000000000..167d9a59c
--- /dev/null
+++ b/libc/sysdeps/linux/mips/bits/atomic.h
@@ -0,0 +1,303 @@
+/* Low-level functions for atomic operations. Mips version.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _MIPS_BITS_ATOMIC_H
+#define _MIPS_BITS_ATOMIC_H 1
+
+#include <inttypes.h>
+#include <sgidefs.h>
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+#if _MIPS_SIM == _ABIO32
+#define MIPS_PUSH_MIPS2 ".set mips2\n\t"
+#else
+#define MIPS_PUSH_MIPS2
+#endif
+
+/* See the comments in <sys/asm.h> about the use of the sync instruction. */
+#ifndef MIPS_SYNC
+# define MIPS_SYNC sync
+#endif
+
+#define MIPS_SYNC_STR_2(X) #X
+#define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
+#define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
+
+/* Compare and exchange. For all of the "xxx" routines, we expect a
+ "__prev" and a "__cmp" variable to be provided by the enclosing scope,
+ in which values are returned. */
+
+#define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
+ (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
+ (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
+ __asm__ __volatile__ ( \
+ ".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ rel "\n" \
+ "1:\t" \
+ "ll %0,%4\n\t" \
+ "move %1,$0\n\t" \
+ "bne %0,%2,2f\n\t" \
+ "move %1,%3\n\t" \
+ "sc %1,%4\n\t" \
+ "beqz %1,1b\n" \
+ acq "\n\t" \
+ ".set pop\n" \
+ "2:\n\t" \
+ : "=&r" (__prev), "=&r" (__cmp) \
+ : "r" (oldval), "r" (newval), "m" (*mem) \
+ : "memory")
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32. */
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+ (abort (), __prev = __cmp = 0)
+#else
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+ __asm__ __volatile__ ("\n" \
+ ".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ rel "\n" \
+ "1:\t" \
+ "lld %0,%4\n\t" \
+ "move %1,$0\n\t" \
+ "bne %0,%2,2f\n\t" \
+ "move %1,%3\n\t" \
+ "scd %1,%4\n\t" \
+ "beqz %1,1b\n" \
+ acq "\n\t" \
+ ".set pop\n" \
+ "2:\n\t" \
+ : "=&r" (__prev), "=&r" (__cmp) \
+ : "r" (oldval), "r" (newval), "m" (*mem) \
+ : "memory")
+#endif
+
+/* For all "bool" routines, we return FALSE if exchange succesful. */
+
+#define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq); \
+ !__cmp; })
+
+#define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq); \
+ !__cmp; })
+
+#define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq); \
+ !__cmp; })
+
+#define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq); \
+ !__cmp; })
+
+/* For all "val" routines, return the old value whether exchange
+ successful or not. */
+
+#define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq); \
+ (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq); \
+ (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq); \
+ (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq); \
+ (typeof (*mem))__prev; })
+
+/* Compare and exchange with "acquire" semantics, ie barrier after. */
+
+#define atomic_compare_and_exchange_bool_acq(mem, new, old) \
+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+ mem, new, old, "", MIPS_SYNC_STR)
+
+#define atomic_compare_and_exchange_val_acq(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, "", MIPS_SYNC_STR)
+
+/* Compare and exchange with "release" semantics, ie barrier before. */
+
+#define atomic_compare_and_exchange_bool_rel(mem, new, old) \
+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+ mem, new, old, MIPS_SYNC_STR, "")
+
+#define atomic_compare_and_exchange_val_rel(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, MIPS_SYNC_STR, "")
+
+
+
+/* Atomic exchange (without compare). */
+
+#define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
+ (abort (), 0)
+
+#define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
+ (abort (), 0)
+
+#define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __asm__ __volatile__ ("\n" \
+ ".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ rel "\n" \
+ "1:\t" \
+ "ll %0,%3\n\t" \
+ "move %1,%2\n\t" \
+ "sc %1,%3\n\t" \
+ "beqz %1,1b\n" \
+ acq "\n\t" \
+ ".set pop\n" \
+ "2:\n\t" \
+ : "=&r" (__prev), "=&r" (__cmp) \
+ : "r" (newval), "m" (*mem) \
+ : "memory"); \
+ __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32. */
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+ (abort (), 0)
+#else
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __asm__ __volatile__ ("\n" \
+ ".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ rel "\n" \
+ "1:\n" \
+ "lld %0,%3\n\t" \
+ "move %1,%2\n\t" \
+ "scd %1,%3\n\t" \
+ "beqz %1,1b\n" \
+ acq "\n\t" \
+ ".set pop\n" \
+ "2:\n\t" \
+ : "=&r" (__prev), "=&r" (__cmp) \
+ : "r" (newval), "m" (*mem) \
+ : "memory"); \
+ __prev; })
+#endif
+
+#define atomic_exchange_acq(mem, value) \
+ __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
+
+#define atomic_exchange_rel(mem, value) \
+ __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
+
+
+/* Atomically add value and return the previous (unincremented) value. */
+
+#define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
+ (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
+ (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __asm__ __volatile__ ("\n" \
+ ".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ rel "\n" \
+ "1:\t" \
+ "ll %0,%3\n\t" \
+ "addu %1,%0,%2\n\t" \
+ "sc %1,%3\n\t" \
+ "beqz %1,1b\n" \
+ acq "\n\t" \
+ ".set pop\n" \
+ "2:\n\t" \
+ : "=&r" (__prev), "=&r" (__cmp) \
+ : "r" (value), "m" (*mem) \
+ : "memory"); \
+ __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32. */
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+ (abort (), (typeof(*mem)) 0)
+#else
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp; \
+ __asm__ __volatile__ ( \
+ ".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ rel "\n" \
+ "1:\t" \
+ "lld %0,%3\n\t" \
+ "daddu %1,%0,%2\n\t" \
+ "scd %1,%3\n\t" \
+ "beqz %1,1b\n" \
+ acq "\n\t" \
+ ".set pop\n" \
+ "2:\n\t" \
+ : "=&r" (__prev), "=&r" (__cmp) \
+ : "r" (value), "m" (*mem) \
+ : "memory"); \
+ __prev; })
+#endif
+
+/* ??? Barrier semantics for atomic_exchange_and_add appear to be
+ undefined. Use full barrier for now, as that's safe. */
+#define atomic_exchange_and_add(mem, value) \
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
+ MIPS_SYNC_STR, MIPS_SYNC_STR)
+
+/* TODO: More atomic operations could be implemented efficiently; only the
+ basic requirements are done. */
+
+#define atomic_full_barrier() \
+ __asm__ __volatile__ (".set push\n\t" \
+ MIPS_PUSH_MIPS2 \
+ MIPS_SYNC_STR "\n\t" \
+ ".set pop" : : : "memory")
+
+#endif /* bits/atomic.h */
diff --git a/libc/sysdeps/linux/sh/bits/atomic.h b/libc/sysdeps/linux/sh/bits/atomic.h
new file mode 100644
index 000000000..a0e5918f0
--- /dev/null
+++ b/libc/sysdeps/linux/sh/bits/atomic.h
@@ -0,0 +1,419 @@
+/* Atomic operations used inside libc. Linux/SH version.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* SH kernel has implemented a gUSA ("g" User Space Atomicity) support
+ for the user space atomicity. The atomicity macros use this scheme.
+
+ Reference:
+ Niibe Yutaka, "gUSA: Simple and Efficient User Space Atomicity
+ Emulation with Little Kernel Modification", Linux Conference 2002,
+ Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in
+ Japanese).
+
+ B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for
+ Uniprocessors", Proceedings of the Fifth Architectural Support for
+ Programming Languages and Operating Systems (ASPLOS), pp. 223-233,
+ October 1992. http://www.cs.washington.edu/homes/bershad/Papers/Rcs.ps
+
+ SuperH ABI:
+ r15: -(size of atomic instruction sequence) < 0
+ r0: end point
+ r1: saved stack pointer
+*/
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+ ({ __typeof (*(mem)) __result; \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.b @%1,%0\n\
+ cmp/eq %0,%3\n\
+ bf 1f\n\
+ mov.b %2,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
+ : "r0", "r1", "t", "memory"); \
+ __result; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+ ({ __typeof (*(mem)) __result; \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.w @%1,%0\n\
+ cmp/eq %0,%3\n\
+ bf 1f\n\
+ mov.w %2,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
+ : "r0", "r1", "t", "memory"); \
+ __result; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+ ({ __typeof (*(mem)) __result; \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.l @%1,%0\n\
+ cmp/eq %0,%3\n\
+ bf 1f\n\
+ mov.l %2,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
+ : "r0", "r1", "t", "memory"); \
+ __result; })
+
+/* XXX We do not really need 64-bit compare-and-exchange. At least
+ not in the moment. Using it would mean causing portability
+ problems since not many other 32-bit architectures have support for
+ such an operation. So don't define any code for now. */
+
+# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+ (abort (), (__typeof (*mem)) 0)
+
+#define atomic_exchange_and_add(mem, value) \
+ ({ __typeof (*(mem)) __result, __tmp, __value = (value); \
+ if (sizeof (*(mem)) == 1) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.b @%2,%0\n\
+ add %0,%1\n\
+ mov.b %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "memory"); \
+ else if (sizeof (*(mem)) == 2) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.w @%2,%0\n\
+ add %0,%1\n\
+ mov.w %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "memory"); \
+ else if (sizeof (*(mem)) == 4) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%2,%0\n\
+ add %0,%1\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "memory"); \
+ else \
+ { \
+ __typeof (mem) memp = (mem); \
+ do \
+ __result = *memp; \
+ while (__arch_compare_and_exchange_val_64_acq \
+ (memp, __result + __value, __result) == __result); \
+ (void) __value; \
+ } \
+ __result; })
+
+#define atomic_add(mem, value) \
+ (void) ({ __typeof (*(mem)) __tmp, __value = (value); \
+ if (sizeof (*(mem)) == 1) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.b @%1,r2\n\
+ add r2,%0\n\
+ mov.b %0,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__tmp) : "r" (mem), "0" (__value) \
+ : "r0", "r1", "r2", "memory"); \
+ else if (sizeof (*(mem)) == 2) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.w @%1,r2\n\
+ add r2,%0\n\
+ mov.w %0,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__tmp) : "r" (mem), "0" (__value) \
+ : "r0", "r1", "r2", "memory"); \
+ else if (sizeof (*(mem)) == 4) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%1,r2\n\
+ add r2,%0\n\
+ mov.l %0,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__tmp) : "r" (mem), "0" (__value) \
+ : "r0", "r1", "r2", "memory"); \
+ else \
+ { \
+ __typeof (*(mem)) oldval; \
+ __typeof (mem) memp = (mem); \
+ do \
+ oldval = *memp; \
+ while (__arch_compare_and_exchange_val_64_acq \
+ (memp, oldval + __value, oldval) == oldval); \
+ (void) __value; \
+ } \
+ })
+
+#define atomic_add_negative(mem, value) \
+ ({ unsigned char __result; \
+ __typeof (*(mem)) __tmp, __value = (value); \
+ if (sizeof (*(mem)) == 1) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.b @%2,r2\n\
+ add r2,%1\n\
+ mov.b %1,@%2\n\
+ 1: mov r1,r15\n\
+ shal %1\n\
+ movt %0"\
+ : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ else if (sizeof (*(mem)) == 2) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.w @%2,r2\n\
+ add r2,%1\n\
+ mov.w %1,@%2\n\
+ 1: mov r1,r15\n\
+ shal %1\n\
+ movt %0"\
+ : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ else if (sizeof (*(mem)) == 4) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%2,r2\n\
+ add r2,%1\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15\n\
+ shal %1\n\
+ movt %0"\
+ : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ else \
+ abort (); \
+ __result; })
+
+#define atomic_add_zero(mem, value) \
+ ({ unsigned char __result; \
+ __typeof (*(mem)) __tmp, __value = (value); \
+ if (sizeof (*(mem)) == 1) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.b @%2,r2\n\
+ add r2,%1\n\
+ mov.b %1,@%2\n\
+ 1: mov r1,r15\n\
+ tst %1,%1\n\
+ movt %0"\
+ : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ else if (sizeof (*(mem)) == 2) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.w @%2,r2\n\
+ add r2,%1\n\
+ mov.w %1,@%2\n\
+ 1: mov r1,r15\n\
+ tst %1,%1\n\
+ movt %0"\
+ : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ else if (sizeof (*(mem)) == 4) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%2,r2\n\
+ add r2,%1\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15\n\
+ tst %1,%1\n\
+ movt %0"\
+ : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ else \
+ abort (); \
+ __result; })
+
+#define atomic_increment_and_test(mem) atomic_add_zero((mem), 1)
+#define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1)
+
+#define atomic_bit_set(mem, bit) \
+ (void) ({ unsigned int __mask = 1 << (bit); \
+ if (sizeof (*(mem)) == 1) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.b @%0,r2\n\
+ or %1,r2\n\
+ mov.b r2,@%0\n\
+ 1: mov r1,r15"\
+ : : "r" (mem), "r" (__mask) \
+ : "r0", "r1", "r2", "memory"); \
+ else if (sizeof (*(mem)) == 2) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.w @%0,r2\n\
+ or %1,r2\n\
+ mov.w r2,@%0\n\
+ 1: mov r1,r15"\
+ : : "r" (mem), "r" (__mask) \
+ : "r0", "r1", "r2", "memory"); \
+ else if (sizeof (*(mem)) == 4) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%0,r2\n\
+ or %1,r2\n\
+ mov.l r2,@%0\n\
+ 1: mov r1,r15"\
+ : : "r" (mem), "r" (__mask) \
+ : "r0", "r1", "r2", "memory"); \
+ else \
+ abort (); \
+ })
+
+#define atomic_bit_test_set(mem, bit) \
+ ({ unsigned int __mask = 1 << (bit); \
+ unsigned int __result = __mask; \
+ if (sizeof (*(mem)) == 1) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.b @%2,r2\n\
+ or r2,%1\n\
+ and r2,%0\n\
+ mov.b %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result), "=&r" (__mask) \
+ : "r" (mem), "0" (__result), "1" (__mask) \
+ : "r0", "r1", "r2", "memory"); \
+ else if (sizeof (*(mem)) == 2) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.w @%2,r2\n\
+ or r2,%1\n\
+ and r2,%0\n\
+ mov.w %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result), "=&r" (__mask) \
+ : "r" (mem), "0" (__result), "1" (__mask) \
+ : "r0", "r1", "r2", "memory"); \
+ else if (sizeof (*(mem)) == 4) \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.l @%2,r2\n\
+ or r2,%1\n\
+ and r2,%0\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result), "=&r" (__mask) \
+ : "r" (mem), "0" (__result), "1" (__mask) \
+ : "r0", "r1", "r2", "memory"); \
+ else \
+ abort (); \
+ __result; })
diff --git a/libc/sysdeps/linux/x86_64/bits/atomic.h b/libc/sysdeps/linux/x86_64/bits/atomic.h
new file mode 100644
index 000000000..133a68d19
--- /dev/null
+++ b/libc/sysdeps/linux/x86_64/bits/atomic.h
@@ -0,0 +1,324 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+# define LOCK_PREFIX /* nothing */
+# else
+# define LOCK_PREFIX "lock;"
+# endif
+#endif
+
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgb %b2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "q" (newval), "m" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgw %w2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" (newval), "m" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgl %2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" (newval), "m" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+ ({ __typeof (*mem) ret; \
+ __asm __volatile (LOCK_PREFIX "cmpxchgq %q2, %1" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" ((long) (newval)), "m" (*mem), \
+ "0" ((long) (oldval))); \
+ ret; })
+
+
+/* Note that we need no lock prefix. */
+#define atomic_exchange_acq(mem, newvalue) \
+ ({ __typeof (*mem) result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile ("xchgb %b0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (newvalue), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile ("xchgw %w0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (newvalue), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile ("xchgl %0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (newvalue), "m" (*mem)); \
+ else \
+ __asm __volatile ("xchgq %q0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" ((long) (newvalue)), "m" (*mem)); \
+ result; })
+
+
+#define atomic_exchange_and_add(mem, value) \
+ ({ __typeof (*mem) result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "xaddb %b0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "xaddw %w0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "xaddl %0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (value), "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "xaddq %q0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" ((long) (value)), "m" (*mem)); \
+ result; })
+
+
+#define atomic_add(mem, value) \
+ (void) ({ if (__builtin_constant_p (value) && (value) == 1) \
+ atomic_increment (mem); \
+ else if (__builtin_constant_p (value) && (value) == 1) \
+ atomic_decrement (mem); \
+ else if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "addb %b1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "addw %w1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "addl %1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "addq %q1, %0" \
+ : "=m" (*mem) \
+ : "ir" ((long) (value)), "m" (*mem)); \
+ })
+
+
+#define atomic_add_negative(mem, value) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "addq %q2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" ((long) (value)), "m" (*mem)); \
+ __result; })
+
+
+#define atomic_add_zero(mem, value) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "addq %q2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" ((long) (value)), "m" (*mem)); \
+ __result; })
+
+
+#define atomic_increment(mem) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "incb %b0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "incw %w0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "incl %0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "incq %q0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ })
+
+
+#define atomic_increment_and_test(mem) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "incb %b0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "incw %w0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "incl %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "incq %q0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ __result; })
+
+
+#define atomic_decrement(mem) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "decb %b0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "decw %w0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "decl %0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "decq %q0" \
+ : "=m" (*mem) \
+ : "m" (*mem)); \
+ })
+
+
+#define atomic_decrement_and_test(mem) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "decb %b0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "decw %w0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "decl %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "decq %q0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "m" (*mem)); \
+ __result; })
+
+
+#define atomic_bit_set(mem, bit) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "orb %b2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "ir" (1L << (bit))); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "orw %w2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "ir" (1L << (bit))); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "orl %2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "ir" (1L << (bit))); \
+ else if (__builtin_constant_p (bit) && (bit) < 32) \
+ __asm __volatile (LOCK_PREFIX "orq %2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "i" (1L << (bit))); \
+ else \
+ __asm __volatile (LOCK_PREFIX "orq %q2, %0" \
+ : "=m" (*mem) \
+ : "m" (*mem), "r" (1UL << (bit))); \
+ })
+
+
+#define atomic_bit_test_set(mem, bit) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ else \
+ __asm __volatile (LOCK_PREFIX "btsq %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "m" (*mem), "ir" (bit)); \
+ __result; })
+
+
+#define atomic_delay() asm ("rep; nop")