Daily bump.
[official-gcc.git] / libgcc / config / nios2 / linux-atomic.c
blob2e07baefb47183dbb780e0f6d675a29aabb03eec
1 /* Linux-specific atomic operations for Nios II Linux.
2 Copyright (C) 2008-2015 Free Software Foundation, Inc.
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.
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.
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.
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/>. */
23 #include <asm/unistd.h>
24 #define EFAULT 14
25 #define EBUSY 16
26 #define ENOSYS 38
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. */
32 /* Crash a userspace program with SIGSEV. */
33 #define ABORT_INSTRUCTION asm ("stw zero, 0(zero)")
35 /* Kernel helper for compare-and-exchange a 32-bit value. */
36 static inline long
37 __kernel_cmpxchg (int oldval, int newval, int *mem)
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;
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;
53 #define HIDDEN __attribute__ ((visibility ("hidden")))
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
63 #define MASK_1 0xffu
64 #define MASK_2 0xffffu
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; \
72 do { \
73 tmp = *ptr; \
74 failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \
75 } while (failure != 0); \
77 return tmp; \
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, ~, &)
87 #define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
88 #define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
90 /* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
91 subword-sized quantities. */
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; \
101 shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
102 mask = MASK_##WIDTH << shift; \
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); \
112 return (RETURN & mask) >> shift; \
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)
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)
129 #define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \
130 int HIDDEN \
131 __sync_##OP##_and_fetch_4 (int *ptr, int val) \
133 int tmp, failure; \
135 do { \
136 tmp = *ptr; \
137 failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \
138 } while (failure != 0); \
140 return PFX_OP (tmp INF_OP val); \
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, ~, &)
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)
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)
164 int HIDDEN
165 __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
167 int actual_oldval, fail;
169 while (1)
171 actual_oldval = *ptr;
173 if (oldval != actual_oldval)
174 return actual_oldval;
176 fail = __kernel_cmpxchg (actual_oldval, newval, ptr);
178 if (!fail)
179 return oldval;
183 #define SUBWORD_VAL_CAS(TYPE, WIDTH) \
184 TYPE HIDDEN \
185 __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
186 TYPE newval) \
188 int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \
189 unsigned int mask, shift, actual_oldval, actual_newval; \
191 shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
192 mask = MASK_##WIDTH << shift; \
194 while (1) \
196 actual_oldval = *wordptr; \
198 if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \
199 return (actual_oldval & mask) >> shift; \
201 actual_newval = (actual_oldval & ~mask) \
202 | (((unsigned int) newval << shift) & mask); \
204 fail = __kernel_cmpxchg (actual_oldval, actual_newval, \
205 wordptr); \
207 if (!fail) \
208 return oldval; \
212 SUBWORD_VAL_CAS (unsigned short, 2)
213 SUBWORD_VAL_CAS (unsigned char, 1)
215 typedef unsigned char bool;
217 bool HIDDEN
218 __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
220 int failure = __kernel_cmpxchg (oldval, newval, ptr);
221 return (failure == 0);
224 #define SUBWORD_BOOL_CAS(TYPE, WIDTH) \
225 bool HIDDEN \
226 __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
227 TYPE newval) \
229 TYPE actual_oldval \
230 = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \
231 return (oldval == actual_oldval); \
234 SUBWORD_BOOL_CAS (unsigned short, 2)
235 SUBWORD_BOOL_CAS (unsigned char, 1)
237 int HIDDEN
238 __sync_lock_test_and_set_4 (int *ptr, int val)
240 int failure, oldval;
242 do {
243 oldval = *ptr;
244 failure = __kernel_cmpxchg (oldval, val, ptr);
245 } while (failure != 0);
247 return oldval;
250 #define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \
251 TYPE HIDDEN \
252 __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
254 int failure; \
255 unsigned int oldval, newval, shift, mask; \
256 int *wordptr = (int *) ((unsigned long) ptr & ~3); \
258 shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
259 mask = MASK_##WIDTH << shift; \
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); \
268 return (oldval & mask) >> shift; \
271 SUBWORD_TEST_AND_SET (unsigned short, 2)
272 SUBWORD_TEST_AND_SET (unsigned char, 1)
274 #define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
275 void HIDDEN \
276 __sync_lock_release_##WIDTH (TYPE *ptr) \
278 /* All writes before this point must be seen before we release \
279 the lock itself. */ \
280 __builtin_sync (); \
281 *ptr = 0; \
284 SYNC_LOCK_RELEASE (int, 4)
285 SYNC_LOCK_RELEASE (short, 2)
286 SYNC_LOCK_RELEASE (char, 1)