diff options
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.patch | 1818 |
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 @@ | |||
1 | 2011-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 | |||
17 | 2011-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 | |||
29 | 2011-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 | |||
77 | 2011-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 | |||
88 | 2011-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 | |||