(root)/
gcc-13.2.0/
libgcc/
config/
pa/
sync-libfuncs.c
       1  /* PA-RISC sync libfunc support.
       2     Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3     Based on code contributed by CodeSourcery for ARM EABI Linux.
       4     Modifications for PA Linux by Helge Deller <deller@gmx.de>
       5     Revised for general use by John David Anglin <danglin@gcc.gnu.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  typedef unsigned char u8;
      29  typedef short unsigned int u16;
      30  typedef unsigned int u32;
      31  #ifdef __LP64__
      32  typedef long unsigned int u64;
      33  #else
      34  typedef long long unsigned int u64;
      35  #endif
      36  
      37  /* PA-RISC 2.0 supports out-of-order execution for loads and stores.
      38     Thus, we need to synchonize memory accesses.  For more info, see:
      39     "Advanced Performance Features of the 64-bit PA-8000" by Doug Hunt.  */
      40  
      41  typedef volatile int __attribute__((aligned (16))) ldcw_t;
      42  static ldcw_t __atomicity_lock = 1;
      43  
      44  /* We want default visibility for the sync routines.  */
      45  #undef VISIBILITY
      46  #if defined(__hpux__) && !defined(__LP64__)
      47  #define VISIBILITY
      48  #else
      49  #define VISIBILITY __attribute__ ((visibility ("default")))
      50  #endif
      51  
      52  /* Perform ldcw operation in cache when possible.  The ldcw instruction
      53     is a full barrier.  */
      54  #ifndef _PA_LDCW_INSN
      55  # ifdef _PA_RISC2_0
      56  # define _PA_LDCW_INSN "ldcw,co"
      57  # else
      58  # define _PA_LDCW_INSN "ldcw"
      59  # endif
      60  #endif
      61  
      62  static inline void
      63  __sync_spin_lock (void)
      64  {
      65    ldcw_t *lock = &__atomicity_lock;
      66    int tmp;
      67  
      68    __asm__ __volatile__ (_PA_LDCW_INSN " 0(%1),%0\n\t"
      69  			"cmpib,<>,n 0,%0,.+20\n\t"
      70  			"ldw,ma 0(%1),%0\n\t"
      71  			"cmpib,<> 0,%0,.-12\n\t"
      72  			"nop\n\t"
      73  			"b,n .-12"
      74  			: "=&r" (tmp)
      75  			: "r" (lock)
      76  			: "memory");
      77  }
      78  
      79  static inline void
      80  __sync_spin_unlock (void)
      81  {
      82    ldcw_t *lock = &__atomicity_lock;
      83    int tmp = 1;
      84  
      85    /* Use ordered store for release.  */
      86    __asm__ __volatile__ ("stw,ma %1,0(%0)"
      87  			: : "r" (lock), "r" (tmp) : "memory");
      88  }
      89  
      90  /* Load value with an atomic processor load if possible.  */
      91  #define ATOMIC_LOAD(TYPE, WIDTH)					\
      92    static inline TYPE							\
      93    atomic_load_##WIDTH (volatile void *ptr)				\
      94    {									\
      95      return *(volatile TYPE *)ptr;					\
      96    }
      97  
      98  #if defined(__LP64__) || defined(__SOFTFP__)
      99  ATOMIC_LOAD (u64, 8)
     100  #else
     101  static inline u64
     102  atomic_load_8 (volatile void *ptr)
     103  {
     104    u64 result;
     105    double tmp;
     106  
     107    asm volatile ("{fldds|fldd} 0(%2),%1\n\t"
     108  		"{fstds|fstd} %1,-16(%%sp)\n\t"
     109  		"{ldws|ldw} -16(%%sp),%0\n\t"
     110  		"{ldws|ldw} -12(%%sp),%R0"
     111  		: "=r" (result), "=f" (tmp) : "r" (ptr): "memory");
     112    return result;
     113  }
     114  #endif
     115  
     116  ATOMIC_LOAD (u32, 4)
     117  ATOMIC_LOAD (u16, 2)
     118  ATOMIC_LOAD (u8, 1)
     119  
     120  /* Store value with an atomic processor store if possible.  */
     121  #define ATOMIC_STORE(TYPE, WIDTH)					\
     122    static inline void							\
     123    atomic_store_##WIDTH (volatile void *ptr, TYPE value)			\
     124    {									\
     125      *(volatile TYPE *)ptr = value;					\
     126    }
     127  
     128  #if defined(__LP64__) || defined(__SOFTFP__)
     129  ATOMIC_STORE (u64, 8)
     130  #else
     131  static inline void
     132  atomic_store_8 (volatile void *ptr, u64 value)
     133  {
     134    double tmp;
     135  
     136    asm volatile ("stws|stw} %2,-16(%%sp)\n\t"
     137  		"{stws|stw} %R2,-12(%%sp)\n\t"
     138  		"{fldds|fldd} -16(%%sp),%1\n\t"
     139  		"{fstds|fstd} %1,0(%0)"
     140  		: "=m" (ptr), "=&f" (tmp) : "r" (value): "memory");
     141  }
     142  #endif
     143  
     144  ATOMIC_STORE (u32, 4)
     145  ATOMIC_STORE (u16, 2)
     146  ATOMIC_STORE (u8, 1)
     147  
     148  #define FETCH_AND_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH)			\
     149    TYPE VISIBILITY							\
     150    __sync_fetch_and_##OP##_##WIDTH (volatile void *ptr, TYPE val)	\
     151    {									\
     152      TYPE tmp, newval;							\
     153  									\
     154      __sync_spin_lock();							\
     155      tmp = atomic_load_##WIDTH (ptr);					\
     156      newval = PFX_OP (tmp INF_OP val);					\
     157      atomic_store_##WIDTH (ptr, newval);					\
     158      __sync_spin_unlock();						\
     159  									\
     160      return tmp;								\
     161    }
     162  
     163  FETCH_AND_OP (add,   , +, u64, 8)
     164  FETCH_AND_OP (sub,   , -, u64, 8)
     165  FETCH_AND_OP (or,    , |, u64, 8)
     166  FETCH_AND_OP (and,   , &, u64, 8)
     167  FETCH_AND_OP (xor,   , ^, u64, 8)
     168  FETCH_AND_OP (nand, ~, &, u64, 8)
     169  
     170  FETCH_AND_OP (add,   , +, u32, 4)
     171  FETCH_AND_OP (sub,   , -, u32, 4)
     172  FETCH_AND_OP (or,    , |, u32, 4)
     173  FETCH_AND_OP (and,   , &, u32, 4)
     174  FETCH_AND_OP (xor,   , ^, u32, 4)
     175  FETCH_AND_OP (nand, ~, &, u32, 4)
     176  
     177  FETCH_AND_OP (add,   , +, u16, 2)
     178  FETCH_AND_OP (sub,   , -, u16, 2)
     179  FETCH_AND_OP (or,    , |, u16, 2)
     180  FETCH_AND_OP (and,   , &, u16, 2)
     181  FETCH_AND_OP (xor,   , ^, u16, 2)
     182  FETCH_AND_OP (nand, ~, &, u16, 2)
     183  
     184  FETCH_AND_OP (add,   , +, u8, 1)
     185  FETCH_AND_OP (sub,   , -, u8, 1)
     186  FETCH_AND_OP (or,    , |, u8, 1)
     187  FETCH_AND_OP (and,   , &, u8, 1)
     188  FETCH_AND_OP (xor,   , ^, u8, 1)
     189  FETCH_AND_OP (nand, ~, &, u8, 1)
     190  
     191  #define OP_AND_FETCH(OP, PFX_OP, INF_OP, TYPE, WIDTH)			\
     192    TYPE VISIBILITY 							\
     193    __sync_##OP##_and_fetch_##WIDTH (volatile void *ptr, TYPE val)	\
     194    {									\
     195      TYPE tmp, newval;							\
     196  									\
     197      __sync_spin_lock();							\
     198      tmp = atomic_load_##WIDTH (ptr);					\
     199      newval = PFX_OP (tmp INF_OP val);					\
     200      atomic_store_##WIDTH (ptr, newval);					\
     201      __sync_spin_unlock();						\
     202  									\
     203      return newval;							\
     204    }
     205  
     206  OP_AND_FETCH (add,   , +, u64, 8)
     207  OP_AND_FETCH (sub,   , -, u64, 8)
     208  OP_AND_FETCH (or,    , |, u64, 8)
     209  OP_AND_FETCH (and,   , &, u64, 8)
     210  OP_AND_FETCH (xor,   , ^, u64, 8)
     211  OP_AND_FETCH (nand, ~, &, u64, 8)
     212  
     213  OP_AND_FETCH (add,   , +, u32, 4)
     214  OP_AND_FETCH (sub,   , -, u32, 4)
     215  OP_AND_FETCH (or,    , |, u32, 4)
     216  OP_AND_FETCH (and,   , &, u32, 4)
     217  OP_AND_FETCH (xor,   , ^, u32, 4)
     218  OP_AND_FETCH (nand, ~, &, u32, 4)
     219  
     220  OP_AND_FETCH (add,   , +, u16, 2)
     221  OP_AND_FETCH (sub,   , -, u16, 2)
     222  OP_AND_FETCH (or,    , |, u16, 2)
     223  OP_AND_FETCH (and,   , &, u16, 2)
     224  OP_AND_FETCH (xor,   , ^, u16, 2)
     225  OP_AND_FETCH (nand, ~, &, u16, 2)
     226  
     227  OP_AND_FETCH (add,   , +, u8, 1)
     228  OP_AND_FETCH (sub,   , -, u8, 1)
     229  OP_AND_FETCH (or,    , |, u8, 1)
     230  OP_AND_FETCH (and,   , &, u8, 1)
     231  OP_AND_FETCH (xor,   , ^, u8, 1)
     232  OP_AND_FETCH (nand, ~, &, u8, 1)
     233  
     234  #define COMPARE_AND_SWAP(TYPE, WIDTH)					\
     235    TYPE VISIBILITY 							\
     236    __sync_val_compare_and_swap_##WIDTH (volatile void *ptr, TYPE oldval,	\
     237  				       TYPE newval)			\
     238    {									\
     239      TYPE actual_oldval;							\
     240  									\
     241      __sync_spin_lock();							\
     242      actual_oldval = atomic_load_##WIDTH (ptr);				\
     243      if (actual_oldval == oldval)					\
     244        atomic_store_##WIDTH (ptr, newval);				\
     245      __sync_spin_unlock();						\
     246  									\
     247      return actual_oldval;						\
     248    }									\
     249  									\
     250    _Bool VISIBILITY							\
     251    __sync_bool_compare_and_swap_##WIDTH (volatile void *ptr,		\
     252  					TYPE oldval, TYPE newval)	\
     253    {									\
     254      TYPE actual_oldval;							\
     255      _Bool result;							\
     256  									\
     257      __sync_spin_lock();							\
     258      actual_oldval = atomic_load_##WIDTH (ptr);				\
     259      result = (actual_oldval == oldval);					\
     260      if (result)								\
     261        atomic_store_##WIDTH (ptr, newval);				\
     262      __sync_spin_unlock();						\
     263  									\
     264      return result;							\
     265    }
     266  
     267  COMPARE_AND_SWAP (u64, 8)
     268  COMPARE_AND_SWAP (u32, 4)
     269  COMPARE_AND_SWAP (u16, 2)
     270  COMPARE_AND_SWAP (u8, 1)
     271  
     272  #define SYNC_LOCK_TEST_AND_SET(TYPE, WIDTH)				\
     273  TYPE VISIBILITY 							\
     274    __sync_lock_test_and_set_##WIDTH (volatile void *ptr, TYPE val)	\
     275    {									\
     276      TYPE oldval;							\
     277  									\
     278      __sync_spin_lock();							\
     279      oldval = atomic_load_##WIDTH (ptr);					\
     280      atomic_store_##WIDTH (ptr, val);					\
     281      __sync_spin_unlock();						\
     282  									\
     283      return oldval;							\
     284    }
     285  
     286  SYNC_LOCK_TEST_AND_SET (u64, 8)
     287  SYNC_LOCK_TEST_AND_SET (u32, 4)
     288  SYNC_LOCK_TEST_AND_SET (u16, 2)
     289  SYNC_LOCK_TEST_AND_SET (u8, 1)
     290  
     291  #define SYNC_LOCK_RELEASE(TYPE, WIDTH)				\
     292    void VISIBILITY						\
     293    __sync_lock_release_##WIDTH (volatile void *ptr)		\
     294    {								\
     295      TYPE val = 0;						\
     296  								\
     297      __sync_spin_lock();						\
     298      atomic_store_##WIDTH (ptr, val);				\
     299      __sync_spin_unlock();					\
     300    }
     301  
     302  SYNC_LOCK_RELEASE (u64, 8)
     303  SYNC_LOCK_RELEASE (u32, 4)
     304  SYNC_LOCK_RELEASE (u16, 2)
     305  SYNC_LOCK_RELEASE (u8, 1)
     306  
     307  #define SYNC_LOCK_LOAD(TYPE, WIDTH)					\
     308  TYPE VISIBILITY __sync_lock_load_##WIDTH (volatile void *); 		\
     309  TYPE VISIBILITY 							\
     310    __sync_lock_load_##WIDTH (volatile void *ptr)				\
     311    {									\
     312      TYPE oldval;							\
     313  									\
     314      __sync_spin_lock();							\
     315      oldval = atomic_load_##WIDTH (ptr);					\
     316      __sync_spin_unlock();						\
     317  									\
     318      return oldval;							\
     319    }
     320  
     321  SYNC_LOCK_LOAD (u64, 8)
     322  SYNC_LOCK_LOAD (u32, 4)
     323  SYNC_LOCK_LOAD (u16, 2)
     324  SYNC_LOCK_LOAD (u8, 1)