1  /* Low-level functions for atomic operations. RISC-V version.
       2     Copyright (C) 2014-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library.  If not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef _LINUX_RISCV_BITS_ATOMIC_H
      20  #define _LINUX_RISCV_BITS_ATOMIC_H 1
      21  
      22  #define atomic_full_barrier() __sync_synchronize ()
      23  
      24  #ifdef __riscv_atomic
      25  
      26  # define __HAVE_64B_ATOMICS (__riscv_xlen >= 64)
      27  # define USE_ATOMIC_COMPILER_BUILTINS 1
      28  # define ATOMIC_EXCHANGE_USES_CAS 0
      29  
      30  /* Compare and exchange.
      31     For all "bool" routines, we return FALSE if exchange successful.  */
      32  
      33  # define __arch_compare_and_exchange_bool_8_int(mem, newval, oldval, model) \
      34    ({									\
      35      typeof (*mem) __oldval = (oldval);					\
      36      !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      37  				  model, __ATOMIC_RELAXED);		\
      38    })
      39  
      40  # define __arch_compare_and_exchange_bool_16_int(mem, newval, oldval, model) \
      41    ({									\
      42      typeof (*mem) __oldval = (oldval);					\
      43      !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      44  				  model, __ATOMIC_RELAXED);		\
      45    })
      46  
      47  # define __arch_compare_and_exchange_bool_32_int(mem, newval, oldval, model) \
      48    ({									\
      49      typeof (*mem) __oldval = (oldval);					\
      50      !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      51  				  model, __ATOMIC_RELAXED);		\
      52    })
      53  
      54  #  define __arch_compare_and_exchange_bool_64_int(mem, newval, oldval, model) \
      55    ({									\
      56      typeof (*mem) __oldval = (oldval);					\
      57      !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      58  				  model, __ATOMIC_RELAXED);		\
      59    })
      60  
      61  # define __arch_compare_and_exchange_val_8_int(mem, newval, oldval, model) \
      62    ({									\
      63      typeof (*mem) __oldval = (oldval);					\
      64      __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      65  				 model, __ATOMIC_RELAXED);		\
      66      __oldval;								\
      67    })
      68  
      69  # define __arch_compare_and_exchange_val_16_int(mem, newval, oldval, model) \
      70    ({									\
      71      typeof (*mem) __oldval = (oldval);					\
      72      __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      73  				 model, __ATOMIC_RELAXED);		\
      74      __oldval;								\
      75    })
      76  
      77  # define __arch_compare_and_exchange_val_32_int(mem, newval, oldval, model) \
      78    ({									\
      79      typeof (*mem) __oldval = (oldval);					\
      80      __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      81  				 model, __ATOMIC_RELAXED);		\
      82      __oldval;								\
      83    })
      84  
      85  # define __arch_compare_and_exchange_val_64_int(mem, newval, oldval, model) \
      86    ({									\
      87      typeof (*mem) __oldval = (oldval);					\
      88      __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
      89  				 model, __ATOMIC_RELAXED);		\
      90      __oldval;								\
      91    })
      92  
      93  /* Atomic compare and exchange.  */
      94  
      95  # define atomic_compare_and_exchange_bool_acq(mem, new, old)	\
      96    __atomic_bool_bysize (__arch_compare_and_exchange_bool, int,	\
      97  			mem, new, old, __ATOMIC_ACQUIRE)
      98  
      99  # define atomic_compare_and_exchange_val_acq(mem, new, old)	\
     100    __atomic_val_bysize (__arch_compare_and_exchange_val, int,	\
     101  		       mem, new, old, __ATOMIC_ACQUIRE)
     102  
     103  # define atomic_compare_and_exchange_val_rel(mem, new, old)	 \
     104    __atomic_val_bysize (__arch_compare_and_exchange_val, int,    \
     105                         mem, new, old, __ATOMIC_RELEASE)
     106  
     107  /* Atomic exchange (without compare).  */
     108  
     109  # define __arch_exchange_8_int(mem, newval, model)	\
     110    __atomic_exchange_n (mem, newval, model)
     111  
     112  # define __arch_exchange_16_int(mem, newval, model)	\
     113    __atomic_exchange_n (mem, newval, model)
     114  
     115  # define __arch_exchange_32_int(mem, newval, model)	\
     116    __atomic_exchange_n (mem, newval, model)
     117  
     118  #  define __arch_exchange_64_int(mem, newval, model)	\
     119    __atomic_exchange_n (mem, newval, model)
     120  
     121  # define atomic_exchange_acq(mem, value)				\
     122    __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_ACQUIRE)
     123  
     124  # define atomic_exchange_rel(mem, value)				\
     125    __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_RELEASE)
     126  
     127  /* Atomically add value and return the previous (unincremented) value.  */
     128  
     129  # define __arch_exchange_and_add_8_int(mem, value, model)	\
     130    __atomic_fetch_add (mem, value, model)
     131  
     132  # define __arch_exchange_and_add_16_int(mem, value, model)	\
     133    __atomic_fetch_add (mem, value, model)
     134  
     135  # define __arch_exchange_and_add_32_int(mem, value, model)	\
     136    __atomic_fetch_add (mem, value, model)
     137  
     138  #  define __arch_exchange_and_add_64_int(mem, value, model)	\
     139    __atomic_fetch_add (mem, value, model)
     140  
     141  # define atomic_exchange_and_add_acq(mem, value)			\
     142    __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	\
     143  		       __ATOMIC_ACQUIRE)
     144  
     145  # define atomic_exchange_and_add_rel(mem, value)			\
     146    __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	\
     147  		       __ATOMIC_RELEASE)
     148  
     149  /* Miscellaneous.  */
     150  
     151  # define asm_amo(which, ordering, mem, value) ({ 		\
     152    __atomic_check_size (mem);					\
     153    typeof (*mem) __tmp; 						\
     154    if (sizeof (__tmp) == 4)					\
     155      asm volatile (which ".w" ordering "\t%0, %z2, %1"		\
     156  		  : "=r" (__tmp), "+A" (* (mem))		\
     157  		  : "rJ" (value));				\
     158    else if (sizeof (__tmp) == 8)					\
     159      asm volatile (which ".d" ordering "\t%0, %z2, %1"		\
     160  		  : "=r" (__tmp), "+A" (* (mem))		\
     161  		  : "rJ" (value));				\
     162    else								\
     163      abort ();							\
     164    __tmp; })
     165  
     166  # define atomic_max(mem, value) asm_amo ("amomaxu", ".aq", mem, value)
     167  # define atomic_min(mem, value) asm_amo ("amominu", ".aq", mem, value)
     168  
     169  # define atomic_bit_test_set(mem, bit)                   \
     170    ({ typeof (*mem) __mask = (typeof (*mem))1 << (bit);    \
     171       asm_amo ("amoor", ".aq", mem, __mask) & __mask; })
     172  
     173  # define catomic_exchange_and_add(mem, value)		\
     174    atomic_exchange_and_add (mem, value)
     175  # define catomic_max(mem, value) atomic_max (mem, value)
     176  
     177  #else /* __riscv_atomic */
     178  # error "ISAs that do not subsume the A extension are not supported"
     179  #endif /* !__riscv_atomic */
     180  
     181  #endif /* bits/atomic.h */