summaryrefslogtreecommitdiffstats
path: root/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106845.patch
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106845.patch')
-rw-r--r--toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106845.patch1818
1 files changed, 0 insertions, 1818 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106845.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106845.patch
deleted file mode 100644
index 17cfd1068..000000000
--- a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106845.patch
+++ /dev/null
@@ -1,1818 +0,0 @@
12011-11-28 David Alan Gilbert <david.gilbert@linaro.org>
2
3 Backport from mainline (svn r19983):
4
5 2011-10-14 David Alan Gilbert <david.gilbert@linaro.org>
6
7 gcc/testsuite/
8 * gcc.dg/di-longlong64-sync-1.c: New test.
9 * gcc.dg/di-sync-multithread.c: New test.
10 * gcc.target/arm/di-longlong64-sync-withhelpers.c: New test.
11 * gcc.target/arm/di-longlong64-sync-withldrexd.c: New test.
12 * lib/target-supports.exp: (arm_arch_*_ok): Series of effective-target
13 tests for v5, v6, v6k, and v7-a, and add-options helpers.
14 (check_effective_target_arm_arm_ok): New helper.
15 (check_effective_target_sync_longlong): New helper.
16
172011-11-28 David Alan Gilbert <david.gilbert@linaro.org>
18
19 Backport from mainline (svn r19982):
20
21 2011-10-14 David Alan Gilbert <david.gilbert@linaro.org>
22
23 gcc/
24 * config/arm/linux-atomic-64bit.c: New (based on linux-atomic.c).
25 * config/arm/linux-atomic.c: Change comment to point to 64bit version.
26 (SYNC_LOCK_RELEASE): Instantiate 64bit version.
27 * config/arm/t-linux-eabi: Pull in linux-atomic-64bit.c.
28
292011-11-28 David Alan Gilbert <david.gilbert@linaro.org>
30
31 Backport from mainline (svn r19981):
32
33 2011-10-14 David Alan Gilbert <david.gilbert@linaro.org>
34
35 gcc/
36 * config/arm/arm.c (arm_output_ldrex): Support ldrexd.
37 (arm_output_strex): Support strexd.
38 (arm_output_it): New helper to output it in Thumb2 mode only.
39 (arm_output_sync_loop): Support DI mode. Change comment to
40 not support const_int.
41 (arm_expand_sync): Support DI mode.
42 * config/arm/arm.h (TARGET_HAVE_LDREXBHD): Split into LDREXBH
43 and LDREXD.
44 * config/arm/iterators.md (NARROW): move from sync.md.
45 (QHSD): New iterator for all current ARM integer modes.
46 (SIDI): New iterator for SI and DI modes only.
47 * config/arm/sync.md (sync_predtab): New mode_attr.
48 (sync_compare_and_swapsi): Fold into sync_compare_and_swap<mode>.
49 (sync_lock_test_and_setsi): Fold into sync_lock_test_and_setsi<mode>.
50 (sync_<sync_optab>si): Fold into sync_<sync_optab><mode>.
51 (sync_nandsi): Fold into sync_nand<mode>.
52 (sync_new_<sync_optab>si): Fold into sync_new_<sync_optab><mode>.
53 (sync_new_nandsi): Fold into sync_new_nand<mode>.
54 (sync_old_<sync_optab>si): Fold into sync_old_<sync_optab><mode>.
55 (sync_old_nandsi): Fold into sync_old_nand<mode>.
56 (sync_compare_and_swap<mode>): Support SI & DI.
57 (sync_lock_test_and_set<mode>): Likewise.
58 (sync_<sync_optab><mode>): Likewise.
59 (sync_nand<mode>): Likewise.
60 (sync_new_<sync_optab><mode>): Likewise.
61 (sync_new_nand<mode>): Likewise.
62 (sync_old_<sync_optab><mode>): Likewise.
63 (sync_old_nand<mode>): Likewise.
64 (arm_sync_compare_and_swapsi): Turn into iterator on SI & DI.
65 (arm_sync_lock_test_and_setsi): Likewise.
66 (arm_sync_new_<sync_optab>si): Likewise.
67 (arm_sync_new_nandsi): Likewise.
68 (arm_sync_old_<sync_optab>si): Likewise.
69 (arm_sync_old_nandsi): Likewise.
70 (arm_sync_compare_and_swap<mode> NARROW): use sync_predtab, fix indent.
71 (arm_sync_lock_test_and_setsi<mode> NARROW): Likewise.
72 (arm_sync_new_<sync_optab><mode> NARROW): Likewise.
73 (arm_sync_new_nand<mode> NARROW): Likewise.
74 (arm_sync_old_<sync_optab><mode> NARROW): Likewise.
75 (arm_sync_old_nand<mode> NARROW): Likewise.
76
772011-11-28 David Alan Gilbert <david.gilbert@linaro.org>
78
79 Backport from mainline (svn r19980):
80
81 2011-10-14 David Alan Gilbert <david.gilbert@linaro.org>
82
83 PR target/48126
84
85 gcc/
86 * config/arm/arm.c (arm_output_sync_loop): Move label before barrier.
87
882011-11-28 David Alan Gilbert <david.gilbert@linaro.org>
89
90 Backport from mainline (svn r19979):
91
92 2011-10-14 David Alan Gilbert <david.gilbert@linaro.org>
93
94 gcc/
95 * config/arm/arm.h (TARGET_HAVE_DMB_MCR): MCR Not available in Thumb1.
96
97=== modified file 'gcc/config/arm/arm.c'
98--- old/gcc/config/arm/arm.c 2011-11-21 01:45:54 +0000
99+++ new/gcc/config/arm/arm.c 2011-11-28 15:07:01 +0000
100@@ -24307,12 +24307,26 @@
101 rtx target,
102 rtx memory)
103 {
104- const char *suffix = arm_ldrex_suffix (mode);
105- rtx operands[2];
106+ rtx operands[3];
107
108 operands[0] = target;
109- operands[1] = memory;
110- arm_output_asm_insn (emit, 0, operands, "ldrex%s\t%%0, %%C1", suffix);
111+ if (mode != DImode)
112+ {
113+ const char *suffix = arm_ldrex_suffix (mode);
114+ operands[1] = memory;
115+ arm_output_asm_insn (emit, 0, operands, "ldrex%s\t%%0, %%C1", suffix);
116+ }
117+ else
118+ {
119+ /* The restrictions on target registers in ARM mode are that the two
120+ registers are consecutive and the first one is even; Thumb is
121+ actually more flexible, but DI should give us this anyway.
122+ Note that the 1st register always gets the lowest word in memory. */
123+ gcc_assert ((REGNO (target) & 1) == 0);
124+ operands[1] = gen_rtx_REG (SImode, REGNO (target) + 1);
125+ operands[2] = memory;
126+ arm_output_asm_insn (emit, 0, operands, "ldrexd\t%%0, %%1, %%C2");
127+ }
128 }
129
130 /* Emit a strex{b,h,d, } instruction appropriate for the specified
131@@ -24325,14 +24339,41 @@
132 rtx value,
133 rtx memory)
134 {
135- const char *suffix = arm_ldrex_suffix (mode);
136- rtx operands[3];
137+ rtx operands[4];
138
139 operands[0] = result;
140 operands[1] = value;
141- operands[2] = memory;
142- arm_output_asm_insn (emit, 0, operands, "strex%s%s\t%%0, %%1, %%C2", suffix,
143- cc);
144+ if (mode != DImode)
145+ {
146+ const char *suffix = arm_ldrex_suffix (mode);
147+ operands[2] = memory;
148+ arm_output_asm_insn (emit, 0, operands, "strex%s%s\t%%0, %%1, %%C2",
149+ suffix, cc);
150+ }
151+ else
152+ {
153+ /* The restrictions on target registers in ARM mode are that the two
154+ registers are consecutive and the first one is even; Thumb is
155+ actually more flexible, but DI should give us this anyway.
156+ Note that the 1st register always gets the lowest word in memory. */
157+ gcc_assert ((REGNO (value) & 1) == 0 || TARGET_THUMB2);
158+ operands[2] = gen_rtx_REG (SImode, REGNO (value) + 1);
159+ operands[3] = memory;
160+ arm_output_asm_insn (emit, 0, operands, "strexd%s\t%%0, %%1, %%2, %%C3",
161+ cc);
162+ }
163+}
164+
165+/* Helper to emit an it instruction in Thumb2 mode only; although the assembler
166+ will ignore it in ARM mode, emitting it will mess up instruction counts we
167+ sometimes keep 'flags' are the extra t's and e's if it's more than one
168+ instruction that is conditional. */
169+static void
170+arm_output_it (emit_f emit, const char *flags, const char *cond)
171+{
172+ rtx operands[1]; /* Don't actually use the operand. */
173+ if (TARGET_THUMB2)
174+ arm_output_asm_insn (emit, 0, operands, "it%s\t%s", flags, cond);
175 }
176
177 /* Helper to emit a two operand instruction. */
178@@ -24374,7 +24415,7 @@
179
180 required_value:
181
182- RTX register or const_int representing the required old_value for
183+ RTX register representing the required old_value for
184 the modify to continue, if NULL no comparsion is performed. */
185 static void
186 arm_output_sync_loop (emit_f emit,
187@@ -24388,7 +24429,13 @@
188 enum attr_sync_op sync_op,
189 int early_barrier_required)
190 {
191- rtx operands[1];
192+ rtx operands[2];
193+ /* We'll use the lo for the normal rtx in the none-DI case
194+ as well as the least-sig word in the DI case. */
195+ rtx old_value_lo, required_value_lo, new_value_lo, t1_lo;
196+ rtx old_value_hi, required_value_hi, new_value_hi, t1_hi;
197+
198+ bool is_di = mode == DImode;
199
200 gcc_assert (t1 != t2);
201
202@@ -24399,82 +24446,142 @@
203
204 arm_output_ldrex (emit, mode, old_value, memory);
205
206+ if (is_di)
207+ {
208+ old_value_lo = gen_lowpart (SImode, old_value);
209+ old_value_hi = gen_highpart (SImode, old_value);
210+ if (required_value)
211+ {
212+ required_value_lo = gen_lowpart (SImode, required_value);
213+ required_value_hi = gen_highpart (SImode, required_value);
214+ }
215+ else
216+ {
217+ /* Silence false potentially unused warning. */
218+ required_value_lo = NULL_RTX;
219+ required_value_hi = NULL_RTX;
220+ }
221+ new_value_lo = gen_lowpart (SImode, new_value);
222+ new_value_hi = gen_highpart (SImode, new_value);
223+ t1_lo = gen_lowpart (SImode, t1);
224+ t1_hi = gen_highpart (SImode, t1);
225+ }
226+ else
227+ {
228+ old_value_lo = old_value;
229+ new_value_lo = new_value;
230+ required_value_lo = required_value;
231+ t1_lo = t1;
232+
233+ /* Silence false potentially unused warning. */
234+ t1_hi = NULL_RTX;
235+ new_value_hi = NULL_RTX;
236+ required_value_hi = NULL_RTX;
237+ old_value_hi = NULL_RTX;
238+ }
239+
240 if (required_value)
241 {
242- rtx operands[2];
243+ operands[0] = old_value_lo;
244+ operands[1] = required_value_lo;
245
246- operands[0] = old_value;
247- operands[1] = required_value;
248 arm_output_asm_insn (emit, 0, operands, "cmp\t%%0, %%1");
249+ if (is_di)
250+ {
251+ arm_output_it (emit, "", "eq");
252+ arm_output_op2 (emit, "cmpeq", old_value_hi, required_value_hi);
253+ }
254 arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYB%%=", LOCAL_LABEL_PREFIX);
255 }
256
257 switch (sync_op)
258 {
259 case SYNC_OP_ADD:
260- arm_output_op3 (emit, "add", t1, old_value, new_value);
261+ arm_output_op3 (emit, is_di ? "adds" : "add",
262+ t1_lo, old_value_lo, new_value_lo);
263+ if (is_di)
264+ arm_output_op3 (emit, "adc", t1_hi, old_value_hi, new_value_hi);
265 break;
266
267 case SYNC_OP_SUB:
268- arm_output_op3 (emit, "sub", t1, old_value, new_value);
269+ arm_output_op3 (emit, is_di ? "subs" : "sub",
270+ t1_lo, old_value_lo, new_value_lo);
271+ if (is_di)
272+ arm_output_op3 (emit, "sbc", t1_hi, old_value_hi, new_value_hi);
273 break;
274
275 case SYNC_OP_IOR:
276- arm_output_op3 (emit, "orr", t1, old_value, new_value);
277+ arm_output_op3 (emit, "orr", t1_lo, old_value_lo, new_value_lo);
278+ if (is_di)
279+ arm_output_op3 (emit, "orr", t1_hi, old_value_hi, new_value_hi);
280 break;
281
282 case SYNC_OP_XOR:
283- arm_output_op3 (emit, "eor", t1, old_value, new_value);
284+ arm_output_op3 (emit, "eor", t1_lo, old_value_lo, new_value_lo);
285+ if (is_di)
286+ arm_output_op3 (emit, "eor", t1_hi, old_value_hi, new_value_hi);
287 break;
288
289 case SYNC_OP_AND:
290- arm_output_op3 (emit,"and", t1, old_value, new_value);
291+ arm_output_op3 (emit,"and", t1_lo, old_value_lo, new_value_lo);
292+ if (is_di)
293+ arm_output_op3 (emit, "and", t1_hi, old_value_hi, new_value_hi);
294 break;
295
296 case SYNC_OP_NAND:
297- arm_output_op3 (emit, "and", t1, old_value, new_value);
298- arm_output_op2 (emit, "mvn", t1, t1);
299+ arm_output_op3 (emit, "and", t1_lo, old_value_lo, new_value_lo);
300+ if (is_di)
301+ arm_output_op3 (emit, "and", t1_hi, old_value_hi, new_value_hi);
302+ arm_output_op2 (emit, "mvn", t1_lo, t1_lo);
303+ if (is_di)
304+ arm_output_op2 (emit, "mvn", t1_hi, t1_hi);
305 break;
306
307 case SYNC_OP_NONE:
308 t1 = new_value;
309+ t1_lo = new_value_lo;
310+ if (is_di)
311+ t1_hi = new_value_hi;
312 break;
313 }
314
315+ /* Note that the result of strex is a 0/1 flag that's always 1 register. */
316 if (t2)
317 {
318- arm_output_strex (emit, mode, "", t2, t1, memory);
319- operands[0] = t2;
320- arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0");
321- arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=",
322- LOCAL_LABEL_PREFIX);
323+ arm_output_strex (emit, mode, "", t2, t1, memory);
324+ operands[0] = t2;
325+ arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0");
326+ arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=",
327+ LOCAL_LABEL_PREFIX);
328 }
329 else
330 {
331 /* Use old_value for the return value because for some operations
332 the old_value can easily be restored. This saves one register. */
333- arm_output_strex (emit, mode, "", old_value, t1, memory);
334- operands[0] = old_value;
335+ arm_output_strex (emit, mode, "", old_value_lo, t1, memory);
336+ operands[0] = old_value_lo;
337 arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0");
338 arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=",
339 LOCAL_LABEL_PREFIX);
340
341+ /* Note that we only used the _lo half of old_value as a temporary
342+ so in DI we don't have to restore the _hi part. */
343 switch (sync_op)
344 {
345 case SYNC_OP_ADD:
346- arm_output_op3 (emit, "sub", old_value, t1, new_value);
347+ arm_output_op3 (emit, "sub", old_value_lo, t1_lo, new_value_lo);
348 break;
349
350 case SYNC_OP_SUB:
351- arm_output_op3 (emit, "add", old_value, t1, new_value);
352+ arm_output_op3 (emit, "add", old_value_lo, t1_lo, new_value_lo);
353 break;
354
355 case SYNC_OP_XOR:
356- arm_output_op3 (emit, "eor", old_value, t1, new_value);
357+ arm_output_op3 (emit, "eor", old_value_lo, t1_lo, new_value_lo);
358 break;
359
360 case SYNC_OP_NONE:
361- arm_output_op2 (emit, "mov", old_value, required_value);
362+ arm_output_op2 (emit, "mov", old_value_lo, required_value_lo);
363 break;
364
365 default:
366@@ -24482,8 +24589,11 @@
367 }
368 }
369
370+ /* Note: label is before barrier so that in cmp failure case we still get
371+ a barrier to stop subsequent loads floating upwards past the ldrex
372+ PR target/48126. */
373+ arm_output_asm_insn (emit, 1, operands, "%sLSYB%%=:", LOCAL_LABEL_PREFIX);
374 arm_process_output_memory_barrier (emit, NULL);
375- arm_output_asm_insn (emit, 1, operands, "%sLSYB%%=:", LOCAL_LABEL_PREFIX);
376 }
377
378 static rtx
379@@ -24577,7 +24687,7 @@
380 target = gen_reg_rtx (mode);
381
382 memory = arm_legitimize_sync_memory (memory);
383- if (mode != SImode)
384+ if (mode != SImode && mode != DImode)
385 {
386 rtx load_temp = gen_reg_rtx (SImode);
387
388
389=== modified file 'gcc/config/arm/arm.h'
390--- old/gcc/config/arm/arm.h 2011-11-21 01:45:54 +0000
391+++ new/gcc/config/arm/arm.h 2011-11-28 15:07:01 +0000
392@@ -300,7 +300,8 @@
393 #define TARGET_HAVE_DMB (arm_arch7)
394
395 /* Nonzero if this chip implements a memory barrier via CP15. */
396-#define TARGET_HAVE_DMB_MCR (arm_arch6k && ! TARGET_HAVE_DMB)
397+#define TARGET_HAVE_DMB_MCR (arm_arch6 && ! TARGET_HAVE_DMB \
398+ && ! TARGET_THUMB1)
399
400 /* Nonzero if this chip implements a memory barrier instruction. */
401 #define TARGET_HAVE_MEMORY_BARRIER (TARGET_HAVE_DMB || TARGET_HAVE_DMB_MCR)
402@@ -308,8 +309,12 @@
403 /* Nonzero if this chip supports ldrex and strex */
404 #define TARGET_HAVE_LDREX ((arm_arch6 && TARGET_ARM) || arm_arch7)
405
406-/* Nonzero if this chip supports ldrex{bhd} and strex{bhd}. */
407-#define TARGET_HAVE_LDREXBHD ((arm_arch6k && TARGET_ARM) || arm_arch7)
408+/* Nonzero if this chip supports ldrex{bh} and strex{bh}. */
409+#define TARGET_HAVE_LDREXBH ((arm_arch6k && TARGET_ARM) || arm_arch7)
410+
411+/* Nonzero if this chip supports ldrexd and strexd. */
412+#define TARGET_HAVE_LDREXD (((arm_arch6k && TARGET_ARM) || arm_arch7) \
413+ && arm_arch_notm)
414
415 /* Nonzero if integer division instructions supported. */
416 #define TARGET_IDIV ((TARGET_ARM && arm_arch_arm_hwdiv) \
417
418=== modified file 'gcc/config/arm/iterators.md'
419--- old/gcc/config/arm/iterators.md 2011-10-23 13:33:07 +0000
420+++ new/gcc/config/arm/iterators.md 2011-11-28 15:07:01 +0000
421@@ -33,6 +33,15 @@
422 ;; A list of integer modes that are up to one word long
423 (define_mode_iterator QHSI [QI HI SI])
424
425+;; A list of integer modes that are less than a word
426+(define_mode_iterator NARROW [QI HI])
427+
428+;; A list of all the integer modes upto 64bit
429+(define_mode_iterator QHSD [QI HI SI DI])
430+
431+;; A list of the 32bit and 64bit integer modes
432+(define_mode_iterator SIDI [SI DI])
433+
434 ;; Integer element sizes implemented by IWMMXT.
435 (define_mode_iterator VMMX [V2SI V4HI V8QI])
436
437
438=== added file 'gcc/config/arm/linux-atomic-64bit.c'
439--- old/gcc/config/arm/linux-atomic-64bit.c 1970-01-01 00:00:00 +0000
440+++ new/gcc/config/arm/linux-atomic-64bit.c 2011-10-14 15:50:44 +0000
441@@ -0,0 +1,166 @@
442+/* 64bit Linux-specific atomic operations for ARM EABI.
443+ Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
444+ Based on linux-atomic.c
445+
446+ 64 bit additions david.gilbert@linaro.org
447+
448+This file is part of GCC.
449+
450+GCC is free software; you can redistribute it and/or modify it under
451+the terms of the GNU General Public License as published by the Free
452+Software Foundation; either version 3, or (at your option) any later
453+version.
454+
455+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
456+WARRANTY; without even the implied warranty of MERCHANTABILITY or
457+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
458+for more details.
459+
460+Under Section 7 of GPL version 3, you are granted additional
461+permissions described in the GCC Runtime Library Exception, version
462+3.1, as published by the Free Software Foundation.
463+
464+You should have received a copy of the GNU General Public License and
465+a copy of the GCC Runtime Library Exception along with this program;
466+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
467+<http://www.gnu.org/licenses/>. */
468+
469+/* 64bit helper functions for atomic operations; the compiler will
470+ call these when the code is compiled for a CPU without ldrexd/strexd.
471+ (If the CPU had those then the compiler inlines the operation).
472+
473+ These helpers require a kernel helper that's only present on newer
474+ kernels; we check for that in an init section and bail out rather
475+ unceremoneously. */
476+
477+extern unsigned int __write (int fd, const void *buf, unsigned int count);
478+extern void abort (void);
479+
480+/* Kernel helper for compare-and-exchange. */
481+typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
482+ const long long* newval,
483+ long long *ptr);
484+#define __kernel_cmpxchg64 (*(__kernel_cmpxchg64_t *) 0xffff0f60)
485+
486+/* Kernel helper page version number. */
487+#define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
488+
489+/* Check that the kernel has a new enough version at load. */
490+static void __check_for_sync8_kernelhelper (void)
491+{
492+ if (__kernel_helper_version < 5)
493+ {
494+ const char err[] = "A newer kernel is required to run this binary. "
495+ "(__kernel_cmpxchg64 helper)\n";
496+ /* At this point we need a way to crash with some information
497+ for the user - I'm not sure I can rely on much else being
498+ available at this point, so do the same as generic-morestack.c
499+ write () and abort (). */
500+ __write (2 /* stderr. */, err, sizeof (err));
501+ abort ();
502+ }
503+};
504+
505+static void (*__sync8_kernelhelper_inithook[]) (void)
506+ __attribute__ ((used, section (".init_array"))) = {
507+ &__check_for_sync8_kernelhelper
508+};
509+
510+#define HIDDEN __attribute__ ((visibility ("hidden")))
511+
512+#define FETCH_AND_OP_WORD64(OP, PFX_OP, INF_OP) \
513+ long long HIDDEN \
514+ __sync_fetch_and_##OP##_8 (long long *ptr, long long val) \
515+ { \
516+ int failure; \
517+ long long tmp,tmp2; \
518+ \
519+ do { \
520+ tmp = *ptr; \
521+ tmp2 = PFX_OP (tmp INF_OP val); \
522+ failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr); \
523+ } while (failure != 0); \
524+ \
525+ return tmp; \
526+ }
527+
528+FETCH_AND_OP_WORD64 (add, , +)
529+FETCH_AND_OP_WORD64 (sub, , -)
530+FETCH_AND_OP_WORD64 (or, , |)
531+FETCH_AND_OP_WORD64 (and, , &)
532+FETCH_AND_OP_WORD64 (xor, , ^)
533+FETCH_AND_OP_WORD64 (nand, ~, &)
534+
535+#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
536+#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
537+
538+/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
539+ subword-sized quantities. */
540+
541+#define OP_AND_FETCH_WORD64(OP, PFX_OP, INF_OP) \
542+ long long HIDDEN \
543+ __sync_##OP##_and_fetch_8 (long long *ptr, long long val) \
544+ { \
545+ int failure; \
546+ long long tmp,tmp2; \
547+ \
548+ do { \
549+ tmp = *ptr; \
550+ tmp2 = PFX_OP (tmp INF_OP val); \
551+ failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr); \
552+ } while (failure != 0); \
553+ \
554+ return tmp2; \
555+ }
556+
557+OP_AND_FETCH_WORD64 (add, , +)
558+OP_AND_FETCH_WORD64 (sub, , -)
559+OP_AND_FETCH_WORD64 (or, , |)
560+OP_AND_FETCH_WORD64 (and, , &)
561+OP_AND_FETCH_WORD64 (xor, , ^)
562+OP_AND_FETCH_WORD64 (nand, ~, &)
563+
564+long long HIDDEN
565+__sync_val_compare_and_swap_8 (long long *ptr, long long oldval,
566+ long long newval)
567+{
568+ int failure;
569+ long long actual_oldval;
570+
571+ while (1)
572+ {
573+ actual_oldval = *ptr;
574+
575+ if (__builtin_expect (oldval != actual_oldval, 0))
576+ return actual_oldval;
577+
578+ failure = __kernel_cmpxchg64 (&actual_oldval, &newval, ptr);
579+
580+ if (__builtin_expect (!failure, 1))
581+ return oldval;
582+ }
583+}
584+
585+typedef unsigned char bool;
586+
587+bool HIDDEN
588+__sync_bool_compare_and_swap_8 (long long *ptr, long long oldval,
589+ long long newval)
590+{
591+ int failure = __kernel_cmpxchg64 (&oldval, &newval, ptr);
592+ return (failure == 0);
593+}
594+
595+long long HIDDEN
596+__sync_lock_test_and_set_8 (long long *ptr, long long val)
597+{
598+ int failure;
599+ long long oldval;
600+
601+ do {
602+ oldval = *ptr;
603+ failure = __kernel_cmpxchg64 (&oldval, &val, ptr);
604+ } while (failure != 0);
605+
606+ return oldval;
607+}
608
609=== modified file 'gcc/config/arm/linux-atomic.c'
610--- old/gcc/config/arm/linux-atomic.c 2011-01-03 20:52:22 +0000
611+++ new/gcc/config/arm/linux-atomic.c 2011-10-14 15:50:44 +0000
612@@ -32,8 +32,8 @@
613 #define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0)
614
615 /* Note: we implement byte, short and int versions of atomic operations using
616- the above kernel helpers, but there is no support for "long long" (64-bit)
617- operations as yet. */
618+ the above kernel helpers; see linux-atomic-64bit.c for "long long" (64-bit)
619+ operations. */
620
621 #define HIDDEN __attribute__ ((visibility ("hidden")))
622
623@@ -273,6 +273,7 @@
624 *ptr = 0; \
625 }
626
627+SYNC_LOCK_RELEASE (long long, 8)
628 SYNC_LOCK_RELEASE (int, 4)
629 SYNC_LOCK_RELEASE (short, 2)
630 SYNC_LOCK_RELEASE (char, 1)
631
632=== modified file 'gcc/config/arm/sync.md'
633--- old/gcc/config/arm/sync.md 2010-12-31 13:25:33 +0000
634+++ new/gcc/config/arm/sync.md 2011-10-14 15:47:15 +0000
635@@ -1,6 +1,7 @@
636 ;; Machine description for ARM processor synchronization primitives.
637 ;; Copyright (C) 2010 Free Software Foundation, Inc.
638 ;; Written by Marcus Shawcroft (marcus.shawcroft@arm.com)
639+;; 64bit Atomics by Dave Gilbert (david.gilbert@linaro.org)
640 ;;
641 ;; This file is part of GCC.
642 ;;
643@@ -33,31 +34,24 @@
644 MEM_VOLATILE_P (operands[0]) = 1;
645 })
646
647-(define_expand "sync_compare_and_swapsi"
648- [(set (match_operand:SI 0 "s_register_operand")
649- (unspec_volatile:SI [(match_operand:SI 1 "memory_operand")
650- (match_operand:SI 2 "s_register_operand")
651- (match_operand:SI 3 "s_register_operand")]
652- VUNSPEC_SYNC_COMPARE_AND_SWAP))]
653- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
654- {
655- struct arm_sync_generator generator;
656- generator.op = arm_sync_generator_omrn;
657- generator.u.omrn = gen_arm_sync_compare_and_swapsi;
658- arm_expand_sync (SImode, &generator, operands[0], operands[1], operands[2],
659- operands[3]);
660- DONE;
661- })
662
663-(define_mode_iterator NARROW [QI HI])
664+(define_mode_attr sync_predtab [(SI "TARGET_HAVE_LDREX &&
665+ TARGET_HAVE_MEMORY_BARRIER")
666+ (QI "TARGET_HAVE_LDREXBH &&
667+ TARGET_HAVE_MEMORY_BARRIER")
668+ (HI "TARGET_HAVE_LDREXBH &&
669+ TARGET_HAVE_MEMORY_BARRIER")
670+ (DI "TARGET_HAVE_LDREXD &&
671+ ARM_DOUBLEWORD_ALIGN &&
672+ TARGET_HAVE_MEMORY_BARRIER")])
673
674 (define_expand "sync_compare_and_swap<mode>"
675- [(set (match_operand:NARROW 0 "s_register_operand")
676- (unspec_volatile:NARROW [(match_operand:NARROW 1 "memory_operand")
677- (match_operand:NARROW 2 "s_register_operand")
678- (match_operand:NARROW 3 "s_register_operand")]
679+ [(set (match_operand:QHSD 0 "s_register_operand")
680+ (unspec_volatile:QHSD [(match_operand:QHSD 1 "memory_operand")
681+ (match_operand:QHSD 2 "s_register_operand")
682+ (match_operand:QHSD 3 "s_register_operand")]
683 VUNSPEC_SYNC_COMPARE_AND_SWAP))]
684- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
685+ "<sync_predtab>"
686 {
687 struct arm_sync_generator generator;
688 generator.op = arm_sync_generator_omrn;
689@@ -67,25 +61,11 @@
690 DONE;
691 })
692
693-(define_expand "sync_lock_test_and_setsi"
694- [(match_operand:SI 0 "s_register_operand")
695- (match_operand:SI 1 "memory_operand")
696- (match_operand:SI 2 "s_register_operand")]
697- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
698- {
699- struct arm_sync_generator generator;
700- generator.op = arm_sync_generator_omn;
701- generator.u.omn = gen_arm_sync_lock_test_and_setsi;
702- arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
703- operands[2]);
704- DONE;
705- })
706-
707 (define_expand "sync_lock_test_and_set<mode>"
708- [(match_operand:NARROW 0 "s_register_operand")
709- (match_operand:NARROW 1 "memory_operand")
710- (match_operand:NARROW 2 "s_register_operand")]
711- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
712+ [(match_operand:QHSD 0 "s_register_operand")
713+ (match_operand:QHSD 1 "memory_operand")
714+ (match_operand:QHSD 2 "s_register_operand")]
715+ "<sync_predtab>"
716 {
717 struct arm_sync_generator generator;
718 generator.op = arm_sync_generator_omn;
719@@ -115,51 +95,25 @@
720 (plus "*")
721 (minus "*")])
722
723-(define_expand "sync_<sync_optab>si"
724- [(match_operand:SI 0 "memory_operand")
725- (match_operand:SI 1 "s_register_operand")
726- (syncop:SI (match_dup 0) (match_dup 1))]
727- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
728- {
729- struct arm_sync_generator generator;
730- generator.op = arm_sync_generator_omn;
731- generator.u.omn = gen_arm_sync_new_<sync_optab>si;
732- arm_expand_sync (SImode, &generator, NULL, operands[0], NULL, operands[1]);
733- DONE;
734- })
735-
736-(define_expand "sync_nandsi"
737- [(match_operand:SI 0 "memory_operand")
738- (match_operand:SI 1 "s_register_operand")
739- (not:SI (and:SI (match_dup 0) (match_dup 1)))]
740- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
741- {
742- struct arm_sync_generator generator;
743- generator.op = arm_sync_generator_omn;
744- generator.u.omn = gen_arm_sync_new_nandsi;
745- arm_expand_sync (SImode, &generator, NULL, operands[0], NULL, operands[1]);
746- DONE;
747- })
748-
749 (define_expand "sync_<sync_optab><mode>"
750- [(match_operand:NARROW 0 "memory_operand")
751- (match_operand:NARROW 1 "s_register_operand")
752- (syncop:NARROW (match_dup 0) (match_dup 1))]
753- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
754+ [(match_operand:QHSD 0 "memory_operand")
755+ (match_operand:QHSD 1 "s_register_operand")
756+ (syncop:QHSD (match_dup 0) (match_dup 1))]
757+ "<sync_predtab>"
758 {
759 struct arm_sync_generator generator;
760 generator.op = arm_sync_generator_omn;
761 generator.u.omn = gen_arm_sync_new_<sync_optab><mode>;
762 arm_expand_sync (<MODE>mode, &generator, NULL, operands[0], NULL,
763- operands[1]);
764+ operands[1]);
765 DONE;
766 })
767
768 (define_expand "sync_nand<mode>"
769- [(match_operand:NARROW 0 "memory_operand")
770- (match_operand:NARROW 1 "s_register_operand")
771- (not:NARROW (and:NARROW (match_dup 0) (match_dup 1)))]
772- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
773+ [(match_operand:QHSD 0 "memory_operand")
774+ (match_operand:QHSD 1 "s_register_operand")
775+ (not:QHSD (and:QHSD (match_dup 0) (match_dup 1)))]
776+ "<sync_predtab>"
777 {
778 struct arm_sync_generator generator;
779 generator.op = arm_sync_generator_omn;
780@@ -169,57 +123,27 @@
781 DONE;
782 })
783
784-(define_expand "sync_new_<sync_optab>si"
785- [(match_operand:SI 0 "s_register_operand")
786- (match_operand:SI 1 "memory_operand")
787- (match_operand:SI 2 "s_register_operand")
788- (syncop:SI (match_dup 1) (match_dup 2))]
789- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
790- {
791- struct arm_sync_generator generator;
792- generator.op = arm_sync_generator_omn;
793- generator.u.omn = gen_arm_sync_new_<sync_optab>si;
794- arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
795- operands[2]);
796- DONE;
797- })
798-
799-(define_expand "sync_new_nandsi"
800- [(match_operand:SI 0 "s_register_operand")
801- (match_operand:SI 1 "memory_operand")
802- (match_operand:SI 2 "s_register_operand")
803- (not:SI (and:SI (match_dup 1) (match_dup 2)))]
804- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
805- {
806- struct arm_sync_generator generator;
807- generator.op = arm_sync_generator_omn;
808- generator.u.omn = gen_arm_sync_new_nandsi;
809- arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
810- operands[2]);
811- DONE;
812- })
813-
814 (define_expand "sync_new_<sync_optab><mode>"
815- [(match_operand:NARROW 0 "s_register_operand")
816- (match_operand:NARROW 1 "memory_operand")
817- (match_operand:NARROW 2 "s_register_operand")
818- (syncop:NARROW (match_dup 1) (match_dup 2))]
819- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
820+ [(match_operand:QHSD 0 "s_register_operand")
821+ (match_operand:QHSD 1 "memory_operand")
822+ (match_operand:QHSD 2 "s_register_operand")
823+ (syncop:QHSD (match_dup 1) (match_dup 2))]
824+ "<sync_predtab>"
825 {
826 struct arm_sync_generator generator;
827 generator.op = arm_sync_generator_omn;
828 generator.u.omn = gen_arm_sync_new_<sync_optab><mode>;
829 arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
830- NULL, operands[2]);
831+ NULL, operands[2]);
832 DONE;
833 })
834
835 (define_expand "sync_new_nand<mode>"
836- [(match_operand:NARROW 0 "s_register_operand")
837- (match_operand:NARROW 1 "memory_operand")
838- (match_operand:NARROW 2 "s_register_operand")
839- (not:NARROW (and:NARROW (match_dup 1) (match_dup 2)))]
840- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
841+ [(match_operand:QHSD 0 "s_register_operand")
842+ (match_operand:QHSD 1 "memory_operand")
843+ (match_operand:QHSD 2 "s_register_operand")
844+ (not:QHSD (and:QHSD (match_dup 1) (match_dup 2)))]
845+ "<sync_predtab>"
846 {
847 struct arm_sync_generator generator;
848 generator.op = arm_sync_generator_omn;
849@@ -229,57 +153,27 @@
850 DONE;
851 });
852
853-(define_expand "sync_old_<sync_optab>si"
854- [(match_operand:SI 0 "s_register_operand")
855- (match_operand:SI 1 "memory_operand")
856- (match_operand:SI 2 "s_register_operand")
857- (syncop:SI (match_dup 1) (match_dup 2))]
858- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
859- {
860- struct arm_sync_generator generator;
861- generator.op = arm_sync_generator_omn;
862- generator.u.omn = gen_arm_sync_old_<sync_optab>si;
863- arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
864- operands[2]);
865- DONE;
866- })
867-
868-(define_expand "sync_old_nandsi"
869- [(match_operand:SI 0 "s_register_operand")
870- (match_operand:SI 1 "memory_operand")
871- (match_operand:SI 2 "s_register_operand")
872- (not:SI (and:SI (match_dup 1) (match_dup 2)))]
873- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
874- {
875- struct arm_sync_generator generator;
876- generator.op = arm_sync_generator_omn;
877- generator.u.omn = gen_arm_sync_old_nandsi;
878- arm_expand_sync (SImode, &generator, operands[0], operands[1], NULL,
879- operands[2]);
880- DONE;
881- })
882-
883 (define_expand "sync_old_<sync_optab><mode>"
884- [(match_operand:NARROW 0 "s_register_operand")
885- (match_operand:NARROW 1 "memory_operand")
886- (match_operand:NARROW 2 "s_register_operand")
887- (syncop:NARROW (match_dup 1) (match_dup 2))]
888- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
889+ [(match_operand:QHSD 0 "s_register_operand")
890+ (match_operand:QHSD 1 "memory_operand")
891+ (match_operand:QHSD 2 "s_register_operand")
892+ (syncop:QHSD (match_dup 1) (match_dup 2))]
893+ "<sync_predtab>"
894 {
895 struct arm_sync_generator generator;
896 generator.op = arm_sync_generator_omn;
897 generator.u.omn = gen_arm_sync_old_<sync_optab><mode>;
898 arm_expand_sync (<MODE>mode, &generator, operands[0], operands[1],
899- NULL, operands[2]);
900+ NULL, operands[2]);
901 DONE;
902 })
903
904 (define_expand "sync_old_nand<mode>"
905- [(match_operand:NARROW 0 "s_register_operand")
906- (match_operand:NARROW 1 "memory_operand")
907- (match_operand:NARROW 2 "s_register_operand")
908- (not:NARROW (and:NARROW (match_dup 1) (match_dup 2)))]
909- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
910+ [(match_operand:QHSD 0 "s_register_operand")
911+ (match_operand:QHSD 1 "memory_operand")
912+ (match_operand:QHSD 2 "s_register_operand")
913+ (not:QHSD (and:QHSD (match_dup 1) (match_dup 2)))]
914+ "<sync_predtab>"
915 {
916 struct arm_sync_generator generator;
917 generator.op = arm_sync_generator_omn;
918@@ -289,22 +183,22 @@
919 DONE;
920 })
921
922-(define_insn "arm_sync_compare_and_swapsi"
923- [(set (match_operand:SI 0 "s_register_operand" "=&r")
924- (unspec_volatile:SI
925- [(match_operand:SI 1 "arm_sync_memory_operand" "+Q")
926- (match_operand:SI 2 "s_register_operand" "r")
927- (match_operand:SI 3 "s_register_operand" "r")]
928- VUNSPEC_SYNC_COMPARE_AND_SWAP))
929- (set (match_dup 1) (unspec_volatile:SI [(match_dup 2)]
930+(define_insn "arm_sync_compare_and_swap<mode>"
931+ [(set (match_operand:SIDI 0 "s_register_operand" "=&r")
932+ (unspec_volatile:SIDI
933+ [(match_operand:SIDI 1 "arm_sync_memory_operand" "+Q")
934+ (match_operand:SIDI 2 "s_register_operand" "r")
935+ (match_operand:SIDI 3 "s_register_operand" "r")]
936+ VUNSPEC_SYNC_COMPARE_AND_SWAP))
937+ (set (match_dup 1) (unspec_volatile:SIDI [(match_dup 2)]
938 VUNSPEC_SYNC_COMPARE_AND_SWAP))
939 (set (reg:CC CC_REGNUM) (unspec_volatile:CC [(match_dup 1)]
940 VUNSPEC_SYNC_COMPARE_AND_SWAP))
941 ]
942- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
943+ "<sync_predtab>"
944 {
945 return arm_output_sync_insn (insn, operands);
946- }
947+ }
948 [(set_attr "sync_result" "0")
949 (set_attr "sync_memory" "1")
950 (set_attr "sync_required_value" "2")
951@@ -318,7 +212,7 @@
952 (zero_extend:SI
953 (unspec_volatile:NARROW
954 [(match_operand:NARROW 1 "arm_sync_memory_operand" "+Q")
955- (match_operand:SI 2 "s_register_operand" "r")
956+ (match_operand:SI 2 "s_register_operand" "r")
957 (match_operand:SI 3 "s_register_operand" "r")]
958 VUNSPEC_SYNC_COMPARE_AND_SWAP)))
959 (set (match_dup 1) (unspec_volatile:NARROW [(match_dup 2)]
960@@ -326,10 +220,10 @@
961 (set (reg:CC CC_REGNUM) (unspec_volatile:CC [(match_dup 1)]
962 VUNSPEC_SYNC_COMPARE_AND_SWAP))
963 ]
964- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
965+ "<sync_predtab>"
966 {
967 return arm_output_sync_insn (insn, operands);
968- }
969+ }
970 [(set_attr "sync_result" "0")
971 (set_attr "sync_memory" "1")
972 (set_attr "sync_required_value" "2")
973@@ -338,18 +232,18 @@
974 (set_attr "conds" "clob")
975 (set_attr "predicable" "no")])
976
977-(define_insn "arm_sync_lock_test_and_setsi"
978- [(set (match_operand:SI 0 "s_register_operand" "=&r")
979- (match_operand:SI 1 "arm_sync_memory_operand" "+Q"))
980+(define_insn "arm_sync_lock_test_and_set<mode>"
981+ [(set (match_operand:SIDI 0 "s_register_operand" "=&r")
982+ (match_operand:SIDI 1 "arm_sync_memory_operand" "+Q"))
983 (set (match_dup 1)
984- (unspec_volatile:SI [(match_operand:SI 2 "s_register_operand" "r")]
985- VUNSPEC_SYNC_LOCK))
986+ (unspec_volatile:SIDI [(match_operand:SIDI 2 "s_register_operand" "r")]
987+ VUNSPEC_SYNC_LOCK))
988 (clobber (reg:CC CC_REGNUM))
989 (clobber (match_scratch:SI 3 "=&r"))]
990- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
991+ "<sync_predtab>"
992 {
993 return arm_output_sync_insn (insn, operands);
994- }
995+ }
996 [(set_attr "sync_release_barrier" "no")
997 (set_attr "sync_result" "0")
998 (set_attr "sync_memory" "1")
999@@ -364,10 +258,10 @@
1000 (zero_extend:SI (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q")))
1001 (set (match_dup 1)
1002 (unspec_volatile:NARROW [(match_operand:SI 2 "s_register_operand" "r")]
1003- VUNSPEC_SYNC_LOCK))
1004+ VUNSPEC_SYNC_LOCK))
1005 (clobber (reg:CC CC_REGNUM))
1006 (clobber (match_scratch:SI 3 "=&r"))]
1007- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
1008+ "<sync_predtab>"
1009 {
1010 return arm_output_sync_insn (insn, operands);
1011 }
1012@@ -380,22 +274,48 @@
1013 (set_attr "conds" "clob")
1014 (set_attr "predicable" "no")])
1015
1016-(define_insn "arm_sync_new_<sync_optab>si"
1017+(define_insn "arm_sync_new_<sync_optab><mode>"
1018+ [(set (match_operand:SIDI 0 "s_register_operand" "=&r")
1019+ (unspec_volatile:SIDI [(syncop:SIDI
1020+ (match_operand:SIDI 1 "arm_sync_memory_operand" "+Q")
1021+ (match_operand:SIDI 2 "s_register_operand" "r"))
1022+ ]
1023+ VUNSPEC_SYNC_NEW_OP))
1024+ (set (match_dup 1)
1025+ (unspec_volatile:SIDI [(match_dup 1) (match_dup 2)]
1026+ VUNSPEC_SYNC_NEW_OP))
1027+ (clobber (reg:CC CC_REGNUM))
1028+ (clobber (match_scratch:SI 3 "=&r"))]
1029+ "<sync_predtab>"
1030+ {
1031+ return arm_output_sync_insn (insn, operands);
1032+ }
1033+ [(set_attr "sync_result" "0")
1034+ (set_attr "sync_memory" "1")
1035+ (set_attr "sync_new_value" "2")
1036+ (set_attr "sync_t1" "0")
1037+ (set_attr "sync_t2" "3")
1038+ (set_attr "sync_op" "<sync_optab>")
1039+ (set_attr "conds" "clob")
1040+ (set_attr "predicable" "no")])
1041+
1042+(define_insn "arm_sync_new_<sync_optab><mode>"
1043 [(set (match_operand:SI 0 "s_register_operand" "=&r")
1044 (unspec_volatile:SI [(syncop:SI
1045- (match_operand:SI 1 "arm_sync_memory_operand" "+Q")
1046- (match_operand:SI 2 "s_register_operand" "r"))
1047- ]
1048- VUNSPEC_SYNC_NEW_OP))
1049+ (zero_extend:SI
1050+ (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1051+ (match_operand:SI 2 "s_register_operand" "r"))
1052+ ]
1053+ VUNSPEC_SYNC_NEW_OP))
1054 (set (match_dup 1)
1055- (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
1056- VUNSPEC_SYNC_NEW_OP))
1057+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1058+ VUNSPEC_SYNC_NEW_OP))
1059 (clobber (reg:CC CC_REGNUM))
1060 (clobber (match_scratch:SI 3 "=&r"))]
1061- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
1062+ "<sync_predtab>"
1063 {
1064 return arm_output_sync_insn (insn, operands);
1065- }
1066+ }
1067 [(set_attr "sync_result" "0")
1068 (set_attr "sync_memory" "1")
1069 (set_attr "sync_new_value" "2")
1070@@ -405,22 +325,22 @@
1071 (set_attr "conds" "clob")
1072 (set_attr "predicable" "no")])
1073
1074-(define_insn "arm_sync_new_nandsi"
1075- [(set (match_operand:SI 0 "s_register_operand" "=&r")
1076- (unspec_volatile:SI [(not:SI (and:SI
1077- (match_operand:SI 1 "arm_sync_memory_operand" "+Q")
1078- (match_operand:SI 2 "s_register_operand" "r")))
1079- ]
1080- VUNSPEC_SYNC_NEW_OP))
1081+(define_insn "arm_sync_new_nand<mode>"
1082+ [(set (match_operand:SIDI 0 "s_register_operand" "=&r")
1083+ (unspec_volatile:SIDI [(not:SIDI (and:SIDI
1084+ (match_operand:SIDI 1 "arm_sync_memory_operand" "+Q")
1085+ (match_operand:SIDI 2 "s_register_operand" "r")))
1086+ ]
1087+ VUNSPEC_SYNC_NEW_OP))
1088 (set (match_dup 1)
1089- (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
1090- VUNSPEC_SYNC_NEW_OP))
1091+ (unspec_volatile:SIDI [(match_dup 1) (match_dup 2)]
1092+ VUNSPEC_SYNC_NEW_OP))
1093 (clobber (reg:CC CC_REGNUM))
1094 (clobber (match_scratch:SI 3 "=&r"))]
1095- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
1096+ "<sync_predtab>"
1097 {
1098 return arm_output_sync_insn (insn, operands);
1099- }
1100+ }
1101 [(set_attr "sync_result" "0")
1102 (set_attr "sync_memory" "1")
1103 (set_attr "sync_new_value" "2")
1104@@ -430,50 +350,24 @@
1105 (set_attr "conds" "clob")
1106 (set_attr "predicable" "no")])
1107
1108-(define_insn "arm_sync_new_<sync_optab><mode>"
1109- [(set (match_operand:SI 0 "s_register_operand" "=&r")
1110- (unspec_volatile:SI [(syncop:SI
1111- (zero_extend:SI
1112- (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1113- (match_operand:SI 2 "s_register_operand" "r"))
1114- ]
1115- VUNSPEC_SYNC_NEW_OP))
1116- (set (match_dup 1)
1117- (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1118- VUNSPEC_SYNC_NEW_OP))
1119- (clobber (reg:CC CC_REGNUM))
1120- (clobber (match_scratch:SI 3 "=&r"))]
1121- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
1122- {
1123- return arm_output_sync_insn (insn, operands);
1124- }
1125- [(set_attr "sync_result" "0")
1126- (set_attr "sync_memory" "1")
1127- (set_attr "sync_new_value" "2")
1128- (set_attr "sync_t1" "0")
1129- (set_attr "sync_t2" "3")
1130- (set_attr "sync_op" "<sync_optab>")
1131- (set_attr "conds" "clob")
1132- (set_attr "predicable" "no")])
1133-
1134 (define_insn "arm_sync_new_nand<mode>"
1135 [(set (match_operand:SI 0 "s_register_operand" "=&r")
1136 (unspec_volatile:SI
1137 [(not:SI
1138 (and:SI
1139- (zero_extend:SI
1140- (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1141- (match_operand:SI 2 "s_register_operand" "r")))
1142+ (zero_extend:SI
1143+ (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1144+ (match_operand:SI 2 "s_register_operand" "r")))
1145 ] VUNSPEC_SYNC_NEW_OP))
1146 (set (match_dup 1)
1147 (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1148- VUNSPEC_SYNC_NEW_OP))
1149+ VUNSPEC_SYNC_NEW_OP))
1150 (clobber (reg:CC CC_REGNUM))
1151 (clobber (match_scratch:SI 3 "=&r"))]
1152- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
1153+ "<sync_predtab>"
1154 {
1155 return arm_output_sync_insn (insn, operands);
1156- }
1157+ }
1158 [(set_attr "sync_result" "0")
1159 (set_attr "sync_memory" "1")
1160 (set_attr "sync_new_value" "2")
1161@@ -483,20 +377,20 @@
1162 (set_attr "conds" "clob")
1163 (set_attr "predicable" "no")])
1164
1165-(define_insn "arm_sync_old_<sync_optab>si"
1166- [(set (match_operand:SI 0 "s_register_operand" "=&r")
1167- (unspec_volatile:SI [(syncop:SI
1168- (match_operand:SI 1 "arm_sync_memory_operand" "+Q")
1169- (match_operand:SI 2 "s_register_operand" "r"))
1170- ]
1171- VUNSPEC_SYNC_OLD_OP))
1172+(define_insn "arm_sync_old_<sync_optab><mode>"
1173+ [(set (match_operand:SIDI 0 "s_register_operand" "=&r")
1174+ (unspec_volatile:SIDI [(syncop:SIDI
1175+ (match_operand:SIDI 1 "arm_sync_memory_operand" "+Q")
1176+ (match_operand:SIDI 2 "s_register_operand" "r"))
1177+ ]
1178+ VUNSPEC_SYNC_OLD_OP))
1179 (set (match_dup 1)
1180- (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
1181- VUNSPEC_SYNC_OLD_OP))
1182+ (unspec_volatile:SIDI [(match_dup 1) (match_dup 2)]
1183+ VUNSPEC_SYNC_OLD_OP))
1184 (clobber (reg:CC CC_REGNUM))
1185- (clobber (match_scratch:SI 3 "=&r"))
1186+ (clobber (match_scratch:SIDI 3 "=&r"))
1187 (clobber (match_scratch:SI 4 "<sync_clobber>"))]
1188- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
1189+ "<sync_predtab>"
1190 {
1191 return arm_output_sync_insn (insn, operands);
1192 }
1193@@ -509,47 +403,21 @@
1194 (set_attr "conds" "clob")
1195 (set_attr "predicable" "no")])
1196
1197-(define_insn "arm_sync_old_nandsi"
1198- [(set (match_operand:SI 0 "s_register_operand" "=&r")
1199- (unspec_volatile:SI [(not:SI (and:SI
1200- (match_operand:SI 1 "arm_sync_memory_operand" "+Q")
1201- (match_operand:SI 2 "s_register_operand" "r")))
1202- ]
1203- VUNSPEC_SYNC_OLD_OP))
1204- (set (match_dup 1)
1205- (unspec_volatile:SI [(match_dup 1) (match_dup 2)]
1206- VUNSPEC_SYNC_OLD_OP))
1207- (clobber (reg:CC CC_REGNUM))
1208- (clobber (match_scratch:SI 3 "=&r"))
1209- (clobber (match_scratch:SI 4 "=&r"))]
1210- "TARGET_HAVE_LDREX && TARGET_HAVE_MEMORY_BARRIER"
1211- {
1212- return arm_output_sync_insn (insn, operands);
1213- }
1214- [(set_attr "sync_result" "0")
1215- (set_attr "sync_memory" "1")
1216- (set_attr "sync_new_value" "2")
1217- (set_attr "sync_t1" "3")
1218- (set_attr "sync_t2" "4")
1219- (set_attr "sync_op" "nand")
1220- (set_attr "conds" "clob")
1221- (set_attr "predicable" "no")])
1222-
1223 (define_insn "arm_sync_old_<sync_optab><mode>"
1224 [(set (match_operand:SI 0 "s_register_operand" "=&r")
1225 (unspec_volatile:SI [(syncop:SI
1226- (zero_extend:SI
1227- (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1228- (match_operand:SI 2 "s_register_operand" "r"))
1229- ]
1230- VUNSPEC_SYNC_OLD_OP))
1231+ (zero_extend:SI
1232+ (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1233+ (match_operand:SI 2 "s_register_operand" "r"))
1234+ ]
1235+ VUNSPEC_SYNC_OLD_OP))
1236 (set (match_dup 1)
1237- (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1238- VUNSPEC_SYNC_OLD_OP))
1239+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1240+ VUNSPEC_SYNC_OLD_OP))
1241 (clobber (reg:CC CC_REGNUM))
1242 (clobber (match_scratch:SI 3 "=&r"))
1243 (clobber (match_scratch:SI 4 "<sync_clobber>"))]
1244- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
1245+ "<sync_predtab>"
1246 {
1247 return arm_output_sync_insn (insn, operands);
1248 }
1249@@ -563,20 +431,46 @@
1250 (set_attr "predicable" "no")])
1251
1252 (define_insn "arm_sync_old_nand<mode>"
1253+ [(set (match_operand:SIDI 0 "s_register_operand" "=&r")
1254+ (unspec_volatile:SIDI [(not:SIDI (and:SIDI
1255+ (match_operand:SIDI 1 "arm_sync_memory_operand" "+Q")
1256+ (match_operand:SIDI 2 "s_register_operand" "r")))
1257+ ]
1258+ VUNSPEC_SYNC_OLD_OP))
1259+ (set (match_dup 1)
1260+ (unspec_volatile:SIDI [(match_dup 1) (match_dup 2)]
1261+ VUNSPEC_SYNC_OLD_OP))
1262+ (clobber (reg:CC CC_REGNUM))
1263+ (clobber (match_scratch:SIDI 3 "=&r"))
1264+ (clobber (match_scratch:SI 4 "=&r"))]
1265+ "<sync_predtab>"
1266+ {
1267+ return arm_output_sync_insn (insn, operands);
1268+ }
1269+ [(set_attr "sync_result" "0")
1270+ (set_attr "sync_memory" "1")
1271+ (set_attr "sync_new_value" "2")
1272+ (set_attr "sync_t1" "3")
1273+ (set_attr "sync_t2" "4")
1274+ (set_attr "sync_op" "nand")
1275+ (set_attr "conds" "clob")
1276+ (set_attr "predicable" "no")])
1277+
1278+(define_insn "arm_sync_old_nand<mode>"
1279 [(set (match_operand:SI 0 "s_register_operand" "=&r")
1280- (unspec_volatile:SI [(not:SI (and:SI
1281- (zero_extend:SI
1282- (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1283- (match_operand:SI 2 "s_register_operand" "r")))
1284- ]
1285- VUNSPEC_SYNC_OLD_OP))
1286+ (unspec_volatile:SI [(not:SI (and:SI
1287+ (zero_extend:SI
1288+ (match_operand:NARROW 1 "arm_sync_memory_operand" "+Q"))
1289+ (match_operand:SI 2 "s_register_operand" "r")))
1290+ ]
1291+ VUNSPEC_SYNC_OLD_OP))
1292 (set (match_dup 1)
1293- (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1294- VUNSPEC_SYNC_OLD_OP))
1295+ (unspec_volatile:NARROW [(match_dup 1) (match_dup 2)]
1296+ VUNSPEC_SYNC_OLD_OP))
1297 (clobber (reg:CC CC_REGNUM))
1298 (clobber (match_scratch:SI 3 "=&r"))
1299 (clobber (match_scratch:SI 4 "=&r"))]
1300- "TARGET_HAVE_LDREXBHD && TARGET_HAVE_MEMORY_BARRIER"
1301+ "<sync_predtab>"
1302 {
1303 return arm_output_sync_insn (insn, operands);
1304 }
1305
1306=== modified file 'gcc/config/arm/t-linux-eabi'
1307--- old/gcc/config/arm/t-linux-eabi 2011-01-03 20:52:22 +0000
1308+++ new/gcc/config/arm/t-linux-eabi 2011-10-14 15:50:44 +0000
1309@@ -36,3 +36,4 @@
1310 EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
1311
1312 LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/arm/linux-atomic.c
1313+LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/arm/linux-atomic-64bit.c
1314
1315=== added file 'gcc/testsuite/gcc.dg/di-longlong64-sync-1.c'
1316--- old/gcc/testsuite/gcc.dg/di-longlong64-sync-1.c 1970-01-01 00:00:00 +0000
1317+++ new/gcc/testsuite/gcc.dg/di-longlong64-sync-1.c 2011-10-14 15:56:32 +0000
1318@@ -0,0 +1,164 @@
1319+/* { dg-do run } */
1320+/* { dg-require-effective-target sync_longlong } */
1321+/* { dg-options "-std=gnu99" } */
1322+/* { dg-message "note: '__sync_fetch_and_nand' changed semantics in GCC 4.4" "" { target *-*-* } 0 } */
1323+/* { dg-message "note: '__sync_nand_and_fetch' changed semantics in GCC 4.4" "" { target *-*-* } 0 } */
1324+
1325+
1326+/* Test basic functionality of the intrinsics. The operations should
1327+ not be optimized away if no one checks the return values. */
1328+
1329+/* Based on ia64-sync-[12].c, but 1) long on ARM is 32 bit so use long long
1330+ (an explicit 64bit type maybe a better bet) and 2) Use values that cross
1331+ the 32bit boundary and cause carries since the actual maths are done as
1332+ pairs of 32 bit instructions. */
1333+
1334+/* Note: This file is #included by some of the ARM tests. */
1335+
1336+__extension__ typedef __SIZE_TYPE__ size_t;
1337+
1338+extern void abort (void);
1339+extern void *memcpy (void *, const void *, size_t);
1340+extern int memcmp (const void *, const void *, size_t);
1341+
1342+/* Temporary space where the work actually gets done. */
1343+static long long AL[24];
1344+/* Values copied into AL before we start. */
1345+static long long init_di[24] = { 0x100000002ll, 0x200000003ll, 0, 1,
1346+
1347+ 0x100000002ll, 0x100000002ll,
1348+ 0x100000002ll, 0x100000002ll,
1349+
1350+ 0, 0x1000e0de0000ll,
1351+ 42 , 0xc001c0de0000ll,
1352+
1353+ -1ll, 0, 0xff00ff0000ll, -1ll,
1354+
1355+ 0, 0x1000e0de0000ll,
1356+ 42 , 0xc001c0de0000ll,
1357+
1358+ -1ll, 0, 0xff00ff0000ll, -1ll};
1359+/* This is what should be in AL at the end. */
1360+static long long test_di[24] = { 0x1234567890ll, 0x1234567890ll, 1, 0,
1361+
1362+ 0x100000002ll, 0x100000002ll,
1363+ 0x100000002ll, 0x100000002ll,
1364+
1365+ 1, 0xc001c0de0000ll,
1366+ 20, 0x1000e0de0000ll,
1367+
1368+ 0x300000007ll , 0x500000009ll,
1369+ 0xf100ff0001ll, ~0xa00000007ll,
1370+
1371+ 1, 0xc001c0de0000ll,
1372+ 20, 0x1000e0de0000ll,
1373+
1374+ 0x300000007ll , 0x500000009ll,
1375+ 0xf100ff0001ll, ~0xa00000007ll };
1376+
1377+/* First check they work in terms of what they do to memory. */
1378+static void
1379+do_noret_di (void)
1380+{
1381+ __sync_val_compare_and_swap (AL+0, 0x100000002ll, 0x1234567890ll);
1382+ __sync_bool_compare_and_swap (AL+1, 0x200000003ll, 0x1234567890ll);
1383+ __sync_lock_test_and_set (AL+2, 1);
1384+ __sync_lock_release (AL+3);
1385+
1386+ /* The following tests should not change the value since the
1387+ original does NOT match. */
1388+ __sync_val_compare_and_swap (AL+4, 0x000000002ll, 0x1234567890ll);
1389+ __sync_val_compare_and_swap (AL+5, 0x100000000ll, 0x1234567890ll);
1390+ __sync_bool_compare_and_swap (AL+6, 0x000000002ll, 0x1234567890ll);
1391+ __sync_bool_compare_and_swap (AL+7, 0x100000000ll, 0x1234567890ll);
1392+
1393+ __sync_fetch_and_add (AL+8, 1);
1394+ __sync_fetch_and_add (AL+9, 0xb000e0000000ll); /* + to both halves & carry. */
1395+ __sync_fetch_and_sub (AL+10, 22);
1396+ __sync_fetch_and_sub (AL+11, 0xb000e0000000ll);
1397+
1398+ __sync_fetch_and_and (AL+12, 0x300000007ll);
1399+ __sync_fetch_and_or (AL+13, 0x500000009ll);
1400+ __sync_fetch_and_xor (AL+14, 0xe00000001ll);
1401+ __sync_fetch_and_nand (AL+15, 0xa00000007ll);
1402+
1403+ /* These should be the same as the fetch_and_* cases except for
1404+ return value. */
1405+ __sync_add_and_fetch (AL+16, 1);
1406+ /* add to both halves & carry. */
1407+ __sync_add_and_fetch (AL+17, 0xb000e0000000ll);
1408+ __sync_sub_and_fetch (AL+18, 22);
1409+ __sync_sub_and_fetch (AL+19, 0xb000e0000000ll);
1410+
1411+ __sync_and_and_fetch (AL+20, 0x300000007ll);
1412+ __sync_or_and_fetch (AL+21, 0x500000009ll);
1413+ __sync_xor_and_fetch (AL+22, 0xe00000001ll);
1414+ __sync_nand_and_fetch (AL+23, 0xa00000007ll);
1415+}
1416+
1417+/* Now check return values. */
1418+static void
1419+do_ret_di (void)
1420+{
1421+ if (__sync_val_compare_and_swap (AL+0, 0x100000002ll, 0x1234567890ll) !=
1422+ 0x100000002ll) abort ();
1423+ if (__sync_bool_compare_and_swap (AL+1, 0x200000003ll, 0x1234567890ll) !=
1424+ 1) abort ();
1425+ if (__sync_lock_test_and_set (AL+2, 1) != 0) abort ();
1426+ __sync_lock_release (AL+3); /* no return value, but keep to match results. */
1427+
1428+ /* The following tests should not change the value since the
1429+ original does NOT match. */
1430+ if (__sync_val_compare_and_swap (AL+4, 0x000000002ll, 0x1234567890ll) !=
1431+ 0x100000002ll) abort ();
1432+ if (__sync_val_compare_and_swap (AL+5, 0x100000000ll, 0x1234567890ll) !=
1433+ 0x100000002ll) abort ();
1434+ if (__sync_bool_compare_and_swap (AL+6, 0x000000002ll, 0x1234567890ll) !=
1435+ 0) abort ();
1436+ if (__sync_bool_compare_and_swap (AL+7, 0x100000000ll, 0x1234567890ll) !=
1437+ 0) abort ();
1438+
1439+ if (__sync_fetch_and_add (AL+8, 1) != 0) abort ();
1440+ if (__sync_fetch_and_add (AL+9, 0xb000e0000000ll) != 0x1000e0de0000ll) abort ();
1441+ if (__sync_fetch_and_sub (AL+10, 22) != 42) abort ();
1442+ if (__sync_fetch_and_sub (AL+11, 0xb000e0000000ll) != 0xc001c0de0000ll)
1443+ abort ();
1444+
1445+ if (__sync_fetch_and_and (AL+12, 0x300000007ll) != -1ll) abort ();
1446+ if (__sync_fetch_and_or (AL+13, 0x500000009ll) != 0) abort ();
1447+ if (__sync_fetch_and_xor (AL+14, 0xe00000001ll) != 0xff00ff0000ll) abort ();
1448+ if (__sync_fetch_and_nand (AL+15, 0xa00000007ll) != -1ll) abort ();
1449+
1450+ /* These should be the same as the fetch_and_* cases except for
1451+ return value. */
1452+ if (__sync_add_and_fetch (AL+16, 1) != 1) abort ();
1453+ if (__sync_add_and_fetch (AL+17, 0xb000e0000000ll) != 0xc001c0de0000ll)
1454+ abort ();
1455+ if (__sync_sub_and_fetch (AL+18, 22) != 20) abort ();
1456+ if (__sync_sub_and_fetch (AL+19, 0xb000e0000000ll) != 0x1000e0de0000ll)
1457+ abort ();
1458+
1459+ if (__sync_and_and_fetch (AL+20, 0x300000007ll) != 0x300000007ll) abort ();
1460+ if (__sync_or_and_fetch (AL+21, 0x500000009ll) != 0x500000009ll) abort ();
1461+ if (__sync_xor_and_fetch (AL+22, 0xe00000001ll) != 0xf100ff0001ll) abort ();
1462+ if (__sync_nand_and_fetch (AL+23, 0xa00000007ll) != ~0xa00000007ll) abort ();
1463+}
1464+
1465+int main ()
1466+{
1467+ memcpy (AL, init_di, sizeof (init_di));
1468+
1469+ do_noret_di ();
1470+
1471+ if (memcmp (AL, test_di, sizeof (test_di)))
1472+ abort ();
1473+
1474+ memcpy (AL, init_di, sizeof (init_di));
1475+
1476+ do_ret_di ();
1477+
1478+ if (memcmp (AL, test_di, sizeof (test_di)))
1479+ abort ();
1480+
1481+ return 0;
1482+}
1483
1484=== added file 'gcc/testsuite/gcc.dg/di-sync-multithread.c'
1485--- old/gcc/testsuite/gcc.dg/di-sync-multithread.c 1970-01-01 00:00:00 +0000
1486+++ new/gcc/testsuite/gcc.dg/di-sync-multithread.c 2011-10-14 15:56:32 +0000
1487@@ -0,0 +1,205 @@
1488+/* { dg-do run } */
1489+/* { dg-require-effective-target sync_longlong } */
1490+/* { dg-require-effective-target pthread_h } */
1491+/* { dg-require-effective-target pthread } */
1492+/* { dg-options "-pthread -std=gnu99" } */
1493+
1494+/* test of long long atomic ops performed in parallel in 3 pthreads
1495+ david.gilbert@linaro.org */
1496+
1497+#include <pthread.h>
1498+#include <unistd.h>
1499+
1500+/*#define DEBUGIT 1 */
1501+
1502+#ifdef DEBUGIT
1503+#include <stdio.h>
1504+
1505+#define DOABORT(x,...) {\
1506+ fprintf (stderr, x, __VA_ARGS__); fflush (stderr); abort ();\
1507+ }
1508+
1509+#else
1510+
1511+#define DOABORT(x,...) abort ();
1512+
1513+#endif
1514+
1515+/* Passed to each thread to describe which bits it is going to work on. */
1516+struct threadwork {
1517+ unsigned long long count; /* incremented each time the worker loops. */
1518+ unsigned int thread; /* ID */
1519+ unsigned int addlsb; /* 8 bit */
1520+ unsigned int logic1lsb; /* 5 bit */
1521+ unsigned int logic2lsb; /* 8 bit */
1522+};
1523+
1524+/* The shared word where all the atomic work is done. */
1525+static volatile long long workspace;
1526+
1527+/* A shared word to tell the workers to quit when non-0. */
1528+static long long doquit;
1529+
1530+extern void abort (void);
1531+
1532+/* Note this test doesn't test the return values much. */
1533+void*
1534+worker (void* data)
1535+{
1536+ struct threadwork *tw = (struct threadwork*)data;
1537+ long long add1bit = 1ll << tw->addlsb;
1538+ long long logic1bit = 1ll << tw->logic1lsb;
1539+ long long logic2bit = 1ll << tw->logic2lsb;
1540+
1541+ /* Clear the bits we use. */
1542+ __sync_and_and_fetch (&workspace, ~(0xffll * add1bit));
1543+ __sync_fetch_and_and (&workspace, ~(0x1fll * logic1bit));
1544+ __sync_fetch_and_and (&workspace, ~(0xffll * logic2bit));
1545+
1546+ do
1547+ {
1548+ long long tmp1, tmp2, tmp3;
1549+ /* OK, lets try and do some stuff to the workspace - by the end
1550+ of the main loop our area should be the same as it is now - i.e. 0. */
1551+
1552+ /* Push the arithmetic section upto 128 - one of the threads will
1553+ case this to carry accross the 32bit boundary. */
1554+ for (tmp2 = 0; tmp2 < 64; tmp2++)
1555+ {
1556+ /* Add 2 using the two different adds. */
1557+ tmp1 = __sync_add_and_fetch (&workspace, add1bit);
1558+ tmp3 = __sync_fetch_and_add (&workspace, add1bit);
1559+
1560+ /* The value should be the intermediate add value in both cases. */
1561+ if ((tmp1 & (add1bit * 0xff)) != (tmp3 & (add1bit * 0xff)))
1562+ DOABORT ("Mismatch of add intermediates on thread %d "
1563+ "workspace=0x%llx tmp1=0x%llx "
1564+ "tmp2=0x%llx tmp3=0x%llx\n",
1565+ tw->thread, workspace, tmp1, tmp2, tmp3);
1566+ }
1567+
1568+ /* Set the logic bits. */
1569+ tmp2=__sync_or_and_fetch (&workspace,
1570+ 0x1fll * logic1bit | 0xffll * logic2bit);
1571+
1572+ /* Check the logic bits are set and the arithmetic value is correct. */
1573+ if ((tmp2 & (0x1fll * logic1bit | 0xffll * logic2bit
1574+ | 0xffll * add1bit))
1575+ != (0x1fll * logic1bit | 0xffll * logic2bit | 0x80ll * add1bit))
1576+ DOABORT ("Midloop check failed on thread %d "
1577+ "workspace=0x%llx tmp2=0x%llx "
1578+ "masktmp2=0x%llx expected=0x%llx\n",
1579+ tw->thread, workspace, tmp2,
1580+ tmp2 & (0x1fll * logic1bit | 0xffll * logic2bit |
1581+ 0xffll * add1bit),
1582+ (0x1fll * logic1bit | 0xffll * logic2bit | 0x80ll * add1bit));
1583+
1584+ /* Pull the arithmetic set back down to 0 - again this should cause a
1585+ carry across the 32bit boundary in one thread. */
1586+
1587+ for (tmp2 = 0; tmp2 < 64; tmp2++)
1588+ {
1589+ /* Subtract 2 using the two different subs. */
1590+ tmp1=__sync_sub_and_fetch (&workspace, add1bit);
1591+ tmp3=__sync_fetch_and_sub (&workspace, add1bit);
1592+
1593+ /* The value should be the intermediate sub value in both cases. */
1594+ if ((tmp1 & (add1bit * 0xff)) != (tmp3 & (add1bit * 0xff)))
1595+ DOABORT ("Mismatch of sub intermediates on thread %d "
1596+ "workspace=0x%llx tmp1=0x%llx "
1597+ "tmp2=0x%llx tmp3=0x%llx\n",
1598+ tw->thread, workspace, tmp1, tmp2, tmp3);
1599+ }
1600+
1601+
1602+ /* Clear the logic bits. */
1603+ __sync_fetch_and_xor (&workspace, 0x1fll * logic1bit);
1604+ tmp3=__sync_and_and_fetch (&workspace, ~(0xffll * logic2bit));
1605+
1606+ /* The logic bits and the arithmetic bits should be zero again. */
1607+ if (tmp3 & (0x1fll * logic1bit | 0xffll * logic2bit | 0xffll * add1bit))
1608+ DOABORT ("End of worker loop; bits none 0 on thread %d "
1609+ "workspace=0x%llx tmp3=0x%llx "
1610+ "mask=0x%llx maskedtmp3=0x%llx\n",
1611+ tw->thread, workspace, tmp3, (0x1fll * logic1bit |
1612+ 0xffll * logic2bit | 0xffll * add1bit),
1613+ tmp3 & (0x1fll * logic1bit | 0xffll * logic2bit | 0xffll * add1bit));
1614+
1615+ __sync_add_and_fetch (&tw->count, 1);
1616+ }
1617+ while (!__sync_bool_compare_and_swap (&doquit, 1, 1));
1618+
1619+ pthread_exit (0);
1620+}
1621+
1622+int
1623+main ()
1624+{
1625+ /* We have 3 threads doing three sets of operations, an 8 bit
1626+ arithmetic field, a 5 bit logic field and an 8 bit logic
1627+ field (just to pack them all in).
1628+
1629+ 6 5 4 4 3 2 1
1630+ 3 6 8 0 2 4 6 8 0
1631+ |...,...|...,...|...,...|...,...|...,...|...,...|...,...|...,...
1632+ - T0 -- T1 -- T2 --T2 -- T0 -*- T2-- T1-- T1 -***- T0-
1633+ logic2 logic2 arith log2 arith log1 log1 arith log1
1634+
1635+ */
1636+ unsigned int t;
1637+ long long tmp;
1638+ int err;
1639+
1640+ struct threadwork tw[3]={
1641+ { 0ll, 0, 27, 0, 56 },
1642+ { 0ll, 1, 8,16, 48 },
1643+ { 0ll, 2, 40,21, 35 }
1644+ };
1645+
1646+ pthread_t threads[3];
1647+
1648+ __sync_lock_release (&doquit);
1649+
1650+ /* Get the work space into a known value - All 1's. */
1651+ __sync_lock_release (&workspace); /* Now all 0. */
1652+ tmp = __sync_val_compare_and_swap (&workspace, 0, -1ll);
1653+ if (tmp!=0)
1654+ DOABORT ("Initial __sync_val_compare_and_swap wasn't 0 workspace=0x%llx "
1655+ "tmp=0x%llx\n", workspace,tmp);
1656+
1657+ for (t = 0; t < 3; t++)
1658+ {
1659+ err=pthread_create (&threads[t], NULL , worker, &tw[t]);
1660+ if (err) DOABORT ("pthread_create failed on thread %d with error %d\n",
1661+ t, err);
1662+ };
1663+
1664+ sleep (5);
1665+
1666+ /* Stop please. */
1667+ __sync_lock_test_and_set (&doquit, 1ll);
1668+
1669+ for (t = 0; t < 3; t++)
1670+ {
1671+ err=pthread_join (threads[t], NULL);
1672+ if (err)
1673+ DOABORT ("pthread_join failed on thread %d with error %d\n", t, err);
1674+ };
1675+
1676+ __sync_synchronize ();
1677+
1678+ /* OK, so all the workers have finished -
1679+ the workers should have zero'd their workspace, the unused areas
1680+ should still be 1. */
1681+ if (!__sync_bool_compare_and_swap (&workspace, 0x040000e0ll, 0))
1682+ DOABORT ("End of run workspace mismatch, got %llx\n", workspace);
1683+
1684+ /* All the workers should have done some work. */
1685+ for (t = 0; t < 3; t++)
1686+ {
1687+ if (tw[t].count == 0) DOABORT ("Worker %d gave 0 count\n", t);
1688+ };
1689+
1690+ return 0;
1691+}
1692+
1693
1694=== added file 'gcc/testsuite/gcc.target/arm/di-longlong64-sync-withhelpers.c'
1695--- old/gcc/testsuite/gcc.target/arm/di-longlong64-sync-withhelpers.c 1970-01-01 00:00:00 +0000
1696+++ new/gcc/testsuite/gcc.target/arm/di-longlong64-sync-withhelpers.c 2011-10-14 15:56:32 +0000
1697@@ -0,0 +1,14 @@
1698+/* { dg-do compile } */
1699+/* { dg-require-effective-target arm_arch_v5_ok } */
1700+/* { dg-options "-std=gnu99" } */
1701+/* { dg-add-options arm_arch_v5 } */
1702+/* { dg-message "note: '__sync_fetch_and_nand' changed semantics in GCC 4.4" "" { target *-*-* } 0 } */
1703+/* { dg-message "note: '__sync_nand_and_fetch' changed semantics in GCC 4.4" "" { target *-*-* } 0 } */
1704+/* { dg-message "file included" "In file included" { target *-*-* } 0 } */
1705+
1706+#include "../../gcc.dg/di-longlong64-sync-1.c"
1707+
1708+/* On an old ARM we have no ldrexd or strexd so we have to use helpers. */
1709+/* { dg-final { scan-assembler-not "ldrexd" } } */
1710+/* { dg-final { scan-assembler-not "strexd" } } */
1711+/* { dg-final { scan-assembler "__sync_" } } */
1712
1713=== added file 'gcc/testsuite/gcc.target/arm/di-longlong64-sync-withldrexd.c'
1714--- old/gcc/testsuite/gcc.target/arm/di-longlong64-sync-withldrexd.c 1970-01-01 00:00:00 +0000
1715+++ new/gcc/testsuite/gcc.target/arm/di-longlong64-sync-withldrexd.c 2011-10-14 15:56:32 +0000
1716@@ -0,0 +1,17 @@
1717+/* { dg-do compile } */
1718+/* { dg-require-effective-target arm_arm_ok } */
1719+/* { dg-options "-marm -std=gnu99" } */
1720+/* { dg-require-effective-target arm_arch_v6k_ok } */
1721+/* { dg-add-options arm_arch_v6k } */
1722+/* { dg-message "note: '__sync_fetch_and_nand' changed semantics in GCC 4.4" "" { target *-*-* } 0 } */
1723+/* { dg-message "note: '__sync_nand_and_fetch' changed semantics in GCC 4.4" "" { target *-*-* } 0 } */
1724+/* { dg-message "file included" "In file included" { target *-*-* } 0 } */
1725+
1726+#include "../../gcc.dg/di-longlong64-sync-1.c"
1727+
1728+/* We should be using ldrexd, strexd and no helpers or shorter ldrex. */
1729+/* { dg-final { scan-assembler-times "\tldrexd" 46 } } */
1730+/* { dg-final { scan-assembler-times "\tstrexd" 46 } } */
1731+/* { dg-final { scan-assembler-not "__sync_" } } */
1732+/* { dg-final { scan-assembler-not "ldrex\t" } } */
1733+/* { dg-final { scan-assembler-not "strex\t" } } */
1734
1735=== modified file 'gcc/testsuite/lib/target-supports.exp'
1736--- old/gcc/testsuite/lib/target-supports.exp 2011-11-22 17:10:17 +0000
1737+++ new/gcc/testsuite/lib/target-supports.exp 2011-11-28 15:07:01 +0000
1738@@ -2000,6 +2000,47 @@
1739 check_effective_target_arm_fp16_ok_nocache]
1740 }
1741
1742+# Creates a series of routines that return 1 if the given architecture
1743+# can be selected and a routine to give the flags to select that architecture
1744+# Note: Extra flags may be added to disable options from newer compilers
1745+# (Thumb in particular - but others may be added in the future)
1746+# Usage: /* { dg-require-effective-target arm_arch_v5_ok } */
1747+# /* { dg-add-options arm_arch_v5 } */
1748+foreach { armfunc armflag armdef } { v5 "-march=armv5 -marm" __ARM_ARCH_5__
1749+ v6 "-march=armv6" __ARM_ARCH_6__
1750+ v6k "-march=armv6k" __ARM_ARCH_6K__
1751+ v7a "-march=armv7-a" __ARM_ARCH_7A__ } {
1752+ eval [string map [list FUNC $armfunc FLAG $armflag DEF $armdef ] {
1753+ proc check_effective_target_arm_arch_FUNC_ok { } {
1754+ if { [ string match "*-marm*" "FLAG" ] &&
1755+ ![check_effective_target_arm_arm_ok] } {
1756+ return 0
1757+ }
1758+ return [check_no_compiler_messages arm_arch_FUNC_ok assembly {
1759+ #if !defined (DEF)
1760+ #error FOO
1761+ #endif
1762+ } "FLAG" ]
1763+ }
1764+
1765+ proc add_options_for_arm_arch_FUNC { flags } {
1766+ return "$flags FLAG"
1767+ }
1768+ }]
1769+}
1770+
1771+# Return 1 if this is an ARM target where -marm causes ARM to be
1772+# used (not Thumb)
1773+
1774+proc check_effective_target_arm_arm_ok { } {
1775+ return [check_no_compiler_messages arm_arm_ok assembly {
1776+ #if !defined (__arm__) || defined (__thumb__) || defined (__thumb2__)
1777+ #error FOO
1778+ #endif
1779+ } "-marm"]
1780+}
1781+
1782+
1783 # Return 1 is this is an ARM target where -mthumb causes Thumb-1 to be
1784 # used.
1785
1786@@ -3384,6 +3425,31 @@
1787 return $et_sync_int_long_saved
1788 }
1789
1790+# Return 1 if the target supports atomic operations on "long long" and can
1791+# execute them
1792+# So far only put checks in for ARM, others may want to add their own
1793+proc check_effective_target_sync_longlong { } {
1794+ return [check_runtime sync_longlong_runtime {
1795+ #include <stdlib.h>
1796+ int main ()
1797+ {
1798+ long long l1;
1799+
1800+ if (sizeof (long long) != 8)
1801+ exit (1);
1802+
1803+ #ifdef __arm__
1804+ /* Just check for native; checking for kernel fallback is tricky. */
1805+ asm volatile ("ldrexd r0,r1, [%0]" : : "r" (&l1) : "r0", "r1");
1806+ #else
1807+ # error "Add other suitable archs here"
1808+ #endif
1809+
1810+ exit (0);
1811+ }
1812+ } "" ]
1813+}
1814+
1815 # Return 1 if the target supports atomic operations on "char" and "short".
1816
1817 proc check_effective_target_sync_char_short { } {
1818