gcc: add support for builtin gcc-atomics for gcc-4.3.x versions
[openembedded.git] / recipes / gcc / gcc-4.3.3 / debian / armel-atomic-builtins.dpatch
1 #! /bin/sh -e
2
3 # DP: Atomic builtins using kernel helpers for ARM Linux/EABI.
4
5 dir=
6 if [ $# -eq 3 -a "$2" = '-d' ]; then
7     pdir="-d $3"
8     dir="$3/"
9 elif [ $# -ne 1 ]; then
10     echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
11     exit 1
12 fi
13 case "$1" in
14     -patch)
15         patch $pdir -f --no-backup-if-mismatch -p0 < $0
16         ;;
17     -unpatch)
18         patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
19         ;;
20     *)
21         echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
22         exit 1
23 esac
24 exit 0
25
26 This patch implements the atomic builtins described at:
27
28   http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Atomic-Builtins.html
29
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.)
34
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.
38
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.
42
43 OK for mainline?
44
45 Julian
46
47 ChangeLog
48
49     gcc/
50     * config/arm/t-linux-eabi (LIB2FUNCS_STATIC_EXTRA): Add
51     config/arm/linux-atomic.c.
52     * config/arm/linux-atomic.c: New.
53
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)
58 @@ -0,0 +1,280 @@
59 +/* Linux-specific atomic operations for ARM EABI.
60 +   Copyright (C) 2008 Free Software Foundation, Inc.
61 +   Contributed by CodeSourcery.
62 +
63 +This file is part of GCC.
64 +
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
68 +version.
69 +
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
77 +executable.)
78 +
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
82 +for more details.
83 +
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
87 +02110-1301, USA.  */
88 +
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)
92 +
93 +/* Kernel helper for memory barrier.  */
94 +typedef void (__kernel_dmb_t) (void);
95 +#define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0)
96 +
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.  */
100 +
101 +#define HIDDEN __attribute__ ((visibility ("hidden")))
102 +
103 +#ifdef __ARMEL__
104 +#define INVERT_MASK_1 0
105 +#define INVERT_MASK_2 0
106 +#else
107 +#define INVERT_MASK_1 24
108 +#define INVERT_MASK_2 16
109 +#endif
110 +
111 +#define MASK_1 0xffu
112 +#define MASK_2 0xffffu
113 +
114 +#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP)                          \
115 +  int HIDDEN                                                           \
116 +  __sync_fetch_and_##OP##_4 (int *ptr, int val)                                \
117 +  {                                                                    \
118 +    int failure, tmp;                                                  \
119 +                                                                       \
120 +    do {                                                               \
121 +      tmp = *ptr;                                                      \
122 +      failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr);    \
123 +    } while (failure != 0);                                            \
124 +                                                                       \
125 +    return tmp;                                                                \
126 +  }
127 +
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, ~, &)
134 +
135 +#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
136 +#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
137 +
138 +/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
139 +   subword-sized quantities.  */
140 +
141 +#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN)       \
142 +  TYPE HIDDEN                                                          \
143 +  NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val)                    \
144 +  {                                                                    \
145 +    int *wordptr = (int *) ((unsigned int) ptr & ~3);                  \
146 +    unsigned int mask, shift, oldval, newval;                          \
147 +    int failure;                                                       \
148 +                                                                       \
149 +    shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;     \
150 +    mask = MASK_##WIDTH << shift;                                      \
151 +                                                                       \
152 +    do {                                                               \
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);                                            \
159 +                                                                       \
160 +    return (RETURN & mask) >> shift;                                   \
161 +  }
162 +
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)
169 +
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)
176 +
177 +#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP)                          \
178 +  int HIDDEN                                                           \
179 +  __sync_##OP##_and_fetch_4 (int *ptr, int val)                                \
180 +  {                                                                    \
181 +    int tmp, failure;                                                  \
182 +                                                                       \
183 +    do {                                                               \
184 +      tmp = *ptr;                                                      \
185 +      failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr);    \
186 +    } while (failure != 0);                                            \
187 +                                                                       \
188 +    return PFX_OP tmp INF_OP val;                                      \
189 +  }
190 +
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, ~, &)
197 +
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)
204 +
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)
211 +
212 +int HIDDEN
213 +__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
214 +{
215 +  int actual_oldval, fail;
216 +    
217 +  while (1)
218 +    {
219 +      actual_oldval = *ptr;
220 +
221 +      if (oldval != actual_oldval)
222 +       return actual_oldval;
223 +
224 +      fail = __kernel_cmpxchg (actual_oldval, newval, ptr);
225 +  
226 +      if (!fail)
227 +        return oldval;
228 +    }
229 +}
230 +
231 +#define SUBWORD_VAL_CAS(TYPE, WIDTH)                                   \
232 +  TYPE HIDDEN                                                          \
233 +  __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,         \
234 +                                      TYPE newval)                     \
235 +  {                                                                    \
236 +    int *wordptr = (int *)((unsigned int) ptr & ~3), fail;             \
237 +    unsigned int mask, shift, actual_oldval, actual_newval;            \
238 +                                                                       \
239 +    shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;     \
240 +    mask = MASK_##WIDTH << shift;                                      \
241 +                                                                       \
242 +    while (1)                                                          \
243 +      {                                                                        \
244 +       actual_oldval = *wordptr;                                       \
245 +                                                                       \
246 +       if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \
247 +          return (actual_oldval & mask) >> shift;                      \
248 +                                                                       \
249 +       actual_newval = (actual_oldval & ~mask)                         \
250 +                       | (((unsigned int) newval << shift) & mask);    \
251 +                                                                       \
252 +       fail = __kernel_cmpxchg (actual_oldval, actual_newval,          \
253 +                                wordptr);                              \
254 +                                                                       \
255 +       if (!fail)                                                      \
256 +          return oldval;                                               \
257 +      }                                                                        \
258 +  }
259 +
260 +SUBWORD_VAL_CAS (short, 2)
261 +SUBWORD_VAL_CAS (char,  1)
262 +
263 +typedef unsigned char bool;
264 +
265 +bool HIDDEN
266 +__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
267 +{
268 +  int failure = __kernel_cmpxchg (oldval, newval, ptr);
269 +  return (failure == 0);
270 +}
271 +
272 +#define SUBWORD_BOOL_CAS(TYPE, WIDTH)                                  \
273 +  bool HIDDEN                                                          \
274 +  __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,                \
275 +                                       TYPE newval)                    \
276 +  {                                                                    \
277 +    TYPE actual_oldval                                                 \
278 +      = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval);     \
279 +    return (oldval == actual_oldval);                                  \
280 +  }
281 +
282 +SUBWORD_BOOL_CAS (short, 2)
283 +SUBWORD_BOOL_CAS (char,  1)
284 +
285 +void HIDDEN
286 +__sync_synchronize (void)
287 +{
288 +  __kernel_dmb ();
289 +}
290 +
291 +int HIDDEN
292 +__sync_lock_test_and_set_4 (int *ptr, int val)
293 +{
294 +  int failure, oldval;
295 +
296 +  do {
297 +    oldval = *ptr;
298 +    failure = __kernel_cmpxchg (oldval, val, ptr);
299 +  } while (failure != 0);
300 +
301 +  return oldval;
302 +}
303 +
304 +#define SUBWORD_TEST_AND_SET(TYPE, WIDTH)                              \
305 +  TYPE HIDDEN                                                          \
306 +  __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val)               \
307 +  {                                                                    \
308 +    int failure;                                                       \
309 +    unsigned int oldval, newval, shift, mask;                          \
310 +    int *wordptr = (int *) ((unsigned int) ptr & ~3);                  \
311 +                                                                       \
312 +    shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;     \
313 +    mask = MASK_##WIDTH << shift;                                      \
314 +                                                                       \
315 +    do {                                                               \
316 +      oldval = *wordptr;                                               \
317 +      newval = (oldval & ~mask)                                                \
318 +              | (((unsigned int) val << shift) & mask);                \
319 +      failure = __kernel_cmpxchg (oldval, newval, wordptr);            \
320 +    } while (failure != 0);                                            \
321 +                                                                       \
322 +    return (oldval & mask) >> shift;                                   \
323 +  }
324 +
325 +SUBWORD_TEST_AND_SET (short, 2)
326 +SUBWORD_TEST_AND_SET (char,  1)
327 +
328 +#define SYNC_LOCK_RELEASE(TYPE, WIDTH)                                 \
329 +  void HIDDEN                                                          \
330 +  __sync_lock_release_##WIDTH (TYPE *ptr)                              \
331 +  {                                                                    \
332 +    *ptr = 0;                                                          \
333 +    __kernel_dmb ();                                                   \
334 +  }
335 +
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
347 +
348 +LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/arm/linux-atomic.c
349
350