1 /* Target Code for TI C6X
2 Copyright (C) 2010-2013 Free Software Foundation, Inc.
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "stor-layout.h"
31 #include "stringpool.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
35 #include "insn-codes.h"
41 #include "sched-int.h"
45 #include "tm-constrs.h"
48 #include "diagnostic-core.h"
50 #include "langhooks.h"
52 #include "target-def.h"
53 #include "sel-sched.h"
56 #include "hw-doloop.h"
57 #include "regrename.h"
59 #include "gimple-expr.h"
61 /* Table of supported architecture variants. */
65 enum c6x_cpu_type type
;
66 unsigned short features
;
69 /* A list of all ISAs, mapping each one to a representative device.
70 Used for -march selection. */
71 static const c6x_arch_table all_isas
[] =
73 #define C6X_ISA(NAME,DEVICE,FLAGS) \
74 { NAME, DEVICE, FLAGS },
75 #include "c6x-isas.def"
77 { NULL
, C6X_CPU_C62X
, 0 }
80 /* This is the parsed result of the "-march=" option, if given. */
81 enum c6x_cpu_type c6x_arch
= C6X_DEFAULT_ARCH
;
83 /* A mask of insn types that are allowed by the architecture selected by
85 unsigned long c6x_insn_mask
= C6X_DEFAULT_INSN_MASK
;
87 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
89 static rtx c6x_current_insn
= NULL_RTX
;
91 /* A decl we build to access __c6xabi_DSBT_base. */
92 static GTY(()) tree dsbt_decl
;
94 /* Determines whether we run our final scheduling pass or not. We always
95 avoid the normal second scheduling pass. */
96 static int c6x_flag_schedule_insns2
;
98 /* Determines whether we run variable tracking in machine dependent
100 static int c6x_flag_var_tracking
;
102 /* Determines whether we use modulo scheduling. */
103 static int c6x_flag_modulo_sched
;
105 /* Record the state of flag_pic before we set it to 1 for DSBT. */
106 int c6x_initial_flag_pic
;
110 /* We record the clock cycle for every insn during scheduling. */
112 /* After scheduling, we run assign_reservations to choose unit
113 reservations for all insns. These are recorded here. */
115 /* Records the new condition for insns which must be made
116 conditional after scheduling. An entry of NULL_RTX means no such
117 change is necessary. */
119 /* True for the first insn that was scheduled in an ebb. */
121 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
122 bits rather than storing the state. Meaningful only for the last
124 unsigned int unit_mask
;
125 } c6x_sched_insn_info
;
128 /* Record a c6x_sched_insn_info structure for every insn in the function. */
129 static vec
<c6x_sched_insn_info
> insn_info
;
131 #define INSN_INFO_LENGTH (insn_info).length ()
132 #define INSN_INFO_ENTRY(N) (insn_info[(N)])
134 static bool done_cfi_sections
;
136 #define RESERVATION_FLAG_D 1
137 #define RESERVATION_FLAG_L 2
138 #define RESERVATION_FLAG_S 4
139 #define RESERVATION_FLAG_M 8
140 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
141 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
142 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
143 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
145 /* The DFA names of the units. */
146 static const char *const c6x_unit_names
[] =
148 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
149 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
152 /* The DFA unit number for each unit in c6x_unit_names[]. */
153 static int c6x_unit_codes
[ARRAY_SIZE (c6x_unit_names
)];
155 /* Unit query IDs. */
156 #define UNIT_QID_D1 0
157 #define UNIT_QID_L1 1
158 #define UNIT_QID_S1 2
159 #define UNIT_QID_M1 3
160 #define UNIT_QID_FPS1 4
161 #define UNIT_QID_FPL1 5
162 #define UNIT_QID_ADDDPS1 6
163 #define UNIT_QID_ADDDPL1 7
164 #define UNIT_QID_SIDE_OFFSET 8
166 #define RESERVATION_S1 2
167 #define RESERVATION_S2 10
169 /* An enum for the unit requirements we count in the UNIT_REQS table. */
185 /* A table used to count unit requirements. Used when computing minimum
186 iteration intervals. */
187 typedef int unit_req_table
[2][UNIT_REQ_MAX
];
188 static unit_req_table unit_reqs
;
190 /* Register map for debugging. */
191 unsigned const dbx_register_map
[FIRST_PSEUDO_REGISTER
] =
193 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
194 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
196 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
198 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
200 -1, -1, -1 /* FP, ARGP, ILC. */
203 /* Allocate a new, cleared machine_function structure. */
205 static struct machine_function
*
206 c6x_init_machine_status (void)
208 return ggc_alloc_cleared_machine_function ();
211 /* Implement TARGET_OPTION_OVERRIDE. */
214 c6x_option_override (void)
218 if (global_options_set
.x_c6x_arch_option
)
220 c6x_arch
= all_isas
[c6x_arch_option
].type
;
221 c6x_insn_mask
&= ~C6X_INSNS_ALL_CPU_BITS
;
222 c6x_insn_mask
|= all_isas
[c6x_arch_option
].features
;
225 c6x_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
226 flag_schedule_insns_after_reload
= 0;
228 c6x_flag_modulo_sched
= flag_modulo_sched
;
229 flag_modulo_sched
= 0;
231 init_machine_status
= c6x_init_machine_status
;
233 for (i
= 0; i
< ARRAY_SIZE (c6x_unit_names
); i
++)
234 c6x_unit_codes
[i
] = get_cpu_unit_code (c6x_unit_names
[i
]);
236 if (flag_pic
&& !TARGET_DSBT
)
238 error ("-fpic and -fPIC not supported without -mdsbt on this target");
241 c6x_initial_flag_pic
= flag_pic
;
242 if (TARGET_DSBT
&& !flag_pic
)
247 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
250 c6x_conditional_register_usage (void)
253 if (c6x_arch
== C6X_CPU_C62X
|| c6x_arch
== C6X_CPU_C67X
)
254 for (i
= 16; i
< 32; i
++)
257 fixed_regs
[32 + i
] = 1;
261 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_A_REGS
],
263 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_REGS
],
265 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_A_REGS
],
267 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_REGS
],
272 static GTY(()) rtx eqdf_libfunc
;
273 static GTY(()) rtx nedf_libfunc
;
274 static GTY(()) rtx ledf_libfunc
;
275 static GTY(()) rtx ltdf_libfunc
;
276 static GTY(()) rtx gedf_libfunc
;
277 static GTY(()) rtx gtdf_libfunc
;
278 static GTY(()) rtx eqsf_libfunc
;
279 static GTY(()) rtx nesf_libfunc
;
280 static GTY(()) rtx lesf_libfunc
;
281 static GTY(()) rtx ltsf_libfunc
;
282 static GTY(()) rtx gesf_libfunc
;
283 static GTY(()) rtx gtsf_libfunc
;
284 static GTY(()) rtx strasgi_libfunc
;
285 static GTY(()) rtx strasgi64p_libfunc
;
287 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
288 functions to match the C6x ABI. */
291 c6x_init_libfuncs (void)
293 /* Double-precision floating-point arithmetic. */
294 set_optab_libfunc (add_optab
, DFmode
, "__c6xabi_addd");
295 set_optab_libfunc (sdiv_optab
, DFmode
, "__c6xabi_divd");
296 set_optab_libfunc (smul_optab
, DFmode
, "__c6xabi_mpyd");
297 set_optab_libfunc (neg_optab
, DFmode
, "__c6xabi_negd");
298 set_optab_libfunc (sub_optab
, DFmode
, "__c6xabi_subd");
300 /* Single-precision floating-point arithmetic. */
301 set_optab_libfunc (add_optab
, SFmode
, "__c6xabi_addf");
302 set_optab_libfunc (sdiv_optab
, SFmode
, "__c6xabi_divf");
303 set_optab_libfunc (smul_optab
, SFmode
, "__c6xabi_mpyf");
304 set_optab_libfunc (neg_optab
, SFmode
, "__c6xabi_negf");
305 set_optab_libfunc (sub_optab
, SFmode
, "__c6xabi_subf");
307 /* Floating-point comparisons. */
308 eqsf_libfunc
= init_one_libfunc ("__c6xabi_eqf");
309 nesf_libfunc
= init_one_libfunc ("__c6xabi_neqf");
310 lesf_libfunc
= init_one_libfunc ("__c6xabi_lef");
311 ltsf_libfunc
= init_one_libfunc ("__c6xabi_ltf");
312 gesf_libfunc
= init_one_libfunc ("__c6xabi_gef");
313 gtsf_libfunc
= init_one_libfunc ("__c6xabi_gtf");
314 eqdf_libfunc
= init_one_libfunc ("__c6xabi_eqd");
315 nedf_libfunc
= init_one_libfunc ("__c6xabi_neqd");
316 ledf_libfunc
= init_one_libfunc ("__c6xabi_led");
317 ltdf_libfunc
= init_one_libfunc ("__c6xabi_ltd");
318 gedf_libfunc
= init_one_libfunc ("__c6xabi_ged");
319 gtdf_libfunc
= init_one_libfunc ("__c6xabi_gtd");
321 set_optab_libfunc (eq_optab
, SFmode
, NULL
);
322 set_optab_libfunc (ne_optab
, SFmode
, "__c6xabi_neqf");
323 set_optab_libfunc (gt_optab
, SFmode
, NULL
);
324 set_optab_libfunc (ge_optab
, SFmode
, NULL
);
325 set_optab_libfunc (lt_optab
, SFmode
, NULL
);
326 set_optab_libfunc (le_optab
, SFmode
, NULL
);
327 set_optab_libfunc (unord_optab
, SFmode
, "__c6xabi_unordf");
328 set_optab_libfunc (eq_optab
, DFmode
, NULL
);
329 set_optab_libfunc (ne_optab
, DFmode
, "__c6xabi_neqd");
330 set_optab_libfunc (gt_optab
, DFmode
, NULL
);
331 set_optab_libfunc (ge_optab
, DFmode
, NULL
);
332 set_optab_libfunc (lt_optab
, DFmode
, NULL
);
333 set_optab_libfunc (le_optab
, DFmode
, NULL
);
334 set_optab_libfunc (unord_optab
, DFmode
, "__c6xabi_unordd");
336 /* Floating-point to integer conversions. */
337 set_conv_libfunc (sfix_optab
, SImode
, DFmode
, "__c6xabi_fixdi");
338 set_conv_libfunc (ufix_optab
, SImode
, DFmode
, "__c6xabi_fixdu");
339 set_conv_libfunc (sfix_optab
, DImode
, DFmode
, "__c6xabi_fixdlli");
340 set_conv_libfunc (ufix_optab
, DImode
, DFmode
, "__c6xabi_fixdull");
341 set_conv_libfunc (sfix_optab
, SImode
, SFmode
, "__c6xabi_fixfi");
342 set_conv_libfunc (ufix_optab
, SImode
, SFmode
, "__c6xabi_fixfu");
343 set_conv_libfunc (sfix_optab
, DImode
, SFmode
, "__c6xabi_fixflli");
344 set_conv_libfunc (ufix_optab
, DImode
, SFmode
, "__c6xabi_fixfull");
346 /* Conversions between floating types. */
347 set_conv_libfunc (trunc_optab
, SFmode
, DFmode
, "__c6xabi_cvtdf");
348 set_conv_libfunc (sext_optab
, DFmode
, SFmode
, "__c6xabi_cvtfd");
350 /* Integer to floating-point conversions. */
351 set_conv_libfunc (sfloat_optab
, DFmode
, SImode
, "__c6xabi_fltid");
352 set_conv_libfunc (ufloat_optab
, DFmode
, SImode
, "__c6xabi_fltud");
353 set_conv_libfunc (sfloat_optab
, DFmode
, DImode
, "__c6xabi_fltllid");
354 set_conv_libfunc (ufloat_optab
, DFmode
, DImode
, "__c6xabi_fltulld");
355 set_conv_libfunc (sfloat_optab
, SFmode
, SImode
, "__c6xabi_fltif");
356 set_conv_libfunc (ufloat_optab
, SFmode
, SImode
, "__c6xabi_fltuf");
357 set_conv_libfunc (sfloat_optab
, SFmode
, DImode
, "__c6xabi_fltllif");
358 set_conv_libfunc (ufloat_optab
, SFmode
, DImode
, "__c6xabi_fltullf");
361 set_optab_libfunc (smul_optab
, DImode
, "__c6xabi_mpyll");
362 set_optab_libfunc (ashl_optab
, DImode
, "__c6xabi_llshl");
363 set_optab_libfunc (lshr_optab
, DImode
, "__c6xabi_llshru");
364 set_optab_libfunc (ashr_optab
, DImode
, "__c6xabi_llshr");
366 set_optab_libfunc (sdiv_optab
, SImode
, "__c6xabi_divi");
367 set_optab_libfunc (udiv_optab
, SImode
, "__c6xabi_divu");
368 set_optab_libfunc (smod_optab
, SImode
, "__c6xabi_remi");
369 set_optab_libfunc (umod_optab
, SImode
, "__c6xabi_remu");
370 set_optab_libfunc (sdivmod_optab
, SImode
, "__c6xabi_divremi");
371 set_optab_libfunc (udivmod_optab
, SImode
, "__c6xabi_divremu");
372 set_optab_libfunc (sdiv_optab
, DImode
, "__c6xabi_divlli");
373 set_optab_libfunc (udiv_optab
, DImode
, "__c6xabi_divull");
374 set_optab_libfunc (smod_optab
, DImode
, "__c6xabi_remlli");
375 set_optab_libfunc (umod_optab
, DImode
, "__c6xabi_remull");
376 set_optab_libfunc (udivmod_optab
, DImode
, "__c6xabi_divremull");
379 strasgi_libfunc
= init_one_libfunc ("__c6xabi_strasgi");
380 strasgi64p_libfunc
= init_one_libfunc ("__c6xabi_strasgi_64plus");
383 /* Begin the assembly file. */
386 c6x_file_start (void)
388 /* Variable tracking should be run after all optimizations which change order
389 of insns. It also needs a valid CFG. This can't be done in
390 c6x_override_options, because flag_var_tracking is finalized after
392 c6x_flag_var_tracking
= flag_var_tracking
;
393 flag_var_tracking
= 0;
395 done_cfi_sections
= false;
396 default_file_start ();
398 /* Arrays are aligned to 8-byte boundaries. */
399 asm_fprintf (asm_out_file
,
400 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
401 asm_fprintf (asm_out_file
,
402 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
404 /* Stack alignment is 8 bytes. */
405 asm_fprintf (asm_out_file
,
406 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
407 asm_fprintf (asm_out_file
,
408 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
410 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
411 /* ??? Ideally we'd check flag_short_wchar somehow. */
412 asm_fprintf (asm_out_file
, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
415 /* We conform to version 1.0 of the ABI. */
416 asm_fprintf (asm_out_file
,
417 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
421 /* The LTO frontend only enables exceptions when it sees a function that
422 uses it. This changes the return value of dwarf2out_do_frame, so we
423 have to check before every function. */
426 c6x_output_file_unwind (FILE * f
)
428 if (done_cfi_sections
)
431 /* Output a .cfi_sections directive. */
432 if (dwarf2out_do_frame ())
434 if (flag_unwind_tables
|| flag_exceptions
)
436 if (write_symbols
== DWARF2_DEBUG
437 || write_symbols
== VMS_AND_DWARF2_DEBUG
)
438 asm_fprintf (f
, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
440 asm_fprintf (f
, "\t.cfi_sections .c6xabi.exidx\n");
443 asm_fprintf (f
, "\t.cfi_sections .debug_frame\n");
444 done_cfi_sections
= true;
448 /* Output unwind directives at the end of a function. */
451 c6x_output_fn_unwind (FILE * f
)
453 /* Return immediately if we are not generating unwinding tables. */
454 if (! (flag_unwind_tables
|| flag_exceptions
))
457 /* If this function will never be unwound, then mark it as such. */
458 if (!(flag_unwind_tables
|| crtl
->uses_eh_lsda
)
459 && (TREE_NOTHROW (current_function_decl
)
460 || crtl
->all_throwers_are_sibcalls
))
461 fputs("\t.cantunwind\n", f
);
463 fputs ("\t.endp\n", f
);
467 /* Stack and Calling. */
469 int argument_registers
[10] =
478 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
481 c6x_init_cumulative_args (CUMULATIVE_ARGS
*cum
, const_tree fntype
, rtx libname
,
482 int n_named_args ATTRIBUTE_UNUSED
)
486 if (!libname
&& fntype
)
488 /* We need to find out the number of named arguments. Unfortunately,
489 for incoming arguments, N_NAMED_ARGS is set to -1. */
490 if (stdarg_p (fntype
))
491 cum
->nregs
= type_num_arguments (fntype
) - 1;
497 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
500 c6x_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
501 const_tree type
, bool named ATTRIBUTE_UNUSED
)
503 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
504 if (cum
->count
>= cum
->nregs
)
508 HOST_WIDE_INT size
= int_size_in_bytes (type
);
509 if (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (type
))
513 rtx reg1
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
] + 1);
514 rtx reg2
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
]);
515 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
516 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
517 return gen_rtx_PARALLEL (mode
, vec
);
521 return gen_rtx_REG (mode
, argument_registers
[cum
->count
]);
525 c6x_function_arg_advance (cumulative_args_t cum_v
,
526 enum machine_mode mode ATTRIBUTE_UNUSED
,
527 const_tree type ATTRIBUTE_UNUSED
,
528 bool named ATTRIBUTE_UNUSED
)
530 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
535 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
536 upward rather than downward. */
539 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED
,
540 const_tree type
, bool first
)
544 if (!TARGET_BIG_ENDIAN
)
550 size
= int_size_in_bytes (type
);
554 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
557 c6x_function_arg_boundary (enum machine_mode mode
, const_tree type
)
559 unsigned int boundary
= type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
);
561 if (boundary
> BITS_PER_WORD
)
562 return 2 * BITS_PER_WORD
;
566 HOST_WIDE_INT size
= int_size_in_bytes (type
);
568 return 2 * BITS_PER_WORD
;
569 if (boundary
< BITS_PER_WORD
)
572 return BITS_PER_WORD
;
574 return 2 * BITS_PER_UNIT
;
580 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
582 c6x_function_arg_round_boundary (enum machine_mode mode
, const_tree type
)
584 return c6x_function_arg_boundary (mode
, type
);
587 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
588 where function FUNC returns or receives a value of data type TYPE. */
591 c6x_function_value (const_tree type
, const_tree func ATTRIBUTE_UNUSED
,
592 bool outgoing ATTRIBUTE_UNUSED
)
594 /* Functions return values in register A4. When returning aggregates, we may
595 have to adjust for endianness. */
596 if (TARGET_BIG_ENDIAN
&& type
&& AGGREGATE_TYPE_P (type
))
598 HOST_WIDE_INT size
= int_size_in_bytes (type
);
602 rtx reg1
= gen_rtx_REG (SImode
, REG_A4
+ 1);
603 rtx reg2
= gen_rtx_REG (SImode
, REG_A4
);
604 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
605 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
606 return gen_rtx_PARALLEL (TYPE_MODE (type
), vec
);
609 return gen_rtx_REG (TYPE_MODE (type
), REG_A4
);
612 /* Implement TARGET_LIBCALL_VALUE. */
615 c6x_libcall_value (enum machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
617 return gen_rtx_REG (mode
, REG_A4
);
620 /* TARGET_STRUCT_VALUE_RTX implementation. */
623 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED
, int incoming ATTRIBUTE_UNUSED
)
625 return gen_rtx_REG (Pmode
, REG_A3
);
628 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
631 c6x_function_value_regno_p (const unsigned int regno
)
633 return regno
== REG_A4
;
636 /* Types larger than 64 bit, and variable sized types, are passed by
637 reference. The callee must copy them; see c6x_callee_copies. */
640 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
641 enum machine_mode mode
, const_tree type
,
642 bool named ATTRIBUTE_UNUSED
)
646 size
= int_size_in_bytes (type
);
647 else if (mode
!= VOIDmode
)
648 size
= GET_MODE_SIZE (mode
);
649 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
652 /* Decide whether a type should be returned in memory (true)
653 or in a register (false). This is called by the macro
654 TARGET_RETURN_IN_MEMORY. */
657 c6x_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
659 int size
= int_size_in_bytes (type
);
660 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
663 /* Values which must be returned in the most-significant end of the return
667 c6x_return_in_msb (const_tree valtype
)
669 HOST_WIDE_INT size
= int_size_in_bytes (valtype
);
670 return TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
) && size
== 3;
673 /* Implement TARGET_CALLEE_COPIES. */
676 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
677 enum machine_mode mode ATTRIBUTE_UNUSED
,
678 const_tree type ATTRIBUTE_UNUSED
,
679 bool named ATTRIBUTE_UNUSED
)
684 /* Return the type to use as __builtin_va_list. */
686 c6x_build_builtin_va_list (void)
688 return build_pointer_type (char_type_node
);
692 c6x_asm_trampoline_template (FILE *f
)
694 fprintf (f
, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
695 fprintf (f
, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
696 fprintf (f
, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
697 fprintf (f
, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
698 fprintf (f
, "\t.long\t0x00000362\n"); /* b .s2 B0 */
699 fprintf (f
, "\t.long\t0x00008000\n"); /* nop 5 */
700 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
701 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
704 /* Emit RTL insns to initialize the variable parts of a trampoline at
705 TRAMP. FNADDR is an RTX for the address of the function's pure
706 code. CXT is an RTX for the static chain value for the function. */
709 c6x_initialize_trampoline (rtx tramp
, tree fndecl
, rtx cxt
)
711 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
712 rtx t1
= copy_to_reg (fnaddr
);
713 rtx t2
= copy_to_reg (cxt
);
714 rtx mask
= gen_reg_rtx (SImode
);
717 emit_block_move (tramp
, assemble_trampoline_template (),
718 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
720 emit_move_insn (mask
, GEN_INT (0xffff << 7));
722 for (i
= 0; i
< 4; i
++)
724 rtx mem
= adjust_address (tramp
, SImode
, i
* 4);
725 rtx t
= (i
& 1) ? t2
: t1
;
726 rtx v1
= gen_reg_rtx (SImode
);
727 rtx v2
= gen_reg_rtx (SImode
);
728 emit_move_insn (v1
, mem
);
730 emit_insn (gen_ashlsi3 (v2
, t
, GEN_INT (7)));
732 emit_insn (gen_lshrsi3 (v2
, t
, GEN_INT (9)));
733 emit_insn (gen_andsi3 (v2
, v2
, mask
));
734 emit_insn (gen_iorsi3 (v2
, v2
, v1
));
735 emit_move_insn (mem
, v2
);
737 #ifdef CLEAR_INSN_CACHE
738 tramp
= XEXP (tramp
, 0);
739 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__gnu_clear_cache"),
740 LCT_NORMAL
, VOIDmode
, 2, tramp
, Pmode
,
741 plus_constant (Pmode
, tramp
, TRAMPOLINE_SIZE
),
746 /* Determine whether c6x_output_mi_thunk can succeed. */
749 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED
,
750 HOST_WIDE_INT delta ATTRIBUTE_UNUSED
,
751 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED
,
752 const_tree function ATTRIBUTE_UNUSED
)
754 return !TARGET_LONG_CALLS
;
757 /* Output the assembler code for a thunk function. THUNK is the
758 declaration for the thunk function itself, FUNCTION is the decl for
759 the target function. DELTA is an immediate constant offset to be
760 added to THIS. If VCALL_OFFSET is nonzero, the word at
761 *(*this + vcall_offset) should be added to THIS. */
764 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
765 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
766 HOST_WIDE_INT vcall_offset
, tree function
)
769 /* The this parameter is passed as the first argument. */
770 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_A4
);
772 c6x_current_insn
= NULL_RTX
;
774 xops
[4] = XEXP (DECL_RTL (function
), 0);
777 output_asm_insn ("b .s2 \t%4", xops
);
779 output_asm_insn ("nop 5", xops
);
782 /* Adjust the this parameter by a fixed constant. */
785 xops
[0] = GEN_INT (delta
);
787 if (delta
>= -16 && delta
<= 15)
789 output_asm_insn ("add .s1 %0, %1, %1", xops
);
791 output_asm_insn ("nop 4", xops
);
793 else if (delta
>= 16 && delta
< 32)
795 output_asm_insn ("add .d1 %0, %1, %1", xops
);
797 output_asm_insn ("nop 4", xops
);
799 else if (delta
>= -32768 && delta
< 32768)
801 output_asm_insn ("mvk .s1 %0, A0", xops
);
802 output_asm_insn ("add .d1 %1, A0, %1", xops
);
804 output_asm_insn ("nop 3", xops
);
808 output_asm_insn ("mvkl .s1 %0, A0", xops
);
809 output_asm_insn ("mvkh .s1 %0, A0", xops
);
810 output_asm_insn ("add .d1 %1, A0, %1", xops
);
812 output_asm_insn ("nop 3", xops
);
816 /* Adjust the this parameter by a value stored in the vtable. */
819 rtx a0tmp
= gen_rtx_REG (Pmode
, REG_A0
);
820 rtx a3tmp
= gen_rtx_REG (Pmode
, REG_A3
);
824 xops
[3] = gen_rtx_MEM (Pmode
, a0tmp
);
825 output_asm_insn ("mv .s1 a4, %2", xops
);
826 output_asm_insn ("ldw .d1t1 %3, %2", xops
);
828 /* Adjust the this parameter. */
829 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (Pmode
, a0tmp
,
831 if (!memory_operand (xops
[0], Pmode
))
833 rtx tmp2
= gen_rtx_REG (Pmode
, REG_A1
);
834 xops
[0] = GEN_INT (vcall_offset
);
836 output_asm_insn ("mvkl .s1 %0, %1", xops
);
837 output_asm_insn ("mvkh .s1 %0, %1", xops
);
838 output_asm_insn ("nop 2", xops
);
839 output_asm_insn ("add .d1 %2, %1, %2", xops
);
840 xops
[0] = gen_rtx_MEM (Pmode
, a0tmp
);
843 output_asm_insn ("nop 4", xops
);
845 output_asm_insn ("ldw .d1t1 %0, %1", xops
);
846 output_asm_insn ("|| b .s2 \t%4", xops
);
847 output_asm_insn ("nop 4", xops
);
848 output_asm_insn ("add .d1 %2, %1, %2", xops
);
852 /* Return true if EXP goes in small data/bss. */
855 c6x_in_small_data_p (const_tree exp
)
857 /* We want to merge strings, so we never consider them small data. */
858 if (TREE_CODE (exp
) == STRING_CST
)
861 /* Functions are never small data. */
862 if (TREE_CODE (exp
) == FUNCTION_DECL
)
865 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_WEAK (exp
))
868 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_SECTION_NAME (exp
))
870 const char *section
= TREE_STRING_POINTER (DECL_SECTION_NAME (exp
));
872 if (strcmp (section
, ".neardata") == 0
873 || strncmp (section
, ".neardata.", 10) == 0
874 || strncmp (section
, ".gnu.linkonce.s.", 16) == 0
875 || strcmp (section
, ".bss") == 0
876 || strncmp (section
, ".bss.", 5) == 0
877 || strncmp (section
, ".gnu.linkonce.sb.", 17) == 0
878 || strcmp (section
, ".rodata") == 0
879 || strncmp (section
, ".rodata.", 8) == 0
880 || strncmp (section
, ".gnu.linkonce.s2.", 17) == 0)
884 return PLACE_IN_SDATA_P (exp
);
889 /* Return a section for X. The only special thing we do here is to
890 honor small data. We don't have a tree type, so we can't use the
891 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
892 everything sized 8 bytes or smaller into small data. */
895 c6x_select_rtx_section (enum machine_mode mode
, rtx x
,
896 unsigned HOST_WIDE_INT align
)
898 if (c6x_sdata_mode
== C6X_SDATA_ALL
899 || (c6x_sdata_mode
!= C6X_SDATA_NONE
&& GET_MODE_SIZE (mode
) <= 8))
900 /* ??? Consider using mergeable sdata sections. */
901 return sdata_section
;
903 return default_elf_select_rtx_section (mode
, x
, align
);
907 c6x_elf_select_section (tree decl
, int reloc
,
908 unsigned HOST_WIDE_INT align
)
910 const char *sname
= NULL
;
911 unsigned int flags
= SECTION_WRITE
;
912 if (c6x_in_small_data_p (decl
))
914 switch (categorize_decl_for_section (decl
, reloc
))
925 flags
|= SECTION_BSS
;
932 switch (categorize_decl_for_section (decl
, reloc
))
937 case SECCAT_DATA_REL
:
938 sname
= ".fardata.rel";
940 case SECCAT_DATA_REL_LOCAL
:
941 sname
= ".fardata.rel.local";
943 case SECCAT_DATA_REL_RO
:
944 sname
= ".fardata.rel.ro";
946 case SECCAT_DATA_REL_RO_LOCAL
:
947 sname
= ".fardata.rel.ro.local";
951 flags
|= SECTION_BSS
;
967 /* We might get called with string constants, but get_named_section
968 doesn't like them as they are not DECLs. Also, we need to set
969 flags in that case. */
971 return get_section (sname
, flags
, NULL
);
972 return get_named_section (decl
, sname
, reloc
);
975 return default_elf_select_section (decl
, reloc
, align
);
978 /* Build up a unique section name, expressed as a
979 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
980 RELOC indicates whether the initial value of EXP requires
981 link-time relocations. */
983 static void ATTRIBUTE_UNUSED
984 c6x_elf_unique_section (tree decl
, int reloc
)
986 const char *prefix
= NULL
;
987 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
988 bool one_only
= DECL_ONE_ONLY (decl
) && !HAVE_COMDAT_GROUP
;
990 if (c6x_in_small_data_p (decl
))
992 switch (categorize_decl_for_section (decl
, reloc
))
995 prefix
= one_only
? ".s" : ".neardata";
998 prefix
= one_only
? ".sb" : ".bss";
1000 case SECCAT_SRODATA
:
1001 prefix
= one_only
? ".s2" : ".rodata";
1003 case SECCAT_RODATA_MERGE_STR
:
1004 case SECCAT_RODATA_MERGE_STR_INIT
:
1005 case SECCAT_RODATA_MERGE_CONST
:
1008 case SECCAT_DATA_REL
:
1009 case SECCAT_DATA_REL_LOCAL
:
1010 case SECCAT_DATA_REL_RO
:
1011 case SECCAT_DATA_REL_RO_LOCAL
:
1014 /* Everything else we place into default sections and hope for the
1021 switch (categorize_decl_for_section (decl
, reloc
))
1024 case SECCAT_DATA_REL
:
1025 case SECCAT_DATA_REL_LOCAL
:
1026 case SECCAT_DATA_REL_RO
:
1027 case SECCAT_DATA_REL_RO_LOCAL
:
1028 prefix
= one_only
? ".fd" : ".fardata";
1031 prefix
= one_only
? ".fb" : ".far";
1034 case SECCAT_RODATA_MERGE_STR
:
1035 case SECCAT_RODATA_MERGE_STR_INIT
:
1036 case SECCAT_RODATA_MERGE_CONST
:
1037 prefix
= one_only
? ".fr" : ".const";
1039 case SECCAT_SRODATA
:
1050 const char *name
, *linkonce
;
1053 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
1054 name
= targetm
.strip_name_encoding (name
);
1056 /* If we're using one_only, then there needs to be a .gnu.linkonce
1057 prefix to the section name. */
1058 linkonce
= one_only
? ".gnu.linkonce" : "";
1060 string
= ACONCAT ((linkonce
, prefix
, ".", name
, NULL
));
1062 DECL_SECTION_NAME (decl
) = build_string (strlen (string
), string
);
1065 default_unique_section (decl
, reloc
);
1069 c6x_section_type_flags (tree decl
, const char *name
, int reloc
)
1071 unsigned int flags
= 0;
1073 if (strcmp (name
, ".far") == 0
1074 || strncmp (name
, ".far.", 5) == 0)
1075 flags
|= SECTION_BSS
;
1077 flags
|= default_section_type_flags (decl
, name
, reloc
);
1082 /* Checks whether the given CALL_EXPR would use a caller saved
1083 register. This is used to decide whether sibling call optimization
1084 could be performed on the respective function call. */
1087 c6x_call_saved_register_used (tree call_expr
)
1089 CUMULATIVE_ARGS cum_v
;
1090 cumulative_args_t cum
;
1091 HARD_REG_SET call_saved_regset
;
1093 enum machine_mode mode
;
1098 INIT_CUMULATIVE_ARGS (cum_v
, NULL
, NULL
, 0, 0);
1099 cum
= pack_cumulative_args (&cum_v
);
1101 COMPL_HARD_REG_SET (call_saved_regset
, call_used_reg_set
);
1102 for (i
= 0; i
< call_expr_nargs (call_expr
); i
++)
1104 parameter
= CALL_EXPR_ARG (call_expr
, i
);
1105 gcc_assert (parameter
);
1107 /* For an undeclared variable passed as parameter we will get
1108 an ERROR_MARK node here. */
1109 if (TREE_CODE (parameter
) == ERROR_MARK
)
1112 type
= TREE_TYPE (parameter
);
1115 mode
= TYPE_MODE (type
);
1118 if (pass_by_reference (&cum_v
, mode
, type
, true))
1121 type
= build_pointer_type (type
);
1124 parm_rtx
= c6x_function_arg (cum
, mode
, type
, 0);
1126 c6x_function_arg_advance (cum
, mode
, type
, 0);
1131 if (REG_P (parm_rtx
)
1132 && overlaps_hard_reg_set_p (call_saved_regset
, GET_MODE (parm_rtx
),
1135 if (GET_CODE (parm_rtx
) == PARALLEL
)
1137 int n
= XVECLEN (parm_rtx
, 0);
1140 rtx x
= XEXP (XVECEXP (parm_rtx
, 0, n
), 0);
1142 && overlaps_hard_reg_set_p (call_saved_regset
,
1143 GET_MODE (x
), REGNO (x
)))
1151 /* Decide whether we can make a sibling call to a function. DECL is the
1152 declaration of the function being targeted by the call and EXP is the
1153 CALL_EXPR representing the call. */
1156 c6x_function_ok_for_sibcall (tree decl
, tree exp
)
1158 /* Registers A10, A12, B10 and B12 are available as arguments
1159 register but unfortunately caller saved. This makes functions
1160 needing these registers for arguments not suitable for
1162 if (c6x_call_saved_register_used (exp
))
1170 /* When compiling for DSBT, the calling function must be local,
1171 so that when we reload B14 in the sibcall epilogue, it will
1172 not change its value. */
1173 struct cgraph_local_info
*this_func
;
1176 /* Not enough information. */
1179 this_func
= cgraph_local_info (current_function_decl
);
1180 return this_func
->local
;
1186 /* Return true if DECL is known to be linked into section SECTION. */
1189 c6x_function_in_section_p (tree decl
, section
*section
)
1191 /* We can only be certain about functions defined in the same
1192 compilation unit. */
1193 if (!TREE_STATIC (decl
))
1196 /* Make sure that SYMBOL always binds to the definition in this
1197 compilation unit. */
1198 if (!targetm
.binds_local_p (decl
))
1201 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1202 if (!DECL_SECTION_NAME (decl
))
1204 /* Make sure that we will not create a unique section for DECL. */
1205 if (flag_function_sections
|| DECL_ONE_ONLY (decl
))
1209 return function_section (decl
) == section
;
1212 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1215 c6x_long_call_p (rtx op
)
1219 if (!TARGET_LONG_CALLS
)
1222 decl
= SYMBOL_REF_DECL (op
);
1224 /* Try to determine whether the symbol is in the same section as the current
1225 function. Be conservative, and only cater for cases in which the
1226 whole of the current function is placed in the same section. */
1227 if (decl
!= NULL_TREE
1228 && !flag_reorder_blocks_and_partition
1229 && TREE_CODE (decl
) == FUNCTION_DECL
1230 && c6x_function_in_section_p (decl
, current_function_section ()))
1236 /* Emit the sequence for a call. */
1238 c6x_expand_call (rtx retval
, rtx address
, bool sibcall
)
1240 rtx callee
= XEXP (address
, 0);
1243 if (!c6x_call_operand (callee
, Pmode
))
1245 callee
= force_reg (Pmode
, callee
);
1246 address
= change_address (address
, Pmode
, callee
);
1248 call_insn
= gen_rtx_CALL (VOIDmode
, address
, const0_rtx
);
1251 call_insn
= emit_call_insn (call_insn
);
1252 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
),
1253 gen_rtx_REG (Pmode
, REG_B3
));
1257 if (retval
== NULL_RTX
)
1258 call_insn
= emit_call_insn (call_insn
);
1260 call_insn
= emit_call_insn (gen_rtx_SET (GET_MODE (retval
), retval
,
1264 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
), pic_offset_table_rtx
);
1267 /* Legitimize PIC addresses. If the address is already position-independent,
1268 we return ORIG. Newly generated position-independent addresses go into a
1269 reg. This is REG if nonzero, otherwise we allocate register(s) as
1270 necessary. PICREG is the register holding the pointer to the PIC offset
1274 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
1279 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
1281 int unspec
= UNSPEC_LOAD_GOT
;
1286 gcc_assert (can_create_pseudo_p ());
1287 reg
= gen_reg_rtx (Pmode
);
1291 if (can_create_pseudo_p ())
1292 tmp
= gen_reg_rtx (Pmode
);
1295 emit_insn (gen_movsi_gotoff_high (tmp
, addr
));
1296 emit_insn (gen_movsi_gotoff_lo_sum (tmp
, tmp
, addr
));
1297 emit_insn (gen_load_got_gotoff (reg
, picreg
, tmp
));
1301 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
1302 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
1304 emit_move_insn (reg
, new_rtx
);
1306 if (picreg
== pic_offset_table_rtx
)
1307 crtl
->uses_pic_offset_table
= 1;
1311 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
1315 if (GET_CODE (addr
) == CONST
)
1317 addr
= XEXP (addr
, 0);
1318 gcc_assert (GET_CODE (addr
) == PLUS
);
1321 if (XEXP (addr
, 0) == picreg
)
1326 gcc_assert (can_create_pseudo_p ());
1327 reg
= gen_reg_rtx (Pmode
);
1330 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
1331 addr
= legitimize_pic_address (XEXP (addr
, 1),
1332 base
== reg
? NULL_RTX
: reg
,
1335 if (GET_CODE (addr
) == CONST_INT
)
1337 gcc_assert (! reload_in_progress
&& ! reload_completed
);
1338 addr
= force_reg (Pmode
, addr
);
1341 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
1343 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
1344 addr
= XEXP (addr
, 1);
1347 return gen_rtx_PLUS (Pmode
, base
, addr
);
1353 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1354 Returns true if no further code must be generated, false if the caller
1355 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1358 expand_move (rtx
*operands
, enum machine_mode mode
)
1360 rtx dest
= operands
[0];
1361 rtx op
= operands
[1];
1363 if ((reload_in_progress
| reload_completed
) == 0
1364 && GET_CODE (dest
) == MEM
&& GET_CODE (op
) != REG
)
1365 operands
[1] = force_reg (mode
, op
);
1366 else if (mode
== SImode
&& symbolic_operand (op
, SImode
))
1370 if (sdata_symbolic_operand (op
, SImode
))
1372 emit_insn (gen_load_sdata_pic (dest
, pic_offset_table_rtx
, op
));
1373 crtl
->uses_pic_offset_table
= 1;
1378 rtx temp
= (reload_completed
|| reload_in_progress
1379 ? dest
: gen_reg_rtx (Pmode
));
1381 operands
[1] = legitimize_pic_address (op
, temp
,
1382 pic_offset_table_rtx
);
1385 else if (reload_completed
1386 && !sdata_symbolic_operand (op
, SImode
))
1388 emit_insn (gen_movsi_high (dest
, op
));
1389 emit_insn (gen_movsi_lo_sum (dest
, dest
, op
));
1396 /* This function is called when we're about to expand an integer compare
1397 operation which performs COMPARISON. It examines the second operand,
1398 and if it is an integer constant that cannot be used directly on the
1399 current machine in a comparison insn, it returns true. */
1401 c6x_force_op_for_comparison_p (enum rtx_code code
, rtx op
)
1403 if (!CONST_INT_P (op
) || satisfies_constraint_Iu4 (op
))
1406 if ((code
== EQ
|| code
== LT
|| code
== GT
)
1407 && !satisfies_constraint_Is5 (op
))
1409 if ((code
== GTU
|| code
== LTU
)
1410 && (!TARGET_INSNS_64
|| !satisfies_constraint_Iu5 (op
)))
1416 /* Emit comparison instruction if necessary, returning the expression
1417 that holds the compare result in the proper mode. Return the comparison
1418 that should be used in the jump insn. */
1421 c6x_expand_compare (rtx comparison
, enum machine_mode mode
)
1423 enum rtx_code code
= GET_CODE (comparison
);
1424 rtx op0
= XEXP (comparison
, 0);
1425 rtx op1
= XEXP (comparison
, 1);
1427 enum rtx_code jump_code
= code
;
1428 enum machine_mode op_mode
= GET_MODE (op0
);
1430 if (op_mode
== DImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1432 rtx t
= gen_reg_rtx (SImode
);
1433 emit_insn (gen_iorsi3 (t
, gen_lowpart (SImode
, op0
),
1434 gen_highpart (SImode
, op0
)));
1438 else if (op_mode
== DImode
)
1443 if (code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1445 code
= reverse_condition (code
);
1451 split_di (&op0
, 1, lo
, high
);
1452 split_di (&op1
, 1, lo
+ 1, high
+ 1);
1454 if (c6x_force_op_for_comparison_p (code
, high
[1])
1455 || c6x_force_op_for_comparison_p (EQ
, high
[1]))
1456 high
[1] = force_reg (SImode
, high
[1]);
1458 cmp1
= gen_reg_rtx (SImode
);
1459 cmp2
= gen_reg_rtx (SImode
);
1460 emit_insn (gen_rtx_SET (VOIDmode
, cmp1
,
1461 gen_rtx_fmt_ee (code
, SImode
, high
[0], high
[1])));
1464 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1465 lo
[1] = force_reg (SImode
, lo
[1]);
1466 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1467 gen_rtx_fmt_ee (code
, SImode
, lo
[0], lo
[1])));
1468 emit_insn (gen_andsi3 (cmp1
, cmp1
, cmp2
));
1472 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1473 gen_rtx_EQ (SImode
, high
[0], high
[1])));
1476 else if (code
== LT
)
1478 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1479 lo
[1] = force_reg (SImode
, lo
[1]);
1480 emit_insn (gen_cmpsi_and (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1482 lo
[0], lo
[1], cmp2
));
1483 emit_insn (gen_iorsi3 (cmp1
, cmp1
, cmp2
));
1487 else if (TARGET_FP
&& !flag_finite_math_only
1488 && (op_mode
== DFmode
|| op_mode
== SFmode
)
1489 && code
!= EQ
&& code
!= NE
&& code
!= LT
&& code
!= GT
1490 && code
!= UNLE
&& code
!= UNGE
)
1492 enum rtx_code code1
, code2
, code3
;
1493 rtx (*fn
) (rtx
, rtx
, rtx
, rtx
, rtx
);
1505 code1
= code
== LE
|| code
== UNGT
? LT
: GT
;
1530 cmp
= gen_reg_rtx (SImode
);
1531 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1532 gen_rtx_fmt_ee (code1
, SImode
, op0
, op1
)));
1533 fn
= op_mode
== DFmode
? gen_cmpdf_ior
: gen_cmpsf_ior
;
1534 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code2
, SImode
, op0
, op1
),
1536 if (code3
!= UNKNOWN
)
1537 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code3
, SImode
, op0
, op1
),
1540 else if (op_mode
== SImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1545 is_fp_libfunc
= !TARGET_FP
&& (op_mode
== DFmode
|| op_mode
== SFmode
);
1547 if ((code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1550 code
= reverse_condition (code
);
1553 else if (code
== UNGE
)
1558 else if (code
== UNLE
)
1573 libfunc
= op_mode
== DFmode
? eqdf_libfunc
: eqsf_libfunc
;
1576 libfunc
= op_mode
== DFmode
? nedf_libfunc
: nesf_libfunc
;
1579 libfunc
= op_mode
== DFmode
? gtdf_libfunc
: gtsf_libfunc
;
1582 libfunc
= op_mode
== DFmode
? gedf_libfunc
: gesf_libfunc
;
1585 libfunc
= op_mode
== DFmode
? ltdf_libfunc
: ltsf_libfunc
;
1588 libfunc
= op_mode
== DFmode
? ledf_libfunc
: lesf_libfunc
;
1595 cmp
= emit_library_call_value (libfunc
, 0, LCT_CONST
, SImode
, 2,
1596 op0
, op_mode
, op1
, op_mode
);
1597 insns
= get_insns ();
1600 emit_libcall_block (insns
, cmp
, cmp
,
1601 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
));
1605 cmp
= gen_reg_rtx (SImode
);
1606 if (c6x_force_op_for_comparison_p (code
, op1
))
1607 op1
= force_reg (SImode
, op1
);
1608 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1609 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
)));
1613 return gen_rtx_fmt_ee (jump_code
, mode
, cmp
, const0_rtx
);
1616 /* Return one word of double-word value OP. HIGH_P is true to select the
1617 high part, false to select the low part. When encountering auto-increment
1618 addressing, we make the assumption that the low part is going to be accessed
1622 c6x_subword (rtx op
, bool high_p
)
1625 enum machine_mode mode
;
1627 mode
= GET_MODE (op
);
1628 if (mode
== VOIDmode
)
1631 if (TARGET_BIG_ENDIAN
? !high_p
: high_p
)
1632 byte
= UNITS_PER_WORD
;
1638 rtx addr
= XEXP (op
, 0);
1639 if (GET_CODE (addr
) == PLUS
|| REG_P (addr
))
1640 return adjust_address (op
, word_mode
, byte
);
1641 /* FIXME: should really support autoincrement addressing for
1642 multi-word modes. */
1646 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
1649 /* Split one or more DImode RTL references into pairs of SImode
1650 references. The RTL can be REG, offsettable MEM, integer constant, or
1651 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1652 split and "num" is its length. lo_half and hi_half are output arrays
1653 that parallel "operands". */
1656 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1660 rtx op
= operands
[num
];
1662 lo_half
[num
] = c6x_subword (op
, false);
1663 hi_half
[num
] = c6x_subword (op
, true);
1667 /* Return true if VAL is a mask valid for a clr instruction. */
1669 c6x_valid_mask_p (HOST_WIDE_INT val
)
1672 for (i
= 0; i
< 32; i
++)
1673 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1676 if (val
& ((unsigned HOST_WIDE_INT
)1 << i
))
1679 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1684 /* Expand a block move for a movmemM pattern. */
1687 c6x_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
,
1688 rtx expected_align_exp ATTRIBUTE_UNUSED
,
1689 rtx expected_size_exp ATTRIBUTE_UNUSED
)
1691 unsigned HOST_WIDE_INT align
= 1;
1692 unsigned HOST_WIDE_INT src_mem_align
, dst_mem_align
, min_mem_align
;
1693 unsigned HOST_WIDE_INT count
= 0, offset
= 0;
1694 unsigned int biggest_move
= TARGET_STDW
? 8 : 4;
1696 if (CONST_INT_P (align_exp
))
1697 align
= INTVAL (align_exp
);
1699 src_mem_align
= MEM_ALIGN (src
) / BITS_PER_UNIT
;
1700 dst_mem_align
= MEM_ALIGN (dst
) / BITS_PER_UNIT
;
1701 min_mem_align
= MIN (src_mem_align
, dst_mem_align
);
1703 if (min_mem_align
> align
)
1704 align
= min_mem_align
/ BITS_PER_UNIT
;
1705 if (src_mem_align
< align
)
1706 src_mem_align
= align
;
1707 if (dst_mem_align
< align
)
1708 dst_mem_align
= align
;
1710 if (CONST_INT_P (count_exp
))
1711 count
= INTVAL (count_exp
);
1715 /* Make sure we don't need to care about overflow later on. */
1716 if (count
> ((unsigned HOST_WIDE_INT
) 1 << 30))
1719 if (count
>= 28 && (count
& 3) == 0 && align
>= 4)
1721 tree dst_expr
= MEM_EXPR (dst
);
1722 tree src_expr
= MEM_EXPR (src
);
1723 rtx fn
= TARGET_INSNS_64PLUS
? strasgi64p_libfunc
: strasgi_libfunc
;
1724 rtx srcreg
= force_reg (Pmode
, XEXP (src
, 0));
1725 rtx dstreg
= force_reg (Pmode
, XEXP (dst
, 0));
1728 mark_addressable (src_expr
);
1730 mark_addressable (dst_expr
);
1731 emit_library_call (fn
, LCT_NORMAL
, VOIDmode
, 3,
1732 dstreg
, Pmode
, srcreg
, Pmode
, count_exp
, SImode
);
1736 if (biggest_move
> align
&& !TARGET_INSNS_64
)
1737 biggest_move
= align
;
1739 if (count
/ biggest_move
> 7)
1744 rtx reg
, reg_lowpart
;
1745 enum machine_mode srcmode
, dstmode
;
1746 unsigned HOST_WIDE_INT src_size
, dst_size
, src_left
;
1750 while (biggest_move
> count
)
1753 src_size
= dst_size
= biggest_move
;
1754 if (src_size
> src_mem_align
&& src_size
== 2)
1756 if (dst_size
> dst_mem_align
&& dst_size
== 2)
1759 if (dst_size
> src_size
)
1760 dst_size
= src_size
;
1762 srcmode
= mode_for_size (src_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1763 dstmode
= mode_for_size (dst_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1765 reg_lowpart
= reg
= gen_reg_rtx (srcmode
);
1768 reg
= gen_reg_rtx (SImode
);
1769 reg_lowpart
= gen_lowpart (srcmode
, reg
);
1772 srcmem
= adjust_address (copy_rtx (src
), srcmode
, offset
);
1774 if (src_size
> src_mem_align
)
1776 enum insn_code icode
= (srcmode
== SImode
? CODE_FOR_movmisalignsi
1777 : CODE_FOR_movmisaligndi
);
1778 emit_insn (GEN_FCN (icode
) (reg_lowpart
, srcmem
));
1781 emit_move_insn (reg_lowpart
, srcmem
);
1783 src_left
= src_size
;
1784 shift
= TARGET_BIG_ENDIAN
? (src_size
- dst_size
) * BITS_PER_UNIT
: 0;
1785 while (src_left
> 0)
1787 rtx dstreg
= reg_lowpart
;
1789 if (src_size
> dst_size
)
1792 int shift_amount
= shift
& (BITS_PER_WORD
- 1);
1794 srcword
= operand_subword_force (srcword
, src_left
>= 4 ? 0 : 4,
1796 if (shift_amount
> 0)
1798 dstreg
= gen_reg_rtx (SImode
);
1799 emit_insn (gen_lshrsi3 (dstreg
, srcword
,
1800 GEN_INT (shift_amount
)));
1804 dstreg
= gen_lowpart (dstmode
, dstreg
);
1807 dstmem
= adjust_address (copy_rtx (dst
), dstmode
, offset
);
1808 if (dst_size
> dst_mem_align
)
1810 enum insn_code icode
= (dstmode
== SImode
? CODE_FOR_movmisalignsi
1811 : CODE_FOR_movmisaligndi
);
1812 emit_insn (GEN_FCN (icode
) (dstmem
, dstreg
));
1815 emit_move_insn (dstmem
, dstreg
);
1817 if (TARGET_BIG_ENDIAN
)
1818 shift
-= dst_size
* BITS_PER_UNIT
;
1820 shift
+= dst_size
* BITS_PER_UNIT
;
1822 src_left
-= dst_size
;
1829 /* Subroutine of print_address_operand, print a single address offset OFF for
1830 a memory access of mode MEM_MODE, choosing between normal form and scaled
1831 form depending on the type of the insn. Misaligned memory references must
1832 use the scaled form. */
1835 print_address_offset (FILE *file
, rtx off
, enum machine_mode mem_mode
)
1839 if (c6x_current_insn
!= NULL_RTX
)
1841 pat
= PATTERN (c6x_current_insn
);
1842 if (GET_CODE (pat
) == COND_EXEC
)
1843 pat
= COND_EXEC_CODE (pat
);
1844 if (GET_CODE (pat
) == PARALLEL
)
1845 pat
= XVECEXP (pat
, 0, 0);
1847 if (GET_CODE (pat
) == SET
1848 && GET_CODE (SET_SRC (pat
)) == UNSPEC
1849 && XINT (SET_SRC (pat
), 1) == UNSPEC_MISALIGNED_ACCESS
)
1851 gcc_assert (CONST_INT_P (off
)
1852 && (INTVAL (off
) & (GET_MODE_SIZE (mem_mode
) - 1)) == 0);
1853 fprintf (file
, "[" HOST_WIDE_INT_PRINT_DEC
"]",
1854 INTVAL (off
) / GET_MODE_SIZE (mem_mode
));
1859 output_address (off
);
1864 c6x_print_operand_punct_valid_p (unsigned char c
)
1866 return c
== '$' || c
== '.' || c
== '|';
1869 static void c6x_print_operand (FILE *, rtx
, int);
1871 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1874 c6x_print_address_operand (FILE *file
, rtx x
, enum machine_mode mem_mode
)
1877 switch (GET_CODE (x
))
1881 if (GET_CODE (x
) == POST_MODIFY
)
1882 output_address (XEXP (x
, 0));
1883 off
= XEXP (XEXP (x
, 1), 1);
1884 if (XEXP (x
, 0) == stack_pointer_rtx
)
1886 if (GET_CODE (x
) == PRE_MODIFY
)
1887 gcc_assert (INTVAL (off
) > 0);
1889 gcc_assert (INTVAL (off
) < 0);
1891 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1893 fprintf (file
, "--");
1894 off
= GEN_INT (-INTVAL (off
));
1897 fprintf (file
, "++");
1898 if (GET_CODE (x
) == PRE_MODIFY
)
1899 output_address (XEXP (x
, 0));
1900 print_address_offset (file
, off
, mem_mode
);
1905 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1907 fprintf (file
, "-");
1908 off
= GEN_INT (-INTVAL (off
));
1911 fprintf (file
, "+");
1912 output_address (XEXP (x
, 0));
1913 print_address_offset (file
, off
, mem_mode
);
1917 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1918 fprintf (file
, "--");
1919 output_address (XEXP (x
, 0));
1920 fprintf (file
, "[1]");
1923 fprintf (file
, "++");
1924 output_address (XEXP (x
, 0));
1925 fprintf (file
, "[1]");
1928 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1929 output_address (XEXP (x
, 0));
1930 fprintf (file
, "++[1]");
1933 output_address (XEXP (x
, 0));
1934 fprintf (file
, "--[1]");
1940 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
1941 fprintf (file
, "+B14(");
1942 output_addr_const (file
, x
);
1943 fprintf (file
, ")");
1947 switch (XINT (x
, 1))
1949 case UNSPEC_LOAD_GOT
:
1950 fputs ("$GOT(", file
);
1951 output_addr_const (file
, XVECEXP (x
, 0, 0));
1954 case UNSPEC_LOAD_SDATA
:
1955 output_addr_const (file
, XVECEXP (x
, 0, 0));
1963 gcc_assert (GET_CODE (x
) != MEM
);
1964 c6x_print_operand (file
, x
, 0);
1969 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1970 specifies the functional unit used by INSN. */
1973 c6x_get_unit_specifier (rtx insn
)
1975 enum attr_units units
;
1977 if (insn_info
.exists ())
1979 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
1980 return c6x_unit_names
[unit
][0];
1983 units
= get_attr_units (insn
);
2008 /* Prints the unit specifier field. */
2010 c6x_print_unit_specifier_field (FILE *file
, rtx insn
)
2012 enum attr_units units
= get_attr_units (insn
);
2013 enum attr_cross cross
= get_attr_cross (insn
);
2014 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
2018 if (units
== UNITS_D_ADDR
)
2020 enum attr_addr_regfile arf
= get_attr_addr_regfile (insn
);
2022 gcc_assert (arf
!= ADDR_REGFILE_UNKNOWN
);
2023 half
= arf
== ADDR_REGFILE_A
? 1 : 2;
2024 t_half
= rf
== DEST_REGFILE_A
? 1 : 2;
2025 fprintf (file
, ".d%dt%d", half
, t_half
);
2029 if (insn_info
.exists ())
2031 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2033 fputs (c6x_unit_names
[unit
], file
);
2034 if (cross
== CROSS_Y
)
2039 gcc_assert (rf
!= DEST_REGFILE_UNKNOWN
);
2040 unitspec
= c6x_get_unit_specifier (insn
);
2041 half
= rf
== DEST_REGFILE_A
? 1 : 2;
2042 fprintf (file
, ".%c%d%s", unitspec
, half
, cross
== CROSS_Y
? "x" : "");
2045 /* Output assembly language output for the address ADDR to FILE. */
2047 c6x_print_operand_address (FILE *file
, rtx addr
)
2049 c6x_print_address_operand (file
, addr
, VOIDmode
);
2052 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2055 $ -- print the unit specifier field for the instruction.
2056 . -- print the predicate for the instruction or an emptry string for an
2058 | -- print "||" if the insn should be issued in parallel with the previous
2061 C -- print an opcode suffix for a reversed condition
2062 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2064 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2066 J -- print a predicate
2067 j -- like J, but use reverse predicate
2068 k -- treat a CONST_INT as a register number and print it as a register
2069 k -- like k, but print out a doubleword register
2070 n -- print an integer operand, negated
2071 p -- print the low part of a DImode register
2072 P -- print the high part of a DImode register
2073 r -- print the absolute value of an integer operand, shifted right by 1
2074 R -- print the absolute value of an integer operand, shifted right by 2
2075 f -- the first clear bit in an integer operand assumed to be a mask for
2077 F -- the last clear bit in such a mask
2078 s -- the first set bit in an integer operand assumed to be a mask for
2080 S -- the last set bit in such a mask
2081 U -- print either 1 or 2, depending on the side of the machine used by
2085 c6x_print_operand (FILE *file
, rtx x
, int code
)
2090 enum machine_mode mode
;
2094 if (GET_MODE (c6x_current_insn
) != TImode
)
2100 c6x_print_unit_specifier_field (file
, c6x_current_insn
);
2106 x
= current_insn_predicate
;
2109 unsigned int regno
= REGNO (XEXP (x
, 0));
2111 if (GET_CODE (x
) == EQ
)
2113 fputs (reg_names
[regno
], file
);
2119 mode
= GET_MODE (x
);
2126 enum rtx_code c
= GET_CODE (x
);
2128 c
= swap_condition (c
);
2129 fputs (GET_RTX_NAME (c
), file
);
2136 unsigned int regno
= REGNO (XEXP (x
, 0));
2137 if ((GET_CODE (x
) == EQ
) == (code
== 'J'))
2139 fputs (reg_names
[regno
], file
);
2144 gcc_assert (GET_CODE (x
) == CONST_INT
);
2146 fprintf (file
, "%s", reg_names
[v
]);
2149 gcc_assert (GET_CODE (x
) == CONST_INT
);
2151 gcc_assert ((v
& 1) == 0);
2152 fprintf (file
, "%s:%s", reg_names
[v
+ 1], reg_names
[v
]);
2159 gcc_assert (GET_CODE (x
) == CONST_INT
);
2161 for (i
= 0; i
< 32; i
++)
2163 HOST_WIDE_INT tst
= v
& 1;
2164 if (((code
== 'f' || code
== 'F') && !tst
)
2165 || ((code
== 's' || code
== 'S') && tst
))
2169 if (code
== 'f' || code
== 's')
2171 fprintf (file
, "%d", i
);
2176 HOST_WIDE_INT tst
= v
& 1;
2177 if ((code
== 'F' && tst
) || (code
== 'S' && !tst
))
2181 fprintf (file
, "%d", i
- 1);
2185 gcc_assert (GET_CODE (x
) == CONST_INT
);
2186 output_addr_const (file
, GEN_INT (-INTVAL (x
)));
2190 gcc_assert (GET_CODE (x
) == CONST_INT
);
2194 output_addr_const (file
, GEN_INT (v
>> 1));
2198 gcc_assert (GET_CODE (x
) == CONST_INT
);
2202 output_addr_const (file
, GEN_INT (v
>> 2));
2206 gcc_assert (GET_CODE (x
) == CONST_INT
);
2208 fputs (v
== 2 ? "h" : v
== 4 ? "w" : "d", file
);
2213 gcc_assert (GET_CODE (x
) == REG
);
2217 fputs (reg_names
[v
], file
);
2222 if (GET_CODE (x
) == CONST
)
2225 gcc_assert (GET_CODE (x
) == PLUS
);
2226 gcc_assert (GET_CODE (XEXP (x
, 1)) == CONST_INT
);
2227 v
= INTVAL (XEXP (x
, 1));
2231 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
2233 t
= SYMBOL_REF_DECL (x
);
2235 v
|= DECL_ALIGN_UNIT (t
);
2237 v
|= TYPE_ALIGN_UNIT (TREE_TYPE (t
));
2250 if (GET_CODE (x
) == PLUS
2251 || GET_RTX_CLASS (GET_CODE (x
)) == RTX_AUTOINC
)
2253 if (GET_CODE (x
) == CONST
|| GET_CODE (x
) == SYMBOL_REF
)
2255 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
2260 gcc_assert (REG_P (x
));
2261 if (A_REGNO_P (REGNO (x
)))
2263 if (B_REGNO_P (REGNO (x
)))
2268 switch (GET_CODE (x
))
2271 if (GET_MODE_SIZE (mode
) == 8)
2272 fprintf (file
, "%s:%s", reg_names
[REGNO (x
) + 1],
2273 reg_names
[REGNO (x
)]);
2275 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
2280 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
2281 c6x_print_address_operand (file
, XEXP (x
, 0), GET_MODE (x
));
2286 output_addr_const (file
, x
);
2291 output_addr_const (file
, x
);
2295 output_operand_lossage ("invalid const_double operand");
2299 output_addr_const (file
, x
);
2304 /* Return TRUE if OP is a valid memory address with a base register of
2305 class C. If SMALL_OFFSET is true, we disallow memory references which would
2306 require a long offset with B14/B15. */
2309 c6x_mem_operand (rtx op
, enum reg_class c
, bool small_offset
)
2311 enum machine_mode mode
= GET_MODE (op
);
2312 rtx base
= XEXP (op
, 0);
2313 switch (GET_CODE (base
))
2319 && (XEXP (base
, 0) == stack_pointer_rtx
2320 || XEXP (base
, 0) == pic_offset_table_rtx
))
2322 if (!c6x_legitimate_address_p_1 (mode
, base
, true, true))
2333 base
= XEXP (base
, 0);
2339 gcc_assert (sdata_symbolic_operand (base
, Pmode
));
2340 return !small_offset
&& c
== B_REGS
;
2345 return TEST_HARD_REG_BIT (reg_class_contents
[ (int) (c
)], REGNO (base
));
2348 /* Returns true if X is a valid address for use in a memory reference
2349 of mode MODE. If STRICT is true, we do not allow pseudo registers
2350 in the address. NO_LARGE_OFFSET is true if we are examining an
2351 address for use in a load or store misaligned instruction, or
2352 recursively examining an operand inside a PRE/POST_MODIFY. */
2355 c6x_legitimate_address_p_1 (enum machine_mode mode
, rtx x
, bool strict
,
2356 bool no_large_offset
)
2360 enum rtx_code code
= GET_CODE (x
);
2366 /* We can't split these into word-sized pieces yet. */
2367 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2369 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
2371 if (!c6x_legitimate_address_p_1 (mode
, XEXP (x
, 1), strict
, true))
2373 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
2381 /* We can't split these into word-sized pieces yet. */
2382 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2391 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x
));
2393 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x
));
2396 if (!REG_P (XEXP (x
, 0))
2397 || !c6x_legitimate_address_p_1 (mode
, XEXP (x
, 0), strict
, false))
2399 /* We cannot ensure currently that both registers end up in the
2400 same register file. */
2401 if (REG_P (XEXP (x
, 1)))
2404 if (mode
== BLKmode
)
2406 else if (mode
== VOIDmode
)
2407 /* ??? This can happen during ivopts. */
2410 size
= GET_MODE_SIZE (mode
);
2413 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2414 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_SDATA
2415 && XEXP (x
, 0) == pic_offset_table_rtx
2416 && sdata_symbolic_operand (XVECEXP (XEXP (x
, 1), 0, 0), SImode
))
2417 return !no_large_offset
&& size
<= 4;
2420 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2421 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_GOT
2422 && XEXP (x
, 0) == pic_offset_table_rtx
2423 && (GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == SYMBOL_REF
2424 || GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == LABEL_REF
))
2425 return !no_large_offset
;
2426 if (GET_CODE (XEXP (x
, 1)) != CONST_INT
)
2429 off
= INTVAL (XEXP (x
, 1));
2431 /* If the machine does not have doubleword load/stores, we'll use
2432 word size accesses. */
2434 if (size
== 2 * UNITS_PER_WORD
&& !TARGET_STDW
)
2435 size
= UNITS_PER_WORD
;
2437 if (((HOST_WIDE_INT
)size1
- 1) & off
)
2440 if (off
> -32 && off
< (size1
== size
? 32 : 28))
2442 if (no_large_offset
|| code
!= PLUS
|| XEXP (x
, 0) != stack_pointer_rtx
2443 || size1
> UNITS_PER_WORD
)
2445 return off
>= 0 && off
< 32768;
2450 return (!no_large_offset
2451 /* With -fpic, we must wrap it in an unspec to show the B14
2454 && GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
2455 && sdata_symbolic_operand (x
, Pmode
));
2463 c6x_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
2465 return c6x_legitimate_address_p_1 (mode
, x
, strict
, false);
2469 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
,
2470 rtx x ATTRIBUTE_UNUSED
)
2475 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2477 c6x_preferred_rename_class (reg_class_t cl
)
2480 return NONPREDICATE_A_REGS
;
2482 return NONPREDICATE_B_REGS
;
2483 if (cl
== ALL_REGS
|| cl
== GENERAL_REGS
)
2484 return NONPREDICATE_REGS
;
2488 /* Implements FINAL_PRESCAN_INSN. */
2490 c6x_final_prescan_insn (rtx insn
, rtx
*opvec ATTRIBUTE_UNUSED
,
2491 int noperands ATTRIBUTE_UNUSED
)
2493 c6x_current_insn
= insn
;
2496 /* A structure to describe the stack layout of a function. The layout is
2499 [saved frame pointer (or possibly padding0)]
2500 --> incoming stack pointer, new hard frame pointer
2501 [saved call-used regs]
2503 --> soft frame pointer
2505 [outgoing arguments]
2508 The structure members are laid out in this order. */
2513 /* Number of registers to save. */
2516 HOST_WIDE_INT frame
;
2517 int outgoing_arguments_size
;
2520 HOST_WIDE_INT to_allocate
;
2521 /* The offsets relative to the incoming stack pointer (which
2522 becomes HARD_FRAME_POINTER). */
2523 HOST_WIDE_INT frame_pointer_offset
;
2524 HOST_WIDE_INT b3_offset
;
2526 /* True if we should call push_rts/pop_rts to save and restore
2531 /* Return true if we need to save and modify the PIC register in the
2535 must_reload_pic_reg_p (void)
2537 struct cgraph_local_info
*i
= NULL
;
2542 i
= cgraph_local_info (current_function_decl
);
2544 if ((crtl
->uses_pic_offset_table
|| !crtl
->is_leaf
) && !i
->local
)
2549 /* Return 1 if we need to save REGNO. */
2551 c6x_save_reg (unsigned int regno
)
2553 return ((df_regs_ever_live_p (regno
)
2554 && !call_used_regs
[regno
]
2555 && !fixed_regs
[regno
])
2556 || (regno
== RETURN_ADDR_REGNO
2557 && (df_regs_ever_live_p (regno
)
2559 || (regno
== PIC_OFFSET_TABLE_REGNUM
&& must_reload_pic_reg_p ()));
2562 /* Examine the number of regs NREGS we've determined we must save.
2563 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2564 prologue and epilogue. */
2567 use_push_rts_p (int nregs
)
2569 if (TARGET_INSNS_64PLUS
&& optimize_function_for_size_p (cfun
)
2570 && !cfun
->machine
->contains_sibcall
2571 && !cfun
->returns_struct
2572 && !TARGET_LONG_CALLS
2573 && nregs
>= 6 && !frame_pointer_needed
)
2578 /* Return number of saved general prupose registers. */
2581 c6x_nsaved_regs (void)
2586 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
2587 if (c6x_save_reg (regno
))
2592 /* The safe debug order mandated by the ABI. */
2593 static unsigned reg_save_order
[] =
2595 REG_A10
, REG_A11
, REG_A12
, REG_A13
,
2597 REG_B10
, REG_B11
, REG_B12
, REG_B13
,
2601 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2603 /* Compute the layout of the stack frame and store it in FRAME. */
2606 c6x_compute_frame_layout (struct c6x_frame
*frame
)
2608 HOST_WIDE_INT size
= get_frame_size ();
2609 HOST_WIDE_INT offset
;
2612 /* We use the four bytes which are technically inside the caller's frame,
2613 usually to save the frame pointer. */
2615 frame
->padding0
= 0;
2616 nregs
= c6x_nsaved_regs ();
2617 frame
->push_rts
= false;
2618 frame
->b3_offset
= 0;
2619 if (use_push_rts_p (nregs
))
2621 frame
->push_rts
= true;
2622 frame
->b3_offset
= (TARGET_BIG_ENDIAN
? -12 : -13) * 4;
2625 else if (c6x_save_reg (REG_B3
))
2628 for (idx
= N_SAVE_ORDER
- 1; reg_save_order
[idx
] != REG_B3
; idx
--)
2630 if (c6x_save_reg (reg_save_order
[idx
]))
2631 frame
->b3_offset
-= 4;
2634 frame
->nregs
= nregs
;
2636 if (size
== 0 && nregs
== 0)
2638 frame
->padding0
= 4;
2639 frame
->padding1
= frame
->padding2
= 0;
2640 frame
->frame_pointer_offset
= frame
->to_allocate
= 0;
2641 frame
->outgoing_arguments_size
= 0;
2645 if (!frame
->push_rts
)
2646 offset
+= frame
->nregs
* 4;
2648 if (offset
== 0 && size
== 0 && crtl
->outgoing_args_size
== 0
2650 /* Don't use the bottom of the caller's frame if we have no
2651 allocation of our own and call other functions. */
2652 frame
->padding0
= frame
->padding1
= 4;
2653 else if (offset
& 4)
2654 frame
->padding1
= 4;
2656 frame
->padding1
= 0;
2658 offset
+= frame
->padding0
+ frame
->padding1
;
2659 frame
->frame_pointer_offset
= offset
;
2662 frame
->outgoing_arguments_size
= crtl
->outgoing_args_size
;
2663 offset
+= frame
->outgoing_arguments_size
;
2665 if ((offset
& 4) == 0)
2666 frame
->padding2
= 8;
2668 frame
->padding2
= 4;
2669 frame
->to_allocate
= offset
+ frame
->padding2
;
2672 /* Return the offset between two registers, one to be eliminated, and the other
2673 its replacement, at the start of a routine. */
2676 c6x_initial_elimination_offset (int from
, int to
)
2678 struct c6x_frame frame
;
2679 c6x_compute_frame_layout (&frame
);
2681 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
2683 else if (from
== FRAME_POINTER_REGNUM
2684 && to
== HARD_FRAME_POINTER_REGNUM
)
2685 return -frame
.frame_pointer_offset
;
2688 gcc_assert (to
== STACK_POINTER_REGNUM
);
2690 if (from
== ARG_POINTER_REGNUM
)
2691 return frame
.to_allocate
+ (frame
.push_rts
? 56 : 0);
2693 gcc_assert (from
== FRAME_POINTER_REGNUM
);
2694 return frame
.to_allocate
- frame
.frame_pointer_offset
;
2698 /* Given FROM and TO register numbers, say whether this elimination is
2699 allowed. Frame pointer elimination is automatically handled. */
2702 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
2704 if (to
== STACK_POINTER_REGNUM
)
2705 return !frame_pointer_needed
;
2709 /* Emit insns to increment the stack pointer by OFFSET. If
2710 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2711 Does nothing if the offset is zero. */
2714 emit_add_sp_const (HOST_WIDE_INT offset
, bool frame_related_p
)
2716 rtx to_add
= GEN_INT (offset
);
2717 rtx orig_to_add
= to_add
;
2723 if (offset
< -32768 || offset
> 32767)
2725 rtx reg
= gen_rtx_REG (SImode
, REG_A0
);
2726 rtx low
= GEN_INT (trunc_int_for_mode (offset
, HImode
));
2728 insn
= emit_insn (gen_movsi_high (reg
, low
));
2729 if (frame_related_p
)
2730 RTX_FRAME_RELATED_P (insn
) = 1;
2731 insn
= emit_insn (gen_movsi_lo_sum (reg
, reg
, to_add
));
2732 if (frame_related_p
)
2733 RTX_FRAME_RELATED_P (insn
) = 1;
2736 insn
= emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2738 if (frame_related_p
)
2741 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
2742 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
2743 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2746 RTX_FRAME_RELATED_P (insn
) = 1;
2750 /* Prologue and epilogue. */
2752 c6x_expand_prologue (void)
2754 struct c6x_frame frame
;
2757 HOST_WIDE_INT initial_offset
, off
, added_already
;
2759 c6x_compute_frame_layout (&frame
);
2761 if (flag_stack_usage_info
)
2762 current_function_static_stack_size
= frame
.to_allocate
;
2764 initial_offset
= -frame
.to_allocate
;
2767 emit_insn (gen_push_rts ());
2768 nsaved
= frame
.nregs
;
2771 /* If the offsets would be too large for the memory references we will
2772 create to save registers, do the stack allocation in two parts.
2773 Ensure by subtracting 8 that we don't store to the word pointed to
2774 by the stack pointer. */
2775 if (initial_offset
< -32768)
2776 initial_offset
= -frame
.frame_pointer_offset
- 8;
2778 if (frame
.to_allocate
> 0)
2779 gcc_assert (initial_offset
!= 0);
2781 off
= -initial_offset
+ 4 - frame
.padding0
;
2783 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2786 if (frame_pointer_needed
)
2788 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2789 /* We go through some contortions here to both follow the ABI's
2790 recommendation that FP == incoming SP, and to avoid writing or
2791 reading the word pointed to by the stack pointer. */
2792 rtx addr
= gen_rtx_POST_MODIFY (Pmode
, stack_pointer_rtx
,
2793 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2795 insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), fp_reg
);
2796 RTX_FRAME_RELATED_P (insn
) = 1;
2798 insn
= emit_insn (gen_addsi3 (hard_frame_pointer_rtx
, stack_pointer_rtx
,
2800 RTX_FRAME_RELATED_P (insn
) = 1;
2805 emit_add_sp_const (initial_offset
- added_already
, true);
2807 if (nsaved
< frame
.nregs
)
2811 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2813 int idx
= N_SAVE_ORDER
- i
- 1;
2814 unsigned regno
= reg_save_order
[idx
];
2816 enum machine_mode save_mode
= SImode
;
2818 if (regno
== REG_A15
&& frame_pointer_needed
)
2819 /* Already saved. */
2821 if (!c6x_save_reg (regno
))
2824 if (TARGET_STDW
&& (off
& 4) == 0 && off
<= 256
2826 && i
+ 1 < N_SAVE_ORDER
2827 && reg_save_order
[idx
- 1] == regno
- 1
2828 && c6x_save_reg (regno
- 1))
2834 reg
= gen_rtx_REG (save_mode
, regno
);
2835 off
-= GET_MODE_SIZE (save_mode
);
2837 insn
= emit_move_insn (adjust_address (mem
, save_mode
, off
),
2839 RTX_FRAME_RELATED_P (insn
) = 1;
2841 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2844 gcc_assert (nsaved
== frame
.nregs
);
2845 emit_add_sp_const (-frame
.to_allocate
- initial_offset
, true);
2846 if (must_reload_pic_reg_p ())
2848 if (dsbt_decl
== NULL
)
2852 t
= build_index_type (integer_one_node
);
2853 t
= build_array_type (integer_type_node
, t
);
2854 t
= build_decl (BUILTINS_LOCATION
, VAR_DECL
,
2855 get_identifier ("__c6xabi_DSBT_BASE"), t
);
2856 DECL_ARTIFICIAL (t
) = 1;
2857 DECL_IGNORED_P (t
) = 1;
2858 DECL_EXTERNAL (t
) = 1;
2859 TREE_STATIC (t
) = 1;
2860 TREE_PUBLIC (t
) = 1;
2865 emit_insn (gen_setup_dsbt (pic_offset_table_rtx
,
2866 XEXP (DECL_RTL (dsbt_decl
), 0)));
2871 c6x_expand_epilogue (bool sibcall
)
2874 struct c6x_frame frame
;
2879 c6x_compute_frame_layout (&frame
);
2881 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2883 /* Insert a dummy set/use of the stack pointer. This creates a
2884 scheduler barrier between the prologue saves and epilogue restores. */
2885 emit_insn (gen_epilogue_barrier (stack_pointer_rtx
, stack_pointer_rtx
));
2887 /* If the offsets would be too large for the memory references we will
2888 create to restore registers, do a preliminary stack adjustment here. */
2889 off
= frame
.to_allocate
- frame
.frame_pointer_offset
+ frame
.padding1
;
2892 nsaved
= frame
.nregs
;
2896 if (frame
.to_allocate
> 32768)
2898 /* Don't add the entire offset so that we leave an unused word
2899 above the stack pointer. */
2900 emit_add_sp_const ((off
- 16) & ~7, false);
2904 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2906 unsigned regno
= reg_save_order
[i
];
2908 enum machine_mode save_mode
= SImode
;
2910 if (!c6x_save_reg (regno
))
2912 if (regno
== REG_A15
&& frame_pointer_needed
)
2915 if (TARGET_STDW
&& (off
& 4) == 0 && off
< 256
2917 && i
+ 1 < N_SAVE_ORDER
2918 && reg_save_order
[i
+ 1] == regno
+ 1
2919 && c6x_save_reg (regno
+ 1))
2924 reg
= gen_rtx_REG (save_mode
, regno
);
2926 emit_move_insn (reg
, adjust_address (mem
, save_mode
, off
));
2928 off
+= GET_MODE_SIZE (save_mode
);
2929 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2932 if (!frame_pointer_needed
)
2933 emit_add_sp_const (off
+ frame
.padding0
- 4, false);
2936 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2937 rtx addr
= gen_rtx_PRE_MODIFY (Pmode
, stack_pointer_rtx
,
2938 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2940 emit_insn (gen_addsi3 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
2942 emit_move_insn (fp_reg
, gen_frame_mem (Pmode
, addr
));
2945 gcc_assert (nsaved
== frame
.nregs
);
2949 emit_jump_insn (gen_pop_rts ());
2951 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode
,
2952 RETURN_ADDR_REGNO
)));
2956 /* Return the value of the return address for the frame COUNT steps up
2957 from the current frame, after the prologue.
2958 We punt for everything but the current frame by returning const0_rtx. */
2961 c6x_return_addr_rtx (int count
)
2966 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNO
);
2969 /* Return true iff TYPE is one of the shadow types. */
2971 shadow_type_p (enum attr_type type
)
2973 return (type
== TYPE_SHADOW
|| type
== TYPE_LOAD_SHADOW
2974 || type
== TYPE_MULT_SHADOW
);
2977 /* Return true iff INSN is a shadow pattern. */
2981 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
2983 return shadow_type_p (get_attr_type (insn
));
2986 /* Return true iff INSN is a shadow or blockage pattern. */
2988 shadow_or_blockage_p (rtx insn
)
2990 enum attr_type type
;
2991 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
2993 type
= get_attr_type (insn
);
2994 return shadow_type_p (type
) || type
== TYPE_BLOCKAGE
;
2997 /* Translate UNITS into a bitmask of units we can reserve for this
3000 get_reservation_flags (enum attr_units units
)
3006 return RESERVATION_FLAG_D
;
3008 return RESERVATION_FLAG_L
;
3010 return RESERVATION_FLAG_S
;
3012 return RESERVATION_FLAG_M
;
3014 return RESERVATION_FLAG_LS
;
3016 return RESERVATION_FLAG_DL
;
3018 return RESERVATION_FLAG_DS
;
3020 return RESERVATION_FLAG_DLS
;
3026 /* Compute the side of the machine used by INSN, which reserves UNITS.
3027 This must match the reservations in the scheduling description. */
3029 get_insn_side (rtx insn
, enum attr_units units
)
3031 if (units
== UNITS_D_ADDR
)
3032 return (get_attr_addr_regfile (insn
) == ADDR_REGFILE_A
? 0 : 1);
3035 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
3036 if (rf
== DEST_REGFILE_ANY
)
3037 return get_attr_type (insn
) == TYPE_BRANCH
? 0 : 1;
3039 return rf
== DEST_REGFILE_A
? 0 : 1;
3043 /* After scheduling, walk the insns between HEAD and END and assign unit
3046 assign_reservations (rtx head
, rtx end
)
3049 for (insn
= head
; insn
!= NEXT_INSN (end
); insn
= NEXT_INSN (insn
))
3051 unsigned int sched_mask
, reserved
;
3055 int rsrv_count
[2][4];
3058 if (GET_MODE (insn
) != TImode
)
3063 /* Find the last insn in the packet. It has a state recorded for it,
3064 which we can use to determine the units we should be using. */
3066 (within
!= NEXT_INSN (end
)
3067 && (within
== insn
|| GET_MODE (within
) != TImode
));
3068 within
= NEXT_INSN (within
))
3071 if (!NONDEBUG_INSN_P (within
))
3073 icode
= recog_memoized (within
);
3076 if (shadow_p (within
))
3078 if (INSN_INFO_ENTRY (INSN_UID (within
)).reservation
!= 0)
3079 reserved
|= 1 << INSN_INFO_ENTRY (INSN_UID (within
)).reservation
;
3082 if (last
== NULL_RTX
)
3085 sched_mask
= INSN_INFO_ENTRY (INSN_UID (last
)).unit_mask
;
3086 sched_mask
&= ~reserved
;
3088 memset (rsrv_count
, 0, sizeof rsrv_count
);
3089 rsrv
[0] = rsrv
[1] = ~0;
3090 for (i
= 0; i
< 8; i
++)
3094 unsigned unit_bit
= 1 << (unit
+ side
* UNIT_QID_SIDE_OFFSET
);
3095 /* Clear the bits which we expect to reserve in the following loop,
3096 leaving the ones set which aren't present in the scheduler's
3097 state and shouldn't be reserved. */
3098 if (sched_mask
& unit_bit
)
3099 rsrv
[i
/ 4] &= ~(1 << unit
);
3102 /* Walk through the insns that occur in the same cycle. We use multiple
3103 passes to assign units, assigning for insns with the most specific
3104 requirements first. */
3105 for (pass
= 0; pass
< 4; pass
++)
3107 (within
!= NEXT_INSN (end
)
3108 && (within
== insn
|| GET_MODE (within
) != TImode
));
3109 within
= NEXT_INSN (within
))
3111 int uid
= INSN_UID (within
);
3112 int this_rsrv
, side
;
3114 enum attr_units units
;
3115 enum attr_type type
;
3118 if (!NONDEBUG_INSN_P (within
))
3120 icode
= recog_memoized (within
);
3123 if (INSN_INFO_ENTRY (uid
).reservation
!= 0)
3125 units
= get_attr_units (within
);
3126 type
= get_attr_type (within
);
3127 this_rsrv
= get_reservation_flags (units
);
3130 side
= get_insn_side (within
, units
);
3132 /* Certain floating point instructions are treated specially. If
3133 an insn can choose between units it can reserve, and its
3134 reservation spans more than one cycle, the reservation contains
3135 special markers in the first cycle to help us reconstruct what
3136 the automaton chose. */
3137 if ((type
== TYPE_ADDDP
|| type
== TYPE_FP4
)
3138 && units
== UNITS_LS
)
3140 int test1_code
= ((type
== TYPE_FP4
? UNIT_QID_FPL1
: UNIT_QID_ADDDPL1
)
3141 + side
* UNIT_QID_SIDE_OFFSET
);
3142 int test2_code
= ((type
== TYPE_FP4
? UNIT_QID_FPS1
: UNIT_QID_ADDDPS1
)
3143 + side
* UNIT_QID_SIDE_OFFSET
);
3144 if ((sched_mask
& (1 << test1_code
)) != 0)
3146 this_rsrv
= RESERVATION_FLAG_L
;
3147 sched_mask
&= ~(1 << test1_code
);
3149 else if ((sched_mask
& (1 << test2_code
)) != 0)
3151 this_rsrv
= RESERVATION_FLAG_S
;
3152 sched_mask
&= ~(1 << test2_code
);
3156 if ((this_rsrv
& (this_rsrv
- 1)) == 0)
3158 int t
= exact_log2 (this_rsrv
) + side
* UNIT_QID_SIDE_OFFSET
;
3159 rsrv
[side
] |= this_rsrv
;
3160 INSN_INFO_ENTRY (uid
).reservation
= t
;
3166 for (j
= 0; j
< 4; j
++)
3167 if (this_rsrv
& (1 << j
))
3168 rsrv_count
[side
][j
]++;
3171 if ((pass
== 2 && this_rsrv
!= RESERVATION_FLAG_DLS
)
3172 || (pass
== 3 && this_rsrv
== RESERVATION_FLAG_DLS
))
3174 int best
= -1, best_cost
= INT_MAX
;
3175 for (j
= 0; j
< 4; j
++)
3176 if ((this_rsrv
& (1 << j
))
3177 && !(rsrv
[side
] & (1 << j
))
3178 && rsrv_count
[side
][j
] < best_cost
)
3180 best_cost
= rsrv_count
[side
][j
];
3183 gcc_assert (best
!= -1);
3184 rsrv
[side
] |= 1 << best
;
3185 for (j
= 0; j
< 4; j
++)
3186 if ((this_rsrv
& (1 << j
)) && j
!= best
)
3187 rsrv_count
[side
][j
]--;
3189 INSN_INFO_ENTRY (uid
).reservation
3190 = best
+ side
* UNIT_QID_SIDE_OFFSET
;
3196 /* Return a factor by which to weight unit imbalances for a reservation
3199 unit_req_factor (enum unitreqs r
)
3221 /* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3222 requirements. Returns zero if INSN can't be handled, otherwise
3223 either one or two to show how many of the two pairs are in use.
3224 REQ1 is always used, it holds what is normally thought of as the
3225 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3226 describe a cross path, or for loads/stores, the T unit. */
3228 get_unit_reqs (rtx insn
, int *req1
, int *side1
, int *req2
, int *side2
)
3230 enum attr_units units
;
3231 enum attr_cross cross
;
3234 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3236 units
= get_attr_units (insn
);
3237 if (units
== UNITS_UNKNOWN
)
3239 side
= get_insn_side (insn
, units
);
3240 cross
= get_attr_cross (insn
);
3242 req
= (units
== UNITS_D
? UNIT_REQ_D
3243 : units
== UNITS_D_ADDR
? UNIT_REQ_D
3244 : units
== UNITS_DL
? UNIT_REQ_DL
3245 : units
== UNITS_DS
? UNIT_REQ_DS
3246 : units
== UNITS_L
? UNIT_REQ_L
3247 : units
== UNITS_LS
? UNIT_REQ_LS
3248 : units
== UNITS_S
? UNIT_REQ_S
3249 : units
== UNITS_M
? UNIT_REQ_M
3250 : units
== UNITS_DLS
? UNIT_REQ_DLS
3252 gcc_assert (req
!= -1);
3255 if (units
== UNITS_D_ADDR
)
3258 *side2
= side
^ (cross
== CROSS_Y
? 1 : 0);
3261 else if (cross
== CROSS_Y
)
3270 /* Walk the insns between and including HEAD and TAIL, and mark the
3271 resource requirements in the unit_reqs table. */
3273 count_unit_reqs (unit_req_table reqs
, rtx head
, rtx tail
)
3277 memset (reqs
, 0, sizeof (unit_req_table
));
3279 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3281 int side1
, side2
, req1
, req2
;
3283 switch (get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
))
3286 reqs
[side2
][req2
]++;
3289 reqs
[side1
][req1
]++;
3295 /* Update the table REQS by merging more specific unit reservations into
3296 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3297 UNIT_REQ_DL, DS, and DLS. */
3299 merge_unit_reqs (unit_req_table reqs
)
3302 for (side
= 0; side
< 2; side
++)
3304 int d
= reqs
[side
][UNIT_REQ_D
];
3305 int l
= reqs
[side
][UNIT_REQ_L
];
3306 int s
= reqs
[side
][UNIT_REQ_S
];
3307 int dl
= reqs
[side
][UNIT_REQ_DL
];
3308 int ls
= reqs
[side
][UNIT_REQ_LS
];
3309 int ds
= reqs
[side
][UNIT_REQ_DS
];
3311 reqs
[side
][UNIT_REQ_DL
] += d
;
3312 reqs
[side
][UNIT_REQ_DL
] += l
;
3313 reqs
[side
][UNIT_REQ_DS
] += d
;
3314 reqs
[side
][UNIT_REQ_DS
] += s
;
3315 reqs
[side
][UNIT_REQ_LS
] += l
;
3316 reqs
[side
][UNIT_REQ_LS
] += s
;
3317 reqs
[side
][UNIT_REQ_DLS
] += ds
+ dl
+ ls
+ d
+ l
+ s
;
3321 /* Examine the table REQS and return a measure of unit imbalance by comparing
3322 the two sides of the machine. If, for example, D1 is used twice and D2
3323 used not at all, the return value should be 1 in the absence of other
3326 unit_req_imbalance (unit_req_table reqs
)
3331 for (i
= 0; i
< UNIT_REQ_MAX
; i
++)
3333 int factor
= unit_req_factor ((enum unitreqs
) i
);
3334 int diff
= abs (reqs
[0][i
] - reqs
[1][i
]);
3335 val
+= (diff
+ factor
- 1) / factor
/ 2;
3340 /* Return the resource-constrained minimum iteration interval given the
3341 data in the REQS table. This must have been processed with
3342 merge_unit_reqs already. */
3344 res_mii (unit_req_table reqs
)
3348 for (side
= 0; side
< 2; side
++)
3349 for (req
= 0; req
< UNIT_REQ_MAX
; req
++)
3351 int factor
= unit_req_factor ((enum unitreqs
) req
);
3352 worst
= MAX ((reqs
[side
][UNIT_REQ_D
] + factor
- 1) / factor
, worst
);
3358 /* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3359 the operands that are involved in the (up to) two reservations, as
3360 found by get_unit_reqs. Return true if we did this successfully, false
3361 if we couldn't identify what to do with INSN. */
3363 get_unit_operand_masks (rtx insn
, unsigned int *pmask1
, unsigned int *pmask2
)
3365 enum attr_op_pattern op_pat
;
3367 if (recog_memoized (insn
) < 0)
3369 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
)
3371 extract_insn (insn
);
3372 op_pat
= get_attr_op_pattern (insn
);
3373 if (op_pat
== OP_PATTERN_DT
)
3375 gcc_assert (recog_data
.n_operands
== 2);
3380 else if (op_pat
== OP_PATTERN_TD
)
3382 gcc_assert (recog_data
.n_operands
== 2);
3387 else if (op_pat
== OP_PATTERN_SXS
)
3389 gcc_assert (recog_data
.n_operands
== 3);
3390 *pmask1
= (1 << 0) | (1 << 2);
3394 else if (op_pat
== OP_PATTERN_SX
)
3396 gcc_assert (recog_data
.n_operands
== 2);
3401 else if (op_pat
== OP_PATTERN_SSX
)
3403 gcc_assert (recog_data
.n_operands
== 3);
3404 *pmask1
= (1 << 0) | (1 << 1);
3411 /* Try to replace a register in INSN, which has corresponding rename info
3412 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3413 about the operands that must be renamed and the side they are on.
3414 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3415 We recompute this information locally after our transformation, and keep
3416 it only if we managed to improve the balance. */
3418 try_rename_operands (rtx head
, rtx tail
, unit_req_table reqs
, rtx insn
,
3419 insn_rr_info
*info
, unsigned int op_mask
, int orig_side
)
3421 enum reg_class super_class
= orig_side
== 0 ? B_REGS
: A_REGS
;
3422 HARD_REG_SET unavailable
;
3423 du_head_p this_head
;
3424 struct du_chain
*chain
;
3427 int best_reg
, old_reg
;
3428 vec
<du_head_p
> involved_chains
= vNULL
;
3429 unit_req_table new_reqs
;
3431 for (i
= 0, tmp_mask
= op_mask
; tmp_mask
; i
++)
3434 if ((tmp_mask
& (1 << i
)) == 0)
3436 if (info
->op_info
[i
].n_chains
!= 1)
3438 op_chain
= regrename_chain_from_id (info
->op_info
[i
].heads
[0]->id
);
3439 involved_chains
.safe_push (op_chain
);
3440 tmp_mask
&= ~(1 << i
);
3443 if (involved_chains
.length () > 1)
3446 this_head
= involved_chains
[0];
3447 if (this_head
->cannot_rename
)
3450 for (chain
= this_head
->first
; chain
; chain
= chain
->next_use
)
3452 unsigned int mask1
, mask2
, mask_changed
;
3453 int count
, side1
, side2
, req1
, req2
;
3454 insn_rr_info
*this_rr
= &insn_rr
[INSN_UID (chain
->insn
)];
3456 count
= get_unit_reqs (chain
->insn
, &req1
, &side1
, &req2
, &side2
);
3461 if (!get_unit_operand_masks (chain
->insn
, &mask1
, &mask2
))
3464 extract_insn (chain
->insn
);
3467 for (i
= 0; i
< recog_data
.n_operands
; i
++)
3470 int n_this_op
= this_rr
->op_info
[i
].n_chains
;
3471 for (j
= 0; j
< n_this_op
; j
++)
3473 du_head_p other
= this_rr
->op_info
[i
].heads
[j
];
3474 if (regrename_chain_from_id (other
->id
) == this_head
)
3482 mask_changed
|= 1 << i
;
3484 gcc_assert (mask_changed
!= 0);
3485 if (mask_changed
!= mask1
&& mask_changed
!= mask2
)
3489 /* If we get here, we can do the renaming. */
3490 COMPL_HARD_REG_SET (unavailable
, reg_class_contents
[(int) super_class
]);
3492 old_reg
= this_head
->regno
;
3493 best_reg
= find_best_rename_reg (this_head
, super_class
, &unavailable
, old_reg
);
3495 regrename_do_replace (this_head
, best_reg
);
3497 count_unit_reqs (new_reqs
, head
, PREV_INSN (tail
));
3498 merge_unit_reqs (new_reqs
);
3501 fprintf (dump_file
, "reshuffle for insn %d, op_mask %x, "
3502 "original side %d, new reg %d\n",
3503 INSN_UID (insn
), op_mask
, orig_side
, best_reg
);
3504 fprintf (dump_file
, " imbalance %d -> %d\n",
3505 unit_req_imbalance (reqs
), unit_req_imbalance (new_reqs
));
3507 if (unit_req_imbalance (new_reqs
) > unit_req_imbalance (reqs
))
3508 regrename_do_replace (this_head
, old_reg
);
3510 memcpy (reqs
, new_reqs
, sizeof (unit_req_table
));
3513 involved_chains
.release ();
3516 /* Find insns in LOOP which would, if shifted to the other side
3517 of the machine, reduce an imbalance in the unit reservations. */
3519 reshuffle_units (basic_block loop
)
3521 rtx head
= BB_HEAD (loop
);
3522 rtx tail
= BB_END (loop
);
3524 unit_req_table reqs
;
3529 count_unit_reqs (reqs
, head
, PREV_INSN (tail
));
3530 merge_unit_reqs (reqs
);
3532 regrename_init (true);
3534 bitmap_initialize (&bbs
, &bitmap_default_obstack
);
3536 FOR_EACH_EDGE (e
, ei
, loop
->preds
)
3537 bitmap_set_bit (&bbs
, e
->src
->index
);
3539 bitmap_set_bit (&bbs
, loop
->index
);
3540 regrename_analyze (&bbs
);
3542 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3544 enum attr_units units
;
3545 int count
, side1
, side2
, req1
, req2
;
3546 unsigned int mask1
, mask2
;
3549 if (!NONDEBUG_INSN_P (insn
))
3552 count
= get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
);
3557 if (!get_unit_operand_masks (insn
, &mask1
, &mask2
))
3560 info
= &insn_rr
[INSN_UID (insn
)];
3561 if (info
->op_info
== NULL
)
3564 if (reqs
[side1
][req1
] > 1
3565 && reqs
[side1
][req1
] > 2 * reqs
[side1
^ 1][req1
])
3567 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask1
, side1
);
3570 units
= get_attr_units (insn
);
3571 if (units
== UNITS_D_ADDR
)
3573 gcc_assert (count
== 2);
3574 if (reqs
[side2
][req2
] > 1
3575 && reqs
[side2
][req2
] > 2 * reqs
[side2
^ 1][req2
])
3577 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask2
, side2
);
3581 regrename_finish ();
3584 /* Backend scheduling state. */
3585 typedef struct c6x_sched_context
3587 /* The current scheduler clock, saved in the sched_reorder hook. */
3588 int curr_sched_clock
;
3590 /* Number of insns issued so far in this cycle. */
3591 int issued_this_cycle
;
3593 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3594 theoretical maximum for number of jumps in flight is 12: 2 every
3595 cycle, with a latency of 6 cycles each. This is a circular
3596 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3597 jumps have a higher index. This array should be accessed through
3598 the jump_cycle function. */
3599 int jump_cycles
[12];
3600 int jump_cycle_index
;
3602 /* In parallel with jump_cycles, this array records the opposite of
3603 the condition used in each pending jump. This is used to
3604 predicate insns that are scheduled in the jump's delay slots. If
3605 this is NULL_RTX no such predication happens. */
3608 /* Similar to the jump_cycles mechanism, but here we take into
3609 account all insns with delay slots, to avoid scheduling asms into
3611 int delays_finished_at
;
3613 /* The following variable value is the last issued insn. */
3614 rtx last_scheduled_insn
;
3615 /* The last issued insn that isn't a shadow of another. */
3616 rtx last_scheduled_iter0
;
3618 /* The following variable value is DFA state before issuing the
3619 first insn in the current clock cycle. We do not use this member
3620 of the structure directly; we copy the data in and out of
3621 prev_cycle_state. */
3622 state_t prev_cycle_state_ctx
;
3624 int reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3625 int reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3626 int reg_set_in_cycle
[FIRST_PSEUDO_REGISTER
];
3628 int tmp_reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3629 int tmp_reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3630 } *c6x_sched_context_t
;
3632 /* The current scheduling state. */
3633 static struct c6x_sched_context ss
;
3635 /* The following variable value is DFA state before issuing the first insn
3636 in the current clock cycle. This is used in c6x_variable_issue for
3637 comparison with the state after issuing the last insn in a cycle. */
3638 static state_t prev_cycle_state
;
3640 /* Set when we discover while processing an insn that it would lead to too
3641 many accesses of the same register. */
3642 static bool reg_access_stall
;
3644 /* The highest insn uid after delayed insns were split, but before loop bodies
3645 were copied by the modulo scheduling code. */
3646 static int sploop_max_uid_iter0
;
3648 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3649 so the caller does not specifically have to test for it. */
3651 get_jump_cycle (int n
)
3655 n
+= ss
.jump_cycle_index
;
3658 return ss
.jump_cycles
[n
];
3661 /* Look up the jump condition with index N. */
3663 get_jump_cond (int n
)
3667 n
+= ss
.jump_cycle_index
;
3670 return ss
.jump_cond
[n
];
3673 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3674 has delay slots beyond CLOCK_VAR, return -1. */
3676 first_jump_index (int clock_var
)
3682 int t
= get_jump_cycle (n
);
3691 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3692 and has the opposite condition of COND. */
3694 record_jump (int cycle
, rtx cond
)
3696 if (ss
.jump_cycle_index
== 0)
3697 ss
.jump_cycle_index
= 11;
3699 ss
.jump_cycle_index
--;
3700 ss
.jump_cycles
[ss
.jump_cycle_index
] = cycle
;
3701 ss
.jump_cond
[ss
.jump_cycle_index
] = cond
;
3704 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3707 insn_set_clock (rtx insn
, int cycle
)
3709 unsigned uid
= INSN_UID (insn
);
3711 if (uid
>= INSN_INFO_LENGTH
)
3712 insn_info
.safe_grow (uid
* 5 / 4 + 10);
3714 INSN_INFO_ENTRY (uid
).clock
= cycle
;
3715 INSN_INFO_ENTRY (uid
).new_cond
= NULL
;
3716 INSN_INFO_ENTRY (uid
).reservation
= 0;
3717 INSN_INFO_ENTRY (uid
).ebb_start
= false;
3720 /* Return the clock cycle we set for the insn with uid UID. */
3722 insn_uid_get_clock (int uid
)
3724 return INSN_INFO_ENTRY (uid
).clock
;
3727 /* Return the clock cycle we set for INSN. */
3729 insn_get_clock (rtx insn
)
3731 return insn_uid_get_clock (INSN_UID (insn
));
3734 /* Examine INSN, and if it is a conditional jump of any kind, return
3735 the opposite of the condition in which it branches. Otherwise,
3738 condjump_opposite_condition (rtx insn
)
3740 rtx pat
= PATTERN (insn
);
3741 int icode
= INSN_CODE (insn
);
3744 if (icode
== CODE_FOR_br_true
|| icode
== CODE_FOR_br_false
)
3746 x
= XEXP (SET_SRC (pat
), 0);
3747 if (icode
== CODE_FOR_br_false
)
3750 if (GET_CODE (pat
) == COND_EXEC
)
3752 rtx t
= COND_EXEC_CODE (pat
);
3753 if ((GET_CODE (t
) == PARALLEL
3754 && GET_CODE (XVECEXP (t
, 0, 0)) == RETURN
)
3755 || (GET_CODE (t
) == UNSPEC
&& XINT (t
, 1) == UNSPEC_REAL_JUMP
)
3756 || (GET_CODE (t
) == SET
&& SET_DEST (t
) == pc_rtx
))
3757 x
= COND_EXEC_TEST (pat
);
3762 enum rtx_code code
= GET_CODE (x
);
3763 x
= gen_rtx_fmt_ee (code
== EQ
? NE
: EQ
,
3764 GET_MODE (x
), XEXP (x
, 0),
3770 /* Return true iff COND1 and COND2 are exactly opposite conditions
3771 one of them NE and the other EQ. */
3773 conditions_opposite_p (rtx cond1
, rtx cond2
)
3775 return (rtx_equal_p (XEXP (cond1
, 0), XEXP (cond2
, 0))
3776 && rtx_equal_p (XEXP (cond1
, 1), XEXP (cond2
, 1))
3777 && GET_CODE (cond1
) == reverse_condition (GET_CODE (cond2
)));
3780 /* Return true if we can add a predicate COND to INSN, or if INSN
3781 already has that predicate. If DOIT is true, also perform the
3784 predicate_insn (rtx insn
, rtx cond
, bool doit
)
3787 if (cond
== NULL_RTX
)
3793 if (get_attr_predicable (insn
) == PREDICABLE_YES
3794 && GET_CODE (PATTERN (insn
)) != COND_EXEC
)
3798 rtx newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3799 PATTERN (insn
) = newpat
;
3800 INSN_CODE (insn
) = -1;
3804 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
3805 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn
)), cond
))
3807 icode
= INSN_CODE (insn
);
3808 if (icode
== CODE_FOR_real_jump
3809 || icode
== CODE_FOR_jump
3810 || icode
== CODE_FOR_indirect_jump
)
3812 rtx pat
= PATTERN (insn
);
3813 rtx dest
= (icode
== CODE_FOR_real_jump
? XVECEXP (pat
, 0, 0)
3814 : icode
== CODE_FOR_jump
? XEXP (SET_SRC (pat
), 0)
3820 newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3822 newpat
= gen_br_true (cond
, XEXP (cond
, 0), dest
);
3823 PATTERN (insn
) = newpat
;
3824 INSN_CODE (insn
) = -1;
3828 if (INSN_CODE (insn
) == CODE_FOR_br_true
)
3830 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3831 return rtx_equal_p (br_cond
, cond
);
3833 if (INSN_CODE (insn
) == CODE_FOR_br_false
)
3835 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3836 return conditions_opposite_p (br_cond
, cond
);
3841 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3843 init_sched_state (c6x_sched_context_t sc
)
3845 sc
->last_scheduled_insn
= NULL_RTX
;
3846 sc
->last_scheduled_iter0
= NULL_RTX
;
3847 sc
->issued_this_cycle
= 0;
3848 memset (sc
->jump_cycles
, 0, sizeof sc
->jump_cycles
);
3849 memset (sc
->jump_cond
, 0, sizeof sc
->jump_cond
);
3850 sc
->jump_cycle_index
= 0;
3851 sc
->delays_finished_at
= 0;
3852 sc
->curr_sched_clock
= 0;
3854 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3856 memset (sc
->reg_n_accesses
, 0, sizeof sc
->reg_n_accesses
);
3857 memset (sc
->reg_n_xaccesses
, 0, sizeof sc
->reg_n_xaccesses
);
3858 memset (sc
->reg_set_in_cycle
, 0, sizeof sc
->reg_set_in_cycle
);
3860 state_reset (sc
->prev_cycle_state_ctx
);
3863 /* Allocate store for new scheduling context. */
3865 c6x_alloc_sched_context (void)
3867 return xmalloc (sizeof (struct c6x_sched_context
));
3870 /* If CLEAN_P is true then initializes _SC with clean data,
3871 and from the global context otherwise. */
3873 c6x_init_sched_context (void *_sc
, bool clean_p
)
3875 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3879 init_sched_state (sc
);
3884 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3885 memcpy (sc
->prev_cycle_state_ctx
, prev_cycle_state
, dfa_state_size
);
3889 /* Sets the global scheduling context to the one pointed to by _SC. */
3891 c6x_set_sched_context (void *_sc
)
3893 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3895 gcc_assert (sc
!= NULL
);
3897 memcpy (prev_cycle_state
, sc
->prev_cycle_state_ctx
, dfa_state_size
);
3900 /* Clear data in _SC. */
3902 c6x_clear_sched_context (void *_sc
)
3904 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3905 gcc_assert (_sc
!= NULL
);
3907 free (sc
->prev_cycle_state_ctx
);
3912 c6x_free_sched_context (void *_sc
)
3917 /* True if we are currently performing a preliminary scheduling
3918 pass before modulo scheduling; we can't allow the scheduler to
3919 modify instruction patterns using packetization assumptions,
3920 since there will be another scheduling pass later if modulo
3921 scheduling fails. */
3922 static bool in_hwloop
;
3924 /* Provide information about speculation capabilities, and set the
3925 DO_BACKTRACKING flag. */
3927 c6x_set_sched_flags (spec_info_t spec_info
)
3929 unsigned int *flags
= &(current_sched_info
->flags
);
3931 if (*flags
& SCHED_EBB
)
3933 *flags
|= DO_BACKTRACKING
| DO_PREDICATION
;
3936 *flags
|= DONT_BREAK_DEPENDENCIES
;
3938 spec_info
->mask
= 0;
3941 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3944 c6x_issue_rate (void)
3949 /* Used together with the collapse_ndfa option, this ensures that we reach a
3950 deterministic automaton state before trying to advance a cycle.
3951 With collapse_ndfa, genautomata creates advance cycle arcs only for
3952 such deterministic states. */
3955 c6x_sched_dfa_pre_cycle_insn (void)
3960 /* We're beginning a new block. Initialize data structures as necessary. */
3963 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED
,
3964 int sched_verbose ATTRIBUTE_UNUSED
,
3965 int max_ready ATTRIBUTE_UNUSED
)
3967 if (prev_cycle_state
== NULL
)
3969 prev_cycle_state
= xmalloc (dfa_state_size
);
3971 init_sched_state (&ss
);
3972 state_reset (prev_cycle_state
);
3975 /* We are about to being issuing INSN. Return nonzero if we cannot
3976 issue it on given cycle CLOCK and return zero if we should not sort
3977 the ready queue on the next clock start.
3978 For C6X, we use this function just to copy the previous DFA state
3979 for comparison purposes. */
3982 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED
, int verbose ATTRIBUTE_UNUSED
,
3983 rtx insn ATTRIBUTE_UNUSED
, int last_clock ATTRIBUTE_UNUSED
,
3984 int clock ATTRIBUTE_UNUSED
, int *sort_p ATTRIBUTE_UNUSED
)
3986 if (clock
!= last_clock
)
3987 memcpy (prev_cycle_state
, curr_state
, dfa_state_size
);
3992 c6x_mark_regno_read (int regno
, bool cross
)
3994 int t
= ++ss
.tmp_reg_n_accesses
[regno
];
3997 reg_access_stall
= true;
4001 int set_cycle
= ss
.reg_set_in_cycle
[regno
];
4002 /* This must be done in this way rather than by tweaking things in
4003 adjust_cost, since the stall occurs even for insns with opposite
4004 predicates, and the scheduler may not even see a dependency. */
4005 if (set_cycle
> 0 && set_cycle
== ss
.curr_sched_clock
)
4006 reg_access_stall
= true;
4007 /* This doesn't quite do anything yet as we're only modeling one
4009 ++ss
.tmp_reg_n_xaccesses
[regno
];
4013 /* Note that REG is read in the insn being examined. If CROSS, it
4014 means the access is through a cross path. Update the temporary reg
4015 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4016 in the current cycle. */
4019 c6x_mark_reg_read (rtx reg
, bool cross
)
4021 unsigned regno
= REGNO (reg
);
4022 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4025 c6x_mark_regno_read (regno
+ nregs
, cross
);
4028 /* Note that register REG is written in cycle CYCLES. */
4031 c6x_mark_reg_written (rtx reg
, int cycles
)
4033 unsigned regno
= REGNO (reg
);
4034 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4037 ss
.reg_set_in_cycle
[regno
+ nregs
] = cycles
;
4040 /* Update the register state information for an instruction whose
4041 body is X. Return true if the instruction has to be delayed until the
4045 c6x_registers_update (rtx insn
)
4047 enum attr_cross cross
;
4048 enum attr_dest_regfile destrf
;
4052 if (!reload_completed
|| recog_memoized (insn
) < 0)
4055 reg_access_stall
= false;
4056 memcpy (ss
.tmp_reg_n_accesses
, ss
.reg_n_accesses
,
4057 sizeof ss
.tmp_reg_n_accesses
);
4058 memcpy (ss
.tmp_reg_n_xaccesses
, ss
.reg_n_xaccesses
,
4059 sizeof ss
.tmp_reg_n_xaccesses
);
4061 extract_insn (insn
);
4063 cross
= get_attr_cross (insn
);
4064 destrf
= get_attr_dest_regfile (insn
);
4066 nops
= recog_data
.n_operands
;
4068 if (GET_CODE (x
) == COND_EXEC
)
4070 c6x_mark_reg_read (XEXP (XEXP (x
, 0), 0), false);
4074 for (i
= 0; i
< nops
; i
++)
4076 rtx op
= recog_data
.operand
[i
];
4077 if (recog_data
.operand_type
[i
] == OP_OUT
)
4081 bool this_cross
= cross
;
4082 if (destrf
== DEST_REGFILE_A
&& A_REGNO_P (REGNO (op
)))
4084 if (destrf
== DEST_REGFILE_B
&& B_REGNO_P (REGNO (op
)))
4086 c6x_mark_reg_read (op
, this_cross
);
4088 else if (MEM_P (op
))
4091 switch (GET_CODE (op
))
4100 c6x_mark_reg_read (op
, false);
4105 gcc_assert (GET_CODE (op
) == PLUS
);
4108 c6x_mark_reg_read (XEXP (op
, 0), false);
4109 if (REG_P (XEXP (op
, 1)))
4110 c6x_mark_reg_read (XEXP (op
, 1), false);
4115 c6x_mark_regno_read (REG_B14
, false);
4121 else if (!CONSTANT_P (op
) && strlen (recog_data
.constraints
[i
]) > 0)
4124 return reg_access_stall
;
4127 /* Helper function for the TARGET_SCHED_REORDER and
4128 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4129 in the current cycle, move it down in the ready list and return the
4130 number of non-unsafe insns. */
4133 c6x_sched_reorder_1 (rtx
*ready
, int *pn_ready
, int clock_var
)
4135 int n_ready
= *pn_ready
;
4136 rtx
*e_ready
= ready
+ n_ready
;
4140 /* Keep track of conflicts due to a limit number of register accesses,
4141 and due to stalls incurred by too early accesses of registers using
4144 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4147 int icode
= recog_memoized (insn
);
4148 bool is_asm
= (icode
< 0
4149 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4150 || asm_noperands (PATTERN (insn
)) >= 0));
4151 bool no_parallel
= (is_asm
|| icode
== CODE_FOR_sploop
4153 && get_attr_type (insn
) == TYPE_ATOMIC
));
4155 /* We delay asm insns until all delay slots are exhausted. We can't
4156 accurately tell how many cycles an asm takes, and the main scheduling
4157 code always assumes at least 1 cycle, which may be wrong. */
4159 && (ss
.issued_this_cycle
> 0 || clock_var
< ss
.delays_finished_at
))
4160 || c6x_registers_update (insn
)
4161 || (ss
.issued_this_cycle
> 0 && icode
== CODE_FOR_sploop
))
4163 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4168 else if (shadow_p (insn
))
4170 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4175 /* Ensure that no other jump is scheduled in jump delay slots, since
4176 it would put the machine into the wrong state. Also, we must
4177 avoid scheduling insns that have a latency longer than the
4178 remaining jump delay slots, as the code at the jump destination
4179 won't be prepared for it.
4181 However, we can relax this condition somewhat. The rest of the
4182 scheduler will automatically avoid scheduling an insn on which
4183 the jump shadow depends so late that its side effect happens
4184 after the jump. This means that if we see an insn with a longer
4185 latency here, it can safely be scheduled if we can ensure that it
4186 has a predicate opposite of the previous jump: the side effect
4187 will happen in what we think of as the same basic block. In
4188 c6x_variable_issue, we will record the necessary predicate in
4189 new_conditions, and after scheduling is finished, we will modify
4192 Special care must be taken whenever there is more than one jump
4195 first_jump
= first_jump_index (clock_var
);
4196 if (first_jump
!= -1)
4198 int first_cycle
= get_jump_cycle (first_jump
);
4199 rtx first_cond
= get_jump_cond (first_jump
);
4200 int second_cycle
= 0;
4203 second_cycle
= get_jump_cycle (first_jump
- 1);
4205 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4208 int icode
= recog_memoized (insn
);
4209 bool is_asm
= (icode
< 0
4210 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4211 || asm_noperands (PATTERN (insn
)) >= 0));
4212 int this_cycles
, rsrv_cycles
;
4213 enum attr_type type
;
4215 gcc_assert (!is_asm
);
4218 this_cycles
= get_attr_cycles (insn
);
4219 rsrv_cycles
= get_attr_reserve_cycles (insn
);
4220 type
= get_attr_type (insn
);
4221 /* Treat branches specially; there is also a hazard if two jumps
4222 end at the same cycle. */
4223 if (type
== TYPE_BRANCH
|| type
== TYPE_CALL
)
4225 if (clock_var
+ this_cycles
<= first_cycle
)
4227 if ((first_jump
> 0 && clock_var
+ this_cycles
> second_cycle
)
4228 || clock_var
+ rsrv_cycles
> first_cycle
4229 || !predicate_insn (insn
, first_cond
, false))
4231 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4242 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4243 for later and clear the register access information for the new
4244 cycle. We also move asm statements out of the way if they would be
4245 scheduled in a delay slot. */
4248 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED
,
4249 int sched_verbose ATTRIBUTE_UNUSED
,
4250 rtx
*ready ATTRIBUTE_UNUSED
,
4251 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4253 ss
.curr_sched_clock
= clock_var
;
4254 ss
.issued_this_cycle
= 0;
4255 memset (ss
.reg_n_accesses
, 0, sizeof ss
.reg_n_accesses
);
4256 memset (ss
.reg_n_xaccesses
, 0, sizeof ss
.reg_n_xaccesses
);
4261 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4264 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4265 cycle for every insn. */
4268 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED
,
4269 int sched_verbose ATTRIBUTE_UNUSED
,
4270 rtx
*ready ATTRIBUTE_UNUSED
,
4271 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4273 /* FIXME: the assembler rejects labels inside an execute packet.
4274 This can occur if prologue insns are scheduled in parallel with
4275 others, so we avoid this here. Also make sure that nothing is
4276 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4277 if (RTX_FRAME_RELATED_P (ss
.last_scheduled_insn
)
4278 || JUMP_P (ss
.last_scheduled_insn
)
4279 || (recog_memoized (ss
.last_scheduled_insn
) >= 0
4280 && get_attr_type (ss
.last_scheduled_insn
) == TYPE_ATOMIC
))
4282 int n_ready
= *pn_ready
;
4283 rtx
*e_ready
= ready
+ n_ready
;
4286 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4289 if (!shadow_p (insn
))
4291 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4300 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4303 /* Subroutine of maybe_clobber_cond, called through note_stores. */
4306 clobber_cond_1 (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
, void *data1
)
4308 rtx
*cond
= (rtx
*)data1
;
4309 if (*cond
!= NULL_RTX
&& reg_overlap_mentioned_p (x
, *cond
))
4313 /* Examine INSN, and if it destroys the conditions have recorded for
4314 any of the jumps in flight, clear that condition so that we don't
4315 predicate any more insns. CLOCK_VAR helps us limit the search to
4316 only those jumps which are still in flight. */
4319 maybe_clobber_cond (rtx insn
, int clock_var
)
4322 idx
= ss
.jump_cycle_index
;
4323 for (n
= 0; n
< 12; n
++, idx
++)
4330 cycle
= ss
.jump_cycles
[idx
];
4331 if (cycle
<= clock_var
)
4334 cond
= ss
.jump_cond
[idx
];
4335 if (cond
== NULL_RTX
)
4340 ss
.jump_cond
[idx
] = NULL_RTX
;
4344 note_stores (PATTERN (insn
), clobber_cond_1
, ss
.jump_cond
+ idx
);
4345 for (link
= REG_NOTES (insn
); link
; link
= XEXP (link
, 1))
4346 if (REG_NOTE_KIND (link
) == REG_INC
)
4347 clobber_cond_1 (XEXP (link
, 0), NULL_RTX
, ss
.jump_cond
+ idx
);
4351 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4352 issue INSN. Return the number of insns left on the ready queue
4353 that can be issued this cycle.
4354 We use this hook to record clock cycles and reservations for every insn. */
4357 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED
,
4358 int sched_verbose ATTRIBUTE_UNUSED
,
4359 rtx insn
, int can_issue_more ATTRIBUTE_UNUSED
)
4361 ss
.last_scheduled_insn
= insn
;
4362 if (INSN_UID (insn
) < sploop_max_uid_iter0
&& !JUMP_P (insn
))
4363 ss
.last_scheduled_iter0
= insn
;
4364 if (GET_CODE (PATTERN (insn
)) != USE
&& GET_CODE (PATTERN (insn
)) != CLOBBER
)
4365 ss
.issued_this_cycle
++;
4366 if (insn_info
.exists ())
4368 state_t st_after
= alloca (dfa_state_size
);
4369 int curr_clock
= ss
.curr_sched_clock
;
4370 int uid
= INSN_UID (insn
);
4371 int icode
= recog_memoized (insn
);
4373 int first
, first_cycle
;
4377 insn_set_clock (insn
, curr_clock
);
4378 INSN_INFO_ENTRY (uid
).ebb_start
4379 = curr_clock
== 0 && ss
.issued_this_cycle
== 1;
4381 first
= first_jump_index (ss
.curr_sched_clock
);
4385 first_cond
= NULL_RTX
;
4389 first_cycle
= get_jump_cycle (first
);
4390 first_cond
= get_jump_cond (first
);
4393 && first_cycle
> curr_clock
4394 && first_cond
!= NULL_RTX
4395 && (curr_clock
+ get_attr_cycles (insn
) > first_cycle
4396 || get_attr_type (insn
) == TYPE_BRANCH
4397 || get_attr_type (insn
) == TYPE_CALL
))
4398 INSN_INFO_ENTRY (uid
).new_cond
= first_cond
;
4400 memcpy (st_after
, curr_state
, dfa_state_size
);
4401 state_transition (st_after
, const0_rtx
);
4404 for (i
= 0; i
< 2 * UNIT_QID_SIDE_OFFSET
; i
++)
4405 if (cpu_unit_reservation_p (st_after
, c6x_unit_codes
[i
])
4406 && !cpu_unit_reservation_p (prev_cycle_state
, c6x_unit_codes
[i
]))
4408 INSN_INFO_ENTRY (uid
).unit_mask
= mask
;
4410 maybe_clobber_cond (insn
, curr_clock
);
4416 c6x_registers_update (insn
);
4417 memcpy (ss
.reg_n_accesses
, ss
.tmp_reg_n_accesses
,
4418 sizeof ss
.reg_n_accesses
);
4419 memcpy (ss
.reg_n_xaccesses
, ss
.tmp_reg_n_accesses
,
4420 sizeof ss
.reg_n_xaccesses
);
4422 cycles
= get_attr_cycles (insn
);
4423 if (ss
.delays_finished_at
< ss
.curr_sched_clock
+ cycles
)
4424 ss
.delays_finished_at
= ss
.curr_sched_clock
+ cycles
;
4425 if (get_attr_type (insn
) == TYPE_BRANCH
4426 || get_attr_type (insn
) == TYPE_CALL
)
4428 rtx opposite
= condjump_opposite_condition (insn
);
4429 record_jump (ss
.curr_sched_clock
+ cycles
, opposite
);
4432 /* Mark the cycles in which the destination registers are written.
4433 This is used for calculating stalls when using cross units. */
4434 extract_insn (insn
);
4435 /* Cross-path stalls don't apply to results of load insns. */
4436 if (get_attr_type (insn
) == TYPE_LOAD
4437 || get_attr_type (insn
) == TYPE_LOADN
4438 || get_attr_type (insn
) == TYPE_LOAD_SHADOW
)
4440 for (i
= 0; i
< recog_data
.n_operands
; i
++)
4442 rtx op
= recog_data
.operand
[i
];
4445 rtx addr
= XEXP (op
, 0);
4446 if (GET_RTX_CLASS (GET_CODE (addr
)) == RTX_AUTOINC
)
4447 c6x_mark_reg_written (XEXP (addr
, 0),
4448 insn_uid_get_clock (uid
) + 1);
4450 if (recog_data
.operand_type
[i
] != OP_IN
4453 c6x_mark_reg_written (op
,
4454 insn_uid_get_clock (uid
) + cycles
);
4459 return can_issue_more
;
4462 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4463 anti- and output dependencies. */
4466 c6x_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
4468 enum attr_type insn_type
= TYPE_UNKNOWN
, dep_insn_type
= TYPE_UNKNOWN
;
4469 int dep_insn_code_number
, insn_code_number
;
4470 int shadow_bonus
= 0;
4472 dep_insn_code_number
= recog_memoized (dep_insn
);
4473 insn_code_number
= recog_memoized (insn
);
4475 if (dep_insn_code_number
>= 0)
4476 dep_insn_type
= get_attr_type (dep_insn
);
4478 if (insn_code_number
>= 0)
4479 insn_type
= get_attr_type (insn
);
4481 kind
= REG_NOTE_KIND (link
);
4484 /* If we have a dependency on a load, and it's not for the result of
4485 the load, it must be for an autoincrement. Reduce the cost in that
4487 if (dep_insn_type
== TYPE_LOAD
)
4489 rtx set
= PATTERN (dep_insn
);
4490 if (GET_CODE (set
) == COND_EXEC
)
4491 set
= COND_EXEC_CODE (set
);
4492 if (GET_CODE (set
) == UNSPEC
)
4496 gcc_assert (GET_CODE (set
) == SET
);
4497 if (!reg_overlap_mentioned_p (SET_DEST (set
), PATTERN (insn
)))
4503 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4504 it occurs in between two cycles, but we schedule it at the end of the
4506 if (shadow_type_p (insn_type
))
4509 /* Anti and output dependencies usually have zero cost, but we want
4510 to insert a stall after a jump, and after certain floating point
4511 insns that take more than one cycle to read their inputs. In the
4512 future, we should try to find a better algorithm for scheduling
4516 /* We can get anti-dependencies against shadow insns. Treat these
4517 like output dependencies, so that the insn is entirely finished
4518 before the branch takes place. */
4519 if (kind
== REG_DEP_ANTI
&& insn_type
== TYPE_SHADOW
)
4520 kind
= REG_DEP_OUTPUT
;
4521 switch (dep_insn_type
)
4527 if (get_attr_has_shadow (dep_insn
) == HAS_SHADOW_Y
)
4528 /* This is a real_jump/real_call insn. These don't have
4529 outputs, and ensuring the validity of scheduling things
4530 in the delay slot is the job of
4531 c6x_sched_reorder_1. */
4533 /* Unsplit calls can happen - e.g. for divide insns. */
4538 if (kind
== REG_DEP_OUTPUT
)
4539 return 5 - shadow_bonus
;
4543 if (kind
== REG_DEP_OUTPUT
)
4544 return 4 - shadow_bonus
;
4547 if (kind
== REG_DEP_OUTPUT
)
4548 return 2 - shadow_bonus
;
4551 if (kind
== REG_DEP_OUTPUT
)
4552 return 2 - shadow_bonus
;
4556 if (kind
== REG_DEP_OUTPUT
)
4557 return 7 - shadow_bonus
;
4560 if (kind
== REG_DEP_OUTPUT
)
4561 return 5 - shadow_bonus
;
4564 if (kind
== REG_DEP_OUTPUT
)
4565 return 9 - shadow_bonus
;
4569 if (kind
== REG_DEP_OUTPUT
)
4570 return 10 - shadow_bonus
;
4574 if (insn_type
== TYPE_SPKERNEL
)
4576 if (kind
== REG_DEP_OUTPUT
)
4577 return 1 - shadow_bonus
;
4583 return cost
- shadow_bonus
;
4586 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4587 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4588 first in the original stream. */
4591 gen_one_bundle (rtx
*slot
, int n_filled
, int real_first
)
4597 bundle
= gen_rtx_SEQUENCE (VOIDmode
, gen_rtvec_v (n_filled
, slot
));
4598 bundle
= make_insn_raw (bundle
);
4599 BLOCK_FOR_INSN (bundle
) = BLOCK_FOR_INSN (slot
[0]);
4600 INSN_LOCATION (bundle
) = INSN_LOCATION (slot
[0]);
4601 PREV_INSN (bundle
) = PREV_INSN (slot
[real_first
]);
4605 for (i
= 0; i
< n_filled
; i
++)
4609 PREV_INSN (insn
) = t
? t
: PREV_INSN (bundle
);
4611 NEXT_INSN (t
) = insn
;
4614 INSN_LOCATION (slot
[i
]) = INSN_LOCATION (bundle
);
4617 NEXT_INSN (bundle
) = NEXT_INSN (PREV_INSN (bundle
));
4618 NEXT_INSN (t
) = NEXT_INSN (bundle
);
4619 NEXT_INSN (PREV_INSN (bundle
)) = bundle
;
4620 PREV_INSN (NEXT_INSN (bundle
)) = bundle
;
4623 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4624 try to insert labels in the middle. */
4627 c6x_gen_bundles (void)
4630 rtx insn
, next
, last_call
;
4635 /* The machine is eight insns wide. We can have up to six shadow
4636 insns, plus an extra slot for merging the jump shadow. */
4641 for (insn
= BB_HEAD (bb
);; insn
= next
)
4644 rtx delete_this
= NULL_RTX
;
4646 if (NONDEBUG_INSN_P (insn
))
4648 /* Put calls at the start of the sequence. */
4654 memmove (&slot
[1], &slot
[0],
4655 n_filled
* sizeof (slot
[0]));
4657 if (!shadow_p (insn
))
4659 PUT_MODE (insn
, TImode
);
4661 PUT_MODE (slot
[1], VOIDmode
);
4668 slot
[n_filled
++] = insn
;
4672 next
= NEXT_INSN (insn
);
4673 while (next
&& insn
!= BB_END (bb
)
4674 && !(NONDEBUG_INSN_P (next
)
4675 && GET_CODE (PATTERN (next
)) != USE
4676 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4679 next
= NEXT_INSN (insn
);
4682 at_end
= insn
== BB_END (bb
);
4683 if (delete_this
== NULL_RTX
4684 && (at_end
|| (GET_MODE (next
) == TImode
4685 && !(shadow_p (next
) && CALL_P (next
)))))
4688 gen_one_bundle (slot
, n_filled
, first_slot
);
4697 /* Bundling, and emitting nops, can separate
4698 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4700 last_call
= NULL_RTX
;
4701 for (insn
= get_insns (); insn
; insn
= next
)
4703 next
= NEXT_INSN (insn
);
4705 || (INSN_P (insn
) && GET_CODE (PATTERN (insn
)) == SEQUENCE
4706 && CALL_P (XVECEXP (PATTERN (insn
), 0, 0))))
4708 if (!NOTE_P (insn
) || NOTE_KIND (insn
) != NOTE_INSN_CALL_ARG_LOCATION
)
4710 if (NEXT_INSN (last_call
) == insn
)
4712 NEXT_INSN (PREV_INSN (insn
)) = NEXT_INSN (insn
);
4713 PREV_INSN (NEXT_INSN (insn
)) = PREV_INSN (insn
);
4714 PREV_INSN (insn
) = last_call
;
4715 NEXT_INSN (insn
) = NEXT_INSN (last_call
);
4716 PREV_INSN (NEXT_INSN (insn
)) = insn
;
4717 NEXT_INSN (PREV_INSN (insn
)) = insn
;
4722 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4725 emit_nop_after (int cycles
, rtx after
)
4729 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4730 operation. We don't need the extra NOP since in this case, the hardware
4731 will automatically insert the required stall. */
4735 gcc_assert (cycles
< 10);
4737 insn
= emit_insn_after (gen_nop_count (GEN_INT (cycles
)), after
);
4738 PUT_MODE (insn
, TImode
);
4743 /* Determine whether INSN is a call that needs to have a return label
4747 returning_call_p (rtx insn
)
4750 return (!SIBLING_CALL_P (insn
)
4751 && get_attr_type (insn
) != TYPE_CALLP
4752 && get_attr_type (insn
) != TYPE_SHADOW
);
4753 if (recog_memoized (insn
) < 0)
4755 if (get_attr_type (insn
) == TYPE_CALL
)
4760 /* Determine whether INSN's pattern can be converted to use callp. */
4762 can_use_callp (rtx insn
)
4764 int icode
= recog_memoized (insn
);
4765 if (!TARGET_INSNS_64PLUS
4767 || GET_CODE (PATTERN (insn
)) == COND_EXEC
)
4770 return ((icode
== CODE_FOR_real_call
4771 || icode
== CODE_FOR_call_internal
4772 || icode
== CODE_FOR_call_value_internal
)
4773 && get_attr_dest_regfile (insn
) == DEST_REGFILE_ANY
);
4776 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4778 convert_to_callp (rtx insn
)
4781 extract_insn (insn
);
4782 if (GET_CODE (PATTERN (insn
)) == SET
)
4784 rtx dest
= recog_data
.operand
[0];
4785 lab
= recog_data
.operand
[1];
4786 PATTERN (insn
) = gen_callp_value (dest
, lab
);
4787 INSN_CODE (insn
) = CODE_FOR_callp_value
;
4791 lab
= recog_data
.operand
[0];
4792 PATTERN (insn
) = gen_callp (lab
);
4793 INSN_CODE (insn
) = CODE_FOR_callp
;
4797 /* Scan forwards from INSN until we find the next insn that has mode TImode
4798 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4799 Return it if we find such an insn, NULL_RTX otherwise. */
4801 find_next_cycle_insn (rtx insn
, int clock
)
4804 if (GET_MODE (t
) == TImode
)
4805 t
= next_real_insn (t
);
4806 while (t
&& GET_MODE (t
) != TImode
)
4807 t
= next_real_insn (t
);
4809 if (t
&& insn_get_clock (t
) == clock
)
4814 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4815 around PAT. Return PAT either unchanged or modified in this
4818 duplicate_cond (rtx pat
, rtx cond_insn
)
4820 rtx cond_pat
= PATTERN (cond_insn
);
4821 if (GET_CODE (cond_pat
) == COND_EXEC
)
4822 pat
= gen_rtx_COND_EXEC (VOIDmode
, copy_rtx (COND_EXEC_TEST (cond_pat
)),
4827 /* Walk forward from INSN to find the last insn that issues in the same clock
4830 find_last_same_clock (rtx insn
)
4833 rtx t
= next_real_insn (insn
);
4835 while (t
&& GET_MODE (t
) != TImode
)
4837 if (!DEBUG_INSN_P (t
) && recog_memoized (t
) >= 0)
4839 t
= next_real_insn (t
);
4844 /* For every call insn in the function, emit code to load the return
4845 address. For each call we create a return label and store it in
4846 CALL_LABELS. If are not scheduling, we emit the labels here,
4847 otherwise the caller will do it later.
4848 This function is called after final insn scheduling, but before creating
4849 the SEQUENCEs that represent execute packets. */
4852 reorg_split_calls (rtx
*call_labels
)
4854 unsigned int reservation_mask
= 0;
4855 rtx insn
= get_insns ();
4856 gcc_assert (NOTE_P (insn
));
4857 insn
= next_real_insn (insn
);
4861 rtx next
= next_real_insn (insn
);
4863 if (DEBUG_INSN_P (insn
))
4866 if (GET_MODE (insn
) == TImode
)
4867 reservation_mask
= 0;
4868 uid
= INSN_UID (insn
);
4869 if (c6x_flag_schedule_insns2
&& recog_memoized (insn
) >= 0)
4870 reservation_mask
|= 1 << INSN_INFO_ENTRY (uid
).reservation
;
4872 if (returning_call_p (insn
))
4874 rtx label
= gen_label_rtx ();
4875 rtx labelref
= gen_rtx_LABEL_REF (Pmode
, label
);
4876 rtx reg
= gen_rtx_REG (SImode
, RETURN_ADDR_REGNO
);
4878 LABEL_NUSES (label
) = 2;
4879 if (!c6x_flag_schedule_insns2
)
4881 if (can_use_callp (insn
))
4882 convert_to_callp (insn
);
4887 emit_label_after (label
, insn
);
4889 /* Bundle the call and its delay slots into a single
4890 SEQUENCE. While these do not issue in parallel
4891 we need to group them into a single EH region. */
4893 PUT_MODE (insn
, TImode
);
4894 if (TARGET_INSNS_64
)
4896 t
= gen_addkpc (reg
, labelref
, GEN_INT (4));
4897 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4899 PUT_MODE (slot
[1], TImode
);
4900 gen_one_bundle (slot
, 2, 0);
4904 slot
[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4906 PUT_MODE (slot
[3], TImode
);
4907 t
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4908 slot
[2] = emit_insn_after (duplicate_cond (t
, insn
),
4910 PUT_MODE (slot
[2], TImode
);
4911 t
= gen_movsi_high (reg
, labelref
);
4912 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4914 PUT_MODE (slot
[1], TImode
);
4915 gen_one_bundle (slot
, 4, 0);
4921 /* If we scheduled, we reserved the .S2 unit for one or two
4922 cycles after the call. Emit the insns in these slots,
4923 unless it's possible to create a CALLP insn.
4924 Note that this works because the dependencies ensure that
4925 no insn setting/using B3 is scheduled in the delay slots of
4927 int this_clock
= insn_get_clock (insn
);
4928 rtx last_same_clock
;
4931 call_labels
[INSN_UID (insn
)] = label
;
4933 last_same_clock
= find_last_same_clock (insn
);
4935 if (can_use_callp (insn
))
4937 /* Find the first insn of the next execute packet. If it
4938 is the shadow insn corresponding to this call, we may
4939 use a CALLP insn. */
4940 rtx shadow
= next_nonnote_nondebug_insn (last_same_clock
);
4943 && insn_get_clock (shadow
) == this_clock
+ 5)
4945 convert_to_callp (shadow
);
4946 insn_set_clock (shadow
, this_clock
);
4947 INSN_INFO_ENTRY (INSN_UID (shadow
)).reservation
4949 INSN_INFO_ENTRY (INSN_UID (shadow
)).unit_mask
4950 = INSN_INFO_ENTRY (INSN_UID (last_same_clock
)).unit_mask
;
4951 if (GET_MODE (insn
) == TImode
)
4953 rtx new_cycle_first
= NEXT_INSN (insn
);
4954 while (!NONDEBUG_INSN_P (new_cycle_first
)
4955 || GET_CODE (PATTERN (new_cycle_first
)) == USE
4956 || GET_CODE (PATTERN (new_cycle_first
)) == CLOBBER
)
4957 new_cycle_first
= NEXT_INSN (new_cycle_first
);
4958 PUT_MODE (new_cycle_first
, TImode
);
4959 if (new_cycle_first
!= shadow
)
4960 PUT_MODE (shadow
, VOIDmode
);
4961 INSN_INFO_ENTRY (INSN_UID (new_cycle_first
)).ebb_start
4962 = INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
;
4965 PUT_MODE (shadow
, VOIDmode
);
4970 after1
= find_next_cycle_insn (last_same_clock
, this_clock
+ 1);
4971 if (after1
== NULL_RTX
)
4972 after1
= last_same_clock
;
4974 after1
= find_last_same_clock (after1
);
4975 if (TARGET_INSNS_64
)
4977 rtx x1
= gen_addkpc (reg
, labelref
, const0_rtx
);
4978 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
4979 insn_set_clock (x1
, this_clock
+ 1);
4980 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
4981 if (after1
== last_same_clock
)
4982 PUT_MODE (x1
, TImode
);
4984 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
4985 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
4990 rtx after2
= find_next_cycle_insn (after1
, this_clock
+ 2);
4991 if (after2
== NULL_RTX
)
4993 x2
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4994 x2
= emit_insn_after (duplicate_cond (x2
, insn
), after2
);
4995 x1
= gen_movsi_high (reg
, labelref
);
4996 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
4997 insn_set_clock (x1
, this_clock
+ 1);
4998 insn_set_clock (x2
, this_clock
+ 2);
4999 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5000 INSN_INFO_ENTRY (INSN_UID (x2
)).reservation
= RESERVATION_S2
;
5001 if (after1
== last_same_clock
)
5002 PUT_MODE (x1
, TImode
);
5004 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5005 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5006 if (after1
== after2
)
5007 PUT_MODE (x2
, TImode
);
5009 INSN_INFO_ENTRY (INSN_UID (x2
)).unit_mask
5010 = INSN_INFO_ENTRY (INSN_UID (after2
)).unit_mask
;
5019 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
5020 insns as required for correctness. CALL_LABELS is the array that
5021 holds the return labels for call insns; we emit these here if
5022 scheduling was run earlier. */
5025 reorg_emit_nops (rtx
*call_labels
)
5028 rtx prev
, last_call
;
5029 int prev_clock
, earliest_bb_end
;
5030 int prev_implicit_nops
;
5031 rtx insn
= get_insns ();
5033 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5034 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5035 clocks, we must insert a NOP.
5036 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5037 current basic block will finish. We must not allow the next basic block to
5038 begin before this cycle.
5039 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5040 a multi-cycle nop. The code is scheduled such that subsequent insns will
5041 show the cycle gap, but we needn't insert a real NOP instruction. */
5042 insn
= next_real_insn (insn
);
5043 last_call
= prev
= NULL_RTX
;
5045 earliest_bb_end
= 0;
5046 prev_implicit_nops
= 0;
5050 int this_clock
= -1;
5054 next
= next_real_insn (insn
);
5056 if (DEBUG_INSN_P (insn
)
5057 || GET_CODE (PATTERN (insn
)) == USE
5058 || GET_CODE (PATTERN (insn
)) == CLOBBER
5059 || shadow_or_blockage_p (insn
)
5060 || JUMP_TABLE_DATA_P (insn
))
5063 if (!c6x_flag_schedule_insns2
)
5064 /* No scheduling; ensure that no parallel issue happens. */
5065 PUT_MODE (insn
, TImode
);
5070 this_clock
= insn_get_clock (insn
);
5071 if (this_clock
!= prev_clock
)
5073 PUT_MODE (insn
, TImode
);
5077 cycles
= this_clock
- prev_clock
;
5079 cycles
-= prev_implicit_nops
;
5082 rtx nop
= emit_nop_after (cycles
- 1, prev
);
5083 insn_set_clock (nop
, prev_clock
+ prev_implicit_nops
+ 1);
5086 prev_clock
= this_clock
;
5089 && insn_get_clock (last_call
) + 6 <= this_clock
)
5091 emit_label_before (call_labels
[INSN_UID (last_call
)], insn
);
5092 last_call
= NULL_RTX
;
5094 prev_implicit_nops
= 0;
5098 /* Examine how many cycles the current insn takes, and adjust
5099 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5100 if (recog_memoized (insn
) >= 0
5101 /* If not scheduling, we've emitted NOPs after calls already. */
5102 && (c6x_flag_schedule_insns2
|| !returning_call_p (insn
)))
5104 max_cycles
= get_attr_cycles (insn
);
5105 if (get_attr_type (insn
) == TYPE_CALLP
)
5106 prev_implicit_nops
= 5;
5110 if (returning_call_p (insn
))
5113 if (c6x_flag_schedule_insns2
)
5115 gcc_assert (this_clock
>= 0);
5116 if (earliest_bb_end
< this_clock
+ max_cycles
)
5117 earliest_bb_end
= this_clock
+ max_cycles
;
5119 else if (max_cycles
> 1)
5120 emit_nop_after (max_cycles
- 1, insn
);
5126 if (c6x_flag_schedule_insns2
5127 && (next
== NULL_RTX
5128 || (GET_MODE (next
) == TImode
5129 && INSN_INFO_ENTRY (INSN_UID (next
)).ebb_start
))
5130 && earliest_bb_end
> 0)
5132 int cycles
= earliest_bb_end
- prev_clock
;
5135 prev
= emit_nop_after (cycles
- 1, prev
);
5136 insn_set_clock (prev
, prev_clock
+ prev_implicit_nops
+ 1);
5138 earliest_bb_end
= 0;
5143 emit_label_after (call_labels
[INSN_UID (last_call
)], prev
);
5144 last_call
= NULL_RTX
;
5150 /* If possible, split INSN, which we know is either a jump or a call, into a real
5151 insn and its shadow. */
5153 split_delayed_branch (rtx insn
)
5155 int code
= recog_memoized (insn
);
5157 rtx pat
= PATTERN (insn
);
5159 if (GET_CODE (pat
) == COND_EXEC
)
5160 pat
= COND_EXEC_CODE (pat
);
5164 rtx src
= pat
, dest
= NULL_RTX
;
5166 if (GET_CODE (pat
) == SET
)
5168 dest
= SET_DEST (pat
);
5169 src
= SET_SRC (pat
);
5171 callee
= XEXP (XEXP (src
, 0), 0);
5172 if (SIBLING_CALL_P (insn
))
5175 newpat
= gen_indirect_sibcall_shadow ();
5177 newpat
= gen_sibcall_shadow (callee
);
5178 pat
= gen_real_jump (callee
);
5180 else if (dest
!= NULL_RTX
)
5183 newpat
= gen_indirect_call_value_shadow (dest
);
5185 newpat
= gen_call_value_shadow (dest
, callee
);
5186 pat
= gen_real_call (callee
);
5191 newpat
= gen_indirect_call_shadow ();
5193 newpat
= gen_call_shadow (callee
);
5194 pat
= gen_real_call (callee
);
5196 pat
= duplicate_cond (pat
, insn
);
5197 newpat
= duplicate_cond (newpat
, insn
);
5202 if (GET_CODE (pat
) == PARALLEL
5203 && GET_CODE (XVECEXP (pat
, 0, 0)) == RETURN
)
5205 newpat
= gen_return_shadow ();
5206 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5207 newpat
= duplicate_cond (newpat
, insn
);
5212 case CODE_FOR_br_true
:
5213 case CODE_FOR_br_false
:
5214 src
= SET_SRC (pat
);
5215 op
= XEXP (src
, code
== CODE_FOR_br_true
? 1 : 2);
5216 newpat
= gen_condjump_shadow (op
);
5217 pat
= gen_real_jump (op
);
5218 if (code
== CODE_FOR_br_true
)
5219 pat
= gen_rtx_COND_EXEC (VOIDmode
, XEXP (src
, 0), pat
);
5221 pat
= gen_rtx_COND_EXEC (VOIDmode
,
5222 reversed_comparison (XEXP (src
, 0),
5229 newpat
= gen_jump_shadow (op
);
5232 case CODE_FOR_indirect_jump
:
5233 newpat
= gen_indirect_jump_shadow ();
5236 case CODE_FOR_return_internal
:
5237 newpat
= gen_return_shadow ();
5238 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5245 i1
= emit_insn_before (pat
, insn
);
5246 PATTERN (insn
) = newpat
;
5247 INSN_CODE (insn
) = -1;
5248 record_delay_slot_pair (i1
, insn
, 5, 0);
5251 /* If INSN is a multi-cycle insn that should be handled properly in
5252 modulo-scheduling, split it into a real insn and a shadow.
5253 Return true if we made a change.
5255 It is valid for us to fail to split an insn; the caller has to deal
5256 with the possibility. Currently we handle loads and most mpy2 and
5259 split_delayed_nonbranch (rtx insn
)
5261 int code
= recog_memoized (insn
);
5262 enum attr_type type
;
5263 rtx i1
, newpat
, src
, dest
;
5264 rtx pat
= PATTERN (insn
);
5268 if (GET_CODE (pat
) == COND_EXEC
)
5269 pat
= COND_EXEC_CODE (pat
);
5271 if (code
< 0 || GET_CODE (pat
) != SET
)
5273 src
= SET_SRC (pat
);
5274 dest
= SET_DEST (pat
);
5278 type
= get_attr_type (insn
);
5280 && (type
== TYPE_LOAD
5281 || type
== TYPE_LOADN
))
5284 && (GET_CODE (src
) != ZERO_EXTEND
5285 || !MEM_P (XEXP (src
, 0))))
5288 if (GET_MODE_SIZE (GET_MODE (dest
)) > 4
5289 && (GET_MODE_SIZE (GET_MODE (dest
)) != 8 || !TARGET_LDDW
))
5292 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5294 newpat
= gen_load_shadow (SET_DEST (pat
));
5295 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_LOAD
);
5299 && (type
== TYPE_MPY2
5300 || type
== TYPE_MPY4
))
5302 /* We don't handle floating point multiplies yet. */
5303 if (GET_MODE (dest
) == SFmode
)
5306 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5308 newpat
= gen_mult_shadow (SET_DEST (pat
));
5309 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_MULT
);
5310 delay
= type
== TYPE_MPY2
? 1 : 3;
5315 pat
= duplicate_cond (pat
, insn
);
5316 newpat
= duplicate_cond (newpat
, insn
);
5317 i1
= emit_insn_before (pat
, insn
);
5318 PATTERN (insn
) = newpat
;
5319 INSN_CODE (insn
) = -1;
5320 recog_memoized (insn
);
5321 recog_memoized (i1
);
5322 record_delay_slot_pair (i1
, insn
, delay
, 0);
5326 /* Examine if INSN is the result of splitting a load into a real load and a
5327 shadow, and if so, undo the transformation. */
5329 undo_split_delayed_nonbranch (rtx insn
)
5331 int icode
= recog_memoized (insn
);
5332 enum attr_type type
;
5333 rtx prev_pat
, insn_pat
, prev
;
5337 type
= get_attr_type (insn
);
5338 if (type
!= TYPE_LOAD_SHADOW
&& type
!= TYPE_MULT_SHADOW
)
5340 prev
= PREV_INSN (insn
);
5341 prev_pat
= PATTERN (prev
);
5342 insn_pat
= PATTERN (insn
);
5343 if (GET_CODE (prev_pat
) == COND_EXEC
)
5345 prev_pat
= COND_EXEC_CODE (prev_pat
);
5346 insn_pat
= COND_EXEC_CODE (insn_pat
);
5349 gcc_assert (GET_CODE (prev_pat
) == UNSPEC
5350 && ((XINT (prev_pat
, 1) == UNSPEC_REAL_LOAD
5351 && type
== TYPE_LOAD_SHADOW
)
5352 || (XINT (prev_pat
, 1) == UNSPEC_REAL_MULT
5353 && type
== TYPE_MULT_SHADOW
)));
5354 insn_pat
= gen_rtx_SET (VOIDmode
, SET_DEST (insn_pat
),
5355 XVECEXP (prev_pat
, 0, 1));
5356 insn_pat
= duplicate_cond (insn_pat
, prev
);
5357 PATTERN (insn
) = insn_pat
;
5358 INSN_CODE (insn
) = -1;
5362 /* Split every insn (i.e. jumps and calls) which can have delay slots into
5363 two parts: the first one is scheduled normally and emits the instruction,
5364 while the second one is a shadow insn which shows the side effect taking
5365 place. The second one is placed in the right cycle by the scheduler, but
5366 not emitted as an assembly instruction. */
5369 split_delayed_insns (void)
5372 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5374 if (JUMP_P (insn
) || CALL_P (insn
))
5375 split_delayed_branch (insn
);
5379 /* For every insn that has an entry in the new_conditions vector, give it
5380 the appropriate predicate. */
5382 conditionalize_after_sched (void)
5387 FOR_BB_INSNS (bb
, insn
)
5389 unsigned uid
= INSN_UID (insn
);
5391 if (!NONDEBUG_INSN_P (insn
) || uid
>= INSN_INFO_LENGTH
)
5393 cond
= INSN_INFO_ENTRY (uid
).new_cond
;
5394 if (cond
== NULL_RTX
)
5397 fprintf (dump_file
, "Conditionalizing insn %d\n", uid
);
5398 predicate_insn (insn
, cond
, true);
5402 /* A callback for the hw-doloop pass. This function examines INSN; if
5403 it is a loop_end pattern we recognize, return the reg rtx for the
5404 loop counter. Otherwise, return NULL_RTX. */
5407 hwloop_pattern_reg (rtx insn
)
5411 if (!JUMP_P (insn
) || recog_memoized (insn
) != CODE_FOR_loop_end
)
5414 pat
= PATTERN (insn
);
5415 reg
= SET_DEST (XVECEXP (pat
, 0, 1));
5421 /* Return the number of cycles taken by BB, as computed by scheduling,
5422 including the latencies of all insns with delay slots. IGNORE is
5423 an insn we should ignore in the calculation, usually the final
5426 bb_earliest_end_cycle (basic_block bb
, rtx ignore
)
5431 FOR_BB_INSNS (bb
, insn
)
5433 int cycles
, this_clock
;
5435 if (LABEL_P (insn
) || NOTE_P (insn
) || DEBUG_INSN_P (insn
)
5436 || GET_CODE (PATTERN (insn
)) == USE
5437 || GET_CODE (PATTERN (insn
)) == CLOBBER
5441 this_clock
= insn_get_clock (insn
);
5442 cycles
= get_attr_cycles (insn
);
5444 if (earliest
< this_clock
+ cycles
)
5445 earliest
= this_clock
+ cycles
;
5450 /* Examine the insns in BB and remove all which have a uid greater or
5451 equal to MAX_UID. */
5453 filter_insns_above (basic_block bb
, int max_uid
)
5456 bool prev_ti
= false;
5457 int prev_cycle
= -1;
5459 FOR_BB_INSNS_SAFE (bb
, insn
, next
)
5462 if (!NONDEBUG_INSN_P (insn
))
5464 if (insn
== BB_END (bb
))
5466 this_cycle
= insn_get_clock (insn
);
5467 if (prev_ti
&& this_cycle
== prev_cycle
)
5469 gcc_assert (GET_MODE (insn
) != TImode
);
5470 PUT_MODE (insn
, TImode
);
5473 if (INSN_UID (insn
) >= max_uid
)
5475 if (GET_MODE (insn
) == TImode
)
5478 prev_cycle
= this_cycle
;
5485 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5488 c6x_asm_emit_except_personality (rtx personality
)
5490 fputs ("\t.personality\t", asm_out_file
);
5491 output_addr_const (asm_out_file
, personality
);
5492 fputc ('\n', asm_out_file
);
5495 /* Use a special assembly directive rather than a regular setion for
5496 unwind table data. */
5499 c6x_asm_init_sections (void)
5501 exception_section
= get_unnamed_section (0, output_section_asm_op
,
5505 /* A callback for the hw-doloop pass. Called to optimize LOOP in a
5506 machine-specific fashion; returns true if successful and false if
5507 the hwloop_fail function should be called. */
5510 hwloop_optimize (hwloop_info loop
)
5512 basic_block entry_bb
, bb
;
5513 rtx seq
, insn
, prev
, entry_after
, end_packet
;
5514 rtx head_insn
, tail_insn
, new_insns
, last_insn
;
5516 int n_execute_packets
;
5519 int max_uid_before
, delayed_splits
;
5520 int i
, sp_ii
, min_ii
, max_ii
, max_parallel
, n_insns
, n_real_insns
, stages
;
5525 if (!c6x_flag_modulo_sched
|| !c6x_flag_schedule_insns2
5526 || !TARGET_INSNS_64PLUS
)
5529 if (loop
->iter_reg_used
|| loop
->depth
> 1)
5531 if (loop
->has_call
|| loop
->has_asm
)
5534 if (loop
->head
!= loop
->tail
)
5537 gcc_assert (loop
->incoming_dest
== loop
->head
);
5540 FOR_EACH_VEC_SAFE_ELT (loop
->incoming
, i
, entry_edge
)
5541 if (entry_edge
->flags
& EDGE_FALLTHRU
)
5543 if (entry_edge
== NULL
)
5546 reshuffle_units (loop
->head
);
5549 schedule_ebbs_init ();
5550 schedule_ebb (BB_HEAD (loop
->tail
), loop
->loop_end
, true);
5551 schedule_ebbs_finish ();
5555 loop_earliest
= bb_earliest_end_cycle (bb
, loop
->loop_end
) + 1;
5557 max_uid_before
= get_max_uid ();
5559 /* Split all multi-cycle operations, such as loads. For normal
5560 scheduling, we only do this for branches, as the generated code
5561 would otherwise not be interrupt-safe. When using sploop, it is
5562 safe and beneficial to split them. If any multi-cycle operations
5563 remain after splitting (because we don't handle them yet), we
5564 cannot pipeline the loop. */
5566 FOR_BB_INSNS (bb
, insn
)
5568 if (NONDEBUG_INSN_P (insn
))
5570 recog_memoized (insn
);
5571 if (split_delayed_nonbranch (insn
))
5573 else if (INSN_CODE (insn
) >= 0
5574 && get_attr_cycles (insn
) > 1)
5579 /* Count the number of insns as well as the number real insns, and save
5580 the original sequence of insns in case we must restore it later. */
5581 n_insns
= n_real_insns
= 0;
5582 FOR_BB_INSNS (bb
, insn
)
5585 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5588 orig_vec
= XNEWVEC (rtx
, n_insns
);
5590 FOR_BB_INSNS (bb
, insn
)
5591 orig_vec
[n_insns
++] = insn
;
5593 /* Count the unit reservations, and compute a minimum II from that
5595 count_unit_reqs (unit_reqs
, loop
->start_label
,
5596 PREV_INSN (loop
->loop_end
));
5597 merge_unit_reqs (unit_reqs
);
5599 min_ii
= res_mii (unit_reqs
);
5600 max_ii
= loop_earliest
< 15 ? loop_earliest
: 14;
5602 /* Make copies of the loop body, up to a maximum number of stages we want
5604 max_parallel
= loop_earliest
/ min_ii
+ 1;
5606 copies
= XCNEWVEC (rtx
, (max_parallel
+ 1) * n_real_insns
);
5607 insn_copies
= XNEWVEC (rtx
*, max_parallel
+ 1);
5608 for (i
= 0; i
< max_parallel
+ 1; i
++)
5609 insn_copies
[i
] = copies
+ i
* n_real_insns
;
5611 head_insn
= next_nonnote_nondebug_insn (loop
->start_label
);
5612 tail_insn
= prev_real_insn (BB_END (bb
));
5615 FOR_BB_INSNS (bb
, insn
)
5616 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5617 insn_copies
[0][i
++] = insn
;
5619 sploop_max_uid_iter0
= get_max_uid ();
5621 /* Generate the copies of the loop body, and save them in the
5622 INSN_COPIES array. */
5624 for (i
= 0; i
< max_parallel
; i
++)
5629 this_iter
= duplicate_insn_chain (head_insn
, tail_insn
);
5633 rtx prev_stage_insn
= insn_copies
[i
][j
];
5634 gcc_assert (INSN_CODE (this_iter
) == INSN_CODE (prev_stage_insn
));
5636 if (INSN_CODE (this_iter
) >= 0
5637 && (get_attr_type (this_iter
) == TYPE_LOAD_SHADOW
5638 || get_attr_type (this_iter
) == TYPE_MULT_SHADOW
))
5640 rtx prev
= PREV_INSN (this_iter
);
5641 record_delay_slot_pair (prev
, this_iter
,
5642 get_attr_cycles (prev
) - 1, 0);
5645 record_delay_slot_pair (prev_stage_insn
, this_iter
, i
, 1);
5647 insn_copies
[i
+ 1][j
] = this_iter
;
5649 this_iter
= next_nonnote_nondebug_insn (this_iter
);
5652 new_insns
= get_insns ();
5653 last_insn
= insn_copies
[max_parallel
][n_real_insns
- 1];
5655 emit_insn_before (new_insns
, BB_END (bb
));
5657 /* Try to schedule the loop using varying initiation intervals,
5658 starting with the smallest possible and incrementing it
5660 for (sp_ii
= min_ii
; sp_ii
<= max_ii
; sp_ii
++)
5664 fprintf (dump_file
, "Trying to schedule for II %d\n", sp_ii
);
5666 df_clear_flags (DF_LR_RUN_DCE
);
5668 schedule_ebbs_init ();
5669 set_modulo_params (sp_ii
, max_parallel
, n_real_insns
,
5670 sploop_max_uid_iter0
);
5671 tmp_bb
= schedule_ebb (BB_HEAD (bb
), last_insn
, true);
5672 schedule_ebbs_finish ();
5677 fprintf (dump_file
, "Found schedule with II %d\n", sp_ii
);
5682 discard_delay_pairs_above (max_uid_before
);
5687 stages
= insn_get_clock (ss
.last_scheduled_iter0
) / sp_ii
+ 1;
5689 if (stages
== 1 && sp_ii
> 5)
5692 /* At this point, we know we've been successful, unless we find later that
5693 there are too many execute packets for the loop buffer to hold. */
5695 /* Assign reservations to the instructions in the loop. We must find
5696 the stage that contains the full loop kernel, and transfer the
5697 reservations of the instructions contained in it to the corresponding
5698 instructions from iteration 0, which are the only ones we'll keep. */
5699 assign_reservations (BB_HEAD (bb
), ss
.last_scheduled_insn
);
5700 PREV_INSN (BB_END (bb
)) = ss
.last_scheduled_iter0
;
5701 NEXT_INSN (ss
.last_scheduled_iter0
) = BB_END (bb
);
5702 filter_insns_above (bb
, sploop_max_uid_iter0
);
5704 for (i
= 0; i
< n_real_insns
; i
++)
5706 rtx insn
= insn_copies
[0][i
];
5707 int uid
= INSN_UID (insn
);
5708 int stage
= insn_uid_get_clock (uid
) / sp_ii
;
5710 if (stage
+ 1 < stages
)
5713 stage
= stages
- stage
- 1;
5714 copy_uid
= INSN_UID (insn_copies
[stage
][i
]);
5715 INSN_INFO_ENTRY (uid
).reservation
5716 = INSN_INFO_ENTRY (copy_uid
).reservation
;
5722 /* Compute the number of execute packets the pipelined form of the loop will
5725 n_execute_packets
= 0;
5726 for (insn
= loop
->start_label
; insn
!= loop
->loop_end
; insn
= NEXT_INSN (insn
))
5728 if (NONDEBUG_INSN_P (insn
) && GET_MODE (insn
) == TImode
5729 && !shadow_p (insn
))
5731 n_execute_packets
++;
5732 if (prev
&& insn_get_clock (prev
) + 1 != insn_get_clock (insn
))
5733 /* We need an extra NOP instruction. */
5734 n_execute_packets
++;
5740 end_packet
= ss
.last_scheduled_iter0
;
5741 while (!NONDEBUG_INSN_P (end_packet
) || GET_MODE (end_packet
) != TImode
)
5742 end_packet
= PREV_INSN (end_packet
);
5744 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5745 loop_earliest
= (stages
- 1) * sp_ii
;
5746 if (loop_earliest
> insn_get_clock (end_packet
))
5748 n_execute_packets
++;
5749 end_packet
= loop
->loop_end
;
5752 loop_earliest
= insn_get_clock (end_packet
);
5754 if (n_execute_packets
> 14)
5757 /* Generate the spkernel instruction, and place it at the appropriate
5759 PUT_MODE (end_packet
, VOIDmode
);
5761 insn
= gen_spkernel (GEN_INT (stages
- 1),
5762 const0_rtx
, JUMP_LABEL (loop
->loop_end
));
5763 insn
= emit_jump_insn_before (insn
, end_packet
);
5764 JUMP_LABEL (insn
) = JUMP_LABEL (loop
->loop_end
);
5765 insn_set_clock (insn
, loop_earliest
);
5766 PUT_MODE (insn
, TImode
);
5767 INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
= false;
5768 delete_insn (loop
->loop_end
);
5770 /* Place the mvc and sploop instructions before the loop. */
5771 entry_bb
= entry_edge
->src
;
5775 insn
= emit_insn (gen_mvilc (loop
->iter_reg
));
5776 insn
= emit_insn (gen_sploop (GEN_INT (sp_ii
)));
5780 if (!single_succ_p (entry_bb
) || vec_safe_length (loop
->incoming
) > 1)
5786 emit_insn_before (seq
, BB_HEAD (loop
->head
));
5787 seq
= emit_label_before (gen_label_rtx (), seq
);
5789 new_bb
= create_basic_block (seq
, insn
, entry_bb
);
5790 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
5792 if (!(e
->flags
& EDGE_FALLTHRU
))
5793 redirect_edge_and_branch_force (e
, new_bb
);
5795 redirect_edge_succ (e
, new_bb
);
5797 make_edge (new_bb
, loop
->head
, 0);
5801 entry_after
= BB_END (entry_bb
);
5802 while (DEBUG_INSN_P (entry_after
)
5803 || (NOTE_P (entry_after
)
5804 && NOTE_KIND (entry_after
) != NOTE_INSN_BASIC_BLOCK
))
5805 entry_after
= PREV_INSN (entry_after
);
5806 emit_insn_after (seq
, entry_after
);
5811 /* Make sure we don't try to schedule this loop again. */
5812 for (ix
= 0; loop
->blocks
.iterate (ix
, &bb
); ix
++)
5813 bb
->flags
|= BB_DISABLE_SCHEDULE
;
5819 fprintf (dump_file
, "Unable to pipeline loop.\n");
5821 for (i
= 1; i
< n_insns
; i
++)
5823 NEXT_INSN (orig_vec
[i
- 1]) = orig_vec
[i
];
5824 PREV_INSN (orig_vec
[i
]) = orig_vec
[i
- 1];
5826 PREV_INSN (orig_vec
[0]) = PREV_INSN (BB_HEAD (bb
));
5827 NEXT_INSN (PREV_INSN (BB_HEAD (bb
))) = orig_vec
[0];
5828 NEXT_INSN (orig_vec
[n_insns
- 1]) = NEXT_INSN (BB_END (bb
));
5829 PREV_INSN (NEXT_INSN (BB_END (bb
))) = orig_vec
[n_insns
- 1];
5830 BB_HEAD (bb
) = orig_vec
[0];
5831 BB_END (bb
) = orig_vec
[n_insns
- 1];
5833 free_delay_pairs ();
5834 FOR_BB_INSNS (bb
, insn
)
5835 if (NONDEBUG_INSN_P (insn
))
5836 undo_split_delayed_nonbranch (insn
);
5840 /* A callback for the hw-doloop pass. Called when a loop we have discovered
5841 turns out not to be optimizable; we have to split the doloop_end pattern
5842 into a subtract and a test. */
5844 hwloop_fail (hwloop_info loop
)
5846 rtx insn
, test
, testreg
;
5849 fprintf (dump_file
, "splitting doloop insn %d\n",
5850 INSN_UID (loop
->loop_end
));
5851 insn
= gen_addsi3 (loop
->iter_reg
, loop
->iter_reg
, constm1_rtx
);
5852 /* See if we can emit the add at the head of the loop rather than at the
5854 if (loop
->head
== NULL
5855 || loop
->iter_reg_used_outside
5856 || loop
->iter_reg_used
5857 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REGNO (loop
->iter_reg
))
5858 || loop
->incoming_dest
!= loop
->head
5859 || EDGE_COUNT (loop
->head
->preds
) != 2)
5860 emit_insn_before (insn
, loop
->loop_end
);
5863 rtx t
= loop
->start_label
;
5864 while (!NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_BASIC_BLOCK
)
5866 emit_insn_after (insn
, t
);
5869 testreg
= SET_DEST (XVECEXP (PATTERN (loop
->loop_end
), 0, 2));
5870 if (GET_CODE (testreg
) == SCRATCH
)
5871 testreg
= loop
->iter_reg
;
5873 emit_insn_before (gen_movsi (testreg
, loop
->iter_reg
), loop
->loop_end
);
5875 test
= gen_rtx_NE (VOIDmode
, testreg
, const0_rtx
);
5876 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
, testreg
, const0_rtx
,
5880 JUMP_LABEL (insn
) = loop
->start_label
;
5881 LABEL_NUSES (loop
->start_label
)++;
5882 delete_insn (loop
->loop_end
);
5885 static struct hw_doloop_hooks c6x_doloop_hooks
=
5892 /* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5893 doloop_end patterns where such optimizations are impossible. */
5898 reorg_loops (true, &c6x_doloop_hooks
);
5901 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5902 into a sequence that loads the return register and performs the call,
5903 and emit the return label.
5904 If scheduling after reload is requested, it happens here. */
5911 bool do_selsched
= (c6x_flag_schedule_insns2
&& flag_selective_scheduling2
5912 && !maybe_skip_selective_scheduling ());
5914 /* We are freeing block_for_insn in the toplev to keep compatibility
5915 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5916 compute_bb_for_insn ();
5918 df_clear_flags (DF_LR_RUN_DCE
);
5919 df_note_add_problem ();
5921 /* If optimizing, we'll have split before scheduling. */
5927 if (c6x_flag_schedule_insns2
)
5929 int sz
= get_max_uid () * 3 / 2 + 1;
5931 insn_info
.create (sz
);
5934 /* Make sure the real-jump insns we create are not deleted. When modulo-
5935 scheduling, situations where a reg is only stored in a loop can also
5936 cause dead code when doing the initial unrolling. */
5937 sched_no_dce
= true;
5941 if (c6x_flag_schedule_insns2
)
5943 split_delayed_insns ();
5944 timevar_push (TV_SCHED2
);
5946 run_selective_scheduling ();
5949 conditionalize_after_sched ();
5950 timevar_pop (TV_SCHED2
);
5952 free_delay_pairs ();
5954 sched_no_dce
= false;
5956 call_labels
= XCNEWVEC (rtx
, get_max_uid () + 1);
5958 reorg_split_calls (call_labels
);
5960 if (c6x_flag_schedule_insns2
)
5963 if ((bb
->flags
& BB_DISABLE_SCHEDULE
) == 0)
5964 assign_reservations (BB_HEAD (bb
), BB_END (bb
));
5967 if (c6x_flag_var_tracking
)
5969 timevar_push (TV_VAR_TRACKING
);
5970 variable_tracking_main ();
5971 timevar_pop (TV_VAR_TRACKING
);
5974 reorg_emit_nops (call_labels
);
5976 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
5977 if (c6x_flag_schedule_insns2
)
5979 free_delay_pairs ();
5983 df_finish_pass (false);
5986 /* Called when a function has been assembled. It should perform all the
5987 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
5989 We free the reservation (and other scheduling) information here now that
5990 all insns have been output. */
5992 c6x_function_end (FILE *file
, const char *fname
)
5994 c6x_output_fn_unwind (file
);
5996 insn_info
.release ();
5998 if (!flag_inhibit_size_directive
)
5999 ASM_OUTPUT_MEASURED_SIZE (file
, fname
);
6002 /* Determine whether X is a shift with code CODE and an integer amount
6005 shift_p (rtx x
, enum rtx_code code
, int amount
)
6007 return (GET_CODE (x
) == code
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
6008 && INTVAL (XEXP (x
, 1)) == amount
);
6011 /* Compute a (partial) cost for rtx X. Return true if the complete
6012 cost has been computed, and false if subexpressions should be
6013 scanned. In either case, *TOTAL contains the cost result. */
6016 c6x_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
6019 int cost2
= COSTS_N_INSNS (1);
6025 if (outer_code
== SET
|| outer_code
== PLUS
)
6026 *total
= satisfies_constraint_IsB (x
) ? 0 : cost2
;
6027 else if (outer_code
== AND
|| outer_code
== IOR
|| outer_code
== XOR
6028 || outer_code
== MINUS
)
6029 *total
= satisfies_constraint_Is5 (x
) ? 0 : cost2
;
6030 else if (GET_RTX_CLASS (outer_code
) == RTX_COMPARE
6031 || GET_RTX_CLASS (outer_code
) == RTX_COMM_COMPARE
)
6032 *total
= satisfies_constraint_Iu4 (x
) ? 0 : cost2
;
6033 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
6034 || outer_code
== LSHIFTRT
)
6035 *total
= satisfies_constraint_Iu5 (x
) ? 0 : cost2
;
6044 *total
= COSTS_N_INSNS (2);
6048 /* Recognize a mult_highpart operation. */
6049 if ((GET_MODE (x
) == HImode
|| GET_MODE (x
) == SImode
)
6050 && GET_CODE (XEXP (x
, 0)) == LSHIFTRT
6051 && GET_MODE (XEXP (x
, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x
))
6052 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
6053 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
6054 && INTVAL (XEXP (XEXP (x
, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x
)))
6056 rtx mul
= XEXP (XEXP (x
, 0), 0);
6057 rtx op0
= XEXP (mul
, 0);
6058 rtx op1
= XEXP (mul
, 1);
6059 enum rtx_code code0
= GET_CODE (op0
);
6060 enum rtx_code code1
= GET_CODE (op1
);
6063 && (code0
== SIGN_EXTEND
|| code0
== ZERO_EXTEND
))
6064 || (GET_MODE (x
) == HImode
6065 && code0
== ZERO_EXTEND
&& code1
== SIGN_EXTEND
))
6067 if (GET_MODE (x
) == HImode
)
6068 *total
= COSTS_N_INSNS (2);
6070 *total
= COSTS_N_INSNS (12);
6071 *total
+= rtx_cost (XEXP (op0
, 0), code0
, 0, speed
);
6072 *total
+= rtx_cost (XEXP (op1
, 0), code1
, 0, speed
);
6081 if (GET_MODE (x
) == DImode
)
6082 *total
= COSTS_N_INSNS (CONSTANT_P (XEXP (x
, 1)) ? 4 : 15);
6084 *total
= COSTS_N_INSNS (1);
6089 *total
= COSTS_N_INSNS (1);
6090 op0
= code
== PLUS
? XEXP (x
, 0) : XEXP (x
, 1);
6091 op1
= code
== PLUS
? XEXP (x
, 1) : XEXP (x
, 0);
6092 if (GET_MODE_SIZE (GET_MODE (x
)) <= UNITS_PER_WORD
6093 && INTEGRAL_MODE_P (GET_MODE (x
))
6094 && GET_CODE (op0
) == MULT
6095 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
6096 && (INTVAL (XEXP (op0
, 1)) == 2
6097 || INTVAL (XEXP (op0
, 1)) == 4
6098 || (code
== PLUS
&& INTVAL (XEXP (op0
, 1)) == 8)))
6100 *total
+= rtx_cost (XEXP (op0
, 0), ASHIFT
, 0, speed
);
6101 *total
+= rtx_cost (op1
, (enum rtx_code
) code
, 1, speed
);
6109 if (GET_MODE (x
) == DFmode
)
6112 *total
= COSTS_N_INSNS (speed
? 10 : 1);
6114 *total
= COSTS_N_INSNS (speed
? 200 : 4);
6116 else if (GET_MODE (x
) == SFmode
)
6119 *total
= COSTS_N_INSNS (speed
? 4 : 1);
6121 *total
= COSTS_N_INSNS (speed
? 100 : 4);
6123 else if (GET_MODE (x
) == DImode
)
6126 && GET_CODE (op0
) == GET_CODE (op1
)
6127 && (GET_CODE (op0
) == ZERO_EXTEND
6128 || GET_CODE (op0
) == SIGN_EXTEND
))
6130 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6131 op0
= XEXP (op0
, 0);
6132 op1
= XEXP (op1
, 0);
6135 /* Maybe improve this laster. */
6136 *total
= COSTS_N_INSNS (20);
6138 else if (GET_MODE (x
) == SImode
)
6140 if (((GET_CODE (op0
) == ZERO_EXTEND
6141 || GET_CODE (op0
) == SIGN_EXTEND
6142 || shift_p (op0
, LSHIFTRT
, 16))
6143 && (GET_CODE (op1
) == SIGN_EXTEND
6144 || GET_CODE (op1
) == ZERO_EXTEND
6145 || scst5_operand (op1
, SImode
)
6146 || shift_p (op1
, ASHIFTRT
, 16)
6147 || shift_p (op1
, LSHIFTRT
, 16)))
6148 || (shift_p (op0
, ASHIFTRT
, 16)
6149 && (GET_CODE (op1
) == SIGN_EXTEND
6150 || shift_p (op1
, ASHIFTRT
, 16))))
6152 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6153 op0
= XEXP (op0
, 0);
6154 if (scst5_operand (op1
, SImode
))
6157 op1
= XEXP (op1
, 0);
6160 *total
= COSTS_N_INSNS (1);
6161 else if (TARGET_MPY32
)
6162 *total
= COSTS_N_INSNS (4);
6164 *total
= COSTS_N_INSNS (6);
6166 else if (GET_MODE (x
) == HImode
)
6167 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6169 if (GET_CODE (op0
) != REG
6170 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
6171 *total
+= rtx_cost (op0
, MULT
, 0, speed
);
6172 if (op1
&& GET_CODE (op1
) != REG
6173 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
6174 *total
+= rtx_cost (op1
, MULT
, 1, speed
);
6179 /* This is a bit random; assuming on average there'll be 16 leading
6180 zeros. FIXME: estimate better for constant dividends. */
6181 *total
= COSTS_N_INSNS (6 + 3 * 16);
6185 /* Recognize the cmp_and/ior patterns. */
6187 if ((GET_CODE (op0
) == EQ
|| GET_CODE (op0
) == NE
)
6188 && REG_P (XEXP (op0
, 0))
6189 && XEXP (op0
, 1) == const0_rtx
6190 && rtx_equal_p (XEXP (x
, 1), XEXP (op0
, 0)))
6192 *total
= rtx_cost (XEXP (x
, 1), (enum rtx_code
) outer_code
,
6203 /* Implements target hook vector_mode_supported_p. */
6206 c6x_vector_mode_supported_p (enum machine_mode mode
)
6221 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6222 static enum machine_mode
6223 c6x_preferred_simd_mode (enum machine_mode mode
)
6237 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6240 c6x_scalar_mode_supported_p (enum machine_mode mode
)
6242 if (ALL_FIXED_POINT_MODE_P (mode
)
6243 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
6246 return default_scalar_mode_supported_p (mode
);
6249 /* Output a reference from a function exception table to the type_info
6250 object X. Output these via a special assembly directive. */
6253 c6x_output_ttype (rtx x
)
6255 /* Use special relocations for symbol references. */
6256 if (GET_CODE (x
) != CONST_INT
)
6257 fputs ("\t.ehtype\t", asm_out_file
);
6259 fputs ("\t.word\t", asm_out_file
);
6260 output_addr_const (asm_out_file
, x
);
6261 fputc ('\n', asm_out_file
);
6266 /* Modify the return address of the current function. */
6269 c6x_set_return_address (rtx source
, rtx scratch
)
6271 struct c6x_frame frame
;
6273 HOST_WIDE_INT offset
;
6275 c6x_compute_frame_layout (&frame
);
6276 if (! c6x_save_reg (RETURN_ADDR_REGNO
))
6277 emit_move_insn (gen_rtx_REG (Pmode
, RETURN_ADDR_REGNO
), source
);
6281 if (frame_pointer_needed
)
6283 addr
= hard_frame_pointer_rtx
;
6284 offset
= frame
.b3_offset
;
6288 addr
= stack_pointer_rtx
;
6289 offset
= frame
.to_allocate
- frame
.b3_offset
;
6292 /* TODO: Use base+offset loads where possible. */
6295 HOST_WIDE_INT low
= trunc_int_for_mode (offset
, HImode
);
6297 emit_insn (gen_movsi_high (scratch
, GEN_INT (low
)));
6299 emit_insn (gen_movsi_lo_sum (scratch
, scratch
, GEN_INT(offset
)));
6300 emit_insn (gen_addsi3 (scratch
, addr
, scratch
));
6304 emit_move_insn (gen_frame_mem (Pmode
, addr
), source
);
6308 /* We save pairs of registers using a DImode store. Describe the component
6309 registers for DWARF generation code. */
6312 c6x_dwarf_register_span (rtx rtl
)
6315 unsigned real_regno
;
6320 regno
= REGNO (rtl
);
6321 nregs
= HARD_REGNO_NREGS (regno
, GET_MODE (rtl
));
6325 p
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc(nregs
));
6326 for (i
= 0; i
< nregs
; i
++)
6328 if (TARGET_BIG_ENDIAN
)
6329 real_regno
= regno
+ nregs
- (i
+ 1);
6331 real_regno
= regno
+ i
;
6333 XVECEXP (p
, 0, i
) = gen_rtx_REG (SImode
, real_regno
);
6339 /* Codes for all the C6X builtins. */
6374 static GTY(()) tree c6x_builtin_decls
[C6X_BUILTIN_MAX
];
6376 /* Return the C6X builtin for CODE. */
6378 c6x_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
6380 if (code
>= C6X_BUILTIN_MAX
)
6381 return error_mark_node
;
6383 return c6x_builtin_decls
[code
];
6386 #define def_builtin(NAME, TYPE, CODE) \
6389 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6391 c6x_builtin_decls[CODE] = bdecl; \
6394 /* Set up all builtin functions for this target. */
6396 c6x_init_builtins (void)
6398 tree V4QI_type_node
= build_vector_type (unsigned_intQI_type_node
, 4);
6399 tree V2HI_type_node
= build_vector_type (intHI_type_node
, 2);
6400 tree V2SI_type_node
= build_vector_type (intSI_type_node
, 2);
6402 = build_function_type_list (integer_type_node
, integer_type_node
,
6404 tree int_ftype_int_int
6405 = build_function_type_list (integer_type_node
, integer_type_node
,
6406 integer_type_node
, NULL_TREE
);
6407 tree v2hi_ftype_v2hi
6408 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
6409 tree v4qi_ftype_v4qi_v4qi
6410 = build_function_type_list (V4QI_type_node
, V4QI_type_node
,
6411 V4QI_type_node
, NULL_TREE
);
6412 tree v2hi_ftype_v2hi_v2hi
6413 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
6414 V2HI_type_node
, NULL_TREE
);
6415 tree v2si_ftype_v2hi_v2hi
6416 = build_function_type_list (V2SI_type_node
, V2HI_type_node
,
6417 V2HI_type_node
, NULL_TREE
);
6419 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int
,
6421 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int
,
6423 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi
,
6425 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi
,
6427 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi
,
6429 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi
,
6431 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi
,
6433 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi
,
6435 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi
,
6437 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi
,
6438 C6X_BUILTIN_SADDU4
);
6439 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi
,
6442 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int
,
6444 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int
,
6446 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int
,
6447 C6X_BUILTIN_SMPYHL
);
6448 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int
,
6449 C6X_BUILTIN_SMPYLH
);
6451 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int
,
6453 def_builtin ("__builtin_c6x_subc", int_ftype_int_int
,
6456 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi
,
6458 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi
,
6461 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int
,
6463 def_builtin ("__builtin_c6x_extr", int_ftype_int_int
,
6465 def_builtin ("__builtin_c6x_extru", int_ftype_int_int
,
6468 def_builtin ("__builtin_c6x_abs", int_ftype_int
, C6X_BUILTIN_ABS
);
6469 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi
, C6X_BUILTIN_ABS2
);
6473 struct builtin_description
6475 const enum insn_code icode
;
6476 const char *const name
;
6477 const enum c6x_builtins code
;
6480 static const struct builtin_description bdesc_2arg
[] =
6482 { CODE_FOR_saddsi3
, "__builtin_c6x_sadd", C6X_BUILTIN_SADD
},
6483 { CODE_FOR_ssubsi3
, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB
},
6484 { CODE_FOR_addv2hi3
, "__builtin_c6x_add2", C6X_BUILTIN_ADD2
},
6485 { CODE_FOR_subv2hi3
, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2
},
6486 { CODE_FOR_addv4qi3
, "__builtin_c6x_add4", C6X_BUILTIN_ADD4
},
6487 { CODE_FOR_subv4qi3
, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4
},
6488 { CODE_FOR_ss_addv2hi3
, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2
},
6489 { CODE_FOR_ss_subv2hi3
, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2
},
6490 { CODE_FOR_us_addv4qi3
, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4
},
6492 { CODE_FOR_subcsi3
, "__builtin_c6x_subc", C6X_BUILTIN_SUBC
},
6493 { CODE_FOR_ss_ashlsi3
, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL
},
6495 { CODE_FOR_avgv2hi3
, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2
},
6496 { CODE_FOR_uavgv4qi3
, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4
},
6498 { CODE_FOR_mulhqsq3
, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY
},
6499 { CODE_FOR_mulhqsq3_hh
, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH
},
6500 { CODE_FOR_mulhqsq3_lh
, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH
},
6501 { CODE_FOR_mulhqsq3_hl
, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL
},
6503 { CODE_FOR_mulv2hqv2sq3
, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2
},
6505 { CODE_FOR_clrr
, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR
},
6506 { CODE_FOR_extr
, "__builtin_c6x_extr", C6X_BUILTIN_EXTR
},
6507 { CODE_FOR_extru
, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU
}
6510 static const struct builtin_description bdesc_1arg
[] =
6512 { CODE_FOR_ssabssi2
, "__builtin_c6x_abs", C6X_BUILTIN_ABS
},
6513 { CODE_FOR_ssabsv2hi2
, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2
}
6516 /* Errors in the source file can cause expand_expr to return const0_rtx
6517 where we expect a vector. To avoid crashing, use one of the vector
6518 clear instructions. */
6520 safe_vector_operand (rtx x
, enum machine_mode mode
)
6522 if (x
!= const0_rtx
)
6524 x
= gen_reg_rtx (SImode
);
6526 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
6527 return gen_lowpart (mode
, x
);
6530 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6531 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6534 c6x_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
6537 int offs
= match_op
? 1 : 0;
6539 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6540 tree arg1
= CALL_EXPR_ARG (exp
, 1);
6541 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6542 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6543 enum machine_mode op0mode
= GET_MODE (op0
);
6544 enum machine_mode op1mode
= GET_MODE (op1
);
6545 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6546 enum machine_mode mode0
= insn_data
[icode
].operand
[1 + offs
].mode
;
6547 enum machine_mode mode1
= insn_data
[icode
].operand
[2 + offs
].mode
;
6550 if (VECTOR_MODE_P (mode0
))
6551 op0
= safe_vector_operand (op0
, mode0
);
6552 if (VECTOR_MODE_P (mode1
))
6553 op1
= safe_vector_operand (op1
, mode1
);
6556 || GET_MODE (target
) != tmode
6557 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6559 if (tmode
== SQmode
|| tmode
== V2SQmode
)
6561 ret
= gen_reg_rtx (tmode
== SQmode
? SImode
: V2SImode
);
6562 target
= gen_lowpart (tmode
, ret
);
6565 target
= gen_reg_rtx (tmode
);
6568 if ((op0mode
== V2HImode
|| op0mode
== SImode
|| op0mode
== VOIDmode
)
6569 && (mode0
== V2HQmode
|| mode0
== HQmode
|| mode0
== SQmode
))
6572 op0
= gen_lowpart (mode0
, op0
);
6574 if ((op1mode
== V2HImode
|| op1mode
== SImode
|| op1mode
== VOIDmode
)
6575 && (mode1
== V2HQmode
|| mode1
== HQmode
|| mode1
== SQmode
))
6578 op1
= gen_lowpart (mode1
, op1
);
6580 /* In case the insn wants input operands in modes different from
6581 the result, abort. */
6582 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
6583 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
6585 if (! (*insn_data
[icode
].operand
[1 + offs
].predicate
) (op0
, mode0
))
6586 op0
= copy_to_mode_reg (mode0
, op0
);
6587 if (! (*insn_data
[icode
].operand
[2 + offs
].predicate
) (op1
, mode1
))
6588 op1
= copy_to_mode_reg (mode1
, op1
);
6591 pat
= GEN_FCN (icode
) (target
, target
, op0
, op1
);
6593 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
6603 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
6606 c6x_expand_unop_builtin (enum insn_code icode
, tree exp
,
6610 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6611 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6612 enum machine_mode op0mode
= GET_MODE (op0
);
6613 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6614 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6617 || GET_MODE (target
) != tmode
6618 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6619 target
= gen_reg_rtx (tmode
);
6621 if (VECTOR_MODE_P (mode0
))
6622 op0
= safe_vector_operand (op0
, mode0
);
6624 if (op0mode
== SImode
&& mode0
== HImode
)
6627 op0
= gen_lowpart (HImode
, op0
);
6629 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
6631 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6632 op0
= copy_to_mode_reg (mode0
, op0
);
6634 pat
= GEN_FCN (icode
) (target
, op0
);
6641 /* Expand an expression EXP that calls a built-in function,
6642 with result going to TARGET if that's convenient
6643 (and in mode MODE if that's convenient).
6644 SUBTARGET may be used as the target for computing one of EXP's operands.
6645 IGNORE is nonzero if the value is to be ignored. */
6648 c6x_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
6649 rtx subtarget ATTRIBUTE_UNUSED
,
6650 enum machine_mode mode ATTRIBUTE_UNUSED
,
6651 int ignore ATTRIBUTE_UNUSED
)
6654 const struct builtin_description
*d
;
6655 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
6656 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
6658 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6659 if (d
->code
== fcode
)
6660 return c6x_expand_binop_builtin (d
->icode
, exp
, target
,
6661 fcode
== C6X_BUILTIN_CLRR
);
6663 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6664 if (d
->code
== fcode
)
6665 return c6x_expand_unop_builtin (d
->icode
, exp
, target
);
6670 /* Target unwind frame info is generated from dwarf CFI directives, so
6671 always output dwarf2 unwind info. */
6673 static enum unwind_info_type
6674 c6x_debug_unwind_info (void)
6676 if (flag_unwind_tables
|| flag_exceptions
)
6679 return default_debug_unwind_info ();
6682 /* Target Structure. */
6684 /* Initialize the GCC target structure. */
6685 #undef TARGET_FUNCTION_ARG
6686 #define TARGET_FUNCTION_ARG c6x_function_arg
6687 #undef TARGET_FUNCTION_ARG_ADVANCE
6688 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6689 #undef TARGET_FUNCTION_ARG_BOUNDARY
6690 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6691 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6692 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6693 c6x_function_arg_round_boundary
6694 #undef TARGET_FUNCTION_VALUE_REGNO_P
6695 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6696 #undef TARGET_FUNCTION_VALUE
6697 #define TARGET_FUNCTION_VALUE c6x_function_value
6698 #undef TARGET_LIBCALL_VALUE
6699 #define TARGET_LIBCALL_VALUE c6x_libcall_value
6700 #undef TARGET_RETURN_IN_MEMORY
6701 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6702 #undef TARGET_RETURN_IN_MSB
6703 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
6704 #undef TARGET_PASS_BY_REFERENCE
6705 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6706 #undef TARGET_CALLEE_COPIES
6707 #define TARGET_CALLEE_COPIES c6x_callee_copies
6708 #undef TARGET_STRUCT_VALUE_RTX
6709 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6710 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6711 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6713 #undef TARGET_ASM_OUTPUT_MI_THUNK
6714 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6715 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6716 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6718 #undef TARGET_BUILD_BUILTIN_VA_LIST
6719 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6721 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6722 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6723 #undef TARGET_TRAMPOLINE_INIT
6724 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6726 #undef TARGET_LEGITIMATE_CONSTANT_P
6727 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6728 #undef TARGET_LEGITIMATE_ADDRESS_P
6729 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6731 #undef TARGET_IN_SMALL_DATA_P
6732 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6733 #undef TARGET_ASM_SELECT_RTX_SECTION
6734 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6735 #undef TARGET_ASM_SELECT_SECTION
6736 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6737 #undef TARGET_ASM_UNIQUE_SECTION
6738 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6739 #undef TARGET_SECTION_TYPE_FLAGS
6740 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6741 #undef TARGET_HAVE_SRODATA_SECTION
6742 #define TARGET_HAVE_SRODATA_SECTION true
6743 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6744 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6746 #undef TARGET_OPTION_OVERRIDE
6747 #define TARGET_OPTION_OVERRIDE c6x_option_override
6748 #undef TARGET_CONDITIONAL_REGISTER_USAGE
6749 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6751 #undef TARGET_INIT_LIBFUNCS
6752 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6753 #undef TARGET_LIBFUNC_GNU_PREFIX
6754 #define TARGET_LIBFUNC_GNU_PREFIX true
6756 #undef TARGET_SCALAR_MODE_SUPPORTED_P
6757 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6758 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6759 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6760 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6761 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6763 #undef TARGET_RTX_COSTS
6764 #define TARGET_RTX_COSTS c6x_rtx_costs
6766 #undef TARGET_SCHED_INIT
6767 #define TARGET_SCHED_INIT c6x_sched_init
6768 #undef TARGET_SCHED_SET_SCHED_FLAGS
6769 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6770 #undef TARGET_SCHED_ADJUST_COST
6771 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6772 #undef TARGET_SCHED_ISSUE_RATE
6773 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6774 #undef TARGET_SCHED_VARIABLE_ISSUE
6775 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6776 #undef TARGET_SCHED_REORDER
6777 #define TARGET_SCHED_REORDER c6x_sched_reorder
6778 #undef TARGET_SCHED_REORDER2
6779 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6780 #undef TARGET_SCHED_DFA_NEW_CYCLE
6781 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6782 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6783 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6784 #undef TARGET_SCHED_EXPOSED_PIPELINE
6785 #define TARGET_SCHED_EXPOSED_PIPELINE true
6787 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6788 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6789 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
6790 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6791 #undef TARGET_SCHED_SET_SCHED_CONTEXT
6792 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6793 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6794 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6795 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
6796 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6798 #undef TARGET_CAN_ELIMINATE
6799 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
6801 #undef TARGET_PREFERRED_RENAME_CLASS
6802 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6804 #undef TARGET_MACHINE_DEPENDENT_REORG
6805 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6807 #undef TARGET_ASM_FILE_START
6808 #define TARGET_ASM_FILE_START c6x_file_start
6810 #undef TARGET_PRINT_OPERAND
6811 #define TARGET_PRINT_OPERAND c6x_print_operand
6812 #undef TARGET_PRINT_OPERAND_ADDRESS
6813 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6814 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6815 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6817 /* C6x unwinding tables use a different format for the typeinfo tables. */
6818 #undef TARGET_ASM_TTYPE
6819 #define TARGET_ASM_TTYPE c6x_output_ttype
6821 /* The C6x ABI follows the ARM EABI exception handling rules. */
6822 #undef TARGET_ARM_EABI_UNWINDER
6823 #define TARGET_ARM_EABI_UNWINDER true
6825 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6826 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6828 #undef TARGET_ASM_INIT_SECTIONS
6829 #define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6831 #undef TARGET_DEBUG_UNWIND_INFO
6832 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6834 #undef TARGET_DWARF_REGISTER_SPAN
6835 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6837 #undef TARGET_INIT_BUILTINS
6838 #define TARGET_INIT_BUILTINS c6x_init_builtins
6839 #undef TARGET_EXPAND_BUILTIN
6840 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6841 #undef TARGET_BUILTIN_DECL
6842 #define TARGET_BUILTIN_DECL c6x_builtin_decl
6844 struct gcc_target targetm
= TARGET_INITIALIZER
;