Home | History | Annotate | Line # | Download | only in pa
sync-libfuncs.c revision 1.1
      1 /* PA-RISC sync libfunc support.
      2    Copyright (C) 2008-2024 Free Software Foundation, Inc.
      3    Based on code contributed by CodeSourcery for ARM EABI Linux.
      4    Modifications for PA Linux by Helge Deller <deller (at) gmx.de>
      5    Revised for general use by John David Anglin <danglin (at) 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)
    325