Blame sysdeps/powerpc/powerpc64/atomic-machine.h

Packit 6c4009
/* Atomic operations.  PowerPC64 version.
Packit 6c4009
   Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
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
/*  POWER6 adds a "Mutex Hint" to the Load and Reserve instruction.
Packit 6c4009
    This is a hint to the hardware to expect additional updates adjacent
Packit 6c4009
    to the lock word or not.  If we are acquiring a Mutex, the hint
Packit 6c4009
    should be true. Otherwise we releasing a Mutex or doing a simple
Packit 6c4009
    atomic operation.  In that case we don't expect additional updates
Packit 6c4009
    adjacent to the lock word after the Store Conditional and the hint
Packit 6c4009
    should be false.  */
Packit 6c4009
Packit 6c4009
#if defined _ARCH_PWR6 || defined _ARCH_PWR6X
Packit 6c4009
# define MUTEX_HINT_ACQ	",1"
Packit 6c4009
# define MUTEX_HINT_REL	",0"
Packit 6c4009
#else
Packit 6c4009
# define MUTEX_HINT_ACQ
Packit 6c4009
# define MUTEX_HINT_REL
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define __HAVE_64B_ATOMICS 1
Packit 6c4009
#define USE_ATOMIC_COMPILER_BUILTINS 0
Packit 6c4009
#define ATOMIC_EXCHANGE_USES_CAS 1
Packit 6c4009
Packit 6c4009
/* The 32-bit exchange_bool is different on powerpc64 because the subf
Packit 6c4009
   does signed 64-bit arithmetic while the lwarx is 32-bit unsigned
Packit 6c4009
   (a load word and zero (high 32) form) load.
Packit 6c4009
   In powerpc64 register values are 64-bit by default,  including oldval.
Packit 6c4009
   The value in old val unknown sign extension, lwarx loads the 32-bit
Packit 6c4009
   value as unsigned.  So we explicitly clear the high 32 bits in oldval.  */
Packit 6c4009
#define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \
Packit 6c4009
({									      \
Packit 6c4009
  unsigned int __tmp, __tmp2;						      \
Packit 6c4009
  __asm __volatile ("   clrldi  %1,%1,32\n"				      \
Packit 6c4009
		    "1:	lwarx	%0,0,%2" MUTEX_HINT_ACQ "\n"	 	      \
Packit 6c4009
		    "	subf.	%0,%1,%0\n"				      \
Packit 6c4009
		    "	bne	2f\n"					      \
Packit 6c4009
		    "	stwcx.	%4,0,%2\n"				      \
Packit 6c4009
		    "	bne-	1b\n"					      \
Packit 6c4009
		    "2:	" __ARCH_ACQ_INSTR				      \
Packit 6c4009
		    : "=&r" (__tmp), "=r" (__tmp2)			      \
Packit 6c4009
		    : "b" (mem), "1" (oldval), "r" (newval)		      \
Packit 6c4009
		    : "cr0", "memory");					      \
Packit 6c4009
  __tmp != 0;								      \
Packit 6c4009
})
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Only powerpc64 processors support Load doubleword and reserve index (ldarx)
Packit 6c4009
 * and Store doubleword conditional indexed (stdcx) instructions.  So here
Packit 6c4009
 * we define the 64-bit forms.
Packit 6c4009
 */
Packit 6c4009
#define __arch_compare_and_exchange_bool_64_acq(mem, newval, oldval) \
Packit 6c4009
({									      \
Packit 6c4009
  unsigned long	__tmp;							      \
Packit 6c4009
  __asm __volatile (							      \
Packit 6c4009
		    "1:	ldarx	%0,0,%1" MUTEX_HINT_ACQ "\n"		      \
Packit 6c4009
		    "	subf.	%0,%2,%0\n"				      \
Packit 6c4009
		    "	bne	2f\n"					      \
Packit 6c4009
		    "	stdcx.	%3,0,%1\n"				      \
Packit 6c4009
		    "	bne-	1b\n"					      \
Packit 6c4009
		    "2:	" __ARCH_ACQ_INSTR				      \
Packit 6c4009
		    : "=&r" (__tmp)					      \
Packit 6c4009
		    : "b" (mem), "r" (oldval), "r" (newval)		      \
Packit 6c4009
		    : "cr0", "memory");					      \
Packit 6c4009
  __tmp != 0;								      \
Packit 6c4009
})
Packit 6c4009
Packit 6c4009
#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
Packit 6c4009
  ({									      \
Packit 6c4009
      __typeof (*(mem)) __tmp;						      \
Packit 6c4009
      __typeof (mem)  __memp = (mem);					      \
Packit 6c4009
      __asm __volatile (						      \
Packit 6c4009
		        "1:	ldarx	%0,0,%1" MUTEX_HINT_ACQ "\n"	      \
Packit 6c4009
		        "	cmpd	%0,%2\n"			      \
Packit 6c4009
		        "	bne	2f\n"				      \
Packit 6c4009
		        "	stdcx.	%3,0,%1\n"			      \
Packit 6c4009
		        "	bne-	1b\n"				      \
Packit 6c4009
		        "2:	" __ARCH_ACQ_INSTR			      \
Packit 6c4009
		        : "=&r" (__tmp)					      \
Packit 6c4009
		        : "b" (__memp), "r" (oldval), "r" (newval)	      \
Packit 6c4009
		        : "cr0", "memory");				      \
Packit 6c4009
      __tmp;								      \
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
#define __arch_compare_and_exchange_val_64_rel(mem, newval, oldval) \
Packit 6c4009
  ({									      \
Packit 6c4009
      __typeof (*(mem)) __tmp;						      \
Packit 6c4009
      __typeof (mem)  __memp = (mem);					      \
Packit 6c4009
      __asm __volatile (__ARCH_REL_INSTR "\n"				      \
Packit 6c4009
		        "1:	ldarx	%0,0,%1" MUTEX_HINT_REL "\n"	      \
Packit 6c4009
		        "	cmpd	%0,%2\n"			      \
Packit 6c4009
		        "	bne	2f\n"				      \
Packit 6c4009
		        "	stdcx.	%3,0,%1\n"			      \
Packit 6c4009
		        "	bne-	1b\n"				      \
Packit 6c4009
		        "2:	"					      \
Packit 6c4009
		        : "=&r" (__tmp)					      \
Packit 6c4009
		        : "b" (__memp), "r" (oldval), "r" (newval)	      \
Packit 6c4009
		        : "cr0", "memory");				      \
Packit 6c4009
      __tmp;								      \
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_exchange_64_acq(mem, value) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*mem) __val;						      \
Packit 6c4009
      __asm __volatile (__ARCH_REL_INSTR "\n"				      \
Packit 6c4009
			"1:	ldarx	%0,0,%2" MUTEX_HINT_ACQ "\n"	      \
Packit 6c4009
			"	stdcx.	%3,0,%2\n"			      \
Packit 6c4009
			"	bne-	1b\n"				      \
Packit 6c4009
		  " " __ARCH_ACQ_INSTR					      \
Packit 6c4009
			: "=&r" (__val), "=m" (*mem)			      \
Packit 6c4009
			: "b" (mem), "r" (value), "m" (*mem)		      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_exchange_64_rel(mem, value) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*mem) __val;						      \
Packit 6c4009
      __asm __volatile (__ARCH_REL_INSTR "\n"				      \
Packit 6c4009
			"1:	ldarx	%0,0,%2" MUTEX_HINT_REL "\n"	      \
Packit 6c4009
			"	stdcx.	%3,0,%2\n"			      \
Packit 6c4009
			"	bne-	1b"				      \
Packit 6c4009
			: "=&r" (__val), "=m" (*mem)			      \
Packit 6c4009
			: "b" (mem), "r" (value), "m" (*mem)		      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_exchange_and_add_64(mem, value) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*mem) __val, __tmp;					      \
Packit 6c4009
      __asm __volatile ("1:	ldarx	%0,0,%3\n"			      \
Packit 6c4009
			"	add	%1,%0,%4\n"			      \
Packit 6c4009
			"	stdcx.	%1,0,%3\n"			      \
Packit 6c4009
			"	bne-	1b"				      \
Packit 6c4009
			: "=&b" (__val), "=&r" (__tmp), "=m" (*mem)	      \
Packit 6c4009
			: "b" (mem), "r" (value), "m" (*mem)		      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_exchange_and_add_64_acq(mem, value) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*mem) __val, __tmp;					      \
Packit 6c4009
      __asm __volatile ("1:	ldarx	%0,0,%3" MUTEX_HINT_ACQ "\n"	      \
Packit 6c4009
			"	add	%1,%0,%4\n"			      \
Packit 6c4009
			"	stdcx.	%1,0,%3\n"			      \
Packit 6c4009
			"	bne-	1b\n"				      \
Packit 6c4009
			__ARCH_ACQ_INSTR				      \
Packit 6c4009
			: "=&b" (__val), "=&r" (__tmp), "=m" (*mem)	      \
Packit 6c4009
			: "b" (mem), "r" (value), "m" (*mem)		      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_exchange_and_add_64_rel(mem, value) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*mem) __val, __tmp;					      \
Packit 6c4009
      __asm __volatile (__ARCH_REL_INSTR "\n"				      \
Packit 6c4009
			"1:	ldarx	%0,0,%3" MUTEX_HINT_REL "\n"	      \
Packit 6c4009
			"	add	%1,%0,%4\n"			      \
Packit 6c4009
			"	stdcx.	%1,0,%3\n"			      \
Packit 6c4009
			"	bne-	1b"				      \
Packit 6c4009
			: "=&b" (__val), "=&r" (__tmp), "=m" (*mem)	      \
Packit 6c4009
			: "b" (mem), "r" (value), "m" (*mem)		      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_increment_val_64(mem) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*(mem)) __val;						      \
Packit 6c4009
      __asm __volatile ("1:	ldarx	%0,0,%2\n"			      \
Packit 6c4009
			"	addi	%0,%0,1\n"			      \
Packit 6c4009
			"	stdcx.	%0,0,%2\n"			      \
Packit 6c4009
			"	bne-	1b"				      \
Packit 6c4009
			: "=&b" (__val), "=m" (*mem)			      \
Packit 6c4009
			: "b" (mem), "m" (*mem)				      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_decrement_val_64(mem) \
Packit 6c4009
    ({									      \
Packit 6c4009
      __typeof (*(mem)) __val;						      \
Packit 6c4009
      __asm __volatile ("1:	ldarx	%0,0,%2\n"			      \
Packit 6c4009
			"	subi	%0,%0,1\n"			      \
Packit 6c4009
			"	stdcx.	%0,0,%2\n"			      \
Packit 6c4009
			"	bne-	1b"				      \
Packit 6c4009
			: "=&b" (__val), "=m" (*mem)			      \
Packit 6c4009
			: "b" (mem), "m" (*mem)				      \
Packit 6c4009
			: "cr0", "memory");				      \
Packit 6c4009
      __val;								      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define __arch_atomic_decrement_if_positive_64(mem) \
Packit 6c4009
  ({ int __val, __tmp;							      \
Packit 6c4009
     __asm __volatile ("1:	ldarx	%0,0,%3\n"			      \
Packit 6c4009
		       "	cmpdi	0,%0,0\n"			      \
Packit 6c4009
		       "	addi	%1,%0,-1\n"			      \
Packit 6c4009
		       "	ble	2f\n"				      \
Packit 6c4009
		       "	stdcx.	%1,0,%3\n"			      \
Packit 6c4009
		       "	bne-	1b\n"				      \
Packit 6c4009
		       "2:	" __ARCH_ACQ_INSTR			      \
Packit 6c4009
		       : "=&b" (__val), "=&r" (__tmp), "=m" (*mem)	      \
Packit 6c4009
		       : "b" (mem), "m" (*mem)				      \
Packit 6c4009
		       : "cr0", "memory");				      \
Packit 6c4009
     __val;								      \
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * All powerpc64 processors support the new "light weight"  sync (lwsync).
Packit 6c4009
 */
Packit 6c4009
#define atomic_read_barrier()	__asm ("lwsync" ::: "memory")
Packit 6c4009
/*
Packit 6c4009
 * "light weight" sync can also be used for the release barrier.
Packit 6c4009
 */
Packit 6c4009
#ifndef UP
Packit 6c4009
# define __ARCH_REL_INSTR	"lwsync"
Packit 6c4009
#endif
Packit 6c4009
#define atomic_write_barrier()	__asm ("lwsync" ::: "memory")
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Include the rest of the atomic ops macros which are common to both
Packit 6c4009
 * powerpc32 and powerpc64.
Packit 6c4009
 */
Packit 6c4009
#include_next <atomic-machine.h>