diff options
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99419.patch')
-rw-r--r-- | toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99419.patch | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99419.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99419.patch new file mode 100644 index 0000000000..cb434082bf --- /dev/null +++ b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99419.patch | |||
@@ -0,0 +1,734 @@ | |||
1 | 2010-10-22 Julian Brown <julian@codesourcery.com> | ||
2 | |||
3 | Backport from mainline: | ||
4 | |||
5 | 2010-10-18 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
6 | |||
7 | gcc/testsuite/ | ||
8 | * gcc.target/arm/synchronize.c: Permit dmb or mcr in assembler scan. | ||
9 | |||
10 | 2010-10-14 Julian Brown <julian@codesourcery.com> | ||
11 | |||
12 | Backport from mainline: | ||
13 | |||
14 | 2010-08-18 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
15 | |||
16 | gcc/ | ||
17 | * config/arm/arm-protos.h (arm_expand_sync): New. | ||
18 | (arm_output_memory_barrier, arm_output_sync_insn): New. | ||
19 | (arm_sync_loop_insns): New. | ||
20 | * config/arm/arm.c (FL_ARCH7): New. | ||
21 | (FL_FOR_ARCH7): Include FL_ARCH7. | ||
22 | (arm_arch7): New. | ||
23 | (arm_print_operand): Support %C markup. | ||
24 | (arm_legitimize_sync_memory): New. | ||
25 | (arm_emit, arm_insn_count, arm_count, arm_output_asm_insn): New. | ||
26 | (arm_process_output_memory_barrier, arm_output_memory_barrier): New. | ||
27 | (arm_ldrex_suffix, arm_output_ldrex, arm_output_strex): New. | ||
28 | (arm_output_op2, arm_output_op3, arm_output_sync_loop): New. | ||
29 | (arm_get_sync_operand, FETCH_SYNC_OPERAND): New. | ||
30 | (arm_process_output_sync_insn, arm_output_sync_insn): New. | ||
31 | (arm_sync_loop_insns,arm_call_generator, arm_expand_sync): New. | ||
32 | * config/arm/arm.h (struct arm_sync_generator): New. | ||
33 | (TARGET_HAVE_DMB, TARGET_HAVE_DMB_MCR): New. | ||
34 | (TARGET_HAVE_MEMORY_BARRIER): New. | ||
35 | (TARGET_HAVE_LDREX, TARGET_HAVE_LDREXBHD): New. | ||
36 | * config/arm/arm.md: Include sync.md. | ||
37 | (UNSPEC_MEMORY_BARRIER): New. | ||
38 | (VUNSPEC_SYNC_COMPARE_AND_SWAP, VUNSPEC_SYNC_LOCK): New. | ||
39 | (VUNSPEC_SYNC_OP):New. | ||
40 | (VUNSPEC_SYNC_NEW_OP, VUNSPEC_SYNC_OLD_OP): New. | ||
41 | (sync_result, sync_memory, sync_required_value): New attributes. | ||
42 | (sync_new_value, sync_t1, sync_t2): Likewise. | ||
43 | (sync_release_barrier, sync_op): Likewise. | ||
44 | (length): Add logic to length attribute defintion to call | ||
45 | arm_sync_loop_insns when appropriate. | ||
46 | * config/arm/sync.md: New file. | ||
47 | |||
48 | 2010-09-02 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
49 | |||
50 | gcc/ | ||
51 | * config/arm/predicates.md (arm_sync_memory_operand): New. | ||
52 | * config/arm/sync.md (arm_sync_compare_and_swapsi): Change predicate | ||
53 | to arm_sync_memory_operand and constraint to Q. | ||
54 | (arm_sync_compare_and_swap<mode>): Likewise. | ||
55 | (arm_sync_compare_and_swap<mode>): Likewise. | ||
56 | (arm_sync_lock_test_and_setsi): Likewise. | ||
57 | (arm_sync_lock_test_and_set<mode>): Likewise. | ||
58 | (arm_sync_new_<sync_optab>si): Likewise. | ||
59 | (arm_sync_new_nandsi): Likewise. | ||
60 | (arm_sync_new_<sync_optab><mode>): Likewise. | ||
61 | (arm_sync_new_nand<mode>): Likewise. | ||
62 | (arm_sync_old_<sync_optab>si): Likewise. | ||
63 | (arm_sync_old_nandsi): Likewise. | ||
64 | (arm_sync_old_<sync_optab><mode>): Likewise. | ||
65 | (arm_sync_old_nand<mode>): Likewise. | ||
66 | |||
67 | 2010-09-13 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
68 | |||
69 | gcc/ | ||
70 | * config/arm/arm.md: (define_attr "conds"): Update comment. | ||
71 | * config/arm/sync.md (arm_sync_compare_and_swapsi): Change | ||
72 | conds attribute to clob. | ||
73 | (arm_sync_compare_and_swapsi): Likewise. | ||
74 | (arm_sync_compare_and_swap<mode>): Likewise. | ||
75 | (arm_sync_lock_test_and_setsi): Likewise. | ||
76 | (arm_sync_lock_test_and_set<mode>): Likewise. | ||
77 | (arm_sync_new_<sync_optab>si): Likewise. | ||
78 | (arm_sync_new_nandsi): Likewise. | ||
79 | (arm_sync_new_<sync_optab><mode>): Likewise. | ||
80 | (arm_sync_new_nand<mode>): Likewise. | ||
81 | (arm_sync_old_<sync_optab>si): Likewise. | ||
82 | (arm_sync_old_nandsi): Likewise. | ||
83 | (arm_sync_old_<sync_optab><mode>): Likewise. | ||
84 | (arm_sync_old_nand<mode>): Likewise. | ||
85 | |||
86 | 2010-09-13 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
87 | |||
88 | gcc/testsuite/ | ||
89 | * gcc.target/arm/sync-1.c: New. | ||
90 | |||
91 | |||
92 | Backport from FSF: | ||
93 | |||
94 | gcc/ | ||
95 | 2010-08-18 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
96 | * config/arm/arm-protos.h (arm_expand_sync): New. | ||
97 | (arm_output_memory_barrier, arm_output_sync_insn): New. | ||
98 | (arm_sync_loop_insns): New. | ||
99 | * config/arm/arm.c (FL_ARCH7): New. | ||
100 | (FL_FOR_ARCH7): Include FL_ARCH7. | ||
101 | (arm_arch7): New. | ||
102 | (arm_print_operand): Support %C markup. | ||
103 | (arm_legitimize_sync_memory): New. | ||
104 | (arm_emit, arm_insn_count, arm_count, arm_output_asm_insn): New. | ||
105 | (arm_process_output_memory_barrier, arm_output_memory_barrier): New. | ||
106 | (arm_ldrex_suffix, arm_output_ldrex, arm_output_strex): New. | ||
107 | (arm_output_op2, arm_output_op3, arm_output_sync_loop): New. | ||
108 | (arm_get_sync_operand, FETCH_SYNC_OPERAND): New. | ||
109 | (arm_process_output_sync_insn, arm_output_sync_insn): New. | ||
110 | (arm_sync_loop_insns,arm_call_generator, arm_expand_sync): New. | ||
111 | * config/arm/arm.h (struct arm_sync_generator): New. | ||
112 | (TARGET_HAVE_DMB, TARGET_HAVE_DMB_MCR): New. | ||
113 | (TARGET_HAVE_MEMORY_BARRIER): New. | ||
114 | (TARGET_HAVE_LDREX, TARGET_HAVE_LDREXBHD): New. | ||
115 | * config/arm/arm.md: Include sync.md. | ||
116 | (UNSPEC_MEMORY_BARRIER): New. | ||
117 | (VUNSPEC_SYNC_COMPARE_AND_SWAP, VUNSPEC_SYNC_LOCK): New. | ||
118 | (VUNSPEC_SYNC_OP):New. | ||
119 | (VUNSPEC_SYNC_NEW_OP, VUNSPEC_SYNC_OLD_OP): New. | ||
120 | (sync_result, sync_memory, sync_required_value): New attributes. | ||
121 | (sync_new_value, sync_t1, sync_t2): Likewise. | ||
122 | (sync_release_barrier, sync_op): Likewise. | ||
123 | (length): Add logic to length attribute defintion to call | ||
124 | arm_sync_loop_insns when appropriate. | ||
125 | * config/arm/sync.md: New file. | ||
126 | |||
127 | gcc/ | ||
128 | 2010-09-02 Marcus Shawcroft <marcus.shawcroft@arm.com> | ||
129 | * config/arm/predicates.md (arm_sync_memory_operand): New. | ||
130 | * config/arm/sync.md (arm_sync_compare_and_swapsi): Change predicate | ||
131 | to arm_sync_memory_operand and constraint to Q. | ||
132 | (arm_sync_compare_and_swap<mode>): Likewise. | ||
133 | (arm_sync_compare_and_swap<mode>): Likewise. | ||
134 | (arm_sync_lock_test_and_setsi): Likewise. | ||
135 | (arm_sync_lock_test_and_set<mode>): Likewise. | ||
136 | (arm_sync_new_<sync_optab>si): Likewise. | ||
137 | (arm_sync_new_nandsi): Likewise. | ||
138 | (arm_sync_new_<sync_optab><mode>): Likewise. | ||
139 | (arm_sync_new_nand<mode>): Likewise. | ||
140 | (arm_sync_old_<sync_optab>si): Likewise. | ||
141 | (arm_sync_old_nandsi): Likewise. | ||
142 | (arm_sync_old_<sync_optab><mode>): Likewise. | ||
143 | (arm_sync_old_nand<mode>): Likewise. | ||
144 | |||
145 | === modified file 'gcc/config/arm/arm-protos.h' | ||
146 | Index: gcc-4.5/gcc/config/arm/arm-protos.h | ||
147 | =================================================================== | ||
148 | --- gcc-4.5.orig/gcc/config/arm/arm-protos.h | ||
149 | +++ gcc-4.5/gcc/config/arm/arm-protos.h | ||
150 | @@ -151,6 +151,11 @@ extern const char *vfp_output_fstmd (rtx | ||
151 | extern void arm_set_return_address (rtx, rtx); | ||
152 | extern int arm_eliminable_register (rtx); | ||
153 | extern const char *arm_output_shift(rtx *, int); | ||
154 | +extern void arm_expand_sync (enum machine_mode, struct arm_sync_generator *, | ||
155 | + rtx, rtx, rtx, rtx); | ||
156 | +extern const char *arm_output_memory_barrier (rtx *); | ||
157 | +extern const char *arm_output_sync_insn (rtx, rtx *); | ||
158 | +extern unsigned int arm_sync_loop_insns (rtx , rtx *); | ||
159 | |||
160 | extern bool arm_output_addr_const_extra (FILE *, rtx); | ||
161 | |||
162 | Index: gcc-4.5/gcc/config/arm/arm.c | ||
163 | =================================================================== | ||
164 | --- gcc-4.5.orig/gcc/config/arm/arm.c | ||
165 | +++ gcc-4.5/gcc/config/arm/arm.c | ||
166 | @@ -602,6 +602,7 @@ static int thumb_call_reg_needed; | ||
167 | #define FL_NEON (1 << 20) /* Neon instructions. */ | ||
168 | #define FL_ARCH7EM (1 << 21) /* Instructions present in the ARMv7E-M | ||
169 | architecture. */ | ||
170 | +#define FL_ARCH7 (1 << 22) /* Architecture 7. */ | ||
171 | |||
172 | #define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */ | ||
173 | |||
174 | @@ -626,7 +627,7 @@ static int thumb_call_reg_needed; | ||
175 | #define FL_FOR_ARCH6ZK FL_FOR_ARCH6K | ||
176 | #define FL_FOR_ARCH6T2 (FL_FOR_ARCH6 | FL_THUMB2) | ||
177 | #define FL_FOR_ARCH6M (FL_FOR_ARCH6 & ~FL_NOTM) | ||
178 | -#define FL_FOR_ARCH7 (FL_FOR_ARCH6T2 &~ FL_NOTM) | ||
179 | +#define FL_FOR_ARCH7 ((FL_FOR_ARCH6T2 & ~FL_NOTM) | FL_ARCH7) | ||
180 | #define FL_FOR_ARCH7A (FL_FOR_ARCH7 | FL_NOTM | FL_ARCH6K) | ||
181 | #define FL_FOR_ARCH7R (FL_FOR_ARCH7A | FL_DIV) | ||
182 | #define FL_FOR_ARCH7M (FL_FOR_ARCH7 | FL_DIV) | ||
183 | @@ -664,6 +665,9 @@ int arm_arch6 = 0; | ||
184 | /* Nonzero if this chip supports the ARM 6K extensions. */ | ||
185 | int arm_arch6k = 0; | ||
186 | |||
187 | +/* Nonzero if this chip supports the ARM 7 extensions. */ | ||
188 | +int arm_arch7 = 0; | ||
189 | + | ||
190 | /* Nonzero if instructions not present in the 'M' profile can be used. */ | ||
191 | int arm_arch_notm = 0; | ||
192 | |||
193 | @@ -1602,6 +1606,7 @@ arm_override_options (void) | ||
194 | arm_arch6 = (insn_flags & FL_ARCH6) != 0; | ||
195 | arm_arch6k = (insn_flags & FL_ARCH6K) != 0; | ||
196 | arm_arch_notm = (insn_flags & FL_NOTM) != 0; | ||
197 | + arm_arch7 = (insn_flags & FL_ARCH7) != 0; | ||
198 | arm_arch7em = (insn_flags & FL_ARCH7EM) != 0; | ||
199 | arm_arch_thumb2 = (insn_flags & FL_THUMB2) != 0; | ||
200 | arm_arch_xscale = (insn_flags & FL_XSCALE) != 0; | ||
201 | @@ -16562,6 +16567,17 @@ arm_print_operand (FILE *stream, rtx x, | ||
202 | } | ||
203 | return; | ||
204 | |||
205 | + case 'C': | ||
206 | + { | ||
207 | + rtx addr; | ||
208 | + | ||
209 | + gcc_assert (GET_CODE (x) == MEM); | ||
210 | + addr = XEXP (x, 0); | ||
211 | + gcc_assert (GET_CODE (addr) == REG); | ||
212 | + asm_fprintf (stream, "[%r]", REGNO (addr)); | ||
213 | + } | ||
214 | + return; | ||
215 | + | ||
216 | /* Translate an S register number into a D register number and element index. */ | ||
217 | case 'y': | ||
218 | { | ||
219 | @@ -22793,4 +22809,372 @@ arm_builtin_support_vector_misalignment | ||
220 | is_packed); | ||
221 | } | ||
222 | |||
223 | +/* Legitimize a memory reference for sync primitive implemented using | ||
224 | + ldrex / strex. We currently force the form of the reference to be | ||
225 | + indirect without offset. We do not yet support the indirect offset | ||
226 | + addressing supported by some ARM targets for these | ||
227 | + instructions. */ | ||
228 | +static rtx | ||
229 | +arm_legitimize_sync_memory (rtx memory) | ||
230 | +{ | ||
231 | + rtx addr = force_reg (Pmode, XEXP (memory, 0)); | ||
232 | + rtx legitimate_memory = gen_rtx_MEM (GET_MODE (memory), addr); | ||
233 | + | ||
234 | + set_mem_alias_set (legitimate_memory, ALIAS_SET_MEMORY_BARRIER); | ||
235 | + MEM_VOLATILE_P (legitimate_memory) = MEM_VOLATILE_P (memory); | ||
236 | + return legitimate_memory; | ||
237 | +} | ||
238 | + | ||
239 | +/* An instruction emitter. */ | ||
240 | +typedef void (* emit_f) (int label, const char *, rtx *); | ||
241 | + | ||
242 | +/* An instruction emitter that emits via the conventional | ||
243 | + output_asm_insn. */ | ||
244 | +static void | ||
245 | +arm_emit (int label ATTRIBUTE_UNUSED, const char *pattern, rtx *operands) | ||
246 | +{ | ||
247 | + output_asm_insn (pattern, operands); | ||
248 | +} | ||
249 | + | ||
250 | +/* Count the number of emitted synchronization instructions. */ | ||
251 | +static unsigned arm_insn_count; | ||
252 | + | ||
253 | +/* An emitter that counts emitted instructions but does not actually | ||
254 | + emit instruction into the the instruction stream. */ | ||
255 | +static void | ||
256 | +arm_count (int label, | ||
257 | + const char *pattern ATTRIBUTE_UNUSED, | ||
258 | + rtx *operands ATTRIBUTE_UNUSED) | ||
259 | +{ | ||
260 | + if (! label) | ||
261 | + ++ arm_insn_count; | ||
262 | +} | ||
263 | + | ||
264 | +/* Construct a pattern using conventional output formatting and feed | ||
265 | + it to output_asm_insn. Provides a mechanism to construct the | ||
266 | + output pattern on the fly. Note the hard limit on the pattern | ||
267 | + buffer size. */ | ||
268 | +static void | ||
269 | +arm_output_asm_insn (emit_f emit, int label, rtx *operands, | ||
270 | + const char *pattern, ...) | ||
271 | +{ | ||
272 | + va_list ap; | ||
273 | + char buffer[256]; | ||
274 | + | ||
275 | + va_start (ap, pattern); | ||
276 | + vsprintf (buffer, pattern, ap); | ||
277 | + va_end (ap); | ||
278 | + emit (label, buffer, operands); | ||
279 | +} | ||
280 | + | ||
281 | +/* Emit the memory barrier instruction, if any, provided by this | ||
282 | + target to a specified emitter. */ | ||
283 | +static void | ||
284 | +arm_process_output_memory_barrier (emit_f emit, rtx *operands) | ||
285 | +{ | ||
286 | + if (TARGET_HAVE_DMB) | ||
287 | + { | ||
288 | + /* Note we issue a system level barrier. We should consider | ||
289 | + issuing a inner shareabilty zone barrier here instead, ie. | ||
290 | + "DMB ISH". */ | ||
291 | + emit (0, "dmb\tsy", operands); | ||
292 | + return; | ||
293 | + } | ||
294 | + | ||
295 | + if (TARGET_HAVE_DMB_MCR) | ||
296 | + { | ||
297 | + emit (0, "mcr\tp15, 0, r0, c7, c10, 5", operands); | ||
298 | + return; | ||
299 | + } | ||
300 | + | ||
301 | + gcc_unreachable (); | ||
302 | +} | ||
303 | + | ||
304 | +/* Emit the memory barrier instruction, if any, provided by this | ||
305 | + target. */ | ||
306 | +const char * | ||
307 | +arm_output_memory_barrier (rtx *operands) | ||
308 | +{ | ||
309 | + arm_process_output_memory_barrier (arm_emit, operands); | ||
310 | + return ""; | ||
311 | +} | ||
312 | + | ||
313 | +/* Helper to figure out the instruction suffix required on ldrex/strex | ||
314 | + for operations on an object of the specified mode. */ | ||
315 | +static const char * | ||
316 | +arm_ldrex_suffix (enum machine_mode mode) | ||
317 | +{ | ||
318 | + switch (mode) | ||
319 | + { | ||
320 | + case QImode: return "b"; | ||
321 | + case HImode: return "h"; | ||
322 | + case SImode: return ""; | ||
323 | + case DImode: return "d"; | ||
324 | + default: | ||
325 | + gcc_unreachable (); | ||
326 | + } | ||
327 | + return ""; | ||
328 | +} | ||
329 | + | ||
330 | +/* Emit an ldrex{b,h,d, } instruction appropriate for the specified | ||
331 | + mode. */ | ||
332 | +static void | ||
333 | +arm_output_ldrex (emit_f emit, | ||
334 | + enum machine_mode mode, | ||
335 | + rtx target, | ||
336 | + rtx memory) | ||
337 | +{ | ||
338 | + const char *suffix = arm_ldrex_suffix (mode); | ||
339 | + rtx operands[2]; | ||
340 | + | ||
341 | + operands[0] = target; | ||
342 | + operands[1] = memory; | ||
343 | + arm_output_asm_insn (emit, 0, operands, "ldrex%s\t%%0, %%C1", suffix); | ||
344 | +} | ||
345 | + | ||
346 | +/* Emit a strex{b,h,d, } instruction appropriate for the specified | ||
347 | + mode. */ | ||
348 | +static void | ||
349 | +arm_output_strex (emit_f emit, | ||
350 | + enum machine_mode mode, | ||
351 | + const char *cc, | ||
352 | + rtx result, | ||
353 | + rtx value, | ||
354 | + rtx memory) | ||
355 | +{ | ||
356 | + const char *suffix = arm_ldrex_suffix (mode); | ||
357 | + rtx operands[3]; | ||
358 | + | ||
359 | + operands[0] = result; | ||
360 | + operands[1] = value; | ||
361 | + operands[2] = memory; | ||
362 | + arm_output_asm_insn (emit, 0, operands, "strex%s%s\t%%0, %%1, %%C2", suffix, | ||
363 | + cc); | ||
364 | +} | ||
365 | + | ||
366 | +/* Helper to emit a two operand instruction. */ | ||
367 | +static void | ||
368 | +arm_output_op2 (emit_f emit, const char *mnemonic, rtx d, rtx s) | ||
369 | +{ | ||
370 | + rtx operands[2]; | ||
371 | + | ||
372 | + operands[0] = d; | ||
373 | + operands[1] = s; | ||
374 | + arm_output_asm_insn (emit, 0, operands, "%s\t%%0, %%1", mnemonic); | ||
375 | +} | ||
376 | + | ||
377 | +/* Helper to emit a three operand instruction. */ | ||
378 | +static void | ||
379 | +arm_output_op3 (emit_f emit, const char *mnemonic, rtx d, rtx a, rtx b) | ||
380 | +{ | ||
381 | + rtx operands[3]; | ||
382 | + | ||
383 | + operands[0] = d; | ||
384 | + operands[1] = a; | ||
385 | + operands[2] = b; | ||
386 | + arm_output_asm_insn (emit, 0, operands, "%s\t%%0, %%1, %%2", mnemonic); | ||
387 | +} | ||
388 | + | ||
389 | +/* Emit a load store exclusive synchronization loop. | ||
390 | + | ||
391 | + do | ||
392 | + old_value = [mem] | ||
393 | + if old_value != required_value | ||
394 | + break; | ||
395 | + t1 = sync_op (old_value, new_value) | ||
396 | + [mem] = t1, t2 = [0|1] | ||
397 | + while ! t2 | ||
398 | + | ||
399 | + Note: | ||
400 | + t1 == t2 is not permitted | ||
401 | + t1 == old_value is permitted | ||
402 | + | ||
403 | + required_value: | ||
404 | + | ||
405 | + RTX register or const_int representing the required old_value for | ||
406 | + the modify to continue, if NULL no comparsion is performed. */ | ||
407 | +static void | ||
408 | +arm_output_sync_loop (emit_f emit, | ||
409 | + enum machine_mode mode, | ||
410 | + rtx old_value, | ||
411 | + rtx memory, | ||
412 | + rtx required_value, | ||
413 | + rtx new_value, | ||
414 | + rtx t1, | ||
415 | + rtx t2, | ||
416 | + enum attr_sync_op sync_op, | ||
417 | + int early_barrier_required) | ||
418 | +{ | ||
419 | + rtx operands[1]; | ||
420 | + | ||
421 | + gcc_assert (t1 != t2); | ||
422 | + | ||
423 | + if (early_barrier_required) | ||
424 | + arm_process_output_memory_barrier (emit, NULL); | ||
425 | + | ||
426 | + arm_output_asm_insn (emit, 1, operands, "%sLSYT%%=:", LOCAL_LABEL_PREFIX); | ||
427 | + | ||
428 | + arm_output_ldrex (emit, mode, old_value, memory); | ||
429 | + | ||
430 | + if (required_value) | ||
431 | + { | ||
432 | + rtx operands[2]; | ||
433 | + | ||
434 | + operands[0] = old_value; | ||
435 | + operands[1] = required_value; | ||
436 | + arm_output_asm_insn (emit, 0, operands, "cmp\t%%0, %%1"); | ||
437 | + arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYB%%=", LOCAL_LABEL_PREFIX); | ||
438 | + } | ||
439 | + | ||
440 | + switch (sync_op) | ||
441 | + { | ||
442 | + case SYNC_OP_ADD: | ||
443 | + arm_output_op3 (emit, "add", t1, old_value, new_value); | ||
444 | + break; | ||
445 | + | ||
446 | + case SYNC_OP_SUB: | ||
447 | + arm_output_op3 (emit, "sub", t1, old_value, new_value); | ||
448 | + break; | ||
449 | + | ||
450 | + case SYNC_OP_IOR: | ||
451 | + arm_output_op3 (emit, "orr", t1, old_value, new_value); | ||
452 | + break; | ||
453 | + | ||
454 | + case SYNC_OP_XOR: | ||
455 | + arm_output_op3 (emit, "eor", t1, old_value, new_value); | ||
456 | + break; | ||
457 | + | ||
458 | + case SYNC_OP_AND: | ||
459 | + arm_output_op3 (emit,"and", t1, old_value, new_value); | ||
460 | + break; | ||
461 | + | ||
462 | + case SYNC_OP_NAND: | ||
463 | + arm_output_op3 (emit, "and", t1, old_value, new_value); | ||
464 | + arm_output_op2 (emit, "mvn", t1, t1); | ||
465 | + break; | ||
466 | + | ||
467 | + case SYNC_OP_NONE: | ||
468 | + t1 = new_value; | ||
469 | + break; | ||
470 | + } | ||
471 | + | ||
472 | + arm_output_strex (emit, mode, "", t2, t1, memory); | ||
473 | + operands[0] = t2; | ||
474 | + arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0"); | ||
475 | + arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=", LOCAL_LABEL_PREFIX); | ||
476 | + | ||
477 | + arm_process_output_memory_barrier (emit, NULL); | ||
478 | + arm_output_asm_insn (emit, 1, operands, "%sLSYB%%=:", LOCAL_LABEL_PREFIX); | ||
479 | +} | ||
480 | + | ||
481 | +static rtx | ||
482 | +arm_get_sync_operand (rtx *operands, int index, rtx default_value) | ||
483 | +{ | ||
484 | + if (index > 0) | ||
485 | + default_value = operands[index - 1]; | ||
486 | + | ||
487 | + return default_value; | ||
488 | +} | ||
489 | + | ||
490 | +#define FETCH_SYNC_OPERAND(NAME, DEFAULT) \ | ||
491 | + arm_get_sync_operand (operands, (int) get_attr_sync_##NAME (insn), DEFAULT); | ||
492 | + | ||
493 | +/* Extract the operands for a synchroniztion instruction from the | ||
494 | + instructions attributes and emit the instruction. */ | ||
495 | +static void | ||
496 | +arm_process_output_sync_insn (emit_f emit, rtx insn, rtx *operands) | ||
497 | +{ | ||
498 | + rtx result, memory, required_value, new_value, t1, t2; | ||
499 | + int early_barrier; | ||
500 | + enum machine_mode mode; | ||
501 | + enum attr_sync_op sync_op; | ||
502 | + | ||
503 | + result = FETCH_SYNC_OPERAND(result, 0); | ||
504 | + memory = FETCH_SYNC_OPERAND(memory, 0); | ||
505 | + required_value = FETCH_SYNC_OPERAND(required_value, 0); | ||
506 | + new_value = FETCH_SYNC_OPERAND(new_value, 0); | ||
507 | + t1 = FETCH_SYNC_OPERAND(t1, 0); | ||
508 | + t2 = FETCH_SYNC_OPERAND(t2, 0); | ||
509 | + early_barrier = | ||
510 | + get_attr_sync_release_barrier (insn) == SYNC_RELEASE_BARRIER_YES; | ||
511 | + sync_op = get_attr_sync_op (insn); | ||
512 | + mode = GET_MODE (memory); | ||
513 | + | ||
514 | + arm_output_sync_loop (emit, mode, result, memory, required_value, | ||
515 | + new_value, t1, t2, sync_op, early_barrier); | ||
516 | +} | ||
517 | + | ||
518 | +/* Emit a synchronization instruction loop. */ | ||
519 | +const char * | ||
520 | +arm_output_sync_insn (rtx insn, rtx *operands) | ||
521 | +{ | ||
522 | + arm_process_output_sync_insn (arm_emit, insn, operands); | ||
523 | + return ""; | ||
524 | +} | ||
525 | + | ||
526 | +/* Count the number of machine instruction that will be emitted for a | ||
527 | + synchronization instruction. Note that the emitter used does not | ||
528 | + emit instructions, it just counts instructions being carefull not | ||
529 | + to count labels. */ | ||
530 | +unsigned int | ||
531 | +arm_sync_loop_insns (rtx insn, rtx *operands) | ||
532 | +{ | ||
533 | + arm_insn_count = 0; | ||
534 | + arm_process_output_sync_insn (arm_count, insn, operands); | ||
535 | + return arm_insn_count; | ||
536 | +} | ||
537 | + | ||
538 | +/* Helper to call a target sync instruction generator, dealing with | ||
539 | + the variation in operands required by the different generators. */ | ||
540 | +static rtx | ||
541 | +arm_call_generator (struct arm_sync_generator *generator, rtx old_value, | ||
542 | + rtx memory, rtx required_value, rtx new_value) | ||
543 | +{ | ||
544 | + switch (generator->op) | ||
545 | + { | ||
546 | + case arm_sync_generator_omn: | ||
547 | + gcc_assert (! required_value); | ||
548 | + return generator->u.omn (old_value, memory, new_value); | ||
549 | + | ||
550 | + case arm_sync_generator_omrn: | ||
551 | + gcc_assert (required_value); | ||
552 | + return generator->u.omrn (old_value, memory, required_value, new_value); | ||
553 | + } | ||
554 | + | ||
555 | + return NULL; | ||
556 | +} | ||
557 | + | ||
558 | +/* Expand a synchronization loop. The synchronization loop is expanded | ||
559 | + as an opaque block of instructions in order to ensure that we do | ||
560 | + not subsequently get extraneous memory accesses inserted within the | ||
561 | + critical region. The exclusive access property of ldrex/strex is | ||
562 | + only guaranteed in there are no intervening memory accesses. */ | ||
563 | +void | ||
564 | +arm_expand_sync (enum machine_mode mode, | ||
565 | + struct arm_sync_generator *generator, | ||
566 | + rtx target, rtx memory, rtx required_value, rtx new_value) | ||
567 | +{ | ||
568 | + if (target == NULL) | ||
569 | + target = gen_reg_rtx (mode); | ||
570 | + | ||
571 | + memory = arm_legitimize_sync_memory (memory); | ||
572 | + if (mode != SImode) | ||
573 | + { | ||
574 | + rtx load_temp = gen_reg_rtx (SImode); | ||
575 | + | ||
576 | + if (required_value) | ||
577 | + required_value = convert_modes (SImode, mode, required_value, true); | ||
578 | + | ||
579 | + new_value = convert_modes (SImode, mode, new_value, true); | ||
580 | + emit_insn (arm_call_generator (generator, load_temp, memory, | ||
581 | + required_value, new_value)); | ||
582 | + emit_move_insn (target, gen_lowpart (mode, load_temp)); | ||
583 | + } | ||
584 | + else | ||
585 | + { | ||
586 | + emit_insn (arm_call_generator (generator, target, memory, required_value, | ||
587 | + new_value)); | ||
588 | + } | ||
589 | +} | ||
590 | + | ||
591 | #include "gt-arm.h" | ||
592 | Index: gcc-4.5/gcc/config/arm/arm.h | ||
593 | =================================================================== | ||
594 | --- gcc-4.5.orig/gcc/config/arm/arm.h | ||
595 | +++ gcc-4.5/gcc/config/arm/arm.h | ||
596 | @@ -128,6 +128,24 @@ enum target_cpus | ||
597 | /* The processor for which instructions should be scheduled. */ | ||
598 | extern enum processor_type arm_tune; | ||
599 | |||
600 | +enum arm_sync_generator_tag | ||
601 | + { | ||
602 | + arm_sync_generator_omn, | ||
603 | + arm_sync_generator_omrn | ||
604 | + }; | ||
605 | + | ||
606 | +/* Wrapper to pass around a polymorphic pointer to a sync instruction | ||
607 | + generator and. */ | ||
608 | +struct arm_sync_generator | ||
609 | +{ | ||
610 | + enum arm_sync_generator_tag op; | ||
611 | + union | ||
612 | + { | ||
613 | + rtx (* omn) (rtx, rtx, rtx); | ||
614 | + rtx (* omrn) (rtx, rtx, rtx, rtx); | ||
615 | + } u; | ||
616 | +}; | ||
617 | + | ||
618 | typedef enum arm_cond_code | ||
619 | { | ||
620 | ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, | ||
621 | @@ -272,6 +290,20 @@ extern void (*arm_lang_output_object_att | ||
622 | for Thumb-2. */ | ||
623 | #define TARGET_UNIFIED_ASM TARGET_THUMB2 | ||
624 | |||
625 | +/* Nonzero if this chip provides the DMB instruction. */ | ||
626 | +#define TARGET_HAVE_DMB (arm_arch7) | ||
627 | + | ||
628 | +/* Nonzero if this chip implements a memory barrier via CP15. */ | ||
629 | +#define TARGET_HAVE_DMB_MCR (arm_arch6k && ! TARGET_HAVE_DMB) | ||
630 | + | ||
631 | +/* Nonzero if this chip implements a memory barrier instruction. */ | ||
632 | +#define TARGET_HAVE_MEMORY_BARRIER (TARGET_HAVE_DMB || TARGET_HAVE_DMB_MCR) | ||
633 | + | ||
634 | +/* Nonzero if this chip supports ldrex and strex */ | ||
635 | +#define TARGET_HAVE_LDREX ((arm_arch6 && TARGET_ARM) || arm_arch7) | ||
636 | + | ||
637 | +/* Nonzero if this chip supports ldrex{bhd} and strex{bhd}. */ | ||
638 | +#define TARGET_HAVE_LDREXBHD ((arm_arch6k && TARGET_ARM) || arm_arch7) | ||
639 | |||
640 | /* True iff the full BPABI is being used. If TARGET_BPABI is true, | ||
641 | then TARGET_AAPCS_BASED must be true -- but the converse does not | ||
642 | @@ -405,6 +437,12 @@ extern int arm_arch5e; | ||
643 | /* Nonzero if this chip supports the ARM Architecture 6 extensions. */ | ||
644 | extern int arm_arch6; | ||
645 | |||
646 | +/* Nonzero if this chip supports the ARM Architecture 6k extensions. */ | ||
647 | +extern int arm_arch6k; | ||
648 | + | ||
649 | +/* Nonzero if this chip supports the ARM Architecture 7 extensions. */ | ||
650 | +extern int arm_arch7; | ||
651 | + | ||
652 | /* Nonzero if instructions not present in the 'M' profile can be used. */ | ||
653 | extern int arm_arch_notm; | ||
654 | |||
655 | Index: gcc-4.5/gcc/config/arm/arm.md | ||
656 | =================================================================== | ||
657 | --- gcc-4.5.orig/gcc/config/arm/arm.md | ||
658 | +++ gcc-4.5/gcc/config/arm/arm.md | ||
659 | @@ -103,6 +103,7 @@ | ||
660 | (UNSPEC_RBIT 26) ; rbit operation. | ||
661 | (UNSPEC_SYMBOL_OFFSET 27) ; The offset of the start of the symbol from | ||
662 | ; another symbolic address. | ||
663 | + (UNSPEC_MEMORY_BARRIER 28) ; Represent a memory barrier. | ||
664 | ] | ||
665 | ) | ||
666 | |||
667 | @@ -139,6 +140,11 @@ | ||
668 | (VUNSPEC_ALIGN32 16) ; Used to force 32-byte alignment. | ||
669 | (VUNSPEC_EH_RETURN 20); Use to override the return address for exception | ||
670 | ; handling. | ||
671 | + (VUNSPEC_SYNC_COMPARE_AND_SWAP 21) ; Represent an atomic compare swap. | ||
672 | + (VUNSPEC_SYNC_LOCK 22) ; Represent a sync_lock_test_and_set. | ||
673 | + (VUNSPEC_SYNC_OP 23) ; Represent a sync_<op> | ||
674 | + (VUNSPEC_SYNC_NEW_OP 24) ; Represent a sync_new_<op> | ||
675 | + (VUNSPEC_SYNC_OLD_OP 25) ; Represent a sync_old_<op> | ||
676 | ] | ||
677 | ) | ||
678 | |||
679 | @@ -163,8 +169,21 @@ | ||
680 | (define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp" | ||
681 | (const (symbol_ref "arm_fpu_attr"))) | ||
682 | |||
683 | +(define_attr "sync_result" "none,0,1,2,3,4,5" (const_string "none")) | ||
684 | +(define_attr "sync_memory" "none,0,1,2,3,4,5" (const_string "none")) | ||
685 | +(define_attr "sync_required_value" "none,0,1,2,3,4,5" (const_string "none")) | ||
686 | +(define_attr "sync_new_value" "none,0,1,2,3,4,5" (const_string "none")) | ||
687 | +(define_attr "sync_t1" "none,0,1,2,3,4,5" (const_string "none")) | ||
688 | +(define_attr "sync_t2" "none,0,1,2,3,4,5" (const_string "none")) | ||
689 | +(define_attr "sync_release_barrier" "yes,no" (const_string "yes")) | ||
690 | +(define_attr "sync_op" "none,add,sub,ior,xor,and,nand" | ||
691 | + (const_string "none")) | ||
692 | + | ||
693 | ; LENGTH of an instruction (in bytes) | ||
694 | -(define_attr "length" "" (const_int 4)) | ||
695 | +(define_attr "length" "" | ||
696 | + (cond [(not (eq_attr "sync_memory" "none")) | ||
697 | + (symbol_ref "arm_sync_loop_insns (insn, operands) * 4") | ||
698 | + ] (const_int 4))) | ||
699 | |||
700 | ; POOL_RANGE is how far away from a constant pool entry that this insn | ||
701 | ; can be placed. If the distance is zero, then this insn will never | ||
702 | @@ -11549,4 +11568,5 @@ | ||
703 | (include "thumb2.md") | ||
704 | ;; Neon patterns | ||
705 | (include "neon.md") | ||
706 | - | ||
707 | +;; Synchronization Primitives | ||
708 | +(include "sync.md") | ||
709 | Index: gcc-4.5/gcc/config/arm/predicates.md | ||
710 | =================================================================== | ||
711 | --- gcc-4.5.orig/gcc/config/arm/predicates.md | ||
712 | +++ gcc-4.5/gcc/config/arm/predicates.md | ||
713 | @@ -573,6 +573,11 @@ | ||
714 | (and (match_test "TARGET_32BIT") | ||
715 | (match_operand 0 "arm_di_operand")))) | ||
716 | |||
717 | +;; True if the operand is memory reference suitable for a ldrex/strex. | ||
718 | +(define_predicate "arm_sync_memory_operand" | ||
719 | + (and (match_operand 0 "memory_operand") | ||
720 | + (match_code "reg" "0"))) | ||
721 | + | ||
722 | ;; Predicates for parallel expanders based on mode. | ||
723 | (define_special_predicate "vect_par_constant_high" | ||
724 | (match_code "parallel") | ||
725 | Index: gcc-4.5/gcc/testsuite/gcc.target/arm/synchronize.c | ||
726 | =================================================================== | ||
727 | --- gcc-4.5.orig/gcc/testsuite/gcc.target/arm/synchronize.c | ||
728 | +++ gcc-4.5/gcc/testsuite/gcc.target/arm/synchronize.c | ||
729 | @@ -1,4 +1,4 @@ | ||
730 | -/* { dg-final { scan-assembler "__sync_synchronize" { target arm*-*-linux-*eabi } } } */ | ||
731 | +/* { dg-final { scan-assembler "__sync_synchronize|dmb|mcr" { target arm*-*-linux-*eabi } } } */ | ||
732 | |||
733 | void *foo (void) | ||
734 | { | ||