Fix support for atomic loads and stores on hppa.
[official-gcc.git] / libgcc / config / pa / sync-libfuncs.c
blobc70be0fde73e555379da6083ce03875e2cc2f9e2
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>
7 This file is part of GCC.
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.
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.
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.
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/>. */
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
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. */
41 typedef volatile int __attribute__((aligned (16))) ldcw_t;
42 static ldcw_t __atomicity_lock = 1;
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
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
62 static inline void
63 __sync_spin_lock (void)
65 ldcw_t *lock = &__atomicity_lock;
66 int tmp;
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");
79 static inline void
80 __sync_spin_unlock (void)
82 ldcw_t *lock = &__atomicity_lock;
83 int tmp = 1;
85 /* Use ordered store for release. */
86 __asm__ __volatile__ ("stw,ma %1,0(%0)"
87 : : "r" (lock), "r" (tmp) : "memory");
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; \
98 #if defined(__LP64__) || defined(__SOFTFP__)
99 ATOMIC_LOAD (u64, 8)
100 #else
101 static inline u64
102 atomic_load_8 (volatile void *ptr)
104 u64 result;
105 double tmp;
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;
114 #endif
116 ATOMIC_LOAD (u32, 4)
117 ATOMIC_LOAD (u16, 2)
118 ATOMIC_LOAD (u8, 1)
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) \
125 *(volatile TYPE *)ptr = value; \
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)
134 double tmp;
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");
142 #endif
144 ATOMIC_STORE (u32, 4)
145 ATOMIC_STORE (u16, 2)
146 ATOMIC_STORE (u8, 1)
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) \
152 TYPE tmp, newval; \
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(); \
160 return tmp; \
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)
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)
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)
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)
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) \
195 TYPE tmp, newval; \
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(); \
203 return newval; \
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)
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)
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)
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)
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) \
239 TYPE actual_oldval; \
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(); \
247 return actual_oldval; \
250 _Bool VISIBILITY \
251 __sync_bool_compare_and_swap_##WIDTH (volatile void *ptr, \
252 TYPE oldval, TYPE newval) \
254 TYPE actual_oldval; \
255 _Bool result; \
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(); \
264 return result; \
267 COMPARE_AND_SWAP (u64, 8)
268 COMPARE_AND_SWAP (u32, 4)
269 COMPARE_AND_SWAP (u16, 2)
270 COMPARE_AND_SWAP (u8, 1)
272 #define SYNC_LOCK_TEST_AND_SET(TYPE, WIDTH) \
273 TYPE VISIBILITY \
274 __sync_lock_test_and_set_##WIDTH (volatile void *ptr, TYPE val) \
276 TYPE oldval; \
278 __sync_spin_lock(); \
279 oldval = atomic_load_##WIDTH (ptr); \
280 atomic_store_##WIDTH (ptr, val); \
281 __sync_spin_unlock(); \
283 return oldval; \
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)
291 #define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
292 void VISIBILITY \
293 __sync_lock_release_##WIDTH (volatile void *ptr) \
295 TYPE val = 0; \
297 __sync_spin_lock(); \
298 atomic_store_##WIDTH (ptr, val); \
299 __sync_spin_unlock(); \
302 SYNC_LOCK_RELEASE (u64, 8)
303 SYNC_LOCK_RELEASE (u32, 4)
304 SYNC_LOCK_RELEASE (u16, 2)
305 SYNC_LOCK_RELEASE (u8, 1)
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) \
312 TYPE oldval; \
314 __sync_spin_lock(); \
315 oldval = atomic_load_##WIDTH (ptr); \
316 __sync_spin_unlock(); \
318 return oldval; \
321 SYNC_LOCK_LOAD (u64, 8)
322 SYNC_LOCK_LOAD (u32, 4)
323 SYNC_LOCK_LOAD (u16, 2)
324 SYNC_LOCK_LOAD (u8, 1)