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