1 /* Target Code for TI C6X
2 Copyright (C) 2010-2015 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"
30 #include "fold-const.h"
31 #include "stor-layout.h"
34 #include "stringpool.h"
35 #include "insn-flags.h"
37 #include "insn-attr.h"
38 #include "insn-codes.h"
39 #include "hard-reg-set.h"
42 #include "insn-config.h"
52 #include "dominance.h"
58 #include "cfgcleanup.h"
60 #include "basic-block.h"
61 #include "sched-int.h"
65 #include "tm-constrs.h"
67 #include "diagnostic-core.h"
69 #include "langhooks.h"
71 #include "sel-sched.h"
74 #include "hw-doloop.h"
75 #include "regrename.h"
77 #include "gimple-expr.h"
80 /* This file should be included last. */
81 #include "target-def.h"
83 /* Table of supported architecture variants. */
87 enum c6x_cpu_type type
;
88 unsigned short features
;
91 /* A list of all ISAs, mapping each one to a representative device.
92 Used for -march selection. */
93 static const c6x_arch_table all_isas
[] =
95 #define C6X_ISA(NAME,DEVICE,FLAGS) \
96 { NAME, DEVICE, FLAGS },
97 #include "c6x-isas.def"
99 { NULL
, C6X_CPU_C62X
, 0 }
102 /* This is the parsed result of the "-march=" option, if given. */
103 enum c6x_cpu_type c6x_arch
= C6X_DEFAULT_ARCH
;
105 /* A mask of insn types that are allowed by the architecture selected by
106 the -march option. */
107 unsigned long c6x_insn_mask
= C6X_DEFAULT_INSN_MASK
;
109 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
111 static rtx_insn
*c6x_current_insn
= NULL
;
113 /* A decl we build to access __c6xabi_DSBT_base. */
114 static GTY(()) tree dsbt_decl
;
116 /* Determines whether we run our final scheduling pass or not. We always
117 avoid the normal second scheduling pass. */
118 static int c6x_flag_schedule_insns2
;
120 /* Determines whether we run variable tracking in machine dependent
122 static int c6x_flag_var_tracking
;
124 /* Determines whether we use modulo scheduling. */
125 static int c6x_flag_modulo_sched
;
127 /* Record the state of flag_pic before we set it to 1 for DSBT. */
128 int c6x_initial_flag_pic
;
132 /* We record the clock cycle for every insn during scheduling. */
134 /* After scheduling, we run assign_reservations to choose unit
135 reservations for all insns. These are recorded here. */
137 /* Records the new condition for insns which must be made
138 conditional after scheduling. An entry of NULL_RTX means no such
139 change is necessary. */
141 /* True for the first insn that was scheduled in an ebb. */
143 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
144 bits rather than storing the state. Meaningful only for the last
146 unsigned int unit_mask
;
147 } c6x_sched_insn_info
;
150 /* Record a c6x_sched_insn_info structure for every insn in the function. */
151 static vec
<c6x_sched_insn_info
> insn_info
;
153 #define INSN_INFO_LENGTH (insn_info).length ()
154 #define INSN_INFO_ENTRY(N) (insn_info[(N)])
156 static bool done_cfi_sections
;
158 #define RESERVATION_FLAG_D 1
159 #define RESERVATION_FLAG_L 2
160 #define RESERVATION_FLAG_S 4
161 #define RESERVATION_FLAG_M 8
162 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
163 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
164 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
165 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
167 /* The DFA names of the units. */
168 static const char *const c6x_unit_names
[] =
170 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
171 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
174 /* The DFA unit number for each unit in c6x_unit_names[]. */
175 static int c6x_unit_codes
[ARRAY_SIZE (c6x_unit_names
)];
177 /* Unit query IDs. */
178 #define UNIT_QID_D1 0
179 #define UNIT_QID_L1 1
180 #define UNIT_QID_S1 2
181 #define UNIT_QID_M1 3
182 #define UNIT_QID_FPS1 4
183 #define UNIT_QID_FPL1 5
184 #define UNIT_QID_ADDDPS1 6
185 #define UNIT_QID_ADDDPL1 7
186 #define UNIT_QID_SIDE_OFFSET 8
188 #define RESERVATION_S1 2
189 #define RESERVATION_S2 10
191 /* An enum for the unit requirements we count in the UNIT_REQS table. */
207 /* A table used to count unit requirements. Used when computing minimum
208 iteration intervals. */
209 typedef int unit_req_table
[2][UNIT_REQ_MAX
];
210 static unit_req_table unit_reqs
;
212 /* Register map for debugging. */
213 unsigned const dbx_register_map
[FIRST_PSEUDO_REGISTER
] =
215 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
216 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
218 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
220 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
222 -1, -1, -1 /* FP, ARGP, ILC. */
225 /* Allocate a new, cleared machine_function structure. */
227 static struct machine_function
*
228 c6x_init_machine_status (void)
230 return ggc_cleared_alloc
<machine_function
> ();
233 /* Implement TARGET_OPTION_OVERRIDE. */
236 c6x_option_override (void)
240 if (global_options_set
.x_c6x_arch_option
)
242 c6x_arch
= all_isas
[c6x_arch_option
].type
;
243 c6x_insn_mask
&= ~C6X_INSNS_ALL_CPU_BITS
;
244 c6x_insn_mask
|= all_isas
[c6x_arch_option
].features
;
247 c6x_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
248 flag_schedule_insns_after_reload
= 0;
250 c6x_flag_modulo_sched
= flag_modulo_sched
;
251 flag_modulo_sched
= 0;
253 init_machine_status
= c6x_init_machine_status
;
255 for (i
= 0; i
< ARRAY_SIZE (c6x_unit_names
); i
++)
256 c6x_unit_codes
[i
] = get_cpu_unit_code (c6x_unit_names
[i
]);
258 if (flag_pic
&& !TARGET_DSBT
)
260 error ("-fpic and -fPIC not supported without -mdsbt on this target");
263 c6x_initial_flag_pic
= flag_pic
;
264 if (TARGET_DSBT
&& !flag_pic
)
269 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
272 c6x_conditional_register_usage (void)
275 if (c6x_arch
== C6X_CPU_C62X
|| c6x_arch
== C6X_CPU_C67X
)
276 for (i
= 16; i
< 32; i
++)
279 fixed_regs
[32 + i
] = 1;
283 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_A_REGS
],
285 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_REGS
],
287 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_A_REGS
],
289 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_REGS
],
294 static GTY(()) rtx eqdf_libfunc
;
295 static GTY(()) rtx nedf_libfunc
;
296 static GTY(()) rtx ledf_libfunc
;
297 static GTY(()) rtx ltdf_libfunc
;
298 static GTY(()) rtx gedf_libfunc
;
299 static GTY(()) rtx gtdf_libfunc
;
300 static GTY(()) rtx eqsf_libfunc
;
301 static GTY(()) rtx nesf_libfunc
;
302 static GTY(()) rtx lesf_libfunc
;
303 static GTY(()) rtx ltsf_libfunc
;
304 static GTY(()) rtx gesf_libfunc
;
305 static GTY(()) rtx gtsf_libfunc
;
306 static GTY(()) rtx strasgi_libfunc
;
307 static GTY(()) rtx strasgi64p_libfunc
;
309 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
310 functions to match the C6x ABI. */
313 c6x_init_libfuncs (void)
315 /* Double-precision floating-point arithmetic. */
316 set_optab_libfunc (add_optab
, DFmode
, "__c6xabi_addd");
317 set_optab_libfunc (sdiv_optab
, DFmode
, "__c6xabi_divd");
318 set_optab_libfunc (smul_optab
, DFmode
, "__c6xabi_mpyd");
319 set_optab_libfunc (neg_optab
, DFmode
, "__c6xabi_negd");
320 set_optab_libfunc (sub_optab
, DFmode
, "__c6xabi_subd");
322 /* Single-precision floating-point arithmetic. */
323 set_optab_libfunc (add_optab
, SFmode
, "__c6xabi_addf");
324 set_optab_libfunc (sdiv_optab
, SFmode
, "__c6xabi_divf");
325 set_optab_libfunc (smul_optab
, SFmode
, "__c6xabi_mpyf");
326 set_optab_libfunc (neg_optab
, SFmode
, "__c6xabi_negf");
327 set_optab_libfunc (sub_optab
, SFmode
, "__c6xabi_subf");
329 /* Floating-point comparisons. */
330 eqsf_libfunc
= init_one_libfunc ("__c6xabi_eqf");
331 nesf_libfunc
= init_one_libfunc ("__c6xabi_neqf");
332 lesf_libfunc
= init_one_libfunc ("__c6xabi_lef");
333 ltsf_libfunc
= init_one_libfunc ("__c6xabi_ltf");
334 gesf_libfunc
= init_one_libfunc ("__c6xabi_gef");
335 gtsf_libfunc
= init_one_libfunc ("__c6xabi_gtf");
336 eqdf_libfunc
= init_one_libfunc ("__c6xabi_eqd");
337 nedf_libfunc
= init_one_libfunc ("__c6xabi_neqd");
338 ledf_libfunc
= init_one_libfunc ("__c6xabi_led");
339 ltdf_libfunc
= init_one_libfunc ("__c6xabi_ltd");
340 gedf_libfunc
= init_one_libfunc ("__c6xabi_ged");
341 gtdf_libfunc
= init_one_libfunc ("__c6xabi_gtd");
343 set_optab_libfunc (eq_optab
, SFmode
, NULL
);
344 set_optab_libfunc (ne_optab
, SFmode
, "__c6xabi_neqf");
345 set_optab_libfunc (gt_optab
, SFmode
, NULL
);
346 set_optab_libfunc (ge_optab
, SFmode
, NULL
);
347 set_optab_libfunc (lt_optab
, SFmode
, NULL
);
348 set_optab_libfunc (le_optab
, SFmode
, NULL
);
349 set_optab_libfunc (unord_optab
, SFmode
, "__c6xabi_unordf");
350 set_optab_libfunc (eq_optab
, DFmode
, NULL
);
351 set_optab_libfunc (ne_optab
, DFmode
, "__c6xabi_neqd");
352 set_optab_libfunc (gt_optab
, DFmode
, NULL
);
353 set_optab_libfunc (ge_optab
, DFmode
, NULL
);
354 set_optab_libfunc (lt_optab
, DFmode
, NULL
);
355 set_optab_libfunc (le_optab
, DFmode
, NULL
);
356 set_optab_libfunc (unord_optab
, DFmode
, "__c6xabi_unordd");
358 /* Floating-point to integer conversions. */
359 set_conv_libfunc (sfix_optab
, SImode
, DFmode
, "__c6xabi_fixdi");
360 set_conv_libfunc (ufix_optab
, SImode
, DFmode
, "__c6xabi_fixdu");
361 set_conv_libfunc (sfix_optab
, DImode
, DFmode
, "__c6xabi_fixdlli");
362 set_conv_libfunc (ufix_optab
, DImode
, DFmode
, "__c6xabi_fixdull");
363 set_conv_libfunc (sfix_optab
, SImode
, SFmode
, "__c6xabi_fixfi");
364 set_conv_libfunc (ufix_optab
, SImode
, SFmode
, "__c6xabi_fixfu");
365 set_conv_libfunc (sfix_optab
, DImode
, SFmode
, "__c6xabi_fixflli");
366 set_conv_libfunc (ufix_optab
, DImode
, SFmode
, "__c6xabi_fixfull");
368 /* Conversions between floating types. */
369 set_conv_libfunc (trunc_optab
, SFmode
, DFmode
, "__c6xabi_cvtdf");
370 set_conv_libfunc (sext_optab
, DFmode
, SFmode
, "__c6xabi_cvtfd");
372 /* Integer to floating-point conversions. */
373 set_conv_libfunc (sfloat_optab
, DFmode
, SImode
, "__c6xabi_fltid");
374 set_conv_libfunc (ufloat_optab
, DFmode
, SImode
, "__c6xabi_fltud");
375 set_conv_libfunc (sfloat_optab
, DFmode
, DImode
, "__c6xabi_fltllid");
376 set_conv_libfunc (ufloat_optab
, DFmode
, DImode
, "__c6xabi_fltulld");
377 set_conv_libfunc (sfloat_optab
, SFmode
, SImode
, "__c6xabi_fltif");
378 set_conv_libfunc (ufloat_optab
, SFmode
, SImode
, "__c6xabi_fltuf");
379 set_conv_libfunc (sfloat_optab
, SFmode
, DImode
, "__c6xabi_fltllif");
380 set_conv_libfunc (ufloat_optab
, SFmode
, DImode
, "__c6xabi_fltullf");
383 set_optab_libfunc (smul_optab
, DImode
, "__c6xabi_mpyll");
384 set_optab_libfunc (ashl_optab
, DImode
, "__c6xabi_llshl");
385 set_optab_libfunc (lshr_optab
, DImode
, "__c6xabi_llshru");
386 set_optab_libfunc (ashr_optab
, DImode
, "__c6xabi_llshr");
388 set_optab_libfunc (sdiv_optab
, SImode
, "__c6xabi_divi");
389 set_optab_libfunc (udiv_optab
, SImode
, "__c6xabi_divu");
390 set_optab_libfunc (smod_optab
, SImode
, "__c6xabi_remi");
391 set_optab_libfunc (umod_optab
, SImode
, "__c6xabi_remu");
392 set_optab_libfunc (sdivmod_optab
, SImode
, "__c6xabi_divremi");
393 set_optab_libfunc (udivmod_optab
, SImode
, "__c6xabi_divremu");
394 set_optab_libfunc (sdiv_optab
, DImode
, "__c6xabi_divlli");
395 set_optab_libfunc (udiv_optab
, DImode
, "__c6xabi_divull");
396 set_optab_libfunc (smod_optab
, DImode
, "__c6xabi_remlli");
397 set_optab_libfunc (umod_optab
, DImode
, "__c6xabi_remull");
398 set_optab_libfunc (udivmod_optab
, DImode
, "__c6xabi_divremull");
401 strasgi_libfunc
= init_one_libfunc ("__c6xabi_strasgi");
402 strasgi64p_libfunc
= init_one_libfunc ("__c6xabi_strasgi_64plus");
405 /* Begin the assembly file. */
408 c6x_file_start (void)
410 /* Variable tracking should be run after all optimizations which change order
411 of insns. It also needs a valid CFG. This can't be done in
412 c6x_override_options, because flag_var_tracking is finalized after
414 c6x_flag_var_tracking
= flag_var_tracking
;
415 flag_var_tracking
= 0;
417 done_cfi_sections
= false;
418 default_file_start ();
420 /* Arrays are aligned to 8-byte boundaries. */
421 asm_fprintf (asm_out_file
,
422 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
423 asm_fprintf (asm_out_file
,
424 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
426 /* Stack alignment is 8 bytes. */
427 asm_fprintf (asm_out_file
,
428 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
429 asm_fprintf (asm_out_file
,
430 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
432 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
433 /* ??? Ideally we'd check flag_short_wchar somehow. */
434 asm_fprintf (asm_out_file
, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
437 /* We conform to version 1.0 of the ABI. */
438 asm_fprintf (asm_out_file
,
439 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
443 /* The LTO frontend only enables exceptions when it sees a function that
444 uses it. This changes the return value of dwarf2out_do_frame, so we
445 have to check before every function. */
448 c6x_output_file_unwind (FILE * f
)
450 if (done_cfi_sections
)
453 /* Output a .cfi_sections directive. */
454 if (dwarf2out_do_frame ())
456 if (flag_unwind_tables
|| flag_exceptions
)
458 if (write_symbols
== DWARF2_DEBUG
459 || write_symbols
== VMS_AND_DWARF2_DEBUG
)
460 asm_fprintf (f
, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
462 asm_fprintf (f
, "\t.cfi_sections .c6xabi.exidx\n");
465 asm_fprintf (f
, "\t.cfi_sections .debug_frame\n");
466 done_cfi_sections
= true;
470 /* Output unwind directives at the end of a function. */
473 c6x_output_fn_unwind (FILE * f
)
475 /* Return immediately if we are not generating unwinding tables. */
476 if (! (flag_unwind_tables
|| flag_exceptions
))
479 /* If this function will never be unwound, then mark it as such. */
480 if (!(flag_unwind_tables
|| crtl
->uses_eh_lsda
)
481 && (TREE_NOTHROW (current_function_decl
)
482 || crtl
->all_throwers_are_sibcalls
))
483 fputs("\t.cantunwind\n", f
);
485 fputs ("\t.endp\n", f
);
489 /* Stack and Calling. */
491 int argument_registers
[10] =
500 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
503 c6x_init_cumulative_args (CUMULATIVE_ARGS
*cum
, const_tree fntype
, rtx libname
,
504 int n_named_args ATTRIBUTE_UNUSED
)
508 if (!libname
&& fntype
)
510 /* We need to find out the number of named arguments. Unfortunately,
511 for incoming arguments, N_NAMED_ARGS is set to -1. */
512 if (stdarg_p (fntype
))
513 cum
->nregs
= type_num_arguments (fntype
) - 1;
519 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
522 c6x_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
523 const_tree type
, bool named ATTRIBUTE_UNUSED
)
525 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
526 if (cum
->count
>= cum
->nregs
)
530 HOST_WIDE_INT size
= int_size_in_bytes (type
);
531 if (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (type
))
535 rtx reg1
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
] + 1);
536 rtx reg2
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
]);
537 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
538 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
539 return gen_rtx_PARALLEL (mode
, vec
);
543 return gen_rtx_REG (mode
, argument_registers
[cum
->count
]);
547 c6x_function_arg_advance (cumulative_args_t cum_v
,
548 machine_mode mode ATTRIBUTE_UNUSED
,
549 const_tree type ATTRIBUTE_UNUSED
,
550 bool named ATTRIBUTE_UNUSED
)
552 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
557 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
558 upward rather than downward. */
561 c6x_block_reg_pad_upward (machine_mode mode ATTRIBUTE_UNUSED
,
562 const_tree type
, bool first
)
566 if (!TARGET_BIG_ENDIAN
)
572 size
= int_size_in_bytes (type
);
576 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
579 c6x_function_arg_boundary (machine_mode mode
, const_tree type
)
581 unsigned int boundary
= type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
);
583 if (boundary
> BITS_PER_WORD
)
584 return 2 * BITS_PER_WORD
;
588 HOST_WIDE_INT size
= int_size_in_bytes (type
);
590 return 2 * BITS_PER_WORD
;
591 if (boundary
< BITS_PER_WORD
)
594 return BITS_PER_WORD
;
596 return 2 * BITS_PER_UNIT
;
602 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
604 c6x_function_arg_round_boundary (machine_mode mode
, const_tree type
)
606 return c6x_function_arg_boundary (mode
, type
);
609 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
610 where function FUNC returns or receives a value of data type TYPE. */
613 c6x_function_value (const_tree type
, const_tree func ATTRIBUTE_UNUSED
,
614 bool outgoing ATTRIBUTE_UNUSED
)
616 /* Functions return values in register A4. When returning aggregates, we may
617 have to adjust for endianness. */
618 if (TARGET_BIG_ENDIAN
&& type
&& AGGREGATE_TYPE_P (type
))
620 HOST_WIDE_INT size
= int_size_in_bytes (type
);
624 rtx reg1
= gen_rtx_REG (SImode
, REG_A4
+ 1);
625 rtx reg2
= gen_rtx_REG (SImode
, REG_A4
);
626 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
627 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
628 return gen_rtx_PARALLEL (TYPE_MODE (type
), vec
);
631 return gen_rtx_REG (TYPE_MODE (type
), REG_A4
);
634 /* Implement TARGET_LIBCALL_VALUE. */
637 c6x_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
639 return gen_rtx_REG (mode
, REG_A4
);
642 /* TARGET_STRUCT_VALUE_RTX implementation. */
645 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED
, int incoming ATTRIBUTE_UNUSED
)
647 return gen_rtx_REG (Pmode
, REG_A3
);
650 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
653 c6x_function_value_regno_p (const unsigned int regno
)
655 return regno
== REG_A4
;
658 /* Types larger than 64 bit, and variable sized types, are passed by
659 reference. The callee must copy them; see c6x_callee_copies. */
662 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
663 machine_mode mode
, const_tree type
,
664 bool named ATTRIBUTE_UNUSED
)
668 size
= int_size_in_bytes (type
);
669 else if (mode
!= VOIDmode
)
670 size
= GET_MODE_SIZE (mode
);
671 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
674 /* Decide whether a type should be returned in memory (true)
675 or in a register (false). This is called by the macro
676 TARGET_RETURN_IN_MEMORY. */
679 c6x_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
681 int size
= int_size_in_bytes (type
);
682 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
685 /* Values which must be returned in the most-significant end of the return
689 c6x_return_in_msb (const_tree valtype
)
691 HOST_WIDE_INT size
= int_size_in_bytes (valtype
);
692 return TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
) && size
== 3;
695 /* Implement TARGET_CALLEE_COPIES. */
698 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
699 machine_mode mode ATTRIBUTE_UNUSED
,
700 const_tree type ATTRIBUTE_UNUSED
,
701 bool named ATTRIBUTE_UNUSED
)
706 /* Return the type to use as __builtin_va_list. */
708 c6x_build_builtin_va_list (void)
710 return build_pointer_type (char_type_node
);
714 c6x_asm_trampoline_template (FILE *f
)
716 fprintf (f
, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
717 fprintf (f
, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
718 fprintf (f
, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
719 fprintf (f
, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
720 fprintf (f
, "\t.long\t0x00000362\n"); /* b .s2 B0 */
721 fprintf (f
, "\t.long\t0x00008000\n"); /* nop 5 */
722 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
723 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
726 /* Emit RTL insns to initialize the variable parts of a trampoline at
727 TRAMP. FNADDR is an RTX for the address of the function's pure
728 code. CXT is an RTX for the static chain value for the function. */
731 c6x_initialize_trampoline (rtx tramp
, tree fndecl
, rtx cxt
)
733 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
734 rtx t1
= copy_to_reg (fnaddr
);
735 rtx t2
= copy_to_reg (cxt
);
736 rtx mask
= gen_reg_rtx (SImode
);
739 emit_block_move (tramp
, assemble_trampoline_template (),
740 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
742 emit_move_insn (mask
, GEN_INT (0xffff << 7));
744 for (i
= 0; i
< 4; i
++)
746 rtx mem
= adjust_address (tramp
, SImode
, i
* 4);
747 rtx t
= (i
& 1) ? t2
: t1
;
748 rtx v1
= gen_reg_rtx (SImode
);
749 rtx v2
= gen_reg_rtx (SImode
);
750 emit_move_insn (v1
, mem
);
752 emit_insn (gen_ashlsi3 (v2
, t
, GEN_INT (7)));
754 emit_insn (gen_lshrsi3 (v2
, t
, GEN_INT (9)));
755 emit_insn (gen_andsi3 (v2
, v2
, mask
));
756 emit_insn (gen_iorsi3 (v2
, v2
, v1
));
757 emit_move_insn (mem
, v2
);
759 #ifdef CLEAR_INSN_CACHE
760 tramp
= XEXP (tramp
, 0);
761 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__gnu_clear_cache"),
762 LCT_NORMAL
, VOIDmode
, 2, tramp
, Pmode
,
763 plus_constant (Pmode
, tramp
, TRAMPOLINE_SIZE
),
768 /* Determine whether c6x_output_mi_thunk can succeed. */
771 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED
,
772 HOST_WIDE_INT delta ATTRIBUTE_UNUSED
,
773 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED
,
774 const_tree function ATTRIBUTE_UNUSED
)
776 return !TARGET_LONG_CALLS
;
779 /* Output the assembler code for a thunk function. THUNK is the
780 declaration for the thunk function itself, FUNCTION is the decl for
781 the target function. DELTA is an immediate constant offset to be
782 added to THIS. If VCALL_OFFSET is nonzero, the word at
783 *(*this + vcall_offset) should be added to THIS. */
786 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
787 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
788 HOST_WIDE_INT vcall_offset
, tree function
)
791 /* The this parameter is passed as the first argument. */
792 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_A4
);
794 c6x_current_insn
= NULL
;
796 xops
[4] = XEXP (DECL_RTL (function
), 0);
799 output_asm_insn ("b .s2 \t%4", xops
);
801 output_asm_insn ("nop 5", xops
);
804 /* Adjust the this parameter by a fixed constant. */
807 xops
[0] = GEN_INT (delta
);
809 if (delta
>= -16 && delta
<= 15)
811 output_asm_insn ("add .s1 %0, %1, %1", xops
);
813 output_asm_insn ("nop 4", xops
);
815 else if (delta
>= 16 && delta
< 32)
817 output_asm_insn ("add .d1 %0, %1, %1", xops
);
819 output_asm_insn ("nop 4", xops
);
821 else if (delta
>= -32768 && delta
< 32768)
823 output_asm_insn ("mvk .s1 %0, A0", xops
);
824 output_asm_insn ("add .d1 %1, A0, %1", xops
);
826 output_asm_insn ("nop 3", xops
);
830 output_asm_insn ("mvkl .s1 %0, A0", xops
);
831 output_asm_insn ("mvkh .s1 %0, A0", xops
);
832 output_asm_insn ("add .d1 %1, A0, %1", xops
);
834 output_asm_insn ("nop 3", xops
);
838 /* Adjust the this parameter by a value stored in the vtable. */
841 rtx a0tmp
= gen_rtx_REG (Pmode
, REG_A0
);
842 rtx a3tmp
= gen_rtx_REG (Pmode
, REG_A3
);
846 xops
[3] = gen_rtx_MEM (Pmode
, a0tmp
);
847 output_asm_insn ("mv .s1 a4, %2", xops
);
848 output_asm_insn ("ldw .d1t1 %3, %2", xops
);
850 /* Adjust the this parameter. */
851 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (Pmode
, a0tmp
,
853 if (!memory_operand (xops
[0], Pmode
))
855 rtx tmp2
= gen_rtx_REG (Pmode
, REG_A1
);
856 xops
[0] = GEN_INT (vcall_offset
);
858 output_asm_insn ("mvkl .s1 %0, %1", xops
);
859 output_asm_insn ("mvkh .s1 %0, %1", xops
);
860 output_asm_insn ("nop 2", xops
);
861 output_asm_insn ("add .d1 %2, %1, %2", xops
);
862 xops
[0] = gen_rtx_MEM (Pmode
, a0tmp
);
865 output_asm_insn ("nop 4", xops
);
867 output_asm_insn ("ldw .d1t1 %0, %1", xops
);
868 output_asm_insn ("|| b .s2 \t%4", xops
);
869 output_asm_insn ("nop 4", xops
);
870 output_asm_insn ("add .d1 %2, %1, %2", xops
);
874 /* Return true if EXP goes in small data/bss. */
877 c6x_in_small_data_p (const_tree exp
)
879 /* We want to merge strings, so we never consider them small data. */
880 if (TREE_CODE (exp
) == STRING_CST
)
883 /* Functions are never small data. */
884 if (TREE_CODE (exp
) == FUNCTION_DECL
)
887 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_WEAK (exp
))
890 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_SECTION_NAME (exp
))
892 const char *section
= DECL_SECTION_NAME (exp
);
894 if (strcmp (section
, ".neardata") == 0
895 || strncmp (section
, ".neardata.", 10) == 0
896 || strncmp (section
, ".gnu.linkonce.s.", 16) == 0
897 || strcmp (section
, ".bss") == 0
898 || strncmp (section
, ".bss.", 5) == 0
899 || strncmp (section
, ".gnu.linkonce.sb.", 17) == 0
900 || strcmp (section
, ".rodata") == 0
901 || strncmp (section
, ".rodata.", 8) == 0
902 || strncmp (section
, ".gnu.linkonce.s2.", 17) == 0)
906 return PLACE_IN_SDATA_P (exp
);
911 /* Return a section for X. The only special thing we do here is to
912 honor small data. We don't have a tree type, so we can't use the
913 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
914 everything sized 8 bytes or smaller into small data. */
917 c6x_select_rtx_section (machine_mode mode
, rtx x
,
918 unsigned HOST_WIDE_INT align
)
920 if (c6x_sdata_mode
== C6X_SDATA_ALL
921 || (c6x_sdata_mode
!= C6X_SDATA_NONE
&& GET_MODE_SIZE (mode
) <= 8))
922 /* ??? Consider using mergeable sdata sections. */
923 return sdata_section
;
925 return default_elf_select_rtx_section (mode
, x
, align
);
929 c6x_elf_select_section (tree decl
, int reloc
,
930 unsigned HOST_WIDE_INT align
)
932 const char *sname
= NULL
;
933 unsigned int flags
= SECTION_WRITE
;
934 if (c6x_in_small_data_p (decl
))
936 switch (categorize_decl_for_section (decl
, reloc
))
947 flags
|= SECTION_BSS
;
954 switch (categorize_decl_for_section (decl
, reloc
))
959 case SECCAT_DATA_REL
:
960 sname
= ".fardata.rel";
962 case SECCAT_DATA_REL_LOCAL
:
963 sname
= ".fardata.rel.local";
965 case SECCAT_DATA_REL_RO
:
966 sname
= ".fardata.rel.ro";
968 case SECCAT_DATA_REL_RO_LOCAL
:
969 sname
= ".fardata.rel.ro.local";
973 flags
|= SECTION_BSS
;
989 /* We might get called with string constants, but get_named_section
990 doesn't like them as they are not DECLs. Also, we need to set
991 flags in that case. */
993 return get_section (sname
, flags
, NULL
);
994 return get_named_section (decl
, sname
, reloc
);
997 return default_elf_select_section (decl
, reloc
, align
);
1000 /* Build up a unique section name, expressed as a
1001 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
1002 RELOC indicates whether the initial value of EXP requires
1003 link-time relocations. */
1005 static void ATTRIBUTE_UNUSED
1006 c6x_elf_unique_section (tree decl
, int reloc
)
1008 const char *prefix
= NULL
;
1009 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
1010 bool one_only
= DECL_COMDAT_GROUP (decl
) && !HAVE_COMDAT_GROUP
;
1012 if (c6x_in_small_data_p (decl
))
1014 switch (categorize_decl_for_section (decl
, reloc
))
1017 prefix
= one_only
? ".s" : ".neardata";
1020 prefix
= one_only
? ".sb" : ".bss";
1022 case SECCAT_SRODATA
:
1023 prefix
= one_only
? ".s2" : ".rodata";
1025 case SECCAT_RODATA_MERGE_STR
:
1026 case SECCAT_RODATA_MERGE_STR_INIT
:
1027 case SECCAT_RODATA_MERGE_CONST
:
1030 case SECCAT_DATA_REL
:
1031 case SECCAT_DATA_REL_LOCAL
:
1032 case SECCAT_DATA_REL_RO
:
1033 case SECCAT_DATA_REL_RO_LOCAL
:
1036 /* Everything else we place into default sections and hope for the
1043 switch (categorize_decl_for_section (decl
, reloc
))
1046 case SECCAT_DATA_REL
:
1047 case SECCAT_DATA_REL_LOCAL
:
1048 case SECCAT_DATA_REL_RO
:
1049 case SECCAT_DATA_REL_RO_LOCAL
:
1050 prefix
= one_only
? ".fd" : ".fardata";
1053 prefix
= one_only
? ".fb" : ".far";
1056 case SECCAT_RODATA_MERGE_STR
:
1057 case SECCAT_RODATA_MERGE_STR_INIT
:
1058 case SECCAT_RODATA_MERGE_CONST
:
1059 prefix
= one_only
? ".fr" : ".const";
1061 case SECCAT_SRODATA
:
1072 const char *name
, *linkonce
;
1075 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
1076 name
= targetm
.strip_name_encoding (name
);
1078 /* If we're using one_only, then there needs to be a .gnu.linkonce
1079 prefix to the section name. */
1080 linkonce
= one_only
? ".gnu.linkonce" : "";
1082 string
= ACONCAT ((linkonce
, prefix
, ".", name
, NULL
));
1084 set_decl_section_name (decl
, string
);
1087 default_unique_section (decl
, reloc
);
1091 c6x_section_type_flags (tree decl
, const char *name
, int reloc
)
1093 unsigned int flags
= 0;
1095 if (strcmp (name
, ".far") == 0
1096 || strncmp (name
, ".far.", 5) == 0)
1097 flags
|= SECTION_BSS
;
1099 flags
|= default_section_type_flags (decl
, name
, reloc
);
1104 /* Checks whether the given CALL_EXPR would use a caller saved
1105 register. This is used to decide whether sibling call optimization
1106 could be performed on the respective function call. */
1109 c6x_call_saved_register_used (tree call_expr
)
1111 CUMULATIVE_ARGS cum_v
;
1112 cumulative_args_t cum
;
1113 HARD_REG_SET call_saved_regset
;
1120 INIT_CUMULATIVE_ARGS (cum_v
, NULL
, NULL
, 0, 0);
1121 cum
= pack_cumulative_args (&cum_v
);
1123 COMPL_HARD_REG_SET (call_saved_regset
, call_used_reg_set
);
1124 for (i
= 0; i
< call_expr_nargs (call_expr
); i
++)
1126 parameter
= CALL_EXPR_ARG (call_expr
, i
);
1127 gcc_assert (parameter
);
1129 /* For an undeclared variable passed as parameter we will get
1130 an ERROR_MARK node here. */
1131 if (TREE_CODE (parameter
) == ERROR_MARK
)
1134 type
= TREE_TYPE (parameter
);
1137 mode
= TYPE_MODE (type
);
1140 if (pass_by_reference (&cum_v
, mode
, type
, true))
1143 type
= build_pointer_type (type
);
1146 parm_rtx
= c6x_function_arg (cum
, mode
, type
, 0);
1148 c6x_function_arg_advance (cum
, mode
, type
, 0);
1153 if (REG_P (parm_rtx
)
1154 && overlaps_hard_reg_set_p (call_saved_regset
, GET_MODE (parm_rtx
),
1157 if (GET_CODE (parm_rtx
) == PARALLEL
)
1159 int n
= XVECLEN (parm_rtx
, 0);
1162 rtx x
= XEXP (XVECEXP (parm_rtx
, 0, n
), 0);
1164 && overlaps_hard_reg_set_p (call_saved_regset
,
1165 GET_MODE (x
), REGNO (x
)))
1173 /* Decide whether we can make a sibling call to a function. DECL is the
1174 declaration of the function being targeted by the call and EXP is the
1175 CALL_EXPR representing the call. */
1178 c6x_function_ok_for_sibcall (tree decl
, tree exp
)
1180 /* Registers A10, A12, B10 and B12 are available as arguments
1181 register but unfortunately caller saved. This makes functions
1182 needing these registers for arguments not suitable for
1184 if (c6x_call_saved_register_used (exp
))
1192 /* When compiling for DSBT, the calling function must be local,
1193 so that when we reload B14 in the sibcall epilogue, it will
1194 not change its value. */
1195 struct cgraph_local_info
*this_func
;
1198 /* Not enough information. */
1201 this_func
= cgraph_node::local_info (current_function_decl
);
1202 return this_func
->local
;
1208 /* Return true if DECL is known to be linked into section SECTION. */
1211 c6x_function_in_section_p (tree decl
, section
*section
)
1213 /* We can only be certain about functions defined in the same
1214 compilation unit. */
1215 if (!TREE_STATIC (decl
))
1218 /* Make sure that SYMBOL always binds to the definition in this
1219 compilation unit. */
1220 if (!targetm
.binds_local_p (decl
))
1223 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1224 if (!DECL_SECTION_NAME (decl
))
1226 /* Make sure that we will not create a unique section for DECL. */
1227 if (flag_function_sections
|| DECL_COMDAT_GROUP (decl
))
1231 return function_section (decl
) == section
;
1234 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1237 c6x_long_call_p (rtx op
)
1241 if (!TARGET_LONG_CALLS
)
1244 decl
= SYMBOL_REF_DECL (op
);
1246 /* Try to determine whether the symbol is in the same section as the current
1247 function. Be conservative, and only cater for cases in which the
1248 whole of the current function is placed in the same section. */
1249 if (decl
!= NULL_TREE
1250 && !flag_reorder_blocks_and_partition
1251 && TREE_CODE (decl
) == FUNCTION_DECL
1252 && c6x_function_in_section_p (decl
, current_function_section ()))
1258 /* Emit the sequence for a call. */
1260 c6x_expand_call (rtx retval
, rtx address
, bool sibcall
)
1262 rtx callee
= XEXP (address
, 0);
1265 if (!c6x_call_operand (callee
, Pmode
))
1267 callee
= force_reg (Pmode
, callee
);
1268 address
= change_address (address
, Pmode
, callee
);
1270 call_insn
= gen_rtx_CALL (VOIDmode
, address
, const0_rtx
);
1273 call_insn
= emit_call_insn (call_insn
);
1274 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
),
1275 gen_rtx_REG (Pmode
, REG_B3
));
1279 if (retval
== NULL_RTX
)
1280 call_insn
= emit_call_insn (call_insn
);
1282 call_insn
= emit_call_insn (gen_rtx_SET (retval
, call_insn
));
1285 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
), pic_offset_table_rtx
);
1288 /* Legitimize PIC addresses. If the address is already position-independent,
1289 we return ORIG. Newly generated position-independent addresses go into a
1290 reg. This is REG if nonzero, otherwise we allocate register(s) as
1291 necessary. PICREG is the register holding the pointer to the PIC offset
1295 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
1300 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
1302 int unspec
= UNSPEC_LOAD_GOT
;
1307 gcc_assert (can_create_pseudo_p ());
1308 reg
= gen_reg_rtx (Pmode
);
1312 if (can_create_pseudo_p ())
1313 tmp
= gen_reg_rtx (Pmode
);
1316 emit_insn (gen_movsi_gotoff_high (tmp
, addr
));
1317 emit_insn (gen_movsi_gotoff_lo_sum (tmp
, tmp
, addr
));
1318 emit_insn (gen_load_got_gotoff (reg
, picreg
, tmp
));
1322 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
1323 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
1325 emit_move_insn (reg
, new_rtx
);
1327 if (picreg
== pic_offset_table_rtx
)
1328 crtl
->uses_pic_offset_table
= 1;
1332 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
1336 if (GET_CODE (addr
) == CONST
)
1338 addr
= XEXP (addr
, 0);
1339 gcc_assert (GET_CODE (addr
) == PLUS
);
1342 if (XEXP (addr
, 0) == picreg
)
1347 gcc_assert (can_create_pseudo_p ());
1348 reg
= gen_reg_rtx (Pmode
);
1351 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
1352 addr
= legitimize_pic_address (XEXP (addr
, 1),
1353 base
== reg
? NULL_RTX
: reg
,
1356 if (GET_CODE (addr
) == CONST_INT
)
1358 gcc_assert (! reload_in_progress
&& ! reload_completed
);
1359 addr
= force_reg (Pmode
, addr
);
1362 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
1364 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
1365 addr
= XEXP (addr
, 1);
1368 return gen_rtx_PLUS (Pmode
, base
, addr
);
1374 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1375 Returns true if no further code must be generated, false if the caller
1376 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1379 expand_move (rtx
*operands
, machine_mode mode
)
1381 rtx dest
= operands
[0];
1382 rtx op
= operands
[1];
1384 if ((reload_in_progress
| reload_completed
) == 0
1385 && GET_CODE (dest
) == MEM
&& GET_CODE (op
) != REG
)
1386 operands
[1] = force_reg (mode
, op
);
1387 else if (mode
== SImode
&& symbolic_operand (op
, SImode
))
1391 if (sdata_symbolic_operand (op
, SImode
))
1393 emit_insn (gen_load_sdata_pic (dest
, pic_offset_table_rtx
, op
));
1394 crtl
->uses_pic_offset_table
= 1;
1399 rtx temp
= (reload_completed
|| reload_in_progress
1400 ? dest
: gen_reg_rtx (Pmode
));
1402 operands
[1] = legitimize_pic_address (op
, temp
,
1403 pic_offset_table_rtx
);
1406 else if (reload_completed
1407 && !sdata_symbolic_operand (op
, SImode
))
1409 emit_insn (gen_movsi_high (dest
, op
));
1410 emit_insn (gen_movsi_lo_sum (dest
, dest
, op
));
1417 /* This function is called when we're about to expand an integer compare
1418 operation which performs COMPARISON. It examines the second operand,
1419 and if it is an integer constant that cannot be used directly on the
1420 current machine in a comparison insn, it returns true. */
1422 c6x_force_op_for_comparison_p (enum rtx_code code
, rtx op
)
1424 if (!CONST_INT_P (op
) || satisfies_constraint_Iu4 (op
))
1427 if ((code
== EQ
|| code
== LT
|| code
== GT
)
1428 && !satisfies_constraint_Is5 (op
))
1430 if ((code
== GTU
|| code
== LTU
)
1431 && (!TARGET_INSNS_64
|| !satisfies_constraint_Iu5 (op
)))
1437 /* Emit comparison instruction if necessary, returning the expression
1438 that holds the compare result in the proper mode. Return the comparison
1439 that should be used in the jump insn. */
1442 c6x_expand_compare (rtx comparison
, machine_mode mode
)
1444 enum rtx_code code
= GET_CODE (comparison
);
1445 rtx op0
= XEXP (comparison
, 0);
1446 rtx op1
= XEXP (comparison
, 1);
1448 enum rtx_code jump_code
= code
;
1449 machine_mode op_mode
= GET_MODE (op0
);
1451 if (op_mode
== DImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1453 rtx t
= gen_reg_rtx (SImode
);
1454 emit_insn (gen_iorsi3 (t
, gen_lowpart (SImode
, op0
),
1455 gen_highpart (SImode
, op0
)));
1459 else if (op_mode
== DImode
)
1464 if (code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1466 code
= reverse_condition (code
);
1472 split_di (&op0
, 1, lo
, high
);
1473 split_di (&op1
, 1, lo
+ 1, high
+ 1);
1475 if (c6x_force_op_for_comparison_p (code
, high
[1])
1476 || c6x_force_op_for_comparison_p (EQ
, high
[1]))
1477 high
[1] = force_reg (SImode
, high
[1]);
1479 cmp1
= gen_reg_rtx (SImode
);
1480 cmp2
= gen_reg_rtx (SImode
);
1481 emit_insn (gen_rtx_SET (cmp1
, gen_rtx_fmt_ee (code
, SImode
,
1482 high
[0], high
[1])));
1485 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1486 lo
[1] = force_reg (SImode
, lo
[1]);
1487 emit_insn (gen_rtx_SET (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1489 emit_insn (gen_andsi3 (cmp1
, cmp1
, cmp2
));
1493 emit_insn (gen_rtx_SET (cmp2
, gen_rtx_EQ (SImode
, high
[0],
1497 else if (code
== LT
)
1499 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1500 lo
[1] = force_reg (SImode
, lo
[1]);
1501 emit_insn (gen_cmpsi_and (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1503 lo
[0], lo
[1], cmp2
));
1504 emit_insn (gen_iorsi3 (cmp1
, cmp1
, cmp2
));
1508 else if (TARGET_FP
&& !flag_finite_math_only
1509 && (op_mode
== DFmode
|| op_mode
== SFmode
)
1510 && code
!= EQ
&& code
!= NE
&& code
!= LT
&& code
!= GT
1511 && code
!= UNLE
&& code
!= UNGE
)
1513 enum rtx_code code1
, code2
, code3
;
1514 rtx (*fn
) (rtx
, rtx
, rtx
, rtx
, rtx
);
1526 code1
= code
== LE
|| code
== UNGT
? LT
: GT
;
1551 cmp
= gen_reg_rtx (SImode
);
1552 emit_insn (gen_rtx_SET (cmp
, gen_rtx_fmt_ee (code1
, SImode
, op0
, op1
)));
1553 fn
= op_mode
== DFmode
? gen_cmpdf_ior
: gen_cmpsf_ior
;
1554 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code2
, SImode
, op0
, op1
),
1556 if (code3
!= UNKNOWN
)
1557 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code3
, SImode
, op0
, op1
),
1560 else if (op_mode
== SImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1565 is_fp_libfunc
= !TARGET_FP
&& (op_mode
== DFmode
|| op_mode
== SFmode
);
1567 if ((code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1570 code
= reverse_condition (code
);
1573 else if (code
== UNGE
)
1578 else if (code
== UNLE
)
1593 libfunc
= op_mode
== DFmode
? eqdf_libfunc
: eqsf_libfunc
;
1596 libfunc
= op_mode
== DFmode
? nedf_libfunc
: nesf_libfunc
;
1599 libfunc
= op_mode
== DFmode
? gtdf_libfunc
: gtsf_libfunc
;
1602 libfunc
= op_mode
== DFmode
? gedf_libfunc
: gesf_libfunc
;
1605 libfunc
= op_mode
== DFmode
? ltdf_libfunc
: ltsf_libfunc
;
1608 libfunc
= op_mode
== DFmode
? ledf_libfunc
: lesf_libfunc
;
1615 cmp
= emit_library_call_value (libfunc
, 0, LCT_CONST
, SImode
, 2,
1616 op0
, op_mode
, op1
, op_mode
);
1617 insns
= get_insns ();
1620 emit_libcall_block (insns
, cmp
, cmp
,
1621 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
));
1625 cmp
= gen_reg_rtx (SImode
);
1626 if (c6x_force_op_for_comparison_p (code
, op1
))
1627 op1
= force_reg (SImode
, op1
);
1628 emit_insn (gen_rtx_SET (cmp
, gen_rtx_fmt_ee (code
, SImode
,
1633 return gen_rtx_fmt_ee (jump_code
, mode
, cmp
, const0_rtx
);
1636 /* Return one word of double-word value OP. HIGH_P is true to select the
1637 high part, false to select the low part. When encountering auto-increment
1638 addressing, we make the assumption that the low part is going to be accessed
1642 c6x_subword (rtx op
, bool high_p
)
1647 mode
= GET_MODE (op
);
1648 if (mode
== VOIDmode
)
1651 if (TARGET_BIG_ENDIAN
? !high_p
: high_p
)
1652 byte
= UNITS_PER_WORD
;
1658 rtx addr
= XEXP (op
, 0);
1659 if (GET_CODE (addr
) == PLUS
|| REG_P (addr
))
1660 return adjust_address (op
, word_mode
, byte
);
1661 /* FIXME: should really support autoincrement addressing for
1662 multi-word modes. */
1666 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
1669 /* Split one or more DImode RTL references into pairs of SImode
1670 references. The RTL can be REG, offsettable MEM, integer constant, or
1671 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1672 split and "num" is its length. lo_half and hi_half are output arrays
1673 that parallel "operands". */
1676 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1680 rtx op
= operands
[num
];
1682 lo_half
[num
] = c6x_subword (op
, false);
1683 hi_half
[num
] = c6x_subword (op
, true);
1687 /* Return true if VAL is a mask valid for a clr instruction. */
1689 c6x_valid_mask_p (HOST_WIDE_INT val
)
1692 for (i
= 0; i
< 32; i
++)
1693 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1696 if (val
& ((unsigned HOST_WIDE_INT
)1 << i
))
1699 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1704 /* Expand a block move for a movmemM pattern. */
1707 c6x_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
,
1708 rtx expected_align_exp ATTRIBUTE_UNUSED
,
1709 rtx expected_size_exp ATTRIBUTE_UNUSED
)
1711 unsigned HOST_WIDE_INT align
= 1;
1712 unsigned HOST_WIDE_INT src_mem_align
, dst_mem_align
, min_mem_align
;
1713 unsigned HOST_WIDE_INT count
= 0, offset
= 0;
1714 unsigned int biggest_move
= TARGET_STDW
? 8 : 4;
1716 if (CONST_INT_P (align_exp
))
1717 align
= INTVAL (align_exp
);
1719 src_mem_align
= MEM_ALIGN (src
) / BITS_PER_UNIT
;
1720 dst_mem_align
= MEM_ALIGN (dst
) / BITS_PER_UNIT
;
1721 min_mem_align
= MIN (src_mem_align
, dst_mem_align
);
1723 if (min_mem_align
> align
)
1724 align
= min_mem_align
/ BITS_PER_UNIT
;
1725 if (src_mem_align
< align
)
1726 src_mem_align
= align
;
1727 if (dst_mem_align
< align
)
1728 dst_mem_align
= align
;
1730 if (CONST_INT_P (count_exp
))
1731 count
= INTVAL (count_exp
);
1735 /* Make sure we don't need to care about overflow later on. */
1736 if (count
> ((unsigned HOST_WIDE_INT
) 1 << 30))
1739 if (count
>= 28 && (count
& 3) == 0 && align
>= 4)
1741 tree dst_expr
= MEM_EXPR (dst
);
1742 tree src_expr
= MEM_EXPR (src
);
1743 rtx fn
= TARGET_INSNS_64PLUS
? strasgi64p_libfunc
: strasgi_libfunc
;
1744 rtx srcreg
= force_reg (Pmode
, XEXP (src
, 0));
1745 rtx dstreg
= force_reg (Pmode
, XEXP (dst
, 0));
1748 mark_addressable (src_expr
);
1750 mark_addressable (dst_expr
);
1751 emit_library_call (fn
, LCT_NORMAL
, VOIDmode
, 3,
1752 dstreg
, Pmode
, srcreg
, Pmode
, count_exp
, SImode
);
1756 if (biggest_move
> align
&& !TARGET_INSNS_64
)
1757 biggest_move
= align
;
1759 if (count
/ biggest_move
> 7)
1764 rtx reg
, reg_lowpart
;
1765 machine_mode srcmode
, dstmode
;
1766 unsigned HOST_WIDE_INT src_size
, dst_size
, src_left
;
1770 while (biggest_move
> count
)
1773 src_size
= dst_size
= biggest_move
;
1774 if (src_size
> src_mem_align
&& src_size
== 2)
1776 if (dst_size
> dst_mem_align
&& dst_size
== 2)
1779 if (dst_size
> src_size
)
1780 dst_size
= src_size
;
1782 srcmode
= mode_for_size (src_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1783 dstmode
= mode_for_size (dst_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1785 reg_lowpart
= reg
= gen_reg_rtx (srcmode
);
1788 reg
= gen_reg_rtx (SImode
);
1789 reg_lowpart
= gen_lowpart (srcmode
, reg
);
1792 srcmem
= adjust_address (copy_rtx (src
), srcmode
, offset
);
1794 if (src_size
> src_mem_align
)
1796 enum insn_code icode
= (srcmode
== SImode
? CODE_FOR_movmisalignsi
1797 : CODE_FOR_movmisaligndi
);
1798 emit_insn (GEN_FCN (icode
) (reg_lowpart
, srcmem
));
1801 emit_move_insn (reg_lowpart
, srcmem
);
1803 src_left
= src_size
;
1804 shift
= TARGET_BIG_ENDIAN
? (src_size
- dst_size
) * BITS_PER_UNIT
: 0;
1805 while (src_left
> 0)
1807 rtx dstreg
= reg_lowpart
;
1809 if (src_size
> dst_size
)
1812 int shift_amount
= shift
& (BITS_PER_WORD
- 1);
1814 srcword
= operand_subword_force (srcword
, src_left
>= 4 ? 0 : 4,
1816 if (shift_amount
> 0)
1818 dstreg
= gen_reg_rtx (SImode
);
1819 emit_insn (gen_lshrsi3 (dstreg
, srcword
,
1820 GEN_INT (shift_amount
)));
1824 dstreg
= gen_lowpart (dstmode
, dstreg
);
1827 dstmem
= adjust_address (copy_rtx (dst
), dstmode
, offset
);
1828 if (dst_size
> dst_mem_align
)
1830 enum insn_code icode
= (dstmode
== SImode
? CODE_FOR_movmisalignsi
1831 : CODE_FOR_movmisaligndi
);
1832 emit_insn (GEN_FCN (icode
) (dstmem
, dstreg
));
1835 emit_move_insn (dstmem
, dstreg
);
1837 if (TARGET_BIG_ENDIAN
)
1838 shift
-= dst_size
* BITS_PER_UNIT
;
1840 shift
+= dst_size
* BITS_PER_UNIT
;
1842 src_left
-= dst_size
;
1849 /* Subroutine of print_address_operand, print a single address offset OFF for
1850 a memory access of mode MEM_MODE, choosing between normal form and scaled
1851 form depending on the type of the insn. Misaligned memory references must
1852 use the scaled form. */
1855 print_address_offset (FILE *file
, rtx off
, machine_mode mem_mode
)
1859 if (c6x_current_insn
!= NULL_RTX
)
1861 pat
= PATTERN (c6x_current_insn
);
1862 if (GET_CODE (pat
) == COND_EXEC
)
1863 pat
= COND_EXEC_CODE (pat
);
1864 if (GET_CODE (pat
) == PARALLEL
)
1865 pat
= XVECEXP (pat
, 0, 0);
1867 if (GET_CODE (pat
) == SET
1868 && GET_CODE (SET_SRC (pat
)) == UNSPEC
1869 && XINT (SET_SRC (pat
), 1) == UNSPEC_MISALIGNED_ACCESS
)
1871 gcc_assert (CONST_INT_P (off
)
1872 && (INTVAL (off
) & (GET_MODE_SIZE (mem_mode
) - 1)) == 0);
1873 fprintf (file
, "[" HOST_WIDE_INT_PRINT_DEC
"]",
1874 INTVAL (off
) / GET_MODE_SIZE (mem_mode
));
1879 output_address (off
);
1884 c6x_print_operand_punct_valid_p (unsigned char c
)
1886 return c
== '$' || c
== '.' || c
== '|';
1889 static void c6x_print_operand (FILE *, rtx
, int);
1891 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1894 c6x_print_address_operand (FILE *file
, rtx x
, machine_mode mem_mode
)
1897 switch (GET_CODE (x
))
1901 if (GET_CODE (x
) == POST_MODIFY
)
1902 output_address (XEXP (x
, 0));
1903 off
= XEXP (XEXP (x
, 1), 1);
1904 if (XEXP (x
, 0) == stack_pointer_rtx
)
1906 if (GET_CODE (x
) == PRE_MODIFY
)
1907 gcc_assert (INTVAL (off
) > 0);
1909 gcc_assert (INTVAL (off
) < 0);
1911 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1913 fprintf (file
, "--");
1914 off
= GEN_INT (-INTVAL (off
));
1917 fprintf (file
, "++");
1918 if (GET_CODE (x
) == PRE_MODIFY
)
1919 output_address (XEXP (x
, 0));
1920 print_address_offset (file
, off
, mem_mode
);
1925 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1927 fprintf (file
, "-");
1928 off
= GEN_INT (-INTVAL (off
));
1931 fprintf (file
, "+");
1932 output_address (XEXP (x
, 0));
1933 print_address_offset (file
, off
, mem_mode
);
1937 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1938 fprintf (file
, "--");
1939 output_address (XEXP (x
, 0));
1940 fprintf (file
, "[1]");
1943 fprintf (file
, "++");
1944 output_address (XEXP (x
, 0));
1945 fprintf (file
, "[1]");
1948 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1949 output_address (XEXP (x
, 0));
1950 fprintf (file
, "++[1]");
1953 output_address (XEXP (x
, 0));
1954 fprintf (file
, "--[1]");
1960 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
1961 fprintf (file
, "+B14(");
1962 output_addr_const (file
, x
);
1963 fprintf (file
, ")");
1967 switch (XINT (x
, 1))
1969 case UNSPEC_LOAD_GOT
:
1970 fputs ("$GOT(", file
);
1971 output_addr_const (file
, XVECEXP (x
, 0, 0));
1974 case UNSPEC_LOAD_SDATA
:
1975 output_addr_const (file
, XVECEXP (x
, 0, 0));
1983 gcc_assert (GET_CODE (x
) != MEM
);
1984 c6x_print_operand (file
, x
, 0);
1989 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1990 specifies the functional unit used by INSN. */
1993 c6x_get_unit_specifier (rtx_insn
*insn
)
1995 enum attr_units units
;
1997 if (insn_info
.exists ())
1999 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2000 return c6x_unit_names
[unit
][0];
2003 units
= get_attr_units (insn
);
2028 /* Prints the unit specifier field. */
2030 c6x_print_unit_specifier_field (FILE *file
, rtx_insn
*insn
)
2032 enum attr_units units
= get_attr_units (insn
);
2033 enum attr_cross cross
= get_attr_cross (insn
);
2034 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
2038 if (units
== UNITS_D_ADDR
)
2040 enum attr_addr_regfile arf
= get_attr_addr_regfile (insn
);
2042 gcc_assert (arf
!= ADDR_REGFILE_UNKNOWN
);
2043 half
= arf
== ADDR_REGFILE_A
? 1 : 2;
2044 t_half
= rf
== DEST_REGFILE_A
? 1 : 2;
2045 fprintf (file
, ".d%dt%d", half
, t_half
);
2049 if (insn_info
.exists ())
2051 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2053 fputs (c6x_unit_names
[unit
], file
);
2054 if (cross
== CROSS_Y
)
2059 gcc_assert (rf
!= DEST_REGFILE_UNKNOWN
);
2060 unitspec
= c6x_get_unit_specifier (insn
);
2061 half
= rf
== DEST_REGFILE_A
? 1 : 2;
2062 fprintf (file
, ".%c%d%s", unitspec
, half
, cross
== CROSS_Y
? "x" : "");
2065 /* Output assembly language output for the address ADDR to FILE. */
2067 c6x_print_operand_address (FILE *file
, rtx addr
)
2069 c6x_print_address_operand (file
, addr
, VOIDmode
);
2072 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2075 $ -- print the unit specifier field for the instruction.
2076 . -- print the predicate for the instruction or an emptry string for an
2078 | -- print "||" if the insn should be issued in parallel with the previous
2081 C -- print an opcode suffix for a reversed condition
2082 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2084 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2086 J -- print a predicate
2087 j -- like J, but use reverse predicate
2088 k -- treat a CONST_INT as a register number and print it as a register
2089 k -- like k, but print out a doubleword register
2090 n -- print an integer operand, negated
2091 p -- print the low part of a DImode register
2092 P -- print the high part of a DImode register
2093 r -- print the absolute value of an integer operand, shifted right by 1
2094 R -- print the absolute value of an integer operand, shifted right by 2
2095 f -- the first clear bit in an integer operand assumed to be a mask for
2097 F -- the last clear bit in such a mask
2098 s -- the first set bit in an integer operand assumed to be a mask for
2100 S -- the last set bit in such a mask
2101 U -- print either 1 or 2, depending on the side of the machine used by
2105 c6x_print_operand (FILE *file
, rtx x
, int code
)
2114 if (GET_MODE (c6x_current_insn
) != TImode
)
2120 c6x_print_unit_specifier_field (file
, c6x_current_insn
);
2126 x
= current_insn_predicate
;
2129 unsigned int regno
= REGNO (XEXP (x
, 0));
2131 if (GET_CODE (x
) == EQ
)
2133 fputs (reg_names
[regno
], file
);
2139 mode
= GET_MODE (x
);
2146 enum rtx_code c
= GET_CODE (x
);
2148 c
= swap_condition (c
);
2149 fputs (GET_RTX_NAME (c
), file
);
2156 unsigned int regno
= REGNO (XEXP (x
, 0));
2157 if ((GET_CODE (x
) == EQ
) == (code
== 'J'))
2159 fputs (reg_names
[regno
], file
);
2164 gcc_assert (GET_CODE (x
) == CONST_INT
);
2166 fprintf (file
, "%s", reg_names
[v
]);
2169 gcc_assert (GET_CODE (x
) == CONST_INT
);
2171 gcc_assert ((v
& 1) == 0);
2172 fprintf (file
, "%s:%s", reg_names
[v
+ 1], reg_names
[v
]);
2179 gcc_assert (GET_CODE (x
) == CONST_INT
);
2181 for (i
= 0; i
< 32; i
++)
2183 HOST_WIDE_INT tst
= v
& 1;
2184 if (((code
== 'f' || code
== 'F') && !tst
)
2185 || ((code
== 's' || code
== 'S') && tst
))
2189 if (code
== 'f' || code
== 's')
2191 fprintf (file
, "%d", i
);
2196 HOST_WIDE_INT tst
= v
& 1;
2197 if ((code
== 'F' && tst
) || (code
== 'S' && !tst
))
2201 fprintf (file
, "%d", i
- 1);
2205 gcc_assert (GET_CODE (x
) == CONST_INT
);
2206 output_addr_const (file
, GEN_INT (-INTVAL (x
)));
2210 gcc_assert (GET_CODE (x
) == CONST_INT
);
2214 output_addr_const (file
, GEN_INT (v
>> 1));
2218 gcc_assert (GET_CODE (x
) == CONST_INT
);
2222 output_addr_const (file
, GEN_INT (v
>> 2));
2226 gcc_assert (GET_CODE (x
) == CONST_INT
);
2228 fputs (v
== 2 ? "h" : v
== 4 ? "w" : "d", file
);
2233 gcc_assert (GET_CODE (x
) == REG
);
2237 fputs (reg_names
[v
], file
);
2242 if (GET_CODE (x
) == CONST
)
2245 gcc_assert (GET_CODE (x
) == PLUS
);
2246 gcc_assert (GET_CODE (XEXP (x
, 1)) == CONST_INT
);
2247 v
= INTVAL (XEXP (x
, 1));
2251 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
2253 t
= SYMBOL_REF_DECL (x
);
2255 v
|= DECL_ALIGN_UNIT (t
);
2257 v
|= TYPE_ALIGN_UNIT (TREE_TYPE (t
));
2270 if (GET_CODE (x
) == PLUS
2271 || GET_RTX_CLASS (GET_CODE (x
)) == RTX_AUTOINC
)
2273 if (GET_CODE (x
) == CONST
|| GET_CODE (x
) == SYMBOL_REF
)
2275 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
2280 gcc_assert (REG_P (x
));
2281 if (A_REGNO_P (REGNO (x
)))
2283 if (B_REGNO_P (REGNO (x
)))
2288 switch (GET_CODE (x
))
2291 if (GET_MODE_SIZE (mode
) == 8)
2292 fprintf (file
, "%s:%s", reg_names
[REGNO (x
) + 1],
2293 reg_names
[REGNO (x
)]);
2295 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
2300 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
2301 c6x_print_address_operand (file
, XEXP (x
, 0), GET_MODE (x
));
2306 output_addr_const (file
, x
);
2311 output_addr_const (file
, x
);
2315 output_operand_lossage ("invalid const_double operand");
2319 output_addr_const (file
, x
);
2324 /* Return TRUE if OP is a valid memory address with a base register of
2325 class C. If SMALL_OFFSET is true, we disallow memory references which would
2326 require a long offset with B14/B15. */
2329 c6x_mem_operand (rtx op
, enum reg_class c
, bool small_offset
)
2331 machine_mode mode
= GET_MODE (op
);
2332 rtx base
= XEXP (op
, 0);
2333 switch (GET_CODE (base
))
2339 && (XEXP (base
, 0) == stack_pointer_rtx
2340 || XEXP (base
, 0) == pic_offset_table_rtx
))
2342 if (!c6x_legitimate_address_p_1 (mode
, base
, true, true))
2353 base
= XEXP (base
, 0);
2359 gcc_assert (sdata_symbolic_operand (base
, Pmode
));
2360 return !small_offset
&& c
== B_REGS
;
2365 return TEST_HARD_REG_BIT (reg_class_contents
[ (int) (c
)], REGNO (base
));
2368 /* Returns true if X is a valid address for use in a memory reference
2369 of mode MODE. If STRICT is true, we do not allow pseudo registers
2370 in the address. NO_LARGE_OFFSET is true if we are examining an
2371 address for use in a load or store misaligned instruction, or
2372 recursively examining an operand inside a PRE/POST_MODIFY. */
2375 c6x_legitimate_address_p_1 (machine_mode mode
, rtx x
, bool strict
,
2376 bool no_large_offset
)
2380 enum rtx_code code
= GET_CODE (x
);
2386 /* We can't split these into word-sized pieces yet. */
2387 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2389 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
2391 if (!c6x_legitimate_address_p_1 (mode
, XEXP (x
, 1), strict
, true))
2393 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
2401 /* We can't split these into word-sized pieces yet. */
2402 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2411 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x
));
2413 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x
));
2416 if (!REG_P (XEXP (x
, 0))
2417 || !c6x_legitimate_address_p_1 (mode
, XEXP (x
, 0), strict
, false))
2419 /* We cannot ensure currently that both registers end up in the
2420 same register file. */
2421 if (REG_P (XEXP (x
, 1)))
2424 if (mode
== BLKmode
)
2426 else if (mode
== VOIDmode
)
2427 /* ??? This can happen during ivopts. */
2430 size
= GET_MODE_SIZE (mode
);
2433 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2434 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_SDATA
2435 && XEXP (x
, 0) == pic_offset_table_rtx
2436 && sdata_symbolic_operand (XVECEXP (XEXP (x
, 1), 0, 0), SImode
))
2437 return !no_large_offset
&& size
<= 4;
2440 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2441 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_GOT
2442 && XEXP (x
, 0) == pic_offset_table_rtx
2443 && (GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == SYMBOL_REF
2444 || GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == LABEL_REF
))
2445 return !no_large_offset
;
2446 if (GET_CODE (XEXP (x
, 1)) != CONST_INT
)
2449 off
= INTVAL (XEXP (x
, 1));
2451 /* If the machine does not have doubleword load/stores, we'll use
2452 word size accesses. */
2454 if (size
== 2 * UNITS_PER_WORD
&& !TARGET_STDW
)
2455 size
= UNITS_PER_WORD
;
2457 if (((HOST_WIDE_INT
)size1
- 1) & off
)
2460 if (off
> -32 && off
< (size1
== size
? 32 : 28))
2462 if (no_large_offset
|| code
!= PLUS
|| XEXP (x
, 0) != stack_pointer_rtx
2463 || size1
> UNITS_PER_WORD
)
2465 return off
>= 0 && off
< 32768;
2470 return (!no_large_offset
2471 /* With -fpic, we must wrap it in an unspec to show the B14
2474 && GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
2475 && sdata_symbolic_operand (x
, Pmode
));
2483 c6x_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
2485 return c6x_legitimate_address_p_1 (mode
, x
, strict
, false);
2489 c6x_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
,
2490 rtx x ATTRIBUTE_UNUSED
)
2495 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2497 c6x_preferred_rename_class (reg_class_t cl
)
2500 return NONPREDICATE_A_REGS
;
2502 return NONPREDICATE_B_REGS
;
2503 if (cl
== ALL_REGS
|| cl
== GENERAL_REGS
)
2504 return NONPREDICATE_REGS
;
2508 /* Implements FINAL_PRESCAN_INSN. */
2510 c6x_final_prescan_insn (rtx_insn
*insn
, rtx
*opvec ATTRIBUTE_UNUSED
,
2511 int noperands ATTRIBUTE_UNUSED
)
2513 c6x_current_insn
= insn
;
2516 /* A structure to describe the stack layout of a function. The layout is
2519 [saved frame pointer (or possibly padding0)]
2520 --> incoming stack pointer, new hard frame pointer
2521 [saved call-used regs]
2523 --> soft frame pointer
2525 [outgoing arguments]
2528 The structure members are laid out in this order. */
2533 /* Number of registers to save. */
2536 HOST_WIDE_INT frame
;
2537 int outgoing_arguments_size
;
2540 HOST_WIDE_INT to_allocate
;
2541 /* The offsets relative to the incoming stack pointer (which
2542 becomes HARD_FRAME_POINTER). */
2543 HOST_WIDE_INT frame_pointer_offset
;
2544 HOST_WIDE_INT b3_offset
;
2546 /* True if we should call push_rts/pop_rts to save and restore
2551 /* Return true if we need to save and modify the PIC register in the
2555 must_reload_pic_reg_p (void)
2557 struct cgraph_local_info
*i
= NULL
;
2562 i
= cgraph_node::local_info (current_function_decl
);
2564 if ((crtl
->uses_pic_offset_table
|| !crtl
->is_leaf
) && !i
->local
)
2569 /* Return 1 if we need to save REGNO. */
2571 c6x_save_reg (unsigned int regno
)
2573 return ((df_regs_ever_live_p (regno
)
2574 && !call_used_regs
[regno
]
2575 && !fixed_regs
[regno
])
2576 || (regno
== RETURN_ADDR_REGNO
2577 && (df_regs_ever_live_p (regno
)
2579 || (regno
== PIC_OFFSET_TABLE_REGNUM
&& must_reload_pic_reg_p ()));
2582 /* Examine the number of regs NREGS we've determined we must save.
2583 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2584 prologue and epilogue. */
2587 use_push_rts_p (int nregs
)
2589 if (TARGET_INSNS_64PLUS
&& optimize_function_for_size_p (cfun
)
2590 && !cfun
->machine
->contains_sibcall
2591 && !cfun
->returns_struct
2592 && !TARGET_LONG_CALLS
2593 && nregs
>= 6 && !frame_pointer_needed
)
2598 /* Return number of saved general prupose registers. */
2601 c6x_nsaved_regs (void)
2606 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
2607 if (c6x_save_reg (regno
))
2612 /* The safe debug order mandated by the ABI. */
2613 static unsigned reg_save_order
[] =
2615 REG_A10
, REG_A11
, REG_A12
, REG_A13
,
2617 REG_B10
, REG_B11
, REG_B12
, REG_B13
,
2621 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2623 /* Compute the layout of the stack frame and store it in FRAME. */
2626 c6x_compute_frame_layout (struct c6x_frame
*frame
)
2628 HOST_WIDE_INT size
= get_frame_size ();
2629 HOST_WIDE_INT offset
;
2632 /* We use the four bytes which are technically inside the caller's frame,
2633 usually to save the frame pointer. */
2635 frame
->padding0
= 0;
2636 nregs
= c6x_nsaved_regs ();
2637 frame
->push_rts
= false;
2638 frame
->b3_offset
= 0;
2639 if (use_push_rts_p (nregs
))
2641 frame
->push_rts
= true;
2642 frame
->b3_offset
= (TARGET_BIG_ENDIAN
? -12 : -13) * 4;
2645 else if (c6x_save_reg (REG_B3
))
2648 for (idx
= N_SAVE_ORDER
- 1; reg_save_order
[idx
] != REG_B3
; idx
--)
2650 if (c6x_save_reg (reg_save_order
[idx
]))
2651 frame
->b3_offset
-= 4;
2654 frame
->nregs
= nregs
;
2656 if (size
== 0 && nregs
== 0)
2658 frame
->padding0
= 4;
2659 frame
->padding1
= frame
->padding2
= 0;
2660 frame
->frame_pointer_offset
= frame
->to_allocate
= 0;
2661 frame
->outgoing_arguments_size
= 0;
2665 if (!frame
->push_rts
)
2666 offset
+= frame
->nregs
* 4;
2668 if (offset
== 0 && size
== 0 && crtl
->outgoing_args_size
== 0
2670 /* Don't use the bottom of the caller's frame if we have no
2671 allocation of our own and call other functions. */
2672 frame
->padding0
= frame
->padding1
= 4;
2673 else if (offset
& 4)
2674 frame
->padding1
= 4;
2676 frame
->padding1
= 0;
2678 offset
+= frame
->padding0
+ frame
->padding1
;
2679 frame
->frame_pointer_offset
= offset
;
2682 frame
->outgoing_arguments_size
= crtl
->outgoing_args_size
;
2683 offset
+= frame
->outgoing_arguments_size
;
2685 if ((offset
& 4) == 0)
2686 frame
->padding2
= 8;
2688 frame
->padding2
= 4;
2689 frame
->to_allocate
= offset
+ frame
->padding2
;
2692 /* Return the offset between two registers, one to be eliminated, and the other
2693 its replacement, at the start of a routine. */
2696 c6x_initial_elimination_offset (int from
, int to
)
2698 struct c6x_frame frame
;
2699 c6x_compute_frame_layout (&frame
);
2701 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
2703 else if (from
== FRAME_POINTER_REGNUM
2704 && to
== HARD_FRAME_POINTER_REGNUM
)
2705 return -frame
.frame_pointer_offset
;
2708 gcc_assert (to
== STACK_POINTER_REGNUM
);
2710 if (from
== ARG_POINTER_REGNUM
)
2711 return frame
.to_allocate
+ (frame
.push_rts
? 56 : 0);
2713 gcc_assert (from
== FRAME_POINTER_REGNUM
);
2714 return frame
.to_allocate
- frame
.frame_pointer_offset
;
2718 /* Given FROM and TO register numbers, say whether this elimination is
2719 allowed. Frame pointer elimination is automatically handled. */
2722 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
2724 if (to
== STACK_POINTER_REGNUM
)
2725 return !frame_pointer_needed
;
2729 /* Emit insns to increment the stack pointer by OFFSET. If
2730 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2731 Does nothing if the offset is zero. */
2734 emit_add_sp_const (HOST_WIDE_INT offset
, bool frame_related_p
)
2736 rtx to_add
= GEN_INT (offset
);
2737 rtx orig_to_add
= to_add
;
2743 if (offset
< -32768 || offset
> 32767)
2745 rtx reg
= gen_rtx_REG (SImode
, REG_A0
);
2746 rtx low
= GEN_INT (trunc_int_for_mode (offset
, HImode
));
2748 insn
= emit_insn (gen_movsi_high (reg
, low
));
2749 if (frame_related_p
)
2750 RTX_FRAME_RELATED_P (insn
) = 1;
2751 insn
= emit_insn (gen_movsi_lo_sum (reg
, reg
, to_add
));
2752 if (frame_related_p
)
2753 RTX_FRAME_RELATED_P (insn
) = 1;
2756 insn
= emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2758 if (frame_related_p
)
2761 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
2762 gen_rtx_SET (stack_pointer_rtx
,
2763 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2766 RTX_FRAME_RELATED_P (insn
) = 1;
2770 /* Prologue and epilogue. */
2772 c6x_expand_prologue (void)
2774 struct c6x_frame frame
;
2778 HOST_WIDE_INT initial_offset
, off
, added_already
;
2780 c6x_compute_frame_layout (&frame
);
2782 if (flag_stack_usage_info
)
2783 current_function_static_stack_size
= frame
.to_allocate
;
2785 initial_offset
= -frame
.to_allocate
;
2788 emit_insn (gen_push_rts ());
2789 nsaved
= frame
.nregs
;
2792 /* If the offsets would be too large for the memory references we will
2793 create to save registers, do the stack allocation in two parts.
2794 Ensure by subtracting 8 that we don't store to the word pointed to
2795 by the stack pointer. */
2796 if (initial_offset
< -32768)
2797 initial_offset
= -frame
.frame_pointer_offset
- 8;
2799 if (frame
.to_allocate
> 0)
2800 gcc_assert (initial_offset
!= 0);
2802 off
= -initial_offset
+ 4 - frame
.padding0
;
2804 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2807 if (frame_pointer_needed
)
2809 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2810 /* We go through some contortions here to both follow the ABI's
2811 recommendation that FP == incoming SP, and to avoid writing or
2812 reading the word pointed to by the stack pointer. */
2813 rtx addr
= gen_rtx_POST_MODIFY (Pmode
, stack_pointer_rtx
,
2814 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2816 insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), fp_reg
);
2817 RTX_FRAME_RELATED_P (insn
) = 1;
2819 insn
= emit_insn (gen_addsi3 (hard_frame_pointer_rtx
, stack_pointer_rtx
,
2821 RTX_FRAME_RELATED_P (insn
) = 1;
2826 emit_add_sp_const (initial_offset
- added_already
, true);
2828 if (nsaved
< frame
.nregs
)
2832 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2834 int idx
= N_SAVE_ORDER
- i
- 1;
2835 unsigned regno
= reg_save_order
[idx
];
2837 machine_mode save_mode
= SImode
;
2839 if (regno
== REG_A15
&& frame_pointer_needed
)
2840 /* Already saved. */
2842 if (!c6x_save_reg (regno
))
2845 if (TARGET_STDW
&& (off
& 4) == 0 && off
<= 256
2847 && i
+ 1 < N_SAVE_ORDER
2848 && reg_save_order
[idx
- 1] == regno
- 1
2849 && c6x_save_reg (regno
- 1))
2855 reg
= gen_rtx_REG (save_mode
, regno
);
2856 off
-= GET_MODE_SIZE (save_mode
);
2858 insn
= emit_move_insn (adjust_address (mem
, save_mode
, off
),
2860 RTX_FRAME_RELATED_P (insn
) = 1;
2862 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2865 gcc_assert (nsaved
== frame
.nregs
);
2866 emit_add_sp_const (-frame
.to_allocate
- initial_offset
, true);
2867 if (must_reload_pic_reg_p ())
2869 if (dsbt_decl
== NULL
)
2873 t
= build_index_type (integer_one_node
);
2874 t
= build_array_type (integer_type_node
, t
);
2875 t
= build_decl (BUILTINS_LOCATION
, VAR_DECL
,
2876 get_identifier ("__c6xabi_DSBT_BASE"), t
);
2877 DECL_ARTIFICIAL (t
) = 1;
2878 DECL_IGNORED_P (t
) = 1;
2879 DECL_EXTERNAL (t
) = 1;
2880 TREE_STATIC (t
) = 1;
2881 TREE_PUBLIC (t
) = 1;
2886 emit_insn (gen_setup_dsbt (pic_offset_table_rtx
,
2887 XEXP (DECL_RTL (dsbt_decl
), 0)));
2892 c6x_expand_epilogue (bool sibcall
)
2895 struct c6x_frame frame
;
2900 c6x_compute_frame_layout (&frame
);
2902 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2904 /* Insert a dummy set/use of the stack pointer. This creates a
2905 scheduler barrier between the prologue saves and epilogue restores. */
2906 emit_insn (gen_epilogue_barrier (stack_pointer_rtx
, stack_pointer_rtx
));
2908 /* If the offsets would be too large for the memory references we will
2909 create to restore registers, do a preliminary stack adjustment here. */
2910 off
= frame
.to_allocate
- frame
.frame_pointer_offset
+ frame
.padding1
;
2913 nsaved
= frame
.nregs
;
2917 if (frame
.to_allocate
> 32768)
2919 /* Don't add the entire offset so that we leave an unused word
2920 above the stack pointer. */
2921 emit_add_sp_const ((off
- 16) & ~7, false);
2925 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2927 unsigned regno
= reg_save_order
[i
];
2929 machine_mode save_mode
= SImode
;
2931 if (!c6x_save_reg (regno
))
2933 if (regno
== REG_A15
&& frame_pointer_needed
)
2936 if (TARGET_STDW
&& (off
& 4) == 0 && off
< 256
2938 && i
+ 1 < N_SAVE_ORDER
2939 && reg_save_order
[i
+ 1] == regno
+ 1
2940 && c6x_save_reg (regno
+ 1))
2945 reg
= gen_rtx_REG (save_mode
, regno
);
2947 emit_move_insn (reg
, adjust_address (mem
, save_mode
, off
));
2949 off
+= GET_MODE_SIZE (save_mode
);
2950 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2953 if (!frame_pointer_needed
)
2954 emit_add_sp_const (off
+ frame
.padding0
- 4, false);
2957 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2958 rtx addr
= gen_rtx_PRE_MODIFY (Pmode
, stack_pointer_rtx
,
2959 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2961 emit_insn (gen_addsi3 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
2963 emit_move_insn (fp_reg
, gen_frame_mem (Pmode
, addr
));
2966 gcc_assert (nsaved
== frame
.nregs
);
2970 emit_jump_insn (gen_pop_rts ());
2972 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode
,
2973 RETURN_ADDR_REGNO
)));
2977 /* Return the value of the return address for the frame COUNT steps up
2978 from the current frame, after the prologue.
2979 We punt for everything but the current frame by returning const0_rtx. */
2982 c6x_return_addr_rtx (int count
)
2987 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNO
);
2990 /* Return true iff TYPE is one of the shadow types. */
2992 shadow_type_p (enum attr_type type
)
2994 return (type
== TYPE_SHADOW
|| type
== TYPE_LOAD_SHADOW
2995 || type
== TYPE_MULT_SHADOW
);
2998 /* Return true iff INSN is a shadow pattern. */
3000 shadow_p (rtx_insn
*insn
)
3002 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3004 return shadow_type_p (get_attr_type (insn
));
3007 /* Return true iff INSN is a shadow or blockage pattern. */
3009 shadow_or_blockage_p (rtx_insn
*insn
)
3011 enum attr_type type
;
3012 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3014 type
= get_attr_type (insn
);
3015 return shadow_type_p (type
) || type
== TYPE_BLOCKAGE
;
3018 /* Translate UNITS into a bitmask of units we can reserve for this
3021 get_reservation_flags (enum attr_units units
)
3027 return RESERVATION_FLAG_D
;
3029 return RESERVATION_FLAG_L
;
3031 return RESERVATION_FLAG_S
;
3033 return RESERVATION_FLAG_M
;
3035 return RESERVATION_FLAG_LS
;
3037 return RESERVATION_FLAG_DL
;
3039 return RESERVATION_FLAG_DS
;
3041 return RESERVATION_FLAG_DLS
;
3047 /* Compute the side of the machine used by INSN, which reserves UNITS.
3048 This must match the reservations in the scheduling description. */
3050 get_insn_side (rtx_insn
*insn
, enum attr_units units
)
3052 if (units
== UNITS_D_ADDR
)
3053 return (get_attr_addr_regfile (insn
) == ADDR_REGFILE_A
? 0 : 1);
3056 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
3057 if (rf
== DEST_REGFILE_ANY
)
3058 return get_attr_type (insn
) == TYPE_BRANCH
? 0 : 1;
3060 return rf
== DEST_REGFILE_A
? 0 : 1;
3064 /* After scheduling, walk the insns between HEAD and END and assign unit
3067 assign_reservations (rtx_insn
*head
, rtx_insn
*end
)
3070 for (insn
= head
; insn
!= NEXT_INSN (end
); insn
= NEXT_INSN (insn
))
3072 unsigned int sched_mask
, reserved
;
3073 rtx_insn
*within
, *last
;
3076 int rsrv_count
[2][4];
3079 if (GET_MODE (insn
) != TImode
)
3084 /* Find the last insn in the packet. It has a state recorded for it,
3085 which we can use to determine the units we should be using. */
3087 (within
!= NEXT_INSN (end
)
3088 && (within
== insn
|| GET_MODE (within
) != TImode
));
3089 within
= NEXT_INSN (within
))
3092 if (!NONDEBUG_INSN_P (within
))
3094 icode
= recog_memoized (within
);
3097 if (shadow_p (within
))
3099 if (INSN_INFO_ENTRY (INSN_UID (within
)).reservation
!= 0)
3100 reserved
|= 1 << INSN_INFO_ENTRY (INSN_UID (within
)).reservation
;
3103 if (last
== NULL_RTX
)
3106 sched_mask
= INSN_INFO_ENTRY (INSN_UID (last
)).unit_mask
;
3107 sched_mask
&= ~reserved
;
3109 memset (rsrv_count
, 0, sizeof rsrv_count
);
3110 rsrv
[0] = rsrv
[1] = ~0;
3111 for (i
= 0; i
< 8; i
++)
3115 unsigned unit_bit
= 1 << (unit
+ side
* UNIT_QID_SIDE_OFFSET
);
3116 /* Clear the bits which we expect to reserve in the following loop,
3117 leaving the ones set which aren't present in the scheduler's
3118 state and shouldn't be reserved. */
3119 if (sched_mask
& unit_bit
)
3120 rsrv
[i
/ 4] &= ~(1 << unit
);
3123 /* Walk through the insns that occur in the same cycle. We use multiple
3124 passes to assign units, assigning for insns with the most specific
3125 requirements first. */
3126 for (pass
= 0; pass
< 4; pass
++)
3128 (within
!= NEXT_INSN (end
)
3129 && (within
== insn
|| GET_MODE (within
) != TImode
));
3130 within
= NEXT_INSN (within
))
3132 int uid
= INSN_UID (within
);
3133 int this_rsrv
, side
;
3135 enum attr_units units
;
3136 enum attr_type type
;
3139 if (!NONDEBUG_INSN_P (within
))
3141 icode
= recog_memoized (within
);
3144 if (INSN_INFO_ENTRY (uid
).reservation
!= 0)
3146 units
= get_attr_units (within
);
3147 type
= get_attr_type (within
);
3148 this_rsrv
= get_reservation_flags (units
);
3151 side
= get_insn_side (within
, units
);
3153 /* Certain floating point instructions are treated specially. If
3154 an insn can choose between units it can reserve, and its
3155 reservation spans more than one cycle, the reservation contains
3156 special markers in the first cycle to help us reconstruct what
3157 the automaton chose. */
3158 if ((type
== TYPE_ADDDP
|| type
== TYPE_FP4
)
3159 && units
== UNITS_LS
)
3161 int test1_code
= ((type
== TYPE_FP4
? UNIT_QID_FPL1
: UNIT_QID_ADDDPL1
)
3162 + side
* UNIT_QID_SIDE_OFFSET
);
3163 int test2_code
= ((type
== TYPE_FP4
? UNIT_QID_FPS1
: UNIT_QID_ADDDPS1
)
3164 + side
* UNIT_QID_SIDE_OFFSET
);
3165 if ((sched_mask
& (1 << test1_code
)) != 0)
3167 this_rsrv
= RESERVATION_FLAG_L
;
3168 sched_mask
&= ~(1 << test1_code
);
3170 else if ((sched_mask
& (1 << test2_code
)) != 0)
3172 this_rsrv
= RESERVATION_FLAG_S
;
3173 sched_mask
&= ~(1 << test2_code
);
3177 if ((this_rsrv
& (this_rsrv
- 1)) == 0)
3179 int t
= exact_log2 (this_rsrv
) + side
* UNIT_QID_SIDE_OFFSET
;
3180 rsrv
[side
] |= this_rsrv
;
3181 INSN_INFO_ENTRY (uid
).reservation
= t
;
3187 for (j
= 0; j
< 4; j
++)
3188 if (this_rsrv
& (1 << j
))
3189 rsrv_count
[side
][j
]++;
3192 if ((pass
== 2 && this_rsrv
!= RESERVATION_FLAG_DLS
)
3193 || (pass
== 3 && this_rsrv
== RESERVATION_FLAG_DLS
))
3195 int best
= -1, best_cost
= INT_MAX
;
3196 for (j
= 0; j
< 4; j
++)
3197 if ((this_rsrv
& (1 << j
))
3198 && !(rsrv
[side
] & (1 << j
))
3199 && rsrv_count
[side
][j
] < best_cost
)
3201 best_cost
= rsrv_count
[side
][j
];
3204 gcc_assert (best
!= -1);
3205 rsrv
[side
] |= 1 << best
;
3206 for (j
= 0; j
< 4; j
++)
3207 if ((this_rsrv
& (1 << j
)) && j
!= best
)
3208 rsrv_count
[side
][j
]--;
3210 INSN_INFO_ENTRY (uid
).reservation
3211 = best
+ side
* UNIT_QID_SIDE_OFFSET
;
3217 /* Return a factor by which to weight unit imbalances for a reservation
3220 unit_req_factor (enum unitreqs r
)
3242 /* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3243 requirements. Returns zero if INSN can't be handled, otherwise
3244 either one or two to show how many of the two pairs are in use.
3245 REQ1 is always used, it holds what is normally thought of as the
3246 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3247 describe a cross path, or for loads/stores, the T unit. */
3249 get_unit_reqs (rtx_insn
*insn
, int *req1
, int *side1
, int *req2
, int *side2
)
3251 enum attr_units units
;
3252 enum attr_cross cross
;
3255 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3257 units
= get_attr_units (insn
);
3258 if (units
== UNITS_UNKNOWN
)
3260 side
= get_insn_side (insn
, units
);
3261 cross
= get_attr_cross (insn
);
3263 req
= (units
== UNITS_D
? UNIT_REQ_D
3264 : units
== UNITS_D_ADDR
? UNIT_REQ_D
3265 : units
== UNITS_DL
? UNIT_REQ_DL
3266 : units
== UNITS_DS
? UNIT_REQ_DS
3267 : units
== UNITS_L
? UNIT_REQ_L
3268 : units
== UNITS_LS
? UNIT_REQ_LS
3269 : units
== UNITS_S
? UNIT_REQ_S
3270 : units
== UNITS_M
? UNIT_REQ_M
3271 : units
== UNITS_DLS
? UNIT_REQ_DLS
3273 gcc_assert (req
!= -1);
3276 if (units
== UNITS_D_ADDR
)
3279 *side2
= side
^ (cross
== CROSS_Y
? 1 : 0);
3282 else if (cross
== CROSS_Y
)
3291 /* Walk the insns between and including HEAD and TAIL, and mark the
3292 resource requirements in the unit_reqs table. */
3294 count_unit_reqs (unit_req_table reqs
, rtx_insn
*head
, rtx_insn
*tail
)
3298 memset (reqs
, 0, sizeof (unit_req_table
));
3300 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3302 int side1
, side2
, req1
, req2
;
3304 switch (get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
))
3307 reqs
[side2
][req2
]++;
3310 reqs
[side1
][req1
]++;
3316 /* Update the table REQS by merging more specific unit reservations into
3317 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3318 UNIT_REQ_DL, DS, and DLS. */
3320 merge_unit_reqs (unit_req_table reqs
)
3323 for (side
= 0; side
< 2; side
++)
3325 int d
= reqs
[side
][UNIT_REQ_D
];
3326 int l
= reqs
[side
][UNIT_REQ_L
];
3327 int s
= reqs
[side
][UNIT_REQ_S
];
3328 int dl
= reqs
[side
][UNIT_REQ_DL
];
3329 int ls
= reqs
[side
][UNIT_REQ_LS
];
3330 int ds
= reqs
[side
][UNIT_REQ_DS
];
3332 reqs
[side
][UNIT_REQ_DL
] += d
;
3333 reqs
[side
][UNIT_REQ_DL
] += l
;
3334 reqs
[side
][UNIT_REQ_DS
] += d
;
3335 reqs
[side
][UNIT_REQ_DS
] += s
;
3336 reqs
[side
][UNIT_REQ_LS
] += l
;
3337 reqs
[side
][UNIT_REQ_LS
] += s
;
3338 reqs
[side
][UNIT_REQ_DLS
] += ds
+ dl
+ ls
+ d
+ l
+ s
;
3342 /* Examine the table REQS and return a measure of unit imbalance by comparing
3343 the two sides of the machine. If, for example, D1 is used twice and D2
3344 used not at all, the return value should be 1 in the absence of other
3347 unit_req_imbalance (unit_req_table reqs
)
3352 for (i
= 0; i
< UNIT_REQ_MAX
; i
++)
3354 int factor
= unit_req_factor ((enum unitreqs
) i
);
3355 int diff
= abs (reqs
[0][i
] - reqs
[1][i
]);
3356 val
+= (diff
+ factor
- 1) / factor
/ 2;
3361 /* Return the resource-constrained minimum iteration interval given the
3362 data in the REQS table. This must have been processed with
3363 merge_unit_reqs already. */
3365 res_mii (unit_req_table reqs
)
3369 for (side
= 0; side
< 2; side
++)
3370 for (req
= 0; req
< UNIT_REQ_MAX
; req
++)
3372 int factor
= unit_req_factor ((enum unitreqs
) req
);
3373 worst
= MAX ((reqs
[side
][UNIT_REQ_D
] + factor
- 1) / factor
, worst
);
3379 /* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3380 the operands that are involved in the (up to) two reservations, as
3381 found by get_unit_reqs. Return true if we did this successfully, false
3382 if we couldn't identify what to do with INSN. */
3384 get_unit_operand_masks (rtx_insn
*insn
, unsigned int *pmask1
,
3385 unsigned int *pmask2
)
3387 enum attr_op_pattern op_pat
;
3389 if (recog_memoized (insn
) < 0)
3391 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
)
3393 extract_insn (insn
);
3394 op_pat
= get_attr_op_pattern (insn
);
3395 if (op_pat
== OP_PATTERN_DT
)
3397 gcc_assert (recog_data
.n_operands
== 2);
3402 else if (op_pat
== OP_PATTERN_TD
)
3404 gcc_assert (recog_data
.n_operands
== 2);
3409 else if (op_pat
== OP_PATTERN_SXS
)
3411 gcc_assert (recog_data
.n_operands
== 3);
3412 *pmask1
= (1 << 0) | (1 << 2);
3416 else if (op_pat
== OP_PATTERN_SX
)
3418 gcc_assert (recog_data
.n_operands
== 2);
3423 else if (op_pat
== OP_PATTERN_SSX
)
3425 gcc_assert (recog_data
.n_operands
== 3);
3426 *pmask1
= (1 << 0) | (1 << 1);
3433 /* Try to replace a register in INSN, which has corresponding rename info
3434 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3435 about the operands that must be renamed and the side they are on.
3436 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3437 We recompute this information locally after our transformation, and keep
3438 it only if we managed to improve the balance. */
3440 try_rename_operands (rtx_insn
*head
, rtx_insn
*tail
, unit_req_table reqs
,
3442 insn_rr_info
*info
, unsigned int op_mask
, int orig_side
)
3444 enum reg_class super_class
= orig_side
== 0 ? B_REGS
: A_REGS
;
3445 HARD_REG_SET unavailable
;
3446 du_head_p this_head
;
3447 struct du_chain
*chain
;
3450 int best_reg
, old_reg
;
3451 vec
<du_head_p
> involved_chains
= vNULL
;
3452 unit_req_table new_reqs
;
3455 for (i
= 0, tmp_mask
= op_mask
; tmp_mask
; i
++)
3458 if ((tmp_mask
& (1 << i
)) == 0)
3460 if (info
->op_info
[i
].n_chains
!= 1)
3462 op_chain
= regrename_chain_from_id (info
->op_info
[i
].heads
[0]->id
);
3463 involved_chains
.safe_push (op_chain
);
3464 tmp_mask
&= ~(1 << i
);
3467 if (involved_chains
.length () > 1)
3470 this_head
= involved_chains
[0];
3471 if (this_head
->cannot_rename
)
3474 for (chain
= this_head
->first
; chain
; chain
= chain
->next_use
)
3476 unsigned int mask1
, mask2
, mask_changed
;
3477 int count
, side1
, side2
, req1
, req2
;
3478 insn_rr_info
*this_rr
= &insn_rr
[INSN_UID (chain
->insn
)];
3480 count
= get_unit_reqs (chain
->insn
, &req1
, &side1
, &req2
, &side2
);
3485 if (!get_unit_operand_masks (chain
->insn
, &mask1
, &mask2
))
3488 extract_insn (chain
->insn
);
3491 for (i
= 0; i
< recog_data
.n_operands
; i
++)
3494 int n_this_op
= this_rr
->op_info
[i
].n_chains
;
3495 for (j
= 0; j
< n_this_op
; j
++)
3497 du_head_p other
= this_rr
->op_info
[i
].heads
[j
];
3498 if (regrename_chain_from_id (other
->id
) == this_head
)
3506 mask_changed
|= 1 << i
;
3508 gcc_assert (mask_changed
!= 0);
3509 if (mask_changed
!= mask1
&& mask_changed
!= mask2
)
3513 /* If we get here, we can do the renaming. */
3514 COMPL_HARD_REG_SET (unavailable
, reg_class_contents
[(int) super_class
]);
3516 old_reg
= this_head
->regno
;
3518 find_rename_reg (this_head
, super_class
, &unavailable
, old_reg
, true);
3520 ok
= regrename_do_replace (this_head
, best_reg
);
3523 count_unit_reqs (new_reqs
, head
, PREV_INSN (tail
));
3524 merge_unit_reqs (new_reqs
);
3527 fprintf (dump_file
, "reshuffle for insn %d, op_mask %x, "
3528 "original side %d, new reg %d\n",
3529 INSN_UID (insn
), op_mask
, orig_side
, best_reg
);
3530 fprintf (dump_file
, " imbalance %d -> %d\n",
3531 unit_req_imbalance (reqs
), unit_req_imbalance (new_reqs
));
3533 if (unit_req_imbalance (new_reqs
) > unit_req_imbalance (reqs
))
3535 ok
= regrename_do_replace (this_head
, old_reg
);
3539 memcpy (reqs
, new_reqs
, sizeof (unit_req_table
));
3542 involved_chains
.release ();
3545 /* Find insns in LOOP which would, if shifted to the other side
3546 of the machine, reduce an imbalance in the unit reservations. */
3548 reshuffle_units (basic_block loop
)
3550 rtx_insn
*head
= BB_HEAD (loop
);
3551 rtx_insn
*tail
= BB_END (loop
);
3553 unit_req_table reqs
;
3558 count_unit_reqs (reqs
, head
, PREV_INSN (tail
));
3559 merge_unit_reqs (reqs
);
3561 regrename_init (true);
3563 bitmap_initialize (&bbs
, &bitmap_default_obstack
);
3565 FOR_EACH_EDGE (e
, ei
, loop
->preds
)
3566 bitmap_set_bit (&bbs
, e
->src
->index
);
3568 bitmap_set_bit (&bbs
, loop
->index
);
3569 regrename_analyze (&bbs
);
3571 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3573 enum attr_units units
;
3574 int count
, side1
, side2
, req1
, req2
;
3575 unsigned int mask1
, mask2
;
3578 if (!NONDEBUG_INSN_P (insn
))
3581 count
= get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
);
3586 if (!get_unit_operand_masks (insn
, &mask1
, &mask2
))
3589 info
= &insn_rr
[INSN_UID (insn
)];
3590 if (info
->op_info
== NULL
)
3593 if (reqs
[side1
][req1
] > 1
3594 && reqs
[side1
][req1
] > 2 * reqs
[side1
^ 1][req1
])
3596 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask1
, side1
);
3599 units
= get_attr_units (insn
);
3600 if (units
== UNITS_D_ADDR
)
3602 gcc_assert (count
== 2);
3603 if (reqs
[side2
][req2
] > 1
3604 && reqs
[side2
][req2
] > 2 * reqs
[side2
^ 1][req2
])
3606 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask2
, side2
);
3610 regrename_finish ();
3613 /* Backend scheduling state. */
3614 typedef struct c6x_sched_context
3616 /* The current scheduler clock, saved in the sched_reorder hook. */
3617 int curr_sched_clock
;
3619 /* Number of insns issued so far in this cycle. */
3620 int issued_this_cycle
;
3622 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3623 theoretical maximum for number of jumps in flight is 12: 2 every
3624 cycle, with a latency of 6 cycles each. This is a circular
3625 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3626 jumps have a higher index. This array should be accessed through
3627 the jump_cycle function. */
3628 int jump_cycles
[12];
3629 int jump_cycle_index
;
3631 /* In parallel with jump_cycles, this array records the opposite of
3632 the condition used in each pending jump. This is used to
3633 predicate insns that are scheduled in the jump's delay slots. If
3634 this is NULL_RTX no such predication happens. */
3637 /* Similar to the jump_cycles mechanism, but here we take into
3638 account all insns with delay slots, to avoid scheduling asms into
3640 int delays_finished_at
;
3642 /* The following variable value is the last issued insn. */
3643 rtx_insn
*last_scheduled_insn
;
3644 /* The last issued insn that isn't a shadow of another. */
3645 rtx_insn
*last_scheduled_iter0
;
3647 /* The following variable value is DFA state before issuing the
3648 first insn in the current clock cycle. We do not use this member
3649 of the structure directly; we copy the data in and out of
3650 prev_cycle_state. */
3651 state_t prev_cycle_state_ctx
;
3653 int reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3654 int reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3655 int reg_set_in_cycle
[FIRST_PSEUDO_REGISTER
];
3657 int tmp_reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3658 int tmp_reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3659 } *c6x_sched_context_t
;
3661 /* The current scheduling state. */
3662 static struct c6x_sched_context ss
;
3664 /* The following variable value is DFA state before issuing the first insn
3665 in the current clock cycle. This is used in c6x_variable_issue for
3666 comparison with the state after issuing the last insn in a cycle. */
3667 static state_t prev_cycle_state
;
3669 /* Set when we discover while processing an insn that it would lead to too
3670 many accesses of the same register. */
3671 static bool reg_access_stall
;
3673 /* The highest insn uid after delayed insns were split, but before loop bodies
3674 were copied by the modulo scheduling code. */
3675 static int sploop_max_uid_iter0
;
3677 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3678 so the caller does not specifically have to test for it. */
3680 get_jump_cycle (int n
)
3684 n
+= ss
.jump_cycle_index
;
3687 return ss
.jump_cycles
[n
];
3690 /* Look up the jump condition with index N. */
3692 get_jump_cond (int n
)
3696 n
+= ss
.jump_cycle_index
;
3699 return ss
.jump_cond
[n
];
3702 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3703 has delay slots beyond CLOCK_VAR, return -1. */
3705 first_jump_index (int clock_var
)
3711 int t
= get_jump_cycle (n
);
3720 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3721 and has the opposite condition of COND. */
3723 record_jump (int cycle
, rtx cond
)
3725 if (ss
.jump_cycle_index
== 0)
3726 ss
.jump_cycle_index
= 11;
3728 ss
.jump_cycle_index
--;
3729 ss
.jump_cycles
[ss
.jump_cycle_index
] = cycle
;
3730 ss
.jump_cond
[ss
.jump_cycle_index
] = cond
;
3733 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3736 insn_set_clock (rtx insn
, int cycle
)
3738 unsigned uid
= INSN_UID (insn
);
3740 if (uid
>= INSN_INFO_LENGTH
)
3741 insn_info
.safe_grow (uid
* 5 / 4 + 10);
3743 INSN_INFO_ENTRY (uid
).clock
= cycle
;
3744 INSN_INFO_ENTRY (uid
).new_cond
= NULL
;
3745 INSN_INFO_ENTRY (uid
).reservation
= 0;
3746 INSN_INFO_ENTRY (uid
).ebb_start
= false;
3749 /* Return the clock cycle we set for the insn with uid UID. */
3751 insn_uid_get_clock (int uid
)
3753 return INSN_INFO_ENTRY (uid
).clock
;
3756 /* Return the clock cycle we set for INSN. */
3758 insn_get_clock (rtx insn
)
3760 return insn_uid_get_clock (INSN_UID (insn
));
3763 /* Examine INSN, and if it is a conditional jump of any kind, return
3764 the opposite of the condition in which it branches. Otherwise,
3767 condjump_opposite_condition (rtx insn
)
3769 rtx pat
= PATTERN (insn
);
3770 int icode
= INSN_CODE (insn
);
3773 if (icode
== CODE_FOR_br_true
|| icode
== CODE_FOR_br_false
)
3775 x
= XEXP (SET_SRC (pat
), 0);
3776 if (icode
== CODE_FOR_br_false
)
3779 if (GET_CODE (pat
) == COND_EXEC
)
3781 rtx t
= COND_EXEC_CODE (pat
);
3782 if ((GET_CODE (t
) == PARALLEL
3783 && GET_CODE (XVECEXP (t
, 0, 0)) == RETURN
)
3784 || (GET_CODE (t
) == UNSPEC
&& XINT (t
, 1) == UNSPEC_REAL_JUMP
)
3785 || (GET_CODE (t
) == SET
&& SET_DEST (t
) == pc_rtx
))
3786 x
= COND_EXEC_TEST (pat
);
3791 enum rtx_code code
= GET_CODE (x
);
3792 x
= gen_rtx_fmt_ee (code
== EQ
? NE
: EQ
,
3793 GET_MODE (x
), XEXP (x
, 0),
3799 /* Return true iff COND1 and COND2 are exactly opposite conditions
3800 one of them NE and the other EQ. */
3802 conditions_opposite_p (rtx cond1
, rtx cond2
)
3804 return (rtx_equal_p (XEXP (cond1
, 0), XEXP (cond2
, 0))
3805 && rtx_equal_p (XEXP (cond1
, 1), XEXP (cond2
, 1))
3806 && GET_CODE (cond1
) == reverse_condition (GET_CODE (cond2
)));
3809 /* Return true if we can add a predicate COND to INSN, or if INSN
3810 already has that predicate. If DOIT is true, also perform the
3813 predicate_insn (rtx_insn
*insn
, rtx cond
, bool doit
)
3816 if (cond
== NULL_RTX
)
3822 if (get_attr_predicable (insn
) == PREDICABLE_YES
3823 && GET_CODE (PATTERN (insn
)) != COND_EXEC
)
3827 rtx newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3828 PATTERN (insn
) = newpat
;
3829 INSN_CODE (insn
) = -1;
3833 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
3834 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn
)), cond
))
3836 icode
= INSN_CODE (insn
);
3837 if (icode
== CODE_FOR_real_jump
3838 || icode
== CODE_FOR_jump
3839 || icode
== CODE_FOR_indirect_jump
)
3841 rtx pat
= PATTERN (insn
);
3842 rtx dest
= (icode
== CODE_FOR_real_jump
? XVECEXP (pat
, 0, 0)
3843 : icode
== CODE_FOR_jump
? XEXP (SET_SRC (pat
), 0)
3849 newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3851 newpat
= gen_br_true (cond
, XEXP (cond
, 0), dest
);
3852 PATTERN (insn
) = newpat
;
3853 INSN_CODE (insn
) = -1;
3857 if (INSN_CODE (insn
) == CODE_FOR_br_true
)
3859 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3860 return rtx_equal_p (br_cond
, cond
);
3862 if (INSN_CODE (insn
) == CODE_FOR_br_false
)
3864 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3865 return conditions_opposite_p (br_cond
, cond
);
3870 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3872 init_sched_state (c6x_sched_context_t sc
)
3874 sc
->last_scheduled_insn
= NULL
;
3875 sc
->last_scheduled_iter0
= NULL
;
3876 sc
->issued_this_cycle
= 0;
3877 memset (sc
->jump_cycles
, 0, sizeof sc
->jump_cycles
);
3878 memset (sc
->jump_cond
, 0, sizeof sc
->jump_cond
);
3879 sc
->jump_cycle_index
= 0;
3880 sc
->delays_finished_at
= 0;
3881 sc
->curr_sched_clock
= 0;
3883 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3885 memset (sc
->reg_n_accesses
, 0, sizeof sc
->reg_n_accesses
);
3886 memset (sc
->reg_n_xaccesses
, 0, sizeof sc
->reg_n_xaccesses
);
3887 memset (sc
->reg_set_in_cycle
, 0, sizeof sc
->reg_set_in_cycle
);
3889 state_reset (sc
->prev_cycle_state_ctx
);
3892 /* Allocate store for new scheduling context. */
3894 c6x_alloc_sched_context (void)
3896 return xmalloc (sizeof (struct c6x_sched_context
));
3899 /* If CLEAN_P is true then initializes _SC with clean data,
3900 and from the global context otherwise. */
3902 c6x_init_sched_context (void *_sc
, bool clean_p
)
3904 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3908 init_sched_state (sc
);
3913 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3914 memcpy (sc
->prev_cycle_state_ctx
, prev_cycle_state
, dfa_state_size
);
3918 /* Sets the global scheduling context to the one pointed to by _SC. */
3920 c6x_set_sched_context (void *_sc
)
3922 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3924 gcc_assert (sc
!= NULL
);
3926 memcpy (prev_cycle_state
, sc
->prev_cycle_state_ctx
, dfa_state_size
);
3929 /* Clear data in _SC. */
3931 c6x_clear_sched_context (void *_sc
)
3933 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3934 gcc_assert (_sc
!= NULL
);
3936 free (sc
->prev_cycle_state_ctx
);
3941 c6x_free_sched_context (void *_sc
)
3946 /* True if we are currently performing a preliminary scheduling
3947 pass before modulo scheduling; we can't allow the scheduler to
3948 modify instruction patterns using packetization assumptions,
3949 since there will be another scheduling pass later if modulo
3950 scheduling fails. */
3951 static bool in_hwloop
;
3953 /* Provide information about speculation capabilities, and set the
3954 DO_BACKTRACKING flag. */
3956 c6x_set_sched_flags (spec_info_t spec_info
)
3958 unsigned int *flags
= &(current_sched_info
->flags
);
3960 if (*flags
& SCHED_EBB
)
3962 *flags
|= DO_BACKTRACKING
| DO_PREDICATION
;
3965 *flags
|= DONT_BREAK_DEPENDENCIES
;
3967 spec_info
->mask
= 0;
3970 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3973 c6x_issue_rate (void)
3978 /* Used together with the collapse_ndfa option, this ensures that we reach a
3979 deterministic automaton state before trying to advance a cycle.
3980 With collapse_ndfa, genautomata creates advance cycle arcs only for
3981 such deterministic states. */
3984 c6x_sched_dfa_pre_cycle_insn (void)
3989 /* We're beginning a new block. Initialize data structures as necessary. */
3992 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED
,
3993 int sched_verbose ATTRIBUTE_UNUSED
,
3994 int max_ready ATTRIBUTE_UNUSED
)
3996 if (prev_cycle_state
== NULL
)
3998 prev_cycle_state
= xmalloc (dfa_state_size
);
4000 init_sched_state (&ss
);
4001 state_reset (prev_cycle_state
);
4004 /* We are about to being issuing INSN. Return nonzero if we cannot
4005 issue it on given cycle CLOCK and return zero if we should not sort
4006 the ready queue on the next clock start.
4007 For C6X, we use this function just to copy the previous DFA state
4008 for comparison purposes. */
4011 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED
, int verbose ATTRIBUTE_UNUSED
,
4012 rtx_insn
*insn ATTRIBUTE_UNUSED
,
4013 int last_clock ATTRIBUTE_UNUSED
,
4014 int clock ATTRIBUTE_UNUSED
, int *sort_p ATTRIBUTE_UNUSED
)
4016 if (clock
!= last_clock
)
4017 memcpy (prev_cycle_state
, curr_state
, dfa_state_size
);
4022 c6x_mark_regno_read (int regno
, bool cross
)
4024 int t
= ++ss
.tmp_reg_n_accesses
[regno
];
4027 reg_access_stall
= true;
4031 int set_cycle
= ss
.reg_set_in_cycle
[regno
];
4032 /* This must be done in this way rather than by tweaking things in
4033 adjust_cost, since the stall occurs even for insns with opposite
4034 predicates, and the scheduler may not even see a dependency. */
4035 if (set_cycle
> 0 && set_cycle
== ss
.curr_sched_clock
)
4036 reg_access_stall
= true;
4037 /* This doesn't quite do anything yet as we're only modeling one
4039 ++ss
.tmp_reg_n_xaccesses
[regno
];
4043 /* Note that REG is read in the insn being examined. If CROSS, it
4044 means the access is through a cross path. Update the temporary reg
4045 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4046 in the current cycle. */
4049 c6x_mark_reg_read (rtx reg
, bool cross
)
4051 unsigned regno
= REGNO (reg
);
4052 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4055 c6x_mark_regno_read (regno
+ nregs
, cross
);
4058 /* Note that register REG is written in cycle CYCLES. */
4061 c6x_mark_reg_written (rtx reg
, int cycles
)
4063 unsigned regno
= REGNO (reg
);
4064 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4067 ss
.reg_set_in_cycle
[regno
+ nregs
] = cycles
;
4070 /* Update the register state information for an instruction whose
4071 body is X. Return true if the instruction has to be delayed until the
4075 c6x_registers_update (rtx_insn
*insn
)
4077 enum attr_cross cross
;
4078 enum attr_dest_regfile destrf
;
4082 if (!reload_completed
|| recog_memoized (insn
) < 0)
4085 reg_access_stall
= false;
4086 memcpy (ss
.tmp_reg_n_accesses
, ss
.reg_n_accesses
,
4087 sizeof ss
.tmp_reg_n_accesses
);
4088 memcpy (ss
.tmp_reg_n_xaccesses
, ss
.reg_n_xaccesses
,
4089 sizeof ss
.tmp_reg_n_xaccesses
);
4091 extract_insn (insn
);
4093 cross
= get_attr_cross (insn
);
4094 destrf
= get_attr_dest_regfile (insn
);
4096 nops
= recog_data
.n_operands
;
4098 if (GET_CODE (x
) == COND_EXEC
)
4100 c6x_mark_reg_read (XEXP (XEXP (x
, 0), 0), false);
4104 for (i
= 0; i
< nops
; i
++)
4106 rtx op
= recog_data
.operand
[i
];
4107 if (recog_data
.operand_type
[i
] == OP_OUT
)
4111 bool this_cross
= cross
;
4112 if (destrf
== DEST_REGFILE_A
&& A_REGNO_P (REGNO (op
)))
4114 if (destrf
== DEST_REGFILE_B
&& B_REGNO_P (REGNO (op
)))
4116 c6x_mark_reg_read (op
, this_cross
);
4118 else if (MEM_P (op
))
4121 switch (GET_CODE (op
))
4130 c6x_mark_reg_read (op
, false);
4135 gcc_assert (GET_CODE (op
) == PLUS
);
4138 c6x_mark_reg_read (XEXP (op
, 0), false);
4139 if (REG_P (XEXP (op
, 1)))
4140 c6x_mark_reg_read (XEXP (op
, 1), false);
4145 c6x_mark_regno_read (REG_B14
, false);
4151 else if (!CONSTANT_P (op
) && strlen (recog_data
.constraints
[i
]) > 0)
4154 return reg_access_stall
;
4157 /* Helper function for the TARGET_SCHED_REORDER and
4158 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4159 in the current cycle, move it down in the ready list and return the
4160 number of non-unsafe insns. */
4163 c6x_sched_reorder_1 (rtx_insn
**ready
, int *pn_ready
, int clock_var
)
4165 int n_ready
= *pn_ready
;
4166 rtx_insn
**e_ready
= ready
+ n_ready
;
4170 /* Keep track of conflicts due to a limit number of register accesses,
4171 and due to stalls incurred by too early accesses of registers using
4174 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4176 rtx_insn
*insn
= *insnp
;
4177 int icode
= recog_memoized (insn
);
4178 bool is_asm
= (icode
< 0
4179 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4180 || asm_noperands (PATTERN (insn
)) >= 0));
4181 bool no_parallel
= (is_asm
|| icode
== CODE_FOR_sploop
4183 && get_attr_type (insn
) == TYPE_ATOMIC
));
4185 /* We delay asm insns until all delay slots are exhausted. We can't
4186 accurately tell how many cycles an asm takes, and the main scheduling
4187 code always assumes at least 1 cycle, which may be wrong. */
4189 && (ss
.issued_this_cycle
> 0 || clock_var
< ss
.delays_finished_at
))
4190 || c6x_registers_update (insn
)
4191 || (ss
.issued_this_cycle
> 0 && icode
== CODE_FOR_sploop
))
4193 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4198 else if (shadow_p (insn
))
4200 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4205 /* Ensure that no other jump is scheduled in jump delay slots, since
4206 it would put the machine into the wrong state. Also, we must
4207 avoid scheduling insns that have a latency longer than the
4208 remaining jump delay slots, as the code at the jump destination
4209 won't be prepared for it.
4211 However, we can relax this condition somewhat. The rest of the
4212 scheduler will automatically avoid scheduling an insn on which
4213 the jump shadow depends so late that its side effect happens
4214 after the jump. This means that if we see an insn with a longer
4215 latency here, it can safely be scheduled if we can ensure that it
4216 has a predicate opposite of the previous jump: the side effect
4217 will happen in what we think of as the same basic block. In
4218 c6x_variable_issue, we will record the necessary predicate in
4219 new_conditions, and after scheduling is finished, we will modify
4222 Special care must be taken whenever there is more than one jump
4225 first_jump
= first_jump_index (clock_var
);
4226 if (first_jump
!= -1)
4228 int first_cycle
= get_jump_cycle (first_jump
);
4229 rtx first_cond
= get_jump_cond (first_jump
);
4230 int second_cycle
= 0;
4233 second_cycle
= get_jump_cycle (first_jump
- 1);
4235 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4237 rtx_insn
*insn
= *insnp
;
4238 int icode
= recog_memoized (insn
);
4239 bool is_asm
= (icode
< 0
4240 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4241 || asm_noperands (PATTERN (insn
)) >= 0));
4242 int this_cycles
, rsrv_cycles
;
4243 enum attr_type type
;
4245 gcc_assert (!is_asm
);
4248 this_cycles
= get_attr_cycles (insn
);
4249 rsrv_cycles
= get_attr_reserve_cycles (insn
);
4250 type
= get_attr_type (insn
);
4251 /* Treat branches specially; there is also a hazard if two jumps
4252 end at the same cycle. */
4253 if (type
== TYPE_BRANCH
|| type
== TYPE_CALL
)
4255 if (clock_var
+ this_cycles
<= first_cycle
)
4257 if ((first_jump
> 0 && clock_var
+ this_cycles
> second_cycle
)
4258 || clock_var
+ rsrv_cycles
> first_cycle
4259 || !predicate_insn (insn
, first_cond
, false))
4261 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4272 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4273 for later and clear the register access information for the new
4274 cycle. We also move asm statements out of the way if they would be
4275 scheduled in a delay slot. */
4278 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED
,
4279 int sched_verbose ATTRIBUTE_UNUSED
,
4280 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4281 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4283 ss
.curr_sched_clock
= clock_var
;
4284 ss
.issued_this_cycle
= 0;
4285 memset (ss
.reg_n_accesses
, 0, sizeof ss
.reg_n_accesses
);
4286 memset (ss
.reg_n_xaccesses
, 0, sizeof ss
.reg_n_xaccesses
);
4291 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4294 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4295 cycle for every insn. */
4298 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED
,
4299 int sched_verbose ATTRIBUTE_UNUSED
,
4300 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4301 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4303 /* FIXME: the assembler rejects labels inside an execute packet.
4304 This can occur if prologue insns are scheduled in parallel with
4305 others, so we avoid this here. Also make sure that nothing is
4306 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4307 if (RTX_FRAME_RELATED_P (ss
.last_scheduled_insn
)
4308 || JUMP_P (ss
.last_scheduled_insn
)
4309 || (recog_memoized (ss
.last_scheduled_insn
) >= 0
4310 && get_attr_type (ss
.last_scheduled_insn
) == TYPE_ATOMIC
))
4312 int n_ready
= *pn_ready
;
4313 rtx_insn
**e_ready
= ready
+ n_ready
;
4316 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4318 rtx_insn
*insn
= *insnp
;
4319 if (!shadow_p (insn
))
4321 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4330 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4333 /* Subroutine of maybe_clobber_cond, called through note_stores. */
4336 clobber_cond_1 (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
, void *data1
)
4338 rtx
*cond
= (rtx
*)data1
;
4339 if (*cond
!= NULL_RTX
&& reg_overlap_mentioned_p (x
, *cond
))
4343 /* Examine INSN, and if it destroys the conditions have recorded for
4344 any of the jumps in flight, clear that condition so that we don't
4345 predicate any more insns. CLOCK_VAR helps us limit the search to
4346 only those jumps which are still in flight. */
4349 maybe_clobber_cond (rtx insn
, int clock_var
)
4352 idx
= ss
.jump_cycle_index
;
4353 for (n
= 0; n
< 12; n
++, idx
++)
4360 cycle
= ss
.jump_cycles
[idx
];
4361 if (cycle
<= clock_var
)
4364 cond
= ss
.jump_cond
[idx
];
4365 if (cond
== NULL_RTX
)
4370 ss
.jump_cond
[idx
] = NULL_RTX
;
4374 note_stores (PATTERN (insn
), clobber_cond_1
, ss
.jump_cond
+ idx
);
4375 for (link
= REG_NOTES (insn
); link
; link
= XEXP (link
, 1))
4376 if (REG_NOTE_KIND (link
) == REG_INC
)
4377 clobber_cond_1 (XEXP (link
, 0), NULL_RTX
, ss
.jump_cond
+ idx
);
4381 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4382 issue INSN. Return the number of insns left on the ready queue
4383 that can be issued this cycle.
4384 We use this hook to record clock cycles and reservations for every insn. */
4387 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED
,
4388 int sched_verbose ATTRIBUTE_UNUSED
,
4389 rtx_insn
*insn
, int can_issue_more ATTRIBUTE_UNUSED
)
4391 ss
.last_scheduled_insn
= insn
;
4392 if (INSN_UID (insn
) < sploop_max_uid_iter0
&& !JUMP_P (insn
))
4393 ss
.last_scheduled_iter0
= insn
;
4394 if (GET_CODE (PATTERN (insn
)) != USE
&& GET_CODE (PATTERN (insn
)) != CLOBBER
)
4395 ss
.issued_this_cycle
++;
4396 if (insn_info
.exists ())
4398 state_t st_after
= alloca (dfa_state_size
);
4399 int curr_clock
= ss
.curr_sched_clock
;
4400 int uid
= INSN_UID (insn
);
4401 int icode
= recog_memoized (insn
);
4403 int first
, first_cycle
;
4407 insn_set_clock (insn
, curr_clock
);
4408 INSN_INFO_ENTRY (uid
).ebb_start
4409 = curr_clock
== 0 && ss
.issued_this_cycle
== 1;
4411 first
= first_jump_index (ss
.curr_sched_clock
);
4415 first_cond
= NULL_RTX
;
4419 first_cycle
= get_jump_cycle (first
);
4420 first_cond
= get_jump_cond (first
);
4423 && first_cycle
> curr_clock
4424 && first_cond
!= NULL_RTX
4425 && (curr_clock
+ get_attr_cycles (insn
) > first_cycle
4426 || get_attr_type (insn
) == TYPE_BRANCH
4427 || get_attr_type (insn
) == TYPE_CALL
))
4428 INSN_INFO_ENTRY (uid
).new_cond
= first_cond
;
4430 memcpy (st_after
, curr_state
, dfa_state_size
);
4431 state_transition (st_after
, const0_rtx
);
4434 for (i
= 0; i
< 2 * UNIT_QID_SIDE_OFFSET
; i
++)
4435 if (cpu_unit_reservation_p (st_after
, c6x_unit_codes
[i
])
4436 && !cpu_unit_reservation_p (prev_cycle_state
, c6x_unit_codes
[i
]))
4438 INSN_INFO_ENTRY (uid
).unit_mask
= mask
;
4440 maybe_clobber_cond (insn
, curr_clock
);
4446 c6x_registers_update (insn
);
4447 memcpy (ss
.reg_n_accesses
, ss
.tmp_reg_n_accesses
,
4448 sizeof ss
.reg_n_accesses
);
4449 memcpy (ss
.reg_n_xaccesses
, ss
.tmp_reg_n_accesses
,
4450 sizeof ss
.reg_n_xaccesses
);
4452 cycles
= get_attr_cycles (insn
);
4453 if (ss
.delays_finished_at
< ss
.curr_sched_clock
+ cycles
)
4454 ss
.delays_finished_at
= ss
.curr_sched_clock
+ cycles
;
4455 if (get_attr_type (insn
) == TYPE_BRANCH
4456 || get_attr_type (insn
) == TYPE_CALL
)
4458 rtx opposite
= condjump_opposite_condition (insn
);
4459 record_jump (ss
.curr_sched_clock
+ cycles
, opposite
);
4462 /* Mark the cycles in which the destination registers are written.
4463 This is used for calculating stalls when using cross units. */
4464 extract_insn (insn
);
4465 /* Cross-path stalls don't apply to results of load insns. */
4466 if (get_attr_type (insn
) == TYPE_LOAD
4467 || get_attr_type (insn
) == TYPE_LOADN
4468 || get_attr_type (insn
) == TYPE_LOAD_SHADOW
)
4470 for (i
= 0; i
< recog_data
.n_operands
; i
++)
4472 rtx op
= recog_data
.operand
[i
];
4475 rtx addr
= XEXP (op
, 0);
4476 if (GET_RTX_CLASS (GET_CODE (addr
)) == RTX_AUTOINC
)
4477 c6x_mark_reg_written (XEXP (addr
, 0),
4478 insn_uid_get_clock (uid
) + 1);
4480 if (recog_data
.operand_type
[i
] != OP_IN
4483 c6x_mark_reg_written (op
,
4484 insn_uid_get_clock (uid
) + cycles
);
4489 return can_issue_more
;
4492 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4493 anti- and output dependencies. */
4496 c6x_adjust_cost (rtx_insn
*insn
, rtx link
, rtx_insn
*dep_insn
, int cost
)
4498 enum attr_type insn_type
= TYPE_UNKNOWN
, dep_insn_type
= TYPE_UNKNOWN
;
4499 int dep_insn_code_number
, insn_code_number
;
4500 int shadow_bonus
= 0;
4502 dep_insn_code_number
= recog_memoized (dep_insn
);
4503 insn_code_number
= recog_memoized (insn
);
4505 if (dep_insn_code_number
>= 0)
4506 dep_insn_type
= get_attr_type (dep_insn
);
4508 if (insn_code_number
>= 0)
4509 insn_type
= get_attr_type (insn
);
4511 kind
= REG_NOTE_KIND (link
);
4514 /* If we have a dependency on a load, and it's not for the result of
4515 the load, it must be for an autoincrement. Reduce the cost in that
4517 if (dep_insn_type
== TYPE_LOAD
)
4519 rtx set
= PATTERN (dep_insn
);
4520 if (GET_CODE (set
) == COND_EXEC
)
4521 set
= COND_EXEC_CODE (set
);
4522 if (GET_CODE (set
) == UNSPEC
)
4526 gcc_assert (GET_CODE (set
) == SET
);
4527 if (!reg_overlap_mentioned_p (SET_DEST (set
), PATTERN (insn
)))
4533 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4534 it occurs in between two cycles, but we schedule it at the end of the
4536 if (shadow_type_p (insn_type
))
4539 /* Anti and output dependencies usually have zero cost, but we want
4540 to insert a stall after a jump, and after certain floating point
4541 insns that take more than one cycle to read their inputs. In the
4542 future, we should try to find a better algorithm for scheduling
4546 /* We can get anti-dependencies against shadow insns. Treat these
4547 like output dependencies, so that the insn is entirely finished
4548 before the branch takes place. */
4549 if (kind
== REG_DEP_ANTI
&& insn_type
== TYPE_SHADOW
)
4550 kind
= REG_DEP_OUTPUT
;
4551 switch (dep_insn_type
)
4557 if (get_attr_has_shadow (dep_insn
) == HAS_SHADOW_Y
)
4558 /* This is a real_jump/real_call insn. These don't have
4559 outputs, and ensuring the validity of scheduling things
4560 in the delay slot is the job of
4561 c6x_sched_reorder_1. */
4563 /* Unsplit calls can happen - e.g. for divide insns. */
4568 if (kind
== REG_DEP_OUTPUT
)
4569 return 5 - shadow_bonus
;
4573 if (kind
== REG_DEP_OUTPUT
)
4574 return 4 - shadow_bonus
;
4577 if (kind
== REG_DEP_OUTPUT
)
4578 return 2 - shadow_bonus
;
4581 if (kind
== REG_DEP_OUTPUT
)
4582 return 2 - shadow_bonus
;
4586 if (kind
== REG_DEP_OUTPUT
)
4587 return 7 - shadow_bonus
;
4590 if (kind
== REG_DEP_OUTPUT
)
4591 return 5 - shadow_bonus
;
4594 if (kind
== REG_DEP_OUTPUT
)
4595 return 9 - shadow_bonus
;
4599 if (kind
== REG_DEP_OUTPUT
)
4600 return 10 - shadow_bonus
;
4604 if (insn_type
== TYPE_SPKERNEL
)
4606 if (kind
== REG_DEP_OUTPUT
)
4607 return 1 - shadow_bonus
;
4613 return cost
- shadow_bonus
;
4616 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4617 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4618 first in the original stream. */
4621 gen_one_bundle (rtx_insn
**slot
, int n_filled
, int real_first
)
4628 seq
= gen_rtx_SEQUENCE (VOIDmode
, gen_rtvec_v (n_filled
, slot
));
4629 bundle
= make_insn_raw (seq
);
4630 BLOCK_FOR_INSN (bundle
) = BLOCK_FOR_INSN (slot
[0]);
4631 INSN_LOCATION (bundle
) = INSN_LOCATION (slot
[0]);
4632 SET_PREV_INSN (bundle
) = SET_PREV_INSN (slot
[real_first
]);
4636 for (i
= 0; i
< n_filled
; i
++)
4638 rtx_insn
*insn
= slot
[i
];
4640 SET_PREV_INSN (insn
) = t
? t
: PREV_INSN (bundle
);
4642 SET_NEXT_INSN (t
) = insn
;
4645 INSN_LOCATION (slot
[i
]) = INSN_LOCATION (bundle
);
4648 SET_NEXT_INSN (bundle
) = NEXT_INSN (PREV_INSN (bundle
));
4649 SET_NEXT_INSN (t
) = NEXT_INSN (bundle
);
4650 SET_NEXT_INSN (PREV_INSN (bundle
)) = bundle
;
4651 SET_PREV_INSN (NEXT_INSN (bundle
)) = bundle
;
4654 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4655 try to insert labels in the middle. */
4658 c6x_gen_bundles (void)
4661 rtx_insn
*insn
, *next
, *last_call
;
4663 FOR_EACH_BB_FN (bb
, cfun
)
4665 rtx_insn
*insn
, *next
;
4666 /* The machine is eight insns wide. We can have up to six shadow
4667 insns, plus an extra slot for merging the jump shadow. */
4672 for (insn
= BB_HEAD (bb
);; insn
= next
)
4675 rtx delete_this
= NULL_RTX
;
4677 if (NONDEBUG_INSN_P (insn
))
4679 /* Put calls at the start of the sequence. */
4685 memmove (&slot
[1], &slot
[0],
4686 n_filled
* sizeof (slot
[0]));
4688 if (!shadow_p (insn
))
4690 PUT_MODE (insn
, TImode
);
4692 PUT_MODE (slot
[1], VOIDmode
);
4699 slot
[n_filled
++] = insn
;
4703 next
= NEXT_INSN (insn
);
4704 while (next
&& insn
!= BB_END (bb
)
4705 && !(NONDEBUG_INSN_P (next
)
4706 && GET_CODE (PATTERN (next
)) != USE
4707 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4710 next
= NEXT_INSN (insn
);
4713 at_end
= insn
== BB_END (bb
);
4714 if (delete_this
== NULL_RTX
4715 && (at_end
|| (GET_MODE (next
) == TImode
4716 && !(shadow_p (next
) && CALL_P (next
)))))
4719 gen_one_bundle (slot
, n_filled
, first_slot
);
4728 /* Bundling, and emitting nops, can separate
4729 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4732 for (insn
= get_insns (); insn
; insn
= next
)
4734 next
= NEXT_INSN (insn
);
4736 || (INSN_P (insn
) && GET_CODE (PATTERN (insn
)) == SEQUENCE
4737 && CALL_P (XVECEXP (PATTERN (insn
), 0, 0))))
4739 if (!NOTE_P (insn
) || NOTE_KIND (insn
) != NOTE_INSN_CALL_ARG_LOCATION
)
4741 if (NEXT_INSN (last_call
) == insn
)
4743 SET_NEXT_INSN (PREV_INSN (insn
)) = NEXT_INSN (insn
);
4744 SET_PREV_INSN (NEXT_INSN (insn
)) = PREV_INSN (insn
);
4745 SET_PREV_INSN (insn
) = last_call
;
4746 SET_NEXT_INSN (insn
) = NEXT_INSN (last_call
);
4747 SET_PREV_INSN (NEXT_INSN (insn
)) = insn
;
4748 SET_NEXT_INSN (PREV_INSN (insn
)) = insn
;
4753 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4756 emit_nop_after (int cycles
, rtx after
)
4760 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4761 operation. We don't need the extra NOP since in this case, the hardware
4762 will automatically insert the required stall. */
4766 gcc_assert (cycles
< 10);
4768 insn
= emit_insn_after (gen_nop_count (GEN_INT (cycles
)), after
);
4769 PUT_MODE (insn
, TImode
);
4774 /* Determine whether INSN is a call that needs to have a return label
4778 returning_call_p (rtx_insn
*insn
)
4781 return (!SIBLING_CALL_P (insn
)
4782 && get_attr_type (insn
) != TYPE_CALLP
4783 && get_attr_type (insn
) != TYPE_SHADOW
);
4784 if (recog_memoized (insn
) < 0)
4786 if (get_attr_type (insn
) == TYPE_CALL
)
4791 /* Determine whether INSN's pattern can be converted to use callp. */
4793 can_use_callp (rtx_insn
*insn
)
4795 int icode
= recog_memoized (insn
);
4796 if (!TARGET_INSNS_64PLUS
4798 || GET_CODE (PATTERN (insn
)) == COND_EXEC
)
4801 return ((icode
== CODE_FOR_real_call
4802 || icode
== CODE_FOR_call_internal
4803 || icode
== CODE_FOR_call_value_internal
)
4804 && get_attr_dest_regfile (insn
) == DEST_REGFILE_ANY
);
4807 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4809 convert_to_callp (rtx_insn
*insn
)
4812 extract_insn (insn
);
4813 if (GET_CODE (PATTERN (insn
)) == SET
)
4815 rtx dest
= recog_data
.operand
[0];
4816 lab
= recog_data
.operand
[1];
4817 PATTERN (insn
) = gen_callp_value (dest
, lab
);
4818 INSN_CODE (insn
) = CODE_FOR_callp_value
;
4822 lab
= recog_data
.operand
[0];
4823 PATTERN (insn
) = gen_callp (lab
);
4824 INSN_CODE (insn
) = CODE_FOR_callp
;
4828 /* Scan forwards from INSN until we find the next insn that has mode TImode
4829 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4830 Return it if we find such an insn, NULL_RTX otherwise. */
4832 find_next_cycle_insn (rtx insn
, int clock
)
4835 if (GET_MODE (t
) == TImode
)
4836 t
= next_real_insn (t
);
4837 while (t
&& GET_MODE (t
) != TImode
)
4838 t
= next_real_insn (t
);
4840 if (t
&& insn_get_clock (t
) == clock
)
4845 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4846 around PAT. Return PAT either unchanged or modified in this
4849 duplicate_cond (rtx pat
, rtx cond_insn
)
4851 rtx cond_pat
= PATTERN (cond_insn
);
4852 if (GET_CODE (cond_pat
) == COND_EXEC
)
4853 pat
= gen_rtx_COND_EXEC (VOIDmode
, copy_rtx (COND_EXEC_TEST (cond_pat
)),
4858 /* Walk forward from INSN to find the last insn that issues in the same clock
4861 find_last_same_clock (rtx insn
)
4864 rtx_insn
*t
= next_real_insn (insn
);
4866 while (t
&& GET_MODE (t
) != TImode
)
4868 if (!DEBUG_INSN_P (t
) && recog_memoized (t
) >= 0)
4870 t
= next_real_insn (t
);
4875 /* For every call insn in the function, emit code to load the return
4876 address. For each call we create a return label and store it in
4877 CALL_LABELS. If are not scheduling, we emit the labels here,
4878 otherwise the caller will do it later.
4879 This function is called after final insn scheduling, but before creating
4880 the SEQUENCEs that represent execute packets. */
4883 reorg_split_calls (rtx
*call_labels
)
4885 unsigned int reservation_mask
= 0;
4886 rtx_insn
*insn
= get_insns ();
4887 gcc_assert (NOTE_P (insn
));
4888 insn
= next_real_insn (insn
);
4892 rtx_insn
*next
= next_real_insn (insn
);
4894 if (DEBUG_INSN_P (insn
))
4897 if (GET_MODE (insn
) == TImode
)
4898 reservation_mask
= 0;
4899 uid
= INSN_UID (insn
);
4900 if (c6x_flag_schedule_insns2
&& recog_memoized (insn
) >= 0)
4901 reservation_mask
|= 1 << INSN_INFO_ENTRY (uid
).reservation
;
4903 if (returning_call_p (insn
))
4905 rtx label
= gen_label_rtx ();
4906 rtx labelref
= gen_rtx_LABEL_REF (Pmode
, label
);
4907 rtx reg
= gen_rtx_REG (SImode
, RETURN_ADDR_REGNO
);
4909 LABEL_NUSES (label
) = 2;
4910 if (!c6x_flag_schedule_insns2
)
4912 if (can_use_callp (insn
))
4913 convert_to_callp (insn
);
4918 emit_label_after (label
, insn
);
4920 /* Bundle the call and its delay slots into a single
4921 SEQUENCE. While these do not issue in parallel
4922 we need to group them into a single EH region. */
4924 PUT_MODE (insn
, TImode
);
4925 if (TARGET_INSNS_64
)
4927 t
= gen_addkpc (reg
, labelref
, GEN_INT (4));
4928 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4930 PUT_MODE (slot
[1], TImode
);
4931 gen_one_bundle (slot
, 2, 0);
4935 slot
[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4937 PUT_MODE (slot
[3], TImode
);
4938 t
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4939 slot
[2] = emit_insn_after (duplicate_cond (t
, insn
),
4941 PUT_MODE (slot
[2], TImode
);
4942 t
= gen_movsi_high (reg
, labelref
);
4943 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4945 PUT_MODE (slot
[1], TImode
);
4946 gen_one_bundle (slot
, 4, 0);
4952 /* If we scheduled, we reserved the .S2 unit for one or two
4953 cycles after the call. Emit the insns in these slots,
4954 unless it's possible to create a CALLP insn.
4955 Note that this works because the dependencies ensure that
4956 no insn setting/using B3 is scheduled in the delay slots of
4958 int this_clock
= insn_get_clock (insn
);
4959 rtx last_same_clock
;
4962 call_labels
[INSN_UID (insn
)] = label
;
4964 last_same_clock
= find_last_same_clock (insn
);
4966 if (can_use_callp (insn
))
4968 /* Find the first insn of the next execute packet. If it
4969 is the shadow insn corresponding to this call, we may
4970 use a CALLP insn. */
4972 next_nonnote_nondebug_insn (last_same_clock
);
4975 && insn_get_clock (shadow
) == this_clock
+ 5)
4977 convert_to_callp (shadow
);
4978 insn_set_clock (shadow
, this_clock
);
4979 INSN_INFO_ENTRY (INSN_UID (shadow
)).reservation
4981 INSN_INFO_ENTRY (INSN_UID (shadow
)).unit_mask
4982 = INSN_INFO_ENTRY (INSN_UID (last_same_clock
)).unit_mask
;
4983 if (GET_MODE (insn
) == TImode
)
4985 rtx_insn
*new_cycle_first
= NEXT_INSN (insn
);
4986 while (!NONDEBUG_INSN_P (new_cycle_first
)
4987 || GET_CODE (PATTERN (new_cycle_first
)) == USE
4988 || GET_CODE (PATTERN (new_cycle_first
)) == CLOBBER
)
4989 new_cycle_first
= NEXT_INSN (new_cycle_first
);
4990 PUT_MODE (new_cycle_first
, TImode
);
4991 if (new_cycle_first
!= shadow
)
4992 PUT_MODE (shadow
, VOIDmode
);
4993 INSN_INFO_ENTRY (INSN_UID (new_cycle_first
)).ebb_start
4994 = INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
;
4997 PUT_MODE (shadow
, VOIDmode
);
5002 after1
= find_next_cycle_insn (last_same_clock
, this_clock
+ 1);
5003 if (after1
== NULL_RTX
)
5004 after1
= last_same_clock
;
5006 after1
= find_last_same_clock (after1
);
5007 if (TARGET_INSNS_64
)
5009 rtx x1
= gen_addkpc (reg
, labelref
, const0_rtx
);
5010 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5011 insn_set_clock (x1
, this_clock
+ 1);
5012 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5013 if (after1
== last_same_clock
)
5014 PUT_MODE (x1
, TImode
);
5016 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5017 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5022 rtx after2
= find_next_cycle_insn (after1
, this_clock
+ 2);
5023 if (after2
== NULL_RTX
)
5025 x2
= gen_movsi_lo_sum (reg
, reg
, labelref
);
5026 x2
= emit_insn_after (duplicate_cond (x2
, insn
), after2
);
5027 x1
= gen_movsi_high (reg
, labelref
);
5028 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5029 insn_set_clock (x1
, this_clock
+ 1);
5030 insn_set_clock (x2
, this_clock
+ 2);
5031 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5032 INSN_INFO_ENTRY (INSN_UID (x2
)).reservation
= RESERVATION_S2
;
5033 if (after1
== last_same_clock
)
5034 PUT_MODE (x1
, TImode
);
5036 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5037 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5038 if (after1
== after2
)
5039 PUT_MODE (x2
, TImode
);
5041 INSN_INFO_ENTRY (INSN_UID (x2
)).unit_mask
5042 = INSN_INFO_ENTRY (INSN_UID (after2
)).unit_mask
;
5051 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
5052 insns as required for correctness. CALL_LABELS is the array that
5053 holds the return labels for call insns; we emit these here if
5054 scheduling was run earlier. */
5057 reorg_emit_nops (rtx
*call_labels
)
5062 int prev_clock
, earliest_bb_end
;
5063 int prev_implicit_nops
;
5064 rtx_insn
*insn
= get_insns ();
5066 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5067 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5068 clocks, we must insert a NOP.
5069 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5070 current basic block will finish. We must not allow the next basic block to
5071 begin before this cycle.
5072 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5073 a multi-cycle nop. The code is scheduled such that subsequent insns will
5074 show the cycle gap, but we needn't insert a real NOP instruction. */
5075 insn
= next_real_insn (insn
);
5076 last_call
= prev
= NULL
;
5078 earliest_bb_end
= 0;
5079 prev_implicit_nops
= 0;
5083 int this_clock
= -1;
5087 next
= next_real_insn (insn
);
5089 if (DEBUG_INSN_P (insn
)
5090 || GET_CODE (PATTERN (insn
)) == USE
5091 || GET_CODE (PATTERN (insn
)) == CLOBBER
5092 || shadow_or_blockage_p (insn
)
5093 || JUMP_TABLE_DATA_P (insn
))
5096 if (!c6x_flag_schedule_insns2
)
5097 /* No scheduling; ensure that no parallel issue happens. */
5098 PUT_MODE (insn
, TImode
);
5103 this_clock
= insn_get_clock (insn
);
5104 if (this_clock
!= prev_clock
)
5106 PUT_MODE (insn
, TImode
);
5110 cycles
= this_clock
- prev_clock
;
5112 cycles
-= prev_implicit_nops
;
5115 rtx nop
= emit_nop_after (cycles
- 1, prev
);
5116 insn_set_clock (nop
, prev_clock
+ prev_implicit_nops
+ 1);
5119 prev_clock
= this_clock
;
5122 && insn_get_clock (last_call
) + 6 <= this_clock
)
5124 emit_label_before (call_labels
[INSN_UID (last_call
)], insn
);
5125 last_call
= NULL_RTX
;
5127 prev_implicit_nops
= 0;
5131 /* Examine how many cycles the current insn takes, and adjust
5132 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5133 if (recog_memoized (insn
) >= 0
5134 /* If not scheduling, we've emitted NOPs after calls already. */
5135 && (c6x_flag_schedule_insns2
|| !returning_call_p (insn
)))
5137 max_cycles
= get_attr_cycles (insn
);
5138 if (get_attr_type (insn
) == TYPE_CALLP
)
5139 prev_implicit_nops
= 5;
5143 if (returning_call_p (insn
))
5146 if (c6x_flag_schedule_insns2
)
5148 gcc_assert (this_clock
>= 0);
5149 if (earliest_bb_end
< this_clock
+ max_cycles
)
5150 earliest_bb_end
= this_clock
+ max_cycles
;
5152 else if (max_cycles
> 1)
5153 emit_nop_after (max_cycles
- 1, insn
);
5159 if (c6x_flag_schedule_insns2
5160 && (next
== NULL_RTX
5161 || (GET_MODE (next
) == TImode
5162 && INSN_INFO_ENTRY (INSN_UID (next
)).ebb_start
))
5163 && earliest_bb_end
> 0)
5165 int cycles
= earliest_bb_end
- prev_clock
;
5168 prev
= emit_nop_after (cycles
- 1, prev
);
5169 insn_set_clock (prev
, prev_clock
+ prev_implicit_nops
+ 1);
5171 earliest_bb_end
= 0;
5176 emit_label_after (call_labels
[INSN_UID (last_call
)], prev
);
5177 last_call
= NULL_RTX
;
5183 /* If possible, split INSN, which we know is either a jump or a call, into a real
5184 insn and its shadow. */
5186 split_delayed_branch (rtx_insn
*insn
)
5188 int code
= recog_memoized (insn
);
5191 rtx pat
= PATTERN (insn
);
5193 if (GET_CODE (pat
) == COND_EXEC
)
5194 pat
= COND_EXEC_CODE (pat
);
5198 rtx src
= pat
, dest
= NULL_RTX
;
5200 if (GET_CODE (pat
) == SET
)
5202 dest
= SET_DEST (pat
);
5203 src
= SET_SRC (pat
);
5205 callee
= XEXP (XEXP (src
, 0), 0);
5206 if (SIBLING_CALL_P (insn
))
5209 newpat
= gen_indirect_sibcall_shadow ();
5211 newpat
= gen_sibcall_shadow (callee
);
5212 pat
= gen_real_jump (callee
);
5214 else if (dest
!= NULL_RTX
)
5217 newpat
= gen_indirect_call_value_shadow (dest
);
5219 newpat
= gen_call_value_shadow (dest
, callee
);
5220 pat
= gen_real_call (callee
);
5225 newpat
= gen_indirect_call_shadow ();
5227 newpat
= gen_call_shadow (callee
);
5228 pat
= gen_real_call (callee
);
5230 pat
= duplicate_cond (pat
, insn
);
5231 newpat
= duplicate_cond (newpat
, insn
);
5236 if (GET_CODE (pat
) == PARALLEL
5237 && GET_CODE (XVECEXP (pat
, 0, 0)) == RETURN
)
5239 newpat
= gen_return_shadow ();
5240 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5241 newpat
= duplicate_cond (newpat
, insn
);
5246 case CODE_FOR_br_true
:
5247 case CODE_FOR_br_false
:
5248 src
= SET_SRC (pat
);
5249 op
= XEXP (src
, code
== CODE_FOR_br_true
? 1 : 2);
5250 newpat
= gen_condjump_shadow (op
);
5251 pat
= gen_real_jump (op
);
5252 if (code
== CODE_FOR_br_true
)
5253 pat
= gen_rtx_COND_EXEC (VOIDmode
, XEXP (src
, 0), pat
);
5255 pat
= gen_rtx_COND_EXEC (VOIDmode
,
5256 reversed_comparison (XEXP (src
, 0),
5263 newpat
= gen_jump_shadow (op
);
5266 case CODE_FOR_indirect_jump
:
5267 newpat
= gen_indirect_jump_shadow ();
5270 case CODE_FOR_return_internal
:
5271 newpat
= gen_return_shadow ();
5272 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5279 i1
= emit_insn_before (pat
, insn
);
5280 PATTERN (insn
) = newpat
;
5281 INSN_CODE (insn
) = -1;
5282 record_delay_slot_pair (i1
, insn
, 5, 0);
5285 /* If INSN is a multi-cycle insn that should be handled properly in
5286 modulo-scheduling, split it into a real insn and a shadow.
5287 Return true if we made a change.
5289 It is valid for us to fail to split an insn; the caller has to deal
5290 with the possibility. Currently we handle loads and most mpy2 and
5293 split_delayed_nonbranch (rtx_insn
*insn
)
5295 int code
= recog_memoized (insn
);
5296 enum attr_type type
;
5298 rtx newpat
, src
, dest
;
5299 rtx pat
= PATTERN (insn
);
5303 if (GET_CODE (pat
) == COND_EXEC
)
5304 pat
= COND_EXEC_CODE (pat
);
5306 if (code
< 0 || GET_CODE (pat
) != SET
)
5308 src
= SET_SRC (pat
);
5309 dest
= SET_DEST (pat
);
5313 type
= get_attr_type (insn
);
5315 && (type
== TYPE_LOAD
5316 || type
== TYPE_LOADN
))
5319 && (GET_CODE (src
) != ZERO_EXTEND
5320 || !MEM_P (XEXP (src
, 0))))
5323 if (GET_MODE_SIZE (GET_MODE (dest
)) > 4
5324 && (GET_MODE_SIZE (GET_MODE (dest
)) != 8 || !TARGET_LDDW
))
5327 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5329 newpat
= gen_load_shadow (SET_DEST (pat
));
5330 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_LOAD
);
5334 && (type
== TYPE_MPY2
5335 || type
== TYPE_MPY4
))
5337 /* We don't handle floating point multiplies yet. */
5338 if (GET_MODE (dest
) == SFmode
)
5341 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5343 newpat
= gen_mult_shadow (SET_DEST (pat
));
5344 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_MULT
);
5345 delay
= type
== TYPE_MPY2
? 1 : 3;
5350 pat
= duplicate_cond (pat
, insn
);
5351 newpat
= duplicate_cond (newpat
, insn
);
5352 i1
= emit_insn_before (pat
, insn
);
5353 PATTERN (insn
) = newpat
;
5354 INSN_CODE (insn
) = -1;
5355 recog_memoized (insn
);
5356 recog_memoized (i1
);
5357 record_delay_slot_pair (i1
, insn
, delay
, 0);
5361 /* Examine if INSN is the result of splitting a load into a real load and a
5362 shadow, and if so, undo the transformation. */
5364 undo_split_delayed_nonbranch (rtx_insn
*insn
)
5366 int icode
= recog_memoized (insn
);
5367 enum attr_type type
;
5368 rtx prev_pat
, insn_pat
;
5373 type
= get_attr_type (insn
);
5374 if (type
!= TYPE_LOAD_SHADOW
&& type
!= TYPE_MULT_SHADOW
)
5376 prev
= PREV_INSN (insn
);
5377 prev_pat
= PATTERN (prev
);
5378 insn_pat
= PATTERN (insn
);
5379 if (GET_CODE (prev_pat
) == COND_EXEC
)
5381 prev_pat
= COND_EXEC_CODE (prev_pat
);
5382 insn_pat
= COND_EXEC_CODE (insn_pat
);
5385 gcc_assert (GET_CODE (prev_pat
) == UNSPEC
5386 && ((XINT (prev_pat
, 1) == UNSPEC_REAL_LOAD
5387 && type
== TYPE_LOAD_SHADOW
)
5388 || (XINT (prev_pat
, 1) == UNSPEC_REAL_MULT
5389 && type
== TYPE_MULT_SHADOW
)));
5390 insn_pat
= gen_rtx_SET (SET_DEST (insn_pat
),
5391 XVECEXP (prev_pat
, 0, 1));
5392 insn_pat
= duplicate_cond (insn_pat
, prev
);
5393 PATTERN (insn
) = insn_pat
;
5394 INSN_CODE (insn
) = -1;
5398 /* Split every insn (i.e. jumps and calls) which can have delay slots into
5399 two parts: the first one is scheduled normally and emits the instruction,
5400 while the second one is a shadow insn which shows the side effect taking
5401 place. The second one is placed in the right cycle by the scheduler, but
5402 not emitted as an assembly instruction. */
5405 split_delayed_insns (void)
5408 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5410 if (JUMP_P (insn
) || CALL_P (insn
))
5411 split_delayed_branch (insn
);
5415 /* For every insn that has an entry in the new_conditions vector, give it
5416 the appropriate predicate. */
5418 conditionalize_after_sched (void)
5422 FOR_EACH_BB_FN (bb
, cfun
)
5423 FOR_BB_INSNS (bb
, insn
)
5425 unsigned uid
= INSN_UID (insn
);
5427 if (!NONDEBUG_INSN_P (insn
) || uid
>= INSN_INFO_LENGTH
)
5429 cond
= INSN_INFO_ENTRY (uid
).new_cond
;
5430 if (cond
== NULL_RTX
)
5433 fprintf (dump_file
, "Conditionalizing insn %d\n", uid
);
5434 predicate_insn (insn
, cond
, true);
5438 /* A callback for the hw-doloop pass. This function examines INSN; if
5439 it is a loop_end pattern we recognize, return the reg rtx for the
5440 loop counter. Otherwise, return NULL_RTX. */
5443 hwloop_pattern_reg (rtx_insn
*insn
)
5447 if (!JUMP_P (insn
) || recog_memoized (insn
) != CODE_FOR_loop_end
)
5450 pat
= PATTERN (insn
);
5451 reg
= SET_DEST (XVECEXP (pat
, 0, 1));
5457 /* Return the number of cycles taken by BB, as computed by scheduling,
5458 including the latencies of all insns with delay slots. IGNORE is
5459 an insn we should ignore in the calculation, usually the final
5462 bb_earliest_end_cycle (basic_block bb
, rtx ignore
)
5467 FOR_BB_INSNS (bb
, insn
)
5469 int cycles
, this_clock
;
5471 if (LABEL_P (insn
) || NOTE_P (insn
) || DEBUG_INSN_P (insn
)
5472 || GET_CODE (PATTERN (insn
)) == USE
5473 || GET_CODE (PATTERN (insn
)) == CLOBBER
5477 this_clock
= insn_get_clock (insn
);
5478 cycles
= get_attr_cycles (insn
);
5480 if (earliest
< this_clock
+ cycles
)
5481 earliest
= this_clock
+ cycles
;
5486 /* Examine the insns in BB and remove all which have a uid greater or
5487 equal to MAX_UID. */
5489 filter_insns_above (basic_block bb
, int max_uid
)
5491 rtx_insn
*insn
, *next
;
5492 bool prev_ti
= false;
5493 int prev_cycle
= -1;
5495 FOR_BB_INSNS_SAFE (bb
, insn
, next
)
5498 if (!NONDEBUG_INSN_P (insn
))
5500 if (insn
== BB_END (bb
))
5502 this_cycle
= insn_get_clock (insn
);
5503 if (prev_ti
&& this_cycle
== prev_cycle
)
5505 gcc_assert (GET_MODE (insn
) != TImode
);
5506 PUT_MODE (insn
, TImode
);
5509 if (INSN_UID (insn
) >= max_uid
)
5511 if (GET_MODE (insn
) == TImode
)
5514 prev_cycle
= this_cycle
;
5521 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5524 c6x_asm_emit_except_personality (rtx personality
)
5526 fputs ("\t.personality\t", asm_out_file
);
5527 output_addr_const (asm_out_file
, personality
);
5528 fputc ('\n', asm_out_file
);
5531 /* Use a special assembly directive rather than a regular setion for
5532 unwind table data. */
5535 c6x_asm_init_sections (void)
5537 exception_section
= get_unnamed_section (0, output_section_asm_op
,
5541 /* A callback for the hw-doloop pass. Called to optimize LOOP in a
5542 machine-specific fashion; returns true if successful and false if
5543 the hwloop_fail function should be called. */
5546 hwloop_optimize (hwloop_info loop
)
5548 basic_block entry_bb
, bb
;
5549 rtx_insn
*seq
, *insn
, *prev
, *entry_after
, *end_packet
;
5550 rtx_insn
*head_insn
, *tail_insn
, *new_insns
, *last_insn
;
5552 int n_execute_packets
;
5555 int max_uid_before
, delayed_splits
;
5556 int i
, sp_ii
, min_ii
, max_ii
, max_parallel
, n_insns
, n_real_insns
, stages
;
5557 rtx_insn
**orig_vec
;
5559 rtx_insn
***insn_copies
;
5561 if (!c6x_flag_modulo_sched
|| !c6x_flag_schedule_insns2
5562 || !TARGET_INSNS_64PLUS
)
5565 if (loop
->iter_reg_used
|| loop
->depth
> 1)
5567 if (loop
->has_call
|| loop
->has_asm
)
5570 if (loop
->head
!= loop
->tail
)
5573 gcc_assert (loop
->incoming_dest
== loop
->head
);
5576 FOR_EACH_VEC_SAFE_ELT (loop
->incoming
, i
, entry_edge
)
5577 if (entry_edge
->flags
& EDGE_FALLTHRU
)
5579 if (entry_edge
== NULL
)
5582 reshuffle_units (loop
->head
);
5585 schedule_ebbs_init ();
5586 schedule_ebb (BB_HEAD (loop
->tail
), loop
->loop_end
, true);
5587 schedule_ebbs_finish ();
5591 loop_earliest
= bb_earliest_end_cycle (bb
, loop
->loop_end
) + 1;
5593 max_uid_before
= get_max_uid ();
5595 /* Split all multi-cycle operations, such as loads. For normal
5596 scheduling, we only do this for branches, as the generated code
5597 would otherwise not be interrupt-safe. When using sploop, it is
5598 safe and beneficial to split them. If any multi-cycle operations
5599 remain after splitting (because we don't handle them yet), we
5600 cannot pipeline the loop. */
5602 FOR_BB_INSNS (bb
, insn
)
5604 if (NONDEBUG_INSN_P (insn
))
5606 recog_memoized (insn
);
5607 if (split_delayed_nonbranch (insn
))
5609 else if (INSN_CODE (insn
) >= 0
5610 && get_attr_cycles (insn
) > 1)
5615 /* Count the number of insns as well as the number real insns, and save
5616 the original sequence of insns in case we must restore it later. */
5617 n_insns
= n_real_insns
= 0;
5618 FOR_BB_INSNS (bb
, insn
)
5621 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5624 orig_vec
= XNEWVEC (rtx_insn
*, n_insns
);
5626 FOR_BB_INSNS (bb
, insn
)
5627 orig_vec
[n_insns
++] = insn
;
5629 /* Count the unit reservations, and compute a minimum II from that
5631 count_unit_reqs (unit_reqs
, loop
->start_label
,
5632 PREV_INSN (loop
->loop_end
));
5633 merge_unit_reqs (unit_reqs
);
5635 min_ii
= res_mii (unit_reqs
);
5636 max_ii
= loop_earliest
< 15 ? loop_earliest
: 14;
5638 /* Make copies of the loop body, up to a maximum number of stages we want
5640 max_parallel
= loop_earliest
/ min_ii
+ 1;
5642 copies
= XCNEWVEC (rtx_insn
*, (max_parallel
+ 1) * n_real_insns
);
5643 insn_copies
= XNEWVEC (rtx_insn
**, max_parallel
+ 1);
5644 for (i
= 0; i
< max_parallel
+ 1; i
++)
5645 insn_copies
[i
] = copies
+ i
* n_real_insns
;
5647 head_insn
= next_nonnote_nondebug_insn (loop
->start_label
);
5648 tail_insn
= prev_real_insn (BB_END (bb
));
5651 FOR_BB_INSNS (bb
, insn
)
5652 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5653 insn_copies
[0][i
++] = insn
;
5655 sploop_max_uid_iter0
= get_max_uid ();
5657 /* Generate the copies of the loop body, and save them in the
5658 INSN_COPIES array. */
5660 for (i
= 0; i
< max_parallel
; i
++)
5663 rtx_insn
*this_iter
;
5665 this_iter
= duplicate_insn_chain (head_insn
, tail_insn
);
5669 rtx_insn
*prev_stage_insn
= insn_copies
[i
][j
];
5670 gcc_assert (INSN_CODE (this_iter
) == INSN_CODE (prev_stage_insn
));
5672 if (INSN_CODE (this_iter
) >= 0
5673 && (get_attr_type (this_iter
) == TYPE_LOAD_SHADOW
5674 || get_attr_type (this_iter
) == TYPE_MULT_SHADOW
))
5676 rtx_insn
*prev
= PREV_INSN (this_iter
);
5677 record_delay_slot_pair (prev
, this_iter
,
5678 get_attr_cycles (prev
) - 1, 0);
5681 record_delay_slot_pair (prev_stage_insn
, this_iter
, i
, 1);
5683 insn_copies
[i
+ 1][j
] = this_iter
;
5685 this_iter
= next_nonnote_nondebug_insn (this_iter
);
5688 new_insns
= get_insns ();
5689 last_insn
= insn_copies
[max_parallel
][n_real_insns
- 1];
5691 emit_insn_before (new_insns
, BB_END (bb
));
5693 /* Try to schedule the loop using varying initiation intervals,
5694 starting with the smallest possible and incrementing it
5696 for (sp_ii
= min_ii
; sp_ii
<= max_ii
; sp_ii
++)
5700 fprintf (dump_file
, "Trying to schedule for II %d\n", sp_ii
);
5702 df_clear_flags (DF_LR_RUN_DCE
);
5704 schedule_ebbs_init ();
5705 set_modulo_params (sp_ii
, max_parallel
, n_real_insns
,
5706 sploop_max_uid_iter0
);
5707 tmp_bb
= schedule_ebb (BB_HEAD (bb
), last_insn
, true);
5708 schedule_ebbs_finish ();
5713 fprintf (dump_file
, "Found schedule with II %d\n", sp_ii
);
5718 discard_delay_pairs_above (max_uid_before
);
5723 stages
= insn_get_clock (ss
.last_scheduled_iter0
) / sp_ii
+ 1;
5725 if (stages
== 1 && sp_ii
> 5)
5728 /* At this point, we know we've been successful, unless we find later that
5729 there are too many execute packets for the loop buffer to hold. */
5731 /* Assign reservations to the instructions in the loop. We must find
5732 the stage that contains the full loop kernel, and transfer the
5733 reservations of the instructions contained in it to the corresponding
5734 instructions from iteration 0, which are the only ones we'll keep. */
5735 assign_reservations (BB_HEAD (bb
), ss
.last_scheduled_insn
);
5736 SET_PREV_INSN (BB_END (bb
)) = ss
.last_scheduled_iter0
;
5737 SET_NEXT_INSN (ss
.last_scheduled_iter0
) = BB_END (bb
);
5738 filter_insns_above (bb
, sploop_max_uid_iter0
);
5740 for (i
= 0; i
< n_real_insns
; i
++)
5742 rtx insn
= insn_copies
[0][i
];
5743 int uid
= INSN_UID (insn
);
5744 int stage
= insn_uid_get_clock (uid
) / sp_ii
;
5746 if (stage
+ 1 < stages
)
5749 stage
= stages
- stage
- 1;
5750 copy_uid
= INSN_UID (insn_copies
[stage
][i
]);
5751 INSN_INFO_ENTRY (uid
).reservation
5752 = INSN_INFO_ENTRY (copy_uid
).reservation
;
5758 /* Compute the number of execute packets the pipelined form of the loop will
5761 n_execute_packets
= 0;
5762 for (insn
= loop
->start_label
;
5763 insn
!= loop
->loop_end
;
5764 insn
= NEXT_INSN (insn
))
5766 if (NONDEBUG_INSN_P (insn
) && GET_MODE (insn
) == TImode
5767 && !shadow_p (insn
))
5769 n_execute_packets
++;
5770 if (prev
&& insn_get_clock (prev
) + 1 != insn_get_clock (insn
))
5771 /* We need an extra NOP instruction. */
5772 n_execute_packets
++;
5778 end_packet
= ss
.last_scheduled_iter0
;
5779 while (!NONDEBUG_INSN_P (end_packet
) || GET_MODE (end_packet
) != TImode
)
5780 end_packet
= PREV_INSN (end_packet
);
5782 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5783 loop_earliest
= (stages
- 1) * sp_ii
;
5784 if (loop_earliest
> insn_get_clock (end_packet
))
5786 n_execute_packets
++;
5787 end_packet
= loop
->loop_end
;
5790 loop_earliest
= insn_get_clock (end_packet
);
5792 if (n_execute_packets
> 14)
5795 /* Generate the spkernel instruction, and place it at the appropriate
5797 PUT_MODE (end_packet
, VOIDmode
);
5799 insn
= emit_jump_insn_before (
5800 gen_spkernel (GEN_INT (stages
- 1),
5801 const0_rtx
, JUMP_LABEL (loop
->loop_end
)),
5803 JUMP_LABEL (insn
) = JUMP_LABEL (loop
->loop_end
);
5804 insn_set_clock (insn
, loop_earliest
);
5805 PUT_MODE (insn
, TImode
);
5806 INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
= false;
5807 delete_insn (loop
->loop_end
);
5809 /* Place the mvc and sploop instructions before the loop. */
5810 entry_bb
= entry_edge
->src
;
5814 insn
= emit_insn (gen_mvilc (loop
->iter_reg
));
5815 insn
= emit_insn (gen_sploop (GEN_INT (sp_ii
)));
5819 if (!single_succ_p (entry_bb
) || vec_safe_length (loop
->incoming
) > 1)
5825 emit_insn_before (seq
, BB_HEAD (loop
->head
));
5826 seq
= emit_label_before (gen_label_rtx (), seq
);
5828 new_bb
= create_basic_block (seq
, insn
, entry_bb
);
5829 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
5831 if (!(e
->flags
& EDGE_FALLTHRU
))
5832 redirect_edge_and_branch_force (e
, new_bb
);
5834 redirect_edge_succ (e
, new_bb
);
5836 make_edge (new_bb
, loop
->head
, 0);
5840 entry_after
= BB_END (entry_bb
);
5841 while (DEBUG_INSN_P (entry_after
)
5842 || (NOTE_P (entry_after
)
5843 && NOTE_KIND (entry_after
) != NOTE_INSN_BASIC_BLOCK
))
5844 entry_after
= PREV_INSN (entry_after
);
5845 emit_insn_after (seq
, entry_after
);
5850 /* Make sure we don't try to schedule this loop again. */
5851 for (ix
= 0; loop
->blocks
.iterate (ix
, &bb
); ix
++)
5852 bb
->flags
|= BB_DISABLE_SCHEDULE
;
5858 fprintf (dump_file
, "Unable to pipeline loop.\n");
5860 for (i
= 1; i
< n_insns
; i
++)
5862 SET_NEXT_INSN (orig_vec
[i
- 1]) = orig_vec
[i
];
5863 SET_PREV_INSN (orig_vec
[i
]) = orig_vec
[i
- 1];
5865 SET_PREV_INSN (orig_vec
[0]) = PREV_INSN (BB_HEAD (bb
));
5866 SET_NEXT_INSN (PREV_INSN (BB_HEAD (bb
))) = orig_vec
[0];
5867 SET_NEXT_INSN (orig_vec
[n_insns
- 1]) = NEXT_INSN (BB_END (bb
));
5868 SET_PREV_INSN (NEXT_INSN (BB_END (bb
))) = orig_vec
[n_insns
- 1];
5869 BB_HEAD (bb
) = orig_vec
[0];
5870 BB_END (bb
) = orig_vec
[n_insns
- 1];
5872 free_delay_pairs ();
5873 FOR_BB_INSNS (bb
, insn
)
5874 if (NONDEBUG_INSN_P (insn
))
5875 undo_split_delayed_nonbranch (insn
);
5879 /* A callback for the hw-doloop pass. Called when a loop we have discovered
5880 turns out not to be optimizable; we have to split the doloop_end pattern
5881 into a subtract and a test. */
5883 hwloop_fail (hwloop_info loop
)
5885 rtx insn
, test
, testreg
;
5888 fprintf (dump_file
, "splitting doloop insn %d\n",
5889 INSN_UID (loop
->loop_end
));
5890 insn
= gen_addsi3 (loop
->iter_reg
, loop
->iter_reg
, constm1_rtx
);
5891 /* See if we can emit the add at the head of the loop rather than at the
5893 if (loop
->head
== NULL
5894 || loop
->iter_reg_used_outside
5895 || loop
->iter_reg_used
5896 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REGNO (loop
->iter_reg
))
5897 || loop
->incoming_dest
!= loop
->head
5898 || EDGE_COUNT (loop
->head
->preds
) != 2)
5899 emit_insn_before (insn
, loop
->loop_end
);
5902 rtx_insn
*t
= loop
->start_label
;
5903 while (!NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_BASIC_BLOCK
)
5905 emit_insn_after (insn
, t
);
5908 testreg
= SET_DEST (XVECEXP (PATTERN (loop
->loop_end
), 0, 2));
5909 if (GET_CODE (testreg
) == SCRATCH
)
5910 testreg
= loop
->iter_reg
;
5912 emit_insn_before (gen_movsi (testreg
, loop
->iter_reg
), loop
->loop_end
);
5914 test
= gen_rtx_NE (VOIDmode
, testreg
, const0_rtx
);
5915 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
, testreg
, const0_rtx
,
5919 JUMP_LABEL (insn
) = loop
->start_label
;
5920 LABEL_NUSES (loop
->start_label
)++;
5921 delete_insn (loop
->loop_end
);
5924 static struct hw_doloop_hooks c6x_doloop_hooks
=
5931 /* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5932 doloop_end patterns where such optimizations are impossible. */
5937 reorg_loops (true, &c6x_doloop_hooks
);
5940 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5941 into a sequence that loads the return register and performs the call,
5942 and emit the return label.
5943 If scheduling after reload is requested, it happens here. */
5950 bool do_selsched
= (c6x_flag_schedule_insns2
&& flag_selective_scheduling2
5951 && !maybe_skip_selective_scheduling ());
5953 /* We are freeing block_for_insn in the toplev to keep compatibility
5954 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5955 compute_bb_for_insn ();
5957 df_clear_flags (DF_LR_RUN_DCE
);
5958 df_note_add_problem ();
5960 /* If optimizing, we'll have split before scheduling. */
5966 if (c6x_flag_schedule_insns2
)
5968 int sz
= get_max_uid () * 3 / 2 + 1;
5970 insn_info
.create (sz
);
5973 /* Make sure the real-jump insns we create are not deleted. When modulo-
5974 scheduling, situations where a reg is only stored in a loop can also
5975 cause dead code when doing the initial unrolling. */
5976 sched_no_dce
= true;
5980 if (c6x_flag_schedule_insns2
)
5982 split_delayed_insns ();
5983 timevar_push (TV_SCHED2
);
5985 run_selective_scheduling ();
5988 conditionalize_after_sched ();
5989 timevar_pop (TV_SCHED2
);
5991 free_delay_pairs ();
5993 sched_no_dce
= false;
5995 call_labels
= XCNEWVEC (rtx
, get_max_uid () + 1);
5997 reorg_split_calls (call_labels
);
5999 if (c6x_flag_schedule_insns2
)
6001 FOR_EACH_BB_FN (bb
, cfun
)
6002 if ((bb
->flags
& BB_DISABLE_SCHEDULE
) == 0)
6003 assign_reservations (BB_HEAD (bb
), BB_END (bb
));
6006 if (c6x_flag_var_tracking
)
6008 timevar_push (TV_VAR_TRACKING
);
6009 variable_tracking_main ();
6010 timevar_pop (TV_VAR_TRACKING
);
6013 reorg_emit_nops (call_labels
);
6015 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
6016 if (c6x_flag_schedule_insns2
)
6018 free_delay_pairs ();
6022 df_finish_pass (false);
6025 /* Called when a function has been assembled. It should perform all the
6026 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
6028 We free the reservation (and other scheduling) information here now that
6029 all insns have been output. */
6031 c6x_function_end (FILE *file
, const char *fname
)
6033 c6x_output_fn_unwind (file
);
6035 insn_info
.release ();
6037 if (!flag_inhibit_size_directive
)
6038 ASM_OUTPUT_MEASURED_SIZE (file
, fname
);
6041 /* Determine whether X is a shift with code CODE and an integer amount
6044 shift_p (rtx x
, enum rtx_code code
, int amount
)
6046 return (GET_CODE (x
) == code
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
6047 && INTVAL (XEXP (x
, 1)) == amount
);
6050 /* Compute a (partial) cost for rtx X. Return true if the complete
6051 cost has been computed, and false if subexpressions should be
6052 scanned. In either case, *TOTAL contains the cost result. */
6055 c6x_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
6058 int cost2
= COSTS_N_INSNS (1);
6064 if (outer_code
== SET
|| outer_code
== PLUS
)
6065 *total
= satisfies_constraint_IsB (x
) ? 0 : cost2
;
6066 else if (outer_code
== AND
|| outer_code
== IOR
|| outer_code
== XOR
6067 || outer_code
== MINUS
)
6068 *total
= satisfies_constraint_Is5 (x
) ? 0 : cost2
;
6069 else if (GET_RTX_CLASS (outer_code
) == RTX_COMPARE
6070 || GET_RTX_CLASS (outer_code
) == RTX_COMM_COMPARE
)
6071 *total
= satisfies_constraint_Iu4 (x
) ? 0 : cost2
;
6072 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
6073 || outer_code
== LSHIFTRT
)
6074 *total
= satisfies_constraint_Iu5 (x
) ? 0 : cost2
;
6083 *total
= COSTS_N_INSNS (2);
6087 /* Recognize a mult_highpart operation. */
6088 if ((GET_MODE (x
) == HImode
|| GET_MODE (x
) == SImode
)
6089 && GET_CODE (XEXP (x
, 0)) == LSHIFTRT
6090 && GET_MODE (XEXP (x
, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x
))
6091 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
6092 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
6093 && INTVAL (XEXP (XEXP (x
, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x
)))
6095 rtx mul
= XEXP (XEXP (x
, 0), 0);
6096 rtx op0
= XEXP (mul
, 0);
6097 rtx op1
= XEXP (mul
, 1);
6098 enum rtx_code code0
= GET_CODE (op0
);
6099 enum rtx_code code1
= GET_CODE (op1
);
6102 && (code0
== SIGN_EXTEND
|| code0
== ZERO_EXTEND
))
6103 || (GET_MODE (x
) == HImode
6104 && code0
== ZERO_EXTEND
&& code1
== SIGN_EXTEND
))
6106 if (GET_MODE (x
) == HImode
)
6107 *total
= COSTS_N_INSNS (2);
6109 *total
= COSTS_N_INSNS (12);
6110 *total
+= rtx_cost (XEXP (op0
, 0), code0
, 0, speed
);
6111 *total
+= rtx_cost (XEXP (op1
, 0), code1
, 0, speed
);
6120 if (GET_MODE (x
) == DImode
)
6121 *total
= COSTS_N_INSNS (CONSTANT_P (XEXP (x
, 1)) ? 4 : 15);
6123 *total
= COSTS_N_INSNS (1);
6128 *total
= COSTS_N_INSNS (1);
6129 op0
= code
== PLUS
? XEXP (x
, 0) : XEXP (x
, 1);
6130 op1
= code
== PLUS
? XEXP (x
, 1) : XEXP (x
, 0);
6131 if (GET_MODE_SIZE (GET_MODE (x
)) <= UNITS_PER_WORD
6132 && INTEGRAL_MODE_P (GET_MODE (x
))
6133 && GET_CODE (op0
) == MULT
6134 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
6135 && (INTVAL (XEXP (op0
, 1)) == 2
6136 || INTVAL (XEXP (op0
, 1)) == 4
6137 || (code
== PLUS
&& INTVAL (XEXP (op0
, 1)) == 8)))
6139 *total
+= rtx_cost (XEXP (op0
, 0), ASHIFT
, 0, speed
);
6140 *total
+= rtx_cost (op1
, (enum rtx_code
) code
, 1, speed
);
6148 if (GET_MODE (x
) == DFmode
)
6151 *total
= COSTS_N_INSNS (speed
? 10 : 1);
6153 *total
= COSTS_N_INSNS (speed
? 200 : 4);
6155 else if (GET_MODE (x
) == SFmode
)
6158 *total
= COSTS_N_INSNS (speed
? 4 : 1);
6160 *total
= COSTS_N_INSNS (speed
? 100 : 4);
6162 else if (GET_MODE (x
) == DImode
)
6165 && GET_CODE (op0
) == GET_CODE (op1
)
6166 && (GET_CODE (op0
) == ZERO_EXTEND
6167 || GET_CODE (op0
) == SIGN_EXTEND
))
6169 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6170 op0
= XEXP (op0
, 0);
6171 op1
= XEXP (op1
, 0);
6174 /* Maybe improve this laster. */
6175 *total
= COSTS_N_INSNS (20);
6177 else if (GET_MODE (x
) == SImode
)
6179 if (((GET_CODE (op0
) == ZERO_EXTEND
6180 || GET_CODE (op0
) == SIGN_EXTEND
6181 || shift_p (op0
, LSHIFTRT
, 16))
6182 && (GET_CODE (op1
) == SIGN_EXTEND
6183 || GET_CODE (op1
) == ZERO_EXTEND
6184 || scst5_operand (op1
, SImode
)
6185 || shift_p (op1
, ASHIFTRT
, 16)
6186 || shift_p (op1
, LSHIFTRT
, 16)))
6187 || (shift_p (op0
, ASHIFTRT
, 16)
6188 && (GET_CODE (op1
) == SIGN_EXTEND
6189 || shift_p (op1
, ASHIFTRT
, 16))))
6191 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6192 op0
= XEXP (op0
, 0);
6193 if (scst5_operand (op1
, SImode
))
6196 op1
= XEXP (op1
, 0);
6199 *total
= COSTS_N_INSNS (1);
6200 else if (TARGET_MPY32
)
6201 *total
= COSTS_N_INSNS (4);
6203 *total
= COSTS_N_INSNS (6);
6205 else if (GET_MODE (x
) == HImode
)
6206 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6208 if (GET_CODE (op0
) != REG
6209 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
6210 *total
+= rtx_cost (op0
, MULT
, 0, speed
);
6211 if (op1
&& GET_CODE (op1
) != REG
6212 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
6213 *total
+= rtx_cost (op1
, MULT
, 1, speed
);
6218 /* This is a bit random; assuming on average there'll be 16 leading
6219 zeros. FIXME: estimate better for constant dividends. */
6220 *total
= COSTS_N_INSNS (6 + 3 * 16);
6224 /* Recognize the cmp_and/ior patterns. */
6226 if ((GET_CODE (op0
) == EQ
|| GET_CODE (op0
) == NE
)
6227 && REG_P (XEXP (op0
, 0))
6228 && XEXP (op0
, 1) == const0_rtx
6229 && rtx_equal_p (XEXP (x
, 1), XEXP (op0
, 0)))
6231 *total
= rtx_cost (XEXP (x
, 1), (enum rtx_code
) outer_code
,
6242 /* Implements target hook vector_mode_supported_p. */
6245 c6x_vector_mode_supported_p (machine_mode mode
)
6260 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6262 c6x_preferred_simd_mode (machine_mode mode
)
6276 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6279 c6x_scalar_mode_supported_p (machine_mode mode
)
6281 if (ALL_FIXED_POINT_MODE_P (mode
)
6282 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
6285 return default_scalar_mode_supported_p (mode
);
6288 /* Output a reference from a function exception table to the type_info
6289 object X. Output these via a special assembly directive. */
6292 c6x_output_ttype (rtx x
)
6294 /* Use special relocations for symbol references. */
6295 if (GET_CODE (x
) != CONST_INT
)
6296 fputs ("\t.ehtype\t", asm_out_file
);
6298 fputs ("\t.word\t", asm_out_file
);
6299 output_addr_const (asm_out_file
, x
);
6300 fputc ('\n', asm_out_file
);
6305 /* Modify the return address of the current function. */
6308 c6x_set_return_address (rtx source
, rtx scratch
)
6310 struct c6x_frame frame
;
6312 HOST_WIDE_INT offset
;
6314 c6x_compute_frame_layout (&frame
);
6315 if (! c6x_save_reg (RETURN_ADDR_REGNO
))
6316 emit_move_insn (gen_rtx_REG (Pmode
, RETURN_ADDR_REGNO
), source
);
6320 if (frame_pointer_needed
)
6322 addr
= hard_frame_pointer_rtx
;
6323 offset
= frame
.b3_offset
;
6327 addr
= stack_pointer_rtx
;
6328 offset
= frame
.to_allocate
- frame
.b3_offset
;
6331 /* TODO: Use base+offset loads where possible. */
6334 HOST_WIDE_INT low
= trunc_int_for_mode (offset
, HImode
);
6336 emit_insn (gen_movsi_high (scratch
, GEN_INT (low
)));
6338 emit_insn (gen_movsi_lo_sum (scratch
, scratch
, GEN_INT(offset
)));
6339 emit_insn (gen_addsi3 (scratch
, addr
, scratch
));
6343 emit_move_insn (gen_frame_mem (Pmode
, addr
), source
);
6347 /* We save pairs of registers using a DImode store. Describe the component
6348 registers for DWARF generation code. */
6351 c6x_dwarf_register_span (rtx rtl
)
6354 unsigned real_regno
;
6359 regno
= REGNO (rtl
);
6360 nregs
= HARD_REGNO_NREGS (regno
, GET_MODE (rtl
));
6364 p
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc(nregs
));
6365 for (i
= 0; i
< nregs
; i
++)
6367 if (TARGET_BIG_ENDIAN
)
6368 real_regno
= regno
+ nregs
- (i
+ 1);
6370 real_regno
= regno
+ i
;
6372 XVECEXP (p
, 0, i
) = gen_rtx_REG (SImode
, real_regno
);
6378 /* Codes for all the C6X builtins. */
6413 static GTY(()) tree c6x_builtin_decls
[C6X_BUILTIN_MAX
];
6415 /* Return the C6X builtin for CODE. */
6417 c6x_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
6419 if (code
>= C6X_BUILTIN_MAX
)
6420 return error_mark_node
;
6422 return c6x_builtin_decls
[code
];
6425 #define def_builtin(NAME, TYPE, CODE) \
6428 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6430 c6x_builtin_decls[CODE] = bdecl; \
6433 /* Set up all builtin functions for this target. */
6435 c6x_init_builtins (void)
6437 tree V4QI_type_node
= build_vector_type (unsigned_intQI_type_node
, 4);
6438 tree V2HI_type_node
= build_vector_type (intHI_type_node
, 2);
6439 tree V2SI_type_node
= build_vector_type (intSI_type_node
, 2);
6441 = build_function_type_list (integer_type_node
, integer_type_node
,
6443 tree int_ftype_int_int
6444 = build_function_type_list (integer_type_node
, integer_type_node
,
6445 integer_type_node
, NULL_TREE
);
6446 tree v2hi_ftype_v2hi
6447 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
6448 tree v4qi_ftype_v4qi_v4qi
6449 = build_function_type_list (V4QI_type_node
, V4QI_type_node
,
6450 V4QI_type_node
, NULL_TREE
);
6451 tree v2hi_ftype_v2hi_v2hi
6452 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
6453 V2HI_type_node
, NULL_TREE
);
6454 tree v2si_ftype_v2hi_v2hi
6455 = build_function_type_list (V2SI_type_node
, V2HI_type_node
,
6456 V2HI_type_node
, NULL_TREE
);
6458 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int
,
6460 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int
,
6462 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi
,
6464 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi
,
6466 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi
,
6468 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi
,
6470 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi
,
6472 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi
,
6474 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi
,
6476 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi
,
6477 C6X_BUILTIN_SADDU4
);
6478 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi
,
6481 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int
,
6483 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int
,
6485 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int
,
6486 C6X_BUILTIN_SMPYHL
);
6487 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int
,
6488 C6X_BUILTIN_SMPYLH
);
6490 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int
,
6492 def_builtin ("__builtin_c6x_subc", int_ftype_int_int
,
6495 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi
,
6497 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi
,
6500 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int
,
6502 def_builtin ("__builtin_c6x_extr", int_ftype_int_int
,
6504 def_builtin ("__builtin_c6x_extru", int_ftype_int_int
,
6507 def_builtin ("__builtin_c6x_abs", int_ftype_int
, C6X_BUILTIN_ABS
);
6508 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi
, C6X_BUILTIN_ABS2
);
6512 struct builtin_description
6514 const enum insn_code icode
;
6515 const char *const name
;
6516 const enum c6x_builtins code
;
6519 static const struct builtin_description bdesc_2arg
[] =
6521 { CODE_FOR_saddsi3
, "__builtin_c6x_sadd", C6X_BUILTIN_SADD
},
6522 { CODE_FOR_ssubsi3
, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB
},
6523 { CODE_FOR_addv2hi3
, "__builtin_c6x_add2", C6X_BUILTIN_ADD2
},
6524 { CODE_FOR_subv2hi3
, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2
},
6525 { CODE_FOR_addv4qi3
, "__builtin_c6x_add4", C6X_BUILTIN_ADD4
},
6526 { CODE_FOR_subv4qi3
, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4
},
6527 { CODE_FOR_ss_addv2hi3
, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2
},
6528 { CODE_FOR_ss_subv2hi3
, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2
},
6529 { CODE_FOR_us_addv4qi3
, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4
},
6531 { CODE_FOR_subcsi3
, "__builtin_c6x_subc", C6X_BUILTIN_SUBC
},
6532 { CODE_FOR_ss_ashlsi3
, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL
},
6534 { CODE_FOR_avgv2hi3
, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2
},
6535 { CODE_FOR_uavgv4qi3
, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4
},
6537 { CODE_FOR_mulhqsq3
, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY
},
6538 { CODE_FOR_mulhqsq3_hh
, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH
},
6539 { CODE_FOR_mulhqsq3_lh
, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH
},
6540 { CODE_FOR_mulhqsq3_hl
, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL
},
6542 { CODE_FOR_mulv2hqv2sq3
, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2
},
6544 { CODE_FOR_clrr
, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR
},
6545 { CODE_FOR_extr
, "__builtin_c6x_extr", C6X_BUILTIN_EXTR
},
6546 { CODE_FOR_extru
, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU
}
6549 static const struct builtin_description bdesc_1arg
[] =
6551 { CODE_FOR_ssabssi2
, "__builtin_c6x_abs", C6X_BUILTIN_ABS
},
6552 { CODE_FOR_ssabsv2hi2
, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2
}
6555 /* Errors in the source file can cause expand_expr to return const0_rtx
6556 where we expect a vector. To avoid crashing, use one of the vector
6557 clear instructions. */
6559 safe_vector_operand (rtx x
, machine_mode mode
)
6561 if (x
!= const0_rtx
)
6563 x
= gen_reg_rtx (SImode
);
6565 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
6566 return gen_lowpart (mode
, x
);
6569 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6570 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6573 c6x_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
6576 int offs
= match_op
? 1 : 0;
6578 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6579 tree arg1
= CALL_EXPR_ARG (exp
, 1);
6580 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6581 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6582 machine_mode op0mode
= GET_MODE (op0
);
6583 machine_mode op1mode
= GET_MODE (op1
);
6584 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6585 machine_mode mode0
= insn_data
[icode
].operand
[1 + offs
].mode
;
6586 machine_mode mode1
= insn_data
[icode
].operand
[2 + offs
].mode
;
6589 if (VECTOR_MODE_P (mode0
))
6590 op0
= safe_vector_operand (op0
, mode0
);
6591 if (VECTOR_MODE_P (mode1
))
6592 op1
= safe_vector_operand (op1
, mode1
);
6595 || GET_MODE (target
) != tmode
6596 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6598 if (tmode
== SQmode
|| tmode
== V2SQmode
)
6600 ret
= gen_reg_rtx (tmode
== SQmode
? SImode
: V2SImode
);
6601 target
= gen_lowpart (tmode
, ret
);
6604 target
= gen_reg_rtx (tmode
);
6607 if ((op0mode
== V2HImode
|| op0mode
== SImode
|| op0mode
== VOIDmode
)
6608 && (mode0
== V2HQmode
|| mode0
== HQmode
|| mode0
== SQmode
))
6611 op0
= gen_lowpart (mode0
, op0
);
6613 if ((op1mode
== V2HImode
|| op1mode
== SImode
|| op1mode
== VOIDmode
)
6614 && (mode1
== V2HQmode
|| mode1
== HQmode
|| mode1
== SQmode
))
6617 op1
= gen_lowpart (mode1
, op1
);
6619 /* In case the insn wants input operands in modes different from
6620 the result, abort. */
6621 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
6622 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
6624 if (! (*insn_data
[icode
].operand
[1 + offs
].predicate
) (op0
, mode0
))
6625 op0
= copy_to_mode_reg (mode0
, op0
);
6626 if (! (*insn_data
[icode
].operand
[2 + offs
].predicate
) (op1
, mode1
))
6627 op1
= copy_to_mode_reg (mode1
, op1
);
6630 pat
= GEN_FCN (icode
) (target
, target
, op0
, op1
);
6632 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
6642 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
6645 c6x_expand_unop_builtin (enum insn_code icode
, tree exp
,
6649 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6650 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6651 machine_mode op0mode
= GET_MODE (op0
);
6652 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6653 machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6656 || GET_MODE (target
) != tmode
6657 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6658 target
= gen_reg_rtx (tmode
);
6660 if (VECTOR_MODE_P (mode0
))
6661 op0
= safe_vector_operand (op0
, mode0
);
6663 if (op0mode
== SImode
&& mode0
== HImode
)
6666 op0
= gen_lowpart (HImode
, op0
);
6668 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
6670 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6671 op0
= copy_to_mode_reg (mode0
, op0
);
6673 pat
= GEN_FCN (icode
) (target
, op0
);
6680 /* Expand an expression EXP that calls a built-in function,
6681 with result going to TARGET if that's convenient
6682 (and in mode MODE if that's convenient).
6683 SUBTARGET may be used as the target for computing one of EXP's operands.
6684 IGNORE is nonzero if the value is to be ignored. */
6687 c6x_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
6688 rtx subtarget ATTRIBUTE_UNUSED
,
6689 machine_mode mode ATTRIBUTE_UNUSED
,
6690 int ignore ATTRIBUTE_UNUSED
)
6693 const struct builtin_description
*d
;
6694 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
6695 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
6697 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6698 if (d
->code
== fcode
)
6699 return c6x_expand_binop_builtin (d
->icode
, exp
, target
,
6700 fcode
== C6X_BUILTIN_CLRR
);
6702 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6703 if (d
->code
== fcode
)
6704 return c6x_expand_unop_builtin (d
->icode
, exp
, target
);
6709 /* Target unwind frame info is generated from dwarf CFI directives, so
6710 always output dwarf2 unwind info. */
6712 static enum unwind_info_type
6713 c6x_debug_unwind_info (void)
6715 if (flag_unwind_tables
|| flag_exceptions
)
6718 return default_debug_unwind_info ();
6721 /* Target Structure. */
6723 /* Initialize the GCC target structure. */
6724 #undef TARGET_FUNCTION_ARG
6725 #define TARGET_FUNCTION_ARG c6x_function_arg
6726 #undef TARGET_FUNCTION_ARG_ADVANCE
6727 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6728 #undef TARGET_FUNCTION_ARG_BOUNDARY
6729 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6730 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6731 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6732 c6x_function_arg_round_boundary
6733 #undef TARGET_FUNCTION_VALUE_REGNO_P
6734 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6735 #undef TARGET_FUNCTION_VALUE
6736 #define TARGET_FUNCTION_VALUE c6x_function_value
6737 #undef TARGET_LIBCALL_VALUE
6738 #define TARGET_LIBCALL_VALUE c6x_libcall_value
6739 #undef TARGET_RETURN_IN_MEMORY
6740 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6741 #undef TARGET_RETURN_IN_MSB
6742 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
6743 #undef TARGET_PASS_BY_REFERENCE
6744 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6745 #undef TARGET_CALLEE_COPIES
6746 #define TARGET_CALLEE_COPIES c6x_callee_copies
6747 #undef TARGET_STRUCT_VALUE_RTX
6748 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6749 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6750 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6752 #undef TARGET_ASM_OUTPUT_MI_THUNK
6753 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6754 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6755 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6757 #undef TARGET_BUILD_BUILTIN_VA_LIST
6758 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6760 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6761 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6762 #undef TARGET_TRAMPOLINE_INIT
6763 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6765 #undef TARGET_LEGITIMATE_CONSTANT_P
6766 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6767 #undef TARGET_LEGITIMATE_ADDRESS_P
6768 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6770 #undef TARGET_IN_SMALL_DATA_P
6771 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6772 #undef TARGET_ASM_SELECT_RTX_SECTION
6773 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6774 #undef TARGET_ASM_SELECT_SECTION
6775 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6776 #undef TARGET_ASM_UNIQUE_SECTION
6777 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6778 #undef TARGET_SECTION_TYPE_FLAGS
6779 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6780 #undef TARGET_HAVE_SRODATA_SECTION
6781 #define TARGET_HAVE_SRODATA_SECTION true
6782 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6783 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6785 #undef TARGET_OPTION_OVERRIDE
6786 #define TARGET_OPTION_OVERRIDE c6x_option_override
6787 #undef TARGET_CONDITIONAL_REGISTER_USAGE
6788 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6790 #undef TARGET_INIT_LIBFUNCS
6791 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6792 #undef TARGET_LIBFUNC_GNU_PREFIX
6793 #define TARGET_LIBFUNC_GNU_PREFIX true
6795 #undef TARGET_SCALAR_MODE_SUPPORTED_P
6796 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6797 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6798 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6799 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6800 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6802 #undef TARGET_RTX_COSTS
6803 #define TARGET_RTX_COSTS c6x_rtx_costs
6805 #undef TARGET_SCHED_INIT
6806 #define TARGET_SCHED_INIT c6x_sched_init
6807 #undef TARGET_SCHED_SET_SCHED_FLAGS
6808 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6809 #undef TARGET_SCHED_ADJUST_COST
6810 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6811 #undef TARGET_SCHED_ISSUE_RATE
6812 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6813 #undef TARGET_SCHED_VARIABLE_ISSUE
6814 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6815 #undef TARGET_SCHED_REORDER
6816 #define TARGET_SCHED_REORDER c6x_sched_reorder
6817 #undef TARGET_SCHED_REORDER2
6818 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6819 #undef TARGET_SCHED_DFA_NEW_CYCLE
6820 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6821 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6822 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6823 #undef TARGET_SCHED_EXPOSED_PIPELINE
6824 #define TARGET_SCHED_EXPOSED_PIPELINE true
6826 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6827 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6828 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
6829 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6830 #undef TARGET_SCHED_SET_SCHED_CONTEXT
6831 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6832 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6833 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6834 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
6835 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6837 #undef TARGET_CAN_ELIMINATE
6838 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
6840 #undef TARGET_PREFERRED_RENAME_CLASS
6841 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6843 #undef TARGET_MACHINE_DEPENDENT_REORG
6844 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6846 #undef TARGET_ASM_FILE_START
6847 #define TARGET_ASM_FILE_START c6x_file_start
6849 #undef TARGET_PRINT_OPERAND
6850 #define TARGET_PRINT_OPERAND c6x_print_operand
6851 #undef TARGET_PRINT_OPERAND_ADDRESS
6852 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6853 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6854 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6856 /* C6x unwinding tables use a different format for the typeinfo tables. */
6857 #undef TARGET_ASM_TTYPE
6858 #define TARGET_ASM_TTYPE c6x_output_ttype
6860 /* The C6x ABI follows the ARM EABI exception handling rules. */
6861 #undef TARGET_ARM_EABI_UNWINDER
6862 #define TARGET_ARM_EABI_UNWINDER true
6864 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6865 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6867 #undef TARGET_ASM_INIT_SECTIONS
6868 #define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6870 #undef TARGET_DEBUG_UNWIND_INFO
6871 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6873 #undef TARGET_DWARF_REGISTER_SPAN
6874 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6876 #undef TARGET_INIT_BUILTINS
6877 #define TARGET_INIT_BUILTINS c6x_init_builtins
6878 #undef TARGET_EXPAND_BUILTIN
6879 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6880 #undef TARGET_BUILTIN_DECL
6881 #define TARGET_BUILTIN_DECL c6x_builtin_decl
6883 struct gcc_target targetm
= TARGET_INITIALIZER
;