Merge branch 'vendor/GCC50' - gcc 5.0 snapshot 1 FEB 2015
[dragonfly.git] / contrib / gcc-5.0 / libgcc / config / nios2 / linux-atomic.c
1 /* Linux-specific atomic operations for Nios II Linux.
2    Copyright (C) 2008-2015 Free Software Foundation, Inc.
3
4 This file is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3, or (at your option) any
7 later version.
8
9 This file is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 General Public License for more details.
13
14 Under Section 7 of GPL version 3, you are granted additional
15 permissions described in the GCC Runtime Library Exception, version
16 3.1, as published by the Free Software Foundation.
17
18 You should have received a copy of the GNU General Public License and
19 a copy of the GCC Runtime Library Exception along with this program;
20 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
21 <http://www.gnu.org/licenses/>.  */
22
23 #include <asm/unistd.h>
24 #define EFAULT  14
25 #define EBUSY   16
26 #define ENOSYS  38
27
28 /* We implement byte, short and int versions of each atomic operation
29    using the kernel helper defined below.  There is no support for
30    64-bit operations yet.  */
31
32 /* Crash a userspace program with SIGSEV.  */
33 #define ABORT_INSTRUCTION asm ("stw zero, 0(zero)")
34
35 /* Kernel helper for compare-and-exchange a 32-bit value.  */
36 static inline long
37 __kernel_cmpxchg (int oldval, int newval, int *mem)
38 {
39   register int r2 asm ("r2");
40   register int *r4 asm ("r4") = mem;
41   register int r5 asm ("r5") = oldval;
42   register int r6 asm ("r6") = newval;
43
44   /* Call the kernel provided fixed address cmpxchg helper routine.  */
45   asm volatile ("movi %0, %4\n\t"
46                 "callr %0\n"
47                 : "=r" (r2)
48                 : "r" (r4), "r" (r5), "r" (r6), "I" (0x00001004)
49                 : "ra", "memory");
50   return r2;
51 }
52
53 #define HIDDEN __attribute__ ((visibility ("hidden")))
54
55 #ifdef __nios2_little_endian__
56 #define INVERT_MASK_1 0
57 #define INVERT_MASK_2 0
58 #else
59 #define INVERT_MASK_1 24
60 #define INVERT_MASK_2 16
61 #endif
62
63 #define MASK_1 0xffu
64 #define MASK_2 0xffffu
65
66 #define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP)                           \
67   int HIDDEN                                                            \
68   __sync_fetch_and_##OP##_4 (int *ptr, int val)                         \
69   {                                                                     \
70     int failure, tmp;                                                   \
71                                                                         \
72     do {                                                                \
73       tmp = *ptr;                                                       \
74       failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr);   \
75     } while (failure != 0);                                             \
76                                                                         \
77     return tmp;                                                         \
78   }
79
80 FETCH_AND_OP_WORD (add,   , +)
81 FETCH_AND_OP_WORD (sub,   , -)
82 FETCH_AND_OP_WORD (or,    , |)
83 FETCH_AND_OP_WORD (and,   , &)
84 FETCH_AND_OP_WORD (xor,   , ^)
85 FETCH_AND_OP_WORD (nand, ~, &)
86
87 #define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
88 #define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
89
90 /* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
91    subword-sized quantities.  */
92
93 #define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN)        \
94   TYPE HIDDEN                                                           \
95   NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val)                     \
96   {                                                                     \
97     int *wordptr = (int *) ((unsigned long) ptr & ~3);                  \
98     unsigned int mask, shift, oldval, newval;                           \
99     int failure;                                                        \
100                                                                         \
101     shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;     \
102     mask = MASK_##WIDTH << shift;                                       \
103                                                                         \
104     do {                                                                \
105       oldval = *wordptr;                                                \
106       newval = ((PFX_OP (((oldval & mask) >> shift)                     \
107                          INF_OP (unsigned int) val)) << shift) & mask;  \
108       newval |= oldval & ~mask;                                         \
109       failure = __kernel_cmpxchg (oldval, newval, wordptr);             \
110     } while (failure != 0);                                             \
111                                                                         \
112     return (RETURN & mask) >> shift;                                    \
113   }
114
115 SUBWORD_SYNC_OP (add,   , +, unsigned short, 2, oldval)
116 SUBWORD_SYNC_OP (sub,   , -, unsigned short, 2, oldval)
117 SUBWORD_SYNC_OP (or,    , |, unsigned short, 2, oldval)
118 SUBWORD_SYNC_OP (and,   , &, unsigned short, 2, oldval)
119 SUBWORD_SYNC_OP (xor,   , ^, unsigned short, 2, oldval)
120 SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval)
121
122 SUBWORD_SYNC_OP (add,   , +, unsigned char, 1, oldval)
123 SUBWORD_SYNC_OP (sub,   , -, unsigned char, 1, oldval)
124 SUBWORD_SYNC_OP (or,    , |, unsigned char, 1, oldval)
125 SUBWORD_SYNC_OP (and,   , &, unsigned char, 1, oldval)
126 SUBWORD_SYNC_OP (xor,   , ^, unsigned char, 1, oldval)
127 SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval)
128
129 #define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP)                           \
130   int HIDDEN                                                            \
131   __sync_##OP##_and_fetch_4 (int *ptr, int val)                         \
132   {                                                                     \
133     int tmp, failure;                                                   \
134                                                                         \
135     do {                                                                \
136       tmp = *ptr;                                                       \
137       failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr);   \
138     } while (failure != 0);                                             \
139                                                                         \
140     return PFX_OP (tmp INF_OP val);                                     \
141   }
142
143 OP_AND_FETCH_WORD (add,   , +)
144 OP_AND_FETCH_WORD (sub,   , -)
145 OP_AND_FETCH_WORD (or,    , |)
146 OP_AND_FETCH_WORD (and,   , &)
147 OP_AND_FETCH_WORD (xor,   , ^)
148 OP_AND_FETCH_WORD (nand, ~, &)
149
150 SUBWORD_SYNC_OP (add,   , +, unsigned short, 2, newval)
151 SUBWORD_SYNC_OP (sub,   , -, unsigned short, 2, newval)
152 SUBWORD_SYNC_OP (or,    , |, unsigned short, 2, newval)
153 SUBWORD_SYNC_OP (and,   , &, unsigned short, 2, newval)
154 SUBWORD_SYNC_OP (xor,   , ^, unsigned short, 2, newval)
155 SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval)
156
157 SUBWORD_SYNC_OP (add,   , +, unsigned char, 1, newval)
158 SUBWORD_SYNC_OP (sub,   , -, unsigned char, 1, newval)
159 SUBWORD_SYNC_OP (or,    , |, unsigned char, 1, newval)
160 SUBWORD_SYNC_OP (and,   , &, unsigned char, 1, newval)
161 SUBWORD_SYNC_OP (xor,   , ^, unsigned char, 1, newval)
162 SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval)
163
164 int HIDDEN
165 __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
166 {
167   int actual_oldval, fail;
168     
169   while (1)
170     {
171       actual_oldval = *ptr;
172
173       if (oldval != actual_oldval)
174         return actual_oldval;
175
176       fail = __kernel_cmpxchg (actual_oldval, newval, ptr);
177   
178       if (!fail)
179         return oldval;
180     }
181 }
182
183 #define SUBWORD_VAL_CAS(TYPE, WIDTH)                                    \
184   TYPE HIDDEN                                                           \
185   __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,          \
186                                        TYPE newval)                     \
187   {                                                                     \
188     int *wordptr = (int *)((unsigned long) ptr & ~3), fail;             \
189     unsigned int mask, shift, actual_oldval, actual_newval;             \
190                                                                         \
191     shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;     \
192     mask = MASK_##WIDTH << shift;                                       \
193                                                                         \
194     while (1)                                                           \
195       {                                                                 \
196         actual_oldval = *wordptr;                                       \
197                                                                         \
198         if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \
199           return (actual_oldval & mask) >> shift;                       \
200                                                                         \
201         actual_newval = (actual_oldval & ~mask)                         \
202                         | (((unsigned int) newval << shift) & mask);    \
203                                                                         \
204         fail = __kernel_cmpxchg (actual_oldval, actual_newval,          \
205                                  wordptr);                              \
206                                                                         \
207         if (!fail)                                                      \
208           return oldval;                                                \
209       }                                                                 \
210   }
211
212 SUBWORD_VAL_CAS (unsigned short, 2)
213 SUBWORD_VAL_CAS (unsigned char,  1)
214
215 typedef unsigned char bool;
216
217 bool HIDDEN
218 __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
219 {
220   int failure = __kernel_cmpxchg (oldval, newval, ptr);
221   return (failure == 0);
222 }
223
224 #define SUBWORD_BOOL_CAS(TYPE, WIDTH)                                   \
225   bool HIDDEN                                                           \
226   __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,         \
227                                         TYPE newval)                    \
228   {                                                                     \
229     TYPE actual_oldval                                                  \
230       = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval);      \
231     return (oldval == actual_oldval);                                   \
232   }
233
234 SUBWORD_BOOL_CAS (unsigned short, 2)
235 SUBWORD_BOOL_CAS (unsigned char,  1)
236
237 int HIDDEN
238 __sync_lock_test_and_set_4 (int *ptr, int val)
239 {
240   int failure, oldval;
241
242   do {
243     oldval = *ptr;
244     failure = __kernel_cmpxchg (oldval, val, ptr);
245   } while (failure != 0);
246
247   return oldval;
248 }
249
250 #define SUBWORD_TEST_AND_SET(TYPE, WIDTH)                               \
251   TYPE HIDDEN                                                           \
252   __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val)                \
253   {                                                                     \
254     int failure;                                                        \
255     unsigned int oldval, newval, shift, mask;                           \
256     int *wordptr = (int *) ((unsigned long) ptr & ~3);                  \
257                                                                         \
258     shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;     \
259     mask = MASK_##WIDTH << shift;                                       \
260                                                                         \
261     do {                                                                \
262       oldval = *wordptr;                                                \
263       newval = (oldval & ~mask)                                         \
264                | (((unsigned int) val << shift) & mask);                \
265       failure = __kernel_cmpxchg (oldval, newval, wordptr);             \
266     } while (failure != 0);                                             \
267                                                                         \
268     return (oldval & mask) >> shift;                                    \
269   }
270
271 SUBWORD_TEST_AND_SET (unsigned short, 2)
272 SUBWORD_TEST_AND_SET (unsigned char,  1)
273
274 #define SYNC_LOCK_RELEASE(TYPE, WIDTH)                                  \
275   void HIDDEN                                                           \
276   __sync_lock_release_##WIDTH (TYPE *ptr)                               \
277   {                                                                     \
278     /* All writes before this point must be seen before we release      \
279        the lock itself.  */                                             \
280     __builtin_sync ();                                                  \
281     *ptr = 0;                                                           \
282   }
283
284 SYNC_LOCK_RELEASE (int,   4)
285 SYNC_LOCK_RELEASE (short, 2)
286 SYNC_LOCK_RELEASE (char,  1)