Blame sysdeps/i386/atomic-machine.h

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <tls.h>	/* For tcbhead_t.  */
Packit 6c4009
Packit 6c4009
Packit 6c4009
typedef int8_t atomic8_t;
Packit 6c4009
typedef uint8_t uatomic8_t;
Packit 6c4009
typedef int_fast8_t atomic_fast8_t;
Packit 6c4009
typedef uint_fast8_t uatomic_fast8_t;
Packit 6c4009
Packit 6c4009
typedef int16_t atomic16_t;
Packit 6c4009
typedef uint16_t uatomic16_t;
Packit 6c4009
typedef int_fast16_t atomic_fast16_t;
Packit 6c4009
typedef uint_fast16_t uatomic_fast16_t;
Packit 6c4009
Packit 6c4009
typedef int32_t atomic32_t;
Packit 6c4009
typedef uint32_t uatomic32_t;
Packit 6c4009
typedef int_fast32_t atomic_fast32_t;
Packit 6c4009
typedef uint_fast32_t uatomic_fast32_t;
Packit 6c4009
Packit 6c4009
typedef int64_t atomic64_t;
Packit 6c4009
typedef uint64_t uatomic64_t;
Packit 6c4009
typedef int_fast64_t atomic_fast64_t;
Packit 6c4009
typedef uint_fast64_t uatomic_fast64_t;
Packit 6c4009
Packit 6c4009
typedef intptr_t atomicptr_t;
Packit 6c4009
typedef uintptr_t uatomicptr_t;
Packit 6c4009
typedef intmax_t atomic_max_t;
Packit 6c4009
typedef uintmax_t uatomic_max_t;
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifndef LOCK_PREFIX
Packit 6c4009
# ifdef UP
Packit 6c4009
#  define LOCK_PREFIX	/* nothing */
Packit 6c4009
# else
Packit 6c4009
#  define LOCK_PREFIX "lock;"
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define __HAVE_64B_ATOMICS 0
Packit 6c4009
#define USE_ATOMIC_COMPILER_BUILTINS 0
Packit 6c4009
#define ATOMIC_EXCHANGE_USES_CAS 0
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
Packit 6c4009
  __sync_val_compare_and_swap (mem, oldval, newval)
Packit 6c4009
#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
Packit 6c4009
  (! __sync_bool_compare_and_swap (mem, oldval, newval))
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_c_compare_and_exchange_val_8_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile ("cmpl $0, %%gs:%P5\n\t"                                \
Packit 6c4009
                       "je 0f\n\t"                                            \
Packit 6c4009
                       "lock\n"                                               \
Packit 6c4009
                       "0:\tcmpxchgb %b2, %1"				      \
Packit 6c4009
		       : "=a" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "q" (newval), "m" (*mem), "0" (oldval),	      \
Packit 6c4009
			 "i" (offsetof (tcbhead_t, multiple_threads)));	      \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
#define __arch_c_compare_and_exchange_val_16_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile ("cmpl $0, %%gs:%P5\n\t"                                \
Packit 6c4009
                       "je 0f\n\t"                                            \
Packit 6c4009
                       "lock\n"                                               \
Packit 6c4009
                       "0:\tcmpxchgw %w2, %1"				      \
Packit 6c4009
		       : "=a" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "r" (newval), "m" (*mem), "0" (oldval),	      \
Packit 6c4009
			 "i" (offsetof (tcbhead_t, multiple_threads)));	      \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
#define __arch_c_compare_and_exchange_val_32_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile ("cmpl $0, %%gs:%P5\n\t"                                \
Packit 6c4009
                       "je 0f\n\t"                                            \
Packit 6c4009
                       "lock\n"                                               \
Packit 6c4009
                       "0:\tcmpxchgl %2, %1"				      \
Packit 6c4009
		       : "=a" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "r" (newval), "m" (*mem), "0" (oldval),	      \
Packit 6c4009
			 "i" (offsetof (tcbhead_t, multiple_threads)));	      \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
/* XXX We do not really need 64-bit compare-and-exchange.  At least
Packit 6c4009
   not in the moment.  Using it would mean causing portability
Packit 6c4009
   problems since not many other 32-bit architectures have support for
Packit 6c4009
   such an operation.  So don't define any code for now.  If it is
Packit 6c4009
   really going to be used the code below can be used on Intel Pentium
Packit 6c4009
   and later, but NOT on i486.  */
Packit 6c4009
#if 1
Packit 6c4009
# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval)	      \
Packit 6c4009
  ({ __typeof (*mem) ret = *(mem);					      \
Packit 6c4009
     abort ();								      \
Packit 6c4009
     ret = (newval);							      \
Packit 6c4009
     ret = (oldval);							      \
Packit 6c4009
     ret; })
Packit 6c4009
# define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval)	      \
Packit 6c4009
  ({ __typeof (*mem) ret = *(mem);					      \
Packit 6c4009
     abort ();								      \
Packit 6c4009
     ret = (newval);							      \
Packit 6c4009
     ret = (oldval);							      \
Packit 6c4009
     ret; })
Packit 6c4009
#else
Packit 6c4009
# ifdef __PIC__
Packit 6c4009
#  define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile ("xchgl %2, %%ebx\n\t"				      \
Packit 6c4009
		       LOCK_PREFIX "cmpxchg8b %1\n\t"			      \
Packit 6c4009
		       "xchgl %2, %%ebx"				      \
Packit 6c4009
		       : "=A" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "DS" (((unsigned long long int) (newval))	      \
Packit 6c4009
			       & 0xffffffff),				      \
Packit 6c4009
			 "c" (((unsigned long long int) (newval)) >> 32),     \
Packit 6c4009
			 "m" (*mem), "a" (((unsigned long long int) (oldval)) \
Packit 6c4009
					  & 0xffffffff),		      \
Packit 6c4009
			 "d" (((unsigned long long int) (oldval)) >> 32));    \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
#  define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile ("xchgl %2, %%ebx\n\t"				      \
Packit 6c4009
		       "cmpl $0, %%gs:%P7\n\t"				      \
Packit 6c4009
		       "je 0f\n\t"					      \
Packit 6c4009
		       "lock\n"						      \
Packit 6c4009
		       "0:\tcmpxchg8b %1\n\t"				      \
Packit 6c4009
		       "xchgl %2, %%ebx"				      \
Packit 6c4009
		       : "=A" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "DS" (((unsigned long long int) (newval))	      \
Packit 6c4009
			       & 0xffffffff),				      \
Packit 6c4009
			 "c" (((unsigned long long int) (newval)) >> 32),     \
Packit 6c4009
			 "m" (*mem), "a" (((unsigned long long int) (oldval)) \
Packit 6c4009
					  & 0xffffffff),		      \
Packit 6c4009
			 "d" (((unsigned long long int) (oldval)) >> 32),     \
Packit 6c4009
			 "i" (offsetof (tcbhead_t, multiple_threads)));	      \
Packit 6c4009
     ret; })
Packit 6c4009
# else
Packit 6c4009
#  define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile (LOCK_PREFIX "cmpxchg8b %1"			      \
Packit 6c4009
		       : "=A" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "b" (((unsigned long long int) (newval))	      \
Packit 6c4009
			      & 0xffffffff),				      \
Packit 6c4009
			 "c" (((unsigned long long int) (newval)) >> 32),     \
Packit 6c4009
			 "m" (*mem), "a" (((unsigned long long int) (oldval)) \
Packit 6c4009
					  & 0xffffffff),		      \
Packit 6c4009
			 "d" (((unsigned long long int) (oldval)) >> 32));    \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
#  define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (*mem) ret;						      \
Packit 6c4009
     __asm __volatile ("cmpl $0, %%gs:%P7\n\t"				      \
Packit 6c4009
		       "je 0f\n\t"					      \
Packit 6c4009
		       "lock\n"						      \
Packit 6c4009
		       "0:\tcmpxchg8b %1"				      \
Packit 6c4009
		       : "=A" (ret), "=m" (*mem)			      \
Packit 6c4009
		       : "b" (((unsigned long long int) (newval))	      \
Packit 6c4009
			      & 0xffffffff),				      \
Packit 6c4009
			 "c" (((unsigned long long int) (newval)) >> 32),     \
Packit 6c4009
			 "m" (*mem), "a" (((unsigned long long int) (oldval)) \
Packit 6c4009
					  & 0xffffffff),		      \
Packit 6c4009
			 "d" (((unsigned long long int) (oldval)) >> 32),     \
Packit 6c4009
			 "i" (offsetof (tcbhead_t, multiple_threads)));	      \
Packit 6c4009
     ret; })
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Note that we need no lock prefix.  */
Packit 6c4009
#define atomic_exchange_acq(mem, newvalue) \
Packit 6c4009
  ({ __typeof (*mem) result;						      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile ("xchgb %b0, %1"				      \
Packit 6c4009
			 : "=q" (result), "=m" (*mem)			      \
Packit 6c4009
			 : "0" (newvalue), "m" (*mem));			      \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile ("xchgw %w0, %1"				      \
Packit 6c4009
			 : "=r" (result), "=m" (*mem)			      \
Packit 6c4009
			 : "0" (newvalue), "m" (*mem));			      \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile ("xchgl %0, %1"					      \
Packit 6c4009
			 : "=r" (result), "=m" (*mem)			      \
Packit 6c4009
			 : "0" (newvalue), "m" (*mem));			      \
Packit 6c4009
     else								      \
Packit 6c4009
       {								      \
Packit 6c4009
	 result = 0;							      \
Packit 6c4009
	 abort ();							      \
Packit 6c4009
       }								      \
Packit 6c4009
     result; })
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_exchange_and_add_body(lock, pfx, mem, value) \
Packit 6c4009
  ({ __typeof (*mem) __result;						      \
Packit 6c4009
     __typeof (value) __addval = (value);				      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile (lock "xaddb %b0, %1"				      \
Packit 6c4009
			 : "=q" (__result), "=m" (*mem)			      \
Packit 6c4009
			 : "0" (__addval), "m" (*mem),			      \
Packit 6c4009
			   "i" (offsetof (tcbhead_t, multiple_threads)));     \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile (lock "xaddw %w0, %1"				      \
Packit 6c4009
			 : "=r" (__result), "=m" (*mem)			      \
Packit 6c4009
			 : "0" (__addval), "m" (*mem),			      \
Packit 6c4009
			   "i" (offsetof (tcbhead_t, multiple_threads)));     \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile (lock "xaddl %0, %1"				      \
Packit 6c4009
			 : "=r" (__result), "=m" (*mem)			      \
Packit 6c4009
			 : "0" (__addval), "m" (*mem),			      \
Packit 6c4009
			   "i" (offsetof (tcbhead_t, multiple_threads)));     \
Packit 6c4009
     else								      \
Packit 6c4009
       {								      \
Packit 6c4009
	 __typeof (mem) __memp = (mem);					      \
Packit 6c4009
	 __typeof (*mem) __tmpval;					      \
Packit 6c4009
	 __result = *__memp;						      \
Packit 6c4009
	 do								      \
Packit 6c4009
	   __tmpval = __result;						      \
Packit 6c4009
	 while ((__result = pfx##_compare_and_exchange_val_64_acq	      \
Packit 6c4009
		 (__memp, __result + __addval, __result)) == __tmpval);	      \
Packit 6c4009
       }								      \
Packit 6c4009
     __result; })
Packit 6c4009
Packit 6c4009
#define atomic_exchange_and_add(mem, value) \
Packit 6c4009
  __sync_fetch_and_add (mem, value)
Packit 6c4009
Packit 6c4009
#define __arch_exchange_and_add_cprefix \
Packit 6c4009
  "cmpl $0, %%gs:%P4\n\tje 0f\n\tlock\n0:\t"
Packit 6c4009
Packit 6c4009
#define catomic_exchange_and_add(mem, value) \
Packit 6c4009
  __arch_exchange_and_add_body (__arch_exchange_and_add_cprefix, __arch_c,    \
Packit 6c4009
				mem, value)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_add_body(lock, pfx, mem, value) \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (__builtin_constant_p (value) && (value) == 1)			      \
Packit 6c4009
      atomic_increment (mem);						      \
Packit 6c4009
    else if (__builtin_constant_p (value) && (value) == -1)		      \
Packit 6c4009
      atomic_decrement (mem);						      \
Packit 6c4009
    else if (sizeof (*mem) == 1)					      \
Packit 6c4009
      __asm __volatile (lock "addb %b1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "iq" (value), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 2)					      \
Packit 6c4009
      __asm __volatile (lock "addw %w1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "ir" (value), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 4)					      \
Packit 6c4009
      __asm __volatile (lock "addl %1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "ir" (value), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	__typeof (value) __addval = (value);				      \
Packit 6c4009
	__typeof (mem) __memp = (mem);					      \
Packit 6c4009
	__typeof (*mem) __oldval = *__memp;				      \
Packit 6c4009
	__typeof (*mem) __tmpval;					      \
Packit 6c4009
	do								      \
Packit 6c4009
	  __tmpval = __oldval;						      \
Packit 6c4009
	while ((__oldval = pfx##_compare_and_exchange_val_64_acq	      \
Packit 6c4009
		(__memp, __oldval + __addval, __oldval)) == __tmpval);	      \
Packit 6c4009
      }									      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define atomic_add(mem, value) \
Packit 6c4009
  __arch_add_body (LOCK_PREFIX, __arch, mem, value)
Packit 6c4009
Packit 6c4009
#define __arch_add_cprefix \
Packit 6c4009
  "cmpl $0, %%gs:%P3\n\tje 0f\n\tlock\n0:\t"
Packit 6c4009
Packit 6c4009
#define catomic_add(mem, value) \
Packit 6c4009
  __arch_add_body (__arch_add_cprefix, __arch_c, mem, value)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_add_negative(mem, value) \
Packit 6c4009
  ({ unsigned char __result;						      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "iq" (value), "m" (*mem));			      \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "ir" (value), "m" (*mem));			      \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "ir" (value), "m" (*mem));			      \
Packit 6c4009
     else								      \
Packit 6c4009
       abort ();							      \
Packit 6c4009
     __result; })
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_add_zero(mem, value) \
Packit 6c4009
  ({ unsigned char __result;						      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "iq" (value), "m" (*mem));			      \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "ir" (value), "m" (*mem));			      \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "ir" (value), "m" (*mem));			      \
Packit 6c4009
     else								      \
Packit 6c4009
       abort ();							      \
Packit 6c4009
     __result; })
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_increment_body(lock,  pfx, mem) \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (sizeof (*mem) == 1)						      \
Packit 6c4009
      __asm __volatile (lock "incb %b0"					      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem),					      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 2)					      \
Packit 6c4009
      __asm __volatile (lock "incw %w0"					      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem),					      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 4)					      \
Packit 6c4009
      __asm __volatile (lock "incl %0"					      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem),					      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	__typeof (mem) __memp = (mem);					      \
Packit 6c4009
	__typeof (*mem) __oldval = *__memp;				      \
Packit 6c4009
	__typeof (*mem) __tmpval;					      \
Packit 6c4009
	do								      \
Packit 6c4009
	  __tmpval = __oldval;						      \
Packit 6c4009
	while ((__oldval = pfx##_compare_and_exchange_val_64_acq	      \
Packit 6c4009
		(__memp, __oldval + 1, __oldval)) == __tmpval);		      \
Packit 6c4009
      }									      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define atomic_increment(mem) __arch_increment_body (LOCK_PREFIX, __arch, mem)
Packit 6c4009
Packit 6c4009
#define __arch_increment_cprefix \
Packit 6c4009
  "cmpl $0, %%gs:%P2\n\tje 0f\n\tlock\n0:\t"
Packit 6c4009
Packit 6c4009
#define catomic_increment(mem) \
Packit 6c4009
  __arch_increment_body (__arch_increment_cprefix, __arch_c, mem)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_increment_and_test(mem) \
Packit 6c4009
  ({ unsigned char __result;						      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "incb %0; sete %b1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "m" (*mem));					      \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "incw %0; sete %w1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "m" (*mem));					      \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "incl %0; sete %1"			      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "m" (*mem));					      \
Packit 6c4009
     else								      \
Packit 6c4009
       abort ();							      \
Packit 6c4009
     __result; })
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_decrement_body(lock, pfx, mem) \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (sizeof (*mem) == 1)						      \
Packit 6c4009
      __asm __volatile (lock "decb %b0"					      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem),					      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 2)					      \
Packit 6c4009
      __asm __volatile (lock "decw %w0"					      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem),					      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 4)					      \
Packit 6c4009
      __asm __volatile (lock "decl %0"					      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem),					      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	__typeof (mem) __memp = (mem);					      \
Packit 6c4009
	__typeof (*mem) __oldval = *__memp;				      \
Packit 6c4009
	__typeof (*mem) __tmpval;					      \
Packit 6c4009
	do								      \
Packit 6c4009
	  __tmpval = __oldval;						      \
Packit 6c4009
	while ((__oldval = pfx##_compare_and_exchange_val_64_acq	      \
Packit 6c4009
		(__memp, __oldval - 1, __oldval)) == __tmpval); 	      \
Packit 6c4009
      }									      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define atomic_decrement(mem) __arch_decrement_body (LOCK_PREFIX, __arch, mem)
Packit 6c4009
Packit 6c4009
#define __arch_decrement_cprefix \
Packit 6c4009
  "cmpl $0, %%gs:%P2\n\tje 0f\n\tlock\n0:\t"
Packit 6c4009
Packit 6c4009
#define catomic_decrement(mem) \
Packit 6c4009
  __arch_decrement_body (__arch_decrement_cprefix, __arch_c, mem)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_decrement_and_test(mem) \
Packit 6c4009
  ({ unsigned char __result;						      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "decb %b0; sete %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "m" (*mem));					      \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "decw %w0; sete %1"		      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "m" (*mem));					      \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "decl %0; sete %1"			      \
Packit 6c4009
			 : "=m" (*mem), "=qm" (__result)		      \
Packit 6c4009
			 : "m" (*mem));					      \
Packit 6c4009
     else								      \
Packit 6c4009
       abort ();							      \
Packit 6c4009
     __result; })
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_bit_set(mem, bit) \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (sizeof (*mem) == 1)						      \
Packit 6c4009
      __asm __volatile (LOCK_PREFIX "orb %b2, %0"			      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem), "iq" (1 << (bit)));		      \
Packit 6c4009
    else if (sizeof (*mem) == 2)					      \
Packit 6c4009
      __asm __volatile (LOCK_PREFIX "orw %w2, %0"			      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem), "ir" (1 << (bit)));		      \
Packit 6c4009
    else if (sizeof (*mem) == 4)					      \
Packit 6c4009
      __asm __volatile (LOCK_PREFIX "orl %2, %0"			      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "m" (*mem), "ir" (1 << (bit)));		      \
Packit 6c4009
    else								      \
Packit 6c4009
      abort ();								      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_bit_test_set(mem, bit) \
Packit 6c4009
  ({ unsigned char __result;						      \
Packit 6c4009
     if (sizeof (*mem) == 1)						      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0"		      \
Packit 6c4009
			 : "=q" (__result), "=m" (*mem)			      \
Packit 6c4009
			 : "m" (*mem), "ir" (bit));			      \
Packit 6c4009
     else if (sizeof (*mem) == 2)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0"		      \
Packit 6c4009
			 : "=q" (__result), "=m" (*mem)			      \
Packit 6c4009
			 : "m" (*mem), "ir" (bit));			      \
Packit 6c4009
     else if (sizeof (*mem) == 4)					      \
Packit 6c4009
       __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0"		      \
Packit 6c4009
			 : "=q" (__result), "=m" (*mem)			      \
Packit 6c4009
			 : "m" (*mem), "ir" (bit));			      \
Packit 6c4009
     else							      	      \
Packit 6c4009
       abort ();							      \
Packit 6c4009
     __result; })
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define atomic_spin_nop() asm ("rep; nop")
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_and_body(lock, mem, mask) \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (sizeof (*mem) == 1)						      \
Packit 6c4009
      __asm __volatile (lock "andb %b1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "iq" (mask), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 2)					      \
Packit 6c4009
      __asm __volatile (lock "andw %w1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "ir" (mask), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 4)					      \
Packit 6c4009
      __asm __volatile (lock "andl %1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "ir" (mask), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else								      \
Packit 6c4009
      abort ();								      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define __arch_cprefix \
Packit 6c4009
  "cmpl $0, %%gs:%P3\n\tje 0f\n\tlock\n0:\t"
Packit 6c4009
Packit 6c4009
#define atomic_and(mem, mask) __arch_and_body (LOCK_PREFIX, mem, mask)
Packit 6c4009
Packit 6c4009
#define catomic_and(mem, mask) __arch_and_body (__arch_cprefix, mem, mask)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define __arch_or_body(lock, mem, mask) \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (sizeof (*mem) == 1)						      \
Packit 6c4009
      __asm __volatile (lock "orb %b1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "iq" (mask), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 2)					      \
Packit 6c4009
      __asm __volatile (lock "orw %w1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "ir" (mask), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else if (sizeof (*mem) == 4)					      \
Packit 6c4009
      __asm __volatile (lock "orl %1, %0"				      \
Packit 6c4009
			: "=m" (*mem)					      \
Packit 6c4009
			: "ir" (mask), "m" (*mem),			      \
Packit 6c4009
			  "i" (offsetof (tcbhead_t, multiple_threads)));      \
Packit 6c4009
    else								      \
Packit 6c4009
      abort ();								      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define atomic_or(mem, mask) __arch_or_body (LOCK_PREFIX, mem, mask)
Packit 6c4009
Packit 6c4009
#define catomic_or(mem, mask) __arch_or_body (__arch_cprefix, mem, mask)
Packit 6c4009
Packit 6c4009
/* We don't use mfence because it is supposedly slower due to having to
Packit 6c4009
   provide stronger guarantees (e.g., regarding self-modifying code).  */
Packit 6c4009
#define atomic_full_barrier() \
Packit 6c4009
    __asm __volatile (LOCK_PREFIX "orl $0, (%%esp)" ::: "memory")
Packit 6c4009
#define atomic_read_barrier() __asm ("" ::: "memory")
Packit 6c4009
#define atomic_write_barrier() __asm ("" ::: "memory")