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