Warning: This file is not a C or C++ file. It does not have highlighting.

1/* Atomic operations used inside libc. Linux/SH version.
2 Copyright (C) 2003-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#define __HAVE_64B_ATOMICS 0
20#define USE_ATOMIC_COMPILER_BUILTINS 0
21
22/* XXX Is this actually correct? */
23#define ATOMIC_EXCHANGE_USES_CAS 1
24
25/* SH kernel has implemented a gUSA ("g" User Space Atomicity) support
26 for the user space atomicity. The atomicity macros use this scheme.
27
28 Reference:
29 Niibe Yutaka, "gUSA: Simple and Efficient User Space Atomicity
30 Emulation with Little Kernel Modification", Linux Conference 2002,
31 Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in
32 Japanese).
33
34 B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for
35 Uniprocessors", Proceedings of the Fifth Architectural Support for
36 Programming Languages and Operating Systems (ASPLOS), pp. 223-233,
37 October 1992. http://www.cs.washington.edu/homes/bershad/Papers/Rcs.ps
38
39 SuperH ABI:
40 r15: -(size of atomic instruction sequence) < 0
41 r0: end point
42 r1: saved stack pointer
43*/
44
45#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
46 ({ __typeof (*(mem)) __result; \
47 __asm __volatile ("\
48 mova 1f,r0\n\
49 .align 2\n\
50 mov r15,r1\n\
51 mov #(0f-1f),r15\n\
52 0: mov.b @%1,%0\n\
53 cmp/eq %0,%3\n\
54 bf 1f\n\
55 mov.b %2,@%1\n\
56 1: mov r1,r15"\
57 : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \
58 : "r0", "r1", "t", "memory"); \
59 __result; })
60
61#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
62 ({ __typeof (*(mem)) __result; \
63 __asm __volatile ("\
64 mova 1f,r0\n\
65 mov r15,r1\n\
66 .align 2\n\
67 mov #(0f-1f),r15\n\
68 mov #-8,r15\n\
69 0: mov.w @%1,%0\n\
70 cmp/eq %0,%3\n\
71 bf 1f\n\
72 mov.w %2,@%1\n\
73 1: mov r1,r15"\
74 : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \
75 : "r0", "r1", "t", "memory"); \
76 __result; })
77
78#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
79 ({ __typeof (*(mem)) __result; \
80 __asm __volatile ("\
81 mova 1f,r0\n\
82 .align 2\n\
83 mov r15,r1\n\
84 mov #(0f-1f),r15\n\
85 0: mov.l @%1,%0\n\
86 cmp/eq %0,%3\n\
87 bf 1f\n\
88 mov.l %2,@%1\n\
89 1: mov r1,r15"\
90 : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \
91 : "r0", "r1", "t", "memory"); \
92 __result; })
93
94/* XXX We do not really need 64-bit compare-and-exchange. At least
95 not in the moment. Using it would mean causing portability
96 problems since not many other 32-bit architectures have support for
97 such an operation. So don't define any code for now. */
98
99# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
100 (abort (), (__typeof (*mem)) 0)
101
102#define atomic_exchange_and_add(mem, value) \
103 ({ __typeof (*(mem)) __result, __tmp, __value = (value); \
104 if (sizeof (*(mem)) == 1) \
105 __asm __volatile ("\
106 mova 1f,r0\n\
107 .align 2\n\
108 mov r15,r1\n\
109 mov #(0f-1f),r15\n\
110 0: mov.b @%2,%0\n\
111 mov %1,r2\n\
112 add %0,r2\n\
113 mov.b r2,@%2\n\
114 1: mov r1,r15"\
115 : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
116 : "r0", "r1", "r2", "memory"); \
117 else if (sizeof (*(mem)) == 2) \
118 __asm __volatile ("\
119 mova 1f,r0\n\
120 .align 2\n\
121 mov r15,r1\n\
122 mov #(0f-1f),r15\n\
123 0: mov.w @%2,%0\n\
124 mov %1,r2\n\
125 add %0,r2\n\
126 mov.w r2,@%2\n\
127 1: mov r1,r15"\
128 : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
129 : "r0", "r1", "r2", "memory"); \
130 else if (sizeof (*(mem)) == 4) \
131 __asm __volatile ("\
132 mova 1f,r0\n\
133 .align 2\n\
134 mov r15,r1\n\
135 mov #(0f-1f),r15\n\
136 0: mov.l @%2,%0\n\
137 mov %1,r2\n\
138 add %0,r2\n\
139 mov.l r2,@%2\n\
140 1: mov r1,r15"\
141 : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
142 : "r0", "r1", "r2", "memory"); \
143 else \
144 { \
145 __typeof (mem) memp = (mem); \
146 do \
147 __result = *memp; \
148 while (__arch_compare_and_exchange_val_64_acq \
149 (memp, __result + __value, __result) == __result); \
150 (void) __value; \
151 } \
152 __result; })
153
154#define atomic_add(mem, value) \
155 (void) ({ __typeof (*(mem)) __tmp, __value = (value); \
156 if (sizeof (*(mem)) == 1) \
157 __asm __volatile ("\
158 mova 1f,r0\n\
159 mov r15,r1\n\
160 .align 2\n\
161 mov #(0f-1f),r15\n\
162 0: mov.b @%1,r2\n\
163 add %0,r2\n\
164 mov.b r2,@%1\n\
165 1: mov r1,r15"\
166 : "=&r" (__tmp) : "u" (mem), "0" (__value) \
167 : "r0", "r1", "r2", "memory"); \
168 else if (sizeof (*(mem)) == 2) \
169 __asm __volatile ("\
170 mova 1f,r0\n\
171 mov r15,r1\n\
172 .align 2\n\
173 mov #(0f-1f),r15\n\
174 0: mov.w @%1,r2\n\
175 add %0,r2\n\
176 mov.w r2,@%1\n\
177 1: mov r1,r15"\
178 : "=&r" (__tmp) : "u" (mem), "0" (__value) \
179 : "r0", "r1", "r2", "memory"); \
180 else if (sizeof (*(mem)) == 4) \
181 __asm __volatile ("\
182 mova 1f,r0\n\
183 mov r15,r1\n\
184 .align 2\n\
185 mov #(0f-1f),r15\n\
186 0: mov.l @%1,r2\n\
187 add %0,r2\n\
188 mov.l r2,@%1\n\
189 1: mov r1,r15"\
190 : "=&r" (__tmp) : "u" (mem), "0" (__value) \
191 : "r0", "r1", "r2", "memory"); \
192 else \
193 { \
194 __typeof (*(mem)) oldval; \
195 __typeof (mem) memp = (mem); \
196 do \
197 oldval = *memp; \
198 while (__arch_compare_and_exchange_val_64_acq \
199 (memp, oldval + __value, oldval) == oldval); \
200 (void) __value; \
201 } \
202 })
203
204#define atomic_add_negative(mem, value) \
205 ({ unsigned char __result; \
206 __typeof (*(mem)) __tmp, __value = (value); \
207 if (sizeof (*(mem)) == 1) \
208 __asm __volatile ("\
209 mova 1f,r0\n\
210 mov r15,r1\n\
211 .align 2\n\
212 mov #(0f-1f),r15\n\
213 0: mov.b @%2,r2\n\
214 add %1,r2\n\
215 mov.b r2,@%2\n\
216 1: mov r1,r15\n\
217 shal r2\n\
218 movt %0"\
219 : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
220 : "r0", "r1", "r2", "t", "memory"); \
221 else if (sizeof (*(mem)) == 2) \
222 __asm __volatile ("\
223 mova 1f,r0\n\
224 mov r15,r1\n\
225 .align 2\n\
226 mov #(0f-1f),r15\n\
227 0: mov.w @%2,r2\n\
228 add %1,r2\n\
229 mov.w r2,@%2\n\
230 1: mov r1,r15\n\
231 shal r2\n\
232 movt %0"\
233 : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
234 : "r0", "r1", "r2", "t", "memory"); \
235 else if (sizeof (*(mem)) == 4) \
236 __asm __volatile ("\
237 mova 1f,r0\n\
238 mov r15,r1\n\
239 .align 2\n\
240 mov #(0f-1f),r15\n\
241 0: mov.l @%2,r2\n\
242 add %1,r2\n\
243 mov.l r2,@%2\n\
244 1: mov r1,r15\n\
245 shal r2\n\
246 movt %0"\
247 : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
248 : "r0", "r1", "r2", "t", "memory"); \
249 else \
250 abort (); \
251 __result; })
252
253#define atomic_add_zero(mem, value) \
254 ({ unsigned char __result; \
255 __typeof (*(mem)) __tmp, __value = (value); \
256 if (sizeof (*(mem)) == 1) \
257 __asm __volatile ("\
258 mova 1f,r0\n\
259 mov r15,r1\n\
260 .align 2\n\
261 mov #(0f-1f),r15\n\
262 0: mov.b @%2,r2\n\
263 add %1,r2\n\
264 mov.b r2,@%2\n\
265 1: mov r1,r15\n\
266 tst r2,r2\n\
267 movt %0"\
268 : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
269 : "r0", "r1", "r2", "t", "memory"); \
270 else if (sizeof (*(mem)) == 2) \
271 __asm __volatile ("\
272 mova 1f,r0\n\
273 mov r15,r1\n\
274 .align 2\n\
275 mov #(0f-1f),r15\n\
276 0: mov.w @%2,r2\n\
277 add %1,r2\n\
278 mov.w r2,@%2\n\
279 1: mov r1,r15\n\
280 tst r2,r2\n\
281 movt %0"\
282 : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
283 : "r0", "r1", "r2", "t", "memory"); \
284 else if (sizeof (*(mem)) == 4) \
285 __asm __volatile ("\
286 mova 1f,r0\n\
287 mov r15,r1\n\
288 .align 2\n\
289 mov #(0f-1f),r15\n\
290 0: mov.l @%2,r2\n\
291 add %1,r2\n\
292 mov.l r2,@%2\n\
293 1: mov r1,r15\n\
294 tst r2,r2\n\
295 movt %0"\
296 : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \
297 : "r0", "r1", "r2", "t", "memory"); \
298 else \
299 abort (); \
300 __result; })
301
302#define atomic_increment_and_test(mem) atomic_add_zero((mem), 1)
303#define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1)
304
305#define atomic_bit_set(mem, bit) \
306 (void) ({ unsigned int __mask = 1 << (bit); \
307 if (sizeof (*(mem)) == 1) \
308 __asm __volatile ("\
309 mova 1f,r0\n\
310 mov r15,r1\n\
311 .align 2\n\
312 mov #(0f-1f),r15\n\
313 0: mov.b @%0,r2\n\
314 or %1,r2\n\
315 mov.b r2,@%0\n\
316 1: mov r1,r15"\
317 : : "u" (mem), "u" (__mask) \
318 : "r0", "r1", "r2", "memory"); \
319 else if (sizeof (*(mem)) == 2) \
320 __asm __volatile ("\
321 mova 1f,r0\n\
322 mov r15,r1\n\
323 .align 2\n\
324 mov #(0f-1f),r15\n\
325 0: mov.w @%0,r2\n\
326 or %1,r2\n\
327 mov.w r2,@%0\n\
328 1: mov r1,r15"\
329 : : "u" (mem), "u" (__mask) \
330 : "r0", "r1", "r2", "memory"); \
331 else if (sizeof (*(mem)) == 4) \
332 __asm __volatile ("\
333 mova 1f,r0\n\
334 mov r15,r1\n\
335 .align 2\n\
336 mov #(0f-1f),r15\n\
337 0: mov.l @%0,r2\n\
338 or %1,r2\n\
339 mov.l r2,@%0\n\
340 1: mov r1,r15"\
341 : : "u" (mem), "u" (__mask) \
342 : "r0", "r1", "r2", "memory"); \
343 else \
344 abort (); \
345 })
346
347#define atomic_bit_test_set(mem, bit) \
348 ({ unsigned int __mask = 1 << (bit); \
349 unsigned int __result = __mask; \
350 if (sizeof (*(mem)) == 1) \
351 __asm __volatile ("\
352 mova 1f,r0\n\
353 .align 2\n\
354 mov r15,r1\n\
355 mov #(0f-1f),r15\n\
356 0: mov.b @%2,r2\n\
357 mov r2,r3\n\
358 or %1,r2\n\
359 mov.b r2,@%2\n\
360 1: mov r1,r15\n\
361 and r3,%0"\
362 : "=&r" (__result), "=&r" (__mask) \
363 : "u" (mem), "0" (__result), "1" (__mask) \
364 : "r0", "r1", "r2", "r3", "memory"); \
365 else if (sizeof (*(mem)) == 2) \
366 __asm __volatile ("\
367 mova 1f,r0\n\
368 .align 2\n\
369 mov r15,r1\n\
370 mov #(0f-1f),r15\n\
371 0: mov.w @%2,r2\n\
372 mov r2,r3\n\
373 or %1,r2\n\
374 mov.w %1,@%2\n\
375 1: mov r1,r15\n\
376 and r3,%0"\
377 : "=&r" (__result), "=&r" (__mask) \
378 : "u" (mem), "0" (__result), "1" (__mask) \
379 : "r0", "r1", "r2", "r3", "memory"); \
380 else if (sizeof (*(mem)) == 4) \
381 __asm __volatile ("\
382 mova 1f,r0\n\
383 .align 2\n\
384 mov r15,r1\n\
385 mov #(0f-1f),r15\n\
386 0: mov.l @%2,r2\n\
387 mov r2,r3\n\
388 or r2,%1\n\
389 mov.l %1,@%2\n\
390 1: mov r1,r15\n\
391 and r3,%0"\
392 : "=&r" (__result), "=&r" (__mask) \
393 : "u" (mem), "0" (__result), "1" (__mask) \
394 : "r0", "r1", "r2", "r3", "memory"); \
395 else \
396 abort (); \
397 __result; })
398

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of glibc/sysdeps/unix/sysv/linux/sh/atomic-machine.h