Blame sysdeps/s390/atomic-machine.h

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 Martin Schwidefsky <schwidefsky@de.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
#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
/* Activate all C11 atomic builtins.
Packit 6c4009
Packit 6c4009
   Note:
Packit 6c4009
   E.g. in nptl/pthread_key_delete.c if compiled with GCCs 6 and before,
Packit 6c4009
   an extra stack-frame is generated and the old value is stored on stack
Packit 6c4009
   before cs instruction but it never loads this value from stack.
Packit 6c4009
   An unreleased GCC 7 omit those stack operations.
Packit 6c4009
Packit 6c4009
   E.g. in nptl/pthread_once.c the condition code of cs instruction is
Packit 6c4009
   evaluated by a sequence of ipm, sra, compare and jump instructions instead
Packit 6c4009
   of one conditional jump instruction.  This also occurs with an unreleased
Packit 6c4009
   GCC 7.
Packit 6c4009
Packit 6c4009
   The atomic_fetch_abc_def C11 builtins are now using load-and-abc instructions
Packit 6c4009
   on z196 zarch and higher cpus instead of a loop with compare-and-swap
Packit 6c4009
   instruction.  */
Packit 6c4009
#define USE_ATOMIC_COMPILER_BUILTINS 1
Packit 6c4009
Packit 6c4009
#ifdef __s390x__
Packit 6c4009
# define __HAVE_64B_ATOMICS 1
Packit 6c4009
#else
Packit 6c4009
# define __HAVE_64B_ATOMICS 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define ATOMIC_EXCHANGE_USES_CAS 1
Packit 6c4009
Packit 6c4009
/* Implement some of the non-C11 atomic macros from include/atomic.h
Packit 6c4009
   with help of the C11 atomic builtins.  The other non-C11 atomic macros
Packit 6c4009
   are using the macros defined here.  */
Packit 6c4009
Packit 6c4009
/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
Packit 6c4009
   Return the old *MEM value.  */
Packit 6c4009
#define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
    typeof ((__typeof (*(mem))) *(mem)) __atg1_oldval = (oldval);	\
Packit 6c4009
    __atomic_compare_exchange_n (mem, (void *) &__atg1_oldval,		\
Packit 6c4009
				 newval, 1, __ATOMIC_ACQUIRE,		\
Packit 6c4009
				 __ATOMIC_RELAXED);			\
Packit 6c4009
    __atg1_oldval; })
Packit 6c4009
#define atomic_compare_and_exchange_val_rel(mem, newval, oldval)	\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
    typeof ((__typeof (*(mem))) *(mem)) __atg1_2_oldval = (oldval);	\
Packit 6c4009
    __atomic_compare_exchange_n (mem, (void *) &__atg1_2_oldval,	\
Packit 6c4009
				 newval, 1, __ATOMIC_RELEASE,		\
Packit 6c4009
				 __ATOMIC_RELAXED);			\
Packit 6c4009
    __atg1_2_oldval; })
Packit 6c4009
Packit 6c4009
/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
Packit 6c4009
   Return zero if *MEM was changed or non-zero if no exchange happened.  */
Packit 6c4009
#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval)	\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
    typeof ((__typeof (*(mem))) *(mem)) __atg2_oldval = (oldval);	\
Packit 6c4009
    !__atomic_compare_exchange_n (mem, (void *) &__atg2_oldval, newval,	\
Packit 6c4009
				  1, __ATOMIC_ACQUIRE,			\
Packit 6c4009
				  __ATOMIC_RELAXED); })
Packit 6c4009
#define catomic_compare_and_exchange_bool_acq(mem, newval, oldval)	\
Packit 6c4009
  atomic_compare_and_exchange_bool_acq (mem, newval, oldval)
Packit 6c4009
Packit 6c4009
/* Store NEWVALUE in *MEM and return the old value.  */
Packit 6c4009
#define atomic_exchange_acq(mem, newvalue)				\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
    __atomic_exchange_n (mem, newvalue, __ATOMIC_ACQUIRE); })
Packit 6c4009
#define atomic_exchange_rel(mem, newvalue)				\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
    __atomic_exchange_n (mem, newvalue, __ATOMIC_RELEASE); })
Packit 6c4009
Packit 6c4009
/* Add VALUE to *MEM and return the old value of *MEM.  */
Packit 6c4009
/* The gcc builtin uses load-and-add instruction on z196 zarch and higher cpus
Packit 6c4009
   instead of a loop with compare-and-swap instruction.  */
Packit 6c4009
# define atomic_exchange_and_add_acq(mem, operand)			\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
  __atomic_fetch_add ((mem), (operand), __ATOMIC_ACQUIRE); })
Packit 6c4009
# define atomic_exchange_and_add_rel(mem, operand)			\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
  __atomic_fetch_add ((mem), (operand), __ATOMIC_RELEASE); })
Packit 6c4009
#define catomic_exchange_and_add(mem, value)	\
Packit 6c4009
  atomic_exchange_and_add (mem, value)
Packit 6c4009
Packit 6c4009
/* Atomically *mem |= mask and return the old value of *mem.  */
Packit 6c4009
/* The gcc builtin uses load-and-or instruction on z196 zarch and higher cpus
Packit 6c4009
   instead of a loop with compare-and-swap instruction.  */
Packit 6c4009
#define atomic_or_val(mem, operand)					\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
  __atomic_fetch_or ((mem), (operand), __ATOMIC_ACQUIRE); })
Packit 6c4009
/* Atomically *mem |= mask.  */
Packit 6c4009
#define atomic_or(mem, mask)			\
Packit 6c4009
  do {						\
Packit 6c4009
    atomic_or_val (mem, mask);			\
Packit 6c4009
  } while (0)
Packit 6c4009
#define catomic_or(mem, mask)			\
Packit 6c4009
  atomic_or (mem, mask)
Packit 6c4009
Packit 6c4009
/* Atomically *mem |= 1 << bit and return true if the bit was set in old value
Packit 6c4009
   of *mem.  */
Packit 6c4009
/* The load-and-or instruction is used on z196 zarch and higher cpus
Packit 6c4009
   instead of a loop with compare-and-swap instruction.  */
Packit 6c4009
#define atomic_bit_test_set(mem, bit)					\
Packit 6c4009
  ({ __typeof (*(mem)) __atg14_old;					\
Packit 6c4009
    __typeof (mem) __atg14_memp = (mem);				\
Packit 6c4009
    __typeof (*(mem)) __atg14_mask = ((__typeof (*(mem))) 1 << (bit));	\
Packit 6c4009
    __atg14_old = atomic_or_val (__atg14_memp, __atg14_mask);		\
Packit 6c4009
    __atg14_old & __atg14_mask; })
Packit 6c4009
Packit 6c4009
/* Atomically *mem &= mask and return the old value of *mem.  */
Packit 6c4009
/* The gcc builtin uses load-and-and instruction on z196 zarch and higher cpus
Packit 6c4009
   instead of a loop with compare-and-swap instruction.  */
Packit 6c4009
#define atomic_and_val(mem, operand)					\
Packit 6c4009
  ({ __atomic_check_size((mem));					\
Packit 6c4009
  __atomic_fetch_and ((mem), (operand), __ATOMIC_ACQUIRE); })
Packit 6c4009
/* Atomically *mem &= mask.  */
Packit 6c4009
#define atomic_and(mem, mask)			\
Packit 6c4009
  do {						\
Packit 6c4009
    atomic_and_val (mem, mask);			\
Packit 6c4009
  } while (0)
Packit 6c4009
#define catomic_and(mem, mask)			\
Packit 6c4009
  atomic_and(mem, mask)