3 # DP: Atomic builtins using kernel helpers for ARM Linux/EABI.
6 if [ $# -eq 3 -a "$2" = '-d' ]; then
9 elif [ $# -ne 1 ]; then
10 echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
15 patch $pdir -f --no-backup-if-mismatch -p0 < $0
18 patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
21 echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
26 This patch implements the atomic builtins described at:
28 http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Atomic-Builtins.html
30 for ARM EABI Linux. This implementation uses the kernel helpers
31 __kernel_cmpxchg and __kernel_dmb, and so should work on any
32 architecture which supports those. (More-efficient versions are possible
33 using ldrex/strex on architectures >=v6, but those are not written yet.)
35 Atomic operations are provided for data sizes of 1, 2 and 4 bytes (but
36 not 8 bytes). The implementation uses actual functions
37 (__sync_fetch_and_add_2, etc.) rather than expanding code inline.
39 Tested with cross to arm-none-linux-gnueabi, and with some additional
40 hand-written tests which hopefully exercised the atomicity of the
41 operations sufficiently.
50 * config/arm/t-linux-eabi (LIB2FUNCS_STATIC_EXTRA): Add
51 config/arm/linux-atomic.c.
52 * config/arm/linux-atomic.c: New.
54 Index: gcc/config/arm/linux-atomic.c
55 ===================================================================
56 --- gcc/config/arm/linux-atomic.c (revision 0)
57 +++ gcc/config/arm/linux-atomic.c (revision 0)
59 +/* Linux-specific atomic operations for ARM EABI.
60 + Copyright (C) 2008 Free Software Foundation, Inc.
61 + Contributed by CodeSourcery.
63 +This file is part of GCC.
65 +GCC is free software; you can redistribute it and/or modify it under
66 +the terms of the GNU General Public License as published by the Free
67 +Software Foundation; either version 2, or (at your option) any later
70 +In addition to the permissions in the GNU General Public License, the
71 +Free Software Foundation gives you unlimited permission to link the
72 +compiled version of this file into combinations with other programs,
73 +and to distribute those combinations without any restriction coming
74 +from the use of this file. (The General Public License restrictions
75 +do apply in other respects; for example, they cover modification of
76 +the file, and distribution when not linked into a combine
79 +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
80 +WARRANTY; without even the implied warranty of MERCHANTABILITY or
81 +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
84 +You should have received a copy of the GNU General Public License
85 +along with GCC; see the file COPYING. If not, write to the Free
86 +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
89 +/* Kernel helper for compare-and-exchange. */
90 +typedef int (__kernel_cmpxchg_t) (int oldval, int newval, int *ptr);
91 +#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0)
93 +/* Kernel helper for memory barrier. */
94 +typedef void (__kernel_dmb_t) (void);
95 +#define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0)
97 +/* Note: we implement byte, short and int versions of atomic operations using
98 + the above kernel helpers, but there is no support for "long long" (64-bit)
99 + operations as yet. */
101 +#define HIDDEN __attribute__ ((visibility ("hidden")))
104 +#define INVERT_MASK_1 0
105 +#define INVERT_MASK_2 0
107 +#define INVERT_MASK_1 24
108 +#define INVERT_MASK_2 16
111 +#define MASK_1 0xffu
112 +#define MASK_2 0xffffu
114 +#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \
116 + __sync_fetch_and_##OP##_4 (int *ptr, int val) \
118 + int failure, tmp; \
122 + failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \
123 + } while (failure != 0); \
128 +FETCH_AND_OP_WORD (add, , +)
129 +FETCH_AND_OP_WORD (sub, , -)
130 +FETCH_AND_OP_WORD (or, , |)
131 +FETCH_AND_OP_WORD (and, , &)
132 +FETCH_AND_OP_WORD (xor, , ^)
133 +FETCH_AND_OP_WORD (nand, ~, &)
135 +#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
136 +#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
138 +/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
139 + subword-sized quantities. */
141 +#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \
143 + NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \
145 + int *wordptr = (int *) ((unsigned int) ptr & ~3); \
146 + unsigned int mask, shift, oldval, newval; \
149 + shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
150 + mask = MASK_##WIDTH << shift; \
153 + oldval = *wordptr; \
154 + newval = ((PFX_OP ((oldval & mask) >> shift) \
155 + INF_OP (unsigned int) val) << shift) & mask; \
156 + newval |= oldval & ~mask; \
157 + failure = __kernel_cmpxchg (oldval, newval, wordptr); \
158 + } while (failure != 0); \
160 + return (RETURN & mask) >> shift; \
163 +SUBWORD_SYNC_OP (add, , +, short, 2, oldval)
164 +SUBWORD_SYNC_OP (sub, , -, short, 2, oldval)
165 +SUBWORD_SYNC_OP (or, , |, short, 2, oldval)
166 +SUBWORD_SYNC_OP (and, , &, short, 2, oldval)
167 +SUBWORD_SYNC_OP (xor, , ^, short, 2, oldval)
168 +SUBWORD_SYNC_OP (nand, ~, &, short, 2, oldval)
170 +SUBWORD_SYNC_OP (add, , +, char, 1, oldval)
171 +SUBWORD_SYNC_OP (sub, , -, char, 1, oldval)
172 +SUBWORD_SYNC_OP (or, , |, char, 1, oldval)
173 +SUBWORD_SYNC_OP (and, , &, char, 1, oldval)
174 +SUBWORD_SYNC_OP (xor, , ^, char, 1, oldval)
175 +SUBWORD_SYNC_OP (nand, ~, &, char, 1, oldval)
177 +#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \
179 + __sync_##OP##_and_fetch_4 (int *ptr, int val) \
181 + int tmp, failure; \
185 + failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \
186 + } while (failure != 0); \
188 + return PFX_OP tmp INF_OP val; \
191 +OP_AND_FETCH_WORD (add, , +)
192 +OP_AND_FETCH_WORD (sub, , -)
193 +OP_AND_FETCH_WORD (or, , |)
194 +OP_AND_FETCH_WORD (and, , &)
195 +OP_AND_FETCH_WORD (xor, , ^)
196 +OP_AND_FETCH_WORD (nand, ~, &)
198 +SUBWORD_SYNC_OP (add, , +, short, 2, newval)
199 +SUBWORD_SYNC_OP (sub, , -, short, 2, newval)
200 +SUBWORD_SYNC_OP (or, , |, short, 2, newval)
201 +SUBWORD_SYNC_OP (and, , &, short, 2, newval)
202 +SUBWORD_SYNC_OP (xor, , ^, short, 2, newval)
203 +SUBWORD_SYNC_OP (nand, ~, &, short, 2, newval)
205 +SUBWORD_SYNC_OP (add, , +, char, 1, newval)
206 +SUBWORD_SYNC_OP (sub, , -, char, 1, newval)
207 +SUBWORD_SYNC_OP (or, , |, char, 1, newval)
208 +SUBWORD_SYNC_OP (and, , &, char, 1, newval)
209 +SUBWORD_SYNC_OP (xor, , ^, char, 1, newval)
210 +SUBWORD_SYNC_OP (nand, ~, &, char, 1, newval)
213 +__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
215 + int actual_oldval, fail;
219 + actual_oldval = *ptr;
221 + if (oldval != actual_oldval)
222 + return actual_oldval;
224 + fail = __kernel_cmpxchg (actual_oldval, newval, ptr);
231 +#define SUBWORD_VAL_CAS(TYPE, WIDTH) \
233 + __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
236 + int *wordptr = (int *)((unsigned int) ptr & ~3), fail; \
237 + unsigned int mask, shift, actual_oldval, actual_newval; \
239 + shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
240 + mask = MASK_##WIDTH << shift; \
244 + actual_oldval = *wordptr; \
246 + if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \
247 + return (actual_oldval & mask) >> shift; \
249 + actual_newval = (actual_oldval & ~mask) \
250 + | (((unsigned int) newval << shift) & mask); \
252 + fail = __kernel_cmpxchg (actual_oldval, actual_newval, \
260 +SUBWORD_VAL_CAS (short, 2)
261 +SUBWORD_VAL_CAS (char, 1)
263 +typedef unsigned char bool;
266 +__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
268 + int failure = __kernel_cmpxchg (oldval, newval, ptr);
269 + return (failure == 0);
272 +#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \
274 + __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
277 + TYPE actual_oldval \
278 + = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \
279 + return (oldval == actual_oldval); \
282 +SUBWORD_BOOL_CAS (short, 2)
283 +SUBWORD_BOOL_CAS (char, 1)
286 +__sync_synchronize (void)
292 +__sync_lock_test_and_set_4 (int *ptr, int val)
294 + int failure, oldval;
298 + failure = __kernel_cmpxchg (oldval, val, ptr);
299 + } while (failure != 0);
304 +#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \
306 + __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
309 + unsigned int oldval, newval, shift, mask; \
310 + int *wordptr = (int *) ((unsigned int) ptr & ~3); \
312 + shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
313 + mask = MASK_##WIDTH << shift; \
316 + oldval = *wordptr; \
317 + newval = (oldval & ~mask) \
318 + | (((unsigned int) val << shift) & mask); \
319 + failure = __kernel_cmpxchg (oldval, newval, wordptr); \
320 + } while (failure != 0); \
322 + return (oldval & mask) >> shift; \
325 +SUBWORD_TEST_AND_SET (short, 2)
326 +SUBWORD_TEST_AND_SET (char, 1)
328 +#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
330 + __sync_lock_release_##WIDTH (TYPE *ptr) \
336 +SYNC_LOCK_RELEASE (int, 4)
337 +SYNC_LOCK_RELEASE (short, 2)
338 +SYNC_LOCK_RELEASE (char, 1)
339 Index: gcc/config/arm/t-linux-eabi
340 ===================================================================
341 --- gcc/config/arm/t-linux-eabi (revision 136167)
342 +++ gcc/config/arm/t-linux-eabi (working copy)
343 @@ -12,3 +12,5 @@ LIB1ASMFUNCS := $(filter-out _dvmd_tls,$
344 # Multilib the standard Linux files. Don't include crti.o or crtn.o,
345 # which are provided by glibc.
346 EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
348 +LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/arm/linux-atomic.c