Amend log entry with omitted file.
[jlayton/glibc.git] / sysdeps / mips / bits / atomic.h
1 /* Low-level functions for atomic operations. Mips version.
2    Copyright (C) 2005 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #ifndef _MIPS_BITS_ATOMIC_H
21 #define _MIPS_BITS_ATOMIC_H 1
22
23 #include <inttypes.h>
24 #include <sgidefs.h>
25
26 typedef int32_t atomic32_t;
27 typedef uint32_t uatomic32_t;
28 typedef int_fast32_t atomic_fast32_t;
29 typedef uint_fast32_t uatomic_fast32_t;
30
31 typedef int64_t atomic64_t;
32 typedef uint64_t uatomic64_t;
33 typedef int_fast64_t atomic_fast64_t;
34 typedef uint_fast64_t uatomic_fast64_t;
35
36 typedef intptr_t atomicptr_t;
37 typedef uintptr_t uatomicptr_t;
38 typedef intmax_t atomic_max_t;
39 typedef uintmax_t uatomic_max_t;
40
41 #if _MIPS_SIM == _ABIO32
42 #define MIPS_PUSH_MIPS2 ".set   mips2\n\t"
43 #else
44 #define MIPS_PUSH_MIPS2
45 #endif
46
47 /* See the comments in <sys/asm.h> about the use of the sync instruction.  */
48 #ifndef MIPS_SYNC
49 # define MIPS_SYNC      sync
50 #endif
51
52 #define MIPS_SYNC_STR_2(X) #X
53 #define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
54 #define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
55
56 /* Compare and exchange.  For all of the "xxx" routines, we expect a
57    "__prev" and a "__cmp" variable to be provided by the enclosing scope,
58    in which values are returned.  */
59
60 #define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
61   (abort (), __prev = __cmp = 0)
62
63 #define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
64   (abort (), __prev = __cmp = 0)
65
66 #define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
67      __asm__ __volatile__ (                                                   \
68      ".set      push\n\t"                                                     \
69      MIPS_PUSH_MIPS2                                                          \
70      rel        "\n"                                                          \
71      "1:\t"                                                                   \
72      "ll        %0,%4\n\t"                                                    \
73      "move      %1,$0\n\t"                                                    \
74      "bne       %0,%2,2f\n\t"                                                 \
75      "move      %1,%3\n\t"                                                    \
76      "sc        %1,%4\n\t"                                                    \
77      "beqz      %1,1b\n"                                                      \
78      acq        "\n\t"                                                        \
79      ".set      pop\n"                                                        \
80      "2:\n\t"                                                                 \
81               : "=&r" (__prev), "=&r" (__cmp)                                 \
82               : "r" (oldval), "r" (newval), "m" (*mem)                        \
83               : "memory")
84
85 #if _MIPS_SIM == _ABIO32
86 /* We can't do an atomic 64-bit operation in O32.  */
87 #define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
88   (abort (), __prev = __cmp = 0)
89 #else
90 #define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
91      __asm__ __volatile__ ("\n"                                               \
92      ".set      push\n\t"                                                     \
93      MIPS_PUSH_MIPS2                                                          \
94      rel        "\n"                                                          \
95      "1:\t"                                                                   \
96      "lld       %0,%4\n\t"                                                    \
97      "move      %1,$0\n\t"                                                    \
98      "bne       %0,%2,2f\n\t"                                                 \
99      "move      %1,%3\n\t"                                                    \
100      "scd       %1,%4\n\t"                                                    \
101      "beqz      %1,1b\n"                                                      \
102      acq        "\n\t"                                                        \
103      ".set      pop\n"                                                        \
104      "2:\n\t"                                                                 \
105               : "=&r" (__prev), "=&r" (__cmp)                                 \
106               : "r" (oldval), "r" (newval), "m" (*mem)                        \
107               : "memory")
108 #endif
109
110 /* For all "bool" routines, we return FALSE if exchange succesful.  */
111
112 #define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq) \
113 ({ typeof (*mem) __prev; int __cmp;                                     \
114    __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);      \
115    !__cmp; })
116
117 #define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
118 ({ typeof (*mem) __prev; int __cmp;                                     \
119    __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);     \
120    !__cmp; })
121
122 #define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
123 ({ typeof (*mem) __prev; int __cmp;                                     \
124    __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);     \
125    !__cmp; })
126
127 #define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
128 ({ typeof (*mem) __prev; int __cmp;                                     \
129    __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);     \
130    !__cmp; })
131
132 /* For all "val" routines, return the old value whether exchange
133    successful or not.  */
134
135 #define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq)  \
136 ({ typeof (*mem) __prev; int __cmp;                                     \
137    __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);      \
138    (typeof (*mem))__prev; })
139
140 #define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
141 ({ typeof (*mem) __prev; int __cmp;                                     \
142    __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);     \
143    (typeof (*mem))__prev; })
144
145 #define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
146 ({ typeof (*mem) __prev; int __cmp;                                     \
147    __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);     \
148    (typeof (*mem))__prev; })
149
150 #define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
151 ({ typeof (*mem) __prev; int __cmp;                                     \
152    __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);     \
153    (typeof (*mem))__prev; })
154
155 /* Compare and exchange with "acquire" semantics, ie barrier after.  */
156
157 #define atomic_compare_and_exchange_bool_acq(mem, new, old)     \
158   __atomic_bool_bysize (__arch_compare_and_exchange_bool, int,  \
159                         mem, new, old, "", MIPS_SYNC_STR)
160
161 #define atomic_compare_and_exchange_val_acq(mem, new, old)      \
162   __atomic_val_bysize (__arch_compare_and_exchange_val, int,    \
163                        mem, new, old, "", MIPS_SYNC_STR)
164
165 /* Compare and exchange with "release" semantics, ie barrier before.  */
166
167 #define atomic_compare_and_exchange_bool_rel(mem, new, old)     \
168   __atomic_bool_bysize (__arch_compare_and_exchange_bool, int,  \
169                         mem, new, old, MIPS_SYNC_STR, "")
170
171 #define atomic_compare_and_exchange_val_rel(mem, new, old)      \
172   __atomic_val_bysize (__arch_compare_and_exchange_val, int,    \
173                        mem, new, old, MIPS_SYNC_STR, "")
174
175
176
177 /* Atomic exchange (without compare).  */
178
179 #define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
180   (abort (), 0)
181
182 #define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
183   (abort (), 0)
184
185 #define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
186 ({ typeof (*mem) __prev; int __cmp;                                           \
187      __asm__ __volatile__ ("\n"                                               \
188      ".set      push\n\t"                                                     \
189      MIPS_PUSH_MIPS2                                                          \
190      rel        "\n"                                                          \
191      "1:\t"                                                                   \
192      "ll        %0,%3\n\t"                                                    \
193      "move      %1,%2\n\t"                                                    \
194      "sc        %1,%3\n\t"                                                    \
195      "beqz      %1,1b\n"                                                      \
196      acq        "\n\t"                                                        \
197      ".set      pop\n"                                                        \
198      "2:\n\t"                                                                 \
199               : "=&r" (__prev), "=&r" (__cmp)                                 \
200               : "r" (newval), "m" (*mem)                                      \
201               : "memory");                                                    \
202   __prev; })
203
204 #if _MIPS_SIM == _ABIO32
205 /* We can't do an atomic 64-bit operation in O32.  */
206 #define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
207   (abort (), 0)
208 #else
209 #define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
210 ({ typeof (*mem) __prev; int __cmp;                                           \
211      __asm__ __volatile__ ("\n"                                               \
212      ".set      push\n\t"                                                     \
213      MIPS_PUSH_MIPS2                                                          \
214      rel        "\n"                                                          \
215      "1:\n"                                                                   \
216      "lld       %0,%3\n\t"                                                    \
217      "move      %1,%2\n\t"                                                    \
218      "scd       %1,%3\n\t"                                                    \
219      "beqz      %1,1b\n"                                                      \
220      acq        "\n\t"                                                        \
221      ".set      pop\n"                                                        \
222      "2:\n\t"                                                                 \
223               : "=&r" (__prev), "=&r" (__cmp)                                 \
224               : "r" (newval), "m" (*mem)                                      \
225               : "memory");                                                    \
226   __prev; })
227 #endif
228
229 #define atomic_exchange_acq(mem, value) \
230   __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
231
232 #define atomic_exchange_rel(mem, value) \
233   __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
234
235
236 /* Atomically add value and return the previous (unincremented) value.  */
237
238 #define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
239   (abort (), (typeof(*mem)) 0)
240
241 #define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
242   (abort (), (typeof(*mem)) 0)
243
244 #define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
245 ({ typeof (*mem) __prev; int __cmp;                                           \
246      __asm__ __volatile__ ("\n"                                               \
247      ".set      push\n\t"                                                     \
248      MIPS_PUSH_MIPS2                                                          \
249      rel        "\n"                                                          \
250      "1:\t"                                                                   \
251      "ll        %0,%3\n\t"                                                    \
252      "addu      %1,%0,%2\n\t"                                                 \
253      "sc        %1,%3\n\t"                                                    \
254      "beqz      %1,1b\n"                                                      \
255      acq        "\n\t"                                                        \
256      ".set      pop\n"                                                        \
257      "2:\n\t"                                                                 \
258               : "=&r" (__prev), "=&r" (__cmp)                                 \
259               : "r" (value), "m" (*mem)                                       \
260               : "memory");                                                    \
261   __prev; })
262
263 #if _MIPS_SIM == _ABIO32
264 /* We can't do an atomic 64-bit operation in O32.  */
265 #define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
266   (abort (), (typeof(*mem)) 0)
267 #else
268 #define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
269 ({ typeof (*mem) __prev; int __cmp;                                           \
270      __asm__ __volatile__ (                                                   \
271      ".set      push\n\t"                                                     \
272      MIPS_PUSH_MIPS2                                                          \
273      rel        "\n"                                                          \
274      "1:\t"                                                                   \
275      "lld       %0,%3\n\t"                                                    \
276      "daddu     %1,%0,%2\n\t"                                                 \
277      "scd       %1,%3\n\t"                                                    \
278      "beqz      %1,1b\n"                                                      \
279      acq        "\n\t"                                                        \
280      ".set      pop\n"                                                        \
281      "2:\n\t"                                                                 \
282               : "=&r" (__prev), "=&r" (__cmp)                                 \
283               : "r" (value), "m" (*mem)                                       \
284               : "memory");                                                    \
285   __prev; })
286 #endif
287
288 /* ??? Barrier semantics for atomic_exchange_and_add appear to be 
289    undefined.  Use full barrier for now, as that's safe.  */
290 #define atomic_exchange_and_add(mem, value) \
291   __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,              \
292                        MIPS_SYNC_STR, MIPS_SYNC_STR)
293
294 /* TODO: More atomic operations could be implemented efficiently; only the
295    basic requirements are done.  */
296
297 #define atomic_full_barrier() \
298   __asm__ __volatile__ (".set push\n\t"                                       \
299                         MIPS_PUSH_MIPS2                                       \
300                         MIPS_SYNC_STR "\n\t"                                  \
301                         ".set pop" : : : "memory")
302
303 #endif /* bits/atomic.h */