1 /* Target Code for TI C6X
2 Copyright (C) 2010-2014 Free Software Foundation, Inc.
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "stor-layout.h"
31 #include "stringpool.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
35 #include "insn-codes.h"
41 #include "sched-int.h"
45 #include "tm-constrs.h"
51 #include "hard-reg-set.h"
54 #include "diagnostic-core.h"
56 #include "langhooks.h"
58 #include "target-def.h"
59 #include "sel-sched.h"
62 #include "hw-doloop.h"
63 #include "regrename.h"
65 #include "gimple-expr.h"
68 /* Table of supported architecture variants. */
72 enum c6x_cpu_type type
;
73 unsigned short features
;
76 /* A list of all ISAs, mapping each one to a representative device.
77 Used for -march selection. */
78 static const c6x_arch_table all_isas
[] =
80 #define C6X_ISA(NAME,DEVICE,FLAGS) \
81 { NAME, DEVICE, FLAGS },
82 #include "c6x-isas.def"
84 { NULL
, C6X_CPU_C62X
, 0 }
87 /* This is the parsed result of the "-march=" option, if given. */
88 enum c6x_cpu_type c6x_arch
= C6X_DEFAULT_ARCH
;
90 /* A mask of insn types that are allowed by the architecture selected by
92 unsigned long c6x_insn_mask
= C6X_DEFAULT_INSN_MASK
;
94 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
96 static rtx_insn
*c6x_current_insn
= NULL
;
98 /* A decl we build to access __c6xabi_DSBT_base. */
99 static GTY(()) tree dsbt_decl
;
101 /* Determines whether we run our final scheduling pass or not. We always
102 avoid the normal second scheduling pass. */
103 static int c6x_flag_schedule_insns2
;
105 /* Determines whether we run variable tracking in machine dependent
107 static int c6x_flag_var_tracking
;
109 /* Determines whether we use modulo scheduling. */
110 static int c6x_flag_modulo_sched
;
112 /* Record the state of flag_pic before we set it to 1 for DSBT. */
113 int c6x_initial_flag_pic
;
117 /* We record the clock cycle for every insn during scheduling. */
119 /* After scheduling, we run assign_reservations to choose unit
120 reservations for all insns. These are recorded here. */
122 /* Records the new condition for insns which must be made
123 conditional after scheduling. An entry of NULL_RTX means no such
124 change is necessary. */
126 /* True for the first insn that was scheduled in an ebb. */
128 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
129 bits rather than storing the state. Meaningful only for the last
131 unsigned int unit_mask
;
132 } c6x_sched_insn_info
;
135 /* Record a c6x_sched_insn_info structure for every insn in the function. */
136 static vec
<c6x_sched_insn_info
> insn_info
;
138 #define INSN_INFO_LENGTH (insn_info).length ()
139 #define INSN_INFO_ENTRY(N) (insn_info[(N)])
141 static bool done_cfi_sections
;
143 #define RESERVATION_FLAG_D 1
144 #define RESERVATION_FLAG_L 2
145 #define RESERVATION_FLAG_S 4
146 #define RESERVATION_FLAG_M 8
147 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
148 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
149 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
150 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
152 /* The DFA names of the units. */
153 static const char *const c6x_unit_names
[] =
155 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
156 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
159 /* The DFA unit number for each unit in c6x_unit_names[]. */
160 static int c6x_unit_codes
[ARRAY_SIZE (c6x_unit_names
)];
162 /* Unit query IDs. */
163 #define UNIT_QID_D1 0
164 #define UNIT_QID_L1 1
165 #define UNIT_QID_S1 2
166 #define UNIT_QID_M1 3
167 #define UNIT_QID_FPS1 4
168 #define UNIT_QID_FPL1 5
169 #define UNIT_QID_ADDDPS1 6
170 #define UNIT_QID_ADDDPL1 7
171 #define UNIT_QID_SIDE_OFFSET 8
173 #define RESERVATION_S1 2
174 #define RESERVATION_S2 10
176 /* An enum for the unit requirements we count in the UNIT_REQS table. */
192 /* A table used to count unit requirements. Used when computing minimum
193 iteration intervals. */
194 typedef int unit_req_table
[2][UNIT_REQ_MAX
];
195 static unit_req_table unit_reqs
;
197 /* Register map for debugging. */
198 unsigned const dbx_register_map
[FIRST_PSEUDO_REGISTER
] =
200 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
201 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
203 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
205 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
207 -1, -1, -1 /* FP, ARGP, ILC. */
210 /* Allocate a new, cleared machine_function structure. */
212 static struct machine_function
*
213 c6x_init_machine_status (void)
215 return ggc_cleared_alloc
<machine_function
> ();
218 /* Implement TARGET_OPTION_OVERRIDE. */
221 c6x_option_override (void)
225 if (global_options_set
.x_c6x_arch_option
)
227 c6x_arch
= all_isas
[c6x_arch_option
].type
;
228 c6x_insn_mask
&= ~C6X_INSNS_ALL_CPU_BITS
;
229 c6x_insn_mask
|= all_isas
[c6x_arch_option
].features
;
232 c6x_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
233 flag_schedule_insns_after_reload
= 0;
235 c6x_flag_modulo_sched
= flag_modulo_sched
;
236 flag_modulo_sched
= 0;
238 init_machine_status
= c6x_init_machine_status
;
240 for (i
= 0; i
< ARRAY_SIZE (c6x_unit_names
); i
++)
241 c6x_unit_codes
[i
] = get_cpu_unit_code (c6x_unit_names
[i
]);
243 if (flag_pic
&& !TARGET_DSBT
)
245 error ("-fpic and -fPIC not supported without -mdsbt on this target");
248 c6x_initial_flag_pic
= flag_pic
;
249 if (TARGET_DSBT
&& !flag_pic
)
254 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
257 c6x_conditional_register_usage (void)
260 if (c6x_arch
== C6X_CPU_C62X
|| c6x_arch
== C6X_CPU_C67X
)
261 for (i
= 16; i
< 32; i
++)
264 fixed_regs
[32 + i
] = 1;
268 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_A_REGS
],
270 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_REGS
],
272 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_A_REGS
],
274 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_REGS
],
279 static GTY(()) rtx eqdf_libfunc
;
280 static GTY(()) rtx nedf_libfunc
;
281 static GTY(()) rtx ledf_libfunc
;
282 static GTY(()) rtx ltdf_libfunc
;
283 static GTY(()) rtx gedf_libfunc
;
284 static GTY(()) rtx gtdf_libfunc
;
285 static GTY(()) rtx eqsf_libfunc
;
286 static GTY(()) rtx nesf_libfunc
;
287 static GTY(()) rtx lesf_libfunc
;
288 static GTY(()) rtx ltsf_libfunc
;
289 static GTY(()) rtx gesf_libfunc
;
290 static GTY(()) rtx gtsf_libfunc
;
291 static GTY(()) rtx strasgi_libfunc
;
292 static GTY(()) rtx strasgi64p_libfunc
;
294 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
295 functions to match the C6x ABI. */
298 c6x_init_libfuncs (void)
300 /* Double-precision floating-point arithmetic. */
301 set_optab_libfunc (add_optab
, DFmode
, "__c6xabi_addd");
302 set_optab_libfunc (sdiv_optab
, DFmode
, "__c6xabi_divd");
303 set_optab_libfunc (smul_optab
, DFmode
, "__c6xabi_mpyd");
304 set_optab_libfunc (neg_optab
, DFmode
, "__c6xabi_negd");
305 set_optab_libfunc (sub_optab
, DFmode
, "__c6xabi_subd");
307 /* Single-precision floating-point arithmetic. */
308 set_optab_libfunc (add_optab
, SFmode
, "__c6xabi_addf");
309 set_optab_libfunc (sdiv_optab
, SFmode
, "__c6xabi_divf");
310 set_optab_libfunc (smul_optab
, SFmode
, "__c6xabi_mpyf");
311 set_optab_libfunc (neg_optab
, SFmode
, "__c6xabi_negf");
312 set_optab_libfunc (sub_optab
, SFmode
, "__c6xabi_subf");
314 /* Floating-point comparisons. */
315 eqsf_libfunc
= init_one_libfunc ("__c6xabi_eqf");
316 nesf_libfunc
= init_one_libfunc ("__c6xabi_neqf");
317 lesf_libfunc
= init_one_libfunc ("__c6xabi_lef");
318 ltsf_libfunc
= init_one_libfunc ("__c6xabi_ltf");
319 gesf_libfunc
= init_one_libfunc ("__c6xabi_gef");
320 gtsf_libfunc
= init_one_libfunc ("__c6xabi_gtf");
321 eqdf_libfunc
= init_one_libfunc ("__c6xabi_eqd");
322 nedf_libfunc
= init_one_libfunc ("__c6xabi_neqd");
323 ledf_libfunc
= init_one_libfunc ("__c6xabi_led");
324 ltdf_libfunc
= init_one_libfunc ("__c6xabi_ltd");
325 gedf_libfunc
= init_one_libfunc ("__c6xabi_ged");
326 gtdf_libfunc
= init_one_libfunc ("__c6xabi_gtd");
328 set_optab_libfunc (eq_optab
, SFmode
, NULL
);
329 set_optab_libfunc (ne_optab
, SFmode
, "__c6xabi_neqf");
330 set_optab_libfunc (gt_optab
, SFmode
, NULL
);
331 set_optab_libfunc (ge_optab
, SFmode
, NULL
);
332 set_optab_libfunc (lt_optab
, SFmode
, NULL
);
333 set_optab_libfunc (le_optab
, SFmode
, NULL
);
334 set_optab_libfunc (unord_optab
, SFmode
, "__c6xabi_unordf");
335 set_optab_libfunc (eq_optab
, DFmode
, NULL
);
336 set_optab_libfunc (ne_optab
, DFmode
, "__c6xabi_neqd");
337 set_optab_libfunc (gt_optab
, DFmode
, NULL
);
338 set_optab_libfunc (ge_optab
, DFmode
, NULL
);
339 set_optab_libfunc (lt_optab
, DFmode
, NULL
);
340 set_optab_libfunc (le_optab
, DFmode
, NULL
);
341 set_optab_libfunc (unord_optab
, DFmode
, "__c6xabi_unordd");
343 /* Floating-point to integer conversions. */
344 set_conv_libfunc (sfix_optab
, SImode
, DFmode
, "__c6xabi_fixdi");
345 set_conv_libfunc (ufix_optab
, SImode
, DFmode
, "__c6xabi_fixdu");
346 set_conv_libfunc (sfix_optab
, DImode
, DFmode
, "__c6xabi_fixdlli");
347 set_conv_libfunc (ufix_optab
, DImode
, DFmode
, "__c6xabi_fixdull");
348 set_conv_libfunc (sfix_optab
, SImode
, SFmode
, "__c6xabi_fixfi");
349 set_conv_libfunc (ufix_optab
, SImode
, SFmode
, "__c6xabi_fixfu");
350 set_conv_libfunc (sfix_optab
, DImode
, SFmode
, "__c6xabi_fixflli");
351 set_conv_libfunc (ufix_optab
, DImode
, SFmode
, "__c6xabi_fixfull");
353 /* Conversions between floating types. */
354 set_conv_libfunc (trunc_optab
, SFmode
, DFmode
, "__c6xabi_cvtdf");
355 set_conv_libfunc (sext_optab
, DFmode
, SFmode
, "__c6xabi_cvtfd");
357 /* Integer to floating-point conversions. */
358 set_conv_libfunc (sfloat_optab
, DFmode
, SImode
, "__c6xabi_fltid");
359 set_conv_libfunc (ufloat_optab
, DFmode
, SImode
, "__c6xabi_fltud");
360 set_conv_libfunc (sfloat_optab
, DFmode
, DImode
, "__c6xabi_fltllid");
361 set_conv_libfunc (ufloat_optab
, DFmode
, DImode
, "__c6xabi_fltulld");
362 set_conv_libfunc (sfloat_optab
, SFmode
, SImode
, "__c6xabi_fltif");
363 set_conv_libfunc (ufloat_optab
, SFmode
, SImode
, "__c6xabi_fltuf");
364 set_conv_libfunc (sfloat_optab
, SFmode
, DImode
, "__c6xabi_fltllif");
365 set_conv_libfunc (ufloat_optab
, SFmode
, DImode
, "__c6xabi_fltullf");
368 set_optab_libfunc (smul_optab
, DImode
, "__c6xabi_mpyll");
369 set_optab_libfunc (ashl_optab
, DImode
, "__c6xabi_llshl");
370 set_optab_libfunc (lshr_optab
, DImode
, "__c6xabi_llshru");
371 set_optab_libfunc (ashr_optab
, DImode
, "__c6xabi_llshr");
373 set_optab_libfunc (sdiv_optab
, SImode
, "__c6xabi_divi");
374 set_optab_libfunc (udiv_optab
, SImode
, "__c6xabi_divu");
375 set_optab_libfunc (smod_optab
, SImode
, "__c6xabi_remi");
376 set_optab_libfunc (umod_optab
, SImode
, "__c6xabi_remu");
377 set_optab_libfunc (sdivmod_optab
, SImode
, "__c6xabi_divremi");
378 set_optab_libfunc (udivmod_optab
, SImode
, "__c6xabi_divremu");
379 set_optab_libfunc (sdiv_optab
, DImode
, "__c6xabi_divlli");
380 set_optab_libfunc (udiv_optab
, DImode
, "__c6xabi_divull");
381 set_optab_libfunc (smod_optab
, DImode
, "__c6xabi_remlli");
382 set_optab_libfunc (umod_optab
, DImode
, "__c6xabi_remull");
383 set_optab_libfunc (udivmod_optab
, DImode
, "__c6xabi_divremull");
386 strasgi_libfunc
= init_one_libfunc ("__c6xabi_strasgi");
387 strasgi64p_libfunc
= init_one_libfunc ("__c6xabi_strasgi_64plus");
390 /* Begin the assembly file. */
393 c6x_file_start (void)
395 /* Variable tracking should be run after all optimizations which change order
396 of insns. It also needs a valid CFG. This can't be done in
397 c6x_override_options, because flag_var_tracking is finalized after
399 c6x_flag_var_tracking
= flag_var_tracking
;
400 flag_var_tracking
= 0;
402 done_cfi_sections
= false;
403 default_file_start ();
405 /* Arrays are aligned to 8-byte boundaries. */
406 asm_fprintf (asm_out_file
,
407 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
408 asm_fprintf (asm_out_file
,
409 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
411 /* Stack alignment is 8 bytes. */
412 asm_fprintf (asm_out_file
,
413 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
414 asm_fprintf (asm_out_file
,
415 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
417 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
418 /* ??? Ideally we'd check flag_short_wchar somehow. */
419 asm_fprintf (asm_out_file
, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
422 /* We conform to version 1.0 of the ABI. */
423 asm_fprintf (asm_out_file
,
424 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
428 /* The LTO frontend only enables exceptions when it sees a function that
429 uses it. This changes the return value of dwarf2out_do_frame, so we
430 have to check before every function. */
433 c6x_output_file_unwind (FILE * f
)
435 if (done_cfi_sections
)
438 /* Output a .cfi_sections directive. */
439 if (dwarf2out_do_frame ())
441 if (flag_unwind_tables
|| flag_exceptions
)
443 if (write_symbols
== DWARF2_DEBUG
444 || write_symbols
== VMS_AND_DWARF2_DEBUG
)
445 asm_fprintf (f
, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
447 asm_fprintf (f
, "\t.cfi_sections .c6xabi.exidx\n");
450 asm_fprintf (f
, "\t.cfi_sections .debug_frame\n");
451 done_cfi_sections
= true;
455 /* Output unwind directives at the end of a function. */
458 c6x_output_fn_unwind (FILE * f
)
460 /* Return immediately if we are not generating unwinding tables. */
461 if (! (flag_unwind_tables
|| flag_exceptions
))
464 /* If this function will never be unwound, then mark it as such. */
465 if (!(flag_unwind_tables
|| crtl
->uses_eh_lsda
)
466 && (TREE_NOTHROW (current_function_decl
)
467 || crtl
->all_throwers_are_sibcalls
))
468 fputs("\t.cantunwind\n", f
);
470 fputs ("\t.endp\n", f
);
474 /* Stack and Calling. */
476 int argument_registers
[10] =
485 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
488 c6x_init_cumulative_args (CUMULATIVE_ARGS
*cum
, const_tree fntype
, rtx libname
,
489 int n_named_args ATTRIBUTE_UNUSED
)
493 if (!libname
&& fntype
)
495 /* We need to find out the number of named arguments. Unfortunately,
496 for incoming arguments, N_NAMED_ARGS is set to -1. */
497 if (stdarg_p (fntype
))
498 cum
->nregs
= type_num_arguments (fntype
) - 1;
504 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
507 c6x_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
508 const_tree type
, bool named ATTRIBUTE_UNUSED
)
510 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
511 if (cum
->count
>= cum
->nregs
)
515 HOST_WIDE_INT size
= int_size_in_bytes (type
);
516 if (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (type
))
520 rtx reg1
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
] + 1);
521 rtx reg2
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
]);
522 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
523 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
524 return gen_rtx_PARALLEL (mode
, vec
);
528 return gen_rtx_REG (mode
, argument_registers
[cum
->count
]);
532 c6x_function_arg_advance (cumulative_args_t cum_v
,
533 enum machine_mode mode ATTRIBUTE_UNUSED
,
534 const_tree type ATTRIBUTE_UNUSED
,
535 bool named ATTRIBUTE_UNUSED
)
537 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
542 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
543 upward rather than downward. */
546 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED
,
547 const_tree type
, bool first
)
551 if (!TARGET_BIG_ENDIAN
)
557 size
= int_size_in_bytes (type
);
561 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
564 c6x_function_arg_boundary (enum machine_mode mode
, const_tree type
)
566 unsigned int boundary
= type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
);
568 if (boundary
> BITS_PER_WORD
)
569 return 2 * BITS_PER_WORD
;
573 HOST_WIDE_INT size
= int_size_in_bytes (type
);
575 return 2 * BITS_PER_WORD
;
576 if (boundary
< BITS_PER_WORD
)
579 return BITS_PER_WORD
;
581 return 2 * BITS_PER_UNIT
;
587 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
589 c6x_function_arg_round_boundary (enum machine_mode mode
, const_tree type
)
591 return c6x_function_arg_boundary (mode
, type
);
594 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
595 where function FUNC returns or receives a value of data type TYPE. */
598 c6x_function_value (const_tree type
, const_tree func ATTRIBUTE_UNUSED
,
599 bool outgoing ATTRIBUTE_UNUSED
)
601 /* Functions return values in register A4. When returning aggregates, we may
602 have to adjust for endianness. */
603 if (TARGET_BIG_ENDIAN
&& type
&& AGGREGATE_TYPE_P (type
))
605 HOST_WIDE_INT size
= int_size_in_bytes (type
);
609 rtx reg1
= gen_rtx_REG (SImode
, REG_A4
+ 1);
610 rtx reg2
= gen_rtx_REG (SImode
, REG_A4
);
611 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
612 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
613 return gen_rtx_PARALLEL (TYPE_MODE (type
), vec
);
616 return gen_rtx_REG (TYPE_MODE (type
), REG_A4
);
619 /* Implement TARGET_LIBCALL_VALUE. */
622 c6x_libcall_value (enum machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
624 return gen_rtx_REG (mode
, REG_A4
);
627 /* TARGET_STRUCT_VALUE_RTX implementation. */
630 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED
, int incoming ATTRIBUTE_UNUSED
)
632 return gen_rtx_REG (Pmode
, REG_A3
);
635 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
638 c6x_function_value_regno_p (const unsigned int regno
)
640 return regno
== REG_A4
;
643 /* Types larger than 64 bit, and variable sized types, are passed by
644 reference. The callee must copy them; see c6x_callee_copies. */
647 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
648 enum machine_mode mode
, const_tree type
,
649 bool named ATTRIBUTE_UNUSED
)
653 size
= int_size_in_bytes (type
);
654 else if (mode
!= VOIDmode
)
655 size
= GET_MODE_SIZE (mode
);
656 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
659 /* Decide whether a type should be returned in memory (true)
660 or in a register (false). This is called by the macro
661 TARGET_RETURN_IN_MEMORY. */
664 c6x_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
666 int size
= int_size_in_bytes (type
);
667 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
670 /* Values which must be returned in the most-significant end of the return
674 c6x_return_in_msb (const_tree valtype
)
676 HOST_WIDE_INT size
= int_size_in_bytes (valtype
);
677 return TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
) && size
== 3;
680 /* Implement TARGET_CALLEE_COPIES. */
683 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
684 enum machine_mode mode ATTRIBUTE_UNUSED
,
685 const_tree type ATTRIBUTE_UNUSED
,
686 bool named ATTRIBUTE_UNUSED
)
691 /* Return the type to use as __builtin_va_list. */
693 c6x_build_builtin_va_list (void)
695 return build_pointer_type (char_type_node
);
699 c6x_asm_trampoline_template (FILE *f
)
701 fprintf (f
, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
702 fprintf (f
, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
703 fprintf (f
, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
704 fprintf (f
, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
705 fprintf (f
, "\t.long\t0x00000362\n"); /* b .s2 B0 */
706 fprintf (f
, "\t.long\t0x00008000\n"); /* nop 5 */
707 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
708 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
711 /* Emit RTL insns to initialize the variable parts of a trampoline at
712 TRAMP. FNADDR is an RTX for the address of the function's pure
713 code. CXT is an RTX for the static chain value for the function. */
716 c6x_initialize_trampoline (rtx tramp
, tree fndecl
, rtx cxt
)
718 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
719 rtx t1
= copy_to_reg (fnaddr
);
720 rtx t2
= copy_to_reg (cxt
);
721 rtx mask
= gen_reg_rtx (SImode
);
724 emit_block_move (tramp
, assemble_trampoline_template (),
725 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
727 emit_move_insn (mask
, GEN_INT (0xffff << 7));
729 for (i
= 0; i
< 4; i
++)
731 rtx mem
= adjust_address (tramp
, SImode
, i
* 4);
732 rtx t
= (i
& 1) ? t2
: t1
;
733 rtx v1
= gen_reg_rtx (SImode
);
734 rtx v2
= gen_reg_rtx (SImode
);
735 emit_move_insn (v1
, mem
);
737 emit_insn (gen_ashlsi3 (v2
, t
, GEN_INT (7)));
739 emit_insn (gen_lshrsi3 (v2
, t
, GEN_INT (9)));
740 emit_insn (gen_andsi3 (v2
, v2
, mask
));
741 emit_insn (gen_iorsi3 (v2
, v2
, v1
));
742 emit_move_insn (mem
, v2
);
744 #ifdef CLEAR_INSN_CACHE
745 tramp
= XEXP (tramp
, 0);
746 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__gnu_clear_cache"),
747 LCT_NORMAL
, VOIDmode
, 2, tramp
, Pmode
,
748 plus_constant (Pmode
, tramp
, TRAMPOLINE_SIZE
),
753 /* Determine whether c6x_output_mi_thunk can succeed. */
756 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED
,
757 HOST_WIDE_INT delta ATTRIBUTE_UNUSED
,
758 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED
,
759 const_tree function ATTRIBUTE_UNUSED
)
761 return !TARGET_LONG_CALLS
;
764 /* Output the assembler code for a thunk function. THUNK is the
765 declaration for the thunk function itself, FUNCTION is the decl for
766 the target function. DELTA is an immediate constant offset to be
767 added to THIS. If VCALL_OFFSET is nonzero, the word at
768 *(*this + vcall_offset) should be added to THIS. */
771 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
772 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
773 HOST_WIDE_INT vcall_offset
, tree function
)
776 /* The this parameter is passed as the first argument. */
777 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_A4
);
779 c6x_current_insn
= NULL
;
781 xops
[4] = XEXP (DECL_RTL (function
), 0);
784 output_asm_insn ("b .s2 \t%4", xops
);
786 output_asm_insn ("nop 5", xops
);
789 /* Adjust the this parameter by a fixed constant. */
792 xops
[0] = GEN_INT (delta
);
794 if (delta
>= -16 && delta
<= 15)
796 output_asm_insn ("add .s1 %0, %1, %1", xops
);
798 output_asm_insn ("nop 4", xops
);
800 else if (delta
>= 16 && delta
< 32)
802 output_asm_insn ("add .d1 %0, %1, %1", xops
);
804 output_asm_insn ("nop 4", xops
);
806 else if (delta
>= -32768 && delta
< 32768)
808 output_asm_insn ("mvk .s1 %0, A0", xops
);
809 output_asm_insn ("add .d1 %1, A0, %1", xops
);
811 output_asm_insn ("nop 3", xops
);
815 output_asm_insn ("mvkl .s1 %0, A0", xops
);
816 output_asm_insn ("mvkh .s1 %0, A0", xops
);
817 output_asm_insn ("add .d1 %1, A0, %1", xops
);
819 output_asm_insn ("nop 3", xops
);
823 /* Adjust the this parameter by a value stored in the vtable. */
826 rtx a0tmp
= gen_rtx_REG (Pmode
, REG_A0
);
827 rtx a3tmp
= gen_rtx_REG (Pmode
, REG_A3
);
831 xops
[3] = gen_rtx_MEM (Pmode
, a0tmp
);
832 output_asm_insn ("mv .s1 a4, %2", xops
);
833 output_asm_insn ("ldw .d1t1 %3, %2", xops
);
835 /* Adjust the this parameter. */
836 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (Pmode
, a0tmp
,
838 if (!memory_operand (xops
[0], Pmode
))
840 rtx tmp2
= gen_rtx_REG (Pmode
, REG_A1
);
841 xops
[0] = GEN_INT (vcall_offset
);
843 output_asm_insn ("mvkl .s1 %0, %1", xops
);
844 output_asm_insn ("mvkh .s1 %0, %1", xops
);
845 output_asm_insn ("nop 2", xops
);
846 output_asm_insn ("add .d1 %2, %1, %2", xops
);
847 xops
[0] = gen_rtx_MEM (Pmode
, a0tmp
);
850 output_asm_insn ("nop 4", xops
);
852 output_asm_insn ("ldw .d1t1 %0, %1", xops
);
853 output_asm_insn ("|| b .s2 \t%4", xops
);
854 output_asm_insn ("nop 4", xops
);
855 output_asm_insn ("add .d1 %2, %1, %2", xops
);
859 /* Return true if EXP goes in small data/bss. */
862 c6x_in_small_data_p (const_tree exp
)
864 /* We want to merge strings, so we never consider them small data. */
865 if (TREE_CODE (exp
) == STRING_CST
)
868 /* Functions are never small data. */
869 if (TREE_CODE (exp
) == FUNCTION_DECL
)
872 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_WEAK (exp
))
875 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_SECTION_NAME (exp
))
877 const char *section
= DECL_SECTION_NAME (exp
);
879 if (strcmp (section
, ".neardata") == 0
880 || strncmp (section
, ".neardata.", 10) == 0
881 || strncmp (section
, ".gnu.linkonce.s.", 16) == 0
882 || strcmp (section
, ".bss") == 0
883 || strncmp (section
, ".bss.", 5) == 0
884 || strncmp (section
, ".gnu.linkonce.sb.", 17) == 0
885 || strcmp (section
, ".rodata") == 0
886 || strncmp (section
, ".rodata.", 8) == 0
887 || strncmp (section
, ".gnu.linkonce.s2.", 17) == 0)
891 return PLACE_IN_SDATA_P (exp
);
896 /* Return a section for X. The only special thing we do here is to
897 honor small data. We don't have a tree type, so we can't use the
898 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
899 everything sized 8 bytes or smaller into small data. */
902 c6x_select_rtx_section (enum machine_mode mode
, rtx x
,
903 unsigned HOST_WIDE_INT align
)
905 if (c6x_sdata_mode
== C6X_SDATA_ALL
906 || (c6x_sdata_mode
!= C6X_SDATA_NONE
&& GET_MODE_SIZE (mode
) <= 8))
907 /* ??? Consider using mergeable sdata sections. */
908 return sdata_section
;
910 return default_elf_select_rtx_section (mode
, x
, align
);
914 c6x_elf_select_section (tree decl
, int reloc
,
915 unsigned HOST_WIDE_INT align
)
917 const char *sname
= NULL
;
918 unsigned int flags
= SECTION_WRITE
;
919 if (c6x_in_small_data_p (decl
))
921 switch (categorize_decl_for_section (decl
, reloc
))
932 flags
|= SECTION_BSS
;
939 switch (categorize_decl_for_section (decl
, reloc
))
944 case SECCAT_DATA_REL
:
945 sname
= ".fardata.rel";
947 case SECCAT_DATA_REL_LOCAL
:
948 sname
= ".fardata.rel.local";
950 case SECCAT_DATA_REL_RO
:
951 sname
= ".fardata.rel.ro";
953 case SECCAT_DATA_REL_RO_LOCAL
:
954 sname
= ".fardata.rel.ro.local";
958 flags
|= SECTION_BSS
;
974 /* We might get called with string constants, but get_named_section
975 doesn't like them as they are not DECLs. Also, we need to set
976 flags in that case. */
978 return get_section (sname
, flags
, NULL
);
979 return get_named_section (decl
, sname
, reloc
);
982 return default_elf_select_section (decl
, reloc
, align
);
985 /* Build up a unique section name, expressed as a
986 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
987 RELOC indicates whether the initial value of EXP requires
988 link-time relocations. */
990 static void ATTRIBUTE_UNUSED
991 c6x_elf_unique_section (tree decl
, int reloc
)
993 const char *prefix
= NULL
;
994 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
995 bool one_only
= DECL_COMDAT_GROUP (decl
) && !HAVE_COMDAT_GROUP
;
997 if (c6x_in_small_data_p (decl
))
999 switch (categorize_decl_for_section (decl
, reloc
))
1002 prefix
= one_only
? ".s" : ".neardata";
1005 prefix
= one_only
? ".sb" : ".bss";
1007 case SECCAT_SRODATA
:
1008 prefix
= one_only
? ".s2" : ".rodata";
1010 case SECCAT_RODATA_MERGE_STR
:
1011 case SECCAT_RODATA_MERGE_STR_INIT
:
1012 case SECCAT_RODATA_MERGE_CONST
:
1015 case SECCAT_DATA_REL
:
1016 case SECCAT_DATA_REL_LOCAL
:
1017 case SECCAT_DATA_REL_RO
:
1018 case SECCAT_DATA_REL_RO_LOCAL
:
1021 /* Everything else we place into default sections and hope for the
1028 switch (categorize_decl_for_section (decl
, reloc
))
1031 case SECCAT_DATA_REL
:
1032 case SECCAT_DATA_REL_LOCAL
:
1033 case SECCAT_DATA_REL_RO
:
1034 case SECCAT_DATA_REL_RO_LOCAL
:
1035 prefix
= one_only
? ".fd" : ".fardata";
1038 prefix
= one_only
? ".fb" : ".far";
1041 case SECCAT_RODATA_MERGE_STR
:
1042 case SECCAT_RODATA_MERGE_STR_INIT
:
1043 case SECCAT_RODATA_MERGE_CONST
:
1044 prefix
= one_only
? ".fr" : ".const";
1046 case SECCAT_SRODATA
:
1057 const char *name
, *linkonce
;
1060 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
1061 name
= targetm
.strip_name_encoding (name
);
1063 /* If we're using one_only, then there needs to be a .gnu.linkonce
1064 prefix to the section name. */
1065 linkonce
= one_only
? ".gnu.linkonce" : "";
1067 string
= ACONCAT ((linkonce
, prefix
, ".", name
, NULL
));
1069 set_decl_section_name (decl
, string
);
1072 default_unique_section (decl
, reloc
);
1076 c6x_section_type_flags (tree decl
, const char *name
, int reloc
)
1078 unsigned int flags
= 0;
1080 if (strcmp (name
, ".far") == 0
1081 || strncmp (name
, ".far.", 5) == 0)
1082 flags
|= SECTION_BSS
;
1084 flags
|= default_section_type_flags (decl
, name
, reloc
);
1089 /* Checks whether the given CALL_EXPR would use a caller saved
1090 register. This is used to decide whether sibling call optimization
1091 could be performed on the respective function call. */
1094 c6x_call_saved_register_used (tree call_expr
)
1096 CUMULATIVE_ARGS cum_v
;
1097 cumulative_args_t cum
;
1098 HARD_REG_SET call_saved_regset
;
1100 enum machine_mode mode
;
1105 INIT_CUMULATIVE_ARGS (cum_v
, NULL
, NULL
, 0, 0);
1106 cum
= pack_cumulative_args (&cum_v
);
1108 COMPL_HARD_REG_SET (call_saved_regset
, call_used_reg_set
);
1109 for (i
= 0; i
< call_expr_nargs (call_expr
); i
++)
1111 parameter
= CALL_EXPR_ARG (call_expr
, i
);
1112 gcc_assert (parameter
);
1114 /* For an undeclared variable passed as parameter we will get
1115 an ERROR_MARK node here. */
1116 if (TREE_CODE (parameter
) == ERROR_MARK
)
1119 type
= TREE_TYPE (parameter
);
1122 mode
= TYPE_MODE (type
);
1125 if (pass_by_reference (&cum_v
, mode
, type
, true))
1128 type
= build_pointer_type (type
);
1131 parm_rtx
= c6x_function_arg (cum
, mode
, type
, 0);
1133 c6x_function_arg_advance (cum
, mode
, type
, 0);
1138 if (REG_P (parm_rtx
)
1139 && overlaps_hard_reg_set_p (call_saved_regset
, GET_MODE (parm_rtx
),
1142 if (GET_CODE (parm_rtx
) == PARALLEL
)
1144 int n
= XVECLEN (parm_rtx
, 0);
1147 rtx x
= XEXP (XVECEXP (parm_rtx
, 0, n
), 0);
1149 && overlaps_hard_reg_set_p (call_saved_regset
,
1150 GET_MODE (x
), REGNO (x
)))
1158 /* Decide whether we can make a sibling call to a function. DECL is the
1159 declaration of the function being targeted by the call and EXP is the
1160 CALL_EXPR representing the call. */
1163 c6x_function_ok_for_sibcall (tree decl
, tree exp
)
1165 /* Registers A10, A12, B10 and B12 are available as arguments
1166 register but unfortunately caller saved. This makes functions
1167 needing these registers for arguments not suitable for
1169 if (c6x_call_saved_register_used (exp
))
1177 /* When compiling for DSBT, the calling function must be local,
1178 so that when we reload B14 in the sibcall epilogue, it will
1179 not change its value. */
1180 struct cgraph_local_info
*this_func
;
1183 /* Not enough information. */
1186 this_func
= cgraph_node::local_info (current_function_decl
);
1187 return this_func
->local
;
1193 /* Return true if DECL is known to be linked into section SECTION. */
1196 c6x_function_in_section_p (tree decl
, section
*section
)
1198 /* We can only be certain about functions defined in the same
1199 compilation unit. */
1200 if (!TREE_STATIC (decl
))
1203 /* Make sure that SYMBOL always binds to the definition in this
1204 compilation unit. */
1205 if (!targetm
.binds_local_p (decl
))
1208 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1209 if (!DECL_SECTION_NAME (decl
))
1211 /* Make sure that we will not create a unique section for DECL. */
1212 if (flag_function_sections
|| DECL_COMDAT_GROUP (decl
))
1216 return function_section (decl
) == section
;
1219 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1222 c6x_long_call_p (rtx op
)
1226 if (!TARGET_LONG_CALLS
)
1229 decl
= SYMBOL_REF_DECL (op
);
1231 /* Try to determine whether the symbol is in the same section as the current
1232 function. Be conservative, and only cater for cases in which the
1233 whole of the current function is placed in the same section. */
1234 if (decl
!= NULL_TREE
1235 && !flag_reorder_blocks_and_partition
1236 && TREE_CODE (decl
) == FUNCTION_DECL
1237 && c6x_function_in_section_p (decl
, current_function_section ()))
1243 /* Emit the sequence for a call. */
1245 c6x_expand_call (rtx retval
, rtx address
, bool sibcall
)
1247 rtx callee
= XEXP (address
, 0);
1250 if (!c6x_call_operand (callee
, Pmode
))
1252 callee
= force_reg (Pmode
, callee
);
1253 address
= change_address (address
, Pmode
, callee
);
1255 call_insn
= gen_rtx_CALL (VOIDmode
, address
, const0_rtx
);
1258 call_insn
= emit_call_insn (call_insn
);
1259 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
),
1260 gen_rtx_REG (Pmode
, REG_B3
));
1264 if (retval
== NULL_RTX
)
1265 call_insn
= emit_call_insn (call_insn
);
1267 call_insn
= emit_call_insn (gen_rtx_SET (GET_MODE (retval
), retval
,
1271 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
), pic_offset_table_rtx
);
1274 /* Legitimize PIC addresses. If the address is already position-independent,
1275 we return ORIG. Newly generated position-independent addresses go into a
1276 reg. This is REG if nonzero, otherwise we allocate register(s) as
1277 necessary. PICREG is the register holding the pointer to the PIC offset
1281 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
1286 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
1288 int unspec
= UNSPEC_LOAD_GOT
;
1293 gcc_assert (can_create_pseudo_p ());
1294 reg
= gen_reg_rtx (Pmode
);
1298 if (can_create_pseudo_p ())
1299 tmp
= gen_reg_rtx (Pmode
);
1302 emit_insn (gen_movsi_gotoff_high (tmp
, addr
));
1303 emit_insn (gen_movsi_gotoff_lo_sum (tmp
, tmp
, addr
));
1304 emit_insn (gen_load_got_gotoff (reg
, picreg
, tmp
));
1308 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
1309 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
1311 emit_move_insn (reg
, new_rtx
);
1313 if (picreg
== pic_offset_table_rtx
)
1314 crtl
->uses_pic_offset_table
= 1;
1318 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
1322 if (GET_CODE (addr
) == CONST
)
1324 addr
= XEXP (addr
, 0);
1325 gcc_assert (GET_CODE (addr
) == PLUS
);
1328 if (XEXP (addr
, 0) == picreg
)
1333 gcc_assert (can_create_pseudo_p ());
1334 reg
= gen_reg_rtx (Pmode
);
1337 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
1338 addr
= legitimize_pic_address (XEXP (addr
, 1),
1339 base
== reg
? NULL_RTX
: reg
,
1342 if (GET_CODE (addr
) == CONST_INT
)
1344 gcc_assert (! reload_in_progress
&& ! reload_completed
);
1345 addr
= force_reg (Pmode
, addr
);
1348 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
1350 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
1351 addr
= XEXP (addr
, 1);
1354 return gen_rtx_PLUS (Pmode
, base
, addr
);
1360 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1361 Returns true if no further code must be generated, false if the caller
1362 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1365 expand_move (rtx
*operands
, enum machine_mode mode
)
1367 rtx dest
= operands
[0];
1368 rtx op
= operands
[1];
1370 if ((reload_in_progress
| reload_completed
) == 0
1371 && GET_CODE (dest
) == MEM
&& GET_CODE (op
) != REG
)
1372 operands
[1] = force_reg (mode
, op
);
1373 else if (mode
== SImode
&& symbolic_operand (op
, SImode
))
1377 if (sdata_symbolic_operand (op
, SImode
))
1379 emit_insn (gen_load_sdata_pic (dest
, pic_offset_table_rtx
, op
));
1380 crtl
->uses_pic_offset_table
= 1;
1385 rtx temp
= (reload_completed
|| reload_in_progress
1386 ? dest
: gen_reg_rtx (Pmode
));
1388 operands
[1] = legitimize_pic_address (op
, temp
,
1389 pic_offset_table_rtx
);
1392 else if (reload_completed
1393 && !sdata_symbolic_operand (op
, SImode
))
1395 emit_insn (gen_movsi_high (dest
, op
));
1396 emit_insn (gen_movsi_lo_sum (dest
, dest
, op
));
1403 /* This function is called when we're about to expand an integer compare
1404 operation which performs COMPARISON. It examines the second operand,
1405 and if it is an integer constant that cannot be used directly on the
1406 current machine in a comparison insn, it returns true. */
1408 c6x_force_op_for_comparison_p (enum rtx_code code
, rtx op
)
1410 if (!CONST_INT_P (op
) || satisfies_constraint_Iu4 (op
))
1413 if ((code
== EQ
|| code
== LT
|| code
== GT
)
1414 && !satisfies_constraint_Is5 (op
))
1416 if ((code
== GTU
|| code
== LTU
)
1417 && (!TARGET_INSNS_64
|| !satisfies_constraint_Iu5 (op
)))
1423 /* Emit comparison instruction if necessary, returning the expression
1424 that holds the compare result in the proper mode. Return the comparison
1425 that should be used in the jump insn. */
1428 c6x_expand_compare (rtx comparison
, enum machine_mode mode
)
1430 enum rtx_code code
= GET_CODE (comparison
);
1431 rtx op0
= XEXP (comparison
, 0);
1432 rtx op1
= XEXP (comparison
, 1);
1434 enum rtx_code jump_code
= code
;
1435 enum machine_mode op_mode
= GET_MODE (op0
);
1437 if (op_mode
== DImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1439 rtx t
= gen_reg_rtx (SImode
);
1440 emit_insn (gen_iorsi3 (t
, gen_lowpart (SImode
, op0
),
1441 gen_highpart (SImode
, op0
)));
1445 else if (op_mode
== DImode
)
1450 if (code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1452 code
= reverse_condition (code
);
1458 split_di (&op0
, 1, lo
, high
);
1459 split_di (&op1
, 1, lo
+ 1, high
+ 1);
1461 if (c6x_force_op_for_comparison_p (code
, high
[1])
1462 || c6x_force_op_for_comparison_p (EQ
, high
[1]))
1463 high
[1] = force_reg (SImode
, high
[1]);
1465 cmp1
= gen_reg_rtx (SImode
);
1466 cmp2
= gen_reg_rtx (SImode
);
1467 emit_insn (gen_rtx_SET (VOIDmode
, cmp1
,
1468 gen_rtx_fmt_ee (code
, SImode
, high
[0], high
[1])));
1471 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1472 lo
[1] = force_reg (SImode
, lo
[1]);
1473 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1474 gen_rtx_fmt_ee (code
, SImode
, lo
[0], lo
[1])));
1475 emit_insn (gen_andsi3 (cmp1
, cmp1
, cmp2
));
1479 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1480 gen_rtx_EQ (SImode
, high
[0], high
[1])));
1483 else if (code
== LT
)
1485 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1486 lo
[1] = force_reg (SImode
, lo
[1]);
1487 emit_insn (gen_cmpsi_and (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1489 lo
[0], lo
[1], cmp2
));
1490 emit_insn (gen_iorsi3 (cmp1
, cmp1
, cmp2
));
1494 else if (TARGET_FP
&& !flag_finite_math_only
1495 && (op_mode
== DFmode
|| op_mode
== SFmode
)
1496 && code
!= EQ
&& code
!= NE
&& code
!= LT
&& code
!= GT
1497 && code
!= UNLE
&& code
!= UNGE
)
1499 enum rtx_code code1
, code2
, code3
;
1500 rtx (*fn
) (rtx
, rtx
, rtx
, rtx
, rtx
);
1512 code1
= code
== LE
|| code
== UNGT
? LT
: GT
;
1537 cmp
= gen_reg_rtx (SImode
);
1538 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1539 gen_rtx_fmt_ee (code1
, SImode
, op0
, op1
)));
1540 fn
= op_mode
== DFmode
? gen_cmpdf_ior
: gen_cmpsf_ior
;
1541 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code2
, SImode
, op0
, op1
),
1543 if (code3
!= UNKNOWN
)
1544 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code3
, SImode
, op0
, op1
),
1547 else if (op_mode
== SImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1552 is_fp_libfunc
= !TARGET_FP
&& (op_mode
== DFmode
|| op_mode
== SFmode
);
1554 if ((code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1557 code
= reverse_condition (code
);
1560 else if (code
== UNGE
)
1565 else if (code
== UNLE
)
1580 libfunc
= op_mode
== DFmode
? eqdf_libfunc
: eqsf_libfunc
;
1583 libfunc
= op_mode
== DFmode
? nedf_libfunc
: nesf_libfunc
;
1586 libfunc
= op_mode
== DFmode
? gtdf_libfunc
: gtsf_libfunc
;
1589 libfunc
= op_mode
== DFmode
? gedf_libfunc
: gesf_libfunc
;
1592 libfunc
= op_mode
== DFmode
? ltdf_libfunc
: ltsf_libfunc
;
1595 libfunc
= op_mode
== DFmode
? ledf_libfunc
: lesf_libfunc
;
1602 cmp
= emit_library_call_value (libfunc
, 0, LCT_CONST
, SImode
, 2,
1603 op0
, op_mode
, op1
, op_mode
);
1604 insns
= get_insns ();
1607 emit_libcall_block (insns
, cmp
, cmp
,
1608 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
));
1612 cmp
= gen_reg_rtx (SImode
);
1613 if (c6x_force_op_for_comparison_p (code
, op1
))
1614 op1
= force_reg (SImode
, op1
);
1615 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1616 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
)));
1620 return gen_rtx_fmt_ee (jump_code
, mode
, cmp
, const0_rtx
);
1623 /* Return one word of double-word value OP. HIGH_P is true to select the
1624 high part, false to select the low part. When encountering auto-increment
1625 addressing, we make the assumption that the low part is going to be accessed
1629 c6x_subword (rtx op
, bool high_p
)
1632 enum machine_mode mode
;
1634 mode
= GET_MODE (op
);
1635 if (mode
== VOIDmode
)
1638 if (TARGET_BIG_ENDIAN
? !high_p
: high_p
)
1639 byte
= UNITS_PER_WORD
;
1645 rtx addr
= XEXP (op
, 0);
1646 if (GET_CODE (addr
) == PLUS
|| REG_P (addr
))
1647 return adjust_address (op
, word_mode
, byte
);
1648 /* FIXME: should really support autoincrement addressing for
1649 multi-word modes. */
1653 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
1656 /* Split one or more DImode RTL references into pairs of SImode
1657 references. The RTL can be REG, offsettable MEM, integer constant, or
1658 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1659 split and "num" is its length. lo_half and hi_half are output arrays
1660 that parallel "operands". */
1663 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1667 rtx op
= operands
[num
];
1669 lo_half
[num
] = c6x_subword (op
, false);
1670 hi_half
[num
] = c6x_subword (op
, true);
1674 /* Return true if VAL is a mask valid for a clr instruction. */
1676 c6x_valid_mask_p (HOST_WIDE_INT val
)
1679 for (i
= 0; i
< 32; i
++)
1680 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1683 if (val
& ((unsigned HOST_WIDE_INT
)1 << i
))
1686 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1691 /* Expand a block move for a movmemM pattern. */
1694 c6x_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
,
1695 rtx expected_align_exp ATTRIBUTE_UNUSED
,
1696 rtx expected_size_exp ATTRIBUTE_UNUSED
)
1698 unsigned HOST_WIDE_INT align
= 1;
1699 unsigned HOST_WIDE_INT src_mem_align
, dst_mem_align
, min_mem_align
;
1700 unsigned HOST_WIDE_INT count
= 0, offset
= 0;
1701 unsigned int biggest_move
= TARGET_STDW
? 8 : 4;
1703 if (CONST_INT_P (align_exp
))
1704 align
= INTVAL (align_exp
);
1706 src_mem_align
= MEM_ALIGN (src
) / BITS_PER_UNIT
;
1707 dst_mem_align
= MEM_ALIGN (dst
) / BITS_PER_UNIT
;
1708 min_mem_align
= MIN (src_mem_align
, dst_mem_align
);
1710 if (min_mem_align
> align
)
1711 align
= min_mem_align
/ BITS_PER_UNIT
;
1712 if (src_mem_align
< align
)
1713 src_mem_align
= align
;
1714 if (dst_mem_align
< align
)
1715 dst_mem_align
= align
;
1717 if (CONST_INT_P (count_exp
))
1718 count
= INTVAL (count_exp
);
1722 /* Make sure we don't need to care about overflow later on. */
1723 if (count
> ((unsigned HOST_WIDE_INT
) 1 << 30))
1726 if (count
>= 28 && (count
& 3) == 0 && align
>= 4)
1728 tree dst_expr
= MEM_EXPR (dst
);
1729 tree src_expr
= MEM_EXPR (src
);
1730 rtx fn
= TARGET_INSNS_64PLUS
? strasgi64p_libfunc
: strasgi_libfunc
;
1731 rtx srcreg
= force_reg (Pmode
, XEXP (src
, 0));
1732 rtx dstreg
= force_reg (Pmode
, XEXP (dst
, 0));
1735 mark_addressable (src_expr
);
1737 mark_addressable (dst_expr
);
1738 emit_library_call (fn
, LCT_NORMAL
, VOIDmode
, 3,
1739 dstreg
, Pmode
, srcreg
, Pmode
, count_exp
, SImode
);
1743 if (biggest_move
> align
&& !TARGET_INSNS_64
)
1744 biggest_move
= align
;
1746 if (count
/ biggest_move
> 7)
1751 rtx reg
, reg_lowpart
;
1752 enum machine_mode srcmode
, dstmode
;
1753 unsigned HOST_WIDE_INT src_size
, dst_size
, src_left
;
1757 while (biggest_move
> count
)
1760 src_size
= dst_size
= biggest_move
;
1761 if (src_size
> src_mem_align
&& src_size
== 2)
1763 if (dst_size
> dst_mem_align
&& dst_size
== 2)
1766 if (dst_size
> src_size
)
1767 dst_size
= src_size
;
1769 srcmode
= mode_for_size (src_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1770 dstmode
= mode_for_size (dst_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1772 reg_lowpart
= reg
= gen_reg_rtx (srcmode
);
1775 reg
= gen_reg_rtx (SImode
);
1776 reg_lowpart
= gen_lowpart (srcmode
, reg
);
1779 srcmem
= adjust_address (copy_rtx (src
), srcmode
, offset
);
1781 if (src_size
> src_mem_align
)
1783 enum insn_code icode
= (srcmode
== SImode
? CODE_FOR_movmisalignsi
1784 : CODE_FOR_movmisaligndi
);
1785 emit_insn (GEN_FCN (icode
) (reg_lowpart
, srcmem
));
1788 emit_move_insn (reg_lowpart
, srcmem
);
1790 src_left
= src_size
;
1791 shift
= TARGET_BIG_ENDIAN
? (src_size
- dst_size
) * BITS_PER_UNIT
: 0;
1792 while (src_left
> 0)
1794 rtx dstreg
= reg_lowpart
;
1796 if (src_size
> dst_size
)
1799 int shift_amount
= shift
& (BITS_PER_WORD
- 1);
1801 srcword
= operand_subword_force (srcword
, src_left
>= 4 ? 0 : 4,
1803 if (shift_amount
> 0)
1805 dstreg
= gen_reg_rtx (SImode
);
1806 emit_insn (gen_lshrsi3 (dstreg
, srcword
,
1807 GEN_INT (shift_amount
)));
1811 dstreg
= gen_lowpart (dstmode
, dstreg
);
1814 dstmem
= adjust_address (copy_rtx (dst
), dstmode
, offset
);
1815 if (dst_size
> dst_mem_align
)
1817 enum insn_code icode
= (dstmode
== SImode
? CODE_FOR_movmisalignsi
1818 : CODE_FOR_movmisaligndi
);
1819 emit_insn (GEN_FCN (icode
) (dstmem
, dstreg
));
1822 emit_move_insn (dstmem
, dstreg
);
1824 if (TARGET_BIG_ENDIAN
)
1825 shift
-= dst_size
* BITS_PER_UNIT
;
1827 shift
+= dst_size
* BITS_PER_UNIT
;
1829 src_left
-= dst_size
;
1836 /* Subroutine of print_address_operand, print a single address offset OFF for
1837 a memory access of mode MEM_MODE, choosing between normal form and scaled
1838 form depending on the type of the insn. Misaligned memory references must
1839 use the scaled form. */
1842 print_address_offset (FILE *file
, rtx off
, enum machine_mode mem_mode
)
1846 if (c6x_current_insn
!= NULL_RTX
)
1848 pat
= PATTERN (c6x_current_insn
);
1849 if (GET_CODE (pat
) == COND_EXEC
)
1850 pat
= COND_EXEC_CODE (pat
);
1851 if (GET_CODE (pat
) == PARALLEL
)
1852 pat
= XVECEXP (pat
, 0, 0);
1854 if (GET_CODE (pat
) == SET
1855 && GET_CODE (SET_SRC (pat
)) == UNSPEC
1856 && XINT (SET_SRC (pat
), 1) == UNSPEC_MISALIGNED_ACCESS
)
1858 gcc_assert (CONST_INT_P (off
)
1859 && (INTVAL (off
) & (GET_MODE_SIZE (mem_mode
) - 1)) == 0);
1860 fprintf (file
, "[" HOST_WIDE_INT_PRINT_DEC
"]",
1861 INTVAL (off
) / GET_MODE_SIZE (mem_mode
));
1866 output_address (off
);
1871 c6x_print_operand_punct_valid_p (unsigned char c
)
1873 return c
== '$' || c
== '.' || c
== '|';
1876 static void c6x_print_operand (FILE *, rtx
, int);
1878 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1881 c6x_print_address_operand (FILE *file
, rtx x
, enum machine_mode mem_mode
)
1884 switch (GET_CODE (x
))
1888 if (GET_CODE (x
) == POST_MODIFY
)
1889 output_address (XEXP (x
, 0));
1890 off
= XEXP (XEXP (x
, 1), 1);
1891 if (XEXP (x
, 0) == stack_pointer_rtx
)
1893 if (GET_CODE (x
) == PRE_MODIFY
)
1894 gcc_assert (INTVAL (off
) > 0);
1896 gcc_assert (INTVAL (off
) < 0);
1898 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1900 fprintf (file
, "--");
1901 off
= GEN_INT (-INTVAL (off
));
1904 fprintf (file
, "++");
1905 if (GET_CODE (x
) == PRE_MODIFY
)
1906 output_address (XEXP (x
, 0));
1907 print_address_offset (file
, off
, mem_mode
);
1912 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1914 fprintf (file
, "-");
1915 off
= GEN_INT (-INTVAL (off
));
1918 fprintf (file
, "+");
1919 output_address (XEXP (x
, 0));
1920 print_address_offset (file
, off
, mem_mode
);
1924 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1925 fprintf (file
, "--");
1926 output_address (XEXP (x
, 0));
1927 fprintf (file
, "[1]");
1930 fprintf (file
, "++");
1931 output_address (XEXP (x
, 0));
1932 fprintf (file
, "[1]");
1935 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1936 output_address (XEXP (x
, 0));
1937 fprintf (file
, "++[1]");
1940 output_address (XEXP (x
, 0));
1941 fprintf (file
, "--[1]");
1947 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
1948 fprintf (file
, "+B14(");
1949 output_addr_const (file
, x
);
1950 fprintf (file
, ")");
1954 switch (XINT (x
, 1))
1956 case UNSPEC_LOAD_GOT
:
1957 fputs ("$GOT(", file
);
1958 output_addr_const (file
, XVECEXP (x
, 0, 0));
1961 case UNSPEC_LOAD_SDATA
:
1962 output_addr_const (file
, XVECEXP (x
, 0, 0));
1970 gcc_assert (GET_CODE (x
) != MEM
);
1971 c6x_print_operand (file
, x
, 0);
1976 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1977 specifies the functional unit used by INSN. */
1980 c6x_get_unit_specifier (rtx_insn
*insn
)
1982 enum attr_units units
;
1984 if (insn_info
.exists ())
1986 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
1987 return c6x_unit_names
[unit
][0];
1990 units
= get_attr_units (insn
);
2015 /* Prints the unit specifier field. */
2017 c6x_print_unit_specifier_field (FILE *file
, rtx_insn
*insn
)
2019 enum attr_units units
= get_attr_units (insn
);
2020 enum attr_cross cross
= get_attr_cross (insn
);
2021 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
2025 if (units
== UNITS_D_ADDR
)
2027 enum attr_addr_regfile arf
= get_attr_addr_regfile (insn
);
2029 gcc_assert (arf
!= ADDR_REGFILE_UNKNOWN
);
2030 half
= arf
== ADDR_REGFILE_A
? 1 : 2;
2031 t_half
= rf
== DEST_REGFILE_A
? 1 : 2;
2032 fprintf (file
, ".d%dt%d", half
, t_half
);
2036 if (insn_info
.exists ())
2038 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2040 fputs (c6x_unit_names
[unit
], file
);
2041 if (cross
== CROSS_Y
)
2046 gcc_assert (rf
!= DEST_REGFILE_UNKNOWN
);
2047 unitspec
= c6x_get_unit_specifier (insn
);
2048 half
= rf
== DEST_REGFILE_A
? 1 : 2;
2049 fprintf (file
, ".%c%d%s", unitspec
, half
, cross
== CROSS_Y
? "x" : "");
2052 /* Output assembly language output for the address ADDR to FILE. */
2054 c6x_print_operand_address (FILE *file
, rtx addr
)
2056 c6x_print_address_operand (file
, addr
, VOIDmode
);
2059 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2062 $ -- print the unit specifier field for the instruction.
2063 . -- print the predicate for the instruction or an emptry string for an
2065 | -- print "||" if the insn should be issued in parallel with the previous
2068 C -- print an opcode suffix for a reversed condition
2069 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2071 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2073 J -- print a predicate
2074 j -- like J, but use reverse predicate
2075 k -- treat a CONST_INT as a register number and print it as a register
2076 k -- like k, but print out a doubleword register
2077 n -- print an integer operand, negated
2078 p -- print the low part of a DImode register
2079 P -- print the high part of a DImode register
2080 r -- print the absolute value of an integer operand, shifted right by 1
2081 R -- print the absolute value of an integer operand, shifted right by 2
2082 f -- the first clear bit in an integer operand assumed to be a mask for
2084 F -- the last clear bit in such a mask
2085 s -- the first set bit in an integer operand assumed to be a mask for
2087 S -- the last set bit in such a mask
2088 U -- print either 1 or 2, depending on the side of the machine used by
2092 c6x_print_operand (FILE *file
, rtx x
, int code
)
2097 enum machine_mode mode
;
2101 if (GET_MODE (c6x_current_insn
) != TImode
)
2107 c6x_print_unit_specifier_field (file
, c6x_current_insn
);
2113 x
= current_insn_predicate
;
2116 unsigned int regno
= REGNO (XEXP (x
, 0));
2118 if (GET_CODE (x
) == EQ
)
2120 fputs (reg_names
[regno
], file
);
2126 mode
= GET_MODE (x
);
2133 enum rtx_code c
= GET_CODE (x
);
2135 c
= swap_condition (c
);
2136 fputs (GET_RTX_NAME (c
), file
);
2143 unsigned int regno
= REGNO (XEXP (x
, 0));
2144 if ((GET_CODE (x
) == EQ
) == (code
== 'J'))
2146 fputs (reg_names
[regno
], file
);
2151 gcc_assert (GET_CODE (x
) == CONST_INT
);
2153 fprintf (file
, "%s", reg_names
[v
]);
2156 gcc_assert (GET_CODE (x
) == CONST_INT
);
2158 gcc_assert ((v
& 1) == 0);
2159 fprintf (file
, "%s:%s", reg_names
[v
+ 1], reg_names
[v
]);
2166 gcc_assert (GET_CODE (x
) == CONST_INT
);
2168 for (i
= 0; i
< 32; i
++)
2170 HOST_WIDE_INT tst
= v
& 1;
2171 if (((code
== 'f' || code
== 'F') && !tst
)
2172 || ((code
== 's' || code
== 'S') && tst
))
2176 if (code
== 'f' || code
== 's')
2178 fprintf (file
, "%d", i
);
2183 HOST_WIDE_INT tst
= v
& 1;
2184 if ((code
== 'F' && tst
) || (code
== 'S' && !tst
))
2188 fprintf (file
, "%d", i
- 1);
2192 gcc_assert (GET_CODE (x
) == CONST_INT
);
2193 output_addr_const (file
, GEN_INT (-INTVAL (x
)));
2197 gcc_assert (GET_CODE (x
) == CONST_INT
);
2201 output_addr_const (file
, GEN_INT (v
>> 1));
2205 gcc_assert (GET_CODE (x
) == CONST_INT
);
2209 output_addr_const (file
, GEN_INT (v
>> 2));
2213 gcc_assert (GET_CODE (x
) == CONST_INT
);
2215 fputs (v
== 2 ? "h" : v
== 4 ? "w" : "d", file
);
2220 gcc_assert (GET_CODE (x
) == REG
);
2224 fputs (reg_names
[v
], file
);
2229 if (GET_CODE (x
) == CONST
)
2232 gcc_assert (GET_CODE (x
) == PLUS
);
2233 gcc_assert (GET_CODE (XEXP (x
, 1)) == CONST_INT
);
2234 v
= INTVAL (XEXP (x
, 1));
2238 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
2240 t
= SYMBOL_REF_DECL (x
);
2242 v
|= DECL_ALIGN_UNIT (t
);
2244 v
|= TYPE_ALIGN_UNIT (TREE_TYPE (t
));
2257 if (GET_CODE (x
) == PLUS
2258 || GET_RTX_CLASS (GET_CODE (x
)) == RTX_AUTOINC
)
2260 if (GET_CODE (x
) == CONST
|| GET_CODE (x
) == SYMBOL_REF
)
2262 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
2267 gcc_assert (REG_P (x
));
2268 if (A_REGNO_P (REGNO (x
)))
2270 if (B_REGNO_P (REGNO (x
)))
2275 switch (GET_CODE (x
))
2278 if (GET_MODE_SIZE (mode
) == 8)
2279 fprintf (file
, "%s:%s", reg_names
[REGNO (x
) + 1],
2280 reg_names
[REGNO (x
)]);
2282 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
2287 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
2288 c6x_print_address_operand (file
, XEXP (x
, 0), GET_MODE (x
));
2293 output_addr_const (file
, x
);
2298 output_addr_const (file
, x
);
2302 output_operand_lossage ("invalid const_double operand");
2306 output_addr_const (file
, x
);
2311 /* Return TRUE if OP is a valid memory address with a base register of
2312 class C. If SMALL_OFFSET is true, we disallow memory references which would
2313 require a long offset with B14/B15. */
2316 c6x_mem_operand (rtx op
, enum reg_class c
, bool small_offset
)
2318 enum machine_mode mode
= GET_MODE (op
);
2319 rtx base
= XEXP (op
, 0);
2320 switch (GET_CODE (base
))
2326 && (XEXP (base
, 0) == stack_pointer_rtx
2327 || XEXP (base
, 0) == pic_offset_table_rtx
))
2329 if (!c6x_legitimate_address_p_1 (mode
, base
, true, true))
2340 base
= XEXP (base
, 0);
2346 gcc_assert (sdata_symbolic_operand (base
, Pmode
));
2347 return !small_offset
&& c
== B_REGS
;
2352 return TEST_HARD_REG_BIT (reg_class_contents
[ (int) (c
)], REGNO (base
));
2355 /* Returns true if X is a valid address for use in a memory reference
2356 of mode MODE. If STRICT is true, we do not allow pseudo registers
2357 in the address. NO_LARGE_OFFSET is true if we are examining an
2358 address for use in a load or store misaligned instruction, or
2359 recursively examining an operand inside a PRE/POST_MODIFY. */
2362 c6x_legitimate_address_p_1 (enum machine_mode mode
, rtx x
, bool strict
,
2363 bool no_large_offset
)
2367 enum rtx_code code
= GET_CODE (x
);
2373 /* We can't split these into word-sized pieces yet. */
2374 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2376 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
2378 if (!c6x_legitimate_address_p_1 (mode
, XEXP (x
, 1), strict
, true))
2380 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
2388 /* We can't split these into word-sized pieces yet. */
2389 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2398 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x
));
2400 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x
));
2403 if (!REG_P (XEXP (x
, 0))
2404 || !c6x_legitimate_address_p_1 (mode
, XEXP (x
, 0), strict
, false))
2406 /* We cannot ensure currently that both registers end up in the
2407 same register file. */
2408 if (REG_P (XEXP (x
, 1)))
2411 if (mode
== BLKmode
)
2413 else if (mode
== VOIDmode
)
2414 /* ??? This can happen during ivopts. */
2417 size
= GET_MODE_SIZE (mode
);
2420 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2421 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_SDATA
2422 && XEXP (x
, 0) == pic_offset_table_rtx
2423 && sdata_symbolic_operand (XVECEXP (XEXP (x
, 1), 0, 0), SImode
))
2424 return !no_large_offset
&& size
<= 4;
2427 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2428 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_GOT
2429 && XEXP (x
, 0) == pic_offset_table_rtx
2430 && (GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == SYMBOL_REF
2431 || GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == LABEL_REF
))
2432 return !no_large_offset
;
2433 if (GET_CODE (XEXP (x
, 1)) != CONST_INT
)
2436 off
= INTVAL (XEXP (x
, 1));
2438 /* If the machine does not have doubleword load/stores, we'll use
2439 word size accesses. */
2441 if (size
== 2 * UNITS_PER_WORD
&& !TARGET_STDW
)
2442 size
= UNITS_PER_WORD
;
2444 if (((HOST_WIDE_INT
)size1
- 1) & off
)
2447 if (off
> -32 && off
< (size1
== size
? 32 : 28))
2449 if (no_large_offset
|| code
!= PLUS
|| XEXP (x
, 0) != stack_pointer_rtx
2450 || size1
> UNITS_PER_WORD
)
2452 return off
>= 0 && off
< 32768;
2457 return (!no_large_offset
2458 /* With -fpic, we must wrap it in an unspec to show the B14
2461 && GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
2462 && sdata_symbolic_operand (x
, Pmode
));
2470 c6x_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
2472 return c6x_legitimate_address_p_1 (mode
, x
, strict
, false);
2476 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
,
2477 rtx x ATTRIBUTE_UNUSED
)
2482 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2484 c6x_preferred_rename_class (reg_class_t cl
)
2487 return NONPREDICATE_A_REGS
;
2489 return NONPREDICATE_B_REGS
;
2490 if (cl
== ALL_REGS
|| cl
== GENERAL_REGS
)
2491 return NONPREDICATE_REGS
;
2495 /* Implements FINAL_PRESCAN_INSN. */
2497 c6x_final_prescan_insn (rtx_insn
*insn
, rtx
*opvec ATTRIBUTE_UNUSED
,
2498 int noperands ATTRIBUTE_UNUSED
)
2500 c6x_current_insn
= insn
;
2503 /* A structure to describe the stack layout of a function. The layout is
2506 [saved frame pointer (or possibly padding0)]
2507 --> incoming stack pointer, new hard frame pointer
2508 [saved call-used regs]
2510 --> soft frame pointer
2512 [outgoing arguments]
2515 The structure members are laid out in this order. */
2520 /* Number of registers to save. */
2523 HOST_WIDE_INT frame
;
2524 int outgoing_arguments_size
;
2527 HOST_WIDE_INT to_allocate
;
2528 /* The offsets relative to the incoming stack pointer (which
2529 becomes HARD_FRAME_POINTER). */
2530 HOST_WIDE_INT frame_pointer_offset
;
2531 HOST_WIDE_INT b3_offset
;
2533 /* True if we should call push_rts/pop_rts to save and restore
2538 /* Return true if we need to save and modify the PIC register in the
2542 must_reload_pic_reg_p (void)
2544 struct cgraph_local_info
*i
= NULL
;
2549 i
= cgraph_node::local_info (current_function_decl
);
2551 if ((crtl
->uses_pic_offset_table
|| !crtl
->is_leaf
) && !i
->local
)
2556 /* Return 1 if we need to save REGNO. */
2558 c6x_save_reg (unsigned int regno
)
2560 return ((df_regs_ever_live_p (regno
)
2561 && !call_used_regs
[regno
]
2562 && !fixed_regs
[regno
])
2563 || (regno
== RETURN_ADDR_REGNO
2564 && (df_regs_ever_live_p (regno
)
2566 || (regno
== PIC_OFFSET_TABLE_REGNUM
&& must_reload_pic_reg_p ()));
2569 /* Examine the number of regs NREGS we've determined we must save.
2570 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2571 prologue and epilogue. */
2574 use_push_rts_p (int nregs
)
2576 if (TARGET_INSNS_64PLUS
&& optimize_function_for_size_p (cfun
)
2577 && !cfun
->machine
->contains_sibcall
2578 && !cfun
->returns_struct
2579 && !TARGET_LONG_CALLS
2580 && nregs
>= 6 && !frame_pointer_needed
)
2585 /* Return number of saved general prupose registers. */
2588 c6x_nsaved_regs (void)
2593 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
2594 if (c6x_save_reg (regno
))
2599 /* The safe debug order mandated by the ABI. */
2600 static unsigned reg_save_order
[] =
2602 REG_A10
, REG_A11
, REG_A12
, REG_A13
,
2604 REG_B10
, REG_B11
, REG_B12
, REG_B13
,
2608 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2610 /* Compute the layout of the stack frame and store it in FRAME. */
2613 c6x_compute_frame_layout (struct c6x_frame
*frame
)
2615 HOST_WIDE_INT size
= get_frame_size ();
2616 HOST_WIDE_INT offset
;
2619 /* We use the four bytes which are technically inside the caller's frame,
2620 usually to save the frame pointer. */
2622 frame
->padding0
= 0;
2623 nregs
= c6x_nsaved_regs ();
2624 frame
->push_rts
= false;
2625 frame
->b3_offset
= 0;
2626 if (use_push_rts_p (nregs
))
2628 frame
->push_rts
= true;
2629 frame
->b3_offset
= (TARGET_BIG_ENDIAN
? -12 : -13) * 4;
2632 else if (c6x_save_reg (REG_B3
))
2635 for (idx
= N_SAVE_ORDER
- 1; reg_save_order
[idx
] != REG_B3
; idx
--)
2637 if (c6x_save_reg (reg_save_order
[idx
]))
2638 frame
->b3_offset
-= 4;
2641 frame
->nregs
= nregs
;
2643 if (size
== 0 && nregs
== 0)
2645 frame
->padding0
= 4;
2646 frame
->padding1
= frame
->padding2
= 0;
2647 frame
->frame_pointer_offset
= frame
->to_allocate
= 0;
2648 frame
->outgoing_arguments_size
= 0;
2652 if (!frame
->push_rts
)
2653 offset
+= frame
->nregs
* 4;
2655 if (offset
== 0 && size
== 0 && crtl
->outgoing_args_size
== 0
2657 /* Don't use the bottom of the caller's frame if we have no
2658 allocation of our own and call other functions. */
2659 frame
->padding0
= frame
->padding1
= 4;
2660 else if (offset
& 4)
2661 frame
->padding1
= 4;
2663 frame
->padding1
= 0;
2665 offset
+= frame
->padding0
+ frame
->padding1
;
2666 frame
->frame_pointer_offset
= offset
;
2669 frame
->outgoing_arguments_size
= crtl
->outgoing_args_size
;
2670 offset
+= frame
->outgoing_arguments_size
;
2672 if ((offset
& 4) == 0)
2673 frame
->padding2
= 8;
2675 frame
->padding2
= 4;
2676 frame
->to_allocate
= offset
+ frame
->padding2
;
2679 /* Return the offset between two registers, one to be eliminated, and the other
2680 its replacement, at the start of a routine. */
2683 c6x_initial_elimination_offset (int from
, int to
)
2685 struct c6x_frame frame
;
2686 c6x_compute_frame_layout (&frame
);
2688 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
2690 else if (from
== FRAME_POINTER_REGNUM
2691 && to
== HARD_FRAME_POINTER_REGNUM
)
2692 return -frame
.frame_pointer_offset
;
2695 gcc_assert (to
== STACK_POINTER_REGNUM
);
2697 if (from
== ARG_POINTER_REGNUM
)
2698 return frame
.to_allocate
+ (frame
.push_rts
? 56 : 0);
2700 gcc_assert (from
== FRAME_POINTER_REGNUM
);
2701 return frame
.to_allocate
- frame
.frame_pointer_offset
;
2705 /* Given FROM and TO register numbers, say whether this elimination is
2706 allowed. Frame pointer elimination is automatically handled. */
2709 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
2711 if (to
== STACK_POINTER_REGNUM
)
2712 return !frame_pointer_needed
;
2716 /* Emit insns to increment the stack pointer by OFFSET. If
2717 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2718 Does nothing if the offset is zero. */
2721 emit_add_sp_const (HOST_WIDE_INT offset
, bool frame_related_p
)
2723 rtx to_add
= GEN_INT (offset
);
2724 rtx orig_to_add
= to_add
;
2730 if (offset
< -32768 || offset
> 32767)
2732 rtx reg
= gen_rtx_REG (SImode
, REG_A0
);
2733 rtx low
= GEN_INT (trunc_int_for_mode (offset
, HImode
));
2735 insn
= emit_insn (gen_movsi_high (reg
, low
));
2736 if (frame_related_p
)
2737 RTX_FRAME_RELATED_P (insn
) = 1;
2738 insn
= emit_insn (gen_movsi_lo_sum (reg
, reg
, to_add
));
2739 if (frame_related_p
)
2740 RTX_FRAME_RELATED_P (insn
) = 1;
2743 insn
= emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2745 if (frame_related_p
)
2748 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
2749 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
2750 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2753 RTX_FRAME_RELATED_P (insn
) = 1;
2757 /* Prologue and epilogue. */
2759 c6x_expand_prologue (void)
2761 struct c6x_frame frame
;
2765 HOST_WIDE_INT initial_offset
, off
, added_already
;
2767 c6x_compute_frame_layout (&frame
);
2769 if (flag_stack_usage_info
)
2770 current_function_static_stack_size
= frame
.to_allocate
;
2772 initial_offset
= -frame
.to_allocate
;
2775 emit_insn (gen_push_rts ());
2776 nsaved
= frame
.nregs
;
2779 /* If the offsets would be too large for the memory references we will
2780 create to save registers, do the stack allocation in two parts.
2781 Ensure by subtracting 8 that we don't store to the word pointed to
2782 by the stack pointer. */
2783 if (initial_offset
< -32768)
2784 initial_offset
= -frame
.frame_pointer_offset
- 8;
2786 if (frame
.to_allocate
> 0)
2787 gcc_assert (initial_offset
!= 0);
2789 off
= -initial_offset
+ 4 - frame
.padding0
;
2791 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2794 if (frame_pointer_needed
)
2796 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2797 /* We go through some contortions here to both follow the ABI's
2798 recommendation that FP == incoming SP, and to avoid writing or
2799 reading the word pointed to by the stack pointer. */
2800 rtx addr
= gen_rtx_POST_MODIFY (Pmode
, stack_pointer_rtx
,
2801 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2803 insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), fp_reg
);
2804 RTX_FRAME_RELATED_P (insn
) = 1;
2806 insn
= emit_insn (gen_addsi3 (hard_frame_pointer_rtx
, stack_pointer_rtx
,
2808 RTX_FRAME_RELATED_P (insn
) = 1;
2813 emit_add_sp_const (initial_offset
- added_already
, true);
2815 if (nsaved
< frame
.nregs
)
2819 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2821 int idx
= N_SAVE_ORDER
- i
- 1;
2822 unsigned regno
= reg_save_order
[idx
];
2824 enum machine_mode save_mode
= SImode
;
2826 if (regno
== REG_A15
&& frame_pointer_needed
)
2827 /* Already saved. */
2829 if (!c6x_save_reg (regno
))
2832 if (TARGET_STDW
&& (off
& 4) == 0 && off
<= 256
2834 && i
+ 1 < N_SAVE_ORDER
2835 && reg_save_order
[idx
- 1] == regno
- 1
2836 && c6x_save_reg (regno
- 1))
2842 reg
= gen_rtx_REG (save_mode
, regno
);
2843 off
-= GET_MODE_SIZE (save_mode
);
2845 insn
= emit_move_insn (adjust_address (mem
, save_mode
, off
),
2847 RTX_FRAME_RELATED_P (insn
) = 1;
2849 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2852 gcc_assert (nsaved
== frame
.nregs
);
2853 emit_add_sp_const (-frame
.to_allocate
- initial_offset
, true);
2854 if (must_reload_pic_reg_p ())
2856 if (dsbt_decl
== NULL
)
2860 t
= build_index_type (integer_one_node
);
2861 t
= build_array_type (integer_type_node
, t
);
2862 t
= build_decl (BUILTINS_LOCATION
, VAR_DECL
,
2863 get_identifier ("__c6xabi_DSBT_BASE"), t
);
2864 DECL_ARTIFICIAL (t
) = 1;
2865 DECL_IGNORED_P (t
) = 1;
2866 DECL_EXTERNAL (t
) = 1;
2867 TREE_STATIC (t
) = 1;
2868 TREE_PUBLIC (t
) = 1;
2873 emit_insn (gen_setup_dsbt (pic_offset_table_rtx
,
2874 XEXP (DECL_RTL (dsbt_decl
), 0)));
2879 c6x_expand_epilogue (bool sibcall
)
2882 struct c6x_frame frame
;
2887 c6x_compute_frame_layout (&frame
);
2889 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2891 /* Insert a dummy set/use of the stack pointer. This creates a
2892 scheduler barrier between the prologue saves and epilogue restores. */
2893 emit_insn (gen_epilogue_barrier (stack_pointer_rtx
, stack_pointer_rtx
));
2895 /* If the offsets would be too large for the memory references we will
2896 create to restore registers, do a preliminary stack adjustment here. */
2897 off
= frame
.to_allocate
- frame
.frame_pointer_offset
+ frame
.padding1
;
2900 nsaved
= frame
.nregs
;
2904 if (frame
.to_allocate
> 32768)
2906 /* Don't add the entire offset so that we leave an unused word
2907 above the stack pointer. */
2908 emit_add_sp_const ((off
- 16) & ~7, false);
2912 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2914 unsigned regno
= reg_save_order
[i
];
2916 enum machine_mode save_mode
= SImode
;
2918 if (!c6x_save_reg (regno
))
2920 if (regno
== REG_A15
&& frame_pointer_needed
)
2923 if (TARGET_STDW
&& (off
& 4) == 0 && off
< 256
2925 && i
+ 1 < N_SAVE_ORDER
2926 && reg_save_order
[i
+ 1] == regno
+ 1
2927 && c6x_save_reg (regno
+ 1))
2932 reg
= gen_rtx_REG (save_mode
, regno
);
2934 emit_move_insn (reg
, adjust_address (mem
, save_mode
, off
));
2936 off
+= GET_MODE_SIZE (save_mode
);
2937 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2940 if (!frame_pointer_needed
)
2941 emit_add_sp_const (off
+ frame
.padding0
- 4, false);
2944 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2945 rtx addr
= gen_rtx_PRE_MODIFY (Pmode
, stack_pointer_rtx
,
2946 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2948 emit_insn (gen_addsi3 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
2950 emit_move_insn (fp_reg
, gen_frame_mem (Pmode
, addr
));
2953 gcc_assert (nsaved
== frame
.nregs
);
2957 emit_jump_insn (gen_pop_rts ());
2959 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode
,
2960 RETURN_ADDR_REGNO
)));
2964 /* Return the value of the return address for the frame COUNT steps up
2965 from the current frame, after the prologue.
2966 We punt for everything but the current frame by returning const0_rtx. */
2969 c6x_return_addr_rtx (int count
)
2974 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNO
);
2977 /* Return true iff TYPE is one of the shadow types. */
2979 shadow_type_p (enum attr_type type
)
2981 return (type
== TYPE_SHADOW
|| type
== TYPE_LOAD_SHADOW
2982 || type
== TYPE_MULT_SHADOW
);
2985 /* Return true iff INSN is a shadow pattern. */
2987 shadow_p (rtx_insn
*insn
)
2989 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
2991 return shadow_type_p (get_attr_type (insn
));
2994 /* Return true iff INSN is a shadow or blockage pattern. */
2996 shadow_or_blockage_p (rtx_insn
*insn
)
2998 enum attr_type type
;
2999 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3001 type
= get_attr_type (insn
);
3002 return shadow_type_p (type
) || type
== TYPE_BLOCKAGE
;
3005 /* Translate UNITS into a bitmask of units we can reserve for this
3008 get_reservation_flags (enum attr_units units
)
3014 return RESERVATION_FLAG_D
;
3016 return RESERVATION_FLAG_L
;
3018 return RESERVATION_FLAG_S
;
3020 return RESERVATION_FLAG_M
;
3022 return RESERVATION_FLAG_LS
;
3024 return RESERVATION_FLAG_DL
;
3026 return RESERVATION_FLAG_DS
;
3028 return RESERVATION_FLAG_DLS
;
3034 /* Compute the side of the machine used by INSN, which reserves UNITS.
3035 This must match the reservations in the scheduling description. */
3037 get_insn_side (rtx_insn
*insn
, enum attr_units units
)
3039 if (units
== UNITS_D_ADDR
)
3040 return (get_attr_addr_regfile (insn
) == ADDR_REGFILE_A
? 0 : 1);
3043 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
3044 if (rf
== DEST_REGFILE_ANY
)
3045 return get_attr_type (insn
) == TYPE_BRANCH
? 0 : 1;
3047 return rf
== DEST_REGFILE_A
? 0 : 1;
3051 /* After scheduling, walk the insns between HEAD and END and assign unit
3054 assign_reservations (rtx_insn
*head
, rtx_insn
*end
)
3057 for (insn
= head
; insn
!= NEXT_INSN (end
); insn
= NEXT_INSN (insn
))
3059 unsigned int sched_mask
, reserved
;
3060 rtx_insn
*within
, *last
;
3063 int rsrv_count
[2][4];
3066 if (GET_MODE (insn
) != TImode
)
3071 /* Find the last insn in the packet. It has a state recorded for it,
3072 which we can use to determine the units we should be using. */
3074 (within
!= NEXT_INSN (end
)
3075 && (within
== insn
|| GET_MODE (within
) != TImode
));
3076 within
= NEXT_INSN (within
))
3079 if (!NONDEBUG_INSN_P (within
))
3081 icode
= recog_memoized (within
);
3084 if (shadow_p (within
))
3086 if (INSN_INFO_ENTRY (INSN_UID (within
)).reservation
!= 0)
3087 reserved
|= 1 << INSN_INFO_ENTRY (INSN_UID (within
)).reservation
;
3090 if (last
== NULL_RTX
)
3093 sched_mask
= INSN_INFO_ENTRY (INSN_UID (last
)).unit_mask
;
3094 sched_mask
&= ~reserved
;
3096 memset (rsrv_count
, 0, sizeof rsrv_count
);
3097 rsrv
[0] = rsrv
[1] = ~0;
3098 for (i
= 0; i
< 8; i
++)
3102 unsigned unit_bit
= 1 << (unit
+ side
* UNIT_QID_SIDE_OFFSET
);
3103 /* Clear the bits which we expect to reserve in the following loop,
3104 leaving the ones set which aren't present in the scheduler's
3105 state and shouldn't be reserved. */
3106 if (sched_mask
& unit_bit
)
3107 rsrv
[i
/ 4] &= ~(1 << unit
);
3110 /* Walk through the insns that occur in the same cycle. We use multiple
3111 passes to assign units, assigning for insns with the most specific
3112 requirements first. */
3113 for (pass
= 0; pass
< 4; pass
++)
3115 (within
!= NEXT_INSN (end
)
3116 && (within
== insn
|| GET_MODE (within
) != TImode
));
3117 within
= NEXT_INSN (within
))
3119 int uid
= INSN_UID (within
);
3120 int this_rsrv
, side
;
3122 enum attr_units units
;
3123 enum attr_type type
;
3126 if (!NONDEBUG_INSN_P (within
))
3128 icode
= recog_memoized (within
);
3131 if (INSN_INFO_ENTRY (uid
).reservation
!= 0)
3133 units
= get_attr_units (within
);
3134 type
= get_attr_type (within
);
3135 this_rsrv
= get_reservation_flags (units
);
3138 side
= get_insn_side (within
, units
);
3140 /* Certain floating point instructions are treated specially. If
3141 an insn can choose between units it can reserve, and its
3142 reservation spans more than one cycle, the reservation contains
3143 special markers in the first cycle to help us reconstruct what
3144 the automaton chose. */
3145 if ((type
== TYPE_ADDDP
|| type
== TYPE_FP4
)
3146 && units
== UNITS_LS
)
3148 int test1_code
= ((type
== TYPE_FP4
? UNIT_QID_FPL1
: UNIT_QID_ADDDPL1
)
3149 + side
* UNIT_QID_SIDE_OFFSET
);
3150 int test2_code
= ((type
== TYPE_FP4
? UNIT_QID_FPS1
: UNIT_QID_ADDDPS1
)
3151 + side
* UNIT_QID_SIDE_OFFSET
);
3152 if ((sched_mask
& (1 << test1_code
)) != 0)
3154 this_rsrv
= RESERVATION_FLAG_L
;
3155 sched_mask
&= ~(1 << test1_code
);
3157 else if ((sched_mask
& (1 << test2_code
)) != 0)
3159 this_rsrv
= RESERVATION_FLAG_S
;
3160 sched_mask
&= ~(1 << test2_code
);
3164 if ((this_rsrv
& (this_rsrv
- 1)) == 0)
3166 int t
= exact_log2 (this_rsrv
) + side
* UNIT_QID_SIDE_OFFSET
;
3167 rsrv
[side
] |= this_rsrv
;
3168 INSN_INFO_ENTRY (uid
).reservation
= t
;
3174 for (j
= 0; j
< 4; j
++)
3175 if (this_rsrv
& (1 << j
))
3176 rsrv_count
[side
][j
]++;
3179 if ((pass
== 2 && this_rsrv
!= RESERVATION_FLAG_DLS
)
3180 || (pass
== 3 && this_rsrv
== RESERVATION_FLAG_DLS
))
3182 int best
= -1, best_cost
= INT_MAX
;
3183 for (j
= 0; j
< 4; j
++)
3184 if ((this_rsrv
& (1 << j
))
3185 && !(rsrv
[side
] & (1 << j
))
3186 && rsrv_count
[side
][j
] < best_cost
)
3188 best_cost
= rsrv_count
[side
][j
];
3191 gcc_assert (best
!= -1);
3192 rsrv
[side
] |= 1 << best
;
3193 for (j
= 0; j
< 4; j
++)
3194 if ((this_rsrv
& (1 << j
)) && j
!= best
)
3195 rsrv_count
[side
][j
]--;
3197 INSN_INFO_ENTRY (uid
).reservation
3198 = best
+ side
* UNIT_QID_SIDE_OFFSET
;
3204 /* Return a factor by which to weight unit imbalances for a reservation
3207 unit_req_factor (enum unitreqs r
)
3229 /* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3230 requirements. Returns zero if INSN can't be handled, otherwise
3231 either one or two to show how many of the two pairs are in use.
3232 REQ1 is always used, it holds what is normally thought of as the
3233 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3234 describe a cross path, or for loads/stores, the T unit. */
3236 get_unit_reqs (rtx_insn
*insn
, int *req1
, int *side1
, int *req2
, int *side2
)
3238 enum attr_units units
;
3239 enum attr_cross cross
;
3242 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3244 units
= get_attr_units (insn
);
3245 if (units
== UNITS_UNKNOWN
)
3247 side
= get_insn_side (insn
, units
);
3248 cross
= get_attr_cross (insn
);
3250 req
= (units
== UNITS_D
? UNIT_REQ_D
3251 : units
== UNITS_D_ADDR
? UNIT_REQ_D
3252 : units
== UNITS_DL
? UNIT_REQ_DL
3253 : units
== UNITS_DS
? UNIT_REQ_DS
3254 : units
== UNITS_L
? UNIT_REQ_L
3255 : units
== UNITS_LS
? UNIT_REQ_LS
3256 : units
== UNITS_S
? UNIT_REQ_S
3257 : units
== UNITS_M
? UNIT_REQ_M
3258 : units
== UNITS_DLS
? UNIT_REQ_DLS
3260 gcc_assert (req
!= -1);
3263 if (units
== UNITS_D_ADDR
)
3266 *side2
= side
^ (cross
== CROSS_Y
? 1 : 0);
3269 else if (cross
== CROSS_Y
)
3278 /* Walk the insns between and including HEAD and TAIL, and mark the
3279 resource requirements in the unit_reqs table. */
3281 count_unit_reqs (unit_req_table reqs
, rtx_insn
*head
, rtx_insn
*tail
)
3285 memset (reqs
, 0, sizeof (unit_req_table
));
3287 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3289 int side1
, side2
, req1
, req2
;
3291 switch (get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
))
3294 reqs
[side2
][req2
]++;
3297 reqs
[side1
][req1
]++;
3303 /* Update the table REQS by merging more specific unit reservations into
3304 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3305 UNIT_REQ_DL, DS, and DLS. */
3307 merge_unit_reqs (unit_req_table reqs
)
3310 for (side
= 0; side
< 2; side
++)
3312 int d
= reqs
[side
][UNIT_REQ_D
];
3313 int l
= reqs
[side
][UNIT_REQ_L
];
3314 int s
= reqs
[side
][UNIT_REQ_S
];
3315 int dl
= reqs
[side
][UNIT_REQ_DL
];
3316 int ls
= reqs
[side
][UNIT_REQ_LS
];
3317 int ds
= reqs
[side
][UNIT_REQ_DS
];
3319 reqs
[side
][UNIT_REQ_DL
] += d
;
3320 reqs
[side
][UNIT_REQ_DL
] += l
;
3321 reqs
[side
][UNIT_REQ_DS
] += d
;
3322 reqs
[side
][UNIT_REQ_DS
] += s
;
3323 reqs
[side
][UNIT_REQ_LS
] += l
;
3324 reqs
[side
][UNIT_REQ_LS
] += s
;
3325 reqs
[side
][UNIT_REQ_DLS
] += ds
+ dl
+ ls
+ d
+ l
+ s
;
3329 /* Examine the table REQS and return a measure of unit imbalance by comparing
3330 the two sides of the machine. If, for example, D1 is used twice and D2
3331 used not at all, the return value should be 1 in the absence of other
3334 unit_req_imbalance (unit_req_table reqs
)
3339 for (i
= 0; i
< UNIT_REQ_MAX
; i
++)
3341 int factor
= unit_req_factor ((enum unitreqs
) i
);
3342 int diff
= abs (reqs
[0][i
] - reqs
[1][i
]);
3343 val
+= (diff
+ factor
- 1) / factor
/ 2;
3348 /* Return the resource-constrained minimum iteration interval given the
3349 data in the REQS table. This must have been processed with
3350 merge_unit_reqs already. */
3352 res_mii (unit_req_table reqs
)
3356 for (side
= 0; side
< 2; side
++)
3357 for (req
= 0; req
< UNIT_REQ_MAX
; req
++)
3359 int factor
= unit_req_factor ((enum unitreqs
) req
);
3360 worst
= MAX ((reqs
[side
][UNIT_REQ_D
] + factor
- 1) / factor
, worst
);
3366 /* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3367 the operands that are involved in the (up to) two reservations, as
3368 found by get_unit_reqs. Return true if we did this successfully, false
3369 if we couldn't identify what to do with INSN. */
3371 get_unit_operand_masks (rtx_insn
*insn
, unsigned int *pmask1
,
3372 unsigned int *pmask2
)
3374 enum attr_op_pattern op_pat
;
3376 if (recog_memoized (insn
) < 0)
3378 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
)
3380 extract_insn (insn
);
3381 op_pat
= get_attr_op_pattern (insn
);
3382 if (op_pat
== OP_PATTERN_DT
)
3384 gcc_assert (recog_data
.n_operands
== 2);
3389 else if (op_pat
== OP_PATTERN_TD
)
3391 gcc_assert (recog_data
.n_operands
== 2);
3396 else if (op_pat
== OP_PATTERN_SXS
)
3398 gcc_assert (recog_data
.n_operands
== 3);
3399 *pmask1
= (1 << 0) | (1 << 2);
3403 else if (op_pat
== OP_PATTERN_SX
)
3405 gcc_assert (recog_data
.n_operands
== 2);
3410 else if (op_pat
== OP_PATTERN_SSX
)
3412 gcc_assert (recog_data
.n_operands
== 3);
3413 *pmask1
= (1 << 0) | (1 << 1);
3420 /* Try to replace a register in INSN, which has corresponding rename info
3421 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3422 about the operands that must be renamed and the side they are on.
3423 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3424 We recompute this information locally after our transformation, and keep
3425 it only if we managed to improve the balance. */
3427 try_rename_operands (rtx_insn
*head
, rtx_insn
*tail
, unit_req_table reqs
,
3429 insn_rr_info
*info
, unsigned int op_mask
, int orig_side
)
3431 enum reg_class super_class
= orig_side
== 0 ? B_REGS
: A_REGS
;
3432 HARD_REG_SET unavailable
;
3433 du_head_p this_head
;
3434 struct du_chain
*chain
;
3437 int best_reg
, old_reg
;
3438 vec
<du_head_p
> involved_chains
= vNULL
;
3439 unit_req_table new_reqs
;
3441 for (i
= 0, tmp_mask
= op_mask
; tmp_mask
; i
++)
3444 if ((tmp_mask
& (1 << i
)) == 0)
3446 if (info
->op_info
[i
].n_chains
!= 1)
3448 op_chain
= regrename_chain_from_id (info
->op_info
[i
].heads
[0]->id
);
3449 involved_chains
.safe_push (op_chain
);
3450 tmp_mask
&= ~(1 << i
);
3453 if (involved_chains
.length () > 1)
3456 this_head
= involved_chains
[0];
3457 if (this_head
->cannot_rename
)
3460 for (chain
= this_head
->first
; chain
; chain
= chain
->next_use
)
3462 unsigned int mask1
, mask2
, mask_changed
;
3463 int count
, side1
, side2
, req1
, req2
;
3464 insn_rr_info
*this_rr
= &insn_rr
[INSN_UID (chain
->insn
)];
3466 count
= get_unit_reqs (chain
->insn
, &req1
, &side1
, &req2
, &side2
);
3471 if (!get_unit_operand_masks (chain
->insn
, &mask1
, &mask2
))
3474 extract_insn (chain
->insn
);
3477 for (i
= 0; i
< recog_data
.n_operands
; i
++)
3480 int n_this_op
= this_rr
->op_info
[i
].n_chains
;
3481 for (j
= 0; j
< n_this_op
; j
++)
3483 du_head_p other
= this_rr
->op_info
[i
].heads
[j
];
3484 if (regrename_chain_from_id (other
->id
) == this_head
)
3492 mask_changed
|= 1 << i
;
3494 gcc_assert (mask_changed
!= 0);
3495 if (mask_changed
!= mask1
&& mask_changed
!= mask2
)
3499 /* If we get here, we can do the renaming. */
3500 COMPL_HARD_REG_SET (unavailable
, reg_class_contents
[(int) super_class
]);
3502 old_reg
= this_head
->regno
;
3503 best_reg
= find_best_rename_reg (this_head
, super_class
, &unavailable
, old_reg
);
3505 regrename_do_replace (this_head
, best_reg
);
3507 count_unit_reqs (new_reqs
, head
, PREV_INSN (tail
));
3508 merge_unit_reqs (new_reqs
);
3511 fprintf (dump_file
, "reshuffle for insn %d, op_mask %x, "
3512 "original side %d, new reg %d\n",
3513 INSN_UID (insn
), op_mask
, orig_side
, best_reg
);
3514 fprintf (dump_file
, " imbalance %d -> %d\n",
3515 unit_req_imbalance (reqs
), unit_req_imbalance (new_reqs
));
3517 if (unit_req_imbalance (new_reqs
) > unit_req_imbalance (reqs
))
3518 regrename_do_replace (this_head
, old_reg
);
3520 memcpy (reqs
, new_reqs
, sizeof (unit_req_table
));
3523 involved_chains
.release ();
3526 /* Find insns in LOOP which would, if shifted to the other side
3527 of the machine, reduce an imbalance in the unit reservations. */
3529 reshuffle_units (basic_block loop
)
3531 rtx_insn
*head
= BB_HEAD (loop
);
3532 rtx_insn
*tail
= BB_END (loop
);
3534 unit_req_table reqs
;
3539 count_unit_reqs (reqs
, head
, PREV_INSN (tail
));
3540 merge_unit_reqs (reqs
);
3542 regrename_init (true);
3544 bitmap_initialize (&bbs
, &bitmap_default_obstack
);
3546 FOR_EACH_EDGE (e
, ei
, loop
->preds
)
3547 bitmap_set_bit (&bbs
, e
->src
->index
);
3549 bitmap_set_bit (&bbs
, loop
->index
);
3550 regrename_analyze (&bbs
);
3552 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3554 enum attr_units units
;
3555 int count
, side1
, side2
, req1
, req2
;
3556 unsigned int mask1
, mask2
;
3559 if (!NONDEBUG_INSN_P (insn
))
3562 count
= get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
);
3567 if (!get_unit_operand_masks (insn
, &mask1
, &mask2
))
3570 info
= &insn_rr
[INSN_UID (insn
)];
3571 if (info
->op_info
== NULL
)
3574 if (reqs
[side1
][req1
] > 1
3575 && reqs
[side1
][req1
] > 2 * reqs
[side1
^ 1][req1
])
3577 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask1
, side1
);
3580 units
= get_attr_units (insn
);
3581 if (units
== UNITS_D_ADDR
)
3583 gcc_assert (count
== 2);
3584 if (reqs
[side2
][req2
] > 1
3585 && reqs
[side2
][req2
] > 2 * reqs
[side2
^ 1][req2
])
3587 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask2
, side2
);
3591 regrename_finish ();
3594 /* Backend scheduling state. */
3595 typedef struct c6x_sched_context
3597 /* The current scheduler clock, saved in the sched_reorder hook. */
3598 int curr_sched_clock
;
3600 /* Number of insns issued so far in this cycle. */
3601 int issued_this_cycle
;
3603 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3604 theoretical maximum for number of jumps in flight is 12: 2 every
3605 cycle, with a latency of 6 cycles each. This is a circular
3606 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3607 jumps have a higher index. This array should be accessed through
3608 the jump_cycle function. */
3609 int jump_cycles
[12];
3610 int jump_cycle_index
;
3612 /* In parallel with jump_cycles, this array records the opposite of
3613 the condition used in each pending jump. This is used to
3614 predicate insns that are scheduled in the jump's delay slots. If
3615 this is NULL_RTX no such predication happens. */
3618 /* Similar to the jump_cycles mechanism, but here we take into
3619 account all insns with delay slots, to avoid scheduling asms into
3621 int delays_finished_at
;
3623 /* The following variable value is the last issued insn. */
3624 rtx_insn
*last_scheduled_insn
;
3625 /* The last issued insn that isn't a shadow of another. */
3626 rtx_insn
*last_scheduled_iter0
;
3628 /* The following variable value is DFA state before issuing the
3629 first insn in the current clock cycle. We do not use this member
3630 of the structure directly; we copy the data in and out of
3631 prev_cycle_state. */
3632 state_t prev_cycle_state_ctx
;
3634 int reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3635 int reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3636 int reg_set_in_cycle
[FIRST_PSEUDO_REGISTER
];
3638 int tmp_reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3639 int tmp_reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3640 } *c6x_sched_context_t
;
3642 /* The current scheduling state. */
3643 static struct c6x_sched_context ss
;
3645 /* The following variable value is DFA state before issuing the first insn
3646 in the current clock cycle. This is used in c6x_variable_issue for
3647 comparison with the state after issuing the last insn in a cycle. */
3648 static state_t prev_cycle_state
;
3650 /* Set when we discover while processing an insn that it would lead to too
3651 many accesses of the same register. */
3652 static bool reg_access_stall
;
3654 /* The highest insn uid after delayed insns were split, but before loop bodies
3655 were copied by the modulo scheduling code. */
3656 static int sploop_max_uid_iter0
;
3658 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3659 so the caller does not specifically have to test for it. */
3661 get_jump_cycle (int n
)
3665 n
+= ss
.jump_cycle_index
;
3668 return ss
.jump_cycles
[n
];
3671 /* Look up the jump condition with index N. */
3673 get_jump_cond (int n
)
3677 n
+= ss
.jump_cycle_index
;
3680 return ss
.jump_cond
[n
];
3683 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3684 has delay slots beyond CLOCK_VAR, return -1. */
3686 first_jump_index (int clock_var
)
3692 int t
= get_jump_cycle (n
);
3701 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3702 and has the opposite condition of COND. */
3704 record_jump (int cycle
, rtx cond
)
3706 if (ss
.jump_cycle_index
== 0)
3707 ss
.jump_cycle_index
= 11;
3709 ss
.jump_cycle_index
--;
3710 ss
.jump_cycles
[ss
.jump_cycle_index
] = cycle
;
3711 ss
.jump_cond
[ss
.jump_cycle_index
] = cond
;
3714 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3717 insn_set_clock (rtx insn
, int cycle
)
3719 unsigned uid
= INSN_UID (insn
);
3721 if (uid
>= INSN_INFO_LENGTH
)
3722 insn_info
.safe_grow (uid
* 5 / 4 + 10);
3724 INSN_INFO_ENTRY (uid
).clock
= cycle
;
3725 INSN_INFO_ENTRY (uid
).new_cond
= NULL
;
3726 INSN_INFO_ENTRY (uid
).reservation
= 0;
3727 INSN_INFO_ENTRY (uid
).ebb_start
= false;
3730 /* Return the clock cycle we set for the insn with uid UID. */
3732 insn_uid_get_clock (int uid
)
3734 return INSN_INFO_ENTRY (uid
).clock
;
3737 /* Return the clock cycle we set for INSN. */
3739 insn_get_clock (rtx insn
)
3741 return insn_uid_get_clock (INSN_UID (insn
));
3744 /* Examine INSN, and if it is a conditional jump of any kind, return
3745 the opposite of the condition in which it branches. Otherwise,
3748 condjump_opposite_condition (rtx insn
)
3750 rtx pat
= PATTERN (insn
);
3751 int icode
= INSN_CODE (insn
);
3754 if (icode
== CODE_FOR_br_true
|| icode
== CODE_FOR_br_false
)
3756 x
= XEXP (SET_SRC (pat
), 0);
3757 if (icode
== CODE_FOR_br_false
)
3760 if (GET_CODE (pat
) == COND_EXEC
)
3762 rtx t
= COND_EXEC_CODE (pat
);
3763 if ((GET_CODE (t
) == PARALLEL
3764 && GET_CODE (XVECEXP (t
, 0, 0)) == RETURN
)
3765 || (GET_CODE (t
) == UNSPEC
&& XINT (t
, 1) == UNSPEC_REAL_JUMP
)
3766 || (GET_CODE (t
) == SET
&& SET_DEST (t
) == pc_rtx
))
3767 x
= COND_EXEC_TEST (pat
);
3772 enum rtx_code code
= GET_CODE (x
);
3773 x
= gen_rtx_fmt_ee (code
== EQ
? NE
: EQ
,
3774 GET_MODE (x
), XEXP (x
, 0),
3780 /* Return true iff COND1 and COND2 are exactly opposite conditions
3781 one of them NE and the other EQ. */
3783 conditions_opposite_p (rtx cond1
, rtx cond2
)
3785 return (rtx_equal_p (XEXP (cond1
, 0), XEXP (cond2
, 0))
3786 && rtx_equal_p (XEXP (cond1
, 1), XEXP (cond2
, 1))
3787 && GET_CODE (cond1
) == reverse_condition (GET_CODE (cond2
)));
3790 /* Return true if we can add a predicate COND to INSN, or if INSN
3791 already has that predicate. If DOIT is true, also perform the
3794 predicate_insn (rtx_insn
*insn
, rtx cond
, bool doit
)
3797 if (cond
== NULL_RTX
)
3803 if (get_attr_predicable (insn
) == PREDICABLE_YES
3804 && GET_CODE (PATTERN (insn
)) != COND_EXEC
)
3808 rtx newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3809 PATTERN (insn
) = newpat
;
3810 INSN_CODE (insn
) = -1;
3814 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
3815 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn
)), cond
))
3817 icode
= INSN_CODE (insn
);
3818 if (icode
== CODE_FOR_real_jump
3819 || icode
== CODE_FOR_jump
3820 || icode
== CODE_FOR_indirect_jump
)
3822 rtx pat
= PATTERN (insn
);
3823 rtx dest
= (icode
== CODE_FOR_real_jump
? XVECEXP (pat
, 0, 0)
3824 : icode
== CODE_FOR_jump
? XEXP (SET_SRC (pat
), 0)
3830 newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3832 newpat
= gen_br_true (cond
, XEXP (cond
, 0), dest
);
3833 PATTERN (insn
) = newpat
;
3834 INSN_CODE (insn
) = -1;
3838 if (INSN_CODE (insn
) == CODE_FOR_br_true
)
3840 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3841 return rtx_equal_p (br_cond
, cond
);
3843 if (INSN_CODE (insn
) == CODE_FOR_br_false
)
3845 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3846 return conditions_opposite_p (br_cond
, cond
);
3851 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3853 init_sched_state (c6x_sched_context_t sc
)
3855 sc
->last_scheduled_insn
= NULL
;
3856 sc
->last_scheduled_iter0
= NULL
;
3857 sc
->issued_this_cycle
= 0;
3858 memset (sc
->jump_cycles
, 0, sizeof sc
->jump_cycles
);
3859 memset (sc
->jump_cond
, 0, sizeof sc
->jump_cond
);
3860 sc
->jump_cycle_index
= 0;
3861 sc
->delays_finished_at
= 0;
3862 sc
->curr_sched_clock
= 0;
3864 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3866 memset (sc
->reg_n_accesses
, 0, sizeof sc
->reg_n_accesses
);
3867 memset (sc
->reg_n_xaccesses
, 0, sizeof sc
->reg_n_xaccesses
);
3868 memset (sc
->reg_set_in_cycle
, 0, sizeof sc
->reg_set_in_cycle
);
3870 state_reset (sc
->prev_cycle_state_ctx
);
3873 /* Allocate store for new scheduling context. */
3875 c6x_alloc_sched_context (void)
3877 return xmalloc (sizeof (struct c6x_sched_context
));
3880 /* If CLEAN_P is true then initializes _SC with clean data,
3881 and from the global context otherwise. */
3883 c6x_init_sched_context (void *_sc
, bool clean_p
)
3885 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3889 init_sched_state (sc
);
3894 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3895 memcpy (sc
->prev_cycle_state_ctx
, prev_cycle_state
, dfa_state_size
);
3899 /* Sets the global scheduling context to the one pointed to by _SC. */
3901 c6x_set_sched_context (void *_sc
)
3903 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3905 gcc_assert (sc
!= NULL
);
3907 memcpy (prev_cycle_state
, sc
->prev_cycle_state_ctx
, dfa_state_size
);
3910 /* Clear data in _SC. */
3912 c6x_clear_sched_context (void *_sc
)
3914 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3915 gcc_assert (_sc
!= NULL
);
3917 free (sc
->prev_cycle_state_ctx
);
3922 c6x_free_sched_context (void *_sc
)
3927 /* True if we are currently performing a preliminary scheduling
3928 pass before modulo scheduling; we can't allow the scheduler to
3929 modify instruction patterns using packetization assumptions,
3930 since there will be another scheduling pass later if modulo
3931 scheduling fails. */
3932 static bool in_hwloop
;
3934 /* Provide information about speculation capabilities, and set the
3935 DO_BACKTRACKING flag. */
3937 c6x_set_sched_flags (spec_info_t spec_info
)
3939 unsigned int *flags
= &(current_sched_info
->flags
);
3941 if (*flags
& SCHED_EBB
)
3943 *flags
|= DO_BACKTRACKING
| DO_PREDICATION
;
3946 *flags
|= DONT_BREAK_DEPENDENCIES
;
3948 spec_info
->mask
= 0;
3951 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3954 c6x_issue_rate (void)
3959 /* Used together with the collapse_ndfa option, this ensures that we reach a
3960 deterministic automaton state before trying to advance a cycle.
3961 With collapse_ndfa, genautomata creates advance cycle arcs only for
3962 such deterministic states. */
3965 c6x_sched_dfa_pre_cycle_insn (void)
3970 /* We're beginning a new block. Initialize data structures as necessary. */
3973 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED
,
3974 int sched_verbose ATTRIBUTE_UNUSED
,
3975 int max_ready ATTRIBUTE_UNUSED
)
3977 if (prev_cycle_state
== NULL
)
3979 prev_cycle_state
= xmalloc (dfa_state_size
);
3981 init_sched_state (&ss
);
3982 state_reset (prev_cycle_state
);
3985 /* We are about to being issuing INSN. Return nonzero if we cannot
3986 issue it on given cycle CLOCK and return zero if we should not sort
3987 the ready queue on the next clock start.
3988 For C6X, we use this function just to copy the previous DFA state
3989 for comparison purposes. */
3992 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED
, int verbose ATTRIBUTE_UNUSED
,
3993 rtx_insn
*insn ATTRIBUTE_UNUSED
,
3994 int last_clock ATTRIBUTE_UNUSED
,
3995 int clock ATTRIBUTE_UNUSED
, int *sort_p ATTRIBUTE_UNUSED
)
3997 if (clock
!= last_clock
)
3998 memcpy (prev_cycle_state
, curr_state
, dfa_state_size
);
4003 c6x_mark_regno_read (int regno
, bool cross
)
4005 int t
= ++ss
.tmp_reg_n_accesses
[regno
];
4008 reg_access_stall
= true;
4012 int set_cycle
= ss
.reg_set_in_cycle
[regno
];
4013 /* This must be done in this way rather than by tweaking things in
4014 adjust_cost, since the stall occurs even for insns with opposite
4015 predicates, and the scheduler may not even see a dependency. */
4016 if (set_cycle
> 0 && set_cycle
== ss
.curr_sched_clock
)
4017 reg_access_stall
= true;
4018 /* This doesn't quite do anything yet as we're only modeling one
4020 ++ss
.tmp_reg_n_xaccesses
[regno
];
4024 /* Note that REG is read in the insn being examined. If CROSS, it
4025 means the access is through a cross path. Update the temporary reg
4026 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4027 in the current cycle. */
4030 c6x_mark_reg_read (rtx reg
, bool cross
)
4032 unsigned regno
= REGNO (reg
);
4033 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4036 c6x_mark_regno_read (regno
+ nregs
, cross
);
4039 /* Note that register REG is written in cycle CYCLES. */
4042 c6x_mark_reg_written (rtx reg
, int cycles
)
4044 unsigned regno
= REGNO (reg
);
4045 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4048 ss
.reg_set_in_cycle
[regno
+ nregs
] = cycles
;
4051 /* Update the register state information for an instruction whose
4052 body is X. Return true if the instruction has to be delayed until the
4056 c6x_registers_update (rtx_insn
*insn
)
4058 enum attr_cross cross
;
4059 enum attr_dest_regfile destrf
;
4063 if (!reload_completed
|| recog_memoized (insn
) < 0)
4066 reg_access_stall
= false;
4067 memcpy (ss
.tmp_reg_n_accesses
, ss
.reg_n_accesses
,
4068 sizeof ss
.tmp_reg_n_accesses
);
4069 memcpy (ss
.tmp_reg_n_xaccesses
, ss
.reg_n_xaccesses
,
4070 sizeof ss
.tmp_reg_n_xaccesses
);
4072 extract_insn (insn
);
4074 cross
= get_attr_cross (insn
);
4075 destrf
= get_attr_dest_regfile (insn
);
4077 nops
= recog_data
.n_operands
;
4079 if (GET_CODE (x
) == COND_EXEC
)
4081 c6x_mark_reg_read (XEXP (XEXP (x
, 0), 0), false);
4085 for (i
= 0; i
< nops
; i
++)
4087 rtx op
= recog_data
.operand
[i
];
4088 if (recog_data
.operand_type
[i
] == OP_OUT
)
4092 bool this_cross
= cross
;
4093 if (destrf
== DEST_REGFILE_A
&& A_REGNO_P (REGNO (op
)))
4095 if (destrf
== DEST_REGFILE_B
&& B_REGNO_P (REGNO (op
)))
4097 c6x_mark_reg_read (op
, this_cross
);
4099 else if (MEM_P (op
))
4102 switch (GET_CODE (op
))
4111 c6x_mark_reg_read (op
, false);
4116 gcc_assert (GET_CODE (op
) == PLUS
);
4119 c6x_mark_reg_read (XEXP (op
, 0), false);
4120 if (REG_P (XEXP (op
, 1)))
4121 c6x_mark_reg_read (XEXP (op
, 1), false);
4126 c6x_mark_regno_read (REG_B14
, false);
4132 else if (!CONSTANT_P (op
) && strlen (recog_data
.constraints
[i
]) > 0)
4135 return reg_access_stall
;
4138 /* Helper function for the TARGET_SCHED_REORDER and
4139 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4140 in the current cycle, move it down in the ready list and return the
4141 number of non-unsafe insns. */
4144 c6x_sched_reorder_1 (rtx_insn
**ready
, int *pn_ready
, int clock_var
)
4146 int n_ready
= *pn_ready
;
4147 rtx_insn
**e_ready
= ready
+ n_ready
;
4151 /* Keep track of conflicts due to a limit number of register accesses,
4152 and due to stalls incurred by too early accesses of registers using
4155 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4157 rtx_insn
*insn
= *insnp
;
4158 int icode
= recog_memoized (insn
);
4159 bool is_asm
= (icode
< 0
4160 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4161 || asm_noperands (PATTERN (insn
)) >= 0));
4162 bool no_parallel
= (is_asm
|| icode
== CODE_FOR_sploop
4164 && get_attr_type (insn
) == TYPE_ATOMIC
));
4166 /* We delay asm insns until all delay slots are exhausted. We can't
4167 accurately tell how many cycles an asm takes, and the main scheduling
4168 code always assumes at least 1 cycle, which may be wrong. */
4170 && (ss
.issued_this_cycle
> 0 || clock_var
< ss
.delays_finished_at
))
4171 || c6x_registers_update (insn
)
4172 || (ss
.issued_this_cycle
> 0 && icode
== CODE_FOR_sploop
))
4174 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4179 else if (shadow_p (insn
))
4181 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4186 /* Ensure that no other jump is scheduled in jump delay slots, since
4187 it would put the machine into the wrong state. Also, we must
4188 avoid scheduling insns that have a latency longer than the
4189 remaining jump delay slots, as the code at the jump destination
4190 won't be prepared for it.
4192 However, we can relax this condition somewhat. The rest of the
4193 scheduler will automatically avoid scheduling an insn on which
4194 the jump shadow depends so late that its side effect happens
4195 after the jump. This means that if we see an insn with a longer
4196 latency here, it can safely be scheduled if we can ensure that it
4197 has a predicate opposite of the previous jump: the side effect
4198 will happen in what we think of as the same basic block. In
4199 c6x_variable_issue, we will record the necessary predicate in
4200 new_conditions, and after scheduling is finished, we will modify
4203 Special care must be taken whenever there is more than one jump
4206 first_jump
= first_jump_index (clock_var
);
4207 if (first_jump
!= -1)
4209 int first_cycle
= get_jump_cycle (first_jump
);
4210 rtx first_cond
= get_jump_cond (first_jump
);
4211 int second_cycle
= 0;
4214 second_cycle
= get_jump_cycle (first_jump
- 1);
4216 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4218 rtx_insn
*insn
= *insnp
;
4219 int icode
= recog_memoized (insn
);
4220 bool is_asm
= (icode
< 0
4221 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4222 || asm_noperands (PATTERN (insn
)) >= 0));
4223 int this_cycles
, rsrv_cycles
;
4224 enum attr_type type
;
4226 gcc_assert (!is_asm
);
4229 this_cycles
= get_attr_cycles (insn
);
4230 rsrv_cycles
= get_attr_reserve_cycles (insn
);
4231 type
= get_attr_type (insn
);
4232 /* Treat branches specially; there is also a hazard if two jumps
4233 end at the same cycle. */
4234 if (type
== TYPE_BRANCH
|| type
== TYPE_CALL
)
4236 if (clock_var
+ this_cycles
<= first_cycle
)
4238 if ((first_jump
> 0 && clock_var
+ this_cycles
> second_cycle
)
4239 || clock_var
+ rsrv_cycles
> first_cycle
4240 || !predicate_insn (insn
, first_cond
, false))
4242 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4253 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4254 for later and clear the register access information for the new
4255 cycle. We also move asm statements out of the way if they would be
4256 scheduled in a delay slot. */
4259 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED
,
4260 int sched_verbose ATTRIBUTE_UNUSED
,
4261 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4262 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4264 ss
.curr_sched_clock
= clock_var
;
4265 ss
.issued_this_cycle
= 0;
4266 memset (ss
.reg_n_accesses
, 0, sizeof ss
.reg_n_accesses
);
4267 memset (ss
.reg_n_xaccesses
, 0, sizeof ss
.reg_n_xaccesses
);
4272 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4275 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4276 cycle for every insn. */
4279 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED
,
4280 int sched_verbose ATTRIBUTE_UNUSED
,
4281 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4282 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4284 /* FIXME: the assembler rejects labels inside an execute packet.
4285 This can occur if prologue insns are scheduled in parallel with
4286 others, so we avoid this here. Also make sure that nothing is
4287 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4288 if (RTX_FRAME_RELATED_P (ss
.last_scheduled_insn
)
4289 || JUMP_P (ss
.last_scheduled_insn
)
4290 || (recog_memoized (ss
.last_scheduled_insn
) >= 0
4291 && get_attr_type (ss
.last_scheduled_insn
) == TYPE_ATOMIC
))
4293 int n_ready
= *pn_ready
;
4294 rtx_insn
**e_ready
= ready
+ n_ready
;
4297 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4299 rtx_insn
*insn
= *insnp
;
4300 if (!shadow_p (insn
))
4302 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4311 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4314 /* Subroutine of maybe_clobber_cond, called through note_stores. */
4317 clobber_cond_1 (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
, void *data1
)
4319 rtx
*cond
= (rtx
*)data1
;
4320 if (*cond
!= NULL_RTX
&& reg_overlap_mentioned_p (x
, *cond
))
4324 /* Examine INSN, and if it destroys the conditions have recorded for
4325 any of the jumps in flight, clear that condition so that we don't
4326 predicate any more insns. CLOCK_VAR helps us limit the search to
4327 only those jumps which are still in flight. */
4330 maybe_clobber_cond (rtx insn
, int clock_var
)
4333 idx
= ss
.jump_cycle_index
;
4334 for (n
= 0; n
< 12; n
++, idx
++)
4341 cycle
= ss
.jump_cycles
[idx
];
4342 if (cycle
<= clock_var
)
4345 cond
= ss
.jump_cond
[idx
];
4346 if (cond
== NULL_RTX
)
4351 ss
.jump_cond
[idx
] = NULL_RTX
;
4355 note_stores (PATTERN (insn
), clobber_cond_1
, ss
.jump_cond
+ idx
);
4356 for (link
= REG_NOTES (insn
); link
; link
= XEXP (link
, 1))
4357 if (REG_NOTE_KIND (link
) == REG_INC
)
4358 clobber_cond_1 (XEXP (link
, 0), NULL_RTX
, ss
.jump_cond
+ idx
);
4362 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4363 issue INSN. Return the number of insns left on the ready queue
4364 that can be issued this cycle.
4365 We use this hook to record clock cycles and reservations for every insn. */
4368 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED
,
4369 int sched_verbose ATTRIBUTE_UNUSED
,
4370 rtx_insn
*insn
, int can_issue_more ATTRIBUTE_UNUSED
)
4372 ss
.last_scheduled_insn
= insn
;
4373 if (INSN_UID (insn
) < sploop_max_uid_iter0
&& !JUMP_P (insn
))
4374 ss
.last_scheduled_iter0
= insn
;
4375 if (GET_CODE (PATTERN (insn
)) != USE
&& GET_CODE (PATTERN (insn
)) != CLOBBER
)
4376 ss
.issued_this_cycle
++;
4377 if (insn_info
.exists ())
4379 state_t st_after
= alloca (dfa_state_size
);
4380 int curr_clock
= ss
.curr_sched_clock
;
4381 int uid
= INSN_UID (insn
);
4382 int icode
= recog_memoized (insn
);
4384 int first
, first_cycle
;
4388 insn_set_clock (insn
, curr_clock
);
4389 INSN_INFO_ENTRY (uid
).ebb_start
4390 = curr_clock
== 0 && ss
.issued_this_cycle
== 1;
4392 first
= first_jump_index (ss
.curr_sched_clock
);
4396 first_cond
= NULL_RTX
;
4400 first_cycle
= get_jump_cycle (first
);
4401 first_cond
= get_jump_cond (first
);
4404 && first_cycle
> curr_clock
4405 && first_cond
!= NULL_RTX
4406 && (curr_clock
+ get_attr_cycles (insn
) > first_cycle
4407 || get_attr_type (insn
) == TYPE_BRANCH
4408 || get_attr_type (insn
) == TYPE_CALL
))
4409 INSN_INFO_ENTRY (uid
).new_cond
= first_cond
;
4411 memcpy (st_after
, curr_state
, dfa_state_size
);
4412 state_transition (st_after
, const0_rtx
);
4415 for (i
= 0; i
< 2 * UNIT_QID_SIDE_OFFSET
; i
++)
4416 if (cpu_unit_reservation_p (st_after
, c6x_unit_codes
[i
])
4417 && !cpu_unit_reservation_p (prev_cycle_state
, c6x_unit_codes
[i
]))
4419 INSN_INFO_ENTRY (uid
).unit_mask
= mask
;
4421 maybe_clobber_cond (insn
, curr_clock
);
4427 c6x_registers_update (insn
);
4428 memcpy (ss
.reg_n_accesses
, ss
.tmp_reg_n_accesses
,
4429 sizeof ss
.reg_n_accesses
);
4430 memcpy (ss
.reg_n_xaccesses
, ss
.tmp_reg_n_accesses
,
4431 sizeof ss
.reg_n_xaccesses
);
4433 cycles
= get_attr_cycles (insn
);
4434 if (ss
.delays_finished_at
< ss
.curr_sched_clock
+ cycles
)
4435 ss
.delays_finished_at
= ss
.curr_sched_clock
+ cycles
;
4436 if (get_attr_type (insn
) == TYPE_BRANCH
4437 || get_attr_type (insn
) == TYPE_CALL
)
4439 rtx opposite
= condjump_opposite_condition (insn
);
4440 record_jump (ss
.curr_sched_clock
+ cycles
, opposite
);
4443 /* Mark the cycles in which the destination registers are written.
4444 This is used for calculating stalls when using cross units. */
4445 extract_insn (insn
);
4446 /* Cross-path stalls don't apply to results of load insns. */
4447 if (get_attr_type (insn
) == TYPE_LOAD
4448 || get_attr_type (insn
) == TYPE_LOADN
4449 || get_attr_type (insn
) == TYPE_LOAD_SHADOW
)
4451 for (i
= 0; i
< recog_data
.n_operands
; i
++)
4453 rtx op
= recog_data
.operand
[i
];
4456 rtx addr
= XEXP (op
, 0);
4457 if (GET_RTX_CLASS (GET_CODE (addr
)) == RTX_AUTOINC
)
4458 c6x_mark_reg_written (XEXP (addr
, 0),
4459 insn_uid_get_clock (uid
) + 1);
4461 if (recog_data
.operand_type
[i
] != OP_IN
4464 c6x_mark_reg_written (op
,
4465 insn_uid_get_clock (uid
) + cycles
);
4470 return can_issue_more
;
4473 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4474 anti- and output dependencies. */
4477 c6x_adjust_cost (rtx_insn
*insn
, rtx link
, rtx_insn
*dep_insn
, int cost
)
4479 enum attr_type insn_type
= TYPE_UNKNOWN
, dep_insn_type
= TYPE_UNKNOWN
;
4480 int dep_insn_code_number
, insn_code_number
;
4481 int shadow_bonus
= 0;
4483 dep_insn_code_number
= recog_memoized (dep_insn
);
4484 insn_code_number
= recog_memoized (insn
);
4486 if (dep_insn_code_number
>= 0)
4487 dep_insn_type
= get_attr_type (dep_insn
);
4489 if (insn_code_number
>= 0)
4490 insn_type
= get_attr_type (insn
);
4492 kind
= REG_NOTE_KIND (link
);
4495 /* If we have a dependency on a load, and it's not for the result of
4496 the load, it must be for an autoincrement. Reduce the cost in that
4498 if (dep_insn_type
== TYPE_LOAD
)
4500 rtx set
= PATTERN (dep_insn
);
4501 if (GET_CODE (set
) == COND_EXEC
)
4502 set
= COND_EXEC_CODE (set
);
4503 if (GET_CODE (set
) == UNSPEC
)
4507 gcc_assert (GET_CODE (set
) == SET
);
4508 if (!reg_overlap_mentioned_p (SET_DEST (set
), PATTERN (insn
)))
4514 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4515 it occurs in between two cycles, but we schedule it at the end of the
4517 if (shadow_type_p (insn_type
))
4520 /* Anti and output dependencies usually have zero cost, but we want
4521 to insert a stall after a jump, and after certain floating point
4522 insns that take more than one cycle to read their inputs. In the
4523 future, we should try to find a better algorithm for scheduling
4527 /* We can get anti-dependencies against shadow insns. Treat these
4528 like output dependencies, so that the insn is entirely finished
4529 before the branch takes place. */
4530 if (kind
== REG_DEP_ANTI
&& insn_type
== TYPE_SHADOW
)
4531 kind
= REG_DEP_OUTPUT
;
4532 switch (dep_insn_type
)
4538 if (get_attr_has_shadow (dep_insn
) == HAS_SHADOW_Y
)
4539 /* This is a real_jump/real_call insn. These don't have
4540 outputs, and ensuring the validity of scheduling things
4541 in the delay slot is the job of
4542 c6x_sched_reorder_1. */
4544 /* Unsplit calls can happen - e.g. for divide insns. */
4549 if (kind
== REG_DEP_OUTPUT
)
4550 return 5 - shadow_bonus
;
4554 if (kind
== REG_DEP_OUTPUT
)
4555 return 4 - shadow_bonus
;
4558 if (kind
== REG_DEP_OUTPUT
)
4559 return 2 - shadow_bonus
;
4562 if (kind
== REG_DEP_OUTPUT
)
4563 return 2 - shadow_bonus
;
4567 if (kind
== REG_DEP_OUTPUT
)
4568 return 7 - shadow_bonus
;
4571 if (kind
== REG_DEP_OUTPUT
)
4572 return 5 - shadow_bonus
;
4575 if (kind
== REG_DEP_OUTPUT
)
4576 return 9 - shadow_bonus
;
4580 if (kind
== REG_DEP_OUTPUT
)
4581 return 10 - shadow_bonus
;
4585 if (insn_type
== TYPE_SPKERNEL
)
4587 if (kind
== REG_DEP_OUTPUT
)
4588 return 1 - shadow_bonus
;
4594 return cost
- shadow_bonus
;
4597 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4598 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4599 first in the original stream. */
4602 gen_one_bundle (rtx_insn
**slot
, int n_filled
, int real_first
)
4609 seq
= gen_rtx_SEQUENCE (VOIDmode
, gen_rtvec_v (n_filled
, slot
));
4610 bundle
= make_insn_raw (seq
);
4611 BLOCK_FOR_INSN (bundle
) = BLOCK_FOR_INSN (slot
[0]);
4612 INSN_LOCATION (bundle
) = INSN_LOCATION (slot
[0]);
4613 SET_PREV_INSN (bundle
) = SET_PREV_INSN (slot
[real_first
]);
4617 for (i
= 0; i
< n_filled
; i
++)
4619 rtx_insn
*insn
= slot
[i
];
4621 SET_PREV_INSN (insn
) = t
? t
: PREV_INSN (bundle
);
4623 SET_NEXT_INSN (t
) = insn
;
4626 INSN_LOCATION (slot
[i
]) = INSN_LOCATION (bundle
);
4629 SET_NEXT_INSN (bundle
) = NEXT_INSN (PREV_INSN (bundle
));
4630 SET_NEXT_INSN (t
) = NEXT_INSN (bundle
);
4631 SET_NEXT_INSN (PREV_INSN (bundle
)) = bundle
;
4632 SET_PREV_INSN (NEXT_INSN (bundle
)) = bundle
;
4635 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4636 try to insert labels in the middle. */
4639 c6x_gen_bundles (void)
4642 rtx_insn
*insn
, *next
, *last_call
;
4644 FOR_EACH_BB_FN (bb
, cfun
)
4646 rtx_insn
*insn
, *next
;
4647 /* The machine is eight insns wide. We can have up to six shadow
4648 insns, plus an extra slot for merging the jump shadow. */
4653 for (insn
= BB_HEAD (bb
);; insn
= next
)
4656 rtx delete_this
= NULL_RTX
;
4658 if (NONDEBUG_INSN_P (insn
))
4660 /* Put calls at the start of the sequence. */
4666 memmove (&slot
[1], &slot
[0],
4667 n_filled
* sizeof (slot
[0]));
4669 if (!shadow_p (insn
))
4671 PUT_MODE (insn
, TImode
);
4673 PUT_MODE (slot
[1], VOIDmode
);
4680 slot
[n_filled
++] = insn
;
4684 next
= NEXT_INSN (insn
);
4685 while (next
&& insn
!= BB_END (bb
)
4686 && !(NONDEBUG_INSN_P (next
)
4687 && GET_CODE (PATTERN (next
)) != USE
4688 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4691 next
= NEXT_INSN (insn
);
4694 at_end
= insn
== BB_END (bb
);
4695 if (delete_this
== NULL_RTX
4696 && (at_end
|| (GET_MODE (next
) == TImode
4697 && !(shadow_p (next
) && CALL_P (next
)))))
4700 gen_one_bundle (slot
, n_filled
, first_slot
);
4709 /* Bundling, and emitting nops, can separate
4710 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4713 for (insn
= get_insns (); insn
; insn
= next
)
4715 next
= NEXT_INSN (insn
);
4717 || (INSN_P (insn
) && GET_CODE (PATTERN (insn
)) == SEQUENCE
4718 && CALL_P (XVECEXP (PATTERN (insn
), 0, 0))))
4720 if (!NOTE_P (insn
) || NOTE_KIND (insn
) != NOTE_INSN_CALL_ARG_LOCATION
)
4722 if (NEXT_INSN (last_call
) == insn
)
4724 SET_NEXT_INSN (PREV_INSN (insn
)) = NEXT_INSN (insn
);
4725 SET_PREV_INSN (NEXT_INSN (insn
)) = PREV_INSN (insn
);
4726 SET_PREV_INSN (insn
) = last_call
;
4727 SET_NEXT_INSN (insn
) = NEXT_INSN (last_call
);
4728 SET_PREV_INSN (NEXT_INSN (insn
)) = insn
;
4729 SET_NEXT_INSN (PREV_INSN (insn
)) = insn
;
4734 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4737 emit_nop_after (int cycles
, rtx after
)
4741 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4742 operation. We don't need the extra NOP since in this case, the hardware
4743 will automatically insert the required stall. */
4747 gcc_assert (cycles
< 10);
4749 insn
= emit_insn_after (gen_nop_count (GEN_INT (cycles
)), after
);
4750 PUT_MODE (insn
, TImode
);
4755 /* Determine whether INSN is a call that needs to have a return label
4759 returning_call_p (rtx_insn
*insn
)
4762 return (!SIBLING_CALL_P (insn
)
4763 && get_attr_type (insn
) != TYPE_CALLP
4764 && get_attr_type (insn
) != TYPE_SHADOW
);
4765 if (recog_memoized (insn
) < 0)
4767 if (get_attr_type (insn
) == TYPE_CALL
)
4772 /* Determine whether INSN's pattern can be converted to use callp. */
4774 can_use_callp (rtx_insn
*insn
)
4776 int icode
= recog_memoized (insn
);
4777 if (!TARGET_INSNS_64PLUS
4779 || GET_CODE (PATTERN (insn
)) == COND_EXEC
)
4782 return ((icode
== CODE_FOR_real_call
4783 || icode
== CODE_FOR_call_internal
4784 || icode
== CODE_FOR_call_value_internal
)
4785 && get_attr_dest_regfile (insn
) == DEST_REGFILE_ANY
);
4788 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4790 convert_to_callp (rtx_insn
*insn
)
4793 extract_insn (insn
);
4794 if (GET_CODE (PATTERN (insn
)) == SET
)
4796 rtx dest
= recog_data
.operand
[0];
4797 lab
= recog_data
.operand
[1];
4798 PATTERN (insn
) = gen_callp_value (dest
, lab
);
4799 INSN_CODE (insn
) = CODE_FOR_callp_value
;
4803 lab
= recog_data
.operand
[0];
4804 PATTERN (insn
) = gen_callp (lab
);
4805 INSN_CODE (insn
) = CODE_FOR_callp
;
4809 /* Scan forwards from INSN until we find the next insn that has mode TImode
4810 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4811 Return it if we find such an insn, NULL_RTX otherwise. */
4813 find_next_cycle_insn (rtx insn
, int clock
)
4816 if (GET_MODE (t
) == TImode
)
4817 t
= next_real_insn (t
);
4818 while (t
&& GET_MODE (t
) != TImode
)
4819 t
= next_real_insn (t
);
4821 if (t
&& insn_get_clock (t
) == clock
)
4826 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4827 around PAT. Return PAT either unchanged or modified in this
4830 duplicate_cond (rtx pat
, rtx cond_insn
)
4832 rtx cond_pat
= PATTERN (cond_insn
);
4833 if (GET_CODE (cond_pat
) == COND_EXEC
)
4834 pat
= gen_rtx_COND_EXEC (VOIDmode
, copy_rtx (COND_EXEC_TEST (cond_pat
)),
4839 /* Walk forward from INSN to find the last insn that issues in the same clock
4842 find_last_same_clock (rtx insn
)
4845 rtx_insn
*t
= next_real_insn (insn
);
4847 while (t
&& GET_MODE (t
) != TImode
)
4849 if (!DEBUG_INSN_P (t
) && recog_memoized (t
) >= 0)
4851 t
= next_real_insn (t
);
4856 /* For every call insn in the function, emit code to load the return
4857 address. For each call we create a return label and store it in
4858 CALL_LABELS. If are not scheduling, we emit the labels here,
4859 otherwise the caller will do it later.
4860 This function is called after final insn scheduling, but before creating
4861 the SEQUENCEs that represent execute packets. */
4864 reorg_split_calls (rtx
*call_labels
)
4866 unsigned int reservation_mask
= 0;
4867 rtx_insn
*insn
= get_insns ();
4868 gcc_assert (NOTE_P (insn
));
4869 insn
= next_real_insn (insn
);
4873 rtx_insn
*next
= next_real_insn (insn
);
4875 if (DEBUG_INSN_P (insn
))
4878 if (GET_MODE (insn
) == TImode
)
4879 reservation_mask
= 0;
4880 uid
= INSN_UID (insn
);
4881 if (c6x_flag_schedule_insns2
&& recog_memoized (insn
) >= 0)
4882 reservation_mask
|= 1 << INSN_INFO_ENTRY (uid
).reservation
;
4884 if (returning_call_p (insn
))
4886 rtx label
= gen_label_rtx ();
4887 rtx labelref
= gen_rtx_LABEL_REF (Pmode
, label
);
4888 rtx reg
= gen_rtx_REG (SImode
, RETURN_ADDR_REGNO
);
4890 LABEL_NUSES (label
) = 2;
4891 if (!c6x_flag_schedule_insns2
)
4893 if (can_use_callp (insn
))
4894 convert_to_callp (insn
);
4899 emit_label_after (label
, insn
);
4901 /* Bundle the call and its delay slots into a single
4902 SEQUENCE. While these do not issue in parallel
4903 we need to group them into a single EH region. */
4905 PUT_MODE (insn
, TImode
);
4906 if (TARGET_INSNS_64
)
4908 t
= gen_addkpc (reg
, labelref
, GEN_INT (4));
4909 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4911 PUT_MODE (slot
[1], TImode
);
4912 gen_one_bundle (slot
, 2, 0);
4916 slot
[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4918 PUT_MODE (slot
[3], TImode
);
4919 t
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4920 slot
[2] = emit_insn_after (duplicate_cond (t
, insn
),
4922 PUT_MODE (slot
[2], TImode
);
4923 t
= gen_movsi_high (reg
, labelref
);
4924 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4926 PUT_MODE (slot
[1], TImode
);
4927 gen_one_bundle (slot
, 4, 0);
4933 /* If we scheduled, we reserved the .S2 unit for one or two
4934 cycles after the call. Emit the insns in these slots,
4935 unless it's possible to create a CALLP insn.
4936 Note that this works because the dependencies ensure that
4937 no insn setting/using B3 is scheduled in the delay slots of
4939 int this_clock
= insn_get_clock (insn
);
4940 rtx last_same_clock
;
4943 call_labels
[INSN_UID (insn
)] = label
;
4945 last_same_clock
= find_last_same_clock (insn
);
4947 if (can_use_callp (insn
))
4949 /* Find the first insn of the next execute packet. If it
4950 is the shadow insn corresponding to this call, we may
4951 use a CALLP insn. */
4953 next_nonnote_nondebug_insn (last_same_clock
);
4956 && insn_get_clock (shadow
) == this_clock
+ 5)
4958 convert_to_callp (shadow
);
4959 insn_set_clock (shadow
, this_clock
);
4960 INSN_INFO_ENTRY (INSN_UID (shadow
)).reservation
4962 INSN_INFO_ENTRY (INSN_UID (shadow
)).unit_mask
4963 = INSN_INFO_ENTRY (INSN_UID (last_same_clock
)).unit_mask
;
4964 if (GET_MODE (insn
) == TImode
)
4966 rtx_insn
*new_cycle_first
= NEXT_INSN (insn
);
4967 while (!NONDEBUG_INSN_P (new_cycle_first
)
4968 || GET_CODE (PATTERN (new_cycle_first
)) == USE
4969 || GET_CODE (PATTERN (new_cycle_first
)) == CLOBBER
)
4970 new_cycle_first
= NEXT_INSN (new_cycle_first
);
4971 PUT_MODE (new_cycle_first
, TImode
);
4972 if (new_cycle_first
!= shadow
)
4973 PUT_MODE (shadow
, VOIDmode
);
4974 INSN_INFO_ENTRY (INSN_UID (new_cycle_first
)).ebb_start
4975 = INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
;
4978 PUT_MODE (shadow
, VOIDmode
);
4983 after1
= find_next_cycle_insn (last_same_clock
, this_clock
+ 1);
4984 if (after1
== NULL_RTX
)
4985 after1
= last_same_clock
;
4987 after1
= find_last_same_clock (after1
);
4988 if (TARGET_INSNS_64
)
4990 rtx x1
= gen_addkpc (reg
, labelref
, const0_rtx
);
4991 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
4992 insn_set_clock (x1
, this_clock
+ 1);
4993 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
4994 if (after1
== last_same_clock
)
4995 PUT_MODE (x1
, TImode
);
4997 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
4998 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5003 rtx after2
= find_next_cycle_insn (after1
, this_clock
+ 2);
5004 if (after2
== NULL_RTX
)
5006 x2
= gen_movsi_lo_sum (reg
, reg
, labelref
);
5007 x2
= emit_insn_after (duplicate_cond (x2
, insn
), after2
);
5008 x1
= gen_movsi_high (reg
, labelref
);
5009 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5010 insn_set_clock (x1
, this_clock
+ 1);
5011 insn_set_clock (x2
, this_clock
+ 2);
5012 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5013 INSN_INFO_ENTRY (INSN_UID (x2
)).reservation
= RESERVATION_S2
;
5014 if (after1
== last_same_clock
)
5015 PUT_MODE (x1
, TImode
);
5017 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5018 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5019 if (after1
== after2
)
5020 PUT_MODE (x2
, TImode
);
5022 INSN_INFO_ENTRY (INSN_UID (x2
)).unit_mask
5023 = INSN_INFO_ENTRY (INSN_UID (after2
)).unit_mask
;
5032 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
5033 insns as required for correctness. CALL_LABELS is the array that
5034 holds the return labels for call insns; we emit these here if
5035 scheduling was run earlier. */
5038 reorg_emit_nops (rtx
*call_labels
)
5043 int prev_clock
, earliest_bb_end
;
5044 int prev_implicit_nops
;
5045 rtx_insn
*insn
= get_insns ();
5047 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5048 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5049 clocks, we must insert a NOP.
5050 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5051 current basic block will finish. We must not allow the next basic block to
5052 begin before this cycle.
5053 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5054 a multi-cycle nop. The code is scheduled such that subsequent insns will
5055 show the cycle gap, but we needn't insert a real NOP instruction. */
5056 insn
= next_real_insn (insn
);
5057 last_call
= prev
= NULL
;
5059 earliest_bb_end
= 0;
5060 prev_implicit_nops
= 0;
5064 int this_clock
= -1;
5068 next
= next_real_insn (insn
);
5070 if (DEBUG_INSN_P (insn
)
5071 || GET_CODE (PATTERN (insn
)) == USE
5072 || GET_CODE (PATTERN (insn
)) == CLOBBER
5073 || shadow_or_blockage_p (insn
)
5074 || JUMP_TABLE_DATA_P (insn
))
5077 if (!c6x_flag_schedule_insns2
)
5078 /* No scheduling; ensure that no parallel issue happens. */
5079 PUT_MODE (insn
, TImode
);
5084 this_clock
= insn_get_clock (insn
);
5085 if (this_clock
!= prev_clock
)
5087 PUT_MODE (insn
, TImode
);
5091 cycles
= this_clock
- prev_clock
;
5093 cycles
-= prev_implicit_nops
;
5096 rtx nop
= emit_nop_after (cycles
- 1, prev
);
5097 insn_set_clock (nop
, prev_clock
+ prev_implicit_nops
+ 1);
5100 prev_clock
= this_clock
;
5103 && insn_get_clock (last_call
) + 6 <= this_clock
)
5105 emit_label_before (call_labels
[INSN_UID (last_call
)], insn
);
5106 last_call
= NULL_RTX
;
5108 prev_implicit_nops
= 0;
5112 /* Examine how many cycles the current insn takes, and adjust
5113 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5114 if (recog_memoized (insn
) >= 0
5115 /* If not scheduling, we've emitted NOPs after calls already. */
5116 && (c6x_flag_schedule_insns2
|| !returning_call_p (insn
)))
5118 max_cycles
= get_attr_cycles (insn
);
5119 if (get_attr_type (insn
) == TYPE_CALLP
)
5120 prev_implicit_nops
= 5;
5124 if (returning_call_p (insn
))
5127 if (c6x_flag_schedule_insns2
)
5129 gcc_assert (this_clock
>= 0);
5130 if (earliest_bb_end
< this_clock
+ max_cycles
)
5131 earliest_bb_end
= this_clock
+ max_cycles
;
5133 else if (max_cycles
> 1)
5134 emit_nop_after (max_cycles
- 1, insn
);
5140 if (c6x_flag_schedule_insns2
5141 && (next
== NULL_RTX
5142 || (GET_MODE (next
) == TImode
5143 && INSN_INFO_ENTRY (INSN_UID (next
)).ebb_start
))
5144 && earliest_bb_end
> 0)
5146 int cycles
= earliest_bb_end
- prev_clock
;
5149 prev
= emit_nop_after (cycles
- 1, prev
);
5150 insn_set_clock (prev
, prev_clock
+ prev_implicit_nops
+ 1);
5152 earliest_bb_end
= 0;
5157 emit_label_after (call_labels
[INSN_UID (last_call
)], prev
);
5158 last_call
= NULL_RTX
;
5164 /* If possible, split INSN, which we know is either a jump or a call, into a real
5165 insn and its shadow. */
5167 split_delayed_branch (rtx_insn
*insn
)
5169 int code
= recog_memoized (insn
);
5172 rtx pat
= PATTERN (insn
);
5174 if (GET_CODE (pat
) == COND_EXEC
)
5175 pat
= COND_EXEC_CODE (pat
);
5179 rtx src
= pat
, dest
= NULL_RTX
;
5181 if (GET_CODE (pat
) == SET
)
5183 dest
= SET_DEST (pat
);
5184 src
= SET_SRC (pat
);
5186 callee
= XEXP (XEXP (src
, 0), 0);
5187 if (SIBLING_CALL_P (insn
))
5190 newpat
= gen_indirect_sibcall_shadow ();
5192 newpat
= gen_sibcall_shadow (callee
);
5193 pat
= gen_real_jump (callee
);
5195 else if (dest
!= NULL_RTX
)
5198 newpat
= gen_indirect_call_value_shadow (dest
);
5200 newpat
= gen_call_value_shadow (dest
, callee
);
5201 pat
= gen_real_call (callee
);
5206 newpat
= gen_indirect_call_shadow ();
5208 newpat
= gen_call_shadow (callee
);
5209 pat
= gen_real_call (callee
);
5211 pat
= duplicate_cond (pat
, insn
);
5212 newpat
= duplicate_cond (newpat
, insn
);
5217 if (GET_CODE (pat
) == PARALLEL
5218 && GET_CODE (XVECEXP (pat
, 0, 0)) == RETURN
)
5220 newpat
= gen_return_shadow ();
5221 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5222 newpat
= duplicate_cond (newpat
, insn
);
5227 case CODE_FOR_br_true
:
5228 case CODE_FOR_br_false
:
5229 src
= SET_SRC (pat
);
5230 op
= XEXP (src
, code
== CODE_FOR_br_true
? 1 : 2);
5231 newpat
= gen_condjump_shadow (op
);
5232 pat
= gen_real_jump (op
);
5233 if (code
== CODE_FOR_br_true
)
5234 pat
= gen_rtx_COND_EXEC (VOIDmode
, XEXP (src
, 0), pat
);
5236 pat
= gen_rtx_COND_EXEC (VOIDmode
,
5237 reversed_comparison (XEXP (src
, 0),
5244 newpat
= gen_jump_shadow (op
);
5247 case CODE_FOR_indirect_jump
:
5248 newpat
= gen_indirect_jump_shadow ();
5251 case CODE_FOR_return_internal
:
5252 newpat
= gen_return_shadow ();
5253 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5260 i1
= emit_insn_before (pat
, insn
);
5261 PATTERN (insn
) = newpat
;
5262 INSN_CODE (insn
) = -1;
5263 record_delay_slot_pair (i1
, insn
, 5, 0);
5266 /* If INSN is a multi-cycle insn that should be handled properly in
5267 modulo-scheduling, split it into a real insn and a shadow.
5268 Return true if we made a change.
5270 It is valid for us to fail to split an insn; the caller has to deal
5271 with the possibility. Currently we handle loads and most mpy2 and
5274 split_delayed_nonbranch (rtx_insn
*insn
)
5276 int code
= recog_memoized (insn
);
5277 enum attr_type type
;
5279 rtx newpat
, src
, dest
;
5280 rtx pat
= PATTERN (insn
);
5284 if (GET_CODE (pat
) == COND_EXEC
)
5285 pat
= COND_EXEC_CODE (pat
);
5287 if (code
< 0 || GET_CODE (pat
) != SET
)
5289 src
= SET_SRC (pat
);
5290 dest
= SET_DEST (pat
);
5294 type
= get_attr_type (insn
);
5296 && (type
== TYPE_LOAD
5297 || type
== TYPE_LOADN
))
5300 && (GET_CODE (src
) != ZERO_EXTEND
5301 || !MEM_P (XEXP (src
, 0))))
5304 if (GET_MODE_SIZE (GET_MODE (dest
)) > 4
5305 && (GET_MODE_SIZE (GET_MODE (dest
)) != 8 || !TARGET_LDDW
))
5308 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5310 newpat
= gen_load_shadow (SET_DEST (pat
));
5311 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_LOAD
);
5315 && (type
== TYPE_MPY2
5316 || type
== TYPE_MPY4
))
5318 /* We don't handle floating point multiplies yet. */
5319 if (GET_MODE (dest
) == SFmode
)
5322 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5324 newpat
= gen_mult_shadow (SET_DEST (pat
));
5325 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_MULT
);
5326 delay
= type
== TYPE_MPY2
? 1 : 3;
5331 pat
= duplicate_cond (pat
, insn
);
5332 newpat
= duplicate_cond (newpat
, insn
);
5333 i1
= emit_insn_before (pat
, insn
);
5334 PATTERN (insn
) = newpat
;
5335 INSN_CODE (insn
) = -1;
5336 recog_memoized (insn
);
5337 recog_memoized (i1
);
5338 record_delay_slot_pair (i1
, insn
, delay
, 0);
5342 /* Examine if INSN is the result of splitting a load into a real load and a
5343 shadow, and if so, undo the transformation. */
5345 undo_split_delayed_nonbranch (rtx_insn
*insn
)
5347 int icode
= recog_memoized (insn
);
5348 enum attr_type type
;
5349 rtx prev_pat
, insn_pat
;
5354 type
= get_attr_type (insn
);
5355 if (type
!= TYPE_LOAD_SHADOW
&& type
!= TYPE_MULT_SHADOW
)
5357 prev
= PREV_INSN (insn
);
5358 prev_pat
= PATTERN (prev
);
5359 insn_pat
= PATTERN (insn
);
5360 if (GET_CODE (prev_pat
) == COND_EXEC
)
5362 prev_pat
= COND_EXEC_CODE (prev_pat
);
5363 insn_pat
= COND_EXEC_CODE (insn_pat
);
5366 gcc_assert (GET_CODE (prev_pat
) == UNSPEC
5367 && ((XINT (prev_pat
, 1) == UNSPEC_REAL_LOAD
5368 && type
== TYPE_LOAD_SHADOW
)
5369 || (XINT (prev_pat
, 1) == UNSPEC_REAL_MULT
5370 && type
== TYPE_MULT_SHADOW
)));
5371 insn_pat
= gen_rtx_SET (VOIDmode
, SET_DEST (insn_pat
),
5372 XVECEXP (prev_pat
, 0, 1));
5373 insn_pat
= duplicate_cond (insn_pat
, prev
);
5374 PATTERN (insn
) = insn_pat
;
5375 INSN_CODE (insn
) = -1;
5379 /* Split every insn (i.e. jumps and calls) which can have delay slots into
5380 two parts: the first one is scheduled normally and emits the instruction,
5381 while the second one is a shadow insn which shows the side effect taking
5382 place. The second one is placed in the right cycle by the scheduler, but
5383 not emitted as an assembly instruction. */
5386 split_delayed_insns (void)
5389 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5391 if (JUMP_P (insn
) || CALL_P (insn
))
5392 split_delayed_branch (insn
);
5396 /* For every insn that has an entry in the new_conditions vector, give it
5397 the appropriate predicate. */
5399 conditionalize_after_sched (void)
5403 FOR_EACH_BB_FN (bb
, cfun
)
5404 FOR_BB_INSNS (bb
, insn
)
5406 unsigned uid
= INSN_UID (insn
);
5408 if (!NONDEBUG_INSN_P (insn
) || uid
>= INSN_INFO_LENGTH
)
5410 cond
= INSN_INFO_ENTRY (uid
).new_cond
;
5411 if (cond
== NULL_RTX
)
5414 fprintf (dump_file
, "Conditionalizing insn %d\n", uid
);
5415 predicate_insn (insn
, cond
, true);
5419 /* A callback for the hw-doloop pass. This function examines INSN; if
5420 it is a loop_end pattern we recognize, return the reg rtx for the
5421 loop counter. Otherwise, return NULL_RTX. */
5424 hwloop_pattern_reg (rtx_insn
*insn
)
5428 if (!JUMP_P (insn
) || recog_memoized (insn
) != CODE_FOR_loop_end
)
5431 pat
= PATTERN (insn
);
5432 reg
= SET_DEST (XVECEXP (pat
, 0, 1));
5438 /* Return the number of cycles taken by BB, as computed by scheduling,
5439 including the latencies of all insns with delay slots. IGNORE is
5440 an insn we should ignore in the calculation, usually the final
5443 bb_earliest_end_cycle (basic_block bb
, rtx ignore
)
5448 FOR_BB_INSNS (bb
, insn
)
5450 int cycles
, this_clock
;
5452 if (LABEL_P (insn
) || NOTE_P (insn
) || DEBUG_INSN_P (insn
)
5453 || GET_CODE (PATTERN (insn
)) == USE
5454 || GET_CODE (PATTERN (insn
)) == CLOBBER
5458 this_clock
= insn_get_clock (insn
);
5459 cycles
= get_attr_cycles (insn
);
5461 if (earliest
< this_clock
+ cycles
)
5462 earliest
= this_clock
+ cycles
;
5467 /* Examine the insns in BB and remove all which have a uid greater or
5468 equal to MAX_UID. */
5470 filter_insns_above (basic_block bb
, int max_uid
)
5472 rtx_insn
*insn
, *next
;
5473 bool prev_ti
= false;
5474 int prev_cycle
= -1;
5476 FOR_BB_INSNS_SAFE (bb
, insn
, next
)
5479 if (!NONDEBUG_INSN_P (insn
))
5481 if (insn
== BB_END (bb
))
5483 this_cycle
= insn_get_clock (insn
);
5484 if (prev_ti
&& this_cycle
== prev_cycle
)
5486 gcc_assert (GET_MODE (insn
) != TImode
);
5487 PUT_MODE (insn
, TImode
);
5490 if (INSN_UID (insn
) >= max_uid
)
5492 if (GET_MODE (insn
) == TImode
)
5495 prev_cycle
= this_cycle
;
5502 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5505 c6x_asm_emit_except_personality (rtx personality
)
5507 fputs ("\t.personality\t", asm_out_file
);
5508 output_addr_const (asm_out_file
, personality
);
5509 fputc ('\n', asm_out_file
);
5512 /* Use a special assembly directive rather than a regular setion for
5513 unwind table data. */
5516 c6x_asm_init_sections (void)
5518 exception_section
= get_unnamed_section (0, output_section_asm_op
,
5522 /* A callback for the hw-doloop pass. Called to optimize LOOP in a
5523 machine-specific fashion; returns true if successful and false if
5524 the hwloop_fail function should be called. */
5527 hwloop_optimize (hwloop_info loop
)
5529 basic_block entry_bb
, bb
;
5530 rtx_insn
*seq
, *insn
, *prev
, *entry_after
, *end_packet
;
5531 rtx_insn
*head_insn
, *tail_insn
, *new_insns
, *last_insn
;
5533 int n_execute_packets
;
5536 int max_uid_before
, delayed_splits
;
5537 int i
, sp_ii
, min_ii
, max_ii
, max_parallel
, n_insns
, n_real_insns
, stages
;
5538 rtx_insn
**orig_vec
;
5540 rtx_insn
***insn_copies
;
5542 if (!c6x_flag_modulo_sched
|| !c6x_flag_schedule_insns2
5543 || !TARGET_INSNS_64PLUS
)
5546 if (loop
->iter_reg_used
|| loop
->depth
> 1)
5548 if (loop
->has_call
|| loop
->has_asm
)
5551 if (loop
->head
!= loop
->tail
)
5554 gcc_assert (loop
->incoming_dest
== loop
->head
);
5557 FOR_EACH_VEC_SAFE_ELT (loop
->incoming
, i
, entry_edge
)
5558 if (entry_edge
->flags
& EDGE_FALLTHRU
)
5560 if (entry_edge
== NULL
)
5563 reshuffle_units (loop
->head
);
5566 schedule_ebbs_init ();
5567 schedule_ebb (BB_HEAD (loop
->tail
), loop
->loop_end
, true);
5568 schedule_ebbs_finish ();
5572 loop_earliest
= bb_earliest_end_cycle (bb
, loop
->loop_end
) + 1;
5574 max_uid_before
= get_max_uid ();
5576 /* Split all multi-cycle operations, such as loads. For normal
5577 scheduling, we only do this for branches, as the generated code
5578 would otherwise not be interrupt-safe. When using sploop, it is
5579 safe and beneficial to split them. If any multi-cycle operations
5580 remain after splitting (because we don't handle them yet), we
5581 cannot pipeline the loop. */
5583 FOR_BB_INSNS (bb
, insn
)
5585 if (NONDEBUG_INSN_P (insn
))
5587 recog_memoized (insn
);
5588 if (split_delayed_nonbranch (insn
))
5590 else if (INSN_CODE (insn
) >= 0
5591 && get_attr_cycles (insn
) > 1)
5596 /* Count the number of insns as well as the number real insns, and save
5597 the original sequence of insns in case we must restore it later. */
5598 n_insns
= n_real_insns
= 0;
5599 FOR_BB_INSNS (bb
, insn
)
5602 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5605 orig_vec
= XNEWVEC (rtx_insn
*, n_insns
);
5607 FOR_BB_INSNS (bb
, insn
)
5608 orig_vec
[n_insns
++] = insn
;
5610 /* Count the unit reservations, and compute a minimum II from that
5612 count_unit_reqs (unit_reqs
, loop
->start_label
,
5613 PREV_INSN (loop
->loop_end
));
5614 merge_unit_reqs (unit_reqs
);
5616 min_ii
= res_mii (unit_reqs
);
5617 max_ii
= loop_earliest
< 15 ? loop_earliest
: 14;
5619 /* Make copies of the loop body, up to a maximum number of stages we want
5621 max_parallel
= loop_earliest
/ min_ii
+ 1;
5623 copies
= XCNEWVEC (rtx_insn
*, (max_parallel
+ 1) * n_real_insns
);
5624 insn_copies
= XNEWVEC (rtx_insn
**, max_parallel
+ 1);
5625 for (i
= 0; i
< max_parallel
+ 1; i
++)
5626 insn_copies
[i
] = copies
+ i
* n_real_insns
;
5628 head_insn
= next_nonnote_nondebug_insn (loop
->start_label
);
5629 tail_insn
= prev_real_insn (BB_END (bb
));
5632 FOR_BB_INSNS (bb
, insn
)
5633 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5634 insn_copies
[0][i
++] = insn
;
5636 sploop_max_uid_iter0
= get_max_uid ();
5638 /* Generate the copies of the loop body, and save them in the
5639 INSN_COPIES array. */
5641 for (i
= 0; i
< max_parallel
; i
++)
5644 rtx_insn
*this_iter
;
5646 this_iter
= duplicate_insn_chain (head_insn
, tail_insn
);
5650 rtx_insn
*prev_stage_insn
= insn_copies
[i
][j
];
5651 gcc_assert (INSN_CODE (this_iter
) == INSN_CODE (prev_stage_insn
));
5653 if (INSN_CODE (this_iter
) >= 0
5654 && (get_attr_type (this_iter
) == TYPE_LOAD_SHADOW
5655 || get_attr_type (this_iter
) == TYPE_MULT_SHADOW
))
5657 rtx_insn
*prev
= PREV_INSN (this_iter
);
5658 record_delay_slot_pair (prev
, this_iter
,
5659 get_attr_cycles (prev
) - 1, 0);
5662 record_delay_slot_pair (prev_stage_insn
, this_iter
, i
, 1);
5664 insn_copies
[i
+ 1][j
] = this_iter
;
5666 this_iter
= next_nonnote_nondebug_insn (this_iter
);
5669 new_insns
= get_insns ();
5670 last_insn
= insn_copies
[max_parallel
][n_real_insns
- 1];
5672 emit_insn_before (new_insns
, BB_END (bb
));
5674 /* Try to schedule the loop using varying initiation intervals,
5675 starting with the smallest possible and incrementing it
5677 for (sp_ii
= min_ii
; sp_ii
<= max_ii
; sp_ii
++)
5681 fprintf (dump_file
, "Trying to schedule for II %d\n", sp_ii
);
5683 df_clear_flags (DF_LR_RUN_DCE
);
5685 schedule_ebbs_init ();
5686 set_modulo_params (sp_ii
, max_parallel
, n_real_insns
,
5687 sploop_max_uid_iter0
);
5688 tmp_bb
= schedule_ebb (BB_HEAD (bb
), last_insn
, true);
5689 schedule_ebbs_finish ();
5694 fprintf (dump_file
, "Found schedule with II %d\n", sp_ii
);
5699 discard_delay_pairs_above (max_uid_before
);
5704 stages
= insn_get_clock (ss
.last_scheduled_iter0
) / sp_ii
+ 1;
5706 if (stages
== 1 && sp_ii
> 5)
5709 /* At this point, we know we've been successful, unless we find later that
5710 there are too many execute packets for the loop buffer to hold. */
5712 /* Assign reservations to the instructions in the loop. We must find
5713 the stage that contains the full loop kernel, and transfer the
5714 reservations of the instructions contained in it to the corresponding
5715 instructions from iteration 0, which are the only ones we'll keep. */
5716 assign_reservations (BB_HEAD (bb
), ss
.last_scheduled_insn
);
5717 SET_PREV_INSN (BB_END (bb
)) = ss
.last_scheduled_iter0
;
5718 SET_NEXT_INSN (ss
.last_scheduled_iter0
) = BB_END (bb
);
5719 filter_insns_above (bb
, sploop_max_uid_iter0
);
5721 for (i
= 0; i
< n_real_insns
; i
++)
5723 rtx insn
= insn_copies
[0][i
];
5724 int uid
= INSN_UID (insn
);
5725 int stage
= insn_uid_get_clock (uid
) / sp_ii
;
5727 if (stage
+ 1 < stages
)
5730 stage
= stages
- stage
- 1;
5731 copy_uid
= INSN_UID (insn_copies
[stage
][i
]);
5732 INSN_INFO_ENTRY (uid
).reservation
5733 = INSN_INFO_ENTRY (copy_uid
).reservation
;
5739 /* Compute the number of execute packets the pipelined form of the loop will
5742 n_execute_packets
= 0;
5743 for (insn
= loop
->start_label
;
5744 insn
!= loop
->loop_end
;
5745 insn
= NEXT_INSN (insn
))
5747 if (NONDEBUG_INSN_P (insn
) && GET_MODE (insn
) == TImode
5748 && !shadow_p (insn
))
5750 n_execute_packets
++;
5751 if (prev
&& insn_get_clock (prev
) + 1 != insn_get_clock (insn
))
5752 /* We need an extra NOP instruction. */
5753 n_execute_packets
++;
5759 end_packet
= ss
.last_scheduled_iter0
;
5760 while (!NONDEBUG_INSN_P (end_packet
) || GET_MODE (end_packet
) != TImode
)
5761 end_packet
= PREV_INSN (end_packet
);
5763 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5764 loop_earliest
= (stages
- 1) * sp_ii
;
5765 if (loop_earliest
> insn_get_clock (end_packet
))
5767 n_execute_packets
++;
5768 end_packet
= loop
->loop_end
;
5771 loop_earliest
= insn_get_clock (end_packet
);
5773 if (n_execute_packets
> 14)
5776 /* Generate the spkernel instruction, and place it at the appropriate
5778 PUT_MODE (end_packet
, VOIDmode
);
5780 insn
= emit_jump_insn_before (
5781 gen_spkernel (GEN_INT (stages
- 1),
5782 const0_rtx
, JUMP_LABEL (loop
->loop_end
)),
5784 JUMP_LABEL (insn
) = JUMP_LABEL (loop
->loop_end
);
5785 insn_set_clock (insn
, loop_earliest
);
5786 PUT_MODE (insn
, TImode
);
5787 INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
= false;
5788 delete_insn (loop
->loop_end
);
5790 /* Place the mvc and sploop instructions before the loop. */
5791 entry_bb
= entry_edge
->src
;
5795 insn
= emit_insn (gen_mvilc (loop
->iter_reg
));
5796 insn
= emit_insn (gen_sploop (GEN_INT (sp_ii
)));
5800 if (!single_succ_p (entry_bb
) || vec_safe_length (loop
->incoming
) > 1)
5806 emit_insn_before (seq
, BB_HEAD (loop
->head
));
5807 seq
= emit_label_before (gen_label_rtx (), seq
);
5809 new_bb
= create_basic_block (seq
, insn
, entry_bb
);
5810 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
5812 if (!(e
->flags
& EDGE_FALLTHRU
))
5813 redirect_edge_and_branch_force (e
, new_bb
);
5815 redirect_edge_succ (e
, new_bb
);
5817 make_edge (new_bb
, loop
->head
, 0);
5821 entry_after
= BB_END (entry_bb
);
5822 while (DEBUG_INSN_P (entry_after
)
5823 || (NOTE_P (entry_after
)
5824 && NOTE_KIND (entry_after
) != NOTE_INSN_BASIC_BLOCK
))
5825 entry_after
= PREV_INSN (entry_after
);
5826 emit_insn_after (seq
, entry_after
);
5831 /* Make sure we don't try to schedule this loop again. */
5832 for (ix
= 0; loop
->blocks
.iterate (ix
, &bb
); ix
++)
5833 bb
->flags
|= BB_DISABLE_SCHEDULE
;
5839 fprintf (dump_file
, "Unable to pipeline loop.\n");
5841 for (i
= 1; i
< n_insns
; i
++)
5843 SET_NEXT_INSN (orig_vec
[i
- 1]) = orig_vec
[i
];
5844 SET_PREV_INSN (orig_vec
[i
]) = orig_vec
[i
- 1];
5846 SET_PREV_INSN (orig_vec
[0]) = PREV_INSN (BB_HEAD (bb
));
5847 SET_NEXT_INSN (PREV_INSN (BB_HEAD (bb
))) = orig_vec
[0];
5848 SET_NEXT_INSN (orig_vec
[n_insns
- 1]) = NEXT_INSN (BB_END (bb
));
5849 SET_PREV_INSN (NEXT_INSN (BB_END (bb
))) = orig_vec
[n_insns
- 1];
5850 BB_HEAD (bb
) = orig_vec
[0];
5851 BB_END (bb
) = orig_vec
[n_insns
- 1];
5853 free_delay_pairs ();
5854 FOR_BB_INSNS (bb
, insn
)
5855 if (NONDEBUG_INSN_P (insn
))
5856 undo_split_delayed_nonbranch (insn
);
5860 /* A callback for the hw-doloop pass. Called when a loop we have discovered
5861 turns out not to be optimizable; we have to split the doloop_end pattern
5862 into a subtract and a test. */
5864 hwloop_fail (hwloop_info loop
)
5866 rtx insn
, test
, testreg
;
5869 fprintf (dump_file
, "splitting doloop insn %d\n",
5870 INSN_UID (loop
->loop_end
));
5871 insn
= gen_addsi3 (loop
->iter_reg
, loop
->iter_reg
, constm1_rtx
);
5872 /* See if we can emit the add at the head of the loop rather than at the
5874 if (loop
->head
== NULL
5875 || loop
->iter_reg_used_outside
5876 || loop
->iter_reg_used
5877 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REGNO (loop
->iter_reg
))
5878 || loop
->incoming_dest
!= loop
->head
5879 || EDGE_COUNT (loop
->head
->preds
) != 2)
5880 emit_insn_before (insn
, loop
->loop_end
);
5883 rtx_insn
*t
= loop
->start_label
;
5884 while (!NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_BASIC_BLOCK
)
5886 emit_insn_after (insn
, t
);
5889 testreg
= SET_DEST (XVECEXP (PATTERN (loop
->loop_end
), 0, 2));
5890 if (GET_CODE (testreg
) == SCRATCH
)
5891 testreg
= loop
->iter_reg
;
5893 emit_insn_before (gen_movsi (testreg
, loop
->iter_reg
), loop
->loop_end
);
5895 test
= gen_rtx_NE (VOIDmode
, testreg
, const0_rtx
);
5896 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
, testreg
, const0_rtx
,
5900 JUMP_LABEL (insn
) = loop
->start_label
;
5901 LABEL_NUSES (loop
->start_label
)++;
5902 delete_insn (loop
->loop_end
);
5905 static struct hw_doloop_hooks c6x_doloop_hooks
=
5912 /* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5913 doloop_end patterns where such optimizations are impossible. */
5918 reorg_loops (true, &c6x_doloop_hooks
);
5921 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5922 into a sequence that loads the return register and performs the call,
5923 and emit the return label.
5924 If scheduling after reload is requested, it happens here. */
5931 bool do_selsched
= (c6x_flag_schedule_insns2
&& flag_selective_scheduling2
5932 && !maybe_skip_selective_scheduling ());
5934 /* We are freeing block_for_insn in the toplev to keep compatibility
5935 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5936 compute_bb_for_insn ();
5938 df_clear_flags (DF_LR_RUN_DCE
);
5939 df_note_add_problem ();
5941 /* If optimizing, we'll have split before scheduling. */
5947 if (c6x_flag_schedule_insns2
)
5949 int sz
= get_max_uid () * 3 / 2 + 1;
5951 insn_info
.create (sz
);
5954 /* Make sure the real-jump insns we create are not deleted. When modulo-
5955 scheduling, situations where a reg is only stored in a loop can also
5956 cause dead code when doing the initial unrolling. */
5957 sched_no_dce
= true;
5961 if (c6x_flag_schedule_insns2
)
5963 split_delayed_insns ();
5964 timevar_push (TV_SCHED2
);
5966 run_selective_scheduling ();
5969 conditionalize_after_sched ();
5970 timevar_pop (TV_SCHED2
);
5972 free_delay_pairs ();
5974 sched_no_dce
= false;
5976 call_labels
= XCNEWVEC (rtx
, get_max_uid () + 1);
5978 reorg_split_calls (call_labels
);
5980 if (c6x_flag_schedule_insns2
)
5982 FOR_EACH_BB_FN (bb
, cfun
)
5983 if ((bb
->flags
& BB_DISABLE_SCHEDULE
) == 0)
5984 assign_reservations (BB_HEAD (bb
), BB_END (bb
));
5987 if (c6x_flag_var_tracking
)
5989 timevar_push (TV_VAR_TRACKING
);
5990 variable_tracking_main ();
5991 timevar_pop (TV_VAR_TRACKING
);
5994 reorg_emit_nops (call_labels
);
5996 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
5997 if (c6x_flag_schedule_insns2
)
5999 free_delay_pairs ();
6003 df_finish_pass (false);
6006 /* Called when a function has been assembled. It should perform all the
6007 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
6009 We free the reservation (and other scheduling) information here now that
6010 all insns have been output. */
6012 c6x_function_end (FILE *file
, const char *fname
)
6014 c6x_output_fn_unwind (file
);
6016 insn_info
.release ();
6018 if (!flag_inhibit_size_directive
)
6019 ASM_OUTPUT_MEASURED_SIZE (file
, fname
);
6022 /* Determine whether X is a shift with code CODE and an integer amount
6025 shift_p (rtx x
, enum rtx_code code
, int amount
)
6027 return (GET_CODE (x
) == code
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
6028 && INTVAL (XEXP (x
, 1)) == amount
);
6031 /* Compute a (partial) cost for rtx X. Return true if the complete
6032 cost has been computed, and false if subexpressions should be
6033 scanned. In either case, *TOTAL contains the cost result. */
6036 c6x_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
6039 int cost2
= COSTS_N_INSNS (1);
6045 if (outer_code
== SET
|| outer_code
== PLUS
)
6046 *total
= satisfies_constraint_IsB (x
) ? 0 : cost2
;
6047 else if (outer_code
== AND
|| outer_code
== IOR
|| outer_code
== XOR
6048 || outer_code
== MINUS
)
6049 *total
= satisfies_constraint_Is5 (x
) ? 0 : cost2
;
6050 else if (GET_RTX_CLASS (outer_code
) == RTX_COMPARE
6051 || GET_RTX_CLASS (outer_code
) == RTX_COMM_COMPARE
)
6052 *total
= satisfies_constraint_Iu4 (x
) ? 0 : cost2
;
6053 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
6054 || outer_code
== LSHIFTRT
)
6055 *total
= satisfies_constraint_Iu5 (x
) ? 0 : cost2
;
6064 *total
= COSTS_N_INSNS (2);
6068 /* Recognize a mult_highpart operation. */
6069 if ((GET_MODE (x
) == HImode
|| GET_MODE (x
) == SImode
)
6070 && GET_CODE (XEXP (x
, 0)) == LSHIFTRT
6071 && GET_MODE (XEXP (x
, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x
))
6072 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
6073 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
6074 && INTVAL (XEXP (XEXP (x
, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x
)))
6076 rtx mul
= XEXP (XEXP (x
, 0), 0);
6077 rtx op0
= XEXP (mul
, 0);
6078 rtx op1
= XEXP (mul
, 1);
6079 enum rtx_code code0
= GET_CODE (op0
);
6080 enum rtx_code code1
= GET_CODE (op1
);
6083 && (code0
== SIGN_EXTEND
|| code0
== ZERO_EXTEND
))
6084 || (GET_MODE (x
) == HImode
6085 && code0
== ZERO_EXTEND
&& code1
== SIGN_EXTEND
))
6087 if (GET_MODE (x
) == HImode
)
6088 *total
= COSTS_N_INSNS (2);
6090 *total
= COSTS_N_INSNS (12);
6091 *total
+= rtx_cost (XEXP (op0
, 0), code0
, 0, speed
);
6092 *total
+= rtx_cost (XEXP (op1
, 0), code1
, 0, speed
);
6101 if (GET_MODE (x
) == DImode
)
6102 *total
= COSTS_N_INSNS (CONSTANT_P (XEXP (x
, 1)) ? 4 : 15);
6104 *total
= COSTS_N_INSNS (1);
6109 *total
= COSTS_N_INSNS (1);
6110 op0
= code
== PLUS
? XEXP (x
, 0) : XEXP (x
, 1);
6111 op1
= code
== PLUS
? XEXP (x
, 1) : XEXP (x
, 0);
6112 if (GET_MODE_SIZE (GET_MODE (x
)) <= UNITS_PER_WORD
6113 && INTEGRAL_MODE_P (GET_MODE (x
))
6114 && GET_CODE (op0
) == MULT
6115 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
6116 && (INTVAL (XEXP (op0
, 1)) == 2
6117 || INTVAL (XEXP (op0
, 1)) == 4
6118 || (code
== PLUS
&& INTVAL (XEXP (op0
, 1)) == 8)))
6120 *total
+= rtx_cost (XEXP (op0
, 0), ASHIFT
, 0, speed
);
6121 *total
+= rtx_cost (op1
, (enum rtx_code
) code
, 1, speed
);
6129 if (GET_MODE (x
) == DFmode
)
6132 *total
= COSTS_N_INSNS (speed
? 10 : 1);
6134 *total
= COSTS_N_INSNS (speed
? 200 : 4);
6136 else if (GET_MODE (x
) == SFmode
)
6139 *total
= COSTS_N_INSNS (speed
? 4 : 1);
6141 *total
= COSTS_N_INSNS (speed
? 100 : 4);
6143 else if (GET_MODE (x
) == DImode
)
6146 && GET_CODE (op0
) == GET_CODE (op1
)
6147 && (GET_CODE (op0
) == ZERO_EXTEND
6148 || GET_CODE (op0
) == SIGN_EXTEND
))
6150 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6151 op0
= XEXP (op0
, 0);
6152 op1
= XEXP (op1
, 0);
6155 /* Maybe improve this laster. */
6156 *total
= COSTS_N_INSNS (20);
6158 else if (GET_MODE (x
) == SImode
)
6160 if (((GET_CODE (op0
) == ZERO_EXTEND
6161 || GET_CODE (op0
) == SIGN_EXTEND
6162 || shift_p (op0
, LSHIFTRT
, 16))
6163 && (GET_CODE (op1
) == SIGN_EXTEND
6164 || GET_CODE (op1
) == ZERO_EXTEND
6165 || scst5_operand (op1
, SImode
)
6166 || shift_p (op1
, ASHIFTRT
, 16)
6167 || shift_p (op1
, LSHIFTRT
, 16)))
6168 || (shift_p (op0
, ASHIFTRT
, 16)
6169 && (GET_CODE (op1
) == SIGN_EXTEND
6170 || shift_p (op1
, ASHIFTRT
, 16))))
6172 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6173 op0
= XEXP (op0
, 0);
6174 if (scst5_operand (op1
, SImode
))
6177 op1
= XEXP (op1
, 0);
6180 *total
= COSTS_N_INSNS (1);
6181 else if (TARGET_MPY32
)
6182 *total
= COSTS_N_INSNS (4);
6184 *total
= COSTS_N_INSNS (6);
6186 else if (GET_MODE (x
) == HImode
)
6187 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6189 if (GET_CODE (op0
) != REG
6190 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
6191 *total
+= rtx_cost (op0
, MULT
, 0, speed
);
6192 if (op1
&& GET_CODE (op1
) != REG
6193 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
6194 *total
+= rtx_cost (op1
, MULT
, 1, speed
);
6199 /* This is a bit random; assuming on average there'll be 16 leading
6200 zeros. FIXME: estimate better for constant dividends. */
6201 *total
= COSTS_N_INSNS (6 + 3 * 16);
6205 /* Recognize the cmp_and/ior patterns. */
6207 if ((GET_CODE (op0
) == EQ
|| GET_CODE (op0
) == NE
)
6208 && REG_P (XEXP (op0
, 0))
6209 && XEXP (op0
, 1) == const0_rtx
6210 && rtx_equal_p (XEXP (x
, 1), XEXP (op0
, 0)))
6212 *total
= rtx_cost (XEXP (x
, 1), (enum rtx_code
) outer_code
,
6223 /* Implements target hook vector_mode_supported_p. */
6226 c6x_vector_mode_supported_p (enum machine_mode mode
)
6241 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6242 static enum machine_mode
6243 c6x_preferred_simd_mode (enum machine_mode mode
)
6257 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6260 c6x_scalar_mode_supported_p (enum machine_mode mode
)
6262 if (ALL_FIXED_POINT_MODE_P (mode
)
6263 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
6266 return default_scalar_mode_supported_p (mode
);
6269 /* Output a reference from a function exception table to the type_info
6270 object X. Output these via a special assembly directive. */
6273 c6x_output_ttype (rtx x
)
6275 /* Use special relocations for symbol references. */
6276 if (GET_CODE (x
) != CONST_INT
)
6277 fputs ("\t.ehtype\t", asm_out_file
);
6279 fputs ("\t.word\t", asm_out_file
);
6280 output_addr_const (asm_out_file
, x
);
6281 fputc ('\n', asm_out_file
);
6286 /* Modify the return address of the current function. */
6289 c6x_set_return_address (rtx source
, rtx scratch
)
6291 struct c6x_frame frame
;
6293 HOST_WIDE_INT offset
;
6295 c6x_compute_frame_layout (&frame
);
6296 if (! c6x_save_reg (RETURN_ADDR_REGNO
))
6297 emit_move_insn (gen_rtx_REG (Pmode
, RETURN_ADDR_REGNO
), source
);
6301 if (frame_pointer_needed
)
6303 addr
= hard_frame_pointer_rtx
;
6304 offset
= frame
.b3_offset
;
6308 addr
= stack_pointer_rtx
;
6309 offset
= frame
.to_allocate
- frame
.b3_offset
;
6312 /* TODO: Use base+offset loads where possible. */
6315 HOST_WIDE_INT low
= trunc_int_for_mode (offset
, HImode
);
6317 emit_insn (gen_movsi_high (scratch
, GEN_INT (low
)));
6319 emit_insn (gen_movsi_lo_sum (scratch
, scratch
, GEN_INT(offset
)));
6320 emit_insn (gen_addsi3 (scratch
, addr
, scratch
));
6324 emit_move_insn (gen_frame_mem (Pmode
, addr
), source
);
6328 /* We save pairs of registers using a DImode store. Describe the component
6329 registers for DWARF generation code. */
6332 c6x_dwarf_register_span (rtx rtl
)
6335 unsigned real_regno
;
6340 regno
= REGNO (rtl
);
6341 nregs
= HARD_REGNO_NREGS (regno
, GET_MODE (rtl
));
6345 p
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc(nregs
));
6346 for (i
= 0; i
< nregs
; i
++)
6348 if (TARGET_BIG_ENDIAN
)
6349 real_regno
= regno
+ nregs
- (i
+ 1);
6351 real_regno
= regno
+ i
;
6353 XVECEXP (p
, 0, i
) = gen_rtx_REG (SImode
, real_regno
);
6359 /* Codes for all the C6X builtins. */
6394 static GTY(()) tree c6x_builtin_decls
[C6X_BUILTIN_MAX
];
6396 /* Return the C6X builtin for CODE. */
6398 c6x_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
6400 if (code
>= C6X_BUILTIN_MAX
)
6401 return error_mark_node
;
6403 return c6x_builtin_decls
[code
];
6406 #define def_builtin(NAME, TYPE, CODE) \
6409 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6411 c6x_builtin_decls[CODE] = bdecl; \
6414 /* Set up all builtin functions for this target. */
6416 c6x_init_builtins (void)
6418 tree V4QI_type_node
= build_vector_type (unsigned_intQI_type_node
, 4);
6419 tree V2HI_type_node
= build_vector_type (intHI_type_node
, 2);
6420 tree V2SI_type_node
= build_vector_type (intSI_type_node
, 2);
6422 = build_function_type_list (integer_type_node
, integer_type_node
,
6424 tree int_ftype_int_int
6425 = build_function_type_list (integer_type_node
, integer_type_node
,
6426 integer_type_node
, NULL_TREE
);
6427 tree v2hi_ftype_v2hi
6428 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
6429 tree v4qi_ftype_v4qi_v4qi
6430 = build_function_type_list (V4QI_type_node
, V4QI_type_node
,
6431 V4QI_type_node
, NULL_TREE
);
6432 tree v2hi_ftype_v2hi_v2hi
6433 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
6434 V2HI_type_node
, NULL_TREE
);
6435 tree v2si_ftype_v2hi_v2hi
6436 = build_function_type_list (V2SI_type_node
, V2HI_type_node
,
6437 V2HI_type_node
, NULL_TREE
);
6439 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int
,
6441 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int
,
6443 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi
,
6445 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi
,
6447 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi
,
6449 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi
,
6451 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi
,
6453 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi
,
6455 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi
,
6457 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi
,
6458 C6X_BUILTIN_SADDU4
);
6459 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi
,
6462 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int
,
6464 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int
,
6466 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int
,
6467 C6X_BUILTIN_SMPYHL
);
6468 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int
,
6469 C6X_BUILTIN_SMPYLH
);
6471 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int
,
6473 def_builtin ("__builtin_c6x_subc", int_ftype_int_int
,
6476 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi
,
6478 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi
,
6481 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int
,
6483 def_builtin ("__builtin_c6x_extr", int_ftype_int_int
,
6485 def_builtin ("__builtin_c6x_extru", int_ftype_int_int
,
6488 def_builtin ("__builtin_c6x_abs", int_ftype_int
, C6X_BUILTIN_ABS
);
6489 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi
, C6X_BUILTIN_ABS2
);
6493 struct builtin_description
6495 const enum insn_code icode
;
6496 const char *const name
;
6497 const enum c6x_builtins code
;
6500 static const struct builtin_description bdesc_2arg
[] =
6502 { CODE_FOR_saddsi3
, "__builtin_c6x_sadd", C6X_BUILTIN_SADD
},
6503 { CODE_FOR_ssubsi3
, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB
},
6504 { CODE_FOR_addv2hi3
, "__builtin_c6x_add2", C6X_BUILTIN_ADD2
},
6505 { CODE_FOR_subv2hi3
, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2
},
6506 { CODE_FOR_addv4qi3
, "__builtin_c6x_add4", C6X_BUILTIN_ADD4
},
6507 { CODE_FOR_subv4qi3
, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4
},
6508 { CODE_FOR_ss_addv2hi3
, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2
},
6509 { CODE_FOR_ss_subv2hi3
, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2
},
6510 { CODE_FOR_us_addv4qi3
, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4
},
6512 { CODE_FOR_subcsi3
, "__builtin_c6x_subc", C6X_BUILTIN_SUBC
},
6513 { CODE_FOR_ss_ashlsi3
, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL
},
6515 { CODE_FOR_avgv2hi3
, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2
},
6516 { CODE_FOR_uavgv4qi3
, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4
},
6518 { CODE_FOR_mulhqsq3
, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY
},
6519 { CODE_FOR_mulhqsq3_hh
, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH
},
6520 { CODE_FOR_mulhqsq3_lh
, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH
},
6521 { CODE_FOR_mulhqsq3_hl
, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL
},
6523 { CODE_FOR_mulv2hqv2sq3
, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2
},
6525 { CODE_FOR_clrr
, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR
},
6526 { CODE_FOR_extr
, "__builtin_c6x_extr", C6X_BUILTIN_EXTR
},
6527 { CODE_FOR_extru
, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU
}
6530 static const struct builtin_description bdesc_1arg
[] =
6532 { CODE_FOR_ssabssi2
, "__builtin_c6x_abs", C6X_BUILTIN_ABS
},
6533 { CODE_FOR_ssabsv2hi2
, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2
}
6536 /* Errors in the source file can cause expand_expr to return const0_rtx
6537 where we expect a vector. To avoid crashing, use one of the vector
6538 clear instructions. */
6540 safe_vector_operand (rtx x
, enum machine_mode mode
)
6542 if (x
!= const0_rtx
)
6544 x
= gen_reg_rtx (SImode
);
6546 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
6547 return gen_lowpart (mode
, x
);
6550 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6551 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6554 c6x_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
6557 int offs
= match_op
? 1 : 0;
6559 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6560 tree arg1
= CALL_EXPR_ARG (exp
, 1);
6561 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6562 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6563 enum machine_mode op0mode
= GET_MODE (op0
);
6564 enum machine_mode op1mode
= GET_MODE (op1
);
6565 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6566 enum machine_mode mode0
= insn_data
[icode
].operand
[1 + offs
].mode
;
6567 enum machine_mode mode1
= insn_data
[icode
].operand
[2 + offs
].mode
;
6570 if (VECTOR_MODE_P (mode0
))
6571 op0
= safe_vector_operand (op0
, mode0
);
6572 if (VECTOR_MODE_P (mode1
))
6573 op1
= safe_vector_operand (op1
, mode1
);
6576 || GET_MODE (target
) != tmode
6577 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6579 if (tmode
== SQmode
|| tmode
== V2SQmode
)
6581 ret
= gen_reg_rtx (tmode
== SQmode
? SImode
: V2SImode
);
6582 target
= gen_lowpart (tmode
, ret
);
6585 target
= gen_reg_rtx (tmode
);
6588 if ((op0mode
== V2HImode
|| op0mode
== SImode
|| op0mode
== VOIDmode
)
6589 && (mode0
== V2HQmode
|| mode0
== HQmode
|| mode0
== SQmode
))
6592 op0
= gen_lowpart (mode0
, op0
);
6594 if ((op1mode
== V2HImode
|| op1mode
== SImode
|| op1mode
== VOIDmode
)
6595 && (mode1
== V2HQmode
|| mode1
== HQmode
|| mode1
== SQmode
))
6598 op1
= gen_lowpart (mode1
, op1
);
6600 /* In case the insn wants input operands in modes different from
6601 the result, abort. */
6602 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
6603 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
6605 if (! (*insn_data
[icode
].operand
[1 + offs
].predicate
) (op0
, mode0
))
6606 op0
= copy_to_mode_reg (mode0
, op0
);
6607 if (! (*insn_data
[icode
].operand
[2 + offs
].predicate
) (op1
, mode1
))
6608 op1
= copy_to_mode_reg (mode1
, op1
);
6611 pat
= GEN_FCN (icode
) (target
, target
, op0
, op1
);
6613 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
6623 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
6626 c6x_expand_unop_builtin (enum insn_code icode
, tree exp
,
6630 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6631 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6632 enum machine_mode op0mode
= GET_MODE (op0
);
6633 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6634 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6637 || GET_MODE (target
) != tmode
6638 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6639 target
= gen_reg_rtx (tmode
);
6641 if (VECTOR_MODE_P (mode0
))
6642 op0
= safe_vector_operand (op0
, mode0
);
6644 if (op0mode
== SImode
&& mode0
== HImode
)
6647 op0
= gen_lowpart (HImode
, op0
);
6649 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
6651 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6652 op0
= copy_to_mode_reg (mode0
, op0
);
6654 pat
= GEN_FCN (icode
) (target
, op0
);
6661 /* Expand an expression EXP that calls a built-in function,
6662 with result going to TARGET if that's convenient
6663 (and in mode MODE if that's convenient).
6664 SUBTARGET may be used as the target for computing one of EXP's operands.
6665 IGNORE is nonzero if the value is to be ignored. */
6668 c6x_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
6669 rtx subtarget ATTRIBUTE_UNUSED
,
6670 enum machine_mode mode ATTRIBUTE_UNUSED
,
6671 int ignore ATTRIBUTE_UNUSED
)
6674 const struct builtin_description
*d
;
6675 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
6676 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
6678 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6679 if (d
->code
== fcode
)
6680 return c6x_expand_binop_builtin (d
->icode
, exp
, target
,
6681 fcode
== C6X_BUILTIN_CLRR
);
6683 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6684 if (d
->code
== fcode
)
6685 return c6x_expand_unop_builtin (d
->icode
, exp
, target
);
6690 /* Target unwind frame info is generated from dwarf CFI directives, so
6691 always output dwarf2 unwind info. */
6693 static enum unwind_info_type
6694 c6x_debug_unwind_info (void)
6696 if (flag_unwind_tables
|| flag_exceptions
)
6699 return default_debug_unwind_info ();
6702 /* Target Structure. */
6704 /* Initialize the GCC target structure. */
6705 #undef TARGET_FUNCTION_ARG
6706 #define TARGET_FUNCTION_ARG c6x_function_arg
6707 #undef TARGET_FUNCTION_ARG_ADVANCE
6708 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6709 #undef TARGET_FUNCTION_ARG_BOUNDARY
6710 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6711 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6712 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6713 c6x_function_arg_round_boundary
6714 #undef TARGET_FUNCTION_VALUE_REGNO_P
6715 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6716 #undef TARGET_FUNCTION_VALUE
6717 #define TARGET_FUNCTION_VALUE c6x_function_value
6718 #undef TARGET_LIBCALL_VALUE
6719 #define TARGET_LIBCALL_VALUE c6x_libcall_value
6720 #undef TARGET_RETURN_IN_MEMORY
6721 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6722 #undef TARGET_RETURN_IN_MSB
6723 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
6724 #undef TARGET_PASS_BY_REFERENCE
6725 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6726 #undef TARGET_CALLEE_COPIES
6727 #define TARGET_CALLEE_COPIES c6x_callee_copies
6728 #undef TARGET_STRUCT_VALUE_RTX
6729 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6730 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6731 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6733 #undef TARGET_ASM_OUTPUT_MI_THUNK
6734 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6735 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6736 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6738 #undef TARGET_BUILD_BUILTIN_VA_LIST
6739 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6741 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6742 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6743 #undef TARGET_TRAMPOLINE_INIT
6744 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6746 #undef TARGET_LEGITIMATE_CONSTANT_P
6747 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6748 #undef TARGET_LEGITIMATE_ADDRESS_P
6749 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6751 #undef TARGET_IN_SMALL_DATA_P
6752 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6753 #undef TARGET_ASM_SELECT_RTX_SECTION
6754 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6755 #undef TARGET_ASM_SELECT_SECTION
6756 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6757 #undef TARGET_ASM_UNIQUE_SECTION
6758 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6759 #undef TARGET_SECTION_TYPE_FLAGS
6760 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6761 #undef TARGET_HAVE_SRODATA_SECTION
6762 #define TARGET_HAVE_SRODATA_SECTION true
6763 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6764 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6766 #undef TARGET_OPTION_OVERRIDE
6767 #define TARGET_OPTION_OVERRIDE c6x_option_override
6768 #undef TARGET_CONDITIONAL_REGISTER_USAGE
6769 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6771 #undef TARGET_INIT_LIBFUNCS
6772 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6773 #undef TARGET_LIBFUNC_GNU_PREFIX
6774 #define TARGET_LIBFUNC_GNU_PREFIX true
6776 #undef TARGET_SCALAR_MODE_SUPPORTED_P
6777 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6778 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6779 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6780 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6781 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6783 #undef TARGET_RTX_COSTS
6784 #define TARGET_RTX_COSTS c6x_rtx_costs
6786 #undef TARGET_SCHED_INIT
6787 #define TARGET_SCHED_INIT c6x_sched_init
6788 #undef TARGET_SCHED_SET_SCHED_FLAGS
6789 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6790 #undef TARGET_SCHED_ADJUST_COST
6791 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6792 #undef TARGET_SCHED_ISSUE_RATE
6793 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6794 #undef TARGET_SCHED_VARIABLE_ISSUE
6795 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6796 #undef TARGET_SCHED_REORDER
6797 #define TARGET_SCHED_REORDER c6x_sched_reorder
6798 #undef TARGET_SCHED_REORDER2
6799 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6800 #undef TARGET_SCHED_DFA_NEW_CYCLE
6801 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6802 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6803 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6804 #undef TARGET_SCHED_EXPOSED_PIPELINE
6805 #define TARGET_SCHED_EXPOSED_PIPELINE true
6807 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6808 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6809 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
6810 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6811 #undef TARGET_SCHED_SET_SCHED_CONTEXT
6812 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6813 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6814 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6815 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
6816 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6818 #undef TARGET_CAN_ELIMINATE
6819 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
6821 #undef TARGET_PREFERRED_RENAME_CLASS
6822 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6824 #undef TARGET_MACHINE_DEPENDENT_REORG
6825 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6827 #undef TARGET_ASM_FILE_START
6828 #define TARGET_ASM_FILE_START c6x_file_start
6830 #undef TARGET_PRINT_OPERAND
6831 #define TARGET_PRINT_OPERAND c6x_print_operand
6832 #undef TARGET_PRINT_OPERAND_ADDRESS
6833 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6834 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6835 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6837 /* C6x unwinding tables use a different format for the typeinfo tables. */
6838 #undef TARGET_ASM_TTYPE
6839 #define TARGET_ASM_TTYPE c6x_output_ttype
6841 /* The C6x ABI follows the ARM EABI exception handling rules. */
6842 #undef TARGET_ARM_EABI_UNWINDER
6843 #define TARGET_ARM_EABI_UNWINDER true
6845 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6846 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6848 #undef TARGET_ASM_INIT_SECTIONS
6849 #define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6851 #undef TARGET_DEBUG_UNWIND_INFO
6852 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6854 #undef TARGET_DWARF_REGISTER_SPAN
6855 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6857 #undef TARGET_INIT_BUILTINS
6858 #define TARGET_INIT_BUILTINS c6x_init_builtins
6859 #undef TARGET_EXPAND_BUILTIN
6860 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6861 #undef TARGET_BUILTIN_DECL
6862 #define TARGET_BUILTIN_DECL c6x_builtin_decl
6864 struct gcc_target targetm
= TARGET_INITIALIZER
;