Blame sysdeps/sparc/sparc32/atomic-machine.h

Packit 6c4009
/* Atomic operations.  sparc32 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 Jakub Jelinek <jakub@redhat.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
#ifndef _ATOMIC_MACHINE_H
Packit 6c4009
#define _ATOMIC_MACHINE_H	1
Packit 6c4009
Packit 6c4009
#include <stdint.h>
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
#define __HAVE_64B_ATOMICS 0
Packit 6c4009
#define USE_ATOMIC_COMPILER_BUILTINS 0
Packit 6c4009
Packit 6c4009
/* XXX Is this actually correct?  */
Packit 6c4009
#define ATOMIC_EXCHANGE_USES_CAS 1
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We have no compare and swap, just test and set.
Packit 6c4009
   The following implementation contends on 64 global locks
Packit 6c4009
   per library and assumes no variable will be accessed using atomic.h
Packit 6c4009
   macros from two different libraries.  */
Packit 6c4009
Packit 6c4009
__make_section_unallocated
Packit 6c4009
  (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits");
Packit 6c4009
Packit 6c4009
volatile unsigned char __sparc32_atomic_locks[64]
Packit 6c4009
  __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks"
Packit 6c4009
				     __sec_comment),
Packit 6c4009
		  visibility ("hidden")));
Packit 6c4009
Packit 6c4009
#define __sparc32_atomic_do_lock(addr) \
Packit 6c4009
  do								      \
Packit 6c4009
    {								      \
Packit 6c4009
      unsigned int __old_lock;					      \
Packit 6c4009
      unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \
Packit 6c4009
			   & 63;				      \
Packit 6c4009
      do							      \
Packit 6c4009
	__asm __volatile ("ldstub %1, %0"			      \
Packit 6c4009
			  : "=r" (__old_lock),			      \
Packit 6c4009
			    "=m" (__sparc32_atomic_locks[__idx])      \
Packit 6c4009
			  : "m" (__sparc32_atomic_locks[__idx])	      \
Packit 6c4009
			  : "memory");				      \
Packit 6c4009
      while (__old_lock);					      \
Packit 6c4009
    }								      \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
#define __sparc32_atomic_do_unlock(addr) \
Packit 6c4009
  do								      \
Packit 6c4009
    {								      \
Packit 6c4009
      __sparc32_atomic_locks[(((long) addr >> 2)		      \
Packit 6c4009
			      ^ ((long) addr >> 12)) & 63] = 0;	      \
Packit 6c4009
      __asm __volatile ("" ::: "memory");			      \
Packit 6c4009
    }								      \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
#define __sparc32_atomic_do_lock24(addr) \
Packit 6c4009
  do								      \
Packit 6c4009
    {								      \
Packit 6c4009
      unsigned int __old_lock;					      \
Packit 6c4009
      do							      \
Packit 6c4009
	__asm __volatile ("ldstub %1, %0"			      \
Packit 6c4009
			  : "=r" (__old_lock), "=m" (*(addr))	      \
Packit 6c4009
			  : "m" (*(addr))			      \
Packit 6c4009
			  : "memory");				      \
Packit 6c4009
      while (__old_lock);					      \
Packit 6c4009
    }								      \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
#define __sparc32_atomic_do_unlock24(addr) \
Packit 6c4009
  do								      \
Packit 6c4009
    {								      \
Packit 6c4009
      __asm __volatile ("" ::: "memory");			      \
Packit 6c4009
      *(char *) (addr) = 0;					      \
Packit 6c4009
    }								      \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifndef SHARED
Packit 6c4009
# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \
Packit 6c4009
({union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };  \
Packit 6c4009
  union { __typeof (newval) a; uint32_t v; } newval_arg = { .a = (newval) };  \
Packit 6c4009
  register uint32_t __acev_tmp __asm ("%g6");			              \
Packit 6c4009
  register __typeof (mem) __acev_mem __asm ("%g1") = (mem);		      \
Packit 6c4009
  register uint32_t __acev_oldval __asm ("%g5");		              \
Packit 6c4009
  __acev_tmp = newval_arg.v;						      \
Packit 6c4009
  __acev_oldval = oldval_arg.v;						      \
Packit 6c4009
  /* .word 0xcde05005 is cas [%g1], %g5, %g6.  Can't use cas here though,     \
Packit 6c4009
     because as will then mark the object file as V8+ arch.  */		      \
Packit 6c4009
  __asm __volatile (".word 0xcde05005"					      \
Packit 6c4009
		    : "+r" (__acev_tmp), "=m" (*__acev_mem)		      \
Packit 6c4009
		    : "r" (__acev_oldval), "m" (*__acev_mem),		      \
Packit 6c4009
		      "r" (__acev_mem) : "memory");			      \
Packit 6c4009
  (__typeof (oldval)) __acev_tmp; })
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* The only basic operation needed is compare and exchange.  */
Packit 6c4009
#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (mem) __acev_memp = (mem);			      \
Packit 6c4009
     __typeof (*mem) __acev_ret;				      \
Packit 6c4009
     __typeof (*mem) __acev_newval = (newval);			      \
Packit 6c4009
								      \
Packit 6c4009
     __sparc32_atomic_do_lock (__acev_memp);			      \
Packit 6c4009
     __acev_ret = *__acev_memp;					      \
Packit 6c4009
     if (__acev_ret == (oldval))				      \
Packit 6c4009
       *__acev_memp = __acev_newval;				      \
Packit 6c4009
     __sparc32_atomic_do_unlock (__acev_memp);			      \
Packit 6c4009
     __acev_ret; })
Packit 6c4009
Packit 6c4009
#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (mem) __aceb_memp = (mem);			      \
Packit 6c4009
     int __aceb_ret;						      \
Packit 6c4009
     __typeof (*mem) __aceb_newval = (newval);			      \
Packit 6c4009
								      \
Packit 6c4009
     __sparc32_atomic_do_lock (__aceb_memp);			      \
Packit 6c4009
     __aceb_ret = 0;						      \
Packit 6c4009
     if (*__aceb_memp == (oldval))				      \
Packit 6c4009
       *__aceb_memp = __aceb_newval;				      \
Packit 6c4009
     else							      \
Packit 6c4009
       __aceb_ret = 1;						      \
Packit 6c4009
     __sparc32_atomic_do_unlock (__aceb_memp);			      \
Packit 6c4009
     __aceb_ret; })
Packit 6c4009
Packit 6c4009
#define __v7_exchange_acq(mem, newval) \
Packit 6c4009
  ({ __typeof (mem) __acev_memp = (mem);			      \
Packit 6c4009
     __typeof (*mem) __acev_ret;				      \
Packit 6c4009
     __typeof (*mem) __acev_newval = (newval);			      \
Packit 6c4009
								      \
Packit 6c4009
     __sparc32_atomic_do_lock (__acev_memp);			      \
Packit 6c4009
     __acev_ret = *__acev_memp;					      \
Packit 6c4009
     *__acev_memp = __acev_newval;				      \
Packit 6c4009
     __sparc32_atomic_do_unlock (__acev_memp);			      \
Packit 6c4009
     __acev_ret; })
Packit 6c4009
Packit 6c4009
#define __v7_exchange_and_add(mem, value) \
Packit 6c4009
  ({ __typeof (mem) __acev_memp = (mem);			      \
Packit 6c4009
     __typeof (*mem) __acev_ret;				      \
Packit 6c4009
								      \
Packit 6c4009
     __sparc32_atomic_do_lock (__acev_memp);			      \
Packit 6c4009
     __acev_ret = *__acev_memp;					      \
Packit 6c4009
     *__acev_memp = __acev_ret + (value);			      \
Packit 6c4009
     __sparc32_atomic_do_unlock (__acev_memp);			      \
Packit 6c4009
     __acev_ret; })
Packit 6c4009
Packit 6c4009
/* Special versions, which guarantee that top 8 bits of all values
Packit 6c4009
   are cleared and use those bits as the ldstub lock.  */
Packit 6c4009
#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \
Packit 6c4009
  ({ __typeof (mem) __acev_memp = (mem);			      \
Packit 6c4009
     __typeof (*mem) __acev_ret;				      \
Packit 6c4009
     __typeof (*mem) __acev_newval = (newval);			      \
Packit 6c4009
								      \
Packit 6c4009
     __sparc32_atomic_do_lock24 (__acev_memp);			      \
Packit 6c4009
     __acev_ret = *__acev_memp & 0xffffff;			      \
Packit 6c4009
     if (__acev_ret == (oldval))				      \
Packit 6c4009
       *__acev_memp = __acev_newval;				      \
Packit 6c4009
     else							      \
Packit 6c4009
       __sparc32_atomic_do_unlock24 (__acev_memp);		      \
Packit 6c4009
     __asm __volatile ("" ::: "memory");			      \
Packit 6c4009
     __acev_ret; })
Packit 6c4009
Packit 6c4009
#define __v7_exchange_24_rel(mem, newval) \
Packit 6c4009
  ({ __typeof (mem) __acev_memp = (mem);			      \
Packit 6c4009
     __typeof (*mem) __acev_ret;				      \
Packit 6c4009
     __typeof (*mem) __acev_newval = (newval);			      \
Packit 6c4009
								      \
Packit 6c4009
     __sparc32_atomic_do_lock24 (__acev_memp);			      \
Packit 6c4009
     __acev_ret = *__acev_memp & 0xffffff;			      \
Packit 6c4009
     *__acev_memp = __acev_newval;				      \
Packit 6c4009
     __asm __volatile ("" ::: "memory");			      \
Packit 6c4009
     __acev_ret; })
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
Packit 6c4009
/* When dynamically linked, we assume pre-v9 libraries are only ever
Packit 6c4009
   used on pre-v9 CPU.  */
Packit 6c4009
# define __atomic_is_v9 0
Packit 6c4009
Packit 6c4009
# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
Packit 6c4009
  __v7_compare_and_exchange_val_acq (mem, newval, oldval)
Packit 6c4009
Packit 6c4009
# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
Packit 6c4009
  __v7_compare_and_exchange_bool_acq (mem, newval, oldval)
Packit 6c4009
Packit 6c4009
# define atomic_exchange_acq(mem, newval) \
Packit 6c4009
  __v7_exchange_acq (mem, newval)
Packit 6c4009
Packit 6c4009
# define atomic_exchange_and_add(mem, value) \
Packit 6c4009
  __v7_exchange_and_add (mem, value)
Packit 6c4009
Packit 6c4009
# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); })
Packit 6c4009
Packit 6c4009
# define atomic_exchange_24_rel(mem, newval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     __v7_exchange_24_rel (mem, newval); })
Packit 6c4009
Packit 6c4009
# define atomic_full_barrier() __asm ("" ::: "memory")
Packit 6c4009
# define atomic_read_barrier() atomic_full_barrier ()
Packit 6c4009
# define atomic_write_barrier() atomic_full_barrier ()
Packit 6c4009
Packit 6c4009
#else
Packit 6c4009
Packit 6c4009
/* In libc.a/libpthread.a etc. we don't know if we'll be run on
Packit 6c4009
   pre-v9 or v9 CPU.  To be interoperable with dynamically linked
Packit 6c4009
   apps on v9 CPUs e.g. with process shared primitives, use cas insn
Packit 6c4009
   on v9 CPUs and ldstub on pre-v9.  */
Packit 6c4009
Packit 6c4009
extern uint64_t _dl_hwcap __attribute__((weak));
Packit 6c4009
# define __atomic_is_v9 \
Packit 6c4009
  (__builtin_expect (&_dl_hwcap != 0, 1) \
Packit 6c4009
   && __builtin_expect (_dl_hwcap & HWCAP_SPARC_V9, HWCAP_SPARC_V9))
Packit 6c4009
Packit 6c4009
# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     __typeof (*mem) __acev_wret;				      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     if (__atomic_is_v9)					      \
Packit 6c4009
       __acev_wret						      \
Packit 6c4009
	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
Packit 6c4009
     else							      \
Packit 6c4009
       __acev_wret						      \
Packit 6c4009
	 = __v7_compare_and_exchange_val_acq (mem, newval, oldval);   \
Packit 6c4009
     __acev_wret; })
Packit 6c4009
Packit 6c4009
# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     int __acev_wret;						      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     if (__atomic_is_v9)					      \
Packit 6c4009
       {							      \
Packit 6c4009
	 __typeof (oldval) __acev_woldval = (oldval);		      \
Packit 6c4009
	 __acev_wret						      \
Packit 6c4009
	   = __v9_compare_and_exchange_val_32_acq (mem, newval,	      \
Packit 6c4009
						   __acev_woldval)    \
Packit 6c4009
	     != __acev_woldval;					      \
Packit 6c4009
       }							      \
Packit 6c4009
     else							      \
Packit 6c4009
       __acev_wret						      \
Packit 6c4009
	 = __v7_compare_and_exchange_bool_acq (mem, newval, oldval);  \
Packit 6c4009
     __acev_wret; })
Packit 6c4009
Packit 6c4009
# define atomic_exchange_rel(mem, newval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     __typeof (*mem) __acev_wret;				      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     if (__atomic_is_v9)					      \
Packit 6c4009
       {							      \
Packit 6c4009
	 __typeof (mem) __acev_wmemp = (mem);			      \
Packit 6c4009
	 __typeof (*(mem)) __acev_wval = (newval);		      \
Packit 6c4009
	 do							      \
Packit 6c4009
	   __acev_wret = *__acev_wmemp;				      \
Packit 6c4009
	 while (__builtin_expect				      \
Packit 6c4009
		  (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\
Packit 6c4009
							 __acev_wval, \
Packit 6c4009
							 __acev_wret) \
Packit 6c4009
		   != __acev_wret, 0));				      \
Packit 6c4009
       }							      \
Packit 6c4009
     else							      \
Packit 6c4009
       __acev_wret = __v7_exchange_acq (mem, newval);		      \
Packit 6c4009
     __acev_wret; })
Packit 6c4009
Packit 6c4009
# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     __typeof (*mem) __acev_wret;				      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     if (__atomic_is_v9)					      \
Packit 6c4009
       __acev_wret						      \
Packit 6c4009
	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
Packit 6c4009
     else							      \
Packit 6c4009
       __acev_wret						      \
Packit 6c4009
	 = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\
Packit 6c4009
     __acev_wret; })
Packit 6c4009
Packit 6c4009
# define atomic_exchange_24_rel(mem, newval) \
Packit 6c4009
  ({								      \
Packit 6c4009
     __typeof (*mem) __acev_w24ret;				      \
Packit 6c4009
     if (sizeof (*mem) != 4)					      \
Packit 6c4009
       abort ();						      \
Packit 6c4009
     if (__atomic_is_v9)					      \
Packit 6c4009
       __acev_w24ret = atomic_exchange_rel (mem, newval);	      \
Packit 6c4009
     else							      \
Packit 6c4009
       __acev_w24ret = __v7_exchange_24_rel (mem, newval);	      \
Packit 6c4009
     __acev_w24ret; })
Packit 6c4009
Packit 6c4009
#define atomic_full_barrier()						\
Packit 6c4009
  do {									\
Packit 6c4009
     if (__atomic_is_v9)						\
Packit 6c4009
       /* membar #LoadLoad | #LoadStore | #StoreLoad | #StoreStore */	\
Packit 6c4009
       __asm __volatile (".word 0x8143e00f" : : : "memory");		\
Packit 6c4009
     else								\
Packit 6c4009
       __asm __volatile ("" : : : "memory");				\
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define atomic_read_barrier()						\
Packit 6c4009
  do {									\
Packit 6c4009
     if (__atomic_is_v9)						\
Packit 6c4009
       /* membar #LoadLoad | #LoadStore */				\
Packit 6c4009
       __asm __volatile (".word 0x8143e005" : : : "memory");		\
Packit 6c4009
     else								\
Packit 6c4009
       __asm __volatile ("" : : : "memory");				\
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define atomic_write_barrier()						\
Packit 6c4009
  do {									\
Packit 6c4009
     if (__atomic_is_v9)						\
Packit 6c4009
       /* membar  #LoadStore | #StoreStore */				\
Packit 6c4009
       __asm __volatile (".word 0x8143e00c" : : : "memory");		\
Packit 6c4009
     else								\
Packit 6c4009
       __asm __volatile ("" : : : "memory");				\
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
Packit 6c4009
#endif	/* atomic-machine.h */