Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/spu/spu.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. | 1 /* Copyright (C) 2006-2017 Free Software Foundation, Inc. |
2 | 2 |
3 This file is free software; you can redistribute it and/or modify it under | 3 This file is free software; you can redistribute it and/or modify it under |
4 the terms of the GNU General Public License as published by the Free | 4 the terms of the GNU General Public License as published by the Free |
5 Software Foundation; either version 3 of the License, or (at your option) | 5 Software Foundation; either version 3 of the License, or (at your option) |
6 any later version. | 6 any later version. |
15 <http://www.gnu.org/licenses/>. */ | 15 <http://www.gnu.org/licenses/>. */ |
16 | 16 |
17 #include "config.h" | 17 #include "config.h" |
18 #include "system.h" | 18 #include "system.h" |
19 #include "coretypes.h" | 19 #include "coretypes.h" |
20 #include "tm.h" | 20 #include "backend.h" |
21 #include "target.h" | |
21 #include "rtl.h" | 22 #include "rtl.h" |
23 #include "tree.h" | |
24 #include "gimple.h" | |
25 #include "cfghooks.h" | |
26 #include "cfgloop.h" | |
27 #include "df.h" | |
28 #include "memmodel.h" | |
29 #include "tm_p.h" | |
30 #include "stringpool.h" | |
31 #include "attribs.h" | |
32 #include "expmed.h" | |
33 #include "optabs.h" | |
22 #include "regs.h" | 34 #include "regs.h" |
23 #include "hard-reg-set.h" | 35 #include "emit-rtl.h" |
24 #include "insn-config.h" | 36 #include "recog.h" |
25 #include "conditions.h" | 37 #include "diagnostic-core.h" |
26 #include "insn-attr.h" | 38 #include "insn-attr.h" |
27 #include "flags.h" | 39 #include "alias.h" |
28 #include "recog.h" | 40 #include "fold-const.h" |
29 #include "obstack.h" | 41 #include "stor-layout.h" |
30 #include "tree.h" | 42 #include "calls.h" |
43 #include "varasm.h" | |
44 #include "explow.h" | |
31 #include "expr.h" | 45 #include "expr.h" |
32 #include "optabs.h" | |
33 #include "except.h" | |
34 #include "function.h" | |
35 #include "output.h" | 46 #include "output.h" |
36 #include "basic-block.h" | 47 #include "cfgrtl.h" |
37 #include "integrate.h" | 48 #include "cfgbuild.h" |
38 #include "diagnostic-core.h" | |
39 #include "ggc.h" | |
40 #include "hashtab.h" | |
41 #include "tm_p.h" | |
42 #include "target.h" | |
43 #include "target-def.h" | |
44 #include "langhooks.h" | 49 #include "langhooks.h" |
45 #include "reload.h" | 50 #include "reload.h" |
46 #include "cfglayout.h" | |
47 #include "sched-int.h" | 51 #include "sched-int.h" |
48 #include "params.h" | 52 #include "params.h" |
49 #include "machmode.h" | 53 #include "gimplify.h" |
50 #include "gimple.h" | |
51 #include "tm-constrs.h" | 54 #include "tm-constrs.h" |
52 #include "ddg.h" | 55 #include "ddg.h" |
53 #include "sbitmap.h" | 56 #include "dumpfile.h" |
54 #include "timevar.h" | 57 #include "builtins.h" |
55 #include "df.h" | 58 #include "rtl-iter.h" |
59 | |
60 /* This file should be included last. */ | |
61 #include "target-def.h" | |
56 | 62 |
57 /* Builtin types, data and prototypes. */ | 63 /* Builtin types, data and prototypes. */ |
58 | 64 |
59 enum spu_builtin_type_index | 65 enum spu_builtin_type_index |
60 { | 66 { |
145 | 151 |
146 /* Target specific attribute specifications. */ | 152 /* Target specific attribute specifications. */ |
147 char regs_ever_allocated[FIRST_PSEUDO_REGISTER]; | 153 char regs_ever_allocated[FIRST_PSEUDO_REGISTER]; |
148 | 154 |
149 /* Prototypes and external defs. */ | 155 /* Prototypes and external defs. */ |
150 static void spu_option_override (void); | 156 static int get_pipe (rtx_insn *insn); |
151 static void spu_option_init_struct (struct gcc_options *opts); | |
152 static void spu_option_default_params (void); | |
153 static void spu_init_builtins (void); | |
154 static tree spu_builtin_decl (unsigned, bool); | |
155 static bool spu_scalar_mode_supported_p (enum machine_mode mode); | |
156 static bool spu_vector_mode_supported_p (enum machine_mode mode); | |
157 static bool spu_legitimate_address_p (enum machine_mode, rtx, bool); | |
158 static bool spu_addr_space_legitimate_address_p (enum machine_mode, rtx, | |
159 bool, addr_space_t); | |
160 static rtx adjust_operand (rtx op, HOST_WIDE_INT * start); | |
161 static rtx get_pic_reg (void); | |
162 static int need_to_save_reg (int regno, int saving); | |
163 static rtx frame_emit_store (int regno, rtx addr, HOST_WIDE_INT offset); | |
164 static rtx frame_emit_load (int regno, rtx addr, HOST_WIDE_INT offset); | |
165 static rtx frame_emit_add_imm (rtx dst, rtx src, HOST_WIDE_INT imm, | |
166 rtx scratch); | |
167 static void emit_nop_for_insn (rtx insn); | |
168 static bool insn_clobbers_hbr (rtx insn); | |
169 static void spu_emit_branch_hint (rtx before, rtx branch, rtx target, | |
170 int distance, sbitmap blocks); | |
171 static rtx spu_emit_vector_compare (enum rtx_code rcode, rtx op0, rtx op1, | |
172 enum machine_mode dmode); | |
173 static rtx get_branch_target (rtx branch); | |
174 static void spu_machine_dependent_reorg (void); | |
175 static int spu_sched_issue_rate (void); | |
176 static int spu_sched_variable_issue (FILE * dump, int verbose, rtx insn, | |
177 int can_issue_more); | |
178 static int get_pipe (rtx insn); | |
179 static int spu_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost); | |
180 static void spu_sched_init_global (FILE *, int, int); | |
181 static void spu_sched_init (FILE *, int, int); | |
182 static int spu_sched_reorder (FILE *, int, rtx *, int *, int); | |
183 static tree spu_handle_fndecl_attribute (tree * node, tree name, tree args, | |
184 int flags, | |
185 bool *no_add_attrs); | |
186 static tree spu_handle_vector_attribute (tree * node, tree name, tree args, | |
187 int flags, | |
188 bool *no_add_attrs); | |
189 static int spu_naked_function_p (tree func); | 157 static int spu_naked_function_p (tree func); |
190 static bool spu_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode, | |
191 const_tree type, bool named); | |
192 static rtx spu_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, | |
193 const_tree type, bool named); | |
194 static void spu_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, | |
195 const_tree type, bool named); | |
196 static tree spu_build_builtin_va_list (void); | |
197 static void spu_va_start (tree, rtx); | |
198 static tree spu_gimplify_va_arg_expr (tree valist, tree type, | |
199 gimple_seq * pre_p, gimple_seq * post_p); | |
200 static int store_with_one_insn_p (rtx mem); | |
201 static int mem_is_padded_component_ref (rtx x); | 158 static int mem_is_padded_component_ref (rtx x); |
202 static int reg_aligned_for_addr (rtx x); | |
203 static bool spu_assemble_integer (rtx x, unsigned int size, int aligned_p); | |
204 static void spu_asm_globalize_label (FILE * file, const char *name); | |
205 static bool spu_rtx_costs (rtx x, int code, int outer_code, | |
206 int *total, bool speed); | |
207 static bool spu_function_ok_for_sibcall (tree decl, tree exp); | |
208 static void spu_init_libfuncs (void); | |
209 static bool spu_return_in_memory (const_tree type, const_tree fntype); | |
210 static void fix_range (const char *); | 159 static void fix_range (const char *); |
211 static void spu_encode_section_info (tree, rtx, int); | |
212 static rtx spu_legitimize_address (rtx, rtx, enum machine_mode); | |
213 static rtx spu_addr_space_legitimize_address (rtx, rtx, enum machine_mode, | |
214 addr_space_t); | |
215 static tree spu_builtin_mul_widen_even (tree); | |
216 static tree spu_builtin_mul_widen_odd (tree); | |
217 static tree spu_builtin_mask_for_load (void); | |
218 static int spu_builtin_vectorization_cost (enum vect_cost_for_stmt, tree, int); | |
219 static bool spu_vector_alignment_reachable (const_tree, bool); | |
220 static tree spu_builtin_vec_perm (tree, tree *); | |
221 static enum machine_mode spu_addr_space_pointer_mode (addr_space_t); | |
222 static enum machine_mode spu_addr_space_address_mode (addr_space_t); | |
223 static bool spu_addr_space_subset_p (addr_space_t, addr_space_t); | |
224 static rtx spu_addr_space_convert (rtx, tree, tree); | |
225 static int spu_sms_res_mii (struct ddg *g); | |
226 static void asm_file_start (void); | |
227 static unsigned int spu_section_type_flags (tree, const char *, int); | |
228 static section *spu_select_section (tree, int, unsigned HOST_WIDE_INT); | |
229 static void spu_unique_section (tree, int); | |
230 static rtx spu_expand_load (rtx, rtx, rtx, int); | 160 static rtx spu_expand_load (rtx, rtx, rtx, int); |
231 static void spu_trampoline_init (rtx, tree, rtx); | |
232 static void spu_conditional_register_usage (void); | |
233 static bool spu_ref_may_alias_errno (ao_ref *); | |
234 | 161 |
235 /* Which instruction set architecture to use. */ | 162 /* Which instruction set architecture to use. */ |
236 int spu_arch; | 163 int spu_arch; |
237 /* Which cpu are we tuning for. */ | 164 /* Which cpu are we tuning for. */ |
238 int spu_tune; | 165 int spu_tune; |
242 compiler needs to see before inserting a hint, and then the compiler | 169 compiler needs to see before inserting a hint, and then the compiler |
243 will insert enough nops to make it at least 8 insns. The default is | 170 will insert enough nops to make it at least 8 insns. The default is |
244 for the compiler to allow up to 2 nops be emitted. The nops are | 171 for the compiler to allow up to 2 nops be emitted. The nops are |
245 inserted in pairs, so we round down. */ | 172 inserted in pairs, so we round down. */ |
246 int spu_hint_dist = (8*4) - (2*4); | 173 int spu_hint_dist = (8*4) - (2*4); |
247 | |
248 /* Determines whether we run variable tracking in machine dependent | |
249 reorganization. */ | |
250 static int spu_flag_var_tracking; | |
251 | 174 |
252 enum spu_immediate { | 175 enum spu_immediate { |
253 SPU_NONE, | 176 SPU_NONE, |
254 SPU_IL, | 177 SPU_IL, |
255 SPU_ILA, | 178 SPU_ILA, |
274 | 197 |
275 static enum spu_immediate which_immediate_load (HOST_WIDE_INT val); | 198 static enum spu_immediate which_immediate_load (HOST_WIDE_INT val); |
276 static enum spu_immediate which_logical_immediate (HOST_WIDE_INT val); | 199 static enum spu_immediate which_logical_immediate (HOST_WIDE_INT val); |
277 static int cpat_info(unsigned char *arr, int size, int *prun, int *pstart); | 200 static int cpat_info(unsigned char *arr, int size, int *prun, int *pstart); |
278 static enum immediate_class classify_immediate (rtx op, | 201 static enum immediate_class classify_immediate (rtx op, |
279 enum machine_mode mode); | 202 machine_mode mode); |
280 | |
281 static enum machine_mode spu_unwind_word_mode (void); | |
282 | |
283 static enum machine_mode | |
284 spu_libgcc_cmp_return_mode (void); | |
285 | |
286 static enum machine_mode | |
287 spu_libgcc_shift_count_mode (void); | |
288 | 203 |
289 /* Pointer mode for __ea references. */ | 204 /* Pointer mode for __ea references. */ |
290 #define EAmode (spu_ea_model != 32 ? DImode : SImode) | 205 #define EAmode (spu_ea_model != 32 ? DImode : SImode) |
291 | 206 |
292 | 207 |
293 /* Table of machine attributes. */ | 208 /* Define the structure for the machine field in struct function. */ |
294 static const struct attribute_spec spu_attribute_table[] = | 209 struct GTY(()) machine_function |
295 { | 210 { |
296 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ | 211 /* Register to use for PIC accesses. */ |
297 { "naked", 0, 0, true, false, false, spu_handle_fndecl_attribute }, | 212 rtx pic_reg; |
298 { "spu_vector", 0, 0, false, true, false, spu_handle_vector_attribute }, | |
299 { NULL, 0, 0, false, false, false, NULL } | |
300 }; | 213 }; |
301 | 214 |
302 /* TARGET overrides. */ | 215 /* How to allocate a 'struct machine_function'. */ |
303 | 216 static struct machine_function * |
304 #undef TARGET_ADDR_SPACE_POINTER_MODE | 217 spu_init_machine_status (void) |
305 #define TARGET_ADDR_SPACE_POINTER_MODE spu_addr_space_pointer_mode | 218 { |
306 | 219 return ggc_cleared_alloc<machine_function> (); |
307 #undef TARGET_ADDR_SPACE_ADDRESS_MODE | |
308 #define TARGET_ADDR_SPACE_ADDRESS_MODE spu_addr_space_address_mode | |
309 | |
310 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P | |
311 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ | |
312 spu_addr_space_legitimate_address_p | |
313 | |
314 #undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS | |
315 #define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS spu_addr_space_legitimize_address | |
316 | |
317 #undef TARGET_ADDR_SPACE_SUBSET_P | |
318 #define TARGET_ADDR_SPACE_SUBSET_P spu_addr_space_subset_p | |
319 | |
320 #undef TARGET_ADDR_SPACE_CONVERT | |
321 #define TARGET_ADDR_SPACE_CONVERT spu_addr_space_convert | |
322 | |
323 #undef TARGET_INIT_BUILTINS | |
324 #define TARGET_INIT_BUILTINS spu_init_builtins | |
325 #undef TARGET_BUILTIN_DECL | |
326 #define TARGET_BUILTIN_DECL spu_builtin_decl | |
327 | |
328 #undef TARGET_EXPAND_BUILTIN | |
329 #define TARGET_EXPAND_BUILTIN spu_expand_builtin | |
330 | |
331 #undef TARGET_UNWIND_WORD_MODE | |
332 #define TARGET_UNWIND_WORD_MODE spu_unwind_word_mode | |
333 | |
334 #undef TARGET_LEGITIMIZE_ADDRESS | |
335 #define TARGET_LEGITIMIZE_ADDRESS spu_legitimize_address | |
336 | |
337 /* The current assembler doesn't like .4byte foo@ppu, so use the normal .long | |
338 and .quad for the debugger. When it is known that the assembler is fixed, | |
339 these can be removed. */ | |
340 #undef TARGET_ASM_UNALIGNED_SI_OP | |
341 #define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" | |
342 | |
343 #undef TARGET_ASM_ALIGNED_DI_OP | |
344 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" | |
345 | |
346 /* The .8byte directive doesn't seem to work well for a 32 bit | |
347 architecture. */ | |
348 #undef TARGET_ASM_UNALIGNED_DI_OP | |
349 #define TARGET_ASM_UNALIGNED_DI_OP NULL | |
350 | |
351 #undef TARGET_RTX_COSTS | |
352 #define TARGET_RTX_COSTS spu_rtx_costs | |
353 | |
354 #undef TARGET_ADDRESS_COST | |
355 #define TARGET_ADDRESS_COST hook_int_rtx_bool_0 | |
356 | |
357 #undef TARGET_SCHED_ISSUE_RATE | |
358 #define TARGET_SCHED_ISSUE_RATE spu_sched_issue_rate | |
359 | |
360 #undef TARGET_SCHED_INIT_GLOBAL | |
361 #define TARGET_SCHED_INIT_GLOBAL spu_sched_init_global | |
362 | |
363 #undef TARGET_SCHED_INIT | |
364 #define TARGET_SCHED_INIT spu_sched_init | |
365 | |
366 #undef TARGET_SCHED_VARIABLE_ISSUE | |
367 #define TARGET_SCHED_VARIABLE_ISSUE spu_sched_variable_issue | |
368 | |
369 #undef TARGET_SCHED_REORDER | |
370 #define TARGET_SCHED_REORDER spu_sched_reorder | |
371 | |
372 #undef TARGET_SCHED_REORDER2 | |
373 #define TARGET_SCHED_REORDER2 spu_sched_reorder | |
374 | |
375 #undef TARGET_SCHED_ADJUST_COST | |
376 #define TARGET_SCHED_ADJUST_COST spu_sched_adjust_cost | |
377 | |
378 #undef TARGET_ATTRIBUTE_TABLE | |
379 #define TARGET_ATTRIBUTE_TABLE spu_attribute_table | |
380 | |
381 #undef TARGET_ASM_INTEGER | |
382 #define TARGET_ASM_INTEGER spu_assemble_integer | |
383 | |
384 #undef TARGET_SCALAR_MODE_SUPPORTED_P | |
385 #define TARGET_SCALAR_MODE_SUPPORTED_P spu_scalar_mode_supported_p | |
386 | |
387 #undef TARGET_VECTOR_MODE_SUPPORTED_P | |
388 #define TARGET_VECTOR_MODE_SUPPORTED_P spu_vector_mode_supported_p | |
389 | |
390 #undef TARGET_FUNCTION_OK_FOR_SIBCALL | |
391 #define TARGET_FUNCTION_OK_FOR_SIBCALL spu_function_ok_for_sibcall | |
392 | |
393 #undef TARGET_ASM_GLOBALIZE_LABEL | |
394 #define TARGET_ASM_GLOBALIZE_LABEL spu_asm_globalize_label | |
395 | |
396 #undef TARGET_PASS_BY_REFERENCE | |
397 #define TARGET_PASS_BY_REFERENCE spu_pass_by_reference | |
398 | |
399 #undef TARGET_FUNCTION_ARG | |
400 #define TARGET_FUNCTION_ARG spu_function_arg | |
401 | |
402 #undef TARGET_FUNCTION_ARG_ADVANCE | |
403 #define TARGET_FUNCTION_ARG_ADVANCE spu_function_arg_advance | |
404 | |
405 #undef TARGET_MUST_PASS_IN_STACK | |
406 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size | |
407 | |
408 #undef TARGET_BUILD_BUILTIN_VA_LIST | |
409 #define TARGET_BUILD_BUILTIN_VA_LIST spu_build_builtin_va_list | |
410 | |
411 #undef TARGET_EXPAND_BUILTIN_VA_START | |
412 #define TARGET_EXPAND_BUILTIN_VA_START spu_va_start | |
413 | |
414 #undef TARGET_SETUP_INCOMING_VARARGS | |
415 #define TARGET_SETUP_INCOMING_VARARGS spu_setup_incoming_varargs | |
416 | |
417 #undef TARGET_MACHINE_DEPENDENT_REORG | |
418 #define TARGET_MACHINE_DEPENDENT_REORG spu_machine_dependent_reorg | |
419 | |
420 #undef TARGET_GIMPLIFY_VA_ARG_EXPR | |
421 #define TARGET_GIMPLIFY_VA_ARG_EXPR spu_gimplify_va_arg_expr | |
422 | |
423 #undef TARGET_DEFAULT_TARGET_FLAGS | |
424 #define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT) | |
425 | |
426 #undef TARGET_INIT_LIBFUNCS | |
427 #define TARGET_INIT_LIBFUNCS spu_init_libfuncs | |
428 | |
429 #undef TARGET_RETURN_IN_MEMORY | |
430 #define TARGET_RETURN_IN_MEMORY spu_return_in_memory | |
431 | |
432 #undef TARGET_ENCODE_SECTION_INFO | |
433 #define TARGET_ENCODE_SECTION_INFO spu_encode_section_info | |
434 | |
435 #undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN | |
436 #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN spu_builtin_mul_widen_even | |
437 | |
438 #undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD | |
439 #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD spu_builtin_mul_widen_odd | |
440 | |
441 #undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD | |
442 #define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD spu_builtin_mask_for_load | |
443 | |
444 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST | |
445 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST spu_builtin_vectorization_cost | |
446 | |
447 #undef TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE | |
448 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE spu_vector_alignment_reachable | |
449 | |
450 #undef TARGET_VECTORIZE_BUILTIN_VEC_PERM | |
451 #define TARGET_VECTORIZE_BUILTIN_VEC_PERM spu_builtin_vec_perm | |
452 | |
453 #undef TARGET_LIBGCC_CMP_RETURN_MODE | |
454 #define TARGET_LIBGCC_CMP_RETURN_MODE spu_libgcc_cmp_return_mode | |
455 | |
456 #undef TARGET_LIBGCC_SHIFT_COUNT_MODE | |
457 #define TARGET_LIBGCC_SHIFT_COUNT_MODE spu_libgcc_shift_count_mode | |
458 | |
459 #undef TARGET_SCHED_SMS_RES_MII | |
460 #define TARGET_SCHED_SMS_RES_MII spu_sms_res_mii | |
461 | |
462 #undef TARGET_ASM_FILE_START | |
463 #define TARGET_ASM_FILE_START asm_file_start | |
464 | |
465 #undef TARGET_SECTION_TYPE_FLAGS | |
466 #define TARGET_SECTION_TYPE_FLAGS spu_section_type_flags | |
467 | |
468 #undef TARGET_ASM_SELECT_SECTION | |
469 #define TARGET_ASM_SELECT_SECTION spu_select_section | |
470 | |
471 #undef TARGET_ASM_UNIQUE_SECTION | |
472 #define TARGET_ASM_UNIQUE_SECTION spu_unique_section | |
473 | |
474 #undef TARGET_LEGITIMATE_ADDRESS_P | |
475 #define TARGET_LEGITIMATE_ADDRESS_P spu_legitimate_address_p | |
476 | |
477 #undef TARGET_TRAMPOLINE_INIT | |
478 #define TARGET_TRAMPOLINE_INIT spu_trampoline_init | |
479 | |
480 #undef TARGET_OPTION_OVERRIDE | |
481 #define TARGET_OPTION_OVERRIDE spu_option_override | |
482 | |
483 #undef TARGET_OPTION_INIT_STRUCT | |
484 #define TARGET_OPTION_INIT_STRUCT spu_option_init_struct | |
485 | |
486 #undef TARGET_OPTION_DEFAULT_PARAMS | |
487 #define TARGET_OPTION_DEFAULT_PARAMS spu_option_default_params | |
488 | |
489 #undef TARGET_EXCEPT_UNWIND_INFO | |
490 #define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info | |
491 | |
492 #undef TARGET_CONDITIONAL_REGISTER_USAGE | |
493 #define TARGET_CONDITIONAL_REGISTER_USAGE spu_conditional_register_usage | |
494 | |
495 #undef TARGET_REF_MAY_ALIAS_ERRNO | |
496 #define TARGET_REF_MAY_ALIAS_ERRNO spu_ref_may_alias_errno | |
497 | |
498 struct gcc_target targetm = TARGET_INITIALIZER; | |
499 | |
500 static void | |
501 spu_option_init_struct (struct gcc_options *opts) | |
502 { | |
503 /* With so many registers this is better on by default. */ | |
504 opts->x_flag_rename_registers = 1; | |
505 } | |
506 | |
507 /* Implement TARGET_OPTION_DEFAULT_PARAMS. */ | |
508 static void | |
509 spu_option_default_params (void) | |
510 { | |
511 /* Override some of the default param values. With so many registers | |
512 larger values are better for these params. */ | |
513 set_default_param_value (PARAM_MAX_PENDING_LIST_LENGTH, 128); | |
514 } | 220 } |
515 | 221 |
516 /* Implement TARGET_OPTION_OVERRIDE. */ | 222 /* Implement TARGET_OPTION_OVERRIDE. */ |
517 static void | 223 static void |
518 spu_option_override (void) | 224 spu_option_override (void) |
519 { | 225 { |
226 /* Set up function hooks. */ | |
227 init_machine_status = spu_init_machine_status; | |
228 | |
520 /* Small loops will be unpeeled at -O3. For SPU it is more important | 229 /* Small loops will be unpeeled at -O3. For SPU it is more important |
521 to keep code small by default. */ | 230 to keep code small by default. */ |
522 if (!flag_unroll_loops && !flag_peel_loops) | 231 if (!flag_unroll_loops && !flag_peel_loops) |
523 maybe_set_param_value (PARAM_MAX_COMPLETELY_PEEL_TIMES, 4, | 232 maybe_set_param_value (PARAM_MAX_COMPLETELY_PEEL_TIMES, 4, |
524 global_options.x_param_values, | 233 global_options.x_param_values, |
570 } | 279 } |
571 | 280 |
572 REAL_MODE_FORMAT (SFmode) = &spu_single_format; | 281 REAL_MODE_FORMAT (SFmode) = &spu_single_format; |
573 } | 282 } |
574 | 283 |
284 /* Implement TARGET_HARD_REGNO_NREGS. */ | |
285 | |
286 static unsigned int | |
287 spu_hard_regno_nregs (unsigned int, machine_mode mode) | |
288 { | |
289 return CEIL (GET_MODE_BITSIZE (mode), MAX_FIXED_MODE_SIZE); | |
290 } | |
291 | |
575 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in | 292 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in |
576 struct attribute_spec.handler. */ | 293 struct attribute_spec.handler. */ |
577 | 294 |
578 /* True if MODE is valid for the target. By "valid", we mean able to | 295 /* True if MODE is valid for the target. By "valid", we mean able to |
579 be manipulated in non-trivial ways. In particular, this means all | 296 be manipulated in non-trivial ways. In particular, this means all |
580 the arithmetic is supported. */ | 297 the arithmetic is supported. */ |
581 static bool | 298 static bool |
582 spu_scalar_mode_supported_p (enum machine_mode mode) | 299 spu_scalar_mode_supported_p (scalar_mode mode) |
583 { | 300 { |
584 switch (mode) | 301 switch (mode) |
585 { | 302 { |
586 case QImode: | 303 case E_QImode: |
587 case HImode: | 304 case E_HImode: |
588 case SImode: | 305 case E_SImode: |
589 case SFmode: | 306 case E_SFmode: |
590 case DImode: | 307 case E_DImode: |
591 case TImode: | 308 case E_TImode: |
592 case DFmode: | 309 case E_DFmode: |
593 return true; | 310 return true; |
594 | 311 |
595 default: | 312 default: |
596 return false; | 313 return false; |
597 } | 314 } |
599 | 316 |
600 /* Similarly for vector modes. "Supported" here is less strict. At | 317 /* Similarly for vector modes. "Supported" here is less strict. At |
601 least some operations are supported; need to check optabs or builtins | 318 least some operations are supported; need to check optabs or builtins |
602 for further details. */ | 319 for further details. */ |
603 static bool | 320 static bool |
604 spu_vector_mode_supported_p (enum machine_mode mode) | 321 spu_vector_mode_supported_p (machine_mode mode) |
605 { | 322 { |
606 switch (mode) | 323 switch (mode) |
607 { | 324 { |
608 case V16QImode: | 325 case E_V16QImode: |
609 case V8HImode: | 326 case E_V8HImode: |
610 case V4SImode: | 327 case E_V4SImode: |
611 case V2DImode: | 328 case E_V2DImode: |
612 case V4SFmode: | 329 case E_V4SFmode: |
613 case V2DFmode: | 330 case E_V2DFmode: |
614 return true; | 331 return true; |
615 | 332 |
616 default: | 333 default: |
617 return false; | 334 return false; |
618 } | 335 } |
622 least significant bytes of the outer mode. This function returns | 339 least significant bytes of the outer mode. This function returns |
623 TRUE for the SUBREG's where this is correct. */ | 340 TRUE for the SUBREG's where this is correct. */ |
624 int | 341 int |
625 valid_subreg (rtx op) | 342 valid_subreg (rtx op) |
626 { | 343 { |
627 enum machine_mode om = GET_MODE (op); | 344 machine_mode om = GET_MODE (op); |
628 enum machine_mode im = GET_MODE (SUBREG_REG (op)); | 345 machine_mode im = GET_MODE (SUBREG_REG (op)); |
629 return om != VOIDmode && im != VOIDmode | 346 return om != VOIDmode && im != VOIDmode |
630 && (GET_MODE_SIZE (im) == GET_MODE_SIZE (om) | 347 && (GET_MODE_SIZE (im) == GET_MODE_SIZE (om) |
631 || (GET_MODE_SIZE (im) <= 4 && GET_MODE_SIZE (om) <= 4) | 348 || (GET_MODE_SIZE (im) <= 4 && GET_MODE_SIZE (om) <= 4) |
632 || (GET_MODE_SIZE (im) >= 16 && GET_MODE_SIZE (om) >= 16)); | 349 || (GET_MODE_SIZE (im) >= 16 && GET_MODE_SIZE (om) >= 16)); |
633 } | 350 } |
635 /* When insv and ext[sz]v ar passed a TI SUBREG, we want to strip it off | 352 /* When insv and ext[sz]v ar passed a TI SUBREG, we want to strip it off |
636 and adjust the start offset. */ | 353 and adjust the start offset. */ |
637 static rtx | 354 static rtx |
638 adjust_operand (rtx op, HOST_WIDE_INT * start) | 355 adjust_operand (rtx op, HOST_WIDE_INT * start) |
639 { | 356 { |
640 enum machine_mode mode; | 357 machine_mode mode; |
641 int op_size; | 358 int op_size; |
642 /* Strip any paradoxical SUBREG. */ | 359 /* Strip any paradoxical SUBREG. */ |
643 if (GET_CODE (op) == SUBREG | 360 if (GET_CODE (op) == SUBREG |
644 && (GET_MODE_BITSIZE (GET_MODE (op)) | 361 && (GET_MODE_BITSIZE (GET_MODE (op)) |
645 > GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op))))) | 362 > GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op))))) |
657 if (start) | 374 if (start) |
658 *start += 32 - op_size; | 375 *start += 32 - op_size; |
659 op_size = 32; | 376 op_size = 32; |
660 } | 377 } |
661 /* If it is not a MODE_INT (and/or it is smaller than SI) add a SUBREG. */ | 378 /* If it is not a MODE_INT (and/or it is smaller than SI) add a SUBREG. */ |
662 mode = mode_for_size (op_size, MODE_INT, 0); | 379 mode = int_mode_for_size (op_size, 0).require (); |
663 if (mode != GET_MODE (op)) | 380 if (mode != GET_MODE (op)) |
664 op = gen_rtx_SUBREG (mode, op, 0); | 381 op = gen_rtx_SUBREG (mode, op, 0); |
665 return op; | 382 return op; |
666 } | 383 } |
667 | 384 |
722 { | 439 { |
723 rtx r = SUBREG_REG (src); | 440 rtx r = SUBREG_REG (src); |
724 gcc_assert (REG_P (r) && SCALAR_INT_MODE_P (GET_MODE (r))); | 441 gcc_assert (REG_P (r) && SCALAR_INT_MODE_P (GET_MODE (r))); |
725 s0 = gen_reg_rtx (TImode); | 442 s0 = gen_reg_rtx (TImode); |
726 if (GET_MODE_SIZE (GET_MODE (r)) < GET_MODE_SIZE (TImode)) | 443 if (GET_MODE_SIZE (GET_MODE (r)) < GET_MODE_SIZE (TImode)) |
727 emit_insn (gen_rtx_SET (VOIDmode, s0, gen_rtx_ZERO_EXTEND (TImode, r))); | 444 emit_insn (gen_rtx_SET (s0, gen_rtx_ZERO_EXTEND (TImode, r))); |
728 else | 445 else |
729 emit_move_insn (s0, src); | 446 emit_move_insn (s0, src); |
730 } | 447 } |
731 else | 448 else |
732 { | 449 { |
739 | 456 |
740 if (start) | 457 if (start) |
741 emit_insn (gen_rotlti3 (s0, s0, GEN_INT (start))); | 458 emit_insn (gen_rotlti3 (s0, s0, GEN_INT (start))); |
742 | 459 |
743 if (128 - width) | 460 if (128 - width) |
744 { | 461 s0 = expand_shift (RSHIFT_EXPR, TImode, s0, 128 - width, s0, unsignedp); |
745 tree c = build_int_cst (NULL_TREE, 128 - width); | |
746 s0 = expand_shift (RSHIFT_EXPR, TImode, s0, c, s0, unsignedp); | |
747 } | |
748 | 462 |
749 emit_move_insn (dst, s0); | 463 emit_move_insn (dst, s0); |
750 } | 464 } |
751 | 465 |
752 void | 466 void |
753 spu_expand_insv (rtx ops[]) | 467 spu_expand_insv (rtx ops[]) |
754 { | 468 { |
755 HOST_WIDE_INT width = INTVAL (ops[1]); | 469 HOST_WIDE_INT width = INTVAL (ops[1]); |
756 HOST_WIDE_INT start = INTVAL (ops[2]); | 470 HOST_WIDE_INT start = INTVAL (ops[2]); |
757 HOST_WIDE_INT maskbits; | 471 unsigned HOST_WIDE_INT maskbits; |
758 enum machine_mode dst_mode; | 472 machine_mode dst_mode; |
759 rtx dst = ops[0], src = ops[3]; | 473 rtx dst = ops[0], src = ops[3]; |
760 int dst_size; | 474 int dst_size; |
761 rtx mask; | 475 rtx mask; |
762 rtx shift_reg; | 476 rtx shift_reg; |
763 int shift; | 477 int shift; |
770 dst_mode = GET_MODE (dst); | 484 dst_mode = GET_MODE (dst); |
771 dst_size = GET_MODE_BITSIZE (GET_MODE (dst)); | 485 dst_size = GET_MODE_BITSIZE (GET_MODE (dst)); |
772 | 486 |
773 if (CONSTANT_P (src)) | 487 if (CONSTANT_P (src)) |
774 { | 488 { |
775 enum machine_mode m = | 489 machine_mode m = |
776 (width <= 32 ? SImode : width <= 64 ? DImode : TImode); | 490 (width <= 32 ? SImode : width <= 64 ? DImode : TImode); |
777 src = force_reg (m, convert_to_mode (m, src, 0)); | 491 src = force_reg (m, convert_to_mode (m, src, 0)); |
778 } | 492 } |
779 src = adjust_operand (src, 0); | 493 src = adjust_operand (src, 0); |
780 | 494 |
788 | 502 |
789 if (shift > 0) | 503 if (shift > 0) |
790 { | 504 { |
791 switch (dst_mode) | 505 switch (dst_mode) |
792 { | 506 { |
793 case SImode: | 507 case E_SImode: |
794 emit_insn (gen_ashlsi3 (shift_reg, shift_reg, GEN_INT (shift))); | 508 emit_insn (gen_ashlsi3 (shift_reg, shift_reg, GEN_INT (shift))); |
795 break; | 509 break; |
796 case DImode: | 510 case E_DImode: |
797 emit_insn (gen_ashldi3 (shift_reg, shift_reg, GEN_INT (shift))); | 511 emit_insn (gen_ashldi3 (shift_reg, shift_reg, GEN_INT (shift))); |
798 break; | 512 break; |
799 case TImode: | 513 case E_TImode: |
800 emit_insn (gen_ashlti3 (shift_reg, shift_reg, GEN_INT (shift))); | 514 emit_insn (gen_ashlti3 (shift_reg, shift_reg, GEN_INT (shift))); |
801 break; | 515 break; |
802 default: | 516 default: |
803 abort (); | 517 abort (); |
804 } | 518 } |
807 abort (); | 521 abort (); |
808 | 522 |
809 switch (dst_size) | 523 switch (dst_size) |
810 { | 524 { |
811 case 32: | 525 case 32: |
812 maskbits = (-1ll << (32 - width - start)); | 526 maskbits = (~(unsigned HOST_WIDE_INT)0 << (32 - width - start)); |
813 if (start) | 527 if (start) |
814 maskbits += (1ll << (32 - start)); | 528 maskbits += ((unsigned HOST_WIDE_INT)1 << (32 - start)); |
815 emit_move_insn (mask, GEN_INT (maskbits)); | 529 emit_move_insn (mask, GEN_INT (maskbits)); |
816 break; | 530 break; |
817 case 64: | 531 case 64: |
818 maskbits = (-1ll << (64 - width - start)); | 532 maskbits = (~(unsigned HOST_WIDE_INT)0 << (64 - width - start)); |
819 if (start) | 533 if (start) |
820 maskbits += (1ll << (64 - start)); | 534 maskbits += ((unsigned HOST_WIDE_INT)1 << (64 - start)); |
821 emit_move_insn (mask, GEN_INT (maskbits)); | 535 emit_move_insn (mask, GEN_INT (maskbits)); |
822 break; | 536 break; |
823 case 128: | 537 case 128: |
824 { | 538 { |
825 unsigned char arr[16]; | 539 unsigned char arr[16]; |
859 { | 573 { |
860 rtx shl = gen_reg_rtx (SImode); | 574 rtx shl = gen_reg_rtx (SImode); |
861 rtx mask1 = gen_reg_rtx (TImode); | 575 rtx mask1 = gen_reg_rtx (TImode); |
862 rtx dst1 = gen_reg_rtx (TImode); | 576 rtx dst1 = gen_reg_rtx (TImode); |
863 rtx mem1; | 577 rtx mem1; |
864 addr1 = plus_constant (addr, 16); | 578 addr1 = plus_constant (Pmode, addr, 16); |
865 addr1 = gen_rtx_AND (Pmode, addr1, GEN_INT (-16)); | 579 addr1 = gen_rtx_AND (Pmode, addr1, GEN_INT (-16)); |
866 emit_insn (gen_subsi3 (shl, GEN_INT (16), low)); | 580 emit_insn (gen_subsi3 (shl, GEN_INT (16), low)); |
867 emit_insn (gen_shlqby_ti (mask1, mask, shl)); | 581 emit_insn (gen_shlqby_ti (mask1, mask, shl)); |
868 mem1 = change_address (ops[0], TImode, addr1); | 582 mem1 = change_address (ops[0], TImode, addr1); |
869 set_mem_alias_set (mem1, 0); | 583 set_mem_alias_set (mem1, 0); |
957 { | 671 { |
958 int reverse_compare = 0; | 672 int reverse_compare = 0; |
959 int reverse_test = 0; | 673 int reverse_test = 0; |
960 rtx compare_result, eq_result; | 674 rtx compare_result, eq_result; |
961 rtx comp_rtx, eq_rtx; | 675 rtx comp_rtx, eq_rtx; |
962 enum machine_mode comp_mode; | 676 machine_mode comp_mode; |
963 enum machine_mode op_mode; | 677 machine_mode op_mode; |
964 enum spu_comp_code scode, eq_code; | 678 enum spu_comp_code scode, eq_code; |
965 enum insn_code ior_code; | 679 enum insn_code ior_code; |
966 enum rtx_code code = GET_CODE (cmp); | 680 enum rtx_code code = GET_CODE (cmp); |
967 rtx op0 = XEXP (cmp, 0); | 681 rtx op0 = XEXP (cmp, 0); |
968 rtx op1 = XEXP (cmp, 1); | 682 rtx op1 = XEXP (cmp, 1); |
990 code = GTU; | 704 code = GTU; |
991 break; | 705 break; |
992 case LTU: | 706 case LTU: |
993 op1 = GEN_INT (val); | 707 op1 = GEN_INT (val); |
994 code = LEU; | 708 code = LEU; |
709 break; | |
710 default: | |
711 break; | |
712 } | |
713 } | |
714 | |
715 /* However, if we generate an integer result, performing a reverse test | |
716 would require an extra negation, so avoid that where possible. */ | |
717 if (GET_CODE (op1) == CONST_INT && is_set == 1) | |
718 { | |
719 HOST_WIDE_INT val = INTVAL (op1) + 1; | |
720 if (trunc_int_for_mode (val, GET_MODE (op0)) == val) | |
721 switch (code) | |
722 { | |
723 case LE: | |
724 op1 = GEN_INT (val); | |
725 code = LT; | |
726 break; | |
727 case LEU: | |
728 op1 = GEN_INT (val); | |
729 code = LTU; | |
995 break; | 730 break; |
996 default: | 731 default: |
997 break; | 732 break; |
998 } | 733 } |
999 } | 734 } |
1073 break; | 808 break; |
1074 } | 809 } |
1075 | 810 |
1076 switch (op_mode) | 811 switch (op_mode) |
1077 { | 812 { |
1078 case QImode: | 813 case E_QImode: |
1079 index = 0; | 814 index = 0; |
1080 comp_mode = QImode; | 815 comp_mode = QImode; |
1081 break; | 816 break; |
1082 case HImode: | 817 case E_HImode: |
1083 index = 1; | 818 index = 1; |
1084 comp_mode = HImode; | 819 comp_mode = HImode; |
1085 break; | 820 break; |
1086 case SImode: | 821 case E_SImode: |
1087 index = 2; | 822 index = 2; |
1088 break; | 823 break; |
1089 case DImode: | 824 case E_DImode: |
1090 index = 3; | 825 index = 3; |
1091 break; | 826 break; |
1092 case TImode: | 827 case E_TImode: |
1093 index = 4; | 828 index = 4; |
1094 break; | 829 break; |
1095 case SFmode: | 830 case E_SFmode: |
1096 index = 5; | 831 index = 5; |
1097 break; | 832 break; |
1098 case DFmode: | 833 case E_DFmode: |
1099 index = 6; | 834 index = 6; |
1100 break; | 835 break; |
1101 case V16QImode: | 836 case E_V16QImode: |
1102 index = 7; | 837 index = 7; |
1103 comp_mode = op_mode; | 838 comp_mode = op_mode; |
1104 break; | 839 break; |
1105 case V8HImode: | 840 case E_V8HImode: |
1106 index = 8; | 841 index = 8; |
1107 comp_mode = op_mode; | 842 comp_mode = op_mode; |
1108 break; | 843 break; |
1109 case V4SImode: | 844 case E_V4SImode: |
1110 index = 9; | 845 index = 9; |
1111 comp_mode = op_mode; | 846 comp_mode = op_mode; |
1112 break; | 847 break; |
1113 case V4SFmode: | 848 case E_V4SFmode: |
1114 index = 10; | 849 index = 10; |
1115 comp_mode = V4SImode; | 850 comp_mode = V4SImode; |
1116 break; | 851 break; |
1117 case V2DFmode: | 852 case E_V2DFmode: |
1118 index = 11; | 853 index = 11; |
1119 comp_mode = V2DImode; | 854 comp_mode = V2DImode; |
1120 break; | 855 break; |
1121 case V2DImode: | 856 case E_V2DImode: |
1122 default: | 857 default: |
1123 abort (); | 858 abort (); |
1124 } | 859 } |
1125 | 860 |
1126 if (GET_MODE (op1) == DFmode | 861 if (GET_MODE (op1) == DFmode |
1127 && (scode != SPU_GT && scode != SPU_EQ)) | 862 && (scode != SPU_GT && scode != SPU_EQ)) |
1128 abort (); | 863 abort (); |
1129 | 864 |
1130 if (is_set == 0 && op1 == const0_rtx | 865 if (is_set == 0 && op1 == const0_rtx |
1131 && (GET_MODE (op0) == SImode | 866 && (GET_MODE (op0) == SImode |
1132 || GET_MODE (op0) == HImode) && scode == SPU_EQ) | 867 || GET_MODE (op0) == HImode |
868 || GET_MODE (op0) == QImode) && scode == SPU_EQ) | |
1133 { | 869 { |
1134 /* Don't need to set a register with the result when we are | 870 /* Don't need to set a register with the result when we are |
1135 comparing against zero and branching. */ | 871 comparing against zero and branching. */ |
1136 reverse_test = !reverse_test; | 872 reverse_test = !reverse_test; |
1137 compare_result = op0; | 873 compare_result = op0; |
1196 bcomp = gen_rtx_EQ (comp_mode, compare_result, const0_rtx); | 932 bcomp = gen_rtx_EQ (comp_mode, compare_result, const0_rtx); |
1197 else | 933 else |
1198 bcomp = gen_rtx_NE (comp_mode, compare_result, const0_rtx); | 934 bcomp = gen_rtx_NE (comp_mode, compare_result, const0_rtx); |
1199 | 935 |
1200 loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]); | 936 loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]); |
1201 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, | 937 emit_jump_insn (gen_rtx_SET (pc_rtx, |
1202 gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, | 938 gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, |
1203 loc_ref, pc_rtx))); | 939 loc_ref, pc_rtx))); |
1204 } | 940 } |
1205 else if (is_set == 2) | 941 else if (is_set == 2) |
1206 { | 942 { |
1207 rtx target = operands[0]; | 943 rtx target = operands[0]; |
1208 int compare_size = GET_MODE_BITSIZE (comp_mode); | 944 int compare_size = GET_MODE_BITSIZE (comp_mode); |
1209 int target_size = GET_MODE_BITSIZE (GET_MODE (target)); | 945 int target_size = GET_MODE_BITSIZE (GET_MODE (target)); |
1210 enum machine_mode mode = mode_for_size (target_size, MODE_INT, 0); | 946 machine_mode mode = int_mode_for_size (target_size, 0).require (); |
1211 rtx select_mask; | 947 rtx select_mask; |
1212 rtx op_t = operands[2]; | 948 rtx op_t = operands[2]; |
1213 rtx op_f = operands[3]; | 949 rtx op_f = operands[3]; |
1214 | 950 |
1215 /* The result of the comparison can be SI, HI or QI mode. Create a | 951 /* The result of the comparison can be SI, HI or QI mode. Create a |
1239 } | 975 } |
1240 else | 976 else |
1241 { | 977 { |
1242 rtx target = operands[0]; | 978 rtx target = operands[0]; |
1243 if (reverse_test) | 979 if (reverse_test) |
1244 emit_insn (gen_rtx_SET (VOIDmode, compare_result, | 980 emit_insn (gen_rtx_SET (compare_result, |
1245 gen_rtx_NOT (comp_mode, compare_result))); | 981 gen_rtx_NOT (comp_mode, compare_result))); |
1246 if (GET_MODE (target) == SImode && GET_MODE (compare_result) == HImode) | 982 if (GET_MODE (target) == SImode && GET_MODE (compare_result) == HImode) |
1247 emit_insn (gen_extendhisi2 (target, compare_result)); | 983 emit_insn (gen_extendhisi2 (target, compare_result)); |
1248 else if (GET_MODE (target) == SImode | 984 else if (GET_MODE (target) == SImode |
1249 && GET_MODE (compare_result) == QImode) | 985 && GET_MODE (compare_result) == QImode) |
1255 | 991 |
1256 HOST_WIDE_INT | 992 HOST_WIDE_INT |
1257 const_double_to_hwint (rtx x) | 993 const_double_to_hwint (rtx x) |
1258 { | 994 { |
1259 HOST_WIDE_INT val; | 995 HOST_WIDE_INT val; |
1260 REAL_VALUE_TYPE rv; | |
1261 if (GET_MODE (x) == SFmode) | 996 if (GET_MODE (x) == SFmode) |
1262 { | 997 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), val); |
1263 REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
1264 REAL_VALUE_TO_TARGET_SINGLE (rv, val); | |
1265 } | |
1266 else if (GET_MODE (x) == DFmode) | 998 else if (GET_MODE (x) == DFmode) |
1267 { | 999 { |
1268 long l[2]; | 1000 long l[2]; |
1269 REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | 1001 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (x), l); |
1270 REAL_VALUE_TO_TARGET_DOUBLE (rv, l); | |
1271 val = l[0]; | 1002 val = l[0]; |
1272 val = (val << 32) | (l[1] & 0xffffffff); | 1003 val = (val << 32) | (l[1] & 0xffffffff); |
1273 } | 1004 } |
1274 else | 1005 else |
1275 abort (); | 1006 abort (); |
1276 return val; | 1007 return val; |
1277 } | 1008 } |
1278 | 1009 |
1279 rtx | 1010 rtx |
1280 hwint_to_const_double (enum machine_mode mode, HOST_WIDE_INT v) | 1011 hwint_to_const_double (machine_mode mode, HOST_WIDE_INT v) |
1281 { | 1012 { |
1282 long tv[2]; | 1013 long tv[2]; |
1283 REAL_VALUE_TYPE rv; | 1014 REAL_VALUE_TYPE rv; |
1284 gcc_assert (mode == SFmode || mode == DFmode); | 1015 gcc_assert (mode == SFmode || mode == DFmode); |
1285 | 1016 |
1289 { | 1020 { |
1290 tv[1] = (v << 32) >> 32; | 1021 tv[1] = (v << 32) >> 32; |
1291 tv[0] = v >> 32; | 1022 tv[0] = v >> 32; |
1292 } | 1023 } |
1293 real_from_target (&rv, tv, mode); | 1024 real_from_target (&rv, tv, mode); |
1294 return CONST_DOUBLE_FROM_REAL_VALUE (rv, mode); | 1025 return const_double_from_real_value (rv, mode); |
1295 } | 1026 } |
1296 | 1027 |
1297 void | 1028 void |
1298 print_operand_address (FILE * file, register rtx addr) | 1029 print_operand_address (FILE * file, register rtx addr) |
1299 { | 1030 { |
1342 } | 1073 } |
1343 | 1074 |
1344 void | 1075 void |
1345 print_operand (FILE * file, rtx x, int code) | 1076 print_operand (FILE * file, rtx x, int code) |
1346 { | 1077 { |
1347 enum machine_mode mode = GET_MODE (x); | 1078 machine_mode mode = GET_MODE (x); |
1348 HOST_WIDE_INT val; | 1079 HOST_WIDE_INT val; |
1349 unsigned char arr[16]; | 1080 unsigned char arr[16]; |
1350 int xcode = GET_CODE (x); | 1081 int xcode = GET_CODE (x); |
1351 int i, info; | 1082 int i, info; |
1352 if (GET_MODE (x) == VOIDmode) | 1083 if (GET_MODE (x) == VOIDmode) |
1616 { | 1347 { |
1617 if (GET_CODE (XEXP (x, 0)) == REG) | 1348 if (GET_CODE (XEXP (x, 0)) == REG) |
1618 /* Used in indirect function calls. */ | 1349 /* Used in indirect function calls. */ |
1619 fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]); | 1350 fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]); |
1620 else | 1351 else |
1621 output_address (XEXP (x, 0)); | 1352 output_address (GET_MODE (x), XEXP (x, 0)); |
1622 } | 1353 } |
1623 return; | 1354 return; |
1624 | 1355 |
1625 case 'p': /* load/store */ | 1356 case 'p': /* load/store */ |
1626 if (xcode == MEM) | 1357 if (xcode == MEM) |
1709 | 1440 |
1710 case 0: | 1441 case 0: |
1711 if (xcode == REG) | 1442 if (xcode == REG) |
1712 fprintf (file, "%s", reg_names[REGNO (x)]); | 1443 fprintf (file, "%s", reg_names[REGNO (x)]); |
1713 else if (xcode == MEM) | 1444 else if (xcode == MEM) |
1714 output_address (XEXP (x, 0)); | 1445 output_address (GET_MODE (x), XEXP (x, 0)); |
1715 else if (xcode == CONST_VECTOR) | 1446 else if (xcode == CONST_VECTOR) |
1716 print_operand (file, CONST_VECTOR_ELT (x, 0), 0); | 1447 print_operand (file, CONST_VECTOR_ELT (x, 0), 0); |
1717 else | 1448 else |
1718 output_addr_const (file, x); | 1449 output_addr_const (file, x); |
1719 return; | 1450 return; |
1733 pic register. This routine is only valid after register allocation | 1464 pic register. This routine is only valid after register allocation |
1734 is completed, so we can pick an unused register. */ | 1465 is completed, so we can pick an unused register. */ |
1735 static rtx | 1466 static rtx |
1736 get_pic_reg (void) | 1467 get_pic_reg (void) |
1737 { | 1468 { |
1738 rtx pic_reg = pic_offset_table_rtx; | |
1739 if (!reload_completed && !reload_in_progress) | 1469 if (!reload_completed && !reload_in_progress) |
1740 abort (); | 1470 abort (); |
1741 if (current_function_is_leaf && !df_regs_ever_live_p (LAST_ARG_REGNUM)) | 1471 |
1742 pic_reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM); | 1472 /* If we've already made the decision, we need to keep with it. Once we've |
1743 return pic_reg; | 1473 decided to use LAST_ARG_REGNUM, future calls to df_regs_ever_live_p may |
1474 return true since the register is now live; this should not cause us to | |
1475 "switch back" to using pic_offset_table_rtx. */ | |
1476 if (!cfun->machine->pic_reg) | |
1477 { | |
1478 if (crtl->is_leaf && !df_regs_ever_live_p (LAST_ARG_REGNUM)) | |
1479 cfun->machine->pic_reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM); | |
1480 else | |
1481 cfun->machine->pic_reg = pic_offset_table_rtx; | |
1482 } | |
1483 | |
1484 return cfun->machine->pic_reg; | |
1744 } | 1485 } |
1745 | 1486 |
1746 /* Split constant addresses to handle cases that are too large. | 1487 /* Split constant addresses to handle cases that are too large. |
1747 Add in the pic register when in PIC mode. | 1488 Add in the pic register when in PIC mode. |
1748 Split immediates that require more than 1 instruction. */ | 1489 Split immediates that require more than 1 instruction. */ |
1749 int | 1490 int |
1750 spu_split_immediate (rtx * ops) | 1491 spu_split_immediate (rtx * ops) |
1751 { | 1492 { |
1752 enum machine_mode mode = GET_MODE (ops[0]); | 1493 machine_mode mode = GET_MODE (ops[0]); |
1753 enum immediate_class c = classify_immediate (ops[1], mode); | 1494 enum immediate_class c = classify_immediate (ops[1], mode); |
1754 | 1495 |
1755 switch (c) | 1496 switch (c) |
1756 { | 1497 { |
1757 case IC_IL2: | 1498 case IC_IL2: |
1758 { | 1499 { |
1759 unsigned char arrhi[16]; | 1500 unsigned char arrhi[16]; |
1760 unsigned char arrlo[16]; | 1501 unsigned char arrlo[16]; |
1761 rtx to, temp, hi, lo; | 1502 rtx to, temp, hi, lo; |
1762 int i; | 1503 int i; |
1763 enum machine_mode imode = mode; | |
1764 /* We need to do reals as ints because the constant used in the | 1504 /* We need to do reals as ints because the constant used in the |
1765 IOR might not be a legitimate real constant. */ | 1505 IOR might not be a legitimate real constant. */ |
1766 imode = int_mode_for_mode (mode); | 1506 scalar_int_mode imode = int_mode_for_mode (mode).require (); |
1767 constant_to_array (mode, ops[1], arrhi); | 1507 constant_to_array (mode, ops[1], arrhi); |
1768 if (imode != mode) | 1508 if (imode != mode) |
1769 to = simplify_gen_subreg (imode, ops[0], mode, 0); | 1509 to = simplify_gen_subreg (imode, ops[0], mode, 0); |
1770 else | 1510 else |
1771 to = ops[0]; | 1511 to = ops[0]; |
1778 arrhi[i + 2] = arrhi[i + 3] = 0; | 1518 arrhi[i + 2] = arrhi[i + 3] = 0; |
1779 } | 1519 } |
1780 hi = array_to_constant (imode, arrhi); | 1520 hi = array_to_constant (imode, arrhi); |
1781 lo = array_to_constant (imode, arrlo); | 1521 lo = array_to_constant (imode, arrlo); |
1782 emit_move_insn (temp, hi); | 1522 emit_move_insn (temp, hi); |
1783 emit_insn (gen_rtx_SET | 1523 emit_insn (gen_rtx_SET (to, gen_rtx_IOR (imode, temp, lo))); |
1784 (VOIDmode, to, gen_rtx_IOR (imode, temp, lo))); | |
1785 return 1; | 1524 return 1; |
1786 } | 1525 } |
1787 case IC_FSMBI2: | 1526 case IC_FSMBI2: |
1788 { | 1527 { |
1789 unsigned char arr_fsmbi[16]; | 1528 unsigned char arr_fsmbi[16]; |
1790 unsigned char arr_andbi[16]; | 1529 unsigned char arr_andbi[16]; |
1791 rtx to, reg_fsmbi, reg_and; | 1530 rtx to, reg_fsmbi, reg_and; |
1792 int i; | 1531 int i; |
1793 enum machine_mode imode = mode; | |
1794 /* We need to do reals as ints because the constant used in the | 1532 /* We need to do reals as ints because the constant used in the |
1795 * AND might not be a legitimate real constant. */ | 1533 * AND might not be a legitimate real constant. */ |
1796 imode = int_mode_for_mode (mode); | 1534 scalar_int_mode imode = int_mode_for_mode (mode).require (); |
1797 constant_to_array (mode, ops[1], arr_fsmbi); | 1535 constant_to_array (mode, ops[1], arr_fsmbi); |
1798 if (imode != mode) | 1536 if (imode != mode) |
1799 to = simplify_gen_subreg(imode, ops[0], GET_MODE (ops[0]), 0); | 1537 to = simplify_gen_subreg(imode, ops[0], GET_MODE (ops[0]), 0); |
1800 else | 1538 else |
1801 to = ops[0]; | 1539 to = ops[0]; |
1808 for (i = 1; i < 16; i++) | 1546 for (i = 1; i < 16; i++) |
1809 arr_andbi[i] = arr_andbi[0]; | 1547 arr_andbi[i] = arr_andbi[0]; |
1810 reg_fsmbi = array_to_constant (imode, arr_fsmbi); | 1548 reg_fsmbi = array_to_constant (imode, arr_fsmbi); |
1811 reg_and = array_to_constant (imode, arr_andbi); | 1549 reg_and = array_to_constant (imode, arr_andbi); |
1812 emit_move_insn (to, reg_fsmbi); | 1550 emit_move_insn (to, reg_fsmbi); |
1813 emit_insn (gen_rtx_SET | 1551 emit_insn (gen_rtx_SET (to, gen_rtx_AND (imode, to, reg_and))); |
1814 (VOIDmode, to, gen_rtx_AND (imode, to, reg_and))); | |
1815 return 1; | 1552 return 1; |
1816 } | 1553 } |
1817 case IC_POOL: | 1554 case IC_POOL: |
1818 if (reload_in_progress || reload_completed) | 1555 if (reload_in_progress || reload_completed) |
1819 { | 1556 { |
1841 emit_insn (gen_pic (ops[0], ops[1])); | 1578 emit_insn (gen_pic (ops[0], ops[1])); |
1842 if (flag_pic) | 1579 if (flag_pic) |
1843 { | 1580 { |
1844 rtx pic_reg = get_pic_reg (); | 1581 rtx pic_reg = get_pic_reg (); |
1845 emit_insn (gen_addsi3 (ops[0], ops[0], pic_reg)); | 1582 emit_insn (gen_addsi3 (ops[0], ops[0], pic_reg)); |
1846 crtl->uses_pic_offset_table = 1; | |
1847 } | 1583 } |
1848 return flag_pic || c == IC_IL2s; | 1584 return flag_pic || c == IC_IL2s; |
1849 } | 1585 } |
1850 break; | 1586 break; |
1851 case IC_IL1: | 1587 case IC_IL1: |
1867 { | 1603 { |
1868 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) | 1604 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) |
1869 return 1; | 1605 return 1; |
1870 if (flag_pic | 1606 if (flag_pic |
1871 && regno == PIC_OFFSET_TABLE_REGNUM | 1607 && regno == PIC_OFFSET_TABLE_REGNUM |
1872 && (!saving || crtl->uses_pic_offset_table) | 1608 && (!saving || cfun->machine->pic_reg == pic_offset_table_rtx)) |
1873 && (!saving | |
1874 || !current_function_is_leaf || df_regs_ever_live_p (LAST_ARG_REGNUM))) | |
1875 return 1; | 1609 return 1; |
1876 return 0; | 1610 return 0; |
1877 } | 1611 } |
1878 | 1612 |
1879 /* This function is only correct starting with local register | 1613 /* This function is only correct starting with local register |
1888 if (need_to_save_reg (regno, 0)) | 1622 if (need_to_save_reg (regno, 0)) |
1889 reg_save_size += 0x10; | 1623 reg_save_size += 0x10; |
1890 return reg_save_size; | 1624 return reg_save_size; |
1891 } | 1625 } |
1892 | 1626 |
1893 static rtx | 1627 static rtx_insn * |
1894 frame_emit_store (int regno, rtx addr, HOST_WIDE_INT offset) | 1628 frame_emit_store (int regno, rtx addr, HOST_WIDE_INT offset) |
1895 { | 1629 { |
1896 rtx reg = gen_rtx_REG (V4SImode, regno); | 1630 rtx reg = gen_rtx_REG (V4SImode, regno); |
1897 rtx mem = | 1631 rtx mem = |
1898 gen_frame_mem (V4SImode, gen_rtx_PLUS (Pmode, addr, GEN_INT (offset))); | 1632 gen_frame_mem (V4SImode, gen_rtx_PLUS (Pmode, addr, GEN_INT (offset))); |
1899 return emit_insn (gen_movv4si (mem, reg)); | 1633 return emit_insn (gen_movv4si (mem, reg)); |
1900 } | 1634 } |
1901 | 1635 |
1902 static rtx | 1636 static rtx_insn * |
1903 frame_emit_load (int regno, rtx addr, HOST_WIDE_INT offset) | 1637 frame_emit_load (int regno, rtx addr, HOST_WIDE_INT offset) |
1904 { | 1638 { |
1905 rtx reg = gen_rtx_REG (V4SImode, regno); | 1639 rtx reg = gen_rtx_REG (V4SImode, regno); |
1906 rtx mem = | 1640 rtx mem = |
1907 gen_frame_mem (V4SImode, gen_rtx_PLUS (Pmode, addr, GEN_INT (offset))); | 1641 gen_frame_mem (V4SImode, gen_rtx_PLUS (Pmode, addr, GEN_INT (offset))); |
1908 return emit_insn (gen_movv4si (reg, mem)); | 1642 return emit_insn (gen_movv4si (reg, mem)); |
1909 } | 1643 } |
1910 | 1644 |
1911 /* This happens after reload, so we need to expand it. */ | 1645 /* This happens after reload, so we need to expand it. */ |
1912 static rtx | 1646 static rtx_insn * |
1913 frame_emit_add_imm (rtx dst, rtx src, HOST_WIDE_INT imm, rtx scratch) | 1647 frame_emit_add_imm (rtx dst, rtx src, HOST_WIDE_INT imm, rtx scratch) |
1914 { | 1648 { |
1915 rtx insn; | 1649 rtx_insn *insn; |
1916 if (satisfies_constraint_K (GEN_INT (imm))) | 1650 if (satisfies_constraint_K (GEN_INT (imm))) |
1917 { | 1651 { |
1918 insn = emit_insn (gen_addsi3 (dst, src, GEN_INT (imm))); | 1652 insn = emit_insn (gen_addsi3 (dst, src, GEN_INT (imm))); |
1919 } | 1653 } |
1920 else | 1654 else |
1937 if (cfun->static_chain_decl == 0 | 1671 if (cfun->static_chain_decl == 0 |
1938 && (spu_saved_regs_size () | 1672 && (spu_saved_regs_size () |
1939 + get_frame_size () | 1673 + get_frame_size () |
1940 + crtl->outgoing_args_size | 1674 + crtl->outgoing_args_size |
1941 + crtl->args.pretend_args_size == 0) | 1675 + crtl->args.pretend_args_size == 0) |
1942 && current_function_is_leaf) | 1676 && crtl->is_leaf) |
1943 return 1; | 1677 return 1; |
1944 } | 1678 } |
1945 return 0; | 1679 return 0; |
1946 } | 1680 } |
1947 | 1681 |
1981 HOST_WIDE_INT size = get_frame_size (), offset, regno; | 1715 HOST_WIDE_INT size = get_frame_size (), offset, regno; |
1982 HOST_WIDE_INT total_size; | 1716 HOST_WIDE_INT total_size; |
1983 HOST_WIDE_INT saved_regs_size; | 1717 HOST_WIDE_INT saved_regs_size; |
1984 rtx sp_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); | 1718 rtx sp_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); |
1985 rtx scratch_reg_0, scratch_reg_1; | 1719 rtx scratch_reg_0, scratch_reg_1; |
1986 rtx insn, real; | 1720 rtx_insn *insn; |
1987 | 1721 rtx real; |
1988 if (flag_pic && optimize == 0) | 1722 |
1989 crtl->uses_pic_offset_table = 1; | 1723 if (flag_pic && optimize == 0 && !cfun->machine->pic_reg) |
1724 cfun->machine->pic_reg = pic_offset_table_rtx; | |
1990 | 1725 |
1991 if (spu_naked_function_p (current_function_decl)) | 1726 if (spu_naked_function_p (current_function_decl)) |
1992 return; | 1727 return; |
1993 | 1728 |
1994 scratch_reg_0 = gen_rtx_REG (SImode, LAST_ARG_REGNUM + 1); | 1729 scratch_reg_0 = gen_rtx_REG (SImode, LAST_ARG_REGNUM + 1); |
1997 saved_regs_size = spu_saved_regs_size (); | 1732 saved_regs_size = spu_saved_regs_size (); |
1998 total_size = size + saved_regs_size | 1733 total_size = size + saved_regs_size |
1999 + crtl->outgoing_args_size | 1734 + crtl->outgoing_args_size |
2000 + crtl->args.pretend_args_size; | 1735 + crtl->args.pretend_args_size; |
2001 | 1736 |
2002 if (!current_function_is_leaf | 1737 if (!crtl->is_leaf |
2003 || cfun->calls_alloca || total_size > 0) | 1738 || cfun->calls_alloca || total_size > 0) |
2004 total_size += STACK_POINTER_OFFSET; | 1739 total_size += STACK_POINTER_OFFSET; |
2005 | 1740 |
2006 /* Save this first because code after this might use the link | 1741 /* Save this first because code after this might use the link |
2007 register as a scratch register. */ | 1742 register as a scratch register. */ |
2008 if (!current_function_is_leaf) | 1743 if (!crtl->is_leaf) |
2009 { | 1744 { |
2010 insn = frame_emit_store (LINK_REGISTER_REGNUM, sp_reg, 16); | 1745 insn = frame_emit_store (LINK_REGISTER_REGNUM, sp_reg, 16); |
2011 RTX_FRAME_RELATED_P (insn) = 1; | 1746 RTX_FRAME_RELATED_P (insn) = 1; |
2012 } | 1747 } |
2013 | 1748 |
2021 insn = frame_emit_store (regno, sp_reg, offset); | 1756 insn = frame_emit_store (regno, sp_reg, offset); |
2022 RTX_FRAME_RELATED_P (insn) = 1; | 1757 RTX_FRAME_RELATED_P (insn) = 1; |
2023 } | 1758 } |
2024 } | 1759 } |
2025 | 1760 |
2026 if (flag_pic && crtl->uses_pic_offset_table) | 1761 if (flag_pic && cfun->machine->pic_reg) |
2027 { | 1762 { |
2028 rtx pic_reg = get_pic_reg (); | 1763 rtx pic_reg = cfun->machine->pic_reg; |
2029 insn = emit_insn (gen_load_pic_offset (pic_reg, scratch_reg_0)); | 1764 insn = emit_insn (gen_load_pic_offset (pic_reg, scratch_reg_0)); |
2030 insn = emit_insn (gen_subsi3 (pic_reg, pic_reg, scratch_reg_0)); | 1765 insn = emit_insn (gen_subsi3 (pic_reg, pic_reg, scratch_reg_0)); |
2031 } | 1766 } |
2032 | 1767 |
2033 if (total_size > 0) | 1768 if (total_size > 0) |
2034 { | 1769 { |
2035 if (flag_stack_check) | 1770 if (flag_stack_check || flag_stack_clash_protection) |
2036 { | 1771 { |
2037 /* We compare against total_size-1 because | 1772 /* We compare against total_size-1 because |
2038 ($sp >= total_size) <=> ($sp > total_size-1) */ | 1773 ($sp >= total_size) <=> ($sp > total_size-1) */ |
2039 rtx scratch_v4si = gen_rtx_REG (V4SImode, REGNO (scratch_reg_0)); | 1774 rtx scratch_v4si = gen_rtx_REG (V4SImode, REGNO (scratch_reg_0)); |
2040 rtx sp_v4si = gen_rtx_REG (V4SImode, STACK_POINTER_REGNUM); | 1775 rtx sp_v4si = gen_rtx_REG (V4SImode, STACK_POINTER_REGNUM); |
2043 { | 1778 { |
2044 emit_move_insn (scratch_v4si, size_v4si); | 1779 emit_move_insn (scratch_v4si, size_v4si); |
2045 size_v4si = scratch_v4si; | 1780 size_v4si = scratch_v4si; |
2046 } | 1781 } |
2047 emit_insn (gen_cgt_v4si (scratch_v4si, sp_v4si, size_v4si)); | 1782 emit_insn (gen_cgt_v4si (scratch_v4si, sp_v4si, size_v4si)); |
2048 emit_insn (gen_vec_extractv4si | 1783 emit_insn (gen_vec_extractv4sisi |
2049 (scratch_reg_0, scratch_v4si, GEN_INT (1))); | 1784 (scratch_reg_0, scratch_v4si, GEN_INT (1))); |
2050 emit_insn (gen_spu_heq (scratch_reg_0, GEN_INT (0))); | 1785 emit_insn (gen_spu_heq (scratch_reg_0, GEN_INT (0))); |
2051 } | 1786 } |
2052 | 1787 |
2053 /* Adjust the stack pointer, and make sure scratch_reg_0 contains | 1788 /* Adjust the stack pointer, and make sure scratch_reg_0 contains |
2088 add_reg_note (insn, REG_FRAME_RELATED_EXPR, real); | 1823 add_reg_note (insn, REG_FRAME_RELATED_EXPR, real); |
2089 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY; | 1824 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY; |
2090 } | 1825 } |
2091 } | 1826 } |
2092 | 1827 |
2093 if (flag_stack_usage) | 1828 if (flag_stack_usage_info) |
2094 current_function_static_stack_size = total_size; | 1829 current_function_static_stack_size = total_size; |
2095 } | 1830 } |
2096 | 1831 |
2097 void | 1832 void |
2098 spu_expand_epilogue (bool sibcall_p) | 1833 spu_expand_epilogue (bool sibcall_p) |
2099 { | 1834 { |
2100 int size = get_frame_size (), offset, regno; | 1835 int size = get_frame_size (), offset, regno; |
2101 HOST_WIDE_INT saved_regs_size, total_size; | 1836 HOST_WIDE_INT saved_regs_size, total_size; |
2102 rtx sp_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); | 1837 rtx sp_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); |
2103 rtx jump, scratch_reg_0; | 1838 rtx scratch_reg_0; |
2104 | 1839 |
2105 if (spu_naked_function_p (current_function_decl)) | 1840 if (spu_naked_function_p (current_function_decl)) |
2106 return; | 1841 return; |
2107 | 1842 |
2108 scratch_reg_0 = gen_rtx_REG (SImode, LAST_ARG_REGNUM + 1); | 1843 scratch_reg_0 = gen_rtx_REG (SImode, LAST_ARG_REGNUM + 1); |
2110 saved_regs_size = spu_saved_regs_size (); | 1845 saved_regs_size = spu_saved_regs_size (); |
2111 total_size = size + saved_regs_size | 1846 total_size = size + saved_regs_size |
2112 + crtl->outgoing_args_size | 1847 + crtl->outgoing_args_size |
2113 + crtl->args.pretend_args_size; | 1848 + crtl->args.pretend_args_size; |
2114 | 1849 |
2115 if (!current_function_is_leaf | 1850 if (!crtl->is_leaf |
2116 || cfun->calls_alloca || total_size > 0) | 1851 || cfun->calls_alloca || total_size > 0) |
2117 total_size += STACK_POINTER_OFFSET; | 1852 total_size += STACK_POINTER_OFFSET; |
2118 | 1853 |
2119 if (total_size > 0) | 1854 if (total_size > 0) |
2120 { | 1855 { |
2134 frame_emit_load (regno, sp_reg, offset); | 1869 frame_emit_load (regno, sp_reg, offset); |
2135 } | 1870 } |
2136 } | 1871 } |
2137 } | 1872 } |
2138 | 1873 |
2139 if (!current_function_is_leaf) | 1874 if (!crtl->is_leaf) |
2140 frame_emit_load (LINK_REGISTER_REGNUM, sp_reg, 16); | 1875 frame_emit_load (LINK_REGISTER_REGNUM, sp_reg, 16); |
2141 | 1876 |
2142 if (!sibcall_p) | 1877 if (!sibcall_p) |
2143 { | 1878 { |
2144 emit_use (gen_rtx_REG (SImode, LINK_REGISTER_REGNUM)); | 1879 emit_use (gen_rtx_REG (SImode, LINK_REGISTER_REGNUM)); |
2145 jump = emit_jump_insn (gen__return ()); | 1880 emit_jump_insn (gen__return ()); |
2146 emit_barrier_after (jump); | 1881 } |
2147 } | |
2148 | |
2149 } | 1882 } |
2150 | 1883 |
2151 rtx | 1884 rtx |
2152 spu_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) | 1885 spu_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) |
2153 { | 1886 { |
2165 | 1898 |
2166 /* Given VAL, generate a constant appropriate for MODE. | 1899 /* Given VAL, generate a constant appropriate for MODE. |
2167 If MODE is a vector mode, every element will be VAL. | 1900 If MODE is a vector mode, every element will be VAL. |
2168 For TImode, VAL will be zero extended to 128 bits. */ | 1901 For TImode, VAL will be zero extended to 128 bits. */ |
2169 rtx | 1902 rtx |
2170 spu_const (enum machine_mode mode, HOST_WIDE_INT val) | 1903 spu_const (machine_mode mode, HOST_WIDE_INT val) |
2171 { | 1904 { |
2172 rtx inner; | 1905 rtx inner; |
2173 rtvec v; | 1906 rtvec v; |
2174 int units, i; | 1907 int units, i; |
2175 | 1908 |
2200 return gen_rtx_CONST_VECTOR (mode, v); | 1933 return gen_rtx_CONST_VECTOR (mode, v); |
2201 } | 1934 } |
2202 | 1935 |
2203 /* Create a MODE vector constant from 4 ints. */ | 1936 /* Create a MODE vector constant from 4 ints. */ |
2204 rtx | 1937 rtx |
2205 spu_const_from_ints(enum machine_mode mode, int a, int b, int c, int d) | 1938 spu_const_from_ints(machine_mode mode, int a, int b, int c, int d) |
2206 { | 1939 { |
2207 unsigned char arr[16]; | 1940 unsigned char arr[16]; |
2208 arr[0] = (a >> 24) & 0xff; | 1941 arr[0] = (a >> 24) & 0xff; |
2209 arr[1] = (a >> 16) & 0xff; | 1942 arr[1] = (a >> 16) & 0xff; |
2210 arr[2] = (a >> 8) & 0xff; | 1943 arr[2] = (a >> 8) & 0xff; |
2227 /* branch hint stuff */ | 1960 /* branch hint stuff */ |
2228 | 1961 |
2229 /* An array of these is used to propagate hints to predecessor blocks. */ | 1962 /* An array of these is used to propagate hints to predecessor blocks. */ |
2230 struct spu_bb_info | 1963 struct spu_bb_info |
2231 { | 1964 { |
2232 rtx prop_jump; /* propagated from another block */ | 1965 rtx_insn *prop_jump; /* propagated from another block */ |
2233 int bb_index; /* the original block. */ | 1966 int bb_index; /* the original block. */ |
2234 }; | 1967 }; |
2235 static struct spu_bb_info *spu_bb_info; | 1968 static struct spu_bb_info *spu_bb_info; |
2236 | 1969 |
2237 #define STOP_HINT_P(INSN) \ | 1970 #define STOP_HINT_P(INSN) \ |
2238 (GET_CODE(INSN) == CALL_INSN \ | 1971 (CALL_P(INSN) \ |
2239 || INSN_CODE(INSN) == CODE_FOR_divmodsi4 \ | 1972 || INSN_CODE(INSN) == CODE_FOR_divmodsi4 \ |
2240 || INSN_CODE(INSN) == CODE_FOR_udivmodsi4) | 1973 || INSN_CODE(INSN) == CODE_FOR_udivmodsi4) |
2241 | 1974 |
2242 /* 1 when RTX is a hinted branch or its target. We keep track of | 1975 /* 1 when RTX is a hinted branch or its target. We keep track of |
2243 what has been hinted so the safe-hint code can test it easily. */ | 1976 what has been hinted so the safe-hint code can test it easily. */ |
2249 (RTL_FLAG_CHECK2("SCHED_ON_EVEN_P", (RTX), JUMP_INSN, CALL_INSN)->in_struct) | 1982 (RTL_FLAG_CHECK2("SCHED_ON_EVEN_P", (RTX), JUMP_INSN, CALL_INSN)->in_struct) |
2250 | 1983 |
2251 /* Emit a nop for INSN such that the two will dual issue. This assumes | 1984 /* Emit a nop for INSN such that the two will dual issue. This assumes |
2252 INSN is 8-byte aligned. When INSN is inline asm we emit an lnop. | 1985 INSN is 8-byte aligned. When INSN is inline asm we emit an lnop. |
2253 We check for TImode to handle a MULTI1 insn which has dual issued its | 1986 We check for TImode to handle a MULTI1 insn which has dual issued its |
2254 first instruction. get_pipe returns -1 for MULTI0, inline asm, or | 1987 first instruction. get_pipe returns -1 for MULTI0 or inline asm. */ |
2255 ADDR_VEC insns. */ | |
2256 static void | 1988 static void |
2257 emit_nop_for_insn (rtx insn) | 1989 emit_nop_for_insn (rtx_insn *insn) |
2258 { | 1990 { |
2259 int p; | 1991 int p; |
2260 rtx new_insn; | 1992 rtx_insn *new_insn; |
1993 | |
1994 /* We need to handle JUMP_TABLE_DATA separately. */ | |
1995 if (JUMP_TABLE_DATA_P (insn)) | |
1996 { | |
1997 new_insn = emit_insn_after (gen_lnop(), insn); | |
1998 recog_memoized (new_insn); | |
1999 INSN_LOCATION (new_insn) = UNKNOWN_LOCATION; | |
2000 return; | |
2001 } | |
2002 | |
2261 p = get_pipe (insn); | 2003 p = get_pipe (insn); |
2262 if ((CALL_P (insn) || JUMP_P (insn)) && SCHED_ON_EVEN_P (insn)) | 2004 if ((CALL_P (insn) || JUMP_P (insn)) && SCHED_ON_EVEN_P (insn)) |
2263 new_insn = emit_insn_after (gen_lnop (), insn); | 2005 new_insn = emit_insn_after (gen_lnop (), insn); |
2264 else if (p == 1 && GET_MODE (insn) == TImode) | 2006 else if (p == 1 && GET_MODE (insn) == TImode) |
2265 { | 2007 { |
2268 PUT_MODE (insn, VOIDmode); | 2010 PUT_MODE (insn, VOIDmode); |
2269 } | 2011 } |
2270 else | 2012 else |
2271 new_insn = emit_insn_after (gen_lnop (), insn); | 2013 new_insn = emit_insn_after (gen_lnop (), insn); |
2272 recog_memoized (new_insn); | 2014 recog_memoized (new_insn); |
2273 INSN_LOCATOR (new_insn) = INSN_LOCATOR (insn); | 2015 INSN_LOCATION (new_insn) = INSN_LOCATION (insn); |
2274 } | 2016 } |
2275 | 2017 |
2276 /* Insert nops in basic blocks to meet dual issue alignment | 2018 /* Insert nops in basic blocks to meet dual issue alignment |
2277 requirements. Also make sure hbrp and hint instructions are at least | 2019 requirements. Also make sure hbrp and hint instructions are at least |
2278 one cycle apart, possibly inserting a nop. */ | 2020 one cycle apart, possibly inserting a nop. */ |
2279 static void | 2021 static void |
2280 pad_bb(void) | 2022 pad_bb(void) |
2281 { | 2023 { |
2282 rtx insn, next_insn, prev_insn, hbr_insn = 0; | 2024 rtx_insn *insn, *next_insn, *prev_insn, *hbr_insn = 0; |
2283 int length; | 2025 int length; |
2284 int addr; | 2026 int addr; |
2285 | 2027 |
2286 /* This sets up INSN_ADDRESSES. */ | 2028 /* This sets up INSN_ADDRESSES. */ |
2287 shorten_branches (get_insns ()); | 2029 shorten_branches (get_insns ()); |
2307 || (a1 - a0 == 4)) | 2049 || (a1 - a0 == 4)) |
2308 { | 2050 { |
2309 prev_insn = emit_insn_before (gen_lnop (), insn); | 2051 prev_insn = emit_insn_before (gen_lnop (), insn); |
2310 PUT_MODE (prev_insn, GET_MODE (insn)); | 2052 PUT_MODE (prev_insn, GET_MODE (insn)); |
2311 PUT_MODE (insn, TImode); | 2053 PUT_MODE (insn, TImode); |
2312 INSN_LOCATOR (prev_insn) = INSN_LOCATOR (insn); | 2054 INSN_LOCATION (prev_insn) = INSN_LOCATION (insn); |
2313 length += 4; | 2055 length += 4; |
2314 } | 2056 } |
2315 } | 2057 } |
2316 hbr_insn = insn; | 2058 hbr_insn = insn; |
2317 } | 2059 } |
2318 if (INSN_CODE (insn) == CODE_FOR_blockage) | 2060 if (INSN_CODE (insn) == CODE_FOR_blockage && next_insn) |
2319 { | 2061 { |
2320 if (GET_MODE (insn) == TImode) | 2062 if (GET_MODE (insn) == TImode) |
2321 PUT_MODE (next_insn, TImode); | 2063 PUT_MODE (next_insn, TImode); |
2322 insn = next_insn; | 2064 insn = next_insn; |
2323 next_insn = next_active_insn (insn); | 2065 next_insn = next_active_insn (insn); |
2347 | 2089 |
2348 | 2090 |
2349 /* Routines for branch hints. */ | 2091 /* Routines for branch hints. */ |
2350 | 2092 |
2351 static void | 2093 static void |
2352 spu_emit_branch_hint (rtx before, rtx branch, rtx target, | 2094 spu_emit_branch_hint (rtx_insn *before, rtx_insn *branch, rtx target, |
2353 int distance, sbitmap blocks) | 2095 int distance, sbitmap blocks) |
2354 { | 2096 { |
2355 rtx branch_label = 0; | 2097 rtx_insn *hint; |
2356 rtx hint; | 2098 rtx_insn *insn; |
2357 rtx insn; | 2099 rtx_jump_table_data *table; |
2358 rtx table; | |
2359 | 2100 |
2360 if (before == 0 || branch == 0 || target == 0) | 2101 if (before == 0 || branch == 0 || target == 0) |
2361 return; | 2102 return; |
2362 | 2103 |
2363 /* While scheduling we require hints to be no further than 600, so | 2104 /* While scheduling we require hints to be no further than 600, so |
2367 | 2108 |
2368 /* If we have a Basic block note, emit it after the basic block note. */ | 2109 /* If we have a Basic block note, emit it after the basic block note. */ |
2369 if (NOTE_INSN_BASIC_BLOCK_P (before)) | 2110 if (NOTE_INSN_BASIC_BLOCK_P (before)) |
2370 before = NEXT_INSN (before); | 2111 before = NEXT_INSN (before); |
2371 | 2112 |
2372 branch_label = gen_label_rtx (); | 2113 rtx_code_label *branch_label = gen_label_rtx (); |
2373 LABEL_NUSES (branch_label)++; | 2114 LABEL_NUSES (branch_label)++; |
2374 LABEL_PRESERVE_P (branch_label) = 1; | 2115 LABEL_PRESERVE_P (branch_label) = 1; |
2375 insn = emit_label_before (branch_label, branch); | 2116 insn = emit_label_before (branch_label, branch); |
2376 branch_label = gen_rtx_LABEL_REF (VOIDmode, branch_label); | 2117 rtx branch_label_ref = gen_rtx_LABEL_REF (VOIDmode, branch_label); |
2377 SET_BIT (blocks, BLOCK_FOR_INSN (branch)->index); | 2118 bitmap_set_bit (blocks, BLOCK_FOR_INSN (branch)->index); |
2378 | 2119 |
2379 hint = emit_insn_before (gen_hbr (branch_label, target), before); | 2120 hint = emit_insn_before (gen_hbr (branch_label_ref, target), before); |
2380 recog_memoized (hint); | 2121 recog_memoized (hint); |
2381 INSN_LOCATOR (hint) = INSN_LOCATOR (branch); | 2122 INSN_LOCATION (hint) = INSN_LOCATION (branch); |
2382 HINTED_P (branch) = 1; | 2123 HINTED_P (branch) = 1; |
2383 | 2124 |
2384 if (GET_CODE (target) == LABEL_REF) | 2125 if (GET_CODE (target) == LABEL_REF) |
2385 HINTED_P (XEXP (target, 0)) = 1; | 2126 HINTED_P (XEXP (target, 0)) = 1; |
2386 else if (tablejump_p (branch, 0, &table)) | 2127 else if (tablejump_p (branch, 0, &table)) |
2399 { | 2140 { |
2400 /* Make sure the hint isn't scheduled any earlier than this point, | 2141 /* Make sure the hint isn't scheduled any earlier than this point, |
2401 which could make it too far for the branch offest to fit */ | 2142 which could make it too far for the branch offest to fit */ |
2402 insn = emit_insn_before (gen_blockage (), hint); | 2143 insn = emit_insn_before (gen_blockage (), hint); |
2403 recog_memoized (insn); | 2144 recog_memoized (insn); |
2404 INSN_LOCATOR (insn) = INSN_LOCATOR (hint); | 2145 INSN_LOCATION (insn) = INSN_LOCATION (hint); |
2405 } | 2146 } |
2406 else if (distance <= 8 * 4) | 2147 else if (distance <= 8 * 4) |
2407 { | 2148 { |
2408 /* To guarantee at least 8 insns between the hint and branch we | 2149 /* To guarantee at least 8 insns between the hint and branch we |
2409 insert nops. */ | 2150 insert nops. */ |
2411 for (d = distance; d < 8 * 4; d += 4) | 2152 for (d = distance; d < 8 * 4; d += 4) |
2412 { | 2153 { |
2413 insn = | 2154 insn = |
2414 emit_insn_after (gen_nopn_nv (gen_rtx_REG (SImode, 127)), hint); | 2155 emit_insn_after (gen_nopn_nv (gen_rtx_REG (SImode, 127)), hint); |
2415 recog_memoized (insn); | 2156 recog_memoized (insn); |
2416 INSN_LOCATOR (insn) = INSN_LOCATOR (hint); | 2157 INSN_LOCATION (insn) = INSN_LOCATION (hint); |
2417 } | 2158 } |
2418 | 2159 |
2419 /* Make sure any nops inserted aren't scheduled before the hint. */ | 2160 /* Make sure any nops inserted aren't scheduled before the hint. */ |
2420 insn = emit_insn_after (gen_blockage (), hint); | 2161 insn = emit_insn_after (gen_blockage (), hint); |
2421 recog_memoized (insn); | 2162 recog_memoized (insn); |
2422 INSN_LOCATOR (insn) = INSN_LOCATOR (hint); | 2163 INSN_LOCATION (insn) = INSN_LOCATION (hint); |
2423 | 2164 |
2424 /* Make sure any nops inserted aren't scheduled after the call. */ | 2165 /* Make sure any nops inserted aren't scheduled after the call. */ |
2425 if (CALL_P (branch) && distance < 8 * 4) | 2166 if (CALL_P (branch) && distance < 8 * 4) |
2426 { | 2167 { |
2427 insn = emit_insn_before (gen_blockage (), branch); | 2168 insn = emit_insn_before (gen_blockage (), branch); |
2428 recog_memoized (insn); | 2169 recog_memoized (insn); |
2429 INSN_LOCATOR (insn) = INSN_LOCATOR (branch); | 2170 INSN_LOCATION (insn) = INSN_LOCATION (branch); |
2430 } | 2171 } |
2431 } | 2172 } |
2432 } | 2173 } |
2433 | 2174 |
2434 /* Returns 0 if we don't want a hint for this branch. Otherwise return | 2175 /* Returns 0 if we don't want a hint for this branch. Otherwise return |
2435 the rtx for the branch target. */ | 2176 the rtx for the branch target. */ |
2436 static rtx | 2177 static rtx |
2437 get_branch_target (rtx branch) | 2178 get_branch_target (rtx_insn *branch) |
2438 { | 2179 { |
2439 if (GET_CODE (branch) == JUMP_INSN) | 2180 if (JUMP_P (branch)) |
2440 { | 2181 { |
2441 rtx set, src; | 2182 rtx set, src; |
2442 | 2183 |
2443 /* Return statements */ | 2184 /* Return statements */ |
2444 if (GET_CODE (PATTERN (branch)) == RETURN) | 2185 if (GET_CODE (PATTERN (branch)) == RETURN) |
2445 return gen_rtx_REG (SImode, LINK_REGISTER_REGNUM); | 2186 return gen_rtx_REG (SImode, LINK_REGISTER_REGNUM); |
2446 | |
2447 /* jump table */ | |
2448 if (GET_CODE (PATTERN (branch)) == ADDR_VEC | |
2449 || GET_CODE (PATTERN (branch)) == ADDR_DIFF_VEC) | |
2450 return 0; | |
2451 | 2187 |
2452 /* ASM GOTOs. */ | 2188 /* ASM GOTOs. */ |
2453 if (extract_asm_operands (PATTERN (branch)) != NULL) | 2189 if (extract_asm_operands (PATTERN (branch)) != NULL) |
2454 return NULL; | 2190 return NULL; |
2455 | 2191 |
2464 rtx note = find_reg_note (branch, REG_BR_PROB, 0); | 2200 rtx note = find_reg_note (branch, REG_BR_PROB, 0); |
2465 if (note) | 2201 if (note) |
2466 { | 2202 { |
2467 /* If the more probable case is not a fall through, then | 2203 /* If the more probable case is not a fall through, then |
2468 try a branch hint. */ | 2204 try a branch hint. */ |
2469 HOST_WIDE_INT prob = INTVAL (XEXP (note, 0)); | 2205 int prob = profile_probability::from_reg_br_prob_note |
2206 (XINT (note, 0)).to_reg_br_prob_base (); | |
2470 if (prob > (REG_BR_PROB_BASE * 6 / 10) | 2207 if (prob > (REG_BR_PROB_BASE * 6 / 10) |
2471 && GET_CODE (XEXP (src, 1)) != PC) | 2208 && GET_CODE (XEXP (src, 1)) != PC) |
2472 lab = XEXP (src, 1); | 2209 lab = XEXP (src, 1); |
2473 else if (prob < (REG_BR_PROB_BASE * 4 / 10) | 2210 else if (prob < (REG_BR_PROB_BASE * 4 / 10) |
2474 && GET_CODE (XEXP (src, 2)) != PC) | 2211 && GET_CODE (XEXP (src, 2)) != PC) |
2483 return 0; | 2220 return 0; |
2484 } | 2221 } |
2485 | 2222 |
2486 return src; | 2223 return src; |
2487 } | 2224 } |
2488 else if (GET_CODE (branch) == CALL_INSN) | 2225 else if (CALL_P (branch)) |
2489 { | 2226 { |
2490 rtx call; | 2227 rtx call; |
2491 /* All of our call patterns are in a PARALLEL and the CALL is | 2228 /* All of our call patterns are in a PARALLEL and the CALL is |
2492 the first pattern in the PARALLEL. */ | 2229 the first pattern in the PARALLEL. */ |
2493 if (GET_CODE (PATTERN (branch)) != PARALLEL) | 2230 if (GET_CODE (PATTERN (branch)) != PARALLEL) |
2505 /* The special $hbr register is used to prevent the insn scheduler from | 2242 /* The special $hbr register is used to prevent the insn scheduler from |
2506 moving hbr insns across instructions which invalidate them. It | 2243 moving hbr insns across instructions which invalidate them. It |
2507 should only be used in a clobber, and this function searches for | 2244 should only be used in a clobber, and this function searches for |
2508 insns which clobber it. */ | 2245 insns which clobber it. */ |
2509 static bool | 2246 static bool |
2510 insn_clobbers_hbr (rtx insn) | 2247 insn_clobbers_hbr (rtx_insn *insn) |
2511 { | 2248 { |
2512 if (INSN_P (insn) | 2249 if (INSN_P (insn) |
2513 && GET_CODE (PATTERN (insn)) == PARALLEL) | 2250 && GET_CODE (PATTERN (insn)) == PARALLEL) |
2514 { | 2251 { |
2515 rtx parallel = PATTERN (insn); | 2252 rtx parallel = PATTERN (insn); |
2536 an even address. | 2273 an even address. |
2537 At then end of the search, insert an hbrp within 4 insns of FIRST, | 2274 At then end of the search, insert an hbrp within 4 insns of FIRST, |
2538 and an hbrp within 16 instructions of FIRST. | 2275 and an hbrp within 16 instructions of FIRST. |
2539 */ | 2276 */ |
2540 static void | 2277 static void |
2541 insert_hbrp_for_ilb_runout (rtx first) | 2278 insert_hbrp_for_ilb_runout (rtx_insn *first) |
2542 { | 2279 { |
2543 rtx insn, before_4 = 0, before_16 = 0; | 2280 rtx_insn *insn, *before_4 = 0, *before_16 = 0; |
2544 int addr = 0, length, first_addr = -1; | 2281 int addr = 0, length, first_addr = -1; |
2545 int hbrp_addr0 = 128 * 4, hbrp_addr1 = 128 * 4; | 2282 int hbrp_addr0 = 128 * 4, hbrp_addr1 = 128 * 4; |
2546 int insert_lnop_after = 0; | 2283 int insert_lnop_after = 0; |
2547 for (insn = first; insn; insn = NEXT_INSN (insn)) | 2284 for (insn = first; insn; insn = NEXT_INSN (insn)) |
2548 if (INSN_P (insn)) | 2285 if (INSN_P (insn)) |
2610 if (hbrp_addr0 > 4 * 4) | 2347 if (hbrp_addr0 > 4 * 4) |
2611 { | 2348 { |
2612 insn = | 2349 insn = |
2613 emit_insn_before (gen_iprefetch (GEN_INT (1)), before_4); | 2350 emit_insn_before (gen_iprefetch (GEN_INT (1)), before_4); |
2614 recog_memoized (insn); | 2351 recog_memoized (insn); |
2615 INSN_LOCATOR (insn) = INSN_LOCATOR (before_4); | 2352 INSN_LOCATION (insn) = INSN_LOCATION (before_4); |
2616 INSN_ADDRESSES_NEW (insn, | 2353 INSN_ADDRESSES_NEW (insn, |
2617 INSN_ADDRESSES (INSN_UID (before_4))); | 2354 INSN_ADDRESSES (INSN_UID (before_4))); |
2618 PUT_MODE (insn, GET_MODE (before_4)); | 2355 PUT_MODE (insn, GET_MODE (before_4)); |
2619 PUT_MODE (before_4, TImode); | 2356 PUT_MODE (before_4, TImode); |
2620 if (insert_lnop_after & 1) | 2357 if (insert_lnop_after & 1) |
2621 { | 2358 { |
2622 insn = emit_insn_before (gen_lnop (), before_4); | 2359 insn = emit_insn_before (gen_lnop (), before_4); |
2623 recog_memoized (insn); | 2360 recog_memoized (insn); |
2624 INSN_LOCATOR (insn) = INSN_LOCATOR (before_4); | 2361 INSN_LOCATION (insn) = INSN_LOCATION (before_4); |
2625 INSN_ADDRESSES_NEW (insn, | 2362 INSN_ADDRESSES_NEW (insn, |
2626 INSN_ADDRESSES (INSN_UID (before_4))); | 2363 INSN_ADDRESSES (INSN_UID (before_4))); |
2627 PUT_MODE (insn, TImode); | 2364 PUT_MODE (insn, TImode); |
2628 } | 2365 } |
2629 } | 2366 } |
2631 && hbrp_addr1 > 16 * 4) | 2368 && hbrp_addr1 > 16 * 4) |
2632 { | 2369 { |
2633 insn = | 2370 insn = |
2634 emit_insn_before (gen_iprefetch (GEN_INT (2)), before_16); | 2371 emit_insn_before (gen_iprefetch (GEN_INT (2)), before_16); |
2635 recog_memoized (insn); | 2372 recog_memoized (insn); |
2636 INSN_LOCATOR (insn) = INSN_LOCATOR (before_16); | 2373 INSN_LOCATION (insn) = INSN_LOCATION (before_16); |
2637 INSN_ADDRESSES_NEW (insn, | 2374 INSN_ADDRESSES_NEW (insn, |
2638 INSN_ADDRESSES (INSN_UID (before_16))); | 2375 INSN_ADDRESSES (INSN_UID (before_16))); |
2639 PUT_MODE (insn, GET_MODE (before_16)); | 2376 PUT_MODE (insn, GET_MODE (before_16)); |
2640 PUT_MODE (before_16, TImode); | 2377 PUT_MODE (before_16, TImode); |
2641 if (insert_lnop_after & 2) | 2378 if (insert_lnop_after & 2) |
2642 { | 2379 { |
2643 insn = emit_insn_before (gen_lnop (), before_16); | 2380 insn = emit_insn_before (gen_lnop (), before_16); |
2644 recog_memoized (insn); | 2381 recog_memoized (insn); |
2645 INSN_LOCATOR (insn) = INSN_LOCATOR (before_16); | 2382 INSN_LOCATION (insn) = INSN_LOCATION (before_16); |
2646 INSN_ADDRESSES_NEW (insn, | 2383 INSN_ADDRESSES_NEW (insn, |
2647 INSN_ADDRESSES (INSN_UID | 2384 INSN_ADDRESSES (INSN_UID |
2648 (before_16))); | 2385 (before_16))); |
2649 PUT_MODE (insn, TImode); | 2386 PUT_MODE (insn, TImode); |
2650 } | 2387 } |
2657 | 2394 |
2658 } | 2395 } |
2659 | 2396 |
2660 /* The SPU might hang when it executes 48 inline instructions after a | 2397 /* The SPU might hang when it executes 48 inline instructions after a |
2661 hinted branch jumps to its hinted target. The beginning of a | 2398 hinted branch jumps to its hinted target. The beginning of a |
2662 function and the return from a call might have been hinted, and must | 2399 function and the return from a call might have been hinted, and |
2663 be handled as well. To prevent a hang we insert 2 hbrps. The first | 2400 must be handled as well. To prevent a hang we insert 2 hbrps. The |
2664 should be within 6 insns of the branch target. The second should be | 2401 first should be within 6 insns of the branch target. The second |
2665 within 22 insns of the branch target. When determining if hbrps are | 2402 should be within 22 insns of the branch target. When determining |
2666 necessary, we look for only 32 inline instructions, because up to to | 2403 if hbrps are necessary, we look for only 32 inline instructions, |
2667 12 nops and 4 hbrps could be inserted. Similarily, when inserting | 2404 because up to 12 nops and 4 hbrps could be inserted. Similarily, |
2668 new hbrps, we insert them within 4 and 16 insns of the target. */ | 2405 when inserting new hbrps, we insert them within 4 and 16 insns of |
2406 the target. */ | |
2669 static void | 2407 static void |
2670 insert_hbrp (void) | 2408 insert_hbrp (void) |
2671 { | 2409 { |
2672 rtx insn; | 2410 rtx_insn *insn; |
2673 if (TARGET_SAFE_HINTS) | 2411 if (TARGET_SAFE_HINTS) |
2674 { | 2412 { |
2675 shorten_branches (get_insns ()); | 2413 shorten_branches (get_insns ()); |
2676 /* Insert hbrp at beginning of function */ | 2414 /* Insert hbrp at beginning of function */ |
2677 insn = next_active_insn (get_insns ()); | 2415 insn = next_active_insn (get_insns ()); |
2684 } | 2422 } |
2685 } | 2423 } |
2686 | 2424 |
2687 static int in_spu_reorg; | 2425 static int in_spu_reorg; |
2688 | 2426 |
2427 static void | |
2428 spu_var_tracking (void) | |
2429 { | |
2430 if (flag_var_tracking) | |
2431 { | |
2432 df_analyze (); | |
2433 timevar_push (TV_VAR_TRACKING); | |
2434 variable_tracking_main (); | |
2435 timevar_pop (TV_VAR_TRACKING); | |
2436 df_finish_pass (false); | |
2437 } | |
2438 } | |
2439 | |
2689 /* Insert branch hints. There are no branch optimizations after this | 2440 /* Insert branch hints. There are no branch optimizations after this |
2690 pass, so it's safe to set our branch hints now. */ | 2441 pass, so it's safe to set our branch hints now. */ |
2691 static void | 2442 static void |
2692 spu_machine_dependent_reorg (void) | 2443 spu_machine_dependent_reorg (void) |
2693 { | 2444 { |
2694 sbitmap blocks; | 2445 sbitmap blocks; |
2695 basic_block bb; | 2446 basic_block bb; |
2696 rtx branch, insn; | 2447 rtx_insn *branch, *insn; |
2697 rtx branch_target = 0; | 2448 rtx branch_target = 0; |
2698 int branch_addr = 0, insn_addr, required_dist = 0; | 2449 int branch_addr = 0, insn_addr, required_dist = 0; |
2699 int i; | 2450 int i; |
2700 unsigned int j; | 2451 unsigned int j; |
2701 | 2452 |
2702 if (!TARGET_BRANCH_HINTS || optimize == 0) | 2453 if (!TARGET_BRANCH_HINTS || optimize == 0) |
2703 { | 2454 { |
2704 /* We still do it for unoptimized code because an external | 2455 /* We still do it for unoptimized code because an external |
2705 function might have hinted a call or return. */ | 2456 function might have hinted a call or return. */ |
2457 compute_bb_for_insn (); | |
2706 insert_hbrp (); | 2458 insert_hbrp (); |
2707 pad_bb (); | 2459 pad_bb (); |
2460 spu_var_tracking (); | |
2461 free_bb_for_insn (); | |
2708 return; | 2462 return; |
2709 } | 2463 } |
2710 | 2464 |
2711 blocks = sbitmap_alloc (last_basic_block); | 2465 blocks = sbitmap_alloc (last_basic_block_for_fn (cfun)); |
2712 sbitmap_zero (blocks); | 2466 bitmap_clear (blocks); |
2713 | 2467 |
2714 in_spu_reorg = 1; | 2468 in_spu_reorg = 1; |
2715 compute_bb_for_insn (); | 2469 compute_bb_for_insn (); |
2716 | 2470 |
2471 /* (Re-)discover loops so that bb->loop_father can be used | |
2472 in the analysis below. */ | |
2473 loop_optimizer_init (AVOID_CFG_MODIFICATIONS); | |
2474 | |
2717 compact_blocks (); | 2475 compact_blocks (); |
2718 | 2476 |
2719 spu_bb_info = | 2477 spu_bb_info = |
2720 (struct spu_bb_info *) xcalloc (n_basic_blocks, | 2478 (struct spu_bb_info *) xcalloc (n_basic_blocks_for_fn (cfun), |
2721 sizeof (struct spu_bb_info)); | 2479 sizeof (struct spu_bb_info)); |
2722 | 2480 |
2723 /* We need exact insn addresses and lengths. */ | 2481 /* We need exact insn addresses and lengths. */ |
2724 shorten_branches (get_insns ()); | 2482 shorten_branches (get_insns ()); |
2725 | 2483 |
2726 for (i = n_basic_blocks - 1; i >= 0; i--) | 2484 for (i = n_basic_blocks_for_fn (cfun) - 1; i >= 0; i--) |
2727 { | 2485 { |
2728 bb = BASIC_BLOCK (i); | 2486 bb = BASIC_BLOCK_FOR_FN (cfun, i); |
2729 branch = 0; | 2487 branch = 0; |
2730 if (spu_bb_info[i].prop_jump) | 2488 if (spu_bb_info[i].prop_jump) |
2731 { | 2489 { |
2732 branch = spu_bb_info[i].prop_jump; | 2490 branch = spu_bb_info[i].prop_jump; |
2733 branch_target = get_branch_target (branch); | 2491 branch_target = get_branch_target (branch); |
2756 && ((GET_CODE (branch_target) == REG | 2514 && ((GET_CODE (branch_target) == REG |
2757 && set_of (branch_target, insn) != NULL_RTX) | 2515 && set_of (branch_target, insn) != NULL_RTX) |
2758 || insn_clobbers_hbr (insn) | 2516 || insn_clobbers_hbr (insn) |
2759 || branch_addr - insn_addr > 600)) | 2517 || branch_addr - insn_addr > 600)) |
2760 { | 2518 { |
2761 rtx next = NEXT_INSN (insn); | 2519 rtx_insn *next = NEXT_INSN (insn); |
2762 int next_addr = INSN_ADDRESSES (INSN_UID (next)); | 2520 int next_addr = INSN_ADDRESSES (INSN_UID (next)); |
2763 if (insn != BB_END (bb) | 2521 if (insn != BB_END (bb) |
2764 && branch_addr - next_addr >= required_dist) | 2522 && branch_addr - next_addr >= required_dist) |
2765 { | 2523 { |
2766 if (dump_file) | 2524 if (dump_file) |
2795 if (branch) | 2553 if (branch) |
2796 { | 2554 { |
2797 /* If we haven't emitted a hint for this branch yet, it might | 2555 /* If we haven't emitted a hint for this branch yet, it might |
2798 be profitable to emit it in one of the predecessor blocks, | 2556 be profitable to emit it in one of the predecessor blocks, |
2799 especially for loops. */ | 2557 especially for loops. */ |
2800 rtx bbend; | 2558 rtx_insn *bbend; |
2801 basic_block prev = 0, prop = 0, prev2 = 0; | 2559 basic_block prev = 0, prop = 0, prev2 = 0; |
2802 int loop_exit = 0, simple_loop = 0; | 2560 int loop_exit = 0, simple_loop = 0; |
2803 int next_addr = INSN_ADDRESSES (INSN_UID (NEXT_INSN (insn))); | 2561 int next_addr = INSN_ADDRESSES (INSN_UID (NEXT_INSN (insn))); |
2804 | 2562 |
2805 for (j = 0; j < EDGE_COUNT (bb->preds); j++) | 2563 for (j = 0; j < EDGE_COUNT (bb->preds); j++) |
2816 | 2574 |
2817 /* If this branch is a loop exit then propagate to previous | 2575 /* If this branch is a loop exit then propagate to previous |
2818 fallthru block. This catches the cases when it is a simple | 2576 fallthru block. This catches the cases when it is a simple |
2819 loop or when there is an initial branch into the loop. */ | 2577 loop or when there is an initial branch into the loop. */ |
2820 if (prev && (loop_exit || simple_loop) | 2578 if (prev && (loop_exit || simple_loop) |
2821 && prev->loop_depth <= bb->loop_depth) | 2579 && bb_loop_depth (prev) <= bb_loop_depth (bb)) |
2822 prop = prev; | 2580 prop = prev; |
2823 | 2581 |
2824 /* If there is only one adjacent predecessor. Don't propagate | 2582 /* If there is only one adjacent predecessor. Don't propagate |
2825 outside this loop. This loop_depth test isn't perfect, but | 2583 outside this loop. */ |
2826 I'm not sure the loop_father member is valid at this point. */ | |
2827 else if (prev && single_pred_p (bb) | 2584 else if (prev && single_pred_p (bb) |
2828 && prev->loop_depth == bb->loop_depth) | 2585 && prev->loop_father == bb->loop_father) |
2829 prop = prev; | 2586 prop = prev; |
2830 | 2587 |
2831 /* If this is the JOIN block of a simple IF-THEN then | 2588 /* If this is the JOIN block of a simple IF-THEN then |
2832 propogate the hint to the HEADER block. */ | 2589 propagate the hint to the HEADER block. */ |
2833 else if (prev && prev2 | 2590 else if (prev && prev2 |
2834 && EDGE_COUNT (bb->preds) == 2 | 2591 && EDGE_COUNT (bb->preds) == 2 |
2835 && EDGE_COUNT (prev->preds) == 1 | 2592 && EDGE_COUNT (prev->preds) == 1 |
2836 && EDGE_PRED (prev, 0)->src == prev2 | 2593 && EDGE_PRED (prev, 0)->src == prev2 |
2837 && prev2->loop_depth == bb->loop_depth | 2594 && prev2->loop_father == bb->loop_father |
2838 && GET_CODE (branch_target) != REG) | 2595 && GET_CODE (branch_target) != REG) |
2839 prop = prev; | 2596 prop = prev; |
2840 | 2597 |
2841 /* Don't propagate when: | 2598 /* Don't propagate when: |
2842 - this is a simple loop and the hint would be too far | 2599 - this is a simple loop and the hint would be too far |
2854 && (JUMP_P (bbend) || !insn_clobbers_hbr (bbend))) | 2611 && (JUMP_P (bbend) || !insn_clobbers_hbr (bbend))) |
2855 { | 2612 { |
2856 if (dump_file) | 2613 if (dump_file) |
2857 fprintf (dump_file, "propagate from %i to %i (loop depth %i) " | 2614 fprintf (dump_file, "propagate from %i to %i (loop depth %i) " |
2858 "for %i (loop_exit %i simple_loop %i dist %i)\n", | 2615 "for %i (loop_exit %i simple_loop %i dist %i)\n", |
2859 bb->index, prop->index, bb->loop_depth, | 2616 bb->index, prop->index, bb_loop_depth (bb), |
2860 INSN_UID (branch), loop_exit, simple_loop, | 2617 INSN_UID (branch), loop_exit, simple_loop, |
2861 branch_addr - INSN_ADDRESSES (INSN_UID (bbend))); | 2618 branch_addr - INSN_ADDRESSES (INSN_UID (bbend))); |
2862 | 2619 |
2863 spu_bb_info[prop->index].prop_jump = branch; | 2620 spu_bb_info[prop->index].prop_jump = branch; |
2864 spu_bb_info[prop->index].bb_index = i; | 2621 spu_bb_info[prop->index].bb_index = i; |
2875 branch = 0; | 2632 branch = 0; |
2876 } | 2633 } |
2877 } | 2634 } |
2878 free (spu_bb_info); | 2635 free (spu_bb_info); |
2879 | 2636 |
2880 if (!sbitmap_empty_p (blocks)) | 2637 if (!bitmap_empty_p (blocks)) |
2881 find_many_sub_basic_blocks (blocks); | 2638 find_many_sub_basic_blocks (blocks); |
2882 | 2639 |
2883 /* We have to schedule to make sure alignment is ok. */ | 2640 /* We have to schedule to make sure alignment is ok. */ |
2884 FOR_EACH_BB (bb) bb->flags &= ~BB_DISABLE_SCHEDULE; | 2641 FOR_EACH_BB_FN (bb, cfun) bb->flags &= ~BB_DISABLE_SCHEDULE; |
2885 | 2642 |
2886 /* The hints need to be scheduled, so call it again. */ | 2643 /* The hints need to be scheduled, so call it again. */ |
2887 schedule_insns (); | 2644 schedule_insns (); |
2888 df_finish_pass (true); | 2645 df_finish_pass (true); |
2889 | 2646 |
2897 /* Adjust the LABEL_REF in a hint when we have inserted a nop | 2654 /* Adjust the LABEL_REF in a hint when we have inserted a nop |
2898 between its branch label and the branch . We don't move the | 2655 between its branch label and the branch . We don't move the |
2899 label because GCC expects it at the beginning of the block. */ | 2656 label because GCC expects it at the beginning of the block. */ |
2900 rtx unspec = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); | 2657 rtx unspec = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); |
2901 rtx label_ref = XVECEXP (unspec, 0, 0); | 2658 rtx label_ref = XVECEXP (unspec, 0, 0); |
2902 rtx label = XEXP (label_ref, 0); | 2659 rtx_insn *label = as_a <rtx_insn *> (XEXP (label_ref, 0)); |
2903 rtx branch; | 2660 rtx_insn *branch; |
2904 int offset = 0; | 2661 int offset = 0; |
2905 for (branch = NEXT_INSN (label); | 2662 for (branch = NEXT_INSN (label); |
2906 !JUMP_P (branch) && !CALL_P (branch); | 2663 !JUMP_P (branch) && !CALL_P (branch); |
2907 branch = NEXT_INSN (branch)) | 2664 branch = NEXT_INSN (branch)) |
2908 if (NONJUMP_INSN_P (branch)) | 2665 if (NONJUMP_INSN_P (branch)) |
2909 offset += get_attr_length (branch); | 2666 offset += get_attr_length (branch); |
2910 if (offset > 0) | 2667 if (offset > 0) |
2911 XVECEXP (unspec, 0, 0) = plus_constant (label_ref, offset); | 2668 XVECEXP (unspec, 0, 0) = plus_constant (Pmode, label_ref, offset); |
2912 } | 2669 } |
2913 | 2670 |
2914 if (spu_flag_var_tracking) | 2671 spu_var_tracking (); |
2915 { | 2672 |
2916 df_analyze (); | 2673 loop_optimizer_finalize (); |
2917 timevar_push (TV_VAR_TRACKING); | |
2918 variable_tracking_main (); | |
2919 timevar_pop (TV_VAR_TRACKING); | |
2920 df_finish_pass (false); | |
2921 } | |
2922 | 2674 |
2923 free_bb_for_insn (); | 2675 free_bb_for_insn (); |
2924 | 2676 |
2925 in_spu_reorg = 0; | 2677 in_spu_reorg = 0; |
2926 } | 2678 } |
2932 { | 2684 { |
2933 return 2; | 2685 return 2; |
2934 } | 2686 } |
2935 | 2687 |
2936 static int | 2688 static int |
2937 uses_ls_unit(rtx insn) | 2689 uses_ls_unit(rtx_insn *insn) |
2938 { | 2690 { |
2939 rtx set = single_set (insn); | 2691 rtx set = single_set (insn); |
2940 if (set != 0 | 2692 if (set != 0 |
2941 && (GET_CODE (SET_DEST (set)) == MEM | 2693 && (GET_CODE (SET_DEST (set)) == MEM |
2942 || GET_CODE (SET_SRC (set)) == MEM)) | 2694 || GET_CODE (SET_SRC (set)) == MEM)) |
2943 return 1; | 2695 return 1; |
2944 return 0; | 2696 return 0; |
2945 } | 2697 } |
2946 | 2698 |
2947 static int | 2699 static int |
2948 get_pipe (rtx insn) | 2700 get_pipe (rtx_insn *insn) |
2949 { | 2701 { |
2950 enum attr_type t; | 2702 enum attr_type t; |
2951 /* Handle inline asm */ | 2703 /* Handle inline asm */ |
2952 if (INSN_CODE (insn) == -1) | 2704 if (INSN_CODE (insn) == -1) |
2953 return -1; | 2705 return -1; |
3039 prev_priority = -1; | 2791 prev_priority = -1; |
3040 } | 2792 } |
3041 | 2793 |
3042 static int | 2794 static int |
3043 spu_sched_variable_issue (FILE *file ATTRIBUTE_UNUSED, | 2795 spu_sched_variable_issue (FILE *file ATTRIBUTE_UNUSED, |
3044 int verbose ATTRIBUTE_UNUSED, rtx insn, int more) | 2796 int verbose ATTRIBUTE_UNUSED, |
2797 rtx_insn *insn, int more) | |
3045 { | 2798 { |
3046 int len; | 2799 int len; |
3047 int p; | 2800 int p; |
3048 if (GET_CODE (PATTERN (insn)) == USE | 2801 if (GET_CODE (PATTERN (insn)) == USE |
3049 || GET_CODE (PATTERN (insn)) == CLOBBER | 2802 || GET_CODE (PATTERN (insn)) == CLOBBER |
3088 that don't have INSN_PRIORITY */ | 2841 that don't have INSN_PRIORITY */ |
3089 if (more >= 0) | 2842 if (more >= 0) |
3090 prev_priority = INSN_PRIORITY (insn); | 2843 prev_priority = INSN_PRIORITY (insn); |
3091 } | 2844 } |
3092 | 2845 |
3093 /* Always try issueing more insns. spu_sched_reorder will decide | 2846 /* Always try issuing more insns. spu_sched_reorder will decide |
3094 when the cycle should be advanced. */ | 2847 when the cycle should be advanced. */ |
3095 return 1; | 2848 return 1; |
3096 } | 2849 } |
3097 | 2850 |
3098 /* This function is called for both TARGET_SCHED_REORDER and | 2851 /* This function is called for both TARGET_SCHED_REORDER and |
3099 TARGET_SCHED_REORDER2. */ | 2852 TARGET_SCHED_REORDER2. */ |
3100 static int | 2853 static int |
3101 spu_sched_reorder (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED, | 2854 spu_sched_reorder (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED, |
3102 rtx *ready, int *nreadyp, int clock) | 2855 rtx_insn **ready, int *nreadyp, int clock) |
3103 { | 2856 { |
3104 int i, nready = *nreadyp; | 2857 int i, nready = *nreadyp; |
3105 int pipe_0, pipe_1, pipe_hbrp, pipe_ls, schedule_i; | 2858 int pipe_0, pipe_1, pipe_hbrp, pipe_ls, schedule_i; |
3106 rtx insn; | 2859 rtx_insn *insn; |
3107 | 2860 |
3108 clock_var = clock; | 2861 clock_var = clock; |
3109 | 2862 |
3110 if (nready <= 0 || pipe1_clock >= clock) | 2863 if (nready <= 0 || pipe1_clock >= clock) |
3111 return 0; | 2864 return 0; |
3146 pipe_0 = i; | 2899 pipe_0 = i; |
3147 break; | 2900 break; |
3148 case TYPE_LOAD: | 2901 case TYPE_LOAD: |
3149 case TYPE_STORE: | 2902 case TYPE_STORE: |
3150 pipe_ls = i; | 2903 pipe_ls = i; |
2904 /* FALLTHRU */ | |
3151 case TYPE_LNOP: | 2905 case TYPE_LNOP: |
3152 case TYPE_SHUF: | 2906 case TYPE_SHUF: |
3153 case TYPE_BR: | 2907 case TYPE_BR: |
3154 case TYPE_MULTI1: | 2908 case TYPE_MULTI1: |
3155 case TYPE_HBR: | 2909 case TYPE_HBR: |
3195 without effecting the critical path. We look at INSN_PRIORITY to | 2949 without effecting the critical path. We look at INSN_PRIORITY to |
3196 make a good guess, but it isn't perfect so -mdual-nops=n can be | 2950 make a good guess, but it isn't perfect so -mdual-nops=n can be |
3197 used to effect it. */ | 2951 used to effect it. */ |
3198 if (in_spu_reorg && spu_dual_nops < 10) | 2952 if (in_spu_reorg && spu_dual_nops < 10) |
3199 { | 2953 { |
3200 /* When we are at an even address and we are not issueing nops to | 2954 /* When we are at an even address and we are not issuing nops to |
3201 improve scheduling then we need to advance the cycle. */ | 2955 improve scheduling then we need to advance the cycle. */ |
3202 if ((spu_sched_length & 7) == 0 && prev_clock_var == clock | 2956 if ((spu_sched_length & 7) == 0 && prev_clock_var == clock |
3203 && (spu_dual_nops == 0 | 2957 && (spu_dual_nops == 0 |
3204 || (pipe_1 != -1 | 2958 || (pipe_1 != -1 |
3205 && prev_priority > | 2959 && prev_priority > |
3236 return 0; | 2990 return 0; |
3237 } | 2991 } |
3238 | 2992 |
3239 /* INSN is dependent on DEP_INSN. */ | 2993 /* INSN is dependent on DEP_INSN. */ |
3240 static int | 2994 static int |
3241 spu_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) | 2995 spu_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, |
2996 int cost, unsigned int) | |
3242 { | 2997 { |
3243 rtx set; | 2998 rtx set; |
3244 | 2999 |
3245 /* The blockage pattern is used to prevent instructions from being | 3000 /* The blockage pattern is used to prevent instructions from being |
3246 moved across it and has no cost. */ | 3001 moved across it and has no cost. */ |
3297 | 3052 |
3298 /* The dfa scheduler sets cost to 0 for all anti-dependencies and the | 3053 /* The dfa scheduler sets cost to 0 for all anti-dependencies and the |
3299 scheduler makes every insn in a block anti-dependent on the final | 3054 scheduler makes every insn in a block anti-dependent on the final |
3300 jump_insn. We adjust here so higher cost insns will get scheduled | 3055 jump_insn. We adjust here so higher cost insns will get scheduled |
3301 earlier. */ | 3056 earlier. */ |
3302 if (JUMP_P (insn) && REG_NOTE_KIND (link) == REG_DEP_ANTI) | 3057 if (JUMP_P (insn) && dep_type == REG_DEP_ANTI) |
3303 return insn_cost (dep_insn) - 3; | 3058 return insn_sched_cost (dep_insn) - 3; |
3304 | 3059 |
3305 return cost; | 3060 return cost; |
3306 } | 3061 } |
3307 | 3062 |
3308 /* Create a CONST_DOUBLE from a string. */ | 3063 /* Create a CONST_DOUBLE from a string. */ |
3309 struct rtx_def * | 3064 rtx |
3310 spu_float_const (const char *string, enum machine_mode mode) | 3065 spu_float_const (const char *string, machine_mode mode) |
3311 { | 3066 { |
3312 REAL_VALUE_TYPE value; | 3067 REAL_VALUE_TYPE value; |
3313 value = REAL_VALUE_ATOF (string, mode); | 3068 value = REAL_VALUE_ATOF (string, mode); |
3314 return CONST_DOUBLE_FROM_REAL_VALUE (value, mode); | 3069 return const_double_from_real_value (value, mode); |
3315 } | 3070 } |
3316 | 3071 |
3317 int | 3072 int |
3318 spu_constant_address_p (rtx x) | 3073 spu_constant_address_p (rtx x) |
3319 { | 3074 { |
3340 } | 3095 } |
3341 | 3096 |
3342 /* Return true when OP can be loaded by one of the il instructions, or | 3097 /* Return true when OP can be loaded by one of the il instructions, or |
3343 when flow2 is not completed and OP can be loaded using ilhu and iohl. */ | 3098 when flow2 is not completed and OP can be loaded using ilhu and iohl. */ |
3344 int | 3099 int |
3345 immediate_load_p (rtx op, enum machine_mode mode) | 3100 immediate_load_p (rtx op, machine_mode mode) |
3346 { | 3101 { |
3347 if (CONSTANT_P (op)) | 3102 if (CONSTANT_P (op)) |
3348 { | 3103 { |
3349 enum immediate_class c = classify_immediate (op, mode); | 3104 enum immediate_class c = classify_immediate (op, mode); |
3350 return c == IC_IL1 || c == IC_IL1s | 3105 return c == IC_IL1 || c == IC_IL1s |
3403 } | 3158 } |
3404 | 3159 |
3405 /* OP is a CONSTANT_P. Determine what instructions can be used to load | 3160 /* OP is a CONSTANT_P. Determine what instructions can be used to load |
3406 it into a register. MODE is only valid when OP is a CONST_INT. */ | 3161 it into a register. MODE is only valid when OP is a CONST_INT. */ |
3407 static enum immediate_class | 3162 static enum immediate_class |
3408 classify_immediate (rtx op, enum machine_mode mode) | 3163 classify_immediate (rtx op, machine_mode mode) |
3409 { | 3164 { |
3410 HOST_WIDE_INT val; | 3165 HOST_WIDE_INT val; |
3411 unsigned char arr[16]; | 3166 unsigned char arr[16]; |
3412 int i, j, repeated, fsmbi, repeat; | 3167 int i, j, repeated, fsmbi, repeat; |
3413 | 3168 |
3419 /* A V4SI const_vector with all identical symbols is ok. */ | 3174 /* A V4SI const_vector with all identical symbols is ok. */ |
3420 if (!flag_pic | 3175 if (!flag_pic |
3421 && mode == V4SImode | 3176 && mode == V4SImode |
3422 && GET_CODE (op) == CONST_VECTOR | 3177 && GET_CODE (op) == CONST_VECTOR |
3423 && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_INT | 3178 && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_INT |
3424 && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_DOUBLE | 3179 && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_DOUBLE) |
3425 && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1) | 3180 op = unwrap_const_vec_duplicate (op); |
3426 && CONST_VECTOR_ELT (op, 1) == CONST_VECTOR_ELT (op, 2) | |
3427 && CONST_VECTOR_ELT (op, 2) == CONST_VECTOR_ELT (op, 3)) | |
3428 op = CONST_VECTOR_ELT (op, 0); | |
3429 | 3181 |
3430 switch (GET_CODE (op)) | 3182 switch (GET_CODE (op)) |
3431 { | 3183 { |
3432 case SYMBOL_REF: | 3184 case SYMBOL_REF: |
3433 case LABEL_REF: | 3185 case LABEL_REF: |
3543 return 0; | 3295 return 0; |
3544 return 1; | 3296 return 1; |
3545 } | 3297 } |
3546 | 3298 |
3547 int | 3299 int |
3548 logical_immediate_p (rtx op, enum machine_mode mode) | 3300 logical_immediate_p (rtx op, machine_mode mode) |
3549 { | 3301 { |
3550 HOST_WIDE_INT val; | 3302 HOST_WIDE_INT val; |
3551 unsigned char arr[16]; | 3303 unsigned char arr[16]; |
3552 int i, j; | 3304 int i, j; |
3553 | 3305 |
3575 i = which_logical_immediate (val); | 3327 i = which_logical_immediate (val); |
3576 return i != SPU_NONE && i != SPU_IOHL; | 3328 return i != SPU_NONE && i != SPU_IOHL; |
3577 } | 3329 } |
3578 | 3330 |
3579 int | 3331 int |
3580 iohl_immediate_p (rtx op, enum machine_mode mode) | 3332 iohl_immediate_p (rtx op, machine_mode mode) |
3581 { | 3333 { |
3582 HOST_WIDE_INT val; | 3334 HOST_WIDE_INT val; |
3583 unsigned char arr[16]; | 3335 unsigned char arr[16]; |
3584 int i, j; | 3336 int i, j; |
3585 | 3337 |
3606 | 3358 |
3607 return val >= 0 && val <= 0xffff; | 3359 return val >= 0 && val <= 0xffff; |
3608 } | 3360 } |
3609 | 3361 |
3610 int | 3362 int |
3611 arith_immediate_p (rtx op, enum machine_mode mode, | 3363 arith_immediate_p (rtx op, machine_mode mode, |
3612 HOST_WIDE_INT low, HOST_WIDE_INT high) | 3364 HOST_WIDE_INT low, HOST_WIDE_INT high) |
3613 { | 3365 { |
3614 HOST_WIDE_INT val; | 3366 HOST_WIDE_INT val; |
3615 unsigned char arr[16]; | 3367 unsigned char arr[16]; |
3616 int bytes, i, j; | 3368 int bytes, i, j; |
3625 if (GET_MODE (op) != VOIDmode) | 3377 if (GET_MODE (op) != VOIDmode) |
3626 mode = GET_MODE (op); | 3378 mode = GET_MODE (op); |
3627 | 3379 |
3628 constant_to_array (mode, op, arr); | 3380 constant_to_array (mode, op, arr); |
3629 | 3381 |
3630 if (VECTOR_MODE_P (mode)) | 3382 bytes = GET_MODE_UNIT_SIZE (mode); |
3631 mode = GET_MODE_INNER (mode); | 3383 mode = int_mode_for_mode (GET_MODE_INNER (mode)).require (); |
3632 | |
3633 bytes = GET_MODE_SIZE (mode); | |
3634 mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0); | |
3635 | 3384 |
3636 /* Check that bytes are repeated. */ | 3385 /* Check that bytes are repeated. */ |
3637 for (i = bytes; i < 16; i += bytes) | 3386 for (i = bytes; i < 16; i += bytes) |
3638 for (j = 0; j < bytes; j++) | 3387 for (j = 0; j < bytes; j++) |
3639 if (arr[j] != arr[i + j]) | 3388 if (arr[j] != arr[i + j]) |
3650 | 3399 |
3651 /* TRUE when op is an immediate and an exact power of 2, and given that | 3400 /* TRUE when op is an immediate and an exact power of 2, and given that |
3652 OP is 2^scale, scale >= LOW && scale <= HIGH. When OP is a vector, | 3401 OP is 2^scale, scale >= LOW && scale <= HIGH. When OP is a vector, |
3653 all entries must be the same. */ | 3402 all entries must be the same. */ |
3654 bool | 3403 bool |
3655 exp2_immediate_p (rtx op, enum machine_mode mode, int low, int high) | 3404 exp2_immediate_p (rtx op, machine_mode mode, int low, int high) |
3656 { | 3405 { |
3657 enum machine_mode int_mode; | 3406 machine_mode int_mode; |
3658 HOST_WIDE_INT val; | 3407 HOST_WIDE_INT val; |
3659 unsigned char arr[16]; | 3408 unsigned char arr[16]; |
3660 int bytes, i, j; | 3409 int bytes, i, j; |
3661 | 3410 |
3662 gcc_assert (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE | 3411 gcc_assert (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE |
3669 if (GET_MODE (op) != VOIDmode) | 3418 if (GET_MODE (op) != VOIDmode) |
3670 mode = GET_MODE (op); | 3419 mode = GET_MODE (op); |
3671 | 3420 |
3672 constant_to_array (mode, op, arr); | 3421 constant_to_array (mode, op, arr); |
3673 | 3422 |
3674 if (VECTOR_MODE_P (mode)) | 3423 mode = GET_MODE_INNER (mode); |
3675 mode = GET_MODE_INNER (mode); | |
3676 | 3424 |
3677 bytes = GET_MODE_SIZE (mode); | 3425 bytes = GET_MODE_SIZE (mode); |
3678 int_mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0); | 3426 int_mode = int_mode_for_mode (mode).require (); |
3679 | 3427 |
3680 /* Check that bytes are repeated. */ | 3428 /* Check that bytes are repeated. */ |
3681 for (i = bytes; i < 16; i += bytes) | 3429 for (i = bytes; i < 16; i += bytes) |
3682 for (j = 0; j < bytes; j++) | 3430 for (j = 0; j < bytes; j++) |
3683 if (arr[j] != arr[i + j]) | 3431 if (arr[j] != arr[i + j]) |
3700 return FALSE; | 3448 return FALSE; |
3701 } | 3449 } |
3702 | 3450 |
3703 /* Return true if X is a SYMBOL_REF to an __ea qualified variable. */ | 3451 /* Return true if X is a SYMBOL_REF to an __ea qualified variable. */ |
3704 | 3452 |
3705 static int | 3453 static bool |
3706 ea_symbol_ref (rtx *px, void *data ATTRIBUTE_UNUSED) | 3454 ea_symbol_ref_p (const_rtx x) |
3707 { | 3455 { |
3708 rtx x = *px; | |
3709 tree decl; | 3456 tree decl; |
3710 | 3457 |
3711 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) | 3458 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) |
3712 { | 3459 { |
3713 rtx plus = XEXP (x, 0); | 3460 rtx plus = XEXP (x, 0); |
3727 - any 32-bit constant (SImode, SFmode) | 3474 - any 32-bit constant (SImode, SFmode) |
3728 - any constant that can be generated with fsmbi (any mode) | 3475 - any constant that can be generated with fsmbi (any mode) |
3729 - a 64-bit constant where the high and low bits are identical | 3476 - a 64-bit constant where the high and low bits are identical |
3730 (DImode, DFmode) | 3477 (DImode, DFmode) |
3731 - a 128-bit constant where the four 32-bit words match. */ | 3478 - a 128-bit constant where the four 32-bit words match. */ |
3732 int | 3479 bool |
3733 spu_legitimate_constant_p (rtx x) | 3480 spu_legitimate_constant_p (machine_mode mode, rtx x) |
3734 { | 3481 { |
3482 subrtx_iterator::array_type array; | |
3735 if (GET_CODE (x) == HIGH) | 3483 if (GET_CODE (x) == HIGH) |
3736 x = XEXP (x, 0); | 3484 x = XEXP (x, 0); |
3737 | 3485 |
3738 /* Reject any __ea qualified reference. These can't appear in | 3486 /* Reject any __ea qualified reference. These can't appear in |
3739 instructions but must be forced to the constant pool. */ | 3487 instructions but must be forced to the constant pool. */ |
3740 if (for_each_rtx (&x, ea_symbol_ref, 0)) | 3488 FOR_EACH_SUBRTX (iter, array, x, ALL) |
3741 return 0; | 3489 if (ea_symbol_ref_p (*iter)) |
3490 return 0; | |
3742 | 3491 |
3743 /* V4SI with all identical symbols is valid. */ | 3492 /* V4SI with all identical symbols is valid. */ |
3744 if (!flag_pic | 3493 if (!flag_pic |
3745 && GET_MODE (x) == V4SImode | 3494 && mode == V4SImode |
3746 && (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF | 3495 && (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF |
3747 || GET_CODE (CONST_VECTOR_ELT (x, 0)) == LABEL_REF | 3496 || GET_CODE (CONST_VECTOR_ELT (x, 0)) == LABEL_REF |
3748 || GET_CODE (CONST_VECTOR_ELT (x, 0)) == CONST)) | 3497 || GET_CODE (CONST_VECTOR_ELT (x, 0)) == CONST)) |
3749 return CONST_VECTOR_ELT (x, 0) == CONST_VECTOR_ELT (x, 1) | 3498 return const_vec_duplicate_p (x); |
3750 && CONST_VECTOR_ELT (x, 1) == CONST_VECTOR_ELT (x, 2) | |
3751 && CONST_VECTOR_ELT (x, 2) == CONST_VECTOR_ELT (x, 3); | |
3752 | 3499 |
3753 if (GET_CODE (x) == CONST_VECTOR | 3500 if (GET_CODE (x) == CONST_VECTOR |
3754 && !const_vector_immediate_p (x)) | 3501 && !const_vector_immediate_p (x)) |
3755 return 0; | 3502 return 0; |
3756 return 1; | 3503 return 1; |
3764 The alignment matters in the reg+const case because lqd and stqd | 3511 The alignment matters in the reg+const case because lqd and stqd |
3765 ignore the 4 least significant bits of the const. We only care about | 3512 ignore the 4 least significant bits of the const. We only care about |
3766 16 byte modes because the expand phase will change all smaller MEM | 3513 16 byte modes because the expand phase will change all smaller MEM |
3767 references to TImode. */ | 3514 references to TImode. */ |
3768 static bool | 3515 static bool |
3769 spu_legitimate_address_p (enum machine_mode mode, | 3516 spu_legitimate_address_p (machine_mode mode, |
3770 rtx x, bool reg_ok_strict) | 3517 rtx x, bool reg_ok_strict) |
3771 { | 3518 { |
3772 int aligned = GET_MODE_SIZE (mode) >= 16; | 3519 int aligned = GET_MODE_SIZE (mode) >= 16; |
3773 if (aligned | 3520 if (aligned |
3774 && GET_CODE (x) == AND | 3521 && GET_CODE (x) == AND |
3782 | 3529 |
3783 case SYMBOL_REF: | 3530 case SYMBOL_REF: |
3784 case CONST: | 3531 case CONST: |
3785 /* Keep __ea references until reload so that spu_expand_mov can see them | 3532 /* Keep __ea references until reload so that spu_expand_mov can see them |
3786 in MEMs. */ | 3533 in MEMs. */ |
3787 if (ea_symbol_ref (&x, 0)) | 3534 if (ea_symbol_ref_p (x)) |
3788 return !reload_in_progress && !reload_completed; | 3535 return !reload_in_progress && !reload_completed; |
3789 return !TARGET_LARGE_MEM; | 3536 return !TARGET_LARGE_MEM; |
3790 | 3537 |
3791 case CONST_INT: | 3538 case CONST_INT: |
3792 return INTVAL (x) >= 0 && INTVAL (x) <= 0x3ffff; | 3539 return INTVAL (x) >= 0 && INTVAL (x) <= 0x3ffff; |
3793 | 3540 |
3794 case SUBREG: | 3541 case SUBREG: |
3795 x = XEXP (x, 0); | 3542 x = XEXP (x, 0); |
3796 if (REG_P (x)) | 3543 if (!REG_P (x)) |
3797 return 0; | 3544 return 0; |
3545 /* FALLTHRU */ | |
3798 | 3546 |
3799 case REG: | 3547 case REG: |
3800 return INT_REG_OK_FOR_BASE_P (x, reg_ok_strict); | 3548 return INT_REG_OK_FOR_BASE_P (x, reg_ok_strict); |
3801 | 3549 |
3802 case PLUS: | 3550 case PLUS: |
3809 if (GET_CODE (op1) == SUBREG) | 3557 if (GET_CODE (op1) == SUBREG) |
3810 op1 = XEXP (op1, 0); | 3558 op1 = XEXP (op1, 0); |
3811 if (GET_CODE (op0) == REG | 3559 if (GET_CODE (op0) == REG |
3812 && INT_REG_OK_FOR_BASE_P (op0, reg_ok_strict) | 3560 && INT_REG_OK_FOR_BASE_P (op0, reg_ok_strict) |
3813 && GET_CODE (op1) == CONST_INT | 3561 && GET_CODE (op1) == CONST_INT |
3814 && INTVAL (op1) >= -0x2000 | 3562 && ((INTVAL (op1) >= -0x2000 && INTVAL (op1) <= 0x1fff) |
3815 && INTVAL (op1) <= 0x1fff | 3563 /* If virtual registers are involved, the displacement will |
3564 change later on anyway, so checking would be premature. | |
3565 Reload will make sure the final displacement after | |
3566 register elimination is OK. */ | |
3567 || op0 == arg_pointer_rtx | |
3568 || op0 == frame_pointer_rtx | |
3569 || op0 == virtual_stack_vars_rtx) | |
3816 && (!aligned || (INTVAL (op1) & 15) == 0)) | 3570 && (!aligned || (INTVAL (op1) & 15) == 0)) |
3817 return TRUE; | 3571 return TRUE; |
3818 if (GET_CODE (op0) == REG | 3572 if (GET_CODE (op0) == REG |
3819 && INT_REG_OK_FOR_BASE_P (op0, reg_ok_strict) | 3573 && INT_REG_OK_FOR_BASE_P (op0, reg_ok_strict) |
3820 && GET_CODE (op1) == REG | 3574 && GET_CODE (op1) == REG |
3829 return FALSE; | 3583 return FALSE; |
3830 } | 3584 } |
3831 | 3585 |
3832 /* Like spu_legitimate_address_p, except with named addresses. */ | 3586 /* Like spu_legitimate_address_p, except with named addresses. */ |
3833 static bool | 3587 static bool |
3834 spu_addr_space_legitimate_address_p (enum machine_mode mode, rtx x, | 3588 spu_addr_space_legitimate_address_p (machine_mode mode, rtx x, |
3835 bool reg_ok_strict, addr_space_t as) | 3589 bool reg_ok_strict, addr_space_t as) |
3836 { | 3590 { |
3837 if (as == ADDR_SPACE_EA) | 3591 if (as == ADDR_SPACE_EA) |
3838 return (REG_P (x) && (GET_MODE (x) == EAmode)); | 3592 return (REG_P (x) && (GET_MODE (x) == EAmode)); |
3839 | 3593 |
3843 return spu_legitimate_address_p (mode, x, reg_ok_strict); | 3597 return spu_legitimate_address_p (mode, x, reg_ok_strict); |
3844 } | 3598 } |
3845 | 3599 |
3846 /* When the address is reg + const_int, force the const_int into a | 3600 /* When the address is reg + const_int, force the const_int into a |
3847 register. */ | 3601 register. */ |
3848 rtx | 3602 static rtx |
3849 spu_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, | 3603 spu_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, |
3850 enum machine_mode mode ATTRIBUTE_UNUSED) | 3604 machine_mode mode ATTRIBUTE_UNUSED) |
3851 { | 3605 { |
3852 rtx op0, op1; | 3606 rtx op0, op1; |
3853 /* Make sure both operands are registers. */ | 3607 /* Make sure both operands are registers. */ |
3854 if (GET_CODE (x) == PLUS) | 3608 if (GET_CODE (x) == PLUS) |
3855 { | 3609 { |
3874 return x; | 3628 return x; |
3875 } | 3629 } |
3876 | 3630 |
3877 /* Like spu_legitimate_address, except with named address support. */ | 3631 /* Like spu_legitimate_address, except with named address support. */ |
3878 static rtx | 3632 static rtx |
3879 spu_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode, | 3633 spu_addr_space_legitimize_address (rtx x, rtx oldx, machine_mode mode, |
3880 addr_space_t as) | 3634 addr_space_t as) |
3881 { | 3635 { |
3882 if (as != ADDR_SPACE_GENERIC) | 3636 if (as != ADDR_SPACE_GENERIC) |
3883 return x; | 3637 return x; |
3884 | 3638 |
3885 return spu_legitimize_address (x, oldx, mode); | 3639 return spu_legitimize_address (x, oldx, mode); |
3640 } | |
3641 | |
3642 /* Reload reg + const_int for out-of-range displacements. */ | |
3643 rtx | |
3644 spu_legitimize_reload_address (rtx ad, machine_mode mode ATTRIBUTE_UNUSED, | |
3645 int opnum, int type) | |
3646 { | |
3647 bool removed_and = false; | |
3648 | |
3649 if (GET_CODE (ad) == AND | |
3650 && CONST_INT_P (XEXP (ad, 1)) | |
3651 && INTVAL (XEXP (ad, 1)) == (HOST_WIDE_INT) - 16) | |
3652 { | |
3653 ad = XEXP (ad, 0); | |
3654 removed_and = true; | |
3655 } | |
3656 | |
3657 if (GET_CODE (ad) == PLUS | |
3658 && REG_P (XEXP (ad, 0)) | |
3659 && CONST_INT_P (XEXP (ad, 1)) | |
3660 && !(INTVAL (XEXP (ad, 1)) >= -0x2000 | |
3661 && INTVAL (XEXP (ad, 1)) <= 0x1fff)) | |
3662 { | |
3663 /* Unshare the sum. */ | |
3664 ad = copy_rtx (ad); | |
3665 | |
3666 /* Reload the displacement. */ | |
3667 push_reload (XEXP (ad, 1), NULL_RTX, &XEXP (ad, 1), NULL, | |
3668 BASE_REG_CLASS, GET_MODE (ad), VOIDmode, 0, 0, | |
3669 opnum, (enum reload_type) type); | |
3670 | |
3671 /* Add back AND for alignment if we stripped it. */ | |
3672 if (removed_and) | |
3673 ad = gen_rtx_AND (GET_MODE (ad), ad, GEN_INT (-16)); | |
3674 | |
3675 return ad; | |
3676 } | |
3677 | |
3678 return NULL_RTX; | |
3886 } | 3679 } |
3887 | 3680 |
3888 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in | 3681 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in |
3889 struct attribute_spec.handler. */ | 3682 struct attribute_spec.handler. */ |
3890 static tree | 3683 static tree |
3908 spu_handle_vector_attribute (tree * node, tree name, | 3701 spu_handle_vector_attribute (tree * node, tree name, |
3909 tree args ATTRIBUTE_UNUSED, | 3702 tree args ATTRIBUTE_UNUSED, |
3910 int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) | 3703 int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) |
3911 { | 3704 { |
3912 tree type = *node, result = NULL_TREE; | 3705 tree type = *node, result = NULL_TREE; |
3913 enum machine_mode mode; | 3706 machine_mode mode; |
3914 int unsigned_p; | 3707 int unsigned_p; |
3915 | 3708 |
3916 while (POINTER_TYPE_P (type) | 3709 while (POINTER_TYPE_P (type) |
3917 || TREE_CODE (type) == FUNCTION_TYPE | 3710 || TREE_CODE (type) == FUNCTION_TYPE |
3918 || TREE_CODE (type) == METHOD_TYPE || TREE_CODE (type) == ARRAY_TYPE) | 3711 || TREE_CODE (type) == METHOD_TYPE || TREE_CODE (type) == ARRAY_TYPE) |
3921 mode = TYPE_MODE (type); | 3714 mode = TYPE_MODE (type); |
3922 | 3715 |
3923 unsigned_p = TYPE_UNSIGNED (type); | 3716 unsigned_p = TYPE_UNSIGNED (type); |
3924 switch (mode) | 3717 switch (mode) |
3925 { | 3718 { |
3926 case DImode: | 3719 case E_DImode: |
3927 result = (unsigned_p ? unsigned_V2DI_type_node : V2DI_type_node); | 3720 result = (unsigned_p ? unsigned_V2DI_type_node : V2DI_type_node); |
3928 break; | 3721 break; |
3929 case SImode: | 3722 case E_SImode: |
3930 result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node); | 3723 result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node); |
3931 break; | 3724 break; |
3932 case HImode: | 3725 case E_HImode: |
3933 result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node); | 3726 result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node); |
3934 break; | 3727 break; |
3935 case QImode: | 3728 case E_QImode: |
3936 result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node); | 3729 result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node); |
3937 break; | 3730 break; |
3938 case SFmode: | 3731 case E_SFmode: |
3939 result = V4SF_type_node; | 3732 result = V4SF_type_node; |
3940 break; | 3733 break; |
3941 case DFmode: | 3734 case E_DFmode: |
3942 result = V2DF_type_node; | 3735 result = V2DF_type_node; |
3943 break; | 3736 break; |
3944 default: | 3737 default: |
3945 break; | 3738 break; |
3946 } | 3739 } |
3976 int | 3769 int |
3977 spu_initial_elimination_offset (int from, int to) | 3770 spu_initial_elimination_offset (int from, int to) |
3978 { | 3771 { |
3979 int saved_regs_size = spu_saved_regs_size (); | 3772 int saved_regs_size = spu_saved_regs_size (); |
3980 int sp_offset = 0; | 3773 int sp_offset = 0; |
3981 if (!current_function_is_leaf || crtl->outgoing_args_size | 3774 if (!crtl->is_leaf || crtl->outgoing_args_size |
3982 || get_frame_size () || saved_regs_size) | 3775 || get_frame_size () || saved_regs_size) |
3983 sp_offset = STACK_POINTER_OFFSET; | 3776 sp_offset = STACK_POINTER_OFFSET; |
3984 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) | 3777 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
3985 return get_frame_size () + crtl->outgoing_args_size + sp_offset; | 3778 return get_frame_size () + crtl->outgoing_args_size + sp_offset; |
3986 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) | 3779 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) |
3995 } | 3788 } |
3996 | 3789 |
3997 rtx | 3790 rtx |
3998 spu_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED) | 3791 spu_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED) |
3999 { | 3792 { |
4000 enum machine_mode mode = TYPE_MODE (type); | 3793 machine_mode mode = TYPE_MODE (type); |
4001 int byte_size = ((mode == BLKmode) | 3794 int byte_size = ((mode == BLKmode) |
4002 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); | 3795 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); |
4003 | 3796 |
4004 /* Make sure small structs are left justified in a register. */ | 3797 /* Make sure small structs are left justified in a register. */ |
4005 if ((mode == BLKmode || (type && AGGREGATE_TYPE_P (type))) | 3798 if ((mode == BLKmode || (type && AGGREGATE_TYPE_P (type))) |
4006 && byte_size <= UNITS_PER_WORD * MAX_REGISTER_RETURN && byte_size > 0) | 3799 && byte_size <= UNITS_PER_WORD * MAX_REGISTER_RETURN && byte_size > 0) |
4007 { | 3800 { |
4008 enum machine_mode smode; | 3801 machine_mode smode; |
4009 rtvec v; | 3802 rtvec v; |
4010 int i; | 3803 int i; |
4011 int nregs = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; | 3804 int nregs = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
4012 int n = byte_size / UNITS_PER_WORD; | 3805 int n = byte_size / UNITS_PER_WORD; |
4013 v = rtvec_alloc (nregs); | 3806 v = rtvec_alloc (nregs); |
4023 | 3816 |
4024 if (n < nregs) | 3817 if (n < nregs) |
4025 { | 3818 { |
4026 if (byte_size < 4) | 3819 if (byte_size < 4) |
4027 byte_size = 4; | 3820 byte_size = 4; |
4028 smode = | 3821 smode = smallest_int_mode_for_size (byte_size * BITS_PER_UNIT); |
4029 smallest_mode_for_size (byte_size * BITS_PER_UNIT, MODE_INT); | |
4030 RTVEC_ELT (v, n) = | 3822 RTVEC_ELT (v, n) = |
4031 gen_rtx_EXPR_LIST (VOIDmode, | 3823 gen_rtx_EXPR_LIST (VOIDmode, |
4032 gen_rtx_REG (smode, FIRST_RETURN_REGNUM + n), | 3824 gen_rtx_REG (smode, FIRST_RETURN_REGNUM + n), |
4033 GEN_INT (UNITS_PER_WORD * n)); | 3825 GEN_INT (UNITS_PER_WORD * n)); |
4034 } | 3826 } |
4036 } | 3828 } |
4037 return gen_rtx_REG (mode, FIRST_RETURN_REGNUM); | 3829 return gen_rtx_REG (mode, FIRST_RETURN_REGNUM); |
4038 } | 3830 } |
4039 | 3831 |
4040 static rtx | 3832 static rtx |
4041 spu_function_arg (CUMULATIVE_ARGS *cum, | 3833 spu_function_arg (cumulative_args_t cum_v, |
4042 enum machine_mode mode, | 3834 machine_mode mode, |
4043 const_tree type, bool named ATTRIBUTE_UNUSED) | 3835 const_tree type, bool named ATTRIBUTE_UNUSED) |
4044 { | 3836 { |
3837 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); | |
4045 int byte_size; | 3838 int byte_size; |
4046 | 3839 |
4047 if (*cum >= MAX_REGISTER_ARGS) | 3840 if (*cum >= MAX_REGISTER_ARGS) |
4048 return 0; | 3841 return 0; |
4049 | 3842 |
4057 | 3850 |
4058 /* Make sure small structs are left justified in a register. */ | 3851 /* Make sure small structs are left justified in a register. */ |
4059 if ((mode == BLKmode || (type && AGGREGATE_TYPE_P (type))) | 3852 if ((mode == BLKmode || (type && AGGREGATE_TYPE_P (type))) |
4060 && byte_size < UNITS_PER_WORD && byte_size > 0) | 3853 && byte_size < UNITS_PER_WORD && byte_size > 0) |
4061 { | 3854 { |
4062 enum machine_mode smode; | 3855 machine_mode smode; |
4063 rtx gr_reg; | 3856 rtx gr_reg; |
4064 if (byte_size < 4) | 3857 if (byte_size < 4) |
4065 byte_size = 4; | 3858 byte_size = 4; |
4066 smode = smallest_mode_for_size (byte_size * BITS_PER_UNIT, MODE_INT); | 3859 smode = smallest_int_mode_for_size (byte_size * BITS_PER_UNIT); |
4067 gr_reg = gen_rtx_EXPR_LIST (VOIDmode, | 3860 gr_reg = gen_rtx_EXPR_LIST (VOIDmode, |
4068 gen_rtx_REG (smode, FIRST_ARG_REGNUM + *cum), | 3861 gen_rtx_REG (smode, FIRST_ARG_REGNUM + *cum), |
4069 const0_rtx); | 3862 const0_rtx); |
4070 return gen_rtx_PARALLEL (mode, gen_rtvec (1, gr_reg)); | 3863 return gen_rtx_PARALLEL (mode, gen_rtvec (1, gr_reg)); |
4071 } | 3864 } |
4072 else | 3865 else |
4073 return gen_rtx_REG (mode, FIRST_ARG_REGNUM + *cum); | 3866 return gen_rtx_REG (mode, FIRST_ARG_REGNUM + *cum); |
4074 } | 3867 } |
4075 | 3868 |
4076 static void | 3869 static void |
4077 spu_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode, | 3870 spu_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, |
4078 const_tree type, bool named ATTRIBUTE_UNUSED) | 3871 const_tree type, bool named ATTRIBUTE_UNUSED) |
4079 { | 3872 { |
3873 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); | |
3874 | |
4080 *cum += (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST | 3875 *cum += (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST |
4081 ? 1 | 3876 ? 1 |
4082 : mode == BLKmode | 3877 : mode == BLKmode |
4083 ? ((int_size_in_bytes (type) + 15) / 16) | 3878 ? ((int_size_in_bytes (type) + 15) / 16) |
4084 : mode == VOIDmode | 3879 : mode == VOIDmode |
4085 ? 1 | 3880 ? 1 |
4086 : HARD_REGNO_NREGS (cum, mode)); | 3881 : spu_hard_regno_nregs (FIRST_ARG_REGNUM, mode)); |
3882 } | |
3883 | |
3884 /* Implement TARGET_FUNCTION_ARG_OFFSET. The SPU ABI wants 32/64-bit | |
3885 types at offset 0 in the quad-word on the stack. 8/16-bit types | |
3886 should be at offsets 3/2 respectively. */ | |
3887 | |
3888 static HOST_WIDE_INT | |
3889 spu_function_arg_offset (machine_mode mode, const_tree type) | |
3890 { | |
3891 if (type && INTEGRAL_TYPE_P (type) && GET_MODE_SIZE (mode) < 4) | |
3892 return 4 - GET_MODE_SIZE (mode); | |
3893 return 0; | |
3894 } | |
3895 | |
3896 /* Implement TARGET_FUNCTION_ARG_PADDING. */ | |
3897 | |
3898 static pad_direction | |
3899 spu_function_arg_padding (machine_mode, const_tree) | |
3900 { | |
3901 return PAD_UPWARD; | |
4087 } | 3902 } |
4088 | 3903 |
4089 /* Variable sized types are passed by reference. */ | 3904 /* Variable sized types are passed by reference. */ |
4090 static bool | 3905 static bool |
4091 spu_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED, | 3906 spu_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, |
4092 enum machine_mode mode ATTRIBUTE_UNUSED, | 3907 machine_mode mode ATTRIBUTE_UNUSED, |
4093 const_tree type, bool named ATTRIBUTE_UNUSED) | 3908 const_tree type, bool named ATTRIBUTE_UNUSED) |
4094 { | 3909 { |
4095 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST; | 3910 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST; |
4096 } | 3911 } |
4097 | 3912 |
4128 FIELD_DECL, get_identifier ("__args"), ptr_type_node); | 3943 FIELD_DECL, get_identifier ("__args"), ptr_type_node); |
4129 f_skip = build_decl (BUILTINS_LOCATION, | 3944 f_skip = build_decl (BUILTINS_LOCATION, |
4130 FIELD_DECL, get_identifier ("__skip"), ptr_type_node); | 3945 FIELD_DECL, get_identifier ("__skip"), ptr_type_node); |
4131 | 3946 |
4132 DECL_FIELD_CONTEXT (f_args) = record; | 3947 DECL_FIELD_CONTEXT (f_args) = record; |
4133 DECL_ALIGN (f_args) = 128; | 3948 SET_DECL_ALIGN (f_args, 128); |
4134 DECL_USER_ALIGN (f_args) = 1; | 3949 DECL_USER_ALIGN (f_args) = 1; |
4135 | 3950 |
4136 DECL_FIELD_CONTEXT (f_skip) = record; | 3951 DECL_FIELD_CONTEXT (f_skip) = record; |
4137 DECL_ALIGN (f_skip) = 128; | 3952 SET_DECL_ALIGN (f_skip, 128); |
4138 DECL_USER_ALIGN (f_skip) = 1; | 3953 DECL_USER_ALIGN (f_skip) = 1; |
4139 | 3954 |
4140 TYPE_STUB_DECL (record) = type_decl; | 3955 TYPE_STUB_DECL (record) = type_decl; |
4141 TYPE_NAME (record) = type_decl; | 3956 TYPE_NAME (record) = type_decl; |
4142 TYPE_FIELDS (record) = f_args; | 3957 TYPE_FIELDS (record) = f_args; |
4184 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); | 3999 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); |
4185 | 4000 |
4186 /* Find the __args area. */ | 4001 /* Find the __args area. */ |
4187 t = make_tree (TREE_TYPE (args), nextarg); | 4002 t = make_tree (TREE_TYPE (args), nextarg); |
4188 if (crtl->args.pretend_args_size > 0) | 4003 if (crtl->args.pretend_args_size > 0) |
4189 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (args), t, | 4004 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); |
4190 size_int (-STACK_POINTER_OFFSET)); | |
4191 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t); | 4005 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t); |
4192 TREE_SIDE_EFFECTS (t) = 1; | 4006 TREE_SIDE_EFFECTS (t) = 1; |
4193 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | 4007 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
4194 | 4008 |
4195 /* Find the __skip area. */ | 4009 /* Find the __skip area. */ |
4196 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx); | 4010 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx); |
4197 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (skip), t, | 4011 t = fold_build_pointer_plus_hwi (t, (crtl->args.pretend_args_size |
4198 size_int (crtl->args.pretend_args_size | 4012 - STACK_POINTER_OFFSET)); |
4199 - STACK_POINTER_OFFSET)); | |
4200 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t); | 4013 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t); |
4201 TREE_SIDE_EFFECTS (t) = 1; | 4014 TREE_SIDE_EFFECTS (t) = 1; |
4202 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | 4015 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
4203 } | 4016 } |
4204 | 4017 |
4224 gimple_seq * post_p ATTRIBUTE_UNUSED) | 4037 gimple_seq * post_p ATTRIBUTE_UNUSED) |
4225 { | 4038 { |
4226 tree f_args, f_skip; | 4039 tree f_args, f_skip; |
4227 tree args, skip; | 4040 tree args, skip; |
4228 HOST_WIDE_INT size, rsize; | 4041 HOST_WIDE_INT size, rsize; |
4229 tree paddedsize, addr, tmp; | 4042 tree addr, tmp; |
4230 bool pass_by_reference_p; | 4043 bool pass_by_reference_p; |
4231 | 4044 |
4232 f_args = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); | 4045 f_args = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); |
4233 f_skip = DECL_CHAIN (f_args); | 4046 f_skip = DECL_CHAIN (f_args); |
4234 | 4047 |
4235 valist = build_simple_mem_ref (valist); | |
4236 args = | 4048 args = |
4237 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); | 4049 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); |
4238 skip = | 4050 skip = |
4239 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); | 4051 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); |
4240 | 4052 |
4241 addr = create_tmp_var (ptr_type_node, "va_arg"); | 4053 addr = create_tmp_var (ptr_type_node, "va_arg"); |
4242 | 4054 |
4243 /* if an object is dynamically sized, a pointer to it is passed | 4055 /* if an object is dynamically sized, a pointer to it is passed |
4244 instead of the object itself. */ | 4056 instead of the object itself. */ |
4245 pass_by_reference_p = spu_pass_by_reference (NULL, TYPE_MODE (type), type, | 4057 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type, |
4246 false); | 4058 false); |
4247 if (pass_by_reference_p) | 4059 if (pass_by_reference_p) |
4248 type = build_pointer_type (type); | 4060 type = build_pointer_type (type); |
4249 size = int_size_in_bytes (type); | 4061 size = int_size_in_bytes (type); |
4250 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD; | 4062 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD; |
4251 | 4063 |
4252 /* build conditional expression to calculate addr. The expression | 4064 /* build conditional expression to calculate addr. The expression |
4253 will be gimplified later. */ | 4065 will be gimplified later. */ |
4254 paddedsize = size_int (rsize); | 4066 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize); |
4255 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (args), paddedsize); | |
4256 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node, | 4067 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node, |
4257 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)), | 4068 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)), |
4258 build2 (LE_EXPR, boolean_type_node, unshare_expr (args), | 4069 build2 (LE_EXPR, boolean_type_node, unshare_expr (args), |
4259 unshare_expr (skip))); | 4070 unshare_expr (skip))); |
4260 | 4071 |
4261 tmp = build3 (COND_EXPR, ptr_type_node, tmp, | 4072 tmp = build3 (COND_EXPR, ptr_type_node, tmp, |
4262 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip), | 4073 fold_build_pointer_plus_hwi (unshare_expr (skip), 32), |
4263 size_int (32)), unshare_expr (args)); | 4074 unshare_expr (args)); |
4264 | 4075 |
4265 gimplify_assign (addr, tmp, pre_p); | 4076 gimplify_assign (addr, tmp, pre_p); |
4266 | 4077 |
4267 /* update VALIST.__args */ | 4078 /* update VALIST.__args */ |
4268 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, addr, paddedsize); | 4079 tmp = fold_build_pointer_plus_hwi (addr, rsize); |
4269 gimplify_assign (unshare_expr (args), tmp, pre_p); | 4080 gimplify_assign (unshare_expr (args), tmp, pre_p); |
4270 | 4081 |
4271 addr = fold_convert (build_pointer_type_for_mode (type, ptr_mode, true), | 4082 addr = fold_convert (build_pointer_type_for_mode (type, ptr_mode, true), |
4272 addr); | 4083 addr); |
4273 | 4084 |
4279 | 4090 |
4280 /* Save parameter registers starting with the register that corresponds | 4091 /* Save parameter registers starting with the register that corresponds |
4281 to the first unnamed parameters. If the first unnamed parameter is | 4092 to the first unnamed parameters. If the first unnamed parameter is |
4282 in the stack then save no registers. Set pretend_args_size to the | 4093 in the stack then save no registers. Set pretend_args_size to the |
4283 amount of space needed to save the registers. */ | 4094 amount of space needed to save the registers. */ |
4284 void | 4095 static void |
4285 spu_setup_incoming_varargs (CUMULATIVE_ARGS * cum, enum machine_mode mode, | 4096 spu_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode, |
4286 tree type, int *pretend_size, int no_rtl) | 4097 tree type, int *pretend_size, int no_rtl) |
4287 { | 4098 { |
4288 if (!no_rtl) | 4099 if (!no_rtl) |
4289 { | 4100 { |
4290 rtx tmp; | 4101 rtx tmp; |
4291 int regno; | 4102 int regno; |
4292 int offset; | 4103 int offset; |
4293 int ncum = *cum; | 4104 int ncum = *get_cumulative_args (cum); |
4294 | 4105 |
4295 /* cum currently points to the last named argument, we want to | 4106 /* cum currently points to the last named argument, we want to |
4296 start at the next argument. */ | 4107 start at the next argument. */ |
4297 spu_function_arg_advance (&ncum, mode, type, true); | 4108 spu_function_arg_advance (pack_cumulative_args (&ncum), mode, type, true); |
4298 | 4109 |
4299 offset = -STACK_POINTER_OFFSET; | 4110 offset = -STACK_POINTER_OFFSET; |
4300 for (regno = ncum; regno < MAX_REGISTER_ARGS; regno++) | 4111 for (regno = ncum; regno < MAX_REGISTER_ARGS; regno++) |
4301 { | 4112 { |
4302 tmp = gen_frame_mem (V4SImode, | 4113 tmp = gen_frame_mem (V4SImode, |
4303 plus_constant (virtual_incoming_args_rtx, | 4114 plus_constant (Pmode, virtual_incoming_args_rtx, |
4304 offset)); | 4115 offset)); |
4305 emit_move_insn (tmp, | 4116 emit_move_insn (tmp, |
4306 gen_rtx_REG (V4SImode, FIRST_ARG_REGNUM + regno)); | 4117 gen_rtx_REG (V4SImode, FIRST_ARG_REGNUM + regno)); |
4307 offset += 16; | 4118 offset += 16; |
4308 } | 4119 } |
4346 | 4157 |
4347 /* Return TRUE if we are certain the mem refers to a complete object | 4158 /* Return TRUE if we are certain the mem refers to a complete object |
4348 which is both 16-byte aligned and padded to a 16-byte boundary. This | 4159 which is both 16-byte aligned and padded to a 16-byte boundary. This |
4349 would make it safe to store with a single instruction. | 4160 would make it safe to store with a single instruction. |
4350 We guarantee the alignment and padding for static objects by aligning | 4161 We guarantee the alignment and padding for static objects by aligning |
4351 all of them to 16-bytes. (DATA_ALIGNMENT and CONSTANT_ALIGNMENT.) | 4162 all of them to 16-bytes. (DATA_ALIGNMENT and TARGET_CONSTANT_ALIGNMENT.) |
4352 FIXME: We currently cannot guarantee this for objects on the stack | 4163 FIXME: We currently cannot guarantee this for objects on the stack |
4353 because assign_parm_setup_stack calls assign_stack_local with the | 4164 because assign_parm_setup_stack calls assign_stack_local with the |
4354 alignment of the parameter mode and in that case the alignment never | 4165 alignment of the parameter mode and in that case the alignment never |
4355 gets adjusted by LOCAL_ALIGNMENT. */ | 4166 gets adjusted by LOCAL_ALIGNMENT. */ |
4356 static int | 4167 static int |
4357 store_with_one_insn_p (rtx mem) | 4168 store_with_one_insn_p (rtx mem) |
4358 { | 4169 { |
4359 enum machine_mode mode = GET_MODE (mem); | 4170 machine_mode mode = GET_MODE (mem); |
4360 rtx addr = XEXP (mem, 0); | 4171 rtx addr = XEXP (mem, 0); |
4361 if (mode == BLKmode) | 4172 if (mode == BLKmode) |
4362 return 0; | 4173 return 0; |
4363 if (GET_MODE_SIZE (mode) >= 16) | 4174 if (GET_MODE_SIZE (mode) >= 16) |
4364 return 1; | 4175 return 1; |
4365 /* Only static objects. */ | 4176 /* Only static objects. */ |
4366 if (GET_CODE (addr) == SYMBOL_REF) | 4177 if (GET_CODE (addr) == SYMBOL_REF) |
4367 { | 4178 { |
4368 /* We use the associated declaration to make sure the access is | 4179 /* We use the associated declaration to make sure the access is |
4369 referring to the whole object. | 4180 referring to the whole object. |
4370 We check both MEM_EXPR and and SYMBOL_REF_DECL. I'm not sure | 4181 We check both MEM_EXPR and SYMBOL_REF_DECL. I'm not sure |
4371 if it is necessary. Will there be cases where one exists, and | 4182 if it is necessary. Will there be cases where one exists, and |
4372 the other does not? Will there be cases where both exist, but | 4183 the other does not? Will there be cases where both exist, but |
4373 have different types? */ | 4184 have different types? */ |
4374 tree decl = MEM_EXPR (mem); | 4185 tree decl = MEM_EXPR (mem); |
4375 if (decl | 4186 if (decl |
4416 { | 4227 { |
4417 rtx ndirty = GEN_INT (GET_MODE_SIZE (GET_MODE (mem))); | 4228 rtx ndirty = GEN_INT (GET_MODE_SIZE (GET_MODE (mem))); |
4418 if (!cache_fetch_dirty) | 4229 if (!cache_fetch_dirty) |
4419 cache_fetch_dirty = init_one_libfunc ("__cache_fetch_dirty"); | 4230 cache_fetch_dirty = init_one_libfunc ("__cache_fetch_dirty"); |
4420 emit_library_call_value (cache_fetch_dirty, data_addr, LCT_NORMAL, Pmode, | 4231 emit_library_call_value (cache_fetch_dirty, data_addr, LCT_NORMAL, Pmode, |
4421 2, ea_addr, EAmode, ndirty, SImode); | 4232 ea_addr, EAmode, ndirty, SImode); |
4422 } | 4233 } |
4423 else | 4234 else |
4424 { | 4235 { |
4425 if (!cache_fetch) | 4236 if (!cache_fetch) |
4426 cache_fetch = init_one_libfunc ("__cache_fetch"); | 4237 cache_fetch = init_one_libfunc ("__cache_fetch"); |
4427 emit_library_call_value (cache_fetch, data_addr, LCT_NORMAL, Pmode, | 4238 emit_library_call_value (cache_fetch, data_addr, LCT_NORMAL, Pmode, |
4428 1, ea_addr, EAmode); | 4239 ea_addr, EAmode); |
4429 } | 4240 } |
4430 } | 4241 } |
4431 | 4242 |
4432 /* Like ea_load_store, but do the cache tag comparison and, for stores, | 4243 /* Like ea_load_store, but do the cache tag comparison and, for stores, |
4433 dirty bit marking, inline. | 4244 dirty bit marking, inline. |
4466 rtx tag_equal = gen_reg_rtx (V4SImode); | 4277 rtx tag_equal = gen_reg_rtx (V4SImode); |
4467 rtx tag_equal_hi = NULL_RTX; | 4278 rtx tag_equal_hi = NULL_RTX; |
4468 rtx tag_eq_pack = gen_reg_rtx (V4SImode); | 4279 rtx tag_eq_pack = gen_reg_rtx (V4SImode); |
4469 rtx tag_eq_pack_si = gen_reg_rtx (SImode); | 4280 rtx tag_eq_pack_si = gen_reg_rtx (SImode); |
4470 rtx eq_index = gen_reg_rtx (SImode); | 4281 rtx eq_index = gen_reg_rtx (SImode); |
4471 rtx bcomp, hit_label, hit_ref, cont_label, insn; | 4282 rtx bcomp, hit_label, hit_ref, cont_label; |
4283 rtx_insn *insn; | |
4472 | 4284 |
4473 if (spu_ea_model != 32) | 4285 if (spu_ea_model != 32) |
4474 { | 4286 { |
4475 splat_hi = gen_reg_rtx (V4SImode); | 4287 splat_hi = gen_reg_rtx (V4SImode); |
4476 cache_tag_hi = gen_reg_rtx (V4SImode); | 4288 cache_tag_hi = gen_reg_rtx (V4SImode); |
4477 tag_equal_hi = gen_reg_rtx (V4SImode); | 4289 tag_equal_hi = gen_reg_rtx (V4SImode); |
4478 } | 4290 } |
4479 | 4291 |
4480 emit_move_insn (index_mask, plus_constant (tag_size_sym, -128)); | 4292 emit_move_insn (index_mask, plus_constant (Pmode, tag_size_sym, -128)); |
4481 emit_move_insn (tag_arr, tag_arr_sym); | 4293 emit_move_insn (tag_arr, tag_arr_sym); |
4482 v = 0x0001020300010203LL; | 4294 v = 0x0001020300010203LL; |
4483 emit_move_insn (splat_mask, immed_double_const (v, v, TImode)); | 4295 emit_move_insn (splat_mask, immed_double_const (v, v, TImode)); |
4484 ea_addr_si = ea_addr; | 4296 ea_addr_si = ea_addr; |
4485 if (spu_ea_model != 32) | 4297 if (spu_ea_model != 32) |
4502 | 4314 |
4503 /* Read cache tags. */ | 4315 /* Read cache tags. */ |
4504 emit_move_insn (cache_tag, gen_rtx_MEM (V4SImode, tag_addr)); | 4316 emit_move_insn (cache_tag, gen_rtx_MEM (V4SImode, tag_addr)); |
4505 if (spu_ea_model != 32) | 4317 if (spu_ea_model != 32) |
4506 emit_move_insn (cache_tag_hi, gen_rtx_MEM (V4SImode, | 4318 emit_move_insn (cache_tag_hi, gen_rtx_MEM (V4SImode, |
4507 plus_constant (tag_addr, 16))); | 4319 plus_constant (Pmode, |
4320 tag_addr, 16))); | |
4508 | 4321 |
4509 /* tag = ea_addr & -128 */ | 4322 /* tag = ea_addr & -128 */ |
4510 emit_insn (gen_andv4si3 (tag, splat, spu_const (V4SImode, -128))); | 4323 emit_insn (gen_andv4si3 (tag, splat, spu_const (V4SImode, -128))); |
4511 | 4324 |
4512 /* Read all four cache data pointers. */ | 4325 /* Read all four cache data pointers. */ |
4513 emit_move_insn (cache_ptrs, gen_rtx_MEM (TImode, | 4326 emit_move_insn (cache_ptrs, gen_rtx_MEM (TImode, |
4514 plus_constant (tag_addr, 32))); | 4327 plus_constant (Pmode, |
4328 tag_addr, 32))); | |
4515 | 4329 |
4516 /* Compare tags. */ | 4330 /* Compare tags. */ |
4517 emit_insn (gen_ceq_v4si (tag_equal, tag, cache_tag)); | 4331 emit_insn (gen_ceq_v4si (tag_equal, tag, cache_tag)); |
4518 if (spu_ea_model != 32) | 4332 if (spu_ea_model != 32) |
4519 { | 4333 { |
4542 | 4356 |
4543 /* Check that we did hit. */ | 4357 /* Check that we did hit. */ |
4544 hit_label = gen_label_rtx (); | 4358 hit_label = gen_label_rtx (); |
4545 hit_ref = gen_rtx_LABEL_REF (VOIDmode, hit_label); | 4359 hit_ref = gen_rtx_LABEL_REF (VOIDmode, hit_label); |
4546 bcomp = gen_rtx_NE (SImode, tag_eq_pack_si, const0_rtx); | 4360 bcomp = gen_rtx_NE (SImode, tag_eq_pack_si, const0_rtx); |
4547 insn = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, | 4361 insn = emit_jump_insn (gen_rtx_SET (pc_rtx, |
4548 gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, | 4362 gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, |
4549 hit_ref, pc_rtx))); | 4363 hit_ref, pc_rtx))); |
4550 /* Say that this branch is very likely to happen. */ | 4364 /* Say that this branch is very likely to happen. */ |
4551 v = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100 - 1; | 4365 add_reg_br_prob_note (insn, profile_probability::very_likely ()); |
4552 add_reg_note (insn, REG_BR_PROB, GEN_INT (v)); | |
4553 | 4366 |
4554 ea_load_store (mem, is_store, ea_addr, data_addr); | 4367 ea_load_store (mem, is_store, ea_addr, data_addr); |
4555 cont_label = gen_label_rtx (); | 4368 cont_label = gen_label_rtx (); |
4556 emit_jump_insn (gen_jump (cont_label)); | 4369 emit_jump_insn (gen_jump (cont_label)); |
4557 emit_barrier (); | 4370 emit_barrier (); |
4626 | 4439 |
4627 return new_mem; | 4440 return new_mem; |
4628 } | 4441 } |
4629 | 4442 |
4630 int | 4443 int |
4631 spu_expand_mov (rtx * ops, enum machine_mode mode) | 4444 spu_expand_mov (rtx * ops, machine_mode mode) |
4632 { | 4445 { |
4633 if (GET_CODE (ops[0]) == SUBREG && !valid_subreg (ops[0])) | 4446 if (GET_CODE (ops[0]) == SUBREG && !valid_subreg (ops[0])) |
4634 { | 4447 { |
4635 /* Perform the move in the destination SUBREG's inner mode. */ | 4448 /* Perform the move in the destination SUBREG's inner mode. */ |
4636 ops[0] = SUBREG_REG (ops[0]); | 4449 ops[0] = SUBREG_REG (ops[0]); |
4640 } | 4453 } |
4641 | 4454 |
4642 if (GET_CODE (ops[1]) == SUBREG && !valid_subreg (ops[1])) | 4455 if (GET_CODE (ops[1]) == SUBREG && !valid_subreg (ops[1])) |
4643 { | 4456 { |
4644 rtx from = SUBREG_REG (ops[1]); | 4457 rtx from = SUBREG_REG (ops[1]); |
4645 enum machine_mode imode = int_mode_for_mode (GET_MODE (from)); | 4458 scalar_int_mode imode = int_mode_for_mode (GET_MODE (from)).require (); |
4646 | 4459 |
4647 gcc_assert (GET_MODE_CLASS (mode) == MODE_INT | 4460 gcc_assert (GET_MODE_CLASS (mode) == MODE_INT |
4648 && GET_MODE_CLASS (imode) == MODE_INT | 4461 && GET_MODE_CLASS (imode) == MODE_INT |
4649 && subreg_lowpart_p (ops[1])); | 4462 && subreg_lowpart_p (ops[1])); |
4650 | 4463 |
4707 } | 4520 } |
4708 | 4521 |
4709 static void | 4522 static void |
4710 spu_convert_move (rtx dst, rtx src) | 4523 spu_convert_move (rtx dst, rtx src) |
4711 { | 4524 { |
4712 enum machine_mode mode = GET_MODE (dst); | 4525 machine_mode mode = GET_MODE (dst); |
4713 enum machine_mode int_mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0); | 4526 machine_mode int_mode = int_mode_for_mode (mode).require (); |
4714 rtx reg; | 4527 rtx reg; |
4715 gcc_assert (GET_MODE (src) == TImode); | 4528 gcc_assert (GET_MODE (src) == TImode); |
4716 reg = int_mode != mode ? gen_reg_rtx (int_mode) : dst; | 4529 reg = int_mode != mode ? gen_reg_rtx (int_mode) : dst; |
4717 emit_insn (gen_rtx_SET (VOIDmode, reg, | 4530 emit_insn (gen_rtx_SET (reg, |
4718 gen_rtx_TRUNCATE (int_mode, | 4531 gen_rtx_TRUNCATE (int_mode, |
4719 gen_rtx_LSHIFTRT (TImode, src, | 4532 gen_rtx_LSHIFTRT (TImode, src, |
4720 GEN_INT (int_mode == DImode ? 64 : 96))))); | 4533 GEN_INT (int_mode == DImode ? 64 : 96))))); |
4721 if (int_mode != mode) | 4534 if (int_mode != mode) |
4722 { | 4535 { |
4860 addr0 = gen_rtx_AND (SImode, copy_rtx (addr), GEN_INT (-16)); | 4673 addr0 = gen_rtx_AND (SImode, copy_rtx (addr), GEN_INT (-16)); |
4861 emit_insn (gen__movti (dst0, change_address (src, TImode, addr0))); | 4674 emit_insn (gen__movti (dst0, change_address (src, TImode, addr0))); |
4862 | 4675 |
4863 if (dst1) | 4676 if (dst1) |
4864 { | 4677 { |
4865 addr1 = plus_constant (copy_rtx (addr), 16); | 4678 addr1 = plus_constant (SImode, copy_rtx (addr), 16); |
4866 addr1 = gen_rtx_AND (SImode, addr1, GEN_INT (-16)); | 4679 addr1 = gen_rtx_AND (SImode, addr1, GEN_INT (-16)); |
4867 emit_insn (gen__movti (dst1, change_address (src, TImode, addr1))); | 4680 emit_insn (gen__movti (dst1, change_address (src, TImode, addr1))); |
4868 } | 4681 } |
4869 | 4682 |
4870 return rot; | 4683 return rot; |
4871 } | 4684 } |
4872 | 4685 |
4873 int | 4686 int |
4874 spu_split_load (rtx * ops) | 4687 spu_split_load (rtx * ops) |
4875 { | 4688 { |
4876 enum machine_mode mode = GET_MODE (ops[0]); | 4689 machine_mode mode = GET_MODE (ops[0]); |
4877 rtx addr, load, rot; | 4690 rtx addr, load, rot; |
4878 int rot_amt; | 4691 int rot_amt; |
4879 | 4692 |
4880 if (GET_MODE_SIZE (mode) >= 16) | 4693 if (GET_MODE_SIZE (mode) >= 16) |
4881 return 0; | 4694 return 0; |
4905 } | 4718 } |
4906 | 4719 |
4907 int | 4720 int |
4908 spu_split_store (rtx * ops) | 4721 spu_split_store (rtx * ops) |
4909 { | 4722 { |
4910 enum machine_mode mode = GET_MODE (ops[0]); | 4723 machine_mode mode = GET_MODE (ops[0]); |
4911 rtx reg; | 4724 rtx reg; |
4912 rtx addr, p0, p1, p1_lo, smem; | 4725 rtx addr, p0, p1, p1_lo, smem; |
4913 int aform; | 4726 int aform; |
4914 int scalar; | 4727 int scalar; |
4915 | 4728 |
5162 } | 4975 } |
5163 | 4976 |
5164 /* Return TRUE if x is a CONST_INT, CONST_DOUBLE or CONST_VECTOR that | 4977 /* Return TRUE if x is a CONST_INT, CONST_DOUBLE or CONST_VECTOR that |
5165 can be generated using the cbd, chd, cwd or cdd instruction. */ | 4978 can be generated using the cbd, chd, cwd or cdd instruction. */ |
5166 int | 4979 int |
5167 cpat_const_p (rtx x, enum machine_mode mode) | 4980 cpat_const_p (rtx x, machine_mode mode) |
5168 { | 4981 { |
5169 if (CONSTANT_P (x)) | 4982 if (CONSTANT_P (x)) |
5170 { | 4983 { |
5171 enum immediate_class c = classify_immediate (x, mode); | 4984 enum immediate_class c = classify_immediate (x, mode); |
5172 return c == IC_CPAT; | 4985 return c == IC_CPAT; |
5208 | 5021 |
5209 /* Convert a CONST_INT, CONST_DOUBLE, or CONST_VECTOR into a 16 byte | 5022 /* Convert a CONST_INT, CONST_DOUBLE, or CONST_VECTOR into a 16 byte |
5210 array. Use MODE for CONST_INT's. When the constant's mode is smaller | 5023 array. Use MODE for CONST_INT's. When the constant's mode is smaller |
5211 than 16 bytes, the value is repeated across the rest of the array. */ | 5024 than 16 bytes, the value is repeated across the rest of the array. */ |
5212 void | 5025 void |
5213 constant_to_array (enum machine_mode mode, rtx x, unsigned char arr[16]) | 5026 constant_to_array (machine_mode mode, rtx x, unsigned char arr[16]) |
5214 { | 5027 { |
5215 HOST_WIDE_INT val; | 5028 HOST_WIDE_INT val; |
5216 int i, j, first; | 5029 int i, j, first; |
5217 | 5030 |
5218 memset (arr, 0, 16); | 5031 memset (arr, 0, 16); |
5287 | 5100 |
5288 /* Convert a 16 byte array to a constant of mode MODE. When MODE is | 5101 /* Convert a 16 byte array to a constant of mode MODE. When MODE is |
5289 smaller than 16 bytes, use the bytes that would represent that value | 5102 smaller than 16 bytes, use the bytes that would represent that value |
5290 in a register, e.g., for QImode return the value of arr[3]. */ | 5103 in a register, e.g., for QImode return the value of arr[3]. */ |
5291 rtx | 5104 rtx |
5292 array_to_constant (enum machine_mode mode, const unsigned char arr[16]) | 5105 array_to_constant (machine_mode mode, const unsigned char arr[16]) |
5293 { | 5106 { |
5294 enum machine_mode inner_mode; | 5107 machine_mode inner_mode; |
5295 rtvec v; | 5108 rtvec v; |
5296 int units, size, i, j, k; | 5109 int units, size, i, j, k; |
5297 HOST_WIDE_INT val; | 5110 HOST_WIDE_INT val; |
5298 | 5111 |
5299 if (GET_MODE_CLASS (mode) == MODE_INT | 5112 if (GET_MODE_CLASS (mode) == MODE_INT |
5421 assemble_name (file, name); | 5234 assemble_name (file, name); |
5422 fputs ("\n", file); | 5235 fputs ("\n", file); |
5423 } | 5236 } |
5424 | 5237 |
5425 static bool | 5238 static bool |
5426 spu_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, | 5239 spu_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED, |
5240 int opno ATTRIBUTE_UNUSED, int *total, | |
5427 bool speed ATTRIBUTE_UNUSED) | 5241 bool speed ATTRIBUTE_UNUSED) |
5428 { | 5242 { |
5429 enum machine_mode mode = GET_MODE (x); | 5243 int code = GET_CODE (x); |
5430 int cost = COSTS_N_INSNS (2); | 5244 int cost = COSTS_N_INSNS (2); |
5431 | 5245 |
5432 /* Folding to a CONST_VECTOR will use extra space but there might | 5246 /* Folding to a CONST_VECTOR will use extra space but there might |
5433 be only a small savings in cycles. We'd like to use a CONST_VECTOR | 5247 be only a small savings in cycles. We'd like to use a CONST_VECTOR |
5434 only if it allows us to fold away multiple insns. Changing the cost | 5248 only if it allows us to fold away multiple insns. Changing the cost |
5435 of a CONST_VECTOR here (or in CONST_COSTS) doesn't help though | 5249 of a CONST_VECTOR here (or in CONST_COSTS) doesn't help though |
5436 because this cost will only be compared against a single insn. | 5250 because this cost will only be compared against a single insn. |
5437 if (code == CONST_VECTOR) | 5251 if (code == CONST_VECTOR) |
5438 return (LEGITIMATE_CONSTANT_P(x)) ? cost : COSTS_N_INSNS(6); | 5252 return spu_legitimate_constant_p (mode, x) ? cost : COSTS_N_INSNS (6); |
5439 */ | 5253 */ |
5440 | 5254 |
5441 /* Use defaults for float operations. Not accurate but good enough. */ | 5255 /* Use defaults for float operations. Not accurate but good enough. */ |
5442 if (mode == DFmode) | 5256 if (mode == DFmode) |
5443 { | 5257 { |
5535 * (GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode)); | 5349 * (GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode)); |
5536 *total = cost; | 5350 *total = cost; |
5537 return true; | 5351 return true; |
5538 } | 5352 } |
5539 | 5353 |
5540 static enum machine_mode | 5354 static scalar_int_mode |
5541 spu_unwind_word_mode (void) | 5355 spu_unwind_word_mode (void) |
5542 { | 5356 { |
5543 return SImode; | 5357 return SImode; |
5544 } | 5358 } |
5545 | 5359 |
5574 emit_insn (gen_shufb (splatted, op1, op1, pat)); | 5388 emit_insn (gen_shufb (splatted, op1, op1, pat)); |
5575 | 5389 |
5576 emit_insn (gen_spu_convert (sp, stack_pointer_rtx)); | 5390 emit_insn (gen_spu_convert (sp, stack_pointer_rtx)); |
5577 emit_insn (gen_subv4si3 (sp, sp, splatted)); | 5391 emit_insn (gen_subv4si3 (sp, sp, splatted)); |
5578 | 5392 |
5579 if (flag_stack_check) | 5393 if (flag_stack_check || flag_stack_clash_protection) |
5580 { | 5394 { |
5581 rtx avail = gen_reg_rtx(SImode); | 5395 rtx avail = gen_reg_rtx(SImode); |
5582 rtx result = gen_reg_rtx(SImode); | 5396 rtx result = gen_reg_rtx(SImode); |
5583 emit_insn (gen_vec_extractv4si (avail, sp, GEN_INT (1))); | 5397 emit_insn (gen_vec_extractv4sisi (avail, sp, GEN_INT (1))); |
5584 emit_insn (gen_cgt_si(result, avail, GEN_INT (-1))); | 5398 emit_insn (gen_cgt_si(result, avail, GEN_INT (-1))); |
5585 emit_insn (gen_spu_heq (result, GEN_INT(0) )); | 5399 emit_insn (gen_spu_heq (result, GEN_INT(0) )); |
5586 } | 5400 } |
5587 | 5401 |
5588 emit_insn (gen_spu_convert (stack_pointer_rtx, sp)); | 5402 emit_insn (gen_spu_convert (stack_pointer_rtx, sp)); |
5633 set_optab_libfunc (umod_optab, DImode, "__umoddi3"); | 5447 set_optab_libfunc (umod_optab, DImode, "__umoddi3"); |
5634 set_optab_libfunc (udivmod_optab, DImode, "__udivmoddi4"); | 5448 set_optab_libfunc (udivmod_optab, DImode, "__udivmoddi4"); |
5635 set_optab_libfunc (ffs_optab, DImode, "__ffsdi2"); | 5449 set_optab_libfunc (ffs_optab, DImode, "__ffsdi2"); |
5636 set_optab_libfunc (clz_optab, DImode, "__clzdi2"); | 5450 set_optab_libfunc (clz_optab, DImode, "__clzdi2"); |
5637 set_optab_libfunc (ctz_optab, DImode, "__ctzdi2"); | 5451 set_optab_libfunc (ctz_optab, DImode, "__ctzdi2"); |
5452 set_optab_libfunc (clrsb_optab, DImode, "__clrsbdi2"); | |
5638 set_optab_libfunc (popcount_optab, DImode, "__popcountdi2"); | 5453 set_optab_libfunc (popcount_optab, DImode, "__popcountdi2"); |
5639 set_optab_libfunc (parity_optab, DImode, "__paritydi2"); | 5454 set_optab_libfunc (parity_optab, DImode, "__paritydi2"); |
5640 | 5455 |
5641 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__float_unssidf"); | 5456 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__float_unssidf"); |
5642 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__float_unsdidf"); | 5457 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__float_unsdidf"); |
5663 } | 5478 } |
5664 | 5479 |
5665 /* Make a subreg, stripping any existing subreg. We could possibly just | 5480 /* Make a subreg, stripping any existing subreg. We could possibly just |
5666 call simplify_subreg, but in this case we know what we want. */ | 5481 call simplify_subreg, but in this case we know what we want. */ |
5667 rtx | 5482 rtx |
5668 spu_gen_subreg (enum machine_mode mode, rtx x) | 5483 spu_gen_subreg (machine_mode mode, rtx x) |
5669 { | 5484 { |
5670 if (GET_CODE (x) == SUBREG) | 5485 if (GET_CODE (x) == SUBREG) |
5671 x = SUBREG_REG (x); | 5486 x = SUBREG_REG (x); |
5672 if (GET_MODE (x) == mode) | 5487 if (GET_MODE (x) == mode) |
5673 return x; | 5488 return x; |
5834 } | 5649 } |
5835 | 5650 |
5836 void | 5651 void |
5837 spu_builtin_splats (rtx ops[]) | 5652 spu_builtin_splats (rtx ops[]) |
5838 { | 5653 { |
5839 enum machine_mode mode = GET_MODE (ops[0]); | 5654 machine_mode mode = GET_MODE (ops[0]); |
5840 if (GET_CODE (ops[1]) == CONST_INT || GET_CODE (ops[1]) == CONST_DOUBLE) | 5655 if (GET_CODE (ops[1]) == CONST_INT || GET_CODE (ops[1]) == CONST_DOUBLE) |
5841 { | 5656 { |
5842 unsigned char arr[16]; | 5657 unsigned char arr[16]; |
5843 constant_to_array (GET_MODE_INNER (mode), ops[1], arr); | 5658 constant_to_array (GET_MODE_INNER (mode), ops[1], arr); |
5844 emit_move_insn (ops[0], array_to_constant (mode, arr)); | 5659 emit_move_insn (ops[0], array_to_constant (mode, arr)); |
5850 if (GET_CODE (ops[1]) != REG | 5665 if (GET_CODE (ops[1]) != REG |
5851 && GET_CODE (ops[1]) != SUBREG) | 5666 && GET_CODE (ops[1]) != SUBREG) |
5852 ops[1] = force_reg (GET_MODE_INNER (mode), ops[1]); | 5667 ops[1] = force_reg (GET_MODE_INNER (mode), ops[1]); |
5853 switch (mode) | 5668 switch (mode) |
5854 { | 5669 { |
5855 case V2DImode: | 5670 case E_V2DImode: |
5856 case V2DFmode: | 5671 case E_V2DFmode: |
5857 shuf = | 5672 shuf = |
5858 immed_double_const (0x0001020304050607ll, 0x1011121314151617ll, | 5673 immed_double_const (0x0001020304050607ll, 0x1011121314151617ll, |
5859 TImode); | 5674 TImode); |
5860 break; | 5675 break; |
5861 case V4SImode: | 5676 case E_V4SImode: |
5862 case V4SFmode: | 5677 case E_V4SFmode: |
5863 shuf = | 5678 shuf = |
5864 immed_double_const (0x0001020300010203ll, 0x0001020300010203ll, | 5679 immed_double_const (0x0001020300010203ll, 0x0001020300010203ll, |
5865 TImode); | 5680 TImode); |
5866 break; | 5681 break; |
5867 case V8HImode: | 5682 case E_V8HImode: |
5868 shuf = | 5683 shuf = |
5869 immed_double_const (0x0203020302030203ll, 0x0203020302030203ll, | 5684 immed_double_const (0x0203020302030203ll, 0x0203020302030203ll, |
5870 TImode); | 5685 TImode); |
5871 break; | 5686 break; |
5872 case V16QImode: | 5687 case E_V16QImode: |
5873 shuf = | 5688 shuf = |
5874 immed_double_const (0x0303030303030303ll, 0x0303030303030303ll, | 5689 immed_double_const (0x0303030303030303ll, 0x0303030303030303ll, |
5875 TImode); | 5690 TImode); |
5876 break; | 5691 break; |
5877 default: | 5692 default: |
5883 } | 5698 } |
5884 | 5699 |
5885 void | 5700 void |
5886 spu_builtin_extract (rtx ops[]) | 5701 spu_builtin_extract (rtx ops[]) |
5887 { | 5702 { |
5888 enum machine_mode mode; | 5703 machine_mode mode; |
5889 rtx rot, from, tmp; | 5704 rtx rot, from, tmp; |
5890 | 5705 |
5891 mode = GET_MODE (ops[1]); | 5706 mode = GET_MODE (ops[1]); |
5892 | 5707 |
5893 if (GET_CODE (ops[2]) == CONST_INT) | 5708 if (GET_CODE (ops[2]) == CONST_INT) |
5894 { | 5709 { |
5895 switch (mode) | 5710 switch (mode) |
5896 { | 5711 { |
5897 case V16QImode: | 5712 case E_V16QImode: |
5898 emit_insn (gen_vec_extractv16qi (ops[0], ops[1], ops[2])); | 5713 emit_insn (gen_vec_extractv16qiqi (ops[0], ops[1], ops[2])); |
5899 break; | 5714 break; |
5900 case V8HImode: | 5715 case E_V8HImode: |
5901 emit_insn (gen_vec_extractv8hi (ops[0], ops[1], ops[2])); | 5716 emit_insn (gen_vec_extractv8hihi (ops[0], ops[1], ops[2])); |
5902 break; | 5717 break; |
5903 case V4SFmode: | 5718 case E_V4SFmode: |
5904 emit_insn (gen_vec_extractv4sf (ops[0], ops[1], ops[2])); | 5719 emit_insn (gen_vec_extractv4sfsf (ops[0], ops[1], ops[2])); |
5905 break; | 5720 break; |
5906 case V4SImode: | 5721 case E_V4SImode: |
5907 emit_insn (gen_vec_extractv4si (ops[0], ops[1], ops[2])); | 5722 emit_insn (gen_vec_extractv4sisi (ops[0], ops[1], ops[2])); |
5908 break; | 5723 break; |
5909 case V2DImode: | 5724 case E_V2DImode: |
5910 emit_insn (gen_vec_extractv2di (ops[0], ops[1], ops[2])); | 5725 emit_insn (gen_vec_extractv2didi (ops[0], ops[1], ops[2])); |
5911 break; | 5726 break; |
5912 case V2DFmode: | 5727 case E_V2DFmode: |
5913 emit_insn (gen_vec_extractv2df (ops[0], ops[1], ops[2])); | 5728 emit_insn (gen_vec_extractv2dfdf (ops[0], ops[1], ops[2])); |
5914 break; | 5729 break; |
5915 default: | 5730 default: |
5916 abort (); | 5731 abort (); |
5917 } | 5732 } |
5918 return; | 5733 return; |
5922 rot = gen_reg_rtx (TImode); | 5737 rot = gen_reg_rtx (TImode); |
5923 tmp = gen_reg_rtx (SImode); | 5738 tmp = gen_reg_rtx (SImode); |
5924 | 5739 |
5925 switch (mode) | 5740 switch (mode) |
5926 { | 5741 { |
5927 case V16QImode: | 5742 case E_V16QImode: |
5928 emit_insn (gen_addsi3 (tmp, ops[2], GEN_INT (-3))); | 5743 emit_insn (gen_addsi3 (tmp, ops[2], GEN_INT (-3))); |
5929 break; | 5744 break; |
5930 case V8HImode: | 5745 case E_V8HImode: |
5931 emit_insn (gen_addsi3 (tmp, ops[2], ops[2])); | 5746 emit_insn (gen_addsi3 (tmp, ops[2], ops[2])); |
5932 emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (-2))); | 5747 emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (-2))); |
5933 break; | 5748 break; |
5934 case V4SFmode: | 5749 case E_V4SFmode: |
5935 case V4SImode: | 5750 case E_V4SImode: |
5936 emit_insn (gen_ashlsi3 (tmp, ops[2], GEN_INT (2))); | 5751 emit_insn (gen_ashlsi3 (tmp, ops[2], GEN_INT (2))); |
5937 break; | 5752 break; |
5938 case V2DImode: | 5753 case E_V2DImode: |
5939 case V2DFmode: | 5754 case E_V2DFmode: |
5940 emit_insn (gen_ashlsi3 (tmp, ops[2], GEN_INT (3))); | 5755 emit_insn (gen_ashlsi3 (tmp, ops[2], GEN_INT (3))); |
5941 break; | 5756 break; |
5942 default: | 5757 default: |
5943 abort (); | 5758 abort (); |
5944 } | 5759 } |
5948 } | 5763 } |
5949 | 5764 |
5950 void | 5765 void |
5951 spu_builtin_insert (rtx ops[]) | 5766 spu_builtin_insert (rtx ops[]) |
5952 { | 5767 { |
5953 enum machine_mode mode = GET_MODE (ops[0]); | 5768 machine_mode mode = GET_MODE (ops[0]); |
5954 enum machine_mode imode = GET_MODE_INNER (mode); | 5769 machine_mode imode = GET_MODE_INNER (mode); |
5955 rtx mask = gen_reg_rtx (TImode); | 5770 rtx mask = gen_reg_rtx (TImode); |
5956 rtx offset; | 5771 rtx offset; |
5957 | 5772 |
5958 if (GET_CODE (ops[3]) == CONST_INT) | 5773 if (GET_CODE (ops[3]) == CONST_INT) |
5959 offset = GEN_INT (INTVAL (ops[3]) * GET_MODE_SIZE (imode)); | 5774 offset = GEN_INT (INTVAL (ops[3]) * GET_MODE_SIZE (imode)); |
5970 } | 5785 } |
5971 | 5786 |
5972 void | 5787 void |
5973 spu_builtin_promote (rtx ops[]) | 5788 spu_builtin_promote (rtx ops[]) |
5974 { | 5789 { |
5975 enum machine_mode mode, imode; | 5790 machine_mode mode, imode; |
5976 rtx rot, from, offset; | 5791 rtx rot, from, offset; |
5977 HOST_WIDE_INT pos; | 5792 HOST_WIDE_INT pos; |
5978 | 5793 |
5979 mode = GET_MODE (ops[0]); | 5794 mode = GET_MODE (ops[0]); |
5980 imode = GET_MODE_INNER (mode); | 5795 imode = GET_MODE_INNER (mode); |
5994 else | 5809 else |
5995 { | 5810 { |
5996 offset = gen_reg_rtx (SImode); | 5811 offset = gen_reg_rtx (SImode); |
5997 switch (mode) | 5812 switch (mode) |
5998 { | 5813 { |
5999 case V16QImode: | 5814 case E_V16QImode: |
6000 emit_insn (gen_subsi3 (offset, GEN_INT (3), ops[2])); | 5815 emit_insn (gen_subsi3 (offset, GEN_INT (3), ops[2])); |
6001 break; | 5816 break; |
6002 case V8HImode: | 5817 case E_V8HImode: |
6003 emit_insn (gen_subsi3 (offset, GEN_INT (1), ops[2])); | 5818 emit_insn (gen_subsi3 (offset, GEN_INT (1), ops[2])); |
6004 emit_insn (gen_addsi3 (offset, offset, offset)); | 5819 emit_insn (gen_addsi3 (offset, offset, offset)); |
6005 break; | 5820 break; |
6006 case V4SFmode: | 5821 case E_V4SFmode: |
6007 case V4SImode: | 5822 case E_V4SImode: |
6008 emit_insn (gen_subsi3 (offset, GEN_INT (0), ops[2])); | 5823 emit_insn (gen_subsi3 (offset, GEN_INT (0), ops[2])); |
6009 emit_insn (gen_ashlsi3 (offset, offset, GEN_INT (2))); | 5824 emit_insn (gen_ashlsi3 (offset, offset, GEN_INT (2))); |
6010 break; | 5825 break; |
6011 case V2DImode: | 5826 case E_V2DImode: |
6012 case V2DFmode: | 5827 case E_V2DFmode: |
6013 emit_insn (gen_ashlsi3 (offset, ops[2], GEN_INT (3))); | 5828 emit_insn (gen_ashlsi3 (offset, ops[2], GEN_INT (3))); |
6014 break; | 5829 break; |
6015 default: | 5830 default: |
6016 abort (); | 5831 abort (); |
6017 } | 5832 } |
6093 emit_move_insn (mem, insn); | 5908 emit_move_insn (mem, insn); |
6094 } | 5909 } |
6095 emit_insn (gen_sync ()); | 5910 emit_insn (gen_sync ()); |
6096 } | 5911 } |
6097 | 5912 |
5913 static bool | |
5914 spu_warn_func_return (tree decl) | |
5915 { | |
5916 /* Naked functions are implemented entirely in assembly, including the | |
5917 return sequence, so suppress warnings about this. */ | |
5918 return !spu_naked_function_p (decl); | |
5919 } | |
5920 | |
6098 void | 5921 void |
6099 spu_expand_sign_extend (rtx ops[]) | 5922 spu_expand_sign_extend (rtx ops[]) |
6100 { | 5923 { |
6101 unsigned char arr[16]; | 5924 unsigned char arr[16]; |
6102 rtx pat = gen_reg_rtx (TImode); | 5925 rtx pat = gen_reg_rtx (TImode); |
6115 { | 5938 { |
6116 for (i = 0; i < 16; i++) | 5939 for (i = 0; i < 16; i++) |
6117 arr[i] = 0x10; | 5940 arr[i] = 0x10; |
6118 switch (GET_MODE (ops[1])) | 5941 switch (GET_MODE (ops[1])) |
6119 { | 5942 { |
6120 case HImode: | 5943 case E_HImode: |
6121 sign = gen_reg_rtx (SImode); | 5944 sign = gen_reg_rtx (SImode); |
6122 emit_insn (gen_extendhisi2 (sign, ops[1])); | 5945 emit_insn (gen_extendhisi2 (sign, ops[1])); |
6123 arr[last] = 0x03; | 5946 arr[last] = 0x03; |
6124 arr[last - 1] = 0x02; | 5947 arr[last - 1] = 0x02; |
6125 break; | 5948 break; |
6126 case SImode: | 5949 case E_SImode: |
6127 sign = gen_reg_rtx (SImode); | 5950 sign = gen_reg_rtx (SImode); |
6128 emit_insn (gen_ashrsi3 (sign, ops[1], GEN_INT (31))); | 5951 emit_insn (gen_ashrsi3 (sign, ops[1], GEN_INT (31))); |
6129 for (i = 0; i < 4; i++) | 5952 for (i = 0; i < 4; i++) |
6130 arr[last - i] = 3 - i; | 5953 arr[last - i] = 3 - i; |
6131 break; | 5954 break; |
6132 case DImode: | 5955 case E_DImode: |
6133 sign = gen_reg_rtx (SImode); | 5956 sign = gen_reg_rtx (SImode); |
6134 c = gen_reg_rtx (SImode); | 5957 c = gen_reg_rtx (SImode); |
6135 emit_insn (gen_spu_convert (c, ops[1])); | 5958 emit_insn (gen_spu_convert (c, ops[1])); |
6136 emit_insn (gen_ashrsi3 (sign, c, GEN_INT (31))); | 5959 emit_insn (gen_ashrsi3 (sign, c, GEN_INT (31))); |
6137 for (i = 0; i < 8; i++) | 5960 for (i = 0; i < 8; i++) |
6148 /* expand vector initialization. If there are any constant parts, | 5971 /* expand vector initialization. If there are any constant parts, |
6149 load constant parts first. Then load any non-constant parts. */ | 5972 load constant parts first. Then load any non-constant parts. */ |
6150 void | 5973 void |
6151 spu_expand_vector_init (rtx target, rtx vals) | 5974 spu_expand_vector_init (rtx target, rtx vals) |
6152 { | 5975 { |
6153 enum machine_mode mode = GET_MODE (target); | 5976 machine_mode mode = GET_MODE (target); |
6154 int n_elts = GET_MODE_NUNITS (mode); | 5977 int n_elts = GET_MODE_NUNITS (mode); |
6155 int n_var = 0; | 5978 int n_var = 0; |
6156 bool all_same = true; | 5979 bool all_same = true; |
6157 rtx first, x = NULL_RTX, first_constant = NULL_RTX; | 5980 rtx first, x = NULL_RTX, first_constant = NULL_RTX; |
6158 int i; | 5981 int i; |
6239 /* Return insn index for the vector compare instruction for given CODE, | 6062 /* Return insn index for the vector compare instruction for given CODE, |
6240 and DEST_MODE, OP_MODE. Return -1 if valid insn is not available. */ | 6063 and DEST_MODE, OP_MODE. Return -1 if valid insn is not available. */ |
6241 | 6064 |
6242 static int | 6065 static int |
6243 get_vec_cmp_insn (enum rtx_code code, | 6066 get_vec_cmp_insn (enum rtx_code code, |
6244 enum machine_mode dest_mode, | 6067 machine_mode dest_mode, |
6245 enum machine_mode op_mode) | 6068 machine_mode op_mode) |
6246 | 6069 |
6247 { | 6070 { |
6248 switch (code) | 6071 switch (code) |
6249 { | 6072 { |
6250 case EQ: | 6073 case EQ: |
6289 DMODE is expected destination mode. This is a recursive function. */ | 6112 DMODE is expected destination mode. This is a recursive function. */ |
6290 | 6113 |
6291 static rtx | 6114 static rtx |
6292 spu_emit_vector_compare (enum rtx_code rcode, | 6115 spu_emit_vector_compare (enum rtx_code rcode, |
6293 rtx op0, rtx op1, | 6116 rtx op0, rtx op1, |
6294 enum machine_mode dmode) | 6117 machine_mode dmode) |
6295 { | 6118 { |
6296 int vec_cmp_insn; | 6119 int vec_cmp_insn; |
6297 rtx mask; | 6120 rtx mask; |
6298 enum machine_mode dest_mode; | 6121 machine_mode dest_mode; |
6299 enum machine_mode op_mode = GET_MODE (op1); | 6122 machine_mode op_mode = GET_MODE (op1); |
6300 | 6123 |
6301 gcc_assert (GET_MODE (op0) == GET_MODE (op1)); | 6124 gcc_assert (GET_MODE (op0) == GET_MODE (op1)); |
6302 | 6125 |
6303 /* Floating point vector compare instructions uses destination V4SImode. | 6126 /* Floating point vector compare instructions uses destination V4SImode. |
6304 Double floating point vector compare instructions uses destination V2DImode. | 6127 Double floating point vector compare instructions uses destination V2DImode. |
6328 rcode = GTU; | 6151 rcode = GTU; |
6329 swap_operands = true; | 6152 swap_operands = true; |
6330 try_again = true; | 6153 try_again = true; |
6331 break; | 6154 break; |
6332 case NE: | 6155 case NE: |
6156 case UNEQ: | |
6157 case UNLE: | |
6158 case UNLT: | |
6159 case UNGE: | |
6160 case UNGT: | |
6161 case UNORDERED: | |
6333 /* Treat A != B as ~(A==B). */ | 6162 /* Treat A != B as ~(A==B). */ |
6334 { | 6163 { |
6164 enum rtx_code rev_code; | |
6335 enum insn_code nor_code; | 6165 enum insn_code nor_code; |
6336 rtx eq_rtx = spu_emit_vector_compare (EQ, op0, op1, dest_mode); | 6166 rtx rev_mask; |
6167 | |
6168 rev_code = reverse_condition_maybe_unordered (rcode); | |
6169 rev_mask = spu_emit_vector_compare (rev_code, op0, op1, dest_mode); | |
6170 | |
6337 nor_code = optab_handler (one_cmpl_optab, dest_mode); | 6171 nor_code = optab_handler (one_cmpl_optab, dest_mode); |
6338 gcc_assert (nor_code != CODE_FOR_nothing); | 6172 gcc_assert (nor_code != CODE_FOR_nothing); |
6339 emit_insn (GEN_FCN (nor_code) (mask, eq_rtx)); | 6173 emit_insn (GEN_FCN (nor_code) (mask, rev_mask)); |
6340 if (dmode != dest_mode) | 6174 if (dmode != dest_mode) |
6341 { | 6175 { |
6342 rtx temp = gen_reg_rtx (dest_mode); | 6176 rtx temp = gen_reg_rtx (dest_mode); |
6343 convert_move (temp, mask, 0); | 6177 convert_move (temp, mask, 0); |
6344 return temp; | 6178 return temp; |
6379 return temp; | 6213 return temp; |
6380 } | 6214 } |
6381 return mask; | 6215 return mask; |
6382 } | 6216 } |
6383 break; | 6217 break; |
6218 case LTGT: | |
6219 /* Try LT OR GT */ | |
6220 { | |
6221 rtx lt_rtx, gt_rtx; | |
6222 enum insn_code ior_code; | |
6223 | |
6224 lt_rtx = spu_emit_vector_compare (LT, op0, op1, dest_mode); | |
6225 gt_rtx = spu_emit_vector_compare (GT, op0, op1, dest_mode); | |
6226 | |
6227 ior_code = optab_handler (ior_optab, dest_mode); | |
6228 gcc_assert (ior_code != CODE_FOR_nothing); | |
6229 emit_insn (GEN_FCN (ior_code) (mask, lt_rtx, gt_rtx)); | |
6230 if (dmode != dest_mode) | |
6231 { | |
6232 rtx temp = gen_reg_rtx (dest_mode); | |
6233 convert_move (temp, mask, 0); | |
6234 return temp; | |
6235 } | |
6236 return mask; | |
6237 } | |
6238 break; | |
6239 case ORDERED: | |
6240 /* Implement as (A==A) & (B==B) */ | |
6241 { | |
6242 rtx a_rtx, b_rtx; | |
6243 enum insn_code and_code; | |
6244 | |
6245 a_rtx = spu_emit_vector_compare (EQ, op0, op0, dest_mode); | |
6246 b_rtx = spu_emit_vector_compare (EQ, op1, op1, dest_mode); | |
6247 | |
6248 and_code = optab_handler (and_optab, dest_mode); | |
6249 gcc_assert (and_code != CODE_FOR_nothing); | |
6250 emit_insn (GEN_FCN (and_code) (mask, a_rtx, b_rtx)); | |
6251 if (dmode != dest_mode) | |
6252 { | |
6253 rtx temp = gen_reg_rtx (dest_mode); | |
6254 convert_move (temp, mask, 0); | |
6255 return temp; | |
6256 } | |
6257 return mask; | |
6258 } | |
6259 break; | |
6384 default: | 6260 default: |
6385 gcc_unreachable (); | 6261 gcc_unreachable (); |
6386 } | 6262 } |
6387 | 6263 |
6388 /* You only get two chances. */ | 6264 /* You only get two chances. */ |
6417 | 6293 |
6418 int | 6294 int |
6419 spu_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2, | 6295 spu_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2, |
6420 rtx cond, rtx cc_op0, rtx cc_op1) | 6296 rtx cond, rtx cc_op0, rtx cc_op1) |
6421 { | 6297 { |
6422 enum machine_mode dest_mode = GET_MODE (dest); | 6298 machine_mode dest_mode = GET_MODE (dest); |
6423 enum rtx_code rcode = GET_CODE (cond); | 6299 enum rtx_code rcode = GET_CODE (cond); |
6424 rtx mask; | 6300 rtx mask; |
6425 | 6301 |
6426 /* Get the vector mask for the given relational operations. */ | 6302 /* Get the vector mask for the given relational operations. */ |
6427 mask = spu_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode); | 6303 mask = spu_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode); |
6430 | 6306 |
6431 return 1; | 6307 return 1; |
6432 } | 6308 } |
6433 | 6309 |
6434 static rtx | 6310 static rtx |
6435 spu_force_reg (enum machine_mode mode, rtx op) | 6311 spu_force_reg (machine_mode mode, rtx op) |
6436 { | 6312 { |
6437 rtx x, r; | 6313 rtx x, r; |
6438 if (GET_MODE (op) == VOIDmode || GET_MODE (op) == BLKmode) | 6314 if (GET_MODE (op) == VOIDmode || GET_MODE (op) == BLKmode) |
6439 { | 6315 { |
6440 if ((SCALAR_INT_MODE_P (mode) && GET_CODE (op) == CONST_INT) | 6316 if ((SCALAR_INT_MODE_P (mode) && GET_CODE (op) == CONST_INT) |
6540 if (arg == 0) | 6416 if (arg == 0) |
6541 abort (); | 6417 abort (); |
6542 ops[i] = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL); | 6418 ops[i] = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL); |
6543 } | 6419 } |
6544 | 6420 |
6545 /* The insn pattern may have additional operands (SCRATCH). | 6421 gcc_assert (i == insn_data[icode].n_generator_args); |
6546 Return the number of actual non-SCRATCH operands. */ | |
6547 gcc_assert (i <= insn_data[icode].n_operands); | |
6548 return i; | 6422 return i; |
6549 } | 6423 } |
6550 | 6424 |
6551 static rtx | 6425 static rtx |
6552 spu_expand_builtin_1 (struct spu_builtin_description *d, | 6426 spu_expand_builtin_1 (struct spu_builtin_description *d, |
6553 tree exp, rtx target) | 6427 tree exp, rtx target) |
6554 { | 6428 { |
6555 rtx pat; | 6429 rtx pat; |
6556 rtx ops[8]; | 6430 rtx ops[8]; |
6557 enum insn_code icode = (enum insn_code) d->icode; | 6431 enum insn_code icode = (enum insn_code) d->icode; |
6558 enum machine_mode mode, tmode; | 6432 machine_mode mode, tmode; |
6559 int i, p; | 6433 int i, p; |
6560 int n_operands; | 6434 int n_operands; |
6561 tree return_type; | 6435 tree return_type; |
6562 | 6436 |
6563 /* Set up ops[] with values from arglist. */ | 6437 /* Set up ops[] with values from arglist. */ |
6588 i++; | 6462 i++; |
6589 } | 6463 } |
6590 | 6464 |
6591 if (d->fcode == SPU_MASK_FOR_LOAD) | 6465 if (d->fcode == SPU_MASK_FOR_LOAD) |
6592 { | 6466 { |
6593 enum machine_mode mode = insn_data[icode].operand[1].mode; | 6467 machine_mode mode = insn_data[icode].operand[1].mode; |
6594 tree arg; | 6468 tree arg; |
6595 rtx addr, op, pat; | 6469 rtx addr, op, pat; |
6596 | 6470 |
6597 /* get addr */ | 6471 /* get addr */ |
6598 arg = CALL_EXPR_ARG (exp, 0); | 6472 arg = CALL_EXPR_ARG (exp, 0); |
6600 op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL); | 6474 op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL); |
6601 addr = memory_address (mode, op); | 6475 addr = memory_address (mode, op); |
6602 | 6476 |
6603 /* negate addr */ | 6477 /* negate addr */ |
6604 op = gen_reg_rtx (GET_MODE (addr)); | 6478 op = gen_reg_rtx (GET_MODE (addr)); |
6605 emit_insn (gen_rtx_SET (VOIDmode, op, | 6479 emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr))); |
6606 gen_rtx_NEG (GET_MODE (addr), addr))); | |
6607 op = gen_rtx_MEM (mode, op); | 6480 op = gen_rtx_MEM (mode, op); |
6608 | 6481 |
6609 pat = GEN_FCN (icode) (target, op); | 6482 pat = GEN_FCN (icode) (target, op); |
6610 if (!pat) | 6483 if (!pat) |
6611 return 0; | 6484 return 0; |
6639 if (GET_CODE (ops[i]) == CONST_INT) | 6512 if (GET_CODE (ops[i]) == CONST_INT) |
6640 ops[i] = spu_const (mode, INTVAL (ops[i])); | 6513 ops[i] = spu_const (mode, INTVAL (ops[i])); |
6641 else | 6514 else |
6642 { | 6515 { |
6643 rtx reg = gen_reg_rtx (mode); | 6516 rtx reg = gen_reg_rtx (mode); |
6644 enum machine_mode imode = GET_MODE_INNER (mode); | 6517 machine_mode imode = GET_MODE_INNER (mode); |
6645 if (!spu_nonmem_operand (ops[i], GET_MODE (ops[i]))) | 6518 if (!spu_nonmem_operand (ops[i], GET_MODE (ops[i]))) |
6646 ops[i] = force_reg (GET_MODE (ops[i]), ops[i]); | 6519 ops[i] = force_reg (GET_MODE (ops[i]), ops[i]); |
6647 if (imode != GET_MODE (ops[i])) | 6520 if (imode != GET_MODE (ops[i])) |
6648 ops[i] = convert_to_mode (imode, ops[i], | 6521 ops[i] = convert_to_mode (imode, ops[i], |
6649 TYPE_UNSIGNED (spu_builtin_types | 6522 TYPE_UNSIGNED (spu_builtin_types |
6713 | 6586 |
6714 rtx | 6587 rtx |
6715 spu_expand_builtin (tree exp, | 6588 spu_expand_builtin (tree exp, |
6716 rtx target, | 6589 rtx target, |
6717 rtx subtarget ATTRIBUTE_UNUSED, | 6590 rtx subtarget ATTRIBUTE_UNUSED, |
6718 enum machine_mode mode ATTRIBUTE_UNUSED, | 6591 machine_mode mode ATTRIBUTE_UNUSED, |
6719 int ignore ATTRIBUTE_UNUSED) | 6592 int ignore ATTRIBUTE_UNUSED) |
6720 { | 6593 { |
6721 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); | 6594 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); |
6722 unsigned int fcode = DECL_FUNCTION_CODE (fndecl); | 6595 unsigned int fcode = DECL_FUNCTION_CODE (fndecl); |
6723 struct spu_builtin_description *d; | 6596 struct spu_builtin_description *d; |
6729 return spu_expand_builtin_1 (d, exp, target); | 6602 return spu_expand_builtin_1 (d, exp, target); |
6730 } | 6603 } |
6731 abort (); | 6604 abort (); |
6732 } | 6605 } |
6733 | 6606 |
6734 /* Implement targetm.vectorize.builtin_mul_widen_even. */ | |
6735 static tree | |
6736 spu_builtin_mul_widen_even (tree type) | |
6737 { | |
6738 switch (TYPE_MODE (type)) | |
6739 { | |
6740 case V8HImode: | |
6741 if (TYPE_UNSIGNED (type)) | |
6742 return spu_builtin_decls[SPU_MULE_0]; | |
6743 else | |
6744 return spu_builtin_decls[SPU_MULE_1]; | |
6745 break; | |
6746 default: | |
6747 return NULL_TREE; | |
6748 } | |
6749 } | |
6750 | |
6751 /* Implement targetm.vectorize.builtin_mul_widen_odd. */ | |
6752 static tree | |
6753 spu_builtin_mul_widen_odd (tree type) | |
6754 { | |
6755 switch (TYPE_MODE (type)) | |
6756 { | |
6757 case V8HImode: | |
6758 if (TYPE_UNSIGNED (type)) | |
6759 return spu_builtin_decls[SPU_MULO_1]; | |
6760 else | |
6761 return spu_builtin_decls[SPU_MULO_0]; | |
6762 break; | |
6763 default: | |
6764 return NULL_TREE; | |
6765 } | |
6766 } | |
6767 | |
6768 /* Implement targetm.vectorize.builtin_mask_for_load. */ | 6607 /* Implement targetm.vectorize.builtin_mask_for_load. */ |
6769 static tree | 6608 static tree |
6770 spu_builtin_mask_for_load (void) | 6609 spu_builtin_mask_for_load (void) |
6771 { | 6610 { |
6772 return spu_builtin_decls[SPU_MASK_FOR_LOAD]; | 6611 return spu_builtin_decls[SPU_MASK_FOR_LOAD]; |
6773 } | 6612 } |
6774 | 6613 |
6775 /* Implement targetm.vectorize.builtin_vectorization_cost. */ | 6614 /* Implement targetm.vectorize.builtin_vectorization_cost. */ |
6776 static int | 6615 static int |
6777 spu_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, | 6616 spu_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, |
6778 tree vectype ATTRIBUTE_UNUSED, | 6617 tree vectype, |
6779 int misalign ATTRIBUTE_UNUSED) | 6618 int misalign ATTRIBUTE_UNUSED) |
6780 { | 6619 { |
6620 unsigned elements; | |
6621 | |
6781 switch (type_of_cost) | 6622 switch (type_of_cost) |
6782 { | 6623 { |
6783 case scalar_stmt: | 6624 case scalar_stmt: |
6784 case vector_stmt: | 6625 case vector_stmt: |
6785 case vector_load: | 6626 case vector_load: |
6786 case vector_store: | 6627 case vector_store: |
6787 case vec_to_scalar: | 6628 case vec_to_scalar: |
6788 case scalar_to_vec: | 6629 case scalar_to_vec: |
6789 case cond_branch_not_taken: | 6630 case cond_branch_not_taken: |
6790 case vec_perm: | 6631 case vec_perm: |
6632 case vec_promote_demote: | |
6791 return 1; | 6633 return 1; |
6792 | 6634 |
6793 case scalar_store: | 6635 case scalar_store: |
6794 return 10; | 6636 return 10; |
6795 | 6637 |
6796 case scalar_load: | 6638 case scalar_load: |
6797 /* Load + rotate. */ | 6639 /* Load + rotate. */ |
6798 return 2; | 6640 return 2; |
6799 | 6641 |
6800 case unaligned_load: | 6642 case unaligned_load: |
6643 case vector_gather_load: | |
6644 case vector_scatter_store: | |
6801 return 2; | 6645 return 2; |
6802 | 6646 |
6803 case cond_branch_taken: | 6647 case cond_branch_taken: |
6804 return 6; | 6648 return 6; |
6805 | 6649 |
6650 case vec_construct: | |
6651 elements = TYPE_VECTOR_SUBPARTS (vectype); | |
6652 return elements / 2 + 1; | |
6653 | |
6806 default: | 6654 default: |
6807 gcc_unreachable (); | 6655 gcc_unreachable (); |
6808 } | 6656 } |
6657 } | |
6658 | |
6659 /* Implement targetm.vectorize.init_cost. */ | |
6660 | |
6661 static void * | |
6662 spu_init_cost (struct loop *loop_info ATTRIBUTE_UNUSED) | |
6663 { | |
6664 unsigned *cost = XNEWVEC (unsigned, 3); | |
6665 cost[vect_prologue] = cost[vect_body] = cost[vect_epilogue] = 0; | |
6666 return cost; | |
6667 } | |
6668 | |
6669 /* Implement targetm.vectorize.add_stmt_cost. */ | |
6670 | |
6671 static unsigned | |
6672 spu_add_stmt_cost (void *data, int count, enum vect_cost_for_stmt kind, | |
6673 struct _stmt_vec_info *stmt_info, int misalign, | |
6674 enum vect_cost_model_location where) | |
6675 { | |
6676 unsigned *cost = (unsigned *) data; | |
6677 unsigned retval = 0; | |
6678 | |
6679 if (flag_vect_cost_model) | |
6680 { | |
6681 tree vectype = stmt_info ? stmt_vectype (stmt_info) : NULL_TREE; | |
6682 int stmt_cost = spu_builtin_vectorization_cost (kind, vectype, misalign); | |
6683 | |
6684 /* Statements in an inner loop relative to the loop being | |
6685 vectorized are weighted more heavily. The value here is | |
6686 arbitrary and could potentially be improved with analysis. */ | |
6687 if (where == vect_body && stmt_info && stmt_in_inner_loop_p (stmt_info)) | |
6688 count *= 50; /* FIXME. */ | |
6689 | |
6690 retval = (unsigned) (count * stmt_cost); | |
6691 cost[where] += retval; | |
6692 } | |
6693 | |
6694 return retval; | |
6695 } | |
6696 | |
6697 /* Implement targetm.vectorize.finish_cost. */ | |
6698 | |
6699 static void | |
6700 spu_finish_cost (void *data, unsigned *prologue_cost, | |
6701 unsigned *body_cost, unsigned *epilogue_cost) | |
6702 { | |
6703 unsigned *cost = (unsigned *) data; | |
6704 *prologue_cost = cost[vect_prologue]; | |
6705 *body_cost = cost[vect_body]; | |
6706 *epilogue_cost = cost[vect_epilogue]; | |
6707 } | |
6708 | |
6709 /* Implement targetm.vectorize.destroy_cost_data. */ | |
6710 | |
6711 static void | |
6712 spu_destroy_cost_data (void *data) | |
6713 { | |
6714 free (data); | |
6809 } | 6715 } |
6810 | 6716 |
6811 /* Return true iff, data reference of TYPE can reach vector alignment (16) | 6717 /* Return true iff, data reference of TYPE can reach vector alignment (16) |
6812 after applying N number of iterations. This routine does not determine | 6718 after applying N number of iterations. This routine does not determine |
6813 how may iterations are required to reach desired alignment. */ | 6719 how may iterations are required to reach desired alignment. */ |
6820 | 6726 |
6821 /* All other types are naturally aligned. */ | 6727 /* All other types are naturally aligned. */ |
6822 return true; | 6728 return true; |
6823 } | 6729 } |
6824 | 6730 |
6825 /* Implement targetm.vectorize.builtin_vec_perm. */ | |
6826 tree | |
6827 spu_builtin_vec_perm (tree type, tree *mask_element_type) | |
6828 { | |
6829 *mask_element_type = unsigned_char_type_node; | |
6830 | |
6831 switch (TYPE_MODE (type)) | |
6832 { | |
6833 case V16QImode: | |
6834 if (TYPE_UNSIGNED (type)) | |
6835 return spu_builtin_decls[SPU_SHUFFLE_0]; | |
6836 else | |
6837 return spu_builtin_decls[SPU_SHUFFLE_1]; | |
6838 | |
6839 case V8HImode: | |
6840 if (TYPE_UNSIGNED (type)) | |
6841 return spu_builtin_decls[SPU_SHUFFLE_2]; | |
6842 else | |
6843 return spu_builtin_decls[SPU_SHUFFLE_3]; | |
6844 | |
6845 case V4SImode: | |
6846 if (TYPE_UNSIGNED (type)) | |
6847 return spu_builtin_decls[SPU_SHUFFLE_4]; | |
6848 else | |
6849 return spu_builtin_decls[SPU_SHUFFLE_5]; | |
6850 | |
6851 case V2DImode: | |
6852 if (TYPE_UNSIGNED (type)) | |
6853 return spu_builtin_decls[SPU_SHUFFLE_6]; | |
6854 else | |
6855 return spu_builtin_decls[SPU_SHUFFLE_7]; | |
6856 | |
6857 case V4SFmode: | |
6858 return spu_builtin_decls[SPU_SHUFFLE_8]; | |
6859 | |
6860 case V2DFmode: | |
6861 return spu_builtin_decls[SPU_SHUFFLE_9]; | |
6862 | |
6863 default: | |
6864 return NULL_TREE; | |
6865 } | |
6866 } | |
6867 | |
6868 /* Return the appropriate mode for a named address pointer. */ | 6731 /* Return the appropriate mode for a named address pointer. */ |
6869 static enum machine_mode | 6732 static scalar_int_mode |
6870 spu_addr_space_pointer_mode (addr_space_t addrspace) | 6733 spu_addr_space_pointer_mode (addr_space_t addrspace) |
6871 { | 6734 { |
6872 switch (addrspace) | 6735 switch (addrspace) |
6873 { | 6736 { |
6874 case ADDR_SPACE_GENERIC: | 6737 case ADDR_SPACE_GENERIC: |
6879 gcc_unreachable (); | 6742 gcc_unreachable (); |
6880 } | 6743 } |
6881 } | 6744 } |
6882 | 6745 |
6883 /* Return the appropriate mode for a named address address. */ | 6746 /* Return the appropriate mode for a named address address. */ |
6884 static enum machine_mode | 6747 static scalar_int_mode |
6885 spu_addr_space_address_mode (addr_space_t addrspace) | 6748 spu_addr_space_address_mode (addr_space_t addrspace) |
6886 { | 6749 { |
6887 switch (addrspace) | 6750 switch (addrspace) |
6888 { | 6751 { |
6889 case ADDR_SPACE_GENERIC: | 6752 case ADDR_SPACE_GENERIC: |
6982 int i; | 6845 int i; |
6983 unsigned t[4] = {0, 0, 0, 0}; | 6846 unsigned t[4] = {0, 0, 0, 0}; |
6984 | 6847 |
6985 for (i = 0; i < g->num_nodes; i++) | 6848 for (i = 0; i < g->num_nodes; i++) |
6986 { | 6849 { |
6987 rtx insn = g->nodes[i].insn; | 6850 rtx_insn *insn = g->nodes[i].insn; |
6988 int p = get_pipe (insn) + 2; | 6851 int p = get_pipe (insn) + 2; |
6989 | 6852 |
6990 gcc_assert (p >= 0); | 6853 gcc_assert (p >= 0); |
6991 gcc_assert (p < 4); | 6854 gcc_assert (p < 4); |
6992 | 6855 |
7025 gcc_assert (REGNO (r0) == LAST_VIRTUAL_REGISTER + 1 | 6888 gcc_assert (REGNO (r0) == LAST_VIRTUAL_REGISTER + 1 |
7026 && REGNO (r1) == LAST_VIRTUAL_REGISTER + 2); | 6889 && REGNO (r1) == LAST_VIRTUAL_REGISTER + 2); |
7027 } | 6890 } |
7028 } | 6891 } |
7029 | 6892 |
7030 static enum machine_mode | 6893 static scalar_int_mode |
7031 spu_libgcc_cmp_return_mode (void) | 6894 spu_libgcc_cmp_return_mode (void) |
7032 { | 6895 { |
7033 | 6896 |
7034 /* For SPU word mode is TI mode so it is better to use SImode | 6897 /* For SPU word mode is TI mode so it is better to use SImode |
7035 for compare returns. */ | 6898 for compare returns. */ |
7036 return SImode; | 6899 return SImode; |
7037 } | 6900 } |
7038 | 6901 |
7039 static enum machine_mode | 6902 static scalar_int_mode |
7040 spu_libgcc_shift_count_mode (void) | 6903 spu_libgcc_shift_count_mode (void) |
7041 { | 6904 { |
7042 /* For SPU word mode is TI mode so it is better to use SImode | 6905 /* For SPU word mode is TI mode so it is better to use SImode |
7043 for shift counts. */ | 6906 for shift counts. */ |
7044 return SImode; | 6907 return SImode; |
7045 } | |
7046 | |
7047 /* An early place to adjust some flags after GCC has finished processing | |
7048 * them. */ | |
7049 static void | |
7050 asm_file_start (void) | |
7051 { | |
7052 /* Variable tracking should be run after all optimizations which | |
7053 change order of insns. It also needs a valid CFG. Therefore, | |
7054 *if* we make nontrivial changes in machine-dependent reorg, | |
7055 run variable tracking after those. However, if we do not run | |
7056 our machine-dependent reorg pass, we must still run the normal | |
7057 variable tracking pass (or else we will ICE in final since | |
7058 debug insns have not been removed). */ | |
7059 if (TARGET_BRANCH_HINTS && optimize) | |
7060 { | |
7061 spu_flag_var_tracking = flag_var_tracking; | |
7062 flag_var_tracking = 0; | |
7063 } | |
7064 | |
7065 default_file_start (); | |
7066 } | 6908 } |
7067 | 6909 |
7068 /* Implement targetm.section_type_flags. */ | 6910 /* Implement targetm.section_type_flags. */ |
7069 static unsigned int | 6911 static unsigned int |
7070 spu_section_type_flags (tree decl, const char *name, int reloc) | 6912 spu_section_type_flags (tree decl, const char *name, int reloc) |
7114 | 6956 |
7115 /* Generate a constant or register which contains 2^SCALE. We assume | 6957 /* Generate a constant or register which contains 2^SCALE. We assume |
7116 the result is valid for MODE. Currently, MODE must be V4SFmode and | 6958 the result is valid for MODE. Currently, MODE must be V4SFmode and |
7117 SCALE must be SImode. */ | 6959 SCALE must be SImode. */ |
7118 rtx | 6960 rtx |
7119 spu_gen_exp2 (enum machine_mode mode, rtx scale) | 6961 spu_gen_exp2 (machine_mode mode, rtx scale) |
7120 { | 6962 { |
7121 gcc_assert (mode == V4SFmode); | 6963 gcc_assert (mode == V4SFmode); |
7122 gcc_assert (GET_MODE (scale) == SImode || GET_CODE (scale) == CONST_INT); | 6964 gcc_assert (GET_MODE (scale) == SImode || GET_CODE (scale) == CONST_INT); |
7123 if (GET_CODE (scale) != CONST_INT) | 6965 if (GET_CODE (scale) != CONST_INT) |
7124 { | 6966 { |
7189 return true; | 7031 return true; |
7190 | 7032 |
7191 return default_ref_may_alias_errno (ref); | 7033 return default_ref_may_alias_errno (ref); |
7192 } | 7034 } |
7193 | 7035 |
7036 /* Output thunk to FILE that implements a C++ virtual function call (with | |
7037 multiple inheritance) to FUNCTION. The thunk adjusts the this pointer | |
7038 by DELTA, and unless VCALL_OFFSET is zero, applies an additional adjustment | |
7039 stored at VCALL_OFFSET in the vtable whose address is located at offset 0 | |
7040 relative to the resulting this pointer. */ | |
7041 | |
7042 static void | |
7043 spu_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, | |
7044 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, | |
7045 tree function) | |
7046 { | |
7047 rtx op[8]; | |
7048 | |
7049 /* Make sure unwind info is emitted for the thunk if needed. */ | |
7050 final_start_function (emit_barrier (), file, 1); | |
7051 | |
7052 /* Operand 0 is the target function. */ | |
7053 op[0] = XEXP (DECL_RTL (function), 0); | |
7054 | |
7055 /* Operand 1 is the 'this' pointer. */ | |
7056 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) | |
7057 op[1] = gen_rtx_REG (Pmode, FIRST_ARG_REGNUM + 1); | |
7058 else | |
7059 op[1] = gen_rtx_REG (Pmode, FIRST_ARG_REGNUM); | |
7060 | |
7061 /* Operands 2/3 are the low/high halfwords of delta. */ | |
7062 op[2] = GEN_INT (trunc_int_for_mode (delta, HImode)); | |
7063 op[3] = GEN_INT (trunc_int_for_mode (delta >> 16, HImode)); | |
7064 | |
7065 /* Operands 4/5 are the low/high halfwords of vcall_offset. */ | |
7066 op[4] = GEN_INT (trunc_int_for_mode (vcall_offset, HImode)); | |
7067 op[5] = GEN_INT (trunc_int_for_mode (vcall_offset >> 16, HImode)); | |
7068 | |
7069 /* Operands 6/7 are temporary registers. */ | |
7070 op[6] = gen_rtx_REG (Pmode, 79); | |
7071 op[7] = gen_rtx_REG (Pmode, 78); | |
7072 | |
7073 /* Add DELTA to this pointer. */ | |
7074 if (delta) | |
7075 { | |
7076 if (delta >= -0x200 && delta < 0x200) | |
7077 output_asm_insn ("ai\t%1,%1,%2", op); | |
7078 else if (delta >= -0x8000 && delta < 0x8000) | |
7079 { | |
7080 output_asm_insn ("il\t%6,%2", op); | |
7081 output_asm_insn ("a\t%1,%1,%6", op); | |
7082 } | |
7083 else | |
7084 { | |
7085 output_asm_insn ("ilhu\t%6,%3", op); | |
7086 output_asm_insn ("iohl\t%6,%2", op); | |
7087 output_asm_insn ("a\t%1,%1,%6", op); | |
7088 } | |
7089 } | |
7090 | |
7091 /* Perform vcall adjustment. */ | |
7092 if (vcall_offset) | |
7093 { | |
7094 output_asm_insn ("lqd\t%7,0(%1)", op); | |
7095 output_asm_insn ("rotqby\t%7,%7,%1", op); | |
7096 | |
7097 if (vcall_offset >= -0x200 && vcall_offset < 0x200) | |
7098 output_asm_insn ("ai\t%7,%7,%4", op); | |
7099 else if (vcall_offset >= -0x8000 && vcall_offset < 0x8000) | |
7100 { | |
7101 output_asm_insn ("il\t%6,%4", op); | |
7102 output_asm_insn ("a\t%7,%7,%6", op); | |
7103 } | |
7104 else | |
7105 { | |
7106 output_asm_insn ("ilhu\t%6,%5", op); | |
7107 output_asm_insn ("iohl\t%6,%4", op); | |
7108 output_asm_insn ("a\t%7,%7,%6", op); | |
7109 } | |
7110 | |
7111 output_asm_insn ("lqd\t%6,0(%7)", op); | |
7112 output_asm_insn ("rotqby\t%6,%6,%7", op); | |
7113 output_asm_insn ("a\t%1,%1,%6", op); | |
7114 } | |
7115 | |
7116 /* Jump to target. */ | |
7117 output_asm_insn ("br\t%0", op); | |
7118 | |
7119 final_end_function (); | |
7120 } | |
7121 | |
7122 /* Canonicalize a comparison from one we don't have to one we do have. */ | |
7123 static void | |
7124 spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1, | |
7125 bool op0_preserve_value) | |
7126 { | |
7127 if (!op0_preserve_value | |
7128 && (*code == LE || *code == LT || *code == LEU || *code == LTU)) | |
7129 { | |
7130 rtx tem = *op0; | |
7131 *op0 = *op1; | |
7132 *op1 = tem; | |
7133 *code = (int)swap_condition ((enum rtx_code)*code); | |
7134 } | |
7135 } | |
7136 | |
7137 /* Expand an atomic fetch-and-operate pattern. CODE is the binary operation | |
7138 to perform. MEM is the memory on which to operate. VAL is the second | |
7139 operand of the binary operator. BEFORE and AFTER are optional locations to | |
7140 return the value of MEM either before of after the operation. */ | |
7141 void | |
7142 spu_expand_atomic_op (enum rtx_code code, rtx mem, rtx val, | |
7143 rtx orig_before, rtx orig_after) | |
7144 { | |
7145 machine_mode mode = GET_MODE (mem); | |
7146 rtx before = orig_before, after = orig_after; | |
7147 | |
7148 if (before == NULL_RTX) | |
7149 before = gen_reg_rtx (mode); | |
7150 | |
7151 emit_move_insn (before, mem); | |
7152 | |
7153 if (code == MULT) /* NAND operation */ | |
7154 { | |
7155 rtx x = expand_simple_binop (mode, AND, before, val, | |
7156 NULL_RTX, 1, OPTAB_LIB_WIDEN); | |
7157 after = expand_simple_unop (mode, NOT, x, after, 1); | |
7158 } | |
7159 else | |
7160 { | |
7161 after = expand_simple_binop (mode, code, before, val, | |
7162 after, 1, OPTAB_LIB_WIDEN); | |
7163 } | |
7164 | |
7165 emit_move_insn (mem, after); | |
7166 | |
7167 if (orig_after && after != orig_after) | |
7168 emit_move_insn (orig_after, after); | |
7169 } | |
7170 | |
7171 /* Implement TARGET_MODES_TIEABLE_P. */ | |
7172 | |
7173 static bool | |
7174 spu_modes_tieable_p (machine_mode mode1, machine_mode mode2) | |
7175 { | |
7176 return (GET_MODE_BITSIZE (mode1) <= MAX_FIXED_MODE_SIZE | |
7177 && GET_MODE_BITSIZE (mode2) <= MAX_FIXED_MODE_SIZE); | |
7178 } | |
7179 | |
7180 /* Implement TARGET_CAN_CHANGE_MODE_CLASS. GCC assumes that modes are | |
7181 in the lowpart of a register, which is only true for SPU. */ | |
7182 | |
7183 static bool | |
7184 spu_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t) | |
7185 { | |
7186 return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to) | |
7187 || (GET_MODE_SIZE (from) <= 4 && GET_MODE_SIZE (to) <= 4) | |
7188 || (GET_MODE_SIZE (from) >= 16 && GET_MODE_SIZE (to) >= 16)); | |
7189 } | |
7190 | |
7191 /* Implement TARGET_TRULY_NOOP_TRUNCATION. */ | |
7192 | |
7193 static bool | |
7194 spu_truly_noop_truncation (unsigned int outprec, unsigned int inprec) | |
7195 { | |
7196 return inprec <= 32 && outprec <= inprec; | |
7197 } | |
7198 | |
7199 /* Implement TARGET_STATIC_RTX_ALIGNMENT. | |
7200 | |
7201 Make all static objects 16-byte aligned. This allows us to assume | |
7202 they are also padded to 16 bytes, which means we can use a single | |
7203 load or store instruction to access them. */ | |
7204 | |
7205 static HOST_WIDE_INT | |
7206 spu_static_rtx_alignment (machine_mode mode) | |
7207 { | |
7208 return MAX (GET_MODE_ALIGNMENT (mode), 128); | |
7209 } | |
7210 | |
7211 /* Implement TARGET_CONSTANT_ALIGNMENT. | |
7212 | |
7213 Make all static objects 16-byte aligned. This allows us to assume | |
7214 they are also padded to 16 bytes, which means we can use a single | |
7215 load or store instruction to access them. */ | |
7216 | |
7217 static HOST_WIDE_INT | |
7218 spu_constant_alignment (const_tree, HOST_WIDE_INT align) | |
7219 { | |
7220 return MAX (align, 128); | |
7221 } | |
7222 | |
7223 /* Table of machine attributes. */ | |
7224 static const struct attribute_spec spu_attribute_table[] = | |
7225 { | |
7226 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, | |
7227 affects_type_identity } */ | |
7228 { "naked", 0, 0, true, false, false, spu_handle_fndecl_attribute, | |
7229 false }, | |
7230 { "spu_vector", 0, 0, false, true, false, spu_handle_vector_attribute, | |
7231 false }, | |
7232 { NULL, 0, 0, false, false, false, NULL, false } | |
7233 }; | |
7234 | |
7235 /* TARGET overrides. */ | |
7236 | |
7237 #undef TARGET_LRA_P | |
7238 #define TARGET_LRA_P hook_bool_void_false | |
7239 | |
7240 #undef TARGET_ADDR_SPACE_POINTER_MODE | |
7241 #define TARGET_ADDR_SPACE_POINTER_MODE spu_addr_space_pointer_mode | |
7242 | |
7243 #undef TARGET_ADDR_SPACE_ADDRESS_MODE | |
7244 #define TARGET_ADDR_SPACE_ADDRESS_MODE spu_addr_space_address_mode | |
7245 | |
7246 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P | |
7247 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ | |
7248 spu_addr_space_legitimate_address_p | |
7249 | |
7250 #undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS | |
7251 #define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS spu_addr_space_legitimize_address | |
7252 | |
7253 #undef TARGET_ADDR_SPACE_SUBSET_P | |
7254 #define TARGET_ADDR_SPACE_SUBSET_P spu_addr_space_subset_p | |
7255 | |
7256 #undef TARGET_ADDR_SPACE_CONVERT | |
7257 #define TARGET_ADDR_SPACE_CONVERT spu_addr_space_convert | |
7258 | |
7259 #undef TARGET_INIT_BUILTINS | |
7260 #define TARGET_INIT_BUILTINS spu_init_builtins | |
7261 #undef TARGET_BUILTIN_DECL | |
7262 #define TARGET_BUILTIN_DECL spu_builtin_decl | |
7263 | |
7264 #undef TARGET_EXPAND_BUILTIN | |
7265 #define TARGET_EXPAND_BUILTIN spu_expand_builtin | |
7266 | |
7267 #undef TARGET_UNWIND_WORD_MODE | |
7268 #define TARGET_UNWIND_WORD_MODE spu_unwind_word_mode | |
7269 | |
7270 #undef TARGET_LEGITIMIZE_ADDRESS | |
7271 #define TARGET_LEGITIMIZE_ADDRESS spu_legitimize_address | |
7272 | |
7273 /* The current assembler doesn't like .4byte foo@ppu, so use the normal .long | |
7274 and .quad for the debugger. When it is known that the assembler is fixed, | |
7275 these can be removed. */ | |
7276 #undef TARGET_ASM_UNALIGNED_SI_OP | |
7277 #define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" | |
7278 | |
7279 #undef TARGET_ASM_ALIGNED_DI_OP | |
7280 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" | |
7281 | |
7282 /* The .8byte directive doesn't seem to work well for a 32 bit | |
7283 architecture. */ | |
7284 #undef TARGET_ASM_UNALIGNED_DI_OP | |
7285 #define TARGET_ASM_UNALIGNED_DI_OP NULL | |
7286 | |
7287 #undef TARGET_RTX_COSTS | |
7288 #define TARGET_RTX_COSTS spu_rtx_costs | |
7289 | |
7290 #undef TARGET_ADDRESS_COST | |
7291 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 | |
7292 | |
7293 #undef TARGET_SCHED_ISSUE_RATE | |
7294 #define TARGET_SCHED_ISSUE_RATE spu_sched_issue_rate | |
7295 | |
7296 #undef TARGET_SCHED_INIT_GLOBAL | |
7297 #define TARGET_SCHED_INIT_GLOBAL spu_sched_init_global | |
7298 | |
7299 #undef TARGET_SCHED_INIT | |
7300 #define TARGET_SCHED_INIT spu_sched_init | |
7301 | |
7302 #undef TARGET_SCHED_VARIABLE_ISSUE | |
7303 #define TARGET_SCHED_VARIABLE_ISSUE spu_sched_variable_issue | |
7304 | |
7305 #undef TARGET_SCHED_REORDER | |
7306 #define TARGET_SCHED_REORDER spu_sched_reorder | |
7307 | |
7308 #undef TARGET_SCHED_REORDER2 | |
7309 #define TARGET_SCHED_REORDER2 spu_sched_reorder | |
7310 | |
7311 #undef TARGET_SCHED_ADJUST_COST | |
7312 #define TARGET_SCHED_ADJUST_COST spu_sched_adjust_cost | |
7313 | |
7314 #undef TARGET_ATTRIBUTE_TABLE | |
7315 #define TARGET_ATTRIBUTE_TABLE spu_attribute_table | |
7316 | |
7317 #undef TARGET_ASM_INTEGER | |
7318 #define TARGET_ASM_INTEGER spu_assemble_integer | |
7319 | |
7320 #undef TARGET_SCALAR_MODE_SUPPORTED_P | |
7321 #define TARGET_SCALAR_MODE_SUPPORTED_P spu_scalar_mode_supported_p | |
7322 | |
7323 #undef TARGET_VECTOR_MODE_SUPPORTED_P | |
7324 #define TARGET_VECTOR_MODE_SUPPORTED_P spu_vector_mode_supported_p | |
7325 | |
7326 #undef TARGET_FUNCTION_OK_FOR_SIBCALL | |
7327 #define TARGET_FUNCTION_OK_FOR_SIBCALL spu_function_ok_for_sibcall | |
7328 | |
7329 #undef TARGET_ASM_GLOBALIZE_LABEL | |
7330 #define TARGET_ASM_GLOBALIZE_LABEL spu_asm_globalize_label | |
7331 | |
7332 #undef TARGET_PASS_BY_REFERENCE | |
7333 #define TARGET_PASS_BY_REFERENCE spu_pass_by_reference | |
7334 | |
7335 #undef TARGET_FUNCTION_ARG | |
7336 #define TARGET_FUNCTION_ARG spu_function_arg | |
7337 | |
7338 #undef TARGET_FUNCTION_ARG_ADVANCE | |
7339 #define TARGET_FUNCTION_ARG_ADVANCE spu_function_arg_advance | |
7340 | |
7341 #undef TARGET_FUNCTION_ARG_OFFSET | |
7342 #define TARGET_FUNCTION_ARG_OFFSET spu_function_arg_offset | |
7343 | |
7344 #undef TARGET_FUNCTION_ARG_PADDING | |
7345 #define TARGET_FUNCTION_ARG_PADDING spu_function_arg_padding | |
7346 | |
7347 #undef TARGET_MUST_PASS_IN_STACK | |
7348 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size | |
7349 | |
7350 #undef TARGET_BUILD_BUILTIN_VA_LIST | |
7351 #define TARGET_BUILD_BUILTIN_VA_LIST spu_build_builtin_va_list | |
7352 | |
7353 #undef TARGET_EXPAND_BUILTIN_VA_START | |
7354 #define TARGET_EXPAND_BUILTIN_VA_START spu_va_start | |
7355 | |
7356 #undef TARGET_SETUP_INCOMING_VARARGS | |
7357 #define TARGET_SETUP_INCOMING_VARARGS spu_setup_incoming_varargs | |
7358 | |
7359 #undef TARGET_MACHINE_DEPENDENT_REORG | |
7360 #define TARGET_MACHINE_DEPENDENT_REORG spu_machine_dependent_reorg | |
7361 | |
7362 #undef TARGET_GIMPLIFY_VA_ARG_EXPR | |
7363 #define TARGET_GIMPLIFY_VA_ARG_EXPR spu_gimplify_va_arg_expr | |
7364 | |
7365 #undef TARGET_INIT_LIBFUNCS | |
7366 #define TARGET_INIT_LIBFUNCS spu_init_libfuncs | |
7367 | |
7368 #undef TARGET_RETURN_IN_MEMORY | |
7369 #define TARGET_RETURN_IN_MEMORY spu_return_in_memory | |
7370 | |
7371 #undef TARGET_ENCODE_SECTION_INFO | |
7372 #define TARGET_ENCODE_SECTION_INFO spu_encode_section_info | |
7373 | |
7374 #undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD | |
7375 #define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD spu_builtin_mask_for_load | |
7376 | |
7377 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST | |
7378 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST spu_builtin_vectorization_cost | |
7379 | |
7380 #undef TARGET_VECTORIZE_INIT_COST | |
7381 #define TARGET_VECTORIZE_INIT_COST spu_init_cost | |
7382 | |
7383 #undef TARGET_VECTORIZE_ADD_STMT_COST | |
7384 #define TARGET_VECTORIZE_ADD_STMT_COST spu_add_stmt_cost | |
7385 | |
7386 #undef TARGET_VECTORIZE_FINISH_COST | |
7387 #define TARGET_VECTORIZE_FINISH_COST spu_finish_cost | |
7388 | |
7389 #undef TARGET_VECTORIZE_DESTROY_COST_DATA | |
7390 #define TARGET_VECTORIZE_DESTROY_COST_DATA spu_destroy_cost_data | |
7391 | |
7392 #undef TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE | |
7393 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE spu_vector_alignment_reachable | |
7394 | |
7395 #undef TARGET_LIBGCC_CMP_RETURN_MODE | |
7396 #define TARGET_LIBGCC_CMP_RETURN_MODE spu_libgcc_cmp_return_mode | |
7397 | |
7398 #undef TARGET_LIBGCC_SHIFT_COUNT_MODE | |
7399 #define TARGET_LIBGCC_SHIFT_COUNT_MODE spu_libgcc_shift_count_mode | |
7400 | |
7401 #undef TARGET_SCHED_SMS_RES_MII | |
7402 #define TARGET_SCHED_SMS_RES_MII spu_sms_res_mii | |
7403 | |
7404 #undef TARGET_SECTION_TYPE_FLAGS | |
7405 #define TARGET_SECTION_TYPE_FLAGS spu_section_type_flags | |
7406 | |
7407 #undef TARGET_ASM_SELECT_SECTION | |
7408 #define TARGET_ASM_SELECT_SECTION spu_select_section | |
7409 | |
7410 #undef TARGET_ASM_UNIQUE_SECTION | |
7411 #define TARGET_ASM_UNIQUE_SECTION spu_unique_section | |
7412 | |
7413 #undef TARGET_LEGITIMATE_ADDRESS_P | |
7414 #define TARGET_LEGITIMATE_ADDRESS_P spu_legitimate_address_p | |
7415 | |
7416 #undef TARGET_LEGITIMATE_CONSTANT_P | |
7417 #define TARGET_LEGITIMATE_CONSTANT_P spu_legitimate_constant_p | |
7418 | |
7419 #undef TARGET_TRAMPOLINE_INIT | |
7420 #define TARGET_TRAMPOLINE_INIT spu_trampoline_init | |
7421 | |
7422 #undef TARGET_WARN_FUNC_RETURN | |
7423 #define TARGET_WARN_FUNC_RETURN spu_warn_func_return | |
7424 | |
7425 #undef TARGET_OPTION_OVERRIDE | |
7426 #define TARGET_OPTION_OVERRIDE spu_option_override | |
7427 | |
7428 #undef TARGET_CONDITIONAL_REGISTER_USAGE | |
7429 #define TARGET_CONDITIONAL_REGISTER_USAGE spu_conditional_register_usage | |
7430 | |
7431 #undef TARGET_REF_MAY_ALIAS_ERRNO | |
7432 #define TARGET_REF_MAY_ALIAS_ERRNO spu_ref_may_alias_errno | |
7433 | |
7434 #undef TARGET_ASM_OUTPUT_MI_THUNK | |
7435 #define TARGET_ASM_OUTPUT_MI_THUNK spu_output_mi_thunk | |
7436 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK | |
7437 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true | |
7438 | |
7439 /* Variable tracking should be run after all optimizations which | |
7440 change order of insns. It also needs a valid CFG. */ | |
7441 #undef TARGET_DELAY_VARTRACK | |
7442 #define TARGET_DELAY_VARTRACK true | |
7443 | |
7444 #undef TARGET_CANONICALIZE_COMPARISON | |
7445 #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison | |
7446 | |
7447 #undef TARGET_CAN_USE_DOLOOP_P | |
7448 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost | |
7449 | |
7450 #undef TARGET_MODES_TIEABLE_P | |
7451 #define TARGET_MODES_TIEABLE_P spu_modes_tieable_p | |
7452 | |
7453 #undef TARGET_HARD_REGNO_NREGS | |
7454 #define TARGET_HARD_REGNO_NREGS spu_hard_regno_nregs | |
7455 | |
7456 #undef TARGET_CAN_CHANGE_MODE_CLASS | |
7457 #define TARGET_CAN_CHANGE_MODE_CLASS spu_can_change_mode_class | |
7458 | |
7459 #undef TARGET_TRULY_NOOP_TRUNCATION | |
7460 #define TARGET_TRULY_NOOP_TRUNCATION spu_truly_noop_truncation | |
7461 | |
7462 #undef TARGET_STATIC_RTX_ALIGNMENT | |
7463 #define TARGET_STATIC_RTX_ALIGNMENT spu_static_rtx_alignment | |
7464 #undef TARGET_CONSTANT_ALIGNMENT | |
7465 #define TARGET_CONSTANT_ALIGNMENT spu_constant_alignment | |
7466 | |
7467 struct gcc_target targetm = TARGET_INITIALIZER; | |
7468 | |
7194 #include "gt-spu.h" | 7469 #include "gt-spu.h" |