(root)/
gcc-13.2.0/
libgcc/
config/
arm/
linux-atomic-64bit.c
       1  /* 64bit Linux-specific atomic operations for ARM EABI.
       2     Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3     Based on linux-atomic.c
       4  
       5     64 bit additions david.gilbert@linaro.org
       6  
       7  This file is part of GCC.
       8  
       9  GCC is free software; you can redistribute it and/or modify it under
      10  the terms of the GNU General Public License as published by the Free
      11  Software Foundation; either version 3, or (at your option) any later
      12  version.
      13  
      14  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      16  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      17  for more details.
      18  
      19  Under Section 7 of GPL version 3, you are granted additional
      20  permissions described in the GCC Runtime Library Exception, version
      21  3.1, as published by the Free Software Foundation.
      22  
      23  You should have received a copy of the GNU General Public License and
      24  a copy of the GCC Runtime Library Exception along with this program;
      25  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      26  <http://www.gnu.org/licenses/>.  */
      27  
      28  /* 64bit helper functions for atomic operations; the compiler will
      29     call these when the code is compiled for a CPU without ldrexd/strexd.
      30     (If the CPU had those then the compiler inlines the operation).
      31  
      32     These helpers require a kernel helper that's only present on newer
      33     kernels; we check for that in an init section and bail out rather
      34     unceremoneously.  */
      35  
      36  extern int write (int fd, const void *buf, unsigned int count);
      37  extern void abort (void);
      38  
      39  /* Kernel helper for compare-and-exchange.  */
      40  typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
      41  					const long long* newval,
      42  					long long *ptr);
      43  #define __kernel_cmpxchg64 (*(__kernel_cmpxchg64_t *) 0xffff0f60)
      44  
      45  /* Kernel helper page version number.  */
      46  #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
      47  
      48  /* Check that the kernel has a new enough version at load.  */
      49  static void __check_for_sync8_kernelhelper (void)
      50  {
      51    if (__kernel_helper_version < 5)
      52      {
      53        const char err[] = "A newer kernel is required to run this binary. "
      54  				"(__kernel_cmpxchg64 helper)\n";
      55        /* At this point we need a way to crash with some information
      56  	 for the user - I'm not sure I can rely on much else being
      57  	 available at this point, so do the same as generic-morestack.c
      58  	 write () and abort ().  */
      59        write (2 /* stderr.  */, err, sizeof (err));
      60        abort ();
      61      }
      62  };
      63  
      64  static void (*__sync8_kernelhelper_inithook[]) (void)
      65  		__attribute__ ((used, section (".init_array"))) = {
      66    &__check_for_sync8_kernelhelper
      67  };
      68  
      69  #define HIDDEN __attribute__ ((visibility ("hidden")))
      70  
      71  #define FETCH_AND_OP_WORD64(OP, PFX_OP, INF_OP)			\
      72    long long HIDDEN						\
      73    __sync_fetch_and_##OP##_8 (long long *ptr, long long val)	\
      74    {								\
      75      int failure;						\
      76      long long tmp,tmp2;						\
      77  								\
      78      do {							\
      79        tmp = *ptr;						\
      80        tmp2 = PFX_OP (tmp INF_OP val);				\
      81        failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr);		\
      82      } while (failure != 0);					\
      83  								\
      84      return tmp;							\
      85    }
      86  
      87  FETCH_AND_OP_WORD64 (add,   , +)
      88  FETCH_AND_OP_WORD64 (sub,   , -)
      89  FETCH_AND_OP_WORD64 (or,    , |)
      90  FETCH_AND_OP_WORD64 (and,   , &)
      91  FETCH_AND_OP_WORD64 (xor,   , ^)
      92  FETCH_AND_OP_WORD64 (nand, ~, &)
      93  
      94  #define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
      95  #define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
      96  
      97  /* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
      98     subword-sized quantities.  */
      99  
     100  #define OP_AND_FETCH_WORD64(OP, PFX_OP, INF_OP)			\
     101    long long HIDDEN						\
     102    __sync_##OP##_and_fetch_8 (long long *ptr, long long val)	\
     103    {								\
     104      int failure;						\
     105      long long tmp,tmp2;						\
     106  								\
     107      do {							\
     108        tmp = *ptr;						\
     109        tmp2 = PFX_OP (tmp INF_OP val);				\
     110        failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr);		\
     111      } while (failure != 0);					\
     112  								\
     113      return tmp2;						\
     114    }
     115  
     116  OP_AND_FETCH_WORD64 (add,   , +)
     117  OP_AND_FETCH_WORD64 (sub,   , -)
     118  OP_AND_FETCH_WORD64 (or,    , |)
     119  OP_AND_FETCH_WORD64 (and,   , &)
     120  OP_AND_FETCH_WORD64 (xor,   , ^)
     121  OP_AND_FETCH_WORD64 (nand, ~, &)
     122  
     123  long long HIDDEN
     124  __sync_val_compare_and_swap_8 (long long *ptr, long long oldval,
     125  				long long newval)
     126  {
     127    int failure;
     128    long long actual_oldval;
     129  
     130    while (1)
     131      {
     132        actual_oldval = *ptr;
     133  
     134        if (__builtin_expect (oldval != actual_oldval, 0))
     135  	return actual_oldval;
     136  
     137        failure = __kernel_cmpxchg64 (&actual_oldval, &newval, ptr);
     138  
     139        if (__builtin_expect (!failure, 1))
     140  	return oldval;
     141      }
     142  }
     143  
     144  typedef unsigned char bool;
     145  
     146  bool HIDDEN
     147  __sync_bool_compare_and_swap_8 (long long *ptr, long long oldval,
     148  				 long long newval)
     149  {
     150    int failure = __kernel_cmpxchg64 (&oldval, &newval, ptr);
     151    return (failure == 0);
     152  }
     153  
     154  long long HIDDEN
     155  __sync_lock_test_and_set_8 (long long *ptr, long long val)
     156  {
     157    int failure;
     158    long long oldval;
     159  
     160    do {
     161      oldval = *ptr;
     162      failure = __kernel_cmpxchg64 (&oldval, &val, ptr);
     163    } while (failure != 0);
     164  
     165    return oldval;
     166  }