1 /* Target Code for TI C6X
2 Copyright (C) 2010-2015 Free Software Foundation, Inc.
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
30 #include "double-int.h"
37 #include "fold-const.h"
38 #include "stor-layout.h"
41 #include "stringpool.h"
42 #include "insn-flags.h"
44 #include "insn-attr.h"
45 #include "insn-codes.h"
47 #include "hard-reg-set.h"
50 #include "statistics.h"
52 #include "fixed-value.h"
53 #include "insn-config.h"
64 #include "dominance.h"
70 #include "cfgcleanup.h"
72 #include "basic-block.h"
73 #include "sched-int.h"
77 #include "tm-constrs.h"
79 #include "diagnostic-core.h"
82 #include "plugin-api.h"
85 #include "langhooks.h"
87 #include "target-def.h"
88 #include "sel-sched.h"
91 #include "hw-doloop.h"
92 #include "regrename.h"
94 #include "gimple-expr.h"
97 /* Table of supported architecture variants. */
101 enum c6x_cpu_type type
;
102 unsigned short features
;
105 /* A list of all ISAs, mapping each one to a representative device.
106 Used for -march selection. */
107 static const c6x_arch_table all_isas
[] =
109 #define C6X_ISA(NAME,DEVICE,FLAGS) \
110 { NAME, DEVICE, FLAGS },
111 #include "c6x-isas.def"
113 { NULL
, C6X_CPU_C62X
, 0 }
116 /* This is the parsed result of the "-march=" option, if given. */
117 enum c6x_cpu_type c6x_arch
= C6X_DEFAULT_ARCH
;
119 /* A mask of insn types that are allowed by the architecture selected by
120 the -march option. */
121 unsigned long c6x_insn_mask
= C6X_DEFAULT_INSN_MASK
;
123 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
125 static rtx_insn
*c6x_current_insn
= NULL
;
127 /* A decl we build to access __c6xabi_DSBT_base. */
128 static GTY(()) tree dsbt_decl
;
130 /* Determines whether we run our final scheduling pass or not. We always
131 avoid the normal second scheduling pass. */
132 static int c6x_flag_schedule_insns2
;
134 /* Determines whether we run variable tracking in machine dependent
136 static int c6x_flag_var_tracking
;
138 /* Determines whether we use modulo scheduling. */
139 static int c6x_flag_modulo_sched
;
141 /* Record the state of flag_pic before we set it to 1 for DSBT. */
142 int c6x_initial_flag_pic
;
146 /* We record the clock cycle for every insn during scheduling. */
148 /* After scheduling, we run assign_reservations to choose unit
149 reservations for all insns. These are recorded here. */
151 /* Records the new condition for insns which must be made
152 conditional after scheduling. An entry of NULL_RTX means no such
153 change is necessary. */
155 /* True for the first insn that was scheduled in an ebb. */
157 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
158 bits rather than storing the state. Meaningful only for the last
160 unsigned int unit_mask
;
161 } c6x_sched_insn_info
;
164 /* Record a c6x_sched_insn_info structure for every insn in the function. */
165 static vec
<c6x_sched_insn_info
> insn_info
;
167 #define INSN_INFO_LENGTH (insn_info).length ()
168 #define INSN_INFO_ENTRY(N) (insn_info[(N)])
170 static bool done_cfi_sections
;
172 #define RESERVATION_FLAG_D 1
173 #define RESERVATION_FLAG_L 2
174 #define RESERVATION_FLAG_S 4
175 #define RESERVATION_FLAG_M 8
176 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
177 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
178 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
179 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
181 /* The DFA names of the units. */
182 static const char *const c6x_unit_names
[] =
184 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
185 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
188 /* The DFA unit number for each unit in c6x_unit_names[]. */
189 static int c6x_unit_codes
[ARRAY_SIZE (c6x_unit_names
)];
191 /* Unit query IDs. */
192 #define UNIT_QID_D1 0
193 #define UNIT_QID_L1 1
194 #define UNIT_QID_S1 2
195 #define UNIT_QID_M1 3
196 #define UNIT_QID_FPS1 4
197 #define UNIT_QID_FPL1 5
198 #define UNIT_QID_ADDDPS1 6
199 #define UNIT_QID_ADDDPL1 7
200 #define UNIT_QID_SIDE_OFFSET 8
202 #define RESERVATION_S1 2
203 #define RESERVATION_S2 10
205 /* An enum for the unit requirements we count in the UNIT_REQS table. */
221 /* A table used to count unit requirements. Used when computing minimum
222 iteration intervals. */
223 typedef int unit_req_table
[2][UNIT_REQ_MAX
];
224 static unit_req_table unit_reqs
;
226 /* Register map for debugging. */
227 unsigned const dbx_register_map
[FIRST_PSEUDO_REGISTER
] =
229 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
230 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
232 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
234 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
236 -1, -1, -1 /* FP, ARGP, ILC. */
239 /* Allocate a new, cleared machine_function structure. */
241 static struct machine_function
*
242 c6x_init_machine_status (void)
244 return ggc_cleared_alloc
<machine_function
> ();
247 /* Implement TARGET_OPTION_OVERRIDE. */
250 c6x_option_override (void)
254 if (global_options_set
.x_c6x_arch_option
)
256 c6x_arch
= all_isas
[c6x_arch_option
].type
;
257 c6x_insn_mask
&= ~C6X_INSNS_ALL_CPU_BITS
;
258 c6x_insn_mask
|= all_isas
[c6x_arch_option
].features
;
261 c6x_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
262 flag_schedule_insns_after_reload
= 0;
264 c6x_flag_modulo_sched
= flag_modulo_sched
;
265 flag_modulo_sched
= 0;
267 init_machine_status
= c6x_init_machine_status
;
269 for (i
= 0; i
< ARRAY_SIZE (c6x_unit_names
); i
++)
270 c6x_unit_codes
[i
] = get_cpu_unit_code (c6x_unit_names
[i
]);
272 if (flag_pic
&& !TARGET_DSBT
)
274 error ("-fpic and -fPIC not supported without -mdsbt on this target");
277 c6x_initial_flag_pic
= flag_pic
;
278 if (TARGET_DSBT
&& !flag_pic
)
283 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
286 c6x_conditional_register_usage (void)
289 if (c6x_arch
== C6X_CPU_C62X
|| c6x_arch
== C6X_CPU_C67X
)
290 for (i
= 16; i
< 32; i
++)
293 fixed_regs
[32 + i
] = 1;
297 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_A_REGS
],
299 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_REGS
],
301 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_A_REGS
],
303 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_REGS
],
308 static GTY(()) rtx eqdf_libfunc
;
309 static GTY(()) rtx nedf_libfunc
;
310 static GTY(()) rtx ledf_libfunc
;
311 static GTY(()) rtx ltdf_libfunc
;
312 static GTY(()) rtx gedf_libfunc
;
313 static GTY(()) rtx gtdf_libfunc
;
314 static GTY(()) rtx eqsf_libfunc
;
315 static GTY(()) rtx nesf_libfunc
;
316 static GTY(()) rtx lesf_libfunc
;
317 static GTY(()) rtx ltsf_libfunc
;
318 static GTY(()) rtx gesf_libfunc
;
319 static GTY(()) rtx gtsf_libfunc
;
320 static GTY(()) rtx strasgi_libfunc
;
321 static GTY(()) rtx strasgi64p_libfunc
;
323 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
324 functions to match the C6x ABI. */
327 c6x_init_libfuncs (void)
329 /* Double-precision floating-point arithmetic. */
330 set_optab_libfunc (add_optab
, DFmode
, "__c6xabi_addd");
331 set_optab_libfunc (sdiv_optab
, DFmode
, "__c6xabi_divd");
332 set_optab_libfunc (smul_optab
, DFmode
, "__c6xabi_mpyd");
333 set_optab_libfunc (neg_optab
, DFmode
, "__c6xabi_negd");
334 set_optab_libfunc (sub_optab
, DFmode
, "__c6xabi_subd");
336 /* Single-precision floating-point arithmetic. */
337 set_optab_libfunc (add_optab
, SFmode
, "__c6xabi_addf");
338 set_optab_libfunc (sdiv_optab
, SFmode
, "__c6xabi_divf");
339 set_optab_libfunc (smul_optab
, SFmode
, "__c6xabi_mpyf");
340 set_optab_libfunc (neg_optab
, SFmode
, "__c6xabi_negf");
341 set_optab_libfunc (sub_optab
, SFmode
, "__c6xabi_subf");
343 /* Floating-point comparisons. */
344 eqsf_libfunc
= init_one_libfunc ("__c6xabi_eqf");
345 nesf_libfunc
= init_one_libfunc ("__c6xabi_neqf");
346 lesf_libfunc
= init_one_libfunc ("__c6xabi_lef");
347 ltsf_libfunc
= init_one_libfunc ("__c6xabi_ltf");
348 gesf_libfunc
= init_one_libfunc ("__c6xabi_gef");
349 gtsf_libfunc
= init_one_libfunc ("__c6xabi_gtf");
350 eqdf_libfunc
= init_one_libfunc ("__c6xabi_eqd");
351 nedf_libfunc
= init_one_libfunc ("__c6xabi_neqd");
352 ledf_libfunc
= init_one_libfunc ("__c6xabi_led");
353 ltdf_libfunc
= init_one_libfunc ("__c6xabi_ltd");
354 gedf_libfunc
= init_one_libfunc ("__c6xabi_ged");
355 gtdf_libfunc
= init_one_libfunc ("__c6xabi_gtd");
357 set_optab_libfunc (eq_optab
, SFmode
, NULL
);
358 set_optab_libfunc (ne_optab
, SFmode
, "__c6xabi_neqf");
359 set_optab_libfunc (gt_optab
, SFmode
, NULL
);
360 set_optab_libfunc (ge_optab
, SFmode
, NULL
);
361 set_optab_libfunc (lt_optab
, SFmode
, NULL
);
362 set_optab_libfunc (le_optab
, SFmode
, NULL
);
363 set_optab_libfunc (unord_optab
, SFmode
, "__c6xabi_unordf");
364 set_optab_libfunc (eq_optab
, DFmode
, NULL
);
365 set_optab_libfunc (ne_optab
, DFmode
, "__c6xabi_neqd");
366 set_optab_libfunc (gt_optab
, DFmode
, NULL
);
367 set_optab_libfunc (ge_optab
, DFmode
, NULL
);
368 set_optab_libfunc (lt_optab
, DFmode
, NULL
);
369 set_optab_libfunc (le_optab
, DFmode
, NULL
);
370 set_optab_libfunc (unord_optab
, DFmode
, "__c6xabi_unordd");
372 /* Floating-point to integer conversions. */
373 set_conv_libfunc (sfix_optab
, SImode
, DFmode
, "__c6xabi_fixdi");
374 set_conv_libfunc (ufix_optab
, SImode
, DFmode
, "__c6xabi_fixdu");
375 set_conv_libfunc (sfix_optab
, DImode
, DFmode
, "__c6xabi_fixdlli");
376 set_conv_libfunc (ufix_optab
, DImode
, DFmode
, "__c6xabi_fixdull");
377 set_conv_libfunc (sfix_optab
, SImode
, SFmode
, "__c6xabi_fixfi");
378 set_conv_libfunc (ufix_optab
, SImode
, SFmode
, "__c6xabi_fixfu");
379 set_conv_libfunc (sfix_optab
, DImode
, SFmode
, "__c6xabi_fixflli");
380 set_conv_libfunc (ufix_optab
, DImode
, SFmode
, "__c6xabi_fixfull");
382 /* Conversions between floating types. */
383 set_conv_libfunc (trunc_optab
, SFmode
, DFmode
, "__c6xabi_cvtdf");
384 set_conv_libfunc (sext_optab
, DFmode
, SFmode
, "__c6xabi_cvtfd");
386 /* Integer to floating-point conversions. */
387 set_conv_libfunc (sfloat_optab
, DFmode
, SImode
, "__c6xabi_fltid");
388 set_conv_libfunc (ufloat_optab
, DFmode
, SImode
, "__c6xabi_fltud");
389 set_conv_libfunc (sfloat_optab
, DFmode
, DImode
, "__c6xabi_fltllid");
390 set_conv_libfunc (ufloat_optab
, DFmode
, DImode
, "__c6xabi_fltulld");
391 set_conv_libfunc (sfloat_optab
, SFmode
, SImode
, "__c6xabi_fltif");
392 set_conv_libfunc (ufloat_optab
, SFmode
, SImode
, "__c6xabi_fltuf");
393 set_conv_libfunc (sfloat_optab
, SFmode
, DImode
, "__c6xabi_fltllif");
394 set_conv_libfunc (ufloat_optab
, SFmode
, DImode
, "__c6xabi_fltullf");
397 set_optab_libfunc (smul_optab
, DImode
, "__c6xabi_mpyll");
398 set_optab_libfunc (ashl_optab
, DImode
, "__c6xabi_llshl");
399 set_optab_libfunc (lshr_optab
, DImode
, "__c6xabi_llshru");
400 set_optab_libfunc (ashr_optab
, DImode
, "__c6xabi_llshr");
402 set_optab_libfunc (sdiv_optab
, SImode
, "__c6xabi_divi");
403 set_optab_libfunc (udiv_optab
, SImode
, "__c6xabi_divu");
404 set_optab_libfunc (smod_optab
, SImode
, "__c6xabi_remi");
405 set_optab_libfunc (umod_optab
, SImode
, "__c6xabi_remu");
406 set_optab_libfunc (sdivmod_optab
, SImode
, "__c6xabi_divremi");
407 set_optab_libfunc (udivmod_optab
, SImode
, "__c6xabi_divremu");
408 set_optab_libfunc (sdiv_optab
, DImode
, "__c6xabi_divlli");
409 set_optab_libfunc (udiv_optab
, DImode
, "__c6xabi_divull");
410 set_optab_libfunc (smod_optab
, DImode
, "__c6xabi_remlli");
411 set_optab_libfunc (umod_optab
, DImode
, "__c6xabi_remull");
412 set_optab_libfunc (udivmod_optab
, DImode
, "__c6xabi_divremull");
415 strasgi_libfunc
= init_one_libfunc ("__c6xabi_strasgi");
416 strasgi64p_libfunc
= init_one_libfunc ("__c6xabi_strasgi_64plus");
419 /* Begin the assembly file. */
422 c6x_file_start (void)
424 /* Variable tracking should be run after all optimizations which change order
425 of insns. It also needs a valid CFG. This can't be done in
426 c6x_override_options, because flag_var_tracking is finalized after
428 c6x_flag_var_tracking
= flag_var_tracking
;
429 flag_var_tracking
= 0;
431 done_cfi_sections
= false;
432 default_file_start ();
434 /* Arrays are aligned to 8-byte boundaries. */
435 asm_fprintf (asm_out_file
,
436 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
437 asm_fprintf (asm_out_file
,
438 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
440 /* Stack alignment is 8 bytes. */
441 asm_fprintf (asm_out_file
,
442 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
443 asm_fprintf (asm_out_file
,
444 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
446 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
447 /* ??? Ideally we'd check flag_short_wchar somehow. */
448 asm_fprintf (asm_out_file
, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
451 /* We conform to version 1.0 of the ABI. */
452 asm_fprintf (asm_out_file
,
453 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
457 /* The LTO frontend only enables exceptions when it sees a function that
458 uses it. This changes the return value of dwarf2out_do_frame, so we
459 have to check before every function. */
462 c6x_output_file_unwind (FILE * f
)
464 if (done_cfi_sections
)
467 /* Output a .cfi_sections directive. */
468 if (dwarf2out_do_frame ())
470 if (flag_unwind_tables
|| flag_exceptions
)
472 if (write_symbols
== DWARF2_DEBUG
473 || write_symbols
== VMS_AND_DWARF2_DEBUG
)
474 asm_fprintf (f
, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
476 asm_fprintf (f
, "\t.cfi_sections .c6xabi.exidx\n");
479 asm_fprintf (f
, "\t.cfi_sections .debug_frame\n");
480 done_cfi_sections
= true;
484 /* Output unwind directives at the end of a function. */
487 c6x_output_fn_unwind (FILE * f
)
489 /* Return immediately if we are not generating unwinding tables. */
490 if (! (flag_unwind_tables
|| flag_exceptions
))
493 /* If this function will never be unwound, then mark it as such. */
494 if (!(flag_unwind_tables
|| crtl
->uses_eh_lsda
)
495 && (TREE_NOTHROW (current_function_decl
)
496 || crtl
->all_throwers_are_sibcalls
))
497 fputs("\t.cantunwind\n", f
);
499 fputs ("\t.endp\n", f
);
503 /* Stack and Calling. */
505 int argument_registers
[10] =
514 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
517 c6x_init_cumulative_args (CUMULATIVE_ARGS
*cum
, const_tree fntype
, rtx libname
,
518 int n_named_args ATTRIBUTE_UNUSED
)
522 if (!libname
&& fntype
)
524 /* We need to find out the number of named arguments. Unfortunately,
525 for incoming arguments, N_NAMED_ARGS is set to -1. */
526 if (stdarg_p (fntype
))
527 cum
->nregs
= type_num_arguments (fntype
) - 1;
533 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
536 c6x_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
537 const_tree type
, bool named ATTRIBUTE_UNUSED
)
539 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
540 if (cum
->count
>= cum
->nregs
)
544 HOST_WIDE_INT size
= int_size_in_bytes (type
);
545 if (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (type
))
549 rtx reg1
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
] + 1);
550 rtx reg2
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
]);
551 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
552 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
553 return gen_rtx_PARALLEL (mode
, vec
);
557 return gen_rtx_REG (mode
, argument_registers
[cum
->count
]);
561 c6x_function_arg_advance (cumulative_args_t cum_v
,
562 machine_mode mode ATTRIBUTE_UNUSED
,
563 const_tree type ATTRIBUTE_UNUSED
,
564 bool named ATTRIBUTE_UNUSED
)
566 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
571 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
572 upward rather than downward. */
575 c6x_block_reg_pad_upward (machine_mode mode ATTRIBUTE_UNUSED
,
576 const_tree type
, bool first
)
580 if (!TARGET_BIG_ENDIAN
)
586 size
= int_size_in_bytes (type
);
590 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
593 c6x_function_arg_boundary (machine_mode mode
, const_tree type
)
595 unsigned int boundary
= type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
);
597 if (boundary
> BITS_PER_WORD
)
598 return 2 * BITS_PER_WORD
;
602 HOST_WIDE_INT size
= int_size_in_bytes (type
);
604 return 2 * BITS_PER_WORD
;
605 if (boundary
< BITS_PER_WORD
)
608 return BITS_PER_WORD
;
610 return 2 * BITS_PER_UNIT
;
616 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
618 c6x_function_arg_round_boundary (machine_mode mode
, const_tree type
)
620 return c6x_function_arg_boundary (mode
, type
);
623 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
624 where function FUNC returns or receives a value of data type TYPE. */
627 c6x_function_value (const_tree type
, const_tree func ATTRIBUTE_UNUSED
,
628 bool outgoing ATTRIBUTE_UNUSED
)
630 /* Functions return values in register A4. When returning aggregates, we may
631 have to adjust for endianness. */
632 if (TARGET_BIG_ENDIAN
&& type
&& AGGREGATE_TYPE_P (type
))
634 HOST_WIDE_INT size
= int_size_in_bytes (type
);
638 rtx reg1
= gen_rtx_REG (SImode
, REG_A4
+ 1);
639 rtx reg2
= gen_rtx_REG (SImode
, REG_A4
);
640 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
641 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
642 return gen_rtx_PARALLEL (TYPE_MODE (type
), vec
);
645 return gen_rtx_REG (TYPE_MODE (type
), REG_A4
);
648 /* Implement TARGET_LIBCALL_VALUE. */
651 c6x_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
653 return gen_rtx_REG (mode
, REG_A4
);
656 /* TARGET_STRUCT_VALUE_RTX implementation. */
659 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED
, int incoming ATTRIBUTE_UNUSED
)
661 return gen_rtx_REG (Pmode
, REG_A3
);
664 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
667 c6x_function_value_regno_p (const unsigned int regno
)
669 return regno
== REG_A4
;
672 /* Types larger than 64 bit, and variable sized types, are passed by
673 reference. The callee must copy them; see c6x_callee_copies. */
676 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
677 machine_mode mode
, const_tree type
,
678 bool named ATTRIBUTE_UNUSED
)
682 size
= int_size_in_bytes (type
);
683 else if (mode
!= VOIDmode
)
684 size
= GET_MODE_SIZE (mode
);
685 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
688 /* Decide whether a type should be returned in memory (true)
689 or in a register (false). This is called by the macro
690 TARGET_RETURN_IN_MEMORY. */
693 c6x_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
695 int size
= int_size_in_bytes (type
);
696 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
699 /* Values which must be returned in the most-significant end of the return
703 c6x_return_in_msb (const_tree valtype
)
705 HOST_WIDE_INT size
= int_size_in_bytes (valtype
);
706 return TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
) && size
== 3;
709 /* Implement TARGET_CALLEE_COPIES. */
712 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
713 machine_mode mode ATTRIBUTE_UNUSED
,
714 const_tree type ATTRIBUTE_UNUSED
,
715 bool named ATTRIBUTE_UNUSED
)
720 /* Return the type to use as __builtin_va_list. */
722 c6x_build_builtin_va_list (void)
724 return build_pointer_type (char_type_node
);
728 c6x_asm_trampoline_template (FILE *f
)
730 fprintf (f
, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
731 fprintf (f
, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
732 fprintf (f
, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
733 fprintf (f
, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
734 fprintf (f
, "\t.long\t0x00000362\n"); /* b .s2 B0 */
735 fprintf (f
, "\t.long\t0x00008000\n"); /* nop 5 */
736 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
737 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
740 /* Emit RTL insns to initialize the variable parts of a trampoline at
741 TRAMP. FNADDR is an RTX for the address of the function's pure
742 code. CXT is an RTX for the static chain value for the function. */
745 c6x_initialize_trampoline (rtx tramp
, tree fndecl
, rtx cxt
)
747 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
748 rtx t1
= copy_to_reg (fnaddr
);
749 rtx t2
= copy_to_reg (cxt
);
750 rtx mask
= gen_reg_rtx (SImode
);
753 emit_block_move (tramp
, assemble_trampoline_template (),
754 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
756 emit_move_insn (mask
, GEN_INT (0xffff << 7));
758 for (i
= 0; i
< 4; i
++)
760 rtx mem
= adjust_address (tramp
, SImode
, i
* 4);
761 rtx t
= (i
& 1) ? t2
: t1
;
762 rtx v1
= gen_reg_rtx (SImode
);
763 rtx v2
= gen_reg_rtx (SImode
);
764 emit_move_insn (v1
, mem
);
766 emit_insn (gen_ashlsi3 (v2
, t
, GEN_INT (7)));
768 emit_insn (gen_lshrsi3 (v2
, t
, GEN_INT (9)));
769 emit_insn (gen_andsi3 (v2
, v2
, mask
));
770 emit_insn (gen_iorsi3 (v2
, v2
, v1
));
771 emit_move_insn (mem
, v2
);
773 #ifdef CLEAR_INSN_CACHE
774 tramp
= XEXP (tramp
, 0);
775 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__gnu_clear_cache"),
776 LCT_NORMAL
, VOIDmode
, 2, tramp
, Pmode
,
777 plus_constant (Pmode
, tramp
, TRAMPOLINE_SIZE
),
782 /* Determine whether c6x_output_mi_thunk can succeed. */
785 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED
,
786 HOST_WIDE_INT delta ATTRIBUTE_UNUSED
,
787 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED
,
788 const_tree function ATTRIBUTE_UNUSED
)
790 return !TARGET_LONG_CALLS
;
793 /* Output the assembler code for a thunk function. THUNK is the
794 declaration for the thunk function itself, FUNCTION is the decl for
795 the target function. DELTA is an immediate constant offset to be
796 added to THIS. If VCALL_OFFSET is nonzero, the word at
797 *(*this + vcall_offset) should be added to THIS. */
800 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
801 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
802 HOST_WIDE_INT vcall_offset
, tree function
)
805 /* The this parameter is passed as the first argument. */
806 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_A4
);
808 c6x_current_insn
= NULL
;
810 xops
[4] = XEXP (DECL_RTL (function
), 0);
813 output_asm_insn ("b .s2 \t%4", xops
);
815 output_asm_insn ("nop 5", xops
);
818 /* Adjust the this parameter by a fixed constant. */
821 xops
[0] = GEN_INT (delta
);
823 if (delta
>= -16 && delta
<= 15)
825 output_asm_insn ("add .s1 %0, %1, %1", xops
);
827 output_asm_insn ("nop 4", xops
);
829 else if (delta
>= 16 && delta
< 32)
831 output_asm_insn ("add .d1 %0, %1, %1", xops
);
833 output_asm_insn ("nop 4", xops
);
835 else if (delta
>= -32768 && delta
< 32768)
837 output_asm_insn ("mvk .s1 %0, A0", xops
);
838 output_asm_insn ("add .d1 %1, A0, %1", xops
);
840 output_asm_insn ("nop 3", xops
);
844 output_asm_insn ("mvkl .s1 %0, A0", xops
);
845 output_asm_insn ("mvkh .s1 %0, A0", xops
);
846 output_asm_insn ("add .d1 %1, A0, %1", xops
);
848 output_asm_insn ("nop 3", xops
);
852 /* Adjust the this parameter by a value stored in the vtable. */
855 rtx a0tmp
= gen_rtx_REG (Pmode
, REG_A0
);
856 rtx a3tmp
= gen_rtx_REG (Pmode
, REG_A3
);
860 xops
[3] = gen_rtx_MEM (Pmode
, a0tmp
);
861 output_asm_insn ("mv .s1 a4, %2", xops
);
862 output_asm_insn ("ldw .d1t1 %3, %2", xops
);
864 /* Adjust the this parameter. */
865 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (Pmode
, a0tmp
,
867 if (!memory_operand (xops
[0], Pmode
))
869 rtx tmp2
= gen_rtx_REG (Pmode
, REG_A1
);
870 xops
[0] = GEN_INT (vcall_offset
);
872 output_asm_insn ("mvkl .s1 %0, %1", xops
);
873 output_asm_insn ("mvkh .s1 %0, %1", xops
);
874 output_asm_insn ("nop 2", xops
);
875 output_asm_insn ("add .d1 %2, %1, %2", xops
);
876 xops
[0] = gen_rtx_MEM (Pmode
, a0tmp
);
879 output_asm_insn ("nop 4", xops
);
881 output_asm_insn ("ldw .d1t1 %0, %1", xops
);
882 output_asm_insn ("|| b .s2 \t%4", xops
);
883 output_asm_insn ("nop 4", xops
);
884 output_asm_insn ("add .d1 %2, %1, %2", xops
);
888 /* Return true if EXP goes in small data/bss. */
891 c6x_in_small_data_p (const_tree exp
)
893 /* We want to merge strings, so we never consider them small data. */
894 if (TREE_CODE (exp
) == STRING_CST
)
897 /* Functions are never small data. */
898 if (TREE_CODE (exp
) == FUNCTION_DECL
)
901 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_WEAK (exp
))
904 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_SECTION_NAME (exp
))
906 const char *section
= DECL_SECTION_NAME (exp
);
908 if (strcmp (section
, ".neardata") == 0
909 || strncmp (section
, ".neardata.", 10) == 0
910 || strncmp (section
, ".gnu.linkonce.s.", 16) == 0
911 || strcmp (section
, ".bss") == 0
912 || strncmp (section
, ".bss.", 5) == 0
913 || strncmp (section
, ".gnu.linkonce.sb.", 17) == 0
914 || strcmp (section
, ".rodata") == 0
915 || strncmp (section
, ".rodata.", 8) == 0
916 || strncmp (section
, ".gnu.linkonce.s2.", 17) == 0)
920 return PLACE_IN_SDATA_P (exp
);
925 /* Return a section for X. The only special thing we do here is to
926 honor small data. We don't have a tree type, so we can't use the
927 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
928 everything sized 8 bytes or smaller into small data. */
931 c6x_select_rtx_section (machine_mode mode
, rtx x
,
932 unsigned HOST_WIDE_INT align
)
934 if (c6x_sdata_mode
== C6X_SDATA_ALL
935 || (c6x_sdata_mode
!= C6X_SDATA_NONE
&& GET_MODE_SIZE (mode
) <= 8))
936 /* ??? Consider using mergeable sdata sections. */
937 return sdata_section
;
939 return default_elf_select_rtx_section (mode
, x
, align
);
943 c6x_elf_select_section (tree decl
, int reloc
,
944 unsigned HOST_WIDE_INT align
)
946 const char *sname
= NULL
;
947 unsigned int flags
= SECTION_WRITE
;
948 if (c6x_in_small_data_p (decl
))
950 switch (categorize_decl_for_section (decl
, reloc
))
961 flags
|= SECTION_BSS
;
968 switch (categorize_decl_for_section (decl
, reloc
))
973 case SECCAT_DATA_REL
:
974 sname
= ".fardata.rel";
976 case SECCAT_DATA_REL_LOCAL
:
977 sname
= ".fardata.rel.local";
979 case SECCAT_DATA_REL_RO
:
980 sname
= ".fardata.rel.ro";
982 case SECCAT_DATA_REL_RO_LOCAL
:
983 sname
= ".fardata.rel.ro.local";
987 flags
|= SECTION_BSS
;
1003 /* We might get called with string constants, but get_named_section
1004 doesn't like them as they are not DECLs. Also, we need to set
1005 flags in that case. */
1007 return get_section (sname
, flags
, NULL
);
1008 return get_named_section (decl
, sname
, reloc
);
1011 return default_elf_select_section (decl
, reloc
, align
);
1014 /* Build up a unique section name, expressed as a
1015 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
1016 RELOC indicates whether the initial value of EXP requires
1017 link-time relocations. */
1019 static void ATTRIBUTE_UNUSED
1020 c6x_elf_unique_section (tree decl
, int reloc
)
1022 const char *prefix
= NULL
;
1023 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
1024 bool one_only
= DECL_COMDAT_GROUP (decl
) && !HAVE_COMDAT_GROUP
;
1026 if (c6x_in_small_data_p (decl
))
1028 switch (categorize_decl_for_section (decl
, reloc
))
1031 prefix
= one_only
? ".s" : ".neardata";
1034 prefix
= one_only
? ".sb" : ".bss";
1036 case SECCAT_SRODATA
:
1037 prefix
= one_only
? ".s2" : ".rodata";
1039 case SECCAT_RODATA_MERGE_STR
:
1040 case SECCAT_RODATA_MERGE_STR_INIT
:
1041 case SECCAT_RODATA_MERGE_CONST
:
1044 case SECCAT_DATA_REL
:
1045 case SECCAT_DATA_REL_LOCAL
:
1046 case SECCAT_DATA_REL_RO
:
1047 case SECCAT_DATA_REL_RO_LOCAL
:
1050 /* Everything else we place into default sections and hope for the
1057 switch (categorize_decl_for_section (decl
, reloc
))
1060 case SECCAT_DATA_REL
:
1061 case SECCAT_DATA_REL_LOCAL
:
1062 case SECCAT_DATA_REL_RO
:
1063 case SECCAT_DATA_REL_RO_LOCAL
:
1064 prefix
= one_only
? ".fd" : ".fardata";
1067 prefix
= one_only
? ".fb" : ".far";
1070 case SECCAT_RODATA_MERGE_STR
:
1071 case SECCAT_RODATA_MERGE_STR_INIT
:
1072 case SECCAT_RODATA_MERGE_CONST
:
1073 prefix
= one_only
? ".fr" : ".const";
1075 case SECCAT_SRODATA
:
1086 const char *name
, *linkonce
;
1089 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
1090 name
= targetm
.strip_name_encoding (name
);
1092 /* If we're using one_only, then there needs to be a .gnu.linkonce
1093 prefix to the section name. */
1094 linkonce
= one_only
? ".gnu.linkonce" : "";
1096 string
= ACONCAT ((linkonce
, prefix
, ".", name
, NULL
));
1098 set_decl_section_name (decl
, string
);
1101 default_unique_section (decl
, reloc
);
1105 c6x_section_type_flags (tree decl
, const char *name
, int reloc
)
1107 unsigned int flags
= 0;
1109 if (strcmp (name
, ".far") == 0
1110 || strncmp (name
, ".far.", 5) == 0)
1111 flags
|= SECTION_BSS
;
1113 flags
|= default_section_type_flags (decl
, name
, reloc
);
1118 /* Checks whether the given CALL_EXPR would use a caller saved
1119 register. This is used to decide whether sibling call optimization
1120 could be performed on the respective function call. */
1123 c6x_call_saved_register_used (tree call_expr
)
1125 CUMULATIVE_ARGS cum_v
;
1126 cumulative_args_t cum
;
1127 HARD_REG_SET call_saved_regset
;
1134 INIT_CUMULATIVE_ARGS (cum_v
, NULL
, NULL
, 0, 0);
1135 cum
= pack_cumulative_args (&cum_v
);
1137 COMPL_HARD_REG_SET (call_saved_regset
, call_used_reg_set
);
1138 for (i
= 0; i
< call_expr_nargs (call_expr
); i
++)
1140 parameter
= CALL_EXPR_ARG (call_expr
, i
);
1141 gcc_assert (parameter
);
1143 /* For an undeclared variable passed as parameter we will get
1144 an ERROR_MARK node here. */
1145 if (TREE_CODE (parameter
) == ERROR_MARK
)
1148 type
= TREE_TYPE (parameter
);
1151 mode
= TYPE_MODE (type
);
1154 if (pass_by_reference (&cum_v
, mode
, type
, true))
1157 type
= build_pointer_type (type
);
1160 parm_rtx
= c6x_function_arg (cum
, mode
, type
, 0);
1162 c6x_function_arg_advance (cum
, mode
, type
, 0);
1167 if (REG_P (parm_rtx
)
1168 && overlaps_hard_reg_set_p (call_saved_regset
, GET_MODE (parm_rtx
),
1171 if (GET_CODE (parm_rtx
) == PARALLEL
)
1173 int n
= XVECLEN (parm_rtx
, 0);
1176 rtx x
= XEXP (XVECEXP (parm_rtx
, 0, n
), 0);
1178 && overlaps_hard_reg_set_p (call_saved_regset
,
1179 GET_MODE (x
), REGNO (x
)))
1187 /* Decide whether we can make a sibling call to a function. DECL is the
1188 declaration of the function being targeted by the call and EXP is the
1189 CALL_EXPR representing the call. */
1192 c6x_function_ok_for_sibcall (tree decl
, tree exp
)
1194 /* Registers A10, A12, B10 and B12 are available as arguments
1195 register but unfortunately caller saved. This makes functions
1196 needing these registers for arguments not suitable for
1198 if (c6x_call_saved_register_used (exp
))
1206 /* When compiling for DSBT, the calling function must be local,
1207 so that when we reload B14 in the sibcall epilogue, it will
1208 not change its value. */
1209 struct cgraph_local_info
*this_func
;
1212 /* Not enough information. */
1215 this_func
= cgraph_node::local_info (current_function_decl
);
1216 return this_func
->local
;
1222 /* Return true if DECL is known to be linked into section SECTION. */
1225 c6x_function_in_section_p (tree decl
, section
*section
)
1227 /* We can only be certain about functions defined in the same
1228 compilation unit. */
1229 if (!TREE_STATIC (decl
))
1232 /* Make sure that SYMBOL always binds to the definition in this
1233 compilation unit. */
1234 if (!targetm
.binds_local_p (decl
))
1237 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1238 if (!DECL_SECTION_NAME (decl
))
1240 /* Make sure that we will not create a unique section for DECL. */
1241 if (flag_function_sections
|| DECL_COMDAT_GROUP (decl
))
1245 return function_section (decl
) == section
;
1248 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1251 c6x_long_call_p (rtx op
)
1255 if (!TARGET_LONG_CALLS
)
1258 decl
= SYMBOL_REF_DECL (op
);
1260 /* Try to determine whether the symbol is in the same section as the current
1261 function. Be conservative, and only cater for cases in which the
1262 whole of the current function is placed in the same section. */
1263 if (decl
!= NULL_TREE
1264 && !flag_reorder_blocks_and_partition
1265 && TREE_CODE (decl
) == FUNCTION_DECL
1266 && c6x_function_in_section_p (decl
, current_function_section ()))
1272 /* Emit the sequence for a call. */
1274 c6x_expand_call (rtx retval
, rtx address
, bool sibcall
)
1276 rtx callee
= XEXP (address
, 0);
1279 if (!c6x_call_operand (callee
, Pmode
))
1281 callee
= force_reg (Pmode
, callee
);
1282 address
= change_address (address
, Pmode
, callee
);
1284 call_insn
= gen_rtx_CALL (VOIDmode
, address
, const0_rtx
);
1287 call_insn
= emit_call_insn (call_insn
);
1288 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
),
1289 gen_rtx_REG (Pmode
, REG_B3
));
1293 if (retval
== NULL_RTX
)
1294 call_insn
= emit_call_insn (call_insn
);
1296 call_insn
= emit_call_insn (gen_rtx_SET (retval
, call_insn
));
1299 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
), pic_offset_table_rtx
);
1302 /* Legitimize PIC addresses. If the address is already position-independent,
1303 we return ORIG. Newly generated position-independent addresses go into a
1304 reg. This is REG if nonzero, otherwise we allocate register(s) as
1305 necessary. PICREG is the register holding the pointer to the PIC offset
1309 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
1314 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
1316 int unspec
= UNSPEC_LOAD_GOT
;
1321 gcc_assert (can_create_pseudo_p ());
1322 reg
= gen_reg_rtx (Pmode
);
1326 if (can_create_pseudo_p ())
1327 tmp
= gen_reg_rtx (Pmode
);
1330 emit_insn (gen_movsi_gotoff_high (tmp
, addr
));
1331 emit_insn (gen_movsi_gotoff_lo_sum (tmp
, tmp
, addr
));
1332 emit_insn (gen_load_got_gotoff (reg
, picreg
, tmp
));
1336 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
1337 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
1339 emit_move_insn (reg
, new_rtx
);
1341 if (picreg
== pic_offset_table_rtx
)
1342 crtl
->uses_pic_offset_table
= 1;
1346 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
1350 if (GET_CODE (addr
) == CONST
)
1352 addr
= XEXP (addr
, 0);
1353 gcc_assert (GET_CODE (addr
) == PLUS
);
1356 if (XEXP (addr
, 0) == picreg
)
1361 gcc_assert (can_create_pseudo_p ());
1362 reg
= gen_reg_rtx (Pmode
);
1365 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
1366 addr
= legitimize_pic_address (XEXP (addr
, 1),
1367 base
== reg
? NULL_RTX
: reg
,
1370 if (GET_CODE (addr
) == CONST_INT
)
1372 gcc_assert (! reload_in_progress
&& ! reload_completed
);
1373 addr
= force_reg (Pmode
, addr
);
1376 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
1378 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
1379 addr
= XEXP (addr
, 1);
1382 return gen_rtx_PLUS (Pmode
, base
, addr
);
1388 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1389 Returns true if no further code must be generated, false if the caller
1390 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1393 expand_move (rtx
*operands
, machine_mode mode
)
1395 rtx dest
= operands
[0];
1396 rtx op
= operands
[1];
1398 if ((reload_in_progress
| reload_completed
) == 0
1399 && GET_CODE (dest
) == MEM
&& GET_CODE (op
) != REG
)
1400 operands
[1] = force_reg (mode
, op
);
1401 else if (mode
== SImode
&& symbolic_operand (op
, SImode
))
1405 if (sdata_symbolic_operand (op
, SImode
))
1407 emit_insn (gen_load_sdata_pic (dest
, pic_offset_table_rtx
, op
));
1408 crtl
->uses_pic_offset_table
= 1;
1413 rtx temp
= (reload_completed
|| reload_in_progress
1414 ? dest
: gen_reg_rtx (Pmode
));
1416 operands
[1] = legitimize_pic_address (op
, temp
,
1417 pic_offset_table_rtx
);
1420 else if (reload_completed
1421 && !sdata_symbolic_operand (op
, SImode
))
1423 emit_insn (gen_movsi_high (dest
, op
));
1424 emit_insn (gen_movsi_lo_sum (dest
, dest
, op
));
1431 /* This function is called when we're about to expand an integer compare
1432 operation which performs COMPARISON. It examines the second operand,
1433 and if it is an integer constant that cannot be used directly on the
1434 current machine in a comparison insn, it returns true. */
1436 c6x_force_op_for_comparison_p (enum rtx_code code
, rtx op
)
1438 if (!CONST_INT_P (op
) || satisfies_constraint_Iu4 (op
))
1441 if ((code
== EQ
|| code
== LT
|| code
== GT
)
1442 && !satisfies_constraint_Is5 (op
))
1444 if ((code
== GTU
|| code
== LTU
)
1445 && (!TARGET_INSNS_64
|| !satisfies_constraint_Iu5 (op
)))
1451 /* Emit comparison instruction if necessary, returning the expression
1452 that holds the compare result in the proper mode. Return the comparison
1453 that should be used in the jump insn. */
1456 c6x_expand_compare (rtx comparison
, machine_mode mode
)
1458 enum rtx_code code
= GET_CODE (comparison
);
1459 rtx op0
= XEXP (comparison
, 0);
1460 rtx op1
= XEXP (comparison
, 1);
1462 enum rtx_code jump_code
= code
;
1463 machine_mode op_mode
= GET_MODE (op0
);
1465 if (op_mode
== DImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1467 rtx t
= gen_reg_rtx (SImode
);
1468 emit_insn (gen_iorsi3 (t
, gen_lowpart (SImode
, op0
),
1469 gen_highpart (SImode
, op0
)));
1473 else if (op_mode
== DImode
)
1478 if (code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1480 code
= reverse_condition (code
);
1486 split_di (&op0
, 1, lo
, high
);
1487 split_di (&op1
, 1, lo
+ 1, high
+ 1);
1489 if (c6x_force_op_for_comparison_p (code
, high
[1])
1490 || c6x_force_op_for_comparison_p (EQ
, high
[1]))
1491 high
[1] = force_reg (SImode
, high
[1]);
1493 cmp1
= gen_reg_rtx (SImode
);
1494 cmp2
= gen_reg_rtx (SImode
);
1495 emit_insn (gen_rtx_SET (cmp1
, gen_rtx_fmt_ee (code
, SImode
,
1496 high
[0], high
[1])));
1499 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1500 lo
[1] = force_reg (SImode
, lo
[1]);
1501 emit_insn (gen_rtx_SET (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1503 emit_insn (gen_andsi3 (cmp1
, cmp1
, cmp2
));
1507 emit_insn (gen_rtx_SET (cmp2
, gen_rtx_EQ (SImode
, high
[0],
1511 else if (code
== LT
)
1513 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1514 lo
[1] = force_reg (SImode
, lo
[1]);
1515 emit_insn (gen_cmpsi_and (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1517 lo
[0], lo
[1], cmp2
));
1518 emit_insn (gen_iorsi3 (cmp1
, cmp1
, cmp2
));
1522 else if (TARGET_FP
&& !flag_finite_math_only
1523 && (op_mode
== DFmode
|| op_mode
== SFmode
)
1524 && code
!= EQ
&& code
!= NE
&& code
!= LT
&& code
!= GT
1525 && code
!= UNLE
&& code
!= UNGE
)
1527 enum rtx_code code1
, code2
, code3
;
1528 rtx (*fn
) (rtx
, rtx
, rtx
, rtx
, rtx
);
1540 code1
= code
== LE
|| code
== UNGT
? LT
: GT
;
1565 cmp
= gen_reg_rtx (SImode
);
1566 emit_insn (gen_rtx_SET (cmp
, gen_rtx_fmt_ee (code1
, SImode
, op0
, op1
)));
1567 fn
= op_mode
== DFmode
? gen_cmpdf_ior
: gen_cmpsf_ior
;
1568 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code2
, SImode
, op0
, op1
),
1570 if (code3
!= UNKNOWN
)
1571 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code3
, SImode
, op0
, op1
),
1574 else if (op_mode
== SImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1579 is_fp_libfunc
= !TARGET_FP
&& (op_mode
== DFmode
|| op_mode
== SFmode
);
1581 if ((code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1584 code
= reverse_condition (code
);
1587 else if (code
== UNGE
)
1592 else if (code
== UNLE
)
1607 libfunc
= op_mode
== DFmode
? eqdf_libfunc
: eqsf_libfunc
;
1610 libfunc
= op_mode
== DFmode
? nedf_libfunc
: nesf_libfunc
;
1613 libfunc
= op_mode
== DFmode
? gtdf_libfunc
: gtsf_libfunc
;
1616 libfunc
= op_mode
== DFmode
? gedf_libfunc
: gesf_libfunc
;
1619 libfunc
= op_mode
== DFmode
? ltdf_libfunc
: ltsf_libfunc
;
1622 libfunc
= op_mode
== DFmode
? ledf_libfunc
: lesf_libfunc
;
1629 cmp
= emit_library_call_value (libfunc
, 0, LCT_CONST
, SImode
, 2,
1630 op0
, op_mode
, op1
, op_mode
);
1631 insns
= get_insns ();
1634 emit_libcall_block (insns
, cmp
, cmp
,
1635 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
));
1639 cmp
= gen_reg_rtx (SImode
);
1640 if (c6x_force_op_for_comparison_p (code
, op1
))
1641 op1
= force_reg (SImode
, op1
);
1642 emit_insn (gen_rtx_SET (cmp
, gen_rtx_fmt_ee (code
, SImode
,
1647 return gen_rtx_fmt_ee (jump_code
, mode
, cmp
, const0_rtx
);
1650 /* Return one word of double-word value OP. HIGH_P is true to select the
1651 high part, false to select the low part. When encountering auto-increment
1652 addressing, we make the assumption that the low part is going to be accessed
1656 c6x_subword (rtx op
, bool high_p
)
1661 mode
= GET_MODE (op
);
1662 if (mode
== VOIDmode
)
1665 if (TARGET_BIG_ENDIAN
? !high_p
: high_p
)
1666 byte
= UNITS_PER_WORD
;
1672 rtx addr
= XEXP (op
, 0);
1673 if (GET_CODE (addr
) == PLUS
|| REG_P (addr
))
1674 return adjust_address (op
, word_mode
, byte
);
1675 /* FIXME: should really support autoincrement addressing for
1676 multi-word modes. */
1680 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
1683 /* Split one or more DImode RTL references into pairs of SImode
1684 references. The RTL can be REG, offsettable MEM, integer constant, or
1685 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1686 split and "num" is its length. lo_half and hi_half are output arrays
1687 that parallel "operands". */
1690 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1694 rtx op
= operands
[num
];
1696 lo_half
[num
] = c6x_subword (op
, false);
1697 hi_half
[num
] = c6x_subword (op
, true);
1701 /* Return true if VAL is a mask valid for a clr instruction. */
1703 c6x_valid_mask_p (HOST_WIDE_INT val
)
1706 for (i
= 0; i
< 32; i
++)
1707 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1710 if (val
& ((unsigned HOST_WIDE_INT
)1 << i
))
1713 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1718 /* Expand a block move for a movmemM pattern. */
1721 c6x_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
,
1722 rtx expected_align_exp ATTRIBUTE_UNUSED
,
1723 rtx expected_size_exp ATTRIBUTE_UNUSED
)
1725 unsigned HOST_WIDE_INT align
= 1;
1726 unsigned HOST_WIDE_INT src_mem_align
, dst_mem_align
, min_mem_align
;
1727 unsigned HOST_WIDE_INT count
= 0, offset
= 0;
1728 unsigned int biggest_move
= TARGET_STDW
? 8 : 4;
1730 if (CONST_INT_P (align_exp
))
1731 align
= INTVAL (align_exp
);
1733 src_mem_align
= MEM_ALIGN (src
) / BITS_PER_UNIT
;
1734 dst_mem_align
= MEM_ALIGN (dst
) / BITS_PER_UNIT
;
1735 min_mem_align
= MIN (src_mem_align
, dst_mem_align
);
1737 if (min_mem_align
> align
)
1738 align
= min_mem_align
/ BITS_PER_UNIT
;
1739 if (src_mem_align
< align
)
1740 src_mem_align
= align
;
1741 if (dst_mem_align
< align
)
1742 dst_mem_align
= align
;
1744 if (CONST_INT_P (count_exp
))
1745 count
= INTVAL (count_exp
);
1749 /* Make sure we don't need to care about overflow later on. */
1750 if (count
> ((unsigned HOST_WIDE_INT
) 1 << 30))
1753 if (count
>= 28 && (count
& 3) == 0 && align
>= 4)
1755 tree dst_expr
= MEM_EXPR (dst
);
1756 tree src_expr
= MEM_EXPR (src
);
1757 rtx fn
= TARGET_INSNS_64PLUS
? strasgi64p_libfunc
: strasgi_libfunc
;
1758 rtx srcreg
= force_reg (Pmode
, XEXP (src
, 0));
1759 rtx dstreg
= force_reg (Pmode
, XEXP (dst
, 0));
1762 mark_addressable (src_expr
);
1764 mark_addressable (dst_expr
);
1765 emit_library_call (fn
, LCT_NORMAL
, VOIDmode
, 3,
1766 dstreg
, Pmode
, srcreg
, Pmode
, count_exp
, SImode
);
1770 if (biggest_move
> align
&& !TARGET_INSNS_64
)
1771 biggest_move
= align
;
1773 if (count
/ biggest_move
> 7)
1778 rtx reg
, reg_lowpart
;
1779 machine_mode srcmode
, dstmode
;
1780 unsigned HOST_WIDE_INT src_size
, dst_size
, src_left
;
1784 while (biggest_move
> count
)
1787 src_size
= dst_size
= biggest_move
;
1788 if (src_size
> src_mem_align
&& src_size
== 2)
1790 if (dst_size
> dst_mem_align
&& dst_size
== 2)
1793 if (dst_size
> src_size
)
1794 dst_size
= src_size
;
1796 srcmode
= mode_for_size (src_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1797 dstmode
= mode_for_size (dst_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1799 reg_lowpart
= reg
= gen_reg_rtx (srcmode
);
1802 reg
= gen_reg_rtx (SImode
);
1803 reg_lowpart
= gen_lowpart (srcmode
, reg
);
1806 srcmem
= adjust_address (copy_rtx (src
), srcmode
, offset
);
1808 if (src_size
> src_mem_align
)
1810 enum insn_code icode
= (srcmode
== SImode
? CODE_FOR_movmisalignsi
1811 : CODE_FOR_movmisaligndi
);
1812 emit_insn (GEN_FCN (icode
) (reg_lowpart
, srcmem
));
1815 emit_move_insn (reg_lowpart
, srcmem
);
1817 src_left
= src_size
;
1818 shift
= TARGET_BIG_ENDIAN
? (src_size
- dst_size
) * BITS_PER_UNIT
: 0;
1819 while (src_left
> 0)
1821 rtx dstreg
= reg_lowpart
;
1823 if (src_size
> dst_size
)
1826 int shift_amount
= shift
& (BITS_PER_WORD
- 1);
1828 srcword
= operand_subword_force (srcword
, src_left
>= 4 ? 0 : 4,
1830 if (shift_amount
> 0)
1832 dstreg
= gen_reg_rtx (SImode
);
1833 emit_insn (gen_lshrsi3 (dstreg
, srcword
,
1834 GEN_INT (shift_amount
)));
1838 dstreg
= gen_lowpart (dstmode
, dstreg
);
1841 dstmem
= adjust_address (copy_rtx (dst
), dstmode
, offset
);
1842 if (dst_size
> dst_mem_align
)
1844 enum insn_code icode
= (dstmode
== SImode
? CODE_FOR_movmisalignsi
1845 : CODE_FOR_movmisaligndi
);
1846 emit_insn (GEN_FCN (icode
) (dstmem
, dstreg
));
1849 emit_move_insn (dstmem
, dstreg
);
1851 if (TARGET_BIG_ENDIAN
)
1852 shift
-= dst_size
* BITS_PER_UNIT
;
1854 shift
+= dst_size
* BITS_PER_UNIT
;
1856 src_left
-= dst_size
;
1863 /* Subroutine of print_address_operand, print a single address offset OFF for
1864 a memory access of mode MEM_MODE, choosing between normal form and scaled
1865 form depending on the type of the insn. Misaligned memory references must
1866 use the scaled form. */
1869 print_address_offset (FILE *file
, rtx off
, machine_mode mem_mode
)
1873 if (c6x_current_insn
!= NULL_RTX
)
1875 pat
= PATTERN (c6x_current_insn
);
1876 if (GET_CODE (pat
) == COND_EXEC
)
1877 pat
= COND_EXEC_CODE (pat
);
1878 if (GET_CODE (pat
) == PARALLEL
)
1879 pat
= XVECEXP (pat
, 0, 0);
1881 if (GET_CODE (pat
) == SET
1882 && GET_CODE (SET_SRC (pat
)) == UNSPEC
1883 && XINT (SET_SRC (pat
), 1) == UNSPEC_MISALIGNED_ACCESS
)
1885 gcc_assert (CONST_INT_P (off
)
1886 && (INTVAL (off
) & (GET_MODE_SIZE (mem_mode
) - 1)) == 0);
1887 fprintf (file
, "[" HOST_WIDE_INT_PRINT_DEC
"]",
1888 INTVAL (off
) / GET_MODE_SIZE (mem_mode
));
1893 output_address (off
);
1898 c6x_print_operand_punct_valid_p (unsigned char c
)
1900 return c
== '$' || c
== '.' || c
== '|';
1903 static void c6x_print_operand (FILE *, rtx
, int);
1905 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1908 c6x_print_address_operand (FILE *file
, rtx x
, machine_mode mem_mode
)
1911 switch (GET_CODE (x
))
1915 if (GET_CODE (x
) == POST_MODIFY
)
1916 output_address (XEXP (x
, 0));
1917 off
= XEXP (XEXP (x
, 1), 1);
1918 if (XEXP (x
, 0) == stack_pointer_rtx
)
1920 if (GET_CODE (x
) == PRE_MODIFY
)
1921 gcc_assert (INTVAL (off
) > 0);
1923 gcc_assert (INTVAL (off
) < 0);
1925 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1927 fprintf (file
, "--");
1928 off
= GEN_INT (-INTVAL (off
));
1931 fprintf (file
, "++");
1932 if (GET_CODE (x
) == PRE_MODIFY
)
1933 output_address (XEXP (x
, 0));
1934 print_address_offset (file
, off
, mem_mode
);
1939 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1941 fprintf (file
, "-");
1942 off
= GEN_INT (-INTVAL (off
));
1945 fprintf (file
, "+");
1946 output_address (XEXP (x
, 0));
1947 print_address_offset (file
, off
, mem_mode
);
1951 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1952 fprintf (file
, "--");
1953 output_address (XEXP (x
, 0));
1954 fprintf (file
, "[1]");
1957 fprintf (file
, "++");
1958 output_address (XEXP (x
, 0));
1959 fprintf (file
, "[1]");
1962 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1963 output_address (XEXP (x
, 0));
1964 fprintf (file
, "++[1]");
1967 output_address (XEXP (x
, 0));
1968 fprintf (file
, "--[1]");
1974 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
1975 fprintf (file
, "+B14(");
1976 output_addr_const (file
, x
);
1977 fprintf (file
, ")");
1981 switch (XINT (x
, 1))
1983 case UNSPEC_LOAD_GOT
:
1984 fputs ("$GOT(", file
);
1985 output_addr_const (file
, XVECEXP (x
, 0, 0));
1988 case UNSPEC_LOAD_SDATA
:
1989 output_addr_const (file
, XVECEXP (x
, 0, 0));
1997 gcc_assert (GET_CODE (x
) != MEM
);
1998 c6x_print_operand (file
, x
, 0);
2003 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
2004 specifies the functional unit used by INSN. */
2007 c6x_get_unit_specifier (rtx_insn
*insn
)
2009 enum attr_units units
;
2011 if (insn_info
.exists ())
2013 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2014 return c6x_unit_names
[unit
][0];
2017 units
= get_attr_units (insn
);
2042 /* Prints the unit specifier field. */
2044 c6x_print_unit_specifier_field (FILE *file
, rtx_insn
*insn
)
2046 enum attr_units units
= get_attr_units (insn
);
2047 enum attr_cross cross
= get_attr_cross (insn
);
2048 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
2052 if (units
== UNITS_D_ADDR
)
2054 enum attr_addr_regfile arf
= get_attr_addr_regfile (insn
);
2056 gcc_assert (arf
!= ADDR_REGFILE_UNKNOWN
);
2057 half
= arf
== ADDR_REGFILE_A
? 1 : 2;
2058 t_half
= rf
== DEST_REGFILE_A
? 1 : 2;
2059 fprintf (file
, ".d%dt%d", half
, t_half
);
2063 if (insn_info
.exists ())
2065 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2067 fputs (c6x_unit_names
[unit
], file
);
2068 if (cross
== CROSS_Y
)
2073 gcc_assert (rf
!= DEST_REGFILE_UNKNOWN
);
2074 unitspec
= c6x_get_unit_specifier (insn
);
2075 half
= rf
== DEST_REGFILE_A
? 1 : 2;
2076 fprintf (file
, ".%c%d%s", unitspec
, half
, cross
== CROSS_Y
? "x" : "");
2079 /* Output assembly language output for the address ADDR to FILE. */
2081 c6x_print_operand_address (FILE *file
, rtx addr
)
2083 c6x_print_address_operand (file
, addr
, VOIDmode
);
2086 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2089 $ -- print the unit specifier field for the instruction.
2090 . -- print the predicate for the instruction or an emptry string for an
2092 | -- print "||" if the insn should be issued in parallel with the previous
2095 C -- print an opcode suffix for a reversed condition
2096 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2098 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2100 J -- print a predicate
2101 j -- like J, but use reverse predicate
2102 k -- treat a CONST_INT as a register number and print it as a register
2103 k -- like k, but print out a doubleword register
2104 n -- print an integer operand, negated
2105 p -- print the low part of a DImode register
2106 P -- print the high part of a DImode register
2107 r -- print the absolute value of an integer operand, shifted right by 1
2108 R -- print the absolute value of an integer operand, shifted right by 2
2109 f -- the first clear bit in an integer operand assumed to be a mask for
2111 F -- the last clear bit in such a mask
2112 s -- the first set bit in an integer operand assumed to be a mask for
2114 S -- the last set bit in such a mask
2115 U -- print either 1 or 2, depending on the side of the machine used by
2119 c6x_print_operand (FILE *file
, rtx x
, int code
)
2128 if (GET_MODE (c6x_current_insn
) != TImode
)
2134 c6x_print_unit_specifier_field (file
, c6x_current_insn
);
2140 x
= current_insn_predicate
;
2143 unsigned int regno
= REGNO (XEXP (x
, 0));
2145 if (GET_CODE (x
) == EQ
)
2147 fputs (reg_names
[regno
], file
);
2153 mode
= GET_MODE (x
);
2160 enum rtx_code c
= GET_CODE (x
);
2162 c
= swap_condition (c
);
2163 fputs (GET_RTX_NAME (c
), file
);
2170 unsigned int regno
= REGNO (XEXP (x
, 0));
2171 if ((GET_CODE (x
) == EQ
) == (code
== 'J'))
2173 fputs (reg_names
[regno
], file
);
2178 gcc_assert (GET_CODE (x
) == CONST_INT
);
2180 fprintf (file
, "%s", reg_names
[v
]);
2183 gcc_assert (GET_CODE (x
) == CONST_INT
);
2185 gcc_assert ((v
& 1) == 0);
2186 fprintf (file
, "%s:%s", reg_names
[v
+ 1], reg_names
[v
]);
2193 gcc_assert (GET_CODE (x
) == CONST_INT
);
2195 for (i
= 0; i
< 32; i
++)
2197 HOST_WIDE_INT tst
= v
& 1;
2198 if (((code
== 'f' || code
== 'F') && !tst
)
2199 || ((code
== 's' || code
== 'S') && tst
))
2203 if (code
== 'f' || code
== 's')
2205 fprintf (file
, "%d", i
);
2210 HOST_WIDE_INT tst
= v
& 1;
2211 if ((code
== 'F' && tst
) || (code
== 'S' && !tst
))
2215 fprintf (file
, "%d", i
- 1);
2219 gcc_assert (GET_CODE (x
) == CONST_INT
);
2220 output_addr_const (file
, GEN_INT (-INTVAL (x
)));
2224 gcc_assert (GET_CODE (x
) == CONST_INT
);
2228 output_addr_const (file
, GEN_INT (v
>> 1));
2232 gcc_assert (GET_CODE (x
) == CONST_INT
);
2236 output_addr_const (file
, GEN_INT (v
>> 2));
2240 gcc_assert (GET_CODE (x
) == CONST_INT
);
2242 fputs (v
== 2 ? "h" : v
== 4 ? "w" : "d", file
);
2247 gcc_assert (GET_CODE (x
) == REG
);
2251 fputs (reg_names
[v
], file
);
2256 if (GET_CODE (x
) == CONST
)
2259 gcc_assert (GET_CODE (x
) == PLUS
);
2260 gcc_assert (GET_CODE (XEXP (x
, 1)) == CONST_INT
);
2261 v
= INTVAL (XEXP (x
, 1));
2265 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
2267 t
= SYMBOL_REF_DECL (x
);
2269 v
|= DECL_ALIGN_UNIT (t
);
2271 v
|= TYPE_ALIGN_UNIT (TREE_TYPE (t
));
2284 if (GET_CODE (x
) == PLUS
2285 || GET_RTX_CLASS (GET_CODE (x
)) == RTX_AUTOINC
)
2287 if (GET_CODE (x
) == CONST
|| GET_CODE (x
) == SYMBOL_REF
)
2289 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
2294 gcc_assert (REG_P (x
));
2295 if (A_REGNO_P (REGNO (x
)))
2297 if (B_REGNO_P (REGNO (x
)))
2302 switch (GET_CODE (x
))
2305 if (GET_MODE_SIZE (mode
) == 8)
2306 fprintf (file
, "%s:%s", reg_names
[REGNO (x
) + 1],
2307 reg_names
[REGNO (x
)]);
2309 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
2314 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
2315 c6x_print_address_operand (file
, XEXP (x
, 0), GET_MODE (x
));
2320 output_addr_const (file
, x
);
2325 output_addr_const (file
, x
);
2329 output_operand_lossage ("invalid const_double operand");
2333 output_addr_const (file
, x
);
2338 /* Return TRUE if OP is a valid memory address with a base register of
2339 class C. If SMALL_OFFSET is true, we disallow memory references which would
2340 require a long offset with B14/B15. */
2343 c6x_mem_operand (rtx op
, enum reg_class c
, bool small_offset
)
2345 machine_mode mode
= GET_MODE (op
);
2346 rtx base
= XEXP (op
, 0);
2347 switch (GET_CODE (base
))
2353 && (XEXP (base
, 0) == stack_pointer_rtx
2354 || XEXP (base
, 0) == pic_offset_table_rtx
))
2356 if (!c6x_legitimate_address_p_1 (mode
, base
, true, true))
2367 base
= XEXP (base
, 0);
2373 gcc_assert (sdata_symbolic_operand (base
, Pmode
));
2374 return !small_offset
&& c
== B_REGS
;
2379 return TEST_HARD_REG_BIT (reg_class_contents
[ (int) (c
)], REGNO (base
));
2382 /* Returns true if X is a valid address for use in a memory reference
2383 of mode MODE. If STRICT is true, we do not allow pseudo registers
2384 in the address. NO_LARGE_OFFSET is true if we are examining an
2385 address for use in a load or store misaligned instruction, or
2386 recursively examining an operand inside a PRE/POST_MODIFY. */
2389 c6x_legitimate_address_p_1 (machine_mode mode
, rtx x
, bool strict
,
2390 bool no_large_offset
)
2394 enum rtx_code code
= GET_CODE (x
);
2400 /* We can't split these into word-sized pieces yet. */
2401 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2403 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
2405 if (!c6x_legitimate_address_p_1 (mode
, XEXP (x
, 1), strict
, true))
2407 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
2415 /* We can't split these into word-sized pieces yet. */
2416 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2425 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x
));
2427 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x
));
2430 if (!REG_P (XEXP (x
, 0))
2431 || !c6x_legitimate_address_p_1 (mode
, XEXP (x
, 0), strict
, false))
2433 /* We cannot ensure currently that both registers end up in the
2434 same register file. */
2435 if (REG_P (XEXP (x
, 1)))
2438 if (mode
== BLKmode
)
2440 else if (mode
== VOIDmode
)
2441 /* ??? This can happen during ivopts. */
2444 size
= GET_MODE_SIZE (mode
);
2447 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2448 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_SDATA
2449 && XEXP (x
, 0) == pic_offset_table_rtx
2450 && sdata_symbolic_operand (XVECEXP (XEXP (x
, 1), 0, 0), SImode
))
2451 return !no_large_offset
&& size
<= 4;
2454 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2455 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_GOT
2456 && XEXP (x
, 0) == pic_offset_table_rtx
2457 && (GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == SYMBOL_REF
2458 || GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == LABEL_REF
))
2459 return !no_large_offset
;
2460 if (GET_CODE (XEXP (x
, 1)) != CONST_INT
)
2463 off
= INTVAL (XEXP (x
, 1));
2465 /* If the machine does not have doubleword load/stores, we'll use
2466 word size accesses. */
2468 if (size
== 2 * UNITS_PER_WORD
&& !TARGET_STDW
)
2469 size
= UNITS_PER_WORD
;
2471 if (((HOST_WIDE_INT
)size1
- 1) & off
)
2474 if (off
> -32 && off
< (size1
== size
? 32 : 28))
2476 if (no_large_offset
|| code
!= PLUS
|| XEXP (x
, 0) != stack_pointer_rtx
2477 || size1
> UNITS_PER_WORD
)
2479 return off
>= 0 && off
< 32768;
2484 return (!no_large_offset
2485 /* With -fpic, we must wrap it in an unspec to show the B14
2488 && GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
2489 && sdata_symbolic_operand (x
, Pmode
));
2497 c6x_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
2499 return c6x_legitimate_address_p_1 (mode
, x
, strict
, false);
2503 c6x_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
,
2504 rtx x ATTRIBUTE_UNUSED
)
2509 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2511 c6x_preferred_rename_class (reg_class_t cl
)
2514 return NONPREDICATE_A_REGS
;
2516 return NONPREDICATE_B_REGS
;
2517 if (cl
== ALL_REGS
|| cl
== GENERAL_REGS
)
2518 return NONPREDICATE_REGS
;
2522 /* Implements FINAL_PRESCAN_INSN. */
2524 c6x_final_prescan_insn (rtx_insn
*insn
, rtx
*opvec ATTRIBUTE_UNUSED
,
2525 int noperands ATTRIBUTE_UNUSED
)
2527 c6x_current_insn
= insn
;
2530 /* A structure to describe the stack layout of a function. The layout is
2533 [saved frame pointer (or possibly padding0)]
2534 --> incoming stack pointer, new hard frame pointer
2535 [saved call-used regs]
2537 --> soft frame pointer
2539 [outgoing arguments]
2542 The structure members are laid out in this order. */
2547 /* Number of registers to save. */
2550 HOST_WIDE_INT frame
;
2551 int outgoing_arguments_size
;
2554 HOST_WIDE_INT to_allocate
;
2555 /* The offsets relative to the incoming stack pointer (which
2556 becomes HARD_FRAME_POINTER). */
2557 HOST_WIDE_INT frame_pointer_offset
;
2558 HOST_WIDE_INT b3_offset
;
2560 /* True if we should call push_rts/pop_rts to save and restore
2565 /* Return true if we need to save and modify the PIC register in the
2569 must_reload_pic_reg_p (void)
2571 struct cgraph_local_info
*i
= NULL
;
2576 i
= cgraph_node::local_info (current_function_decl
);
2578 if ((crtl
->uses_pic_offset_table
|| !crtl
->is_leaf
) && !i
->local
)
2583 /* Return 1 if we need to save REGNO. */
2585 c6x_save_reg (unsigned int regno
)
2587 return ((df_regs_ever_live_p (regno
)
2588 && !call_used_regs
[regno
]
2589 && !fixed_regs
[regno
])
2590 || (regno
== RETURN_ADDR_REGNO
2591 && (df_regs_ever_live_p (regno
)
2593 || (regno
== PIC_OFFSET_TABLE_REGNUM
&& must_reload_pic_reg_p ()));
2596 /* Examine the number of regs NREGS we've determined we must save.
2597 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2598 prologue and epilogue. */
2601 use_push_rts_p (int nregs
)
2603 if (TARGET_INSNS_64PLUS
&& optimize_function_for_size_p (cfun
)
2604 && !cfun
->machine
->contains_sibcall
2605 && !cfun
->returns_struct
2606 && !TARGET_LONG_CALLS
2607 && nregs
>= 6 && !frame_pointer_needed
)
2612 /* Return number of saved general prupose registers. */
2615 c6x_nsaved_regs (void)
2620 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
2621 if (c6x_save_reg (regno
))
2626 /* The safe debug order mandated by the ABI. */
2627 static unsigned reg_save_order
[] =
2629 REG_A10
, REG_A11
, REG_A12
, REG_A13
,
2631 REG_B10
, REG_B11
, REG_B12
, REG_B13
,
2635 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2637 /* Compute the layout of the stack frame and store it in FRAME. */
2640 c6x_compute_frame_layout (struct c6x_frame
*frame
)
2642 HOST_WIDE_INT size
= get_frame_size ();
2643 HOST_WIDE_INT offset
;
2646 /* We use the four bytes which are technically inside the caller's frame,
2647 usually to save the frame pointer. */
2649 frame
->padding0
= 0;
2650 nregs
= c6x_nsaved_regs ();
2651 frame
->push_rts
= false;
2652 frame
->b3_offset
= 0;
2653 if (use_push_rts_p (nregs
))
2655 frame
->push_rts
= true;
2656 frame
->b3_offset
= (TARGET_BIG_ENDIAN
? -12 : -13) * 4;
2659 else if (c6x_save_reg (REG_B3
))
2662 for (idx
= N_SAVE_ORDER
- 1; reg_save_order
[idx
] != REG_B3
; idx
--)
2664 if (c6x_save_reg (reg_save_order
[idx
]))
2665 frame
->b3_offset
-= 4;
2668 frame
->nregs
= nregs
;
2670 if (size
== 0 && nregs
== 0)
2672 frame
->padding0
= 4;
2673 frame
->padding1
= frame
->padding2
= 0;
2674 frame
->frame_pointer_offset
= frame
->to_allocate
= 0;
2675 frame
->outgoing_arguments_size
= 0;
2679 if (!frame
->push_rts
)
2680 offset
+= frame
->nregs
* 4;
2682 if (offset
== 0 && size
== 0 && crtl
->outgoing_args_size
== 0
2684 /* Don't use the bottom of the caller's frame if we have no
2685 allocation of our own and call other functions. */
2686 frame
->padding0
= frame
->padding1
= 4;
2687 else if (offset
& 4)
2688 frame
->padding1
= 4;
2690 frame
->padding1
= 0;
2692 offset
+= frame
->padding0
+ frame
->padding1
;
2693 frame
->frame_pointer_offset
= offset
;
2696 frame
->outgoing_arguments_size
= crtl
->outgoing_args_size
;
2697 offset
+= frame
->outgoing_arguments_size
;
2699 if ((offset
& 4) == 0)
2700 frame
->padding2
= 8;
2702 frame
->padding2
= 4;
2703 frame
->to_allocate
= offset
+ frame
->padding2
;
2706 /* Return the offset between two registers, one to be eliminated, and the other
2707 its replacement, at the start of a routine. */
2710 c6x_initial_elimination_offset (int from
, int to
)
2712 struct c6x_frame frame
;
2713 c6x_compute_frame_layout (&frame
);
2715 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
2717 else if (from
== FRAME_POINTER_REGNUM
2718 && to
== HARD_FRAME_POINTER_REGNUM
)
2719 return -frame
.frame_pointer_offset
;
2722 gcc_assert (to
== STACK_POINTER_REGNUM
);
2724 if (from
== ARG_POINTER_REGNUM
)
2725 return frame
.to_allocate
+ (frame
.push_rts
? 56 : 0);
2727 gcc_assert (from
== FRAME_POINTER_REGNUM
);
2728 return frame
.to_allocate
- frame
.frame_pointer_offset
;
2732 /* Given FROM and TO register numbers, say whether this elimination is
2733 allowed. Frame pointer elimination is automatically handled. */
2736 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
2738 if (to
== STACK_POINTER_REGNUM
)
2739 return !frame_pointer_needed
;
2743 /* Emit insns to increment the stack pointer by OFFSET. If
2744 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2745 Does nothing if the offset is zero. */
2748 emit_add_sp_const (HOST_WIDE_INT offset
, bool frame_related_p
)
2750 rtx to_add
= GEN_INT (offset
);
2751 rtx orig_to_add
= to_add
;
2757 if (offset
< -32768 || offset
> 32767)
2759 rtx reg
= gen_rtx_REG (SImode
, REG_A0
);
2760 rtx low
= GEN_INT (trunc_int_for_mode (offset
, HImode
));
2762 insn
= emit_insn (gen_movsi_high (reg
, low
));
2763 if (frame_related_p
)
2764 RTX_FRAME_RELATED_P (insn
) = 1;
2765 insn
= emit_insn (gen_movsi_lo_sum (reg
, reg
, to_add
));
2766 if (frame_related_p
)
2767 RTX_FRAME_RELATED_P (insn
) = 1;
2770 insn
= emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2772 if (frame_related_p
)
2775 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
2776 gen_rtx_SET (stack_pointer_rtx
,
2777 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2780 RTX_FRAME_RELATED_P (insn
) = 1;
2784 /* Prologue and epilogue. */
2786 c6x_expand_prologue (void)
2788 struct c6x_frame frame
;
2792 HOST_WIDE_INT initial_offset
, off
, added_already
;
2794 c6x_compute_frame_layout (&frame
);
2796 if (flag_stack_usage_info
)
2797 current_function_static_stack_size
= frame
.to_allocate
;
2799 initial_offset
= -frame
.to_allocate
;
2802 emit_insn (gen_push_rts ());
2803 nsaved
= frame
.nregs
;
2806 /* If the offsets would be too large for the memory references we will
2807 create to save registers, do the stack allocation in two parts.
2808 Ensure by subtracting 8 that we don't store to the word pointed to
2809 by the stack pointer. */
2810 if (initial_offset
< -32768)
2811 initial_offset
= -frame
.frame_pointer_offset
- 8;
2813 if (frame
.to_allocate
> 0)
2814 gcc_assert (initial_offset
!= 0);
2816 off
= -initial_offset
+ 4 - frame
.padding0
;
2818 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2821 if (frame_pointer_needed
)
2823 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2824 /* We go through some contortions here to both follow the ABI's
2825 recommendation that FP == incoming SP, and to avoid writing or
2826 reading the word pointed to by the stack pointer. */
2827 rtx addr
= gen_rtx_POST_MODIFY (Pmode
, stack_pointer_rtx
,
2828 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2830 insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), fp_reg
);
2831 RTX_FRAME_RELATED_P (insn
) = 1;
2833 insn
= emit_insn (gen_addsi3 (hard_frame_pointer_rtx
, stack_pointer_rtx
,
2835 RTX_FRAME_RELATED_P (insn
) = 1;
2840 emit_add_sp_const (initial_offset
- added_already
, true);
2842 if (nsaved
< frame
.nregs
)
2846 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2848 int idx
= N_SAVE_ORDER
- i
- 1;
2849 unsigned regno
= reg_save_order
[idx
];
2851 machine_mode save_mode
= SImode
;
2853 if (regno
== REG_A15
&& frame_pointer_needed
)
2854 /* Already saved. */
2856 if (!c6x_save_reg (regno
))
2859 if (TARGET_STDW
&& (off
& 4) == 0 && off
<= 256
2861 && i
+ 1 < N_SAVE_ORDER
2862 && reg_save_order
[idx
- 1] == regno
- 1
2863 && c6x_save_reg (regno
- 1))
2869 reg
= gen_rtx_REG (save_mode
, regno
);
2870 off
-= GET_MODE_SIZE (save_mode
);
2872 insn
= emit_move_insn (adjust_address (mem
, save_mode
, off
),
2874 RTX_FRAME_RELATED_P (insn
) = 1;
2876 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2879 gcc_assert (nsaved
== frame
.nregs
);
2880 emit_add_sp_const (-frame
.to_allocate
- initial_offset
, true);
2881 if (must_reload_pic_reg_p ())
2883 if (dsbt_decl
== NULL
)
2887 t
= build_index_type (integer_one_node
);
2888 t
= build_array_type (integer_type_node
, t
);
2889 t
= build_decl (BUILTINS_LOCATION
, VAR_DECL
,
2890 get_identifier ("__c6xabi_DSBT_BASE"), t
);
2891 DECL_ARTIFICIAL (t
) = 1;
2892 DECL_IGNORED_P (t
) = 1;
2893 DECL_EXTERNAL (t
) = 1;
2894 TREE_STATIC (t
) = 1;
2895 TREE_PUBLIC (t
) = 1;
2900 emit_insn (gen_setup_dsbt (pic_offset_table_rtx
,
2901 XEXP (DECL_RTL (dsbt_decl
), 0)));
2906 c6x_expand_epilogue (bool sibcall
)
2909 struct c6x_frame frame
;
2914 c6x_compute_frame_layout (&frame
);
2916 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2918 /* Insert a dummy set/use of the stack pointer. This creates a
2919 scheduler barrier between the prologue saves and epilogue restores. */
2920 emit_insn (gen_epilogue_barrier (stack_pointer_rtx
, stack_pointer_rtx
));
2922 /* If the offsets would be too large for the memory references we will
2923 create to restore registers, do a preliminary stack adjustment here. */
2924 off
= frame
.to_allocate
- frame
.frame_pointer_offset
+ frame
.padding1
;
2927 nsaved
= frame
.nregs
;
2931 if (frame
.to_allocate
> 32768)
2933 /* Don't add the entire offset so that we leave an unused word
2934 above the stack pointer. */
2935 emit_add_sp_const ((off
- 16) & ~7, false);
2939 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2941 unsigned regno
= reg_save_order
[i
];
2943 machine_mode save_mode
= SImode
;
2945 if (!c6x_save_reg (regno
))
2947 if (regno
== REG_A15
&& frame_pointer_needed
)
2950 if (TARGET_STDW
&& (off
& 4) == 0 && off
< 256
2952 && i
+ 1 < N_SAVE_ORDER
2953 && reg_save_order
[i
+ 1] == regno
+ 1
2954 && c6x_save_reg (regno
+ 1))
2959 reg
= gen_rtx_REG (save_mode
, regno
);
2961 emit_move_insn (reg
, adjust_address (mem
, save_mode
, off
));
2963 off
+= GET_MODE_SIZE (save_mode
);
2964 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2967 if (!frame_pointer_needed
)
2968 emit_add_sp_const (off
+ frame
.padding0
- 4, false);
2971 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2972 rtx addr
= gen_rtx_PRE_MODIFY (Pmode
, stack_pointer_rtx
,
2973 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2975 emit_insn (gen_addsi3 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
2977 emit_move_insn (fp_reg
, gen_frame_mem (Pmode
, addr
));
2980 gcc_assert (nsaved
== frame
.nregs
);
2984 emit_jump_insn (gen_pop_rts ());
2986 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode
,
2987 RETURN_ADDR_REGNO
)));
2991 /* Return the value of the return address for the frame COUNT steps up
2992 from the current frame, after the prologue.
2993 We punt for everything but the current frame by returning const0_rtx. */
2996 c6x_return_addr_rtx (int count
)
3001 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNO
);
3004 /* Return true iff TYPE is one of the shadow types. */
3006 shadow_type_p (enum attr_type type
)
3008 return (type
== TYPE_SHADOW
|| type
== TYPE_LOAD_SHADOW
3009 || type
== TYPE_MULT_SHADOW
);
3012 /* Return true iff INSN is a shadow pattern. */
3014 shadow_p (rtx_insn
*insn
)
3016 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3018 return shadow_type_p (get_attr_type (insn
));
3021 /* Return true iff INSN is a shadow or blockage pattern. */
3023 shadow_or_blockage_p (rtx_insn
*insn
)
3025 enum attr_type type
;
3026 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3028 type
= get_attr_type (insn
);
3029 return shadow_type_p (type
) || type
== TYPE_BLOCKAGE
;
3032 /* Translate UNITS into a bitmask of units we can reserve for this
3035 get_reservation_flags (enum attr_units units
)
3041 return RESERVATION_FLAG_D
;
3043 return RESERVATION_FLAG_L
;
3045 return RESERVATION_FLAG_S
;
3047 return RESERVATION_FLAG_M
;
3049 return RESERVATION_FLAG_LS
;
3051 return RESERVATION_FLAG_DL
;
3053 return RESERVATION_FLAG_DS
;
3055 return RESERVATION_FLAG_DLS
;
3061 /* Compute the side of the machine used by INSN, which reserves UNITS.
3062 This must match the reservations in the scheduling description. */
3064 get_insn_side (rtx_insn
*insn
, enum attr_units units
)
3066 if (units
== UNITS_D_ADDR
)
3067 return (get_attr_addr_regfile (insn
) == ADDR_REGFILE_A
? 0 : 1);
3070 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
3071 if (rf
== DEST_REGFILE_ANY
)
3072 return get_attr_type (insn
) == TYPE_BRANCH
? 0 : 1;
3074 return rf
== DEST_REGFILE_A
? 0 : 1;
3078 /* After scheduling, walk the insns between HEAD and END and assign unit
3081 assign_reservations (rtx_insn
*head
, rtx_insn
*end
)
3084 for (insn
= head
; insn
!= NEXT_INSN (end
); insn
= NEXT_INSN (insn
))
3086 unsigned int sched_mask
, reserved
;
3087 rtx_insn
*within
, *last
;
3090 int rsrv_count
[2][4];
3093 if (GET_MODE (insn
) != TImode
)
3098 /* Find the last insn in the packet. It has a state recorded for it,
3099 which we can use to determine the units we should be using. */
3101 (within
!= NEXT_INSN (end
)
3102 && (within
== insn
|| GET_MODE (within
) != TImode
));
3103 within
= NEXT_INSN (within
))
3106 if (!NONDEBUG_INSN_P (within
))
3108 icode
= recog_memoized (within
);
3111 if (shadow_p (within
))
3113 if (INSN_INFO_ENTRY (INSN_UID (within
)).reservation
!= 0)
3114 reserved
|= 1 << INSN_INFO_ENTRY (INSN_UID (within
)).reservation
;
3117 if (last
== NULL_RTX
)
3120 sched_mask
= INSN_INFO_ENTRY (INSN_UID (last
)).unit_mask
;
3121 sched_mask
&= ~reserved
;
3123 memset (rsrv_count
, 0, sizeof rsrv_count
);
3124 rsrv
[0] = rsrv
[1] = ~0;
3125 for (i
= 0; i
< 8; i
++)
3129 unsigned unit_bit
= 1 << (unit
+ side
* UNIT_QID_SIDE_OFFSET
);
3130 /* Clear the bits which we expect to reserve in the following loop,
3131 leaving the ones set which aren't present in the scheduler's
3132 state and shouldn't be reserved. */
3133 if (sched_mask
& unit_bit
)
3134 rsrv
[i
/ 4] &= ~(1 << unit
);
3137 /* Walk through the insns that occur in the same cycle. We use multiple
3138 passes to assign units, assigning for insns with the most specific
3139 requirements first. */
3140 for (pass
= 0; pass
< 4; pass
++)
3142 (within
!= NEXT_INSN (end
)
3143 && (within
== insn
|| GET_MODE (within
) != TImode
));
3144 within
= NEXT_INSN (within
))
3146 int uid
= INSN_UID (within
);
3147 int this_rsrv
, side
;
3149 enum attr_units units
;
3150 enum attr_type type
;
3153 if (!NONDEBUG_INSN_P (within
))
3155 icode
= recog_memoized (within
);
3158 if (INSN_INFO_ENTRY (uid
).reservation
!= 0)
3160 units
= get_attr_units (within
);
3161 type
= get_attr_type (within
);
3162 this_rsrv
= get_reservation_flags (units
);
3165 side
= get_insn_side (within
, units
);
3167 /* Certain floating point instructions are treated specially. If
3168 an insn can choose between units it can reserve, and its
3169 reservation spans more than one cycle, the reservation contains
3170 special markers in the first cycle to help us reconstruct what
3171 the automaton chose. */
3172 if ((type
== TYPE_ADDDP
|| type
== TYPE_FP4
)
3173 && units
== UNITS_LS
)
3175 int test1_code
= ((type
== TYPE_FP4
? UNIT_QID_FPL1
: UNIT_QID_ADDDPL1
)
3176 + side
* UNIT_QID_SIDE_OFFSET
);
3177 int test2_code
= ((type
== TYPE_FP4
? UNIT_QID_FPS1
: UNIT_QID_ADDDPS1
)
3178 + side
* UNIT_QID_SIDE_OFFSET
);
3179 if ((sched_mask
& (1 << test1_code
)) != 0)
3181 this_rsrv
= RESERVATION_FLAG_L
;
3182 sched_mask
&= ~(1 << test1_code
);
3184 else if ((sched_mask
& (1 << test2_code
)) != 0)
3186 this_rsrv
= RESERVATION_FLAG_S
;
3187 sched_mask
&= ~(1 << test2_code
);
3191 if ((this_rsrv
& (this_rsrv
- 1)) == 0)
3193 int t
= exact_log2 (this_rsrv
) + side
* UNIT_QID_SIDE_OFFSET
;
3194 rsrv
[side
] |= this_rsrv
;
3195 INSN_INFO_ENTRY (uid
).reservation
= t
;
3201 for (j
= 0; j
< 4; j
++)
3202 if (this_rsrv
& (1 << j
))
3203 rsrv_count
[side
][j
]++;
3206 if ((pass
== 2 && this_rsrv
!= RESERVATION_FLAG_DLS
)
3207 || (pass
== 3 && this_rsrv
== RESERVATION_FLAG_DLS
))
3209 int best
= -1, best_cost
= INT_MAX
;
3210 for (j
= 0; j
< 4; j
++)
3211 if ((this_rsrv
& (1 << j
))
3212 && !(rsrv
[side
] & (1 << j
))
3213 && rsrv_count
[side
][j
] < best_cost
)
3215 best_cost
= rsrv_count
[side
][j
];
3218 gcc_assert (best
!= -1);
3219 rsrv
[side
] |= 1 << best
;
3220 for (j
= 0; j
< 4; j
++)
3221 if ((this_rsrv
& (1 << j
)) && j
!= best
)
3222 rsrv_count
[side
][j
]--;
3224 INSN_INFO_ENTRY (uid
).reservation
3225 = best
+ side
* UNIT_QID_SIDE_OFFSET
;
3231 /* Return a factor by which to weight unit imbalances for a reservation
3234 unit_req_factor (enum unitreqs r
)
3256 /* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3257 requirements. Returns zero if INSN can't be handled, otherwise
3258 either one or two to show how many of the two pairs are in use.
3259 REQ1 is always used, it holds what is normally thought of as the
3260 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3261 describe a cross path, or for loads/stores, the T unit. */
3263 get_unit_reqs (rtx_insn
*insn
, int *req1
, int *side1
, int *req2
, int *side2
)
3265 enum attr_units units
;
3266 enum attr_cross cross
;
3269 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3271 units
= get_attr_units (insn
);
3272 if (units
== UNITS_UNKNOWN
)
3274 side
= get_insn_side (insn
, units
);
3275 cross
= get_attr_cross (insn
);
3277 req
= (units
== UNITS_D
? UNIT_REQ_D
3278 : units
== UNITS_D_ADDR
? UNIT_REQ_D
3279 : units
== UNITS_DL
? UNIT_REQ_DL
3280 : units
== UNITS_DS
? UNIT_REQ_DS
3281 : units
== UNITS_L
? UNIT_REQ_L
3282 : units
== UNITS_LS
? UNIT_REQ_LS
3283 : units
== UNITS_S
? UNIT_REQ_S
3284 : units
== UNITS_M
? UNIT_REQ_M
3285 : units
== UNITS_DLS
? UNIT_REQ_DLS
3287 gcc_assert (req
!= -1);
3290 if (units
== UNITS_D_ADDR
)
3293 *side2
= side
^ (cross
== CROSS_Y
? 1 : 0);
3296 else if (cross
== CROSS_Y
)
3305 /* Walk the insns between and including HEAD and TAIL, and mark the
3306 resource requirements in the unit_reqs table. */
3308 count_unit_reqs (unit_req_table reqs
, rtx_insn
*head
, rtx_insn
*tail
)
3312 memset (reqs
, 0, sizeof (unit_req_table
));
3314 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3316 int side1
, side2
, req1
, req2
;
3318 switch (get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
))
3321 reqs
[side2
][req2
]++;
3324 reqs
[side1
][req1
]++;
3330 /* Update the table REQS by merging more specific unit reservations into
3331 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3332 UNIT_REQ_DL, DS, and DLS. */
3334 merge_unit_reqs (unit_req_table reqs
)
3337 for (side
= 0; side
< 2; side
++)
3339 int d
= reqs
[side
][UNIT_REQ_D
];
3340 int l
= reqs
[side
][UNIT_REQ_L
];
3341 int s
= reqs
[side
][UNIT_REQ_S
];
3342 int dl
= reqs
[side
][UNIT_REQ_DL
];
3343 int ls
= reqs
[side
][UNIT_REQ_LS
];
3344 int ds
= reqs
[side
][UNIT_REQ_DS
];
3346 reqs
[side
][UNIT_REQ_DL
] += d
;
3347 reqs
[side
][UNIT_REQ_DL
] += l
;
3348 reqs
[side
][UNIT_REQ_DS
] += d
;
3349 reqs
[side
][UNIT_REQ_DS
] += s
;
3350 reqs
[side
][UNIT_REQ_LS
] += l
;
3351 reqs
[side
][UNIT_REQ_LS
] += s
;
3352 reqs
[side
][UNIT_REQ_DLS
] += ds
+ dl
+ ls
+ d
+ l
+ s
;
3356 /* Examine the table REQS and return a measure of unit imbalance by comparing
3357 the two sides of the machine. If, for example, D1 is used twice and D2
3358 used not at all, the return value should be 1 in the absence of other
3361 unit_req_imbalance (unit_req_table reqs
)
3366 for (i
= 0; i
< UNIT_REQ_MAX
; i
++)
3368 int factor
= unit_req_factor ((enum unitreqs
) i
);
3369 int diff
= abs (reqs
[0][i
] - reqs
[1][i
]);
3370 val
+= (diff
+ factor
- 1) / factor
/ 2;
3375 /* Return the resource-constrained minimum iteration interval given the
3376 data in the REQS table. This must have been processed with
3377 merge_unit_reqs already. */
3379 res_mii (unit_req_table reqs
)
3383 for (side
= 0; side
< 2; side
++)
3384 for (req
= 0; req
< UNIT_REQ_MAX
; req
++)
3386 int factor
= unit_req_factor ((enum unitreqs
) req
);
3387 worst
= MAX ((reqs
[side
][UNIT_REQ_D
] + factor
- 1) / factor
, worst
);
3393 /* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3394 the operands that are involved in the (up to) two reservations, as
3395 found by get_unit_reqs. Return true if we did this successfully, false
3396 if we couldn't identify what to do with INSN. */
3398 get_unit_operand_masks (rtx_insn
*insn
, unsigned int *pmask1
,
3399 unsigned int *pmask2
)
3401 enum attr_op_pattern op_pat
;
3403 if (recog_memoized (insn
) < 0)
3405 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
)
3407 extract_insn (insn
);
3408 op_pat
= get_attr_op_pattern (insn
);
3409 if (op_pat
== OP_PATTERN_DT
)
3411 gcc_assert (recog_data
.n_operands
== 2);
3416 else if (op_pat
== OP_PATTERN_TD
)
3418 gcc_assert (recog_data
.n_operands
== 2);
3423 else if (op_pat
== OP_PATTERN_SXS
)
3425 gcc_assert (recog_data
.n_operands
== 3);
3426 *pmask1
= (1 << 0) | (1 << 2);
3430 else if (op_pat
== OP_PATTERN_SX
)
3432 gcc_assert (recog_data
.n_operands
== 2);
3437 else if (op_pat
== OP_PATTERN_SSX
)
3439 gcc_assert (recog_data
.n_operands
== 3);
3440 *pmask1
= (1 << 0) | (1 << 1);
3447 /* Try to replace a register in INSN, which has corresponding rename info
3448 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3449 about the operands that must be renamed and the side they are on.
3450 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3451 We recompute this information locally after our transformation, and keep
3452 it only if we managed to improve the balance. */
3454 try_rename_operands (rtx_insn
*head
, rtx_insn
*tail
, unit_req_table reqs
,
3456 insn_rr_info
*info
, unsigned int op_mask
, int orig_side
)
3458 enum reg_class super_class
= orig_side
== 0 ? B_REGS
: A_REGS
;
3459 HARD_REG_SET unavailable
;
3460 du_head_p this_head
;
3461 struct du_chain
*chain
;
3464 int best_reg
, old_reg
;
3465 vec
<du_head_p
> involved_chains
= vNULL
;
3466 unit_req_table new_reqs
;
3468 for (i
= 0, tmp_mask
= op_mask
; tmp_mask
; i
++)
3471 if ((tmp_mask
& (1 << i
)) == 0)
3473 if (info
->op_info
[i
].n_chains
!= 1)
3475 op_chain
= regrename_chain_from_id (info
->op_info
[i
].heads
[0]->id
);
3476 involved_chains
.safe_push (op_chain
);
3477 tmp_mask
&= ~(1 << i
);
3480 if (involved_chains
.length () > 1)
3483 this_head
= involved_chains
[0];
3484 if (this_head
->cannot_rename
)
3487 for (chain
= this_head
->first
; chain
; chain
= chain
->next_use
)
3489 unsigned int mask1
, mask2
, mask_changed
;
3490 int count
, side1
, side2
, req1
, req2
;
3491 insn_rr_info
*this_rr
= &insn_rr
[INSN_UID (chain
->insn
)];
3493 count
= get_unit_reqs (chain
->insn
, &req1
, &side1
, &req2
, &side2
);
3498 if (!get_unit_operand_masks (chain
->insn
, &mask1
, &mask2
))
3501 extract_insn (chain
->insn
);
3504 for (i
= 0; i
< recog_data
.n_operands
; i
++)
3507 int n_this_op
= this_rr
->op_info
[i
].n_chains
;
3508 for (j
= 0; j
< n_this_op
; j
++)
3510 du_head_p other
= this_rr
->op_info
[i
].heads
[j
];
3511 if (regrename_chain_from_id (other
->id
) == this_head
)
3519 mask_changed
|= 1 << i
;
3521 gcc_assert (mask_changed
!= 0);
3522 if (mask_changed
!= mask1
&& mask_changed
!= mask2
)
3526 /* If we get here, we can do the renaming. */
3527 COMPL_HARD_REG_SET (unavailable
, reg_class_contents
[(int) super_class
]);
3529 old_reg
= this_head
->regno
;
3531 find_rename_reg (this_head
, super_class
, &unavailable
, old_reg
, true);
3533 regrename_do_replace (this_head
, best_reg
);
3535 count_unit_reqs (new_reqs
, head
, PREV_INSN (tail
));
3536 merge_unit_reqs (new_reqs
);
3539 fprintf (dump_file
, "reshuffle for insn %d, op_mask %x, "
3540 "original side %d, new reg %d\n",
3541 INSN_UID (insn
), op_mask
, orig_side
, best_reg
);
3542 fprintf (dump_file
, " imbalance %d -> %d\n",
3543 unit_req_imbalance (reqs
), unit_req_imbalance (new_reqs
));
3545 if (unit_req_imbalance (new_reqs
) > unit_req_imbalance (reqs
))
3546 regrename_do_replace (this_head
, old_reg
);
3548 memcpy (reqs
, new_reqs
, sizeof (unit_req_table
));
3551 involved_chains
.release ();
3554 /* Find insns in LOOP which would, if shifted to the other side
3555 of the machine, reduce an imbalance in the unit reservations. */
3557 reshuffle_units (basic_block loop
)
3559 rtx_insn
*head
= BB_HEAD (loop
);
3560 rtx_insn
*tail
= BB_END (loop
);
3562 unit_req_table reqs
;
3567 count_unit_reqs (reqs
, head
, PREV_INSN (tail
));
3568 merge_unit_reqs (reqs
);
3570 regrename_init (true);
3572 bitmap_initialize (&bbs
, &bitmap_default_obstack
);
3574 FOR_EACH_EDGE (e
, ei
, loop
->preds
)
3575 bitmap_set_bit (&bbs
, e
->src
->index
);
3577 bitmap_set_bit (&bbs
, loop
->index
);
3578 regrename_analyze (&bbs
);
3580 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3582 enum attr_units units
;
3583 int count
, side1
, side2
, req1
, req2
;
3584 unsigned int mask1
, mask2
;
3587 if (!NONDEBUG_INSN_P (insn
))
3590 count
= get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
);
3595 if (!get_unit_operand_masks (insn
, &mask1
, &mask2
))
3598 info
= &insn_rr
[INSN_UID (insn
)];
3599 if (info
->op_info
== NULL
)
3602 if (reqs
[side1
][req1
] > 1
3603 && reqs
[side1
][req1
] > 2 * reqs
[side1
^ 1][req1
])
3605 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask1
, side1
);
3608 units
= get_attr_units (insn
);
3609 if (units
== UNITS_D_ADDR
)
3611 gcc_assert (count
== 2);
3612 if (reqs
[side2
][req2
] > 1
3613 && reqs
[side2
][req2
] > 2 * reqs
[side2
^ 1][req2
])
3615 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask2
, side2
);
3619 regrename_finish ();
3622 /* Backend scheduling state. */
3623 typedef struct c6x_sched_context
3625 /* The current scheduler clock, saved in the sched_reorder hook. */
3626 int curr_sched_clock
;
3628 /* Number of insns issued so far in this cycle. */
3629 int issued_this_cycle
;
3631 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3632 theoretical maximum for number of jumps in flight is 12: 2 every
3633 cycle, with a latency of 6 cycles each. This is a circular
3634 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3635 jumps have a higher index. This array should be accessed through
3636 the jump_cycle function. */
3637 int jump_cycles
[12];
3638 int jump_cycle_index
;
3640 /* In parallel with jump_cycles, this array records the opposite of
3641 the condition used in each pending jump. This is used to
3642 predicate insns that are scheduled in the jump's delay slots. If
3643 this is NULL_RTX no such predication happens. */
3646 /* Similar to the jump_cycles mechanism, but here we take into
3647 account all insns with delay slots, to avoid scheduling asms into
3649 int delays_finished_at
;
3651 /* The following variable value is the last issued insn. */
3652 rtx_insn
*last_scheduled_insn
;
3653 /* The last issued insn that isn't a shadow of another. */
3654 rtx_insn
*last_scheduled_iter0
;
3656 /* The following variable value is DFA state before issuing the
3657 first insn in the current clock cycle. We do not use this member
3658 of the structure directly; we copy the data in and out of
3659 prev_cycle_state. */
3660 state_t prev_cycle_state_ctx
;
3662 int reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3663 int reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3664 int reg_set_in_cycle
[FIRST_PSEUDO_REGISTER
];
3666 int tmp_reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3667 int tmp_reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3668 } *c6x_sched_context_t
;
3670 /* The current scheduling state. */
3671 static struct c6x_sched_context ss
;
3673 /* The following variable value is DFA state before issuing the first insn
3674 in the current clock cycle. This is used in c6x_variable_issue for
3675 comparison with the state after issuing the last insn in a cycle. */
3676 static state_t prev_cycle_state
;
3678 /* Set when we discover while processing an insn that it would lead to too
3679 many accesses of the same register. */
3680 static bool reg_access_stall
;
3682 /* The highest insn uid after delayed insns were split, but before loop bodies
3683 were copied by the modulo scheduling code. */
3684 static int sploop_max_uid_iter0
;
3686 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3687 so the caller does not specifically have to test for it. */
3689 get_jump_cycle (int n
)
3693 n
+= ss
.jump_cycle_index
;
3696 return ss
.jump_cycles
[n
];
3699 /* Look up the jump condition with index N. */
3701 get_jump_cond (int n
)
3705 n
+= ss
.jump_cycle_index
;
3708 return ss
.jump_cond
[n
];
3711 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3712 has delay slots beyond CLOCK_VAR, return -1. */
3714 first_jump_index (int clock_var
)
3720 int t
= get_jump_cycle (n
);
3729 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3730 and has the opposite condition of COND. */
3732 record_jump (int cycle
, rtx cond
)
3734 if (ss
.jump_cycle_index
== 0)
3735 ss
.jump_cycle_index
= 11;
3737 ss
.jump_cycle_index
--;
3738 ss
.jump_cycles
[ss
.jump_cycle_index
] = cycle
;
3739 ss
.jump_cond
[ss
.jump_cycle_index
] = cond
;
3742 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3745 insn_set_clock (rtx insn
, int cycle
)
3747 unsigned uid
= INSN_UID (insn
);
3749 if (uid
>= INSN_INFO_LENGTH
)
3750 insn_info
.safe_grow (uid
* 5 / 4 + 10);
3752 INSN_INFO_ENTRY (uid
).clock
= cycle
;
3753 INSN_INFO_ENTRY (uid
).new_cond
= NULL
;
3754 INSN_INFO_ENTRY (uid
).reservation
= 0;
3755 INSN_INFO_ENTRY (uid
).ebb_start
= false;
3758 /* Return the clock cycle we set for the insn with uid UID. */
3760 insn_uid_get_clock (int uid
)
3762 return INSN_INFO_ENTRY (uid
).clock
;
3765 /* Return the clock cycle we set for INSN. */
3767 insn_get_clock (rtx insn
)
3769 return insn_uid_get_clock (INSN_UID (insn
));
3772 /* Examine INSN, and if it is a conditional jump of any kind, return
3773 the opposite of the condition in which it branches. Otherwise,
3776 condjump_opposite_condition (rtx insn
)
3778 rtx pat
= PATTERN (insn
);
3779 int icode
= INSN_CODE (insn
);
3782 if (icode
== CODE_FOR_br_true
|| icode
== CODE_FOR_br_false
)
3784 x
= XEXP (SET_SRC (pat
), 0);
3785 if (icode
== CODE_FOR_br_false
)
3788 if (GET_CODE (pat
) == COND_EXEC
)
3790 rtx t
= COND_EXEC_CODE (pat
);
3791 if ((GET_CODE (t
) == PARALLEL
3792 && GET_CODE (XVECEXP (t
, 0, 0)) == RETURN
)
3793 || (GET_CODE (t
) == UNSPEC
&& XINT (t
, 1) == UNSPEC_REAL_JUMP
)
3794 || (GET_CODE (t
) == SET
&& SET_DEST (t
) == pc_rtx
))
3795 x
= COND_EXEC_TEST (pat
);
3800 enum rtx_code code
= GET_CODE (x
);
3801 x
= gen_rtx_fmt_ee (code
== EQ
? NE
: EQ
,
3802 GET_MODE (x
), XEXP (x
, 0),
3808 /* Return true iff COND1 and COND2 are exactly opposite conditions
3809 one of them NE and the other EQ. */
3811 conditions_opposite_p (rtx cond1
, rtx cond2
)
3813 return (rtx_equal_p (XEXP (cond1
, 0), XEXP (cond2
, 0))
3814 && rtx_equal_p (XEXP (cond1
, 1), XEXP (cond2
, 1))
3815 && GET_CODE (cond1
) == reverse_condition (GET_CODE (cond2
)));
3818 /* Return true if we can add a predicate COND to INSN, or if INSN
3819 already has that predicate. If DOIT is true, also perform the
3822 predicate_insn (rtx_insn
*insn
, rtx cond
, bool doit
)
3825 if (cond
== NULL_RTX
)
3831 if (get_attr_predicable (insn
) == PREDICABLE_YES
3832 && GET_CODE (PATTERN (insn
)) != COND_EXEC
)
3836 rtx newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3837 PATTERN (insn
) = newpat
;
3838 INSN_CODE (insn
) = -1;
3842 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
3843 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn
)), cond
))
3845 icode
= INSN_CODE (insn
);
3846 if (icode
== CODE_FOR_real_jump
3847 || icode
== CODE_FOR_jump
3848 || icode
== CODE_FOR_indirect_jump
)
3850 rtx pat
= PATTERN (insn
);
3851 rtx dest
= (icode
== CODE_FOR_real_jump
? XVECEXP (pat
, 0, 0)
3852 : icode
== CODE_FOR_jump
? XEXP (SET_SRC (pat
), 0)
3858 newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3860 newpat
= gen_br_true (cond
, XEXP (cond
, 0), dest
);
3861 PATTERN (insn
) = newpat
;
3862 INSN_CODE (insn
) = -1;
3866 if (INSN_CODE (insn
) == CODE_FOR_br_true
)
3868 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3869 return rtx_equal_p (br_cond
, cond
);
3871 if (INSN_CODE (insn
) == CODE_FOR_br_false
)
3873 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3874 return conditions_opposite_p (br_cond
, cond
);
3879 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3881 init_sched_state (c6x_sched_context_t sc
)
3883 sc
->last_scheduled_insn
= NULL
;
3884 sc
->last_scheduled_iter0
= NULL
;
3885 sc
->issued_this_cycle
= 0;
3886 memset (sc
->jump_cycles
, 0, sizeof sc
->jump_cycles
);
3887 memset (sc
->jump_cond
, 0, sizeof sc
->jump_cond
);
3888 sc
->jump_cycle_index
= 0;
3889 sc
->delays_finished_at
= 0;
3890 sc
->curr_sched_clock
= 0;
3892 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3894 memset (sc
->reg_n_accesses
, 0, sizeof sc
->reg_n_accesses
);
3895 memset (sc
->reg_n_xaccesses
, 0, sizeof sc
->reg_n_xaccesses
);
3896 memset (sc
->reg_set_in_cycle
, 0, sizeof sc
->reg_set_in_cycle
);
3898 state_reset (sc
->prev_cycle_state_ctx
);
3901 /* Allocate store for new scheduling context. */
3903 c6x_alloc_sched_context (void)
3905 return xmalloc (sizeof (struct c6x_sched_context
));
3908 /* If CLEAN_P is true then initializes _SC with clean data,
3909 and from the global context otherwise. */
3911 c6x_init_sched_context (void *_sc
, bool clean_p
)
3913 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3917 init_sched_state (sc
);
3922 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3923 memcpy (sc
->prev_cycle_state_ctx
, prev_cycle_state
, dfa_state_size
);
3927 /* Sets the global scheduling context to the one pointed to by _SC. */
3929 c6x_set_sched_context (void *_sc
)
3931 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3933 gcc_assert (sc
!= NULL
);
3935 memcpy (prev_cycle_state
, sc
->prev_cycle_state_ctx
, dfa_state_size
);
3938 /* Clear data in _SC. */
3940 c6x_clear_sched_context (void *_sc
)
3942 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3943 gcc_assert (_sc
!= NULL
);
3945 free (sc
->prev_cycle_state_ctx
);
3950 c6x_free_sched_context (void *_sc
)
3955 /* True if we are currently performing a preliminary scheduling
3956 pass before modulo scheduling; we can't allow the scheduler to
3957 modify instruction patterns using packetization assumptions,
3958 since there will be another scheduling pass later if modulo
3959 scheduling fails. */
3960 static bool in_hwloop
;
3962 /* Provide information about speculation capabilities, and set the
3963 DO_BACKTRACKING flag. */
3965 c6x_set_sched_flags (spec_info_t spec_info
)
3967 unsigned int *flags
= &(current_sched_info
->flags
);
3969 if (*flags
& SCHED_EBB
)
3971 *flags
|= DO_BACKTRACKING
| DO_PREDICATION
;
3974 *flags
|= DONT_BREAK_DEPENDENCIES
;
3976 spec_info
->mask
= 0;
3979 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3982 c6x_issue_rate (void)
3987 /* Used together with the collapse_ndfa option, this ensures that we reach a
3988 deterministic automaton state before trying to advance a cycle.
3989 With collapse_ndfa, genautomata creates advance cycle arcs only for
3990 such deterministic states. */
3993 c6x_sched_dfa_pre_cycle_insn (void)
3998 /* We're beginning a new block. Initialize data structures as necessary. */
4001 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED
,
4002 int sched_verbose ATTRIBUTE_UNUSED
,
4003 int max_ready ATTRIBUTE_UNUSED
)
4005 if (prev_cycle_state
== NULL
)
4007 prev_cycle_state
= xmalloc (dfa_state_size
);
4009 init_sched_state (&ss
);
4010 state_reset (prev_cycle_state
);
4013 /* We are about to being issuing INSN. Return nonzero if we cannot
4014 issue it on given cycle CLOCK and return zero if we should not sort
4015 the ready queue on the next clock start.
4016 For C6X, we use this function just to copy the previous DFA state
4017 for comparison purposes. */
4020 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED
, int verbose ATTRIBUTE_UNUSED
,
4021 rtx_insn
*insn ATTRIBUTE_UNUSED
,
4022 int last_clock ATTRIBUTE_UNUSED
,
4023 int clock ATTRIBUTE_UNUSED
, int *sort_p ATTRIBUTE_UNUSED
)
4025 if (clock
!= last_clock
)
4026 memcpy (prev_cycle_state
, curr_state
, dfa_state_size
);
4031 c6x_mark_regno_read (int regno
, bool cross
)
4033 int t
= ++ss
.tmp_reg_n_accesses
[regno
];
4036 reg_access_stall
= true;
4040 int set_cycle
= ss
.reg_set_in_cycle
[regno
];
4041 /* This must be done in this way rather than by tweaking things in
4042 adjust_cost, since the stall occurs even for insns with opposite
4043 predicates, and the scheduler may not even see a dependency. */
4044 if (set_cycle
> 0 && set_cycle
== ss
.curr_sched_clock
)
4045 reg_access_stall
= true;
4046 /* This doesn't quite do anything yet as we're only modeling one
4048 ++ss
.tmp_reg_n_xaccesses
[regno
];
4052 /* Note that REG is read in the insn being examined. If CROSS, it
4053 means the access is through a cross path. Update the temporary reg
4054 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4055 in the current cycle. */
4058 c6x_mark_reg_read (rtx reg
, bool cross
)
4060 unsigned regno
= REGNO (reg
);
4061 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4064 c6x_mark_regno_read (regno
+ nregs
, cross
);
4067 /* Note that register REG is written in cycle CYCLES. */
4070 c6x_mark_reg_written (rtx reg
, int cycles
)
4072 unsigned regno
= REGNO (reg
);
4073 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4076 ss
.reg_set_in_cycle
[regno
+ nregs
] = cycles
;
4079 /* Update the register state information for an instruction whose
4080 body is X. Return true if the instruction has to be delayed until the
4084 c6x_registers_update (rtx_insn
*insn
)
4086 enum attr_cross cross
;
4087 enum attr_dest_regfile destrf
;
4091 if (!reload_completed
|| recog_memoized (insn
) < 0)
4094 reg_access_stall
= false;
4095 memcpy (ss
.tmp_reg_n_accesses
, ss
.reg_n_accesses
,
4096 sizeof ss
.tmp_reg_n_accesses
);
4097 memcpy (ss
.tmp_reg_n_xaccesses
, ss
.reg_n_xaccesses
,
4098 sizeof ss
.tmp_reg_n_xaccesses
);
4100 extract_insn (insn
);
4102 cross
= get_attr_cross (insn
);
4103 destrf
= get_attr_dest_regfile (insn
);
4105 nops
= recog_data
.n_operands
;
4107 if (GET_CODE (x
) == COND_EXEC
)
4109 c6x_mark_reg_read (XEXP (XEXP (x
, 0), 0), false);
4113 for (i
= 0; i
< nops
; i
++)
4115 rtx op
= recog_data
.operand
[i
];
4116 if (recog_data
.operand_type
[i
] == OP_OUT
)
4120 bool this_cross
= cross
;
4121 if (destrf
== DEST_REGFILE_A
&& A_REGNO_P (REGNO (op
)))
4123 if (destrf
== DEST_REGFILE_B
&& B_REGNO_P (REGNO (op
)))
4125 c6x_mark_reg_read (op
, this_cross
);
4127 else if (MEM_P (op
))
4130 switch (GET_CODE (op
))
4139 c6x_mark_reg_read (op
, false);
4144 gcc_assert (GET_CODE (op
) == PLUS
);
4147 c6x_mark_reg_read (XEXP (op
, 0), false);
4148 if (REG_P (XEXP (op
, 1)))
4149 c6x_mark_reg_read (XEXP (op
, 1), false);
4154 c6x_mark_regno_read (REG_B14
, false);
4160 else if (!CONSTANT_P (op
) && strlen (recog_data
.constraints
[i
]) > 0)
4163 return reg_access_stall
;
4166 /* Helper function for the TARGET_SCHED_REORDER and
4167 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4168 in the current cycle, move it down in the ready list and return the
4169 number of non-unsafe insns. */
4172 c6x_sched_reorder_1 (rtx_insn
**ready
, int *pn_ready
, int clock_var
)
4174 int n_ready
= *pn_ready
;
4175 rtx_insn
**e_ready
= ready
+ n_ready
;
4179 /* Keep track of conflicts due to a limit number of register accesses,
4180 and due to stalls incurred by too early accesses of registers using
4183 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4185 rtx_insn
*insn
= *insnp
;
4186 int icode
= recog_memoized (insn
);
4187 bool is_asm
= (icode
< 0
4188 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4189 || asm_noperands (PATTERN (insn
)) >= 0));
4190 bool no_parallel
= (is_asm
|| icode
== CODE_FOR_sploop
4192 && get_attr_type (insn
) == TYPE_ATOMIC
));
4194 /* We delay asm insns until all delay slots are exhausted. We can't
4195 accurately tell how many cycles an asm takes, and the main scheduling
4196 code always assumes at least 1 cycle, which may be wrong. */
4198 && (ss
.issued_this_cycle
> 0 || clock_var
< ss
.delays_finished_at
))
4199 || c6x_registers_update (insn
)
4200 || (ss
.issued_this_cycle
> 0 && icode
== CODE_FOR_sploop
))
4202 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4207 else if (shadow_p (insn
))
4209 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4214 /* Ensure that no other jump is scheduled in jump delay slots, since
4215 it would put the machine into the wrong state. Also, we must
4216 avoid scheduling insns that have a latency longer than the
4217 remaining jump delay slots, as the code at the jump destination
4218 won't be prepared for it.
4220 However, we can relax this condition somewhat. The rest of the
4221 scheduler will automatically avoid scheduling an insn on which
4222 the jump shadow depends so late that its side effect happens
4223 after the jump. This means that if we see an insn with a longer
4224 latency here, it can safely be scheduled if we can ensure that it
4225 has a predicate opposite of the previous jump: the side effect
4226 will happen in what we think of as the same basic block. In
4227 c6x_variable_issue, we will record the necessary predicate in
4228 new_conditions, and after scheduling is finished, we will modify
4231 Special care must be taken whenever there is more than one jump
4234 first_jump
= first_jump_index (clock_var
);
4235 if (first_jump
!= -1)
4237 int first_cycle
= get_jump_cycle (first_jump
);
4238 rtx first_cond
= get_jump_cond (first_jump
);
4239 int second_cycle
= 0;
4242 second_cycle
= get_jump_cycle (first_jump
- 1);
4244 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4246 rtx_insn
*insn
= *insnp
;
4247 int icode
= recog_memoized (insn
);
4248 bool is_asm
= (icode
< 0
4249 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4250 || asm_noperands (PATTERN (insn
)) >= 0));
4251 int this_cycles
, rsrv_cycles
;
4252 enum attr_type type
;
4254 gcc_assert (!is_asm
);
4257 this_cycles
= get_attr_cycles (insn
);
4258 rsrv_cycles
= get_attr_reserve_cycles (insn
);
4259 type
= get_attr_type (insn
);
4260 /* Treat branches specially; there is also a hazard if two jumps
4261 end at the same cycle. */
4262 if (type
== TYPE_BRANCH
|| type
== TYPE_CALL
)
4264 if (clock_var
+ this_cycles
<= first_cycle
)
4266 if ((first_jump
> 0 && clock_var
+ this_cycles
> second_cycle
)
4267 || clock_var
+ rsrv_cycles
> first_cycle
4268 || !predicate_insn (insn
, first_cond
, false))
4270 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4281 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4282 for later and clear the register access information for the new
4283 cycle. We also move asm statements out of the way if they would be
4284 scheduled in a delay slot. */
4287 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED
,
4288 int sched_verbose ATTRIBUTE_UNUSED
,
4289 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4290 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4292 ss
.curr_sched_clock
= clock_var
;
4293 ss
.issued_this_cycle
= 0;
4294 memset (ss
.reg_n_accesses
, 0, sizeof ss
.reg_n_accesses
);
4295 memset (ss
.reg_n_xaccesses
, 0, sizeof ss
.reg_n_xaccesses
);
4300 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4303 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4304 cycle for every insn. */
4307 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED
,
4308 int sched_verbose ATTRIBUTE_UNUSED
,
4309 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4310 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4312 /* FIXME: the assembler rejects labels inside an execute packet.
4313 This can occur if prologue insns are scheduled in parallel with
4314 others, so we avoid this here. Also make sure that nothing is
4315 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4316 if (RTX_FRAME_RELATED_P (ss
.last_scheduled_insn
)
4317 || JUMP_P (ss
.last_scheduled_insn
)
4318 || (recog_memoized (ss
.last_scheduled_insn
) >= 0
4319 && get_attr_type (ss
.last_scheduled_insn
) == TYPE_ATOMIC
))
4321 int n_ready
= *pn_ready
;
4322 rtx_insn
**e_ready
= ready
+ n_ready
;
4325 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4327 rtx_insn
*insn
= *insnp
;
4328 if (!shadow_p (insn
))
4330 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4339 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4342 /* Subroutine of maybe_clobber_cond, called through note_stores. */
4345 clobber_cond_1 (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
, void *data1
)
4347 rtx
*cond
= (rtx
*)data1
;
4348 if (*cond
!= NULL_RTX
&& reg_overlap_mentioned_p (x
, *cond
))
4352 /* Examine INSN, and if it destroys the conditions have recorded for
4353 any of the jumps in flight, clear that condition so that we don't
4354 predicate any more insns. CLOCK_VAR helps us limit the search to
4355 only those jumps which are still in flight. */
4358 maybe_clobber_cond (rtx insn
, int clock_var
)
4361 idx
= ss
.jump_cycle_index
;
4362 for (n
= 0; n
< 12; n
++, idx
++)
4369 cycle
= ss
.jump_cycles
[idx
];
4370 if (cycle
<= clock_var
)
4373 cond
= ss
.jump_cond
[idx
];
4374 if (cond
== NULL_RTX
)
4379 ss
.jump_cond
[idx
] = NULL_RTX
;
4383 note_stores (PATTERN (insn
), clobber_cond_1
, ss
.jump_cond
+ idx
);
4384 for (link
= REG_NOTES (insn
); link
; link
= XEXP (link
, 1))
4385 if (REG_NOTE_KIND (link
) == REG_INC
)
4386 clobber_cond_1 (XEXP (link
, 0), NULL_RTX
, ss
.jump_cond
+ idx
);
4390 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4391 issue INSN. Return the number of insns left on the ready queue
4392 that can be issued this cycle.
4393 We use this hook to record clock cycles and reservations for every insn. */
4396 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED
,
4397 int sched_verbose ATTRIBUTE_UNUSED
,
4398 rtx_insn
*insn
, int can_issue_more ATTRIBUTE_UNUSED
)
4400 ss
.last_scheduled_insn
= insn
;
4401 if (INSN_UID (insn
) < sploop_max_uid_iter0
&& !JUMP_P (insn
))
4402 ss
.last_scheduled_iter0
= insn
;
4403 if (GET_CODE (PATTERN (insn
)) != USE
&& GET_CODE (PATTERN (insn
)) != CLOBBER
)
4404 ss
.issued_this_cycle
++;
4405 if (insn_info
.exists ())
4407 state_t st_after
= alloca (dfa_state_size
);
4408 int curr_clock
= ss
.curr_sched_clock
;
4409 int uid
= INSN_UID (insn
);
4410 int icode
= recog_memoized (insn
);
4412 int first
, first_cycle
;
4416 insn_set_clock (insn
, curr_clock
);
4417 INSN_INFO_ENTRY (uid
).ebb_start
4418 = curr_clock
== 0 && ss
.issued_this_cycle
== 1;
4420 first
= first_jump_index (ss
.curr_sched_clock
);
4424 first_cond
= NULL_RTX
;
4428 first_cycle
= get_jump_cycle (first
);
4429 first_cond
= get_jump_cond (first
);
4432 && first_cycle
> curr_clock
4433 && first_cond
!= NULL_RTX
4434 && (curr_clock
+ get_attr_cycles (insn
) > first_cycle
4435 || get_attr_type (insn
) == TYPE_BRANCH
4436 || get_attr_type (insn
) == TYPE_CALL
))
4437 INSN_INFO_ENTRY (uid
).new_cond
= first_cond
;
4439 memcpy (st_after
, curr_state
, dfa_state_size
);
4440 state_transition (st_after
, const0_rtx
);
4443 for (i
= 0; i
< 2 * UNIT_QID_SIDE_OFFSET
; i
++)
4444 if (cpu_unit_reservation_p (st_after
, c6x_unit_codes
[i
])
4445 && !cpu_unit_reservation_p (prev_cycle_state
, c6x_unit_codes
[i
]))
4447 INSN_INFO_ENTRY (uid
).unit_mask
= mask
;
4449 maybe_clobber_cond (insn
, curr_clock
);
4455 c6x_registers_update (insn
);
4456 memcpy (ss
.reg_n_accesses
, ss
.tmp_reg_n_accesses
,
4457 sizeof ss
.reg_n_accesses
);
4458 memcpy (ss
.reg_n_xaccesses
, ss
.tmp_reg_n_accesses
,
4459 sizeof ss
.reg_n_xaccesses
);
4461 cycles
= get_attr_cycles (insn
);
4462 if (ss
.delays_finished_at
< ss
.curr_sched_clock
+ cycles
)
4463 ss
.delays_finished_at
= ss
.curr_sched_clock
+ cycles
;
4464 if (get_attr_type (insn
) == TYPE_BRANCH
4465 || get_attr_type (insn
) == TYPE_CALL
)
4467 rtx opposite
= condjump_opposite_condition (insn
);
4468 record_jump (ss
.curr_sched_clock
+ cycles
, opposite
);
4471 /* Mark the cycles in which the destination registers are written.
4472 This is used for calculating stalls when using cross units. */
4473 extract_insn (insn
);
4474 /* Cross-path stalls don't apply to results of load insns. */
4475 if (get_attr_type (insn
) == TYPE_LOAD
4476 || get_attr_type (insn
) == TYPE_LOADN
4477 || get_attr_type (insn
) == TYPE_LOAD_SHADOW
)
4479 for (i
= 0; i
< recog_data
.n_operands
; i
++)
4481 rtx op
= recog_data
.operand
[i
];
4484 rtx addr
= XEXP (op
, 0);
4485 if (GET_RTX_CLASS (GET_CODE (addr
)) == RTX_AUTOINC
)
4486 c6x_mark_reg_written (XEXP (addr
, 0),
4487 insn_uid_get_clock (uid
) + 1);
4489 if (recog_data
.operand_type
[i
] != OP_IN
4492 c6x_mark_reg_written (op
,
4493 insn_uid_get_clock (uid
) + cycles
);
4498 return can_issue_more
;
4501 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4502 anti- and output dependencies. */
4505 c6x_adjust_cost (rtx_insn
*insn
, rtx link
, rtx_insn
*dep_insn
, int cost
)
4507 enum attr_type insn_type
= TYPE_UNKNOWN
, dep_insn_type
= TYPE_UNKNOWN
;
4508 int dep_insn_code_number
, insn_code_number
;
4509 int shadow_bonus
= 0;
4511 dep_insn_code_number
= recog_memoized (dep_insn
);
4512 insn_code_number
= recog_memoized (insn
);
4514 if (dep_insn_code_number
>= 0)
4515 dep_insn_type
= get_attr_type (dep_insn
);
4517 if (insn_code_number
>= 0)
4518 insn_type
= get_attr_type (insn
);
4520 kind
= REG_NOTE_KIND (link
);
4523 /* If we have a dependency on a load, and it's not for the result of
4524 the load, it must be for an autoincrement. Reduce the cost in that
4526 if (dep_insn_type
== TYPE_LOAD
)
4528 rtx set
= PATTERN (dep_insn
);
4529 if (GET_CODE (set
) == COND_EXEC
)
4530 set
= COND_EXEC_CODE (set
);
4531 if (GET_CODE (set
) == UNSPEC
)
4535 gcc_assert (GET_CODE (set
) == SET
);
4536 if (!reg_overlap_mentioned_p (SET_DEST (set
), PATTERN (insn
)))
4542 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4543 it occurs in between two cycles, but we schedule it at the end of the
4545 if (shadow_type_p (insn_type
))
4548 /* Anti and output dependencies usually have zero cost, but we want
4549 to insert a stall after a jump, and after certain floating point
4550 insns that take more than one cycle to read their inputs. In the
4551 future, we should try to find a better algorithm for scheduling
4555 /* We can get anti-dependencies against shadow insns. Treat these
4556 like output dependencies, so that the insn is entirely finished
4557 before the branch takes place. */
4558 if (kind
== REG_DEP_ANTI
&& insn_type
== TYPE_SHADOW
)
4559 kind
= REG_DEP_OUTPUT
;
4560 switch (dep_insn_type
)
4566 if (get_attr_has_shadow (dep_insn
) == HAS_SHADOW_Y
)
4567 /* This is a real_jump/real_call insn. These don't have
4568 outputs, and ensuring the validity of scheduling things
4569 in the delay slot is the job of
4570 c6x_sched_reorder_1. */
4572 /* Unsplit calls can happen - e.g. for divide insns. */
4577 if (kind
== REG_DEP_OUTPUT
)
4578 return 5 - shadow_bonus
;
4582 if (kind
== REG_DEP_OUTPUT
)
4583 return 4 - shadow_bonus
;
4586 if (kind
== REG_DEP_OUTPUT
)
4587 return 2 - shadow_bonus
;
4590 if (kind
== REG_DEP_OUTPUT
)
4591 return 2 - shadow_bonus
;
4595 if (kind
== REG_DEP_OUTPUT
)
4596 return 7 - shadow_bonus
;
4599 if (kind
== REG_DEP_OUTPUT
)
4600 return 5 - shadow_bonus
;
4603 if (kind
== REG_DEP_OUTPUT
)
4604 return 9 - shadow_bonus
;
4608 if (kind
== REG_DEP_OUTPUT
)
4609 return 10 - shadow_bonus
;
4613 if (insn_type
== TYPE_SPKERNEL
)
4615 if (kind
== REG_DEP_OUTPUT
)
4616 return 1 - shadow_bonus
;
4622 return cost
- shadow_bonus
;
4625 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4626 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4627 first in the original stream. */
4630 gen_one_bundle (rtx_insn
**slot
, int n_filled
, int real_first
)
4637 seq
= gen_rtx_SEQUENCE (VOIDmode
, gen_rtvec_v (n_filled
, slot
));
4638 bundle
= make_insn_raw (seq
);
4639 BLOCK_FOR_INSN (bundle
) = BLOCK_FOR_INSN (slot
[0]);
4640 INSN_LOCATION (bundle
) = INSN_LOCATION (slot
[0]);
4641 SET_PREV_INSN (bundle
) = SET_PREV_INSN (slot
[real_first
]);
4645 for (i
= 0; i
< n_filled
; i
++)
4647 rtx_insn
*insn
= slot
[i
];
4649 SET_PREV_INSN (insn
) = t
? t
: PREV_INSN (bundle
);
4651 SET_NEXT_INSN (t
) = insn
;
4654 INSN_LOCATION (slot
[i
]) = INSN_LOCATION (bundle
);
4657 SET_NEXT_INSN (bundle
) = NEXT_INSN (PREV_INSN (bundle
));
4658 SET_NEXT_INSN (t
) = NEXT_INSN (bundle
);
4659 SET_NEXT_INSN (PREV_INSN (bundle
)) = bundle
;
4660 SET_PREV_INSN (NEXT_INSN (bundle
)) = bundle
;
4663 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4664 try to insert labels in the middle. */
4667 c6x_gen_bundles (void)
4670 rtx_insn
*insn
, *next
, *last_call
;
4672 FOR_EACH_BB_FN (bb
, cfun
)
4674 rtx_insn
*insn
, *next
;
4675 /* The machine is eight insns wide. We can have up to six shadow
4676 insns, plus an extra slot for merging the jump shadow. */
4681 for (insn
= BB_HEAD (bb
);; insn
= next
)
4684 rtx delete_this
= NULL_RTX
;
4686 if (NONDEBUG_INSN_P (insn
))
4688 /* Put calls at the start of the sequence. */
4694 memmove (&slot
[1], &slot
[0],
4695 n_filled
* sizeof (slot
[0]));
4697 if (!shadow_p (insn
))
4699 PUT_MODE (insn
, TImode
);
4701 PUT_MODE (slot
[1], VOIDmode
);
4708 slot
[n_filled
++] = insn
;
4712 next
= NEXT_INSN (insn
);
4713 while (next
&& insn
!= BB_END (bb
)
4714 && !(NONDEBUG_INSN_P (next
)
4715 && GET_CODE (PATTERN (next
)) != USE
4716 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4719 next
= NEXT_INSN (insn
);
4722 at_end
= insn
== BB_END (bb
);
4723 if (delete_this
== NULL_RTX
4724 && (at_end
|| (GET_MODE (next
) == TImode
4725 && !(shadow_p (next
) && CALL_P (next
)))))
4728 gen_one_bundle (slot
, n_filled
, first_slot
);
4737 /* Bundling, and emitting nops, can separate
4738 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4741 for (insn
= get_insns (); insn
; insn
= next
)
4743 next
= NEXT_INSN (insn
);
4745 || (INSN_P (insn
) && GET_CODE (PATTERN (insn
)) == SEQUENCE
4746 && CALL_P (XVECEXP (PATTERN (insn
), 0, 0))))
4748 if (!NOTE_P (insn
) || NOTE_KIND (insn
) != NOTE_INSN_CALL_ARG_LOCATION
)
4750 if (NEXT_INSN (last_call
) == insn
)
4752 SET_NEXT_INSN (PREV_INSN (insn
)) = NEXT_INSN (insn
);
4753 SET_PREV_INSN (NEXT_INSN (insn
)) = PREV_INSN (insn
);
4754 SET_PREV_INSN (insn
) = last_call
;
4755 SET_NEXT_INSN (insn
) = NEXT_INSN (last_call
);
4756 SET_PREV_INSN (NEXT_INSN (insn
)) = insn
;
4757 SET_NEXT_INSN (PREV_INSN (insn
)) = insn
;
4762 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4765 emit_nop_after (int cycles
, rtx after
)
4769 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4770 operation. We don't need the extra NOP since in this case, the hardware
4771 will automatically insert the required stall. */
4775 gcc_assert (cycles
< 10);
4777 insn
= emit_insn_after (gen_nop_count (GEN_INT (cycles
)), after
);
4778 PUT_MODE (insn
, TImode
);
4783 /* Determine whether INSN is a call that needs to have a return label
4787 returning_call_p (rtx_insn
*insn
)
4790 return (!SIBLING_CALL_P (insn
)
4791 && get_attr_type (insn
) != TYPE_CALLP
4792 && get_attr_type (insn
) != TYPE_SHADOW
);
4793 if (recog_memoized (insn
) < 0)
4795 if (get_attr_type (insn
) == TYPE_CALL
)
4800 /* Determine whether INSN's pattern can be converted to use callp. */
4802 can_use_callp (rtx_insn
*insn
)
4804 int icode
= recog_memoized (insn
);
4805 if (!TARGET_INSNS_64PLUS
4807 || GET_CODE (PATTERN (insn
)) == COND_EXEC
)
4810 return ((icode
== CODE_FOR_real_call
4811 || icode
== CODE_FOR_call_internal
4812 || icode
== CODE_FOR_call_value_internal
)
4813 && get_attr_dest_regfile (insn
) == DEST_REGFILE_ANY
);
4816 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4818 convert_to_callp (rtx_insn
*insn
)
4821 extract_insn (insn
);
4822 if (GET_CODE (PATTERN (insn
)) == SET
)
4824 rtx dest
= recog_data
.operand
[0];
4825 lab
= recog_data
.operand
[1];
4826 PATTERN (insn
) = gen_callp_value (dest
, lab
);
4827 INSN_CODE (insn
) = CODE_FOR_callp_value
;
4831 lab
= recog_data
.operand
[0];
4832 PATTERN (insn
) = gen_callp (lab
);
4833 INSN_CODE (insn
) = CODE_FOR_callp
;
4837 /* Scan forwards from INSN until we find the next insn that has mode TImode
4838 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4839 Return it if we find such an insn, NULL_RTX otherwise. */
4841 find_next_cycle_insn (rtx insn
, int clock
)
4844 if (GET_MODE (t
) == TImode
)
4845 t
= next_real_insn (t
);
4846 while (t
&& GET_MODE (t
) != TImode
)
4847 t
= next_real_insn (t
);
4849 if (t
&& insn_get_clock (t
) == clock
)
4854 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4855 around PAT. Return PAT either unchanged or modified in this
4858 duplicate_cond (rtx pat
, rtx cond_insn
)
4860 rtx cond_pat
= PATTERN (cond_insn
);
4861 if (GET_CODE (cond_pat
) == COND_EXEC
)
4862 pat
= gen_rtx_COND_EXEC (VOIDmode
, copy_rtx (COND_EXEC_TEST (cond_pat
)),
4867 /* Walk forward from INSN to find the last insn that issues in the same clock
4870 find_last_same_clock (rtx insn
)
4873 rtx_insn
*t
= next_real_insn (insn
);
4875 while (t
&& GET_MODE (t
) != TImode
)
4877 if (!DEBUG_INSN_P (t
) && recog_memoized (t
) >= 0)
4879 t
= next_real_insn (t
);
4884 /* For every call insn in the function, emit code to load the return
4885 address. For each call we create a return label and store it in
4886 CALL_LABELS. If are not scheduling, we emit the labels here,
4887 otherwise the caller will do it later.
4888 This function is called after final insn scheduling, but before creating
4889 the SEQUENCEs that represent execute packets. */
4892 reorg_split_calls (rtx
*call_labels
)
4894 unsigned int reservation_mask
= 0;
4895 rtx_insn
*insn
= get_insns ();
4896 gcc_assert (NOTE_P (insn
));
4897 insn
= next_real_insn (insn
);
4901 rtx_insn
*next
= next_real_insn (insn
);
4903 if (DEBUG_INSN_P (insn
))
4906 if (GET_MODE (insn
) == TImode
)
4907 reservation_mask
= 0;
4908 uid
= INSN_UID (insn
);
4909 if (c6x_flag_schedule_insns2
&& recog_memoized (insn
) >= 0)
4910 reservation_mask
|= 1 << INSN_INFO_ENTRY (uid
).reservation
;
4912 if (returning_call_p (insn
))
4914 rtx label
= gen_label_rtx ();
4915 rtx labelref
= gen_rtx_LABEL_REF (Pmode
, label
);
4916 rtx reg
= gen_rtx_REG (SImode
, RETURN_ADDR_REGNO
);
4918 LABEL_NUSES (label
) = 2;
4919 if (!c6x_flag_schedule_insns2
)
4921 if (can_use_callp (insn
))
4922 convert_to_callp (insn
);
4927 emit_label_after (label
, insn
);
4929 /* Bundle the call and its delay slots into a single
4930 SEQUENCE. While these do not issue in parallel
4931 we need to group them into a single EH region. */
4933 PUT_MODE (insn
, TImode
);
4934 if (TARGET_INSNS_64
)
4936 t
= gen_addkpc (reg
, labelref
, GEN_INT (4));
4937 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4939 PUT_MODE (slot
[1], TImode
);
4940 gen_one_bundle (slot
, 2, 0);
4944 slot
[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4946 PUT_MODE (slot
[3], TImode
);
4947 t
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4948 slot
[2] = emit_insn_after (duplicate_cond (t
, insn
),
4950 PUT_MODE (slot
[2], TImode
);
4951 t
= gen_movsi_high (reg
, labelref
);
4952 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4954 PUT_MODE (slot
[1], TImode
);
4955 gen_one_bundle (slot
, 4, 0);
4961 /* If we scheduled, we reserved the .S2 unit for one or two
4962 cycles after the call. Emit the insns in these slots,
4963 unless it's possible to create a CALLP insn.
4964 Note that this works because the dependencies ensure that
4965 no insn setting/using B3 is scheduled in the delay slots of
4967 int this_clock
= insn_get_clock (insn
);
4968 rtx last_same_clock
;
4971 call_labels
[INSN_UID (insn
)] = label
;
4973 last_same_clock
= find_last_same_clock (insn
);
4975 if (can_use_callp (insn
))
4977 /* Find the first insn of the next execute packet. If it
4978 is the shadow insn corresponding to this call, we may
4979 use a CALLP insn. */
4981 next_nonnote_nondebug_insn (last_same_clock
);
4984 && insn_get_clock (shadow
) == this_clock
+ 5)
4986 convert_to_callp (shadow
);
4987 insn_set_clock (shadow
, this_clock
);
4988 INSN_INFO_ENTRY (INSN_UID (shadow
)).reservation
4990 INSN_INFO_ENTRY (INSN_UID (shadow
)).unit_mask
4991 = INSN_INFO_ENTRY (INSN_UID (last_same_clock
)).unit_mask
;
4992 if (GET_MODE (insn
) == TImode
)
4994 rtx_insn
*new_cycle_first
= NEXT_INSN (insn
);
4995 while (!NONDEBUG_INSN_P (new_cycle_first
)
4996 || GET_CODE (PATTERN (new_cycle_first
)) == USE
4997 || GET_CODE (PATTERN (new_cycle_first
)) == CLOBBER
)
4998 new_cycle_first
= NEXT_INSN (new_cycle_first
);
4999 PUT_MODE (new_cycle_first
, TImode
);
5000 if (new_cycle_first
!= shadow
)
5001 PUT_MODE (shadow
, VOIDmode
);
5002 INSN_INFO_ENTRY (INSN_UID (new_cycle_first
)).ebb_start
5003 = INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
;
5006 PUT_MODE (shadow
, VOIDmode
);
5011 after1
= find_next_cycle_insn (last_same_clock
, this_clock
+ 1);
5012 if (after1
== NULL_RTX
)
5013 after1
= last_same_clock
;
5015 after1
= find_last_same_clock (after1
);
5016 if (TARGET_INSNS_64
)
5018 rtx x1
= gen_addkpc (reg
, labelref
, const0_rtx
);
5019 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5020 insn_set_clock (x1
, this_clock
+ 1);
5021 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5022 if (after1
== last_same_clock
)
5023 PUT_MODE (x1
, TImode
);
5025 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5026 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5031 rtx after2
= find_next_cycle_insn (after1
, this_clock
+ 2);
5032 if (after2
== NULL_RTX
)
5034 x2
= gen_movsi_lo_sum (reg
, reg
, labelref
);
5035 x2
= emit_insn_after (duplicate_cond (x2
, insn
), after2
);
5036 x1
= gen_movsi_high (reg
, labelref
);
5037 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5038 insn_set_clock (x1
, this_clock
+ 1);
5039 insn_set_clock (x2
, this_clock
+ 2);
5040 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5041 INSN_INFO_ENTRY (INSN_UID (x2
)).reservation
= RESERVATION_S2
;
5042 if (after1
== last_same_clock
)
5043 PUT_MODE (x1
, TImode
);
5045 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5046 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5047 if (after1
== after2
)
5048 PUT_MODE (x2
, TImode
);
5050 INSN_INFO_ENTRY (INSN_UID (x2
)).unit_mask
5051 = INSN_INFO_ENTRY (INSN_UID (after2
)).unit_mask
;
5060 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
5061 insns as required for correctness. CALL_LABELS is the array that
5062 holds the return labels for call insns; we emit these here if
5063 scheduling was run earlier. */
5066 reorg_emit_nops (rtx
*call_labels
)
5071 int prev_clock
, earliest_bb_end
;
5072 int prev_implicit_nops
;
5073 rtx_insn
*insn
= get_insns ();
5075 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5076 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5077 clocks, we must insert a NOP.
5078 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5079 current basic block will finish. We must not allow the next basic block to
5080 begin before this cycle.
5081 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5082 a multi-cycle nop. The code is scheduled such that subsequent insns will
5083 show the cycle gap, but we needn't insert a real NOP instruction. */
5084 insn
= next_real_insn (insn
);
5085 last_call
= prev
= NULL
;
5087 earliest_bb_end
= 0;
5088 prev_implicit_nops
= 0;
5092 int this_clock
= -1;
5096 next
= next_real_insn (insn
);
5098 if (DEBUG_INSN_P (insn
)
5099 || GET_CODE (PATTERN (insn
)) == USE
5100 || GET_CODE (PATTERN (insn
)) == CLOBBER
5101 || shadow_or_blockage_p (insn
)
5102 || JUMP_TABLE_DATA_P (insn
))
5105 if (!c6x_flag_schedule_insns2
)
5106 /* No scheduling; ensure that no parallel issue happens. */
5107 PUT_MODE (insn
, TImode
);
5112 this_clock
= insn_get_clock (insn
);
5113 if (this_clock
!= prev_clock
)
5115 PUT_MODE (insn
, TImode
);
5119 cycles
= this_clock
- prev_clock
;
5121 cycles
-= prev_implicit_nops
;
5124 rtx nop
= emit_nop_after (cycles
- 1, prev
);
5125 insn_set_clock (nop
, prev_clock
+ prev_implicit_nops
+ 1);
5128 prev_clock
= this_clock
;
5131 && insn_get_clock (last_call
) + 6 <= this_clock
)
5133 emit_label_before (call_labels
[INSN_UID (last_call
)], insn
);
5134 last_call
= NULL_RTX
;
5136 prev_implicit_nops
= 0;
5140 /* Examine how many cycles the current insn takes, and adjust
5141 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5142 if (recog_memoized (insn
) >= 0
5143 /* If not scheduling, we've emitted NOPs after calls already. */
5144 && (c6x_flag_schedule_insns2
|| !returning_call_p (insn
)))
5146 max_cycles
= get_attr_cycles (insn
);
5147 if (get_attr_type (insn
) == TYPE_CALLP
)
5148 prev_implicit_nops
= 5;
5152 if (returning_call_p (insn
))
5155 if (c6x_flag_schedule_insns2
)
5157 gcc_assert (this_clock
>= 0);
5158 if (earliest_bb_end
< this_clock
+ max_cycles
)
5159 earliest_bb_end
= this_clock
+ max_cycles
;
5161 else if (max_cycles
> 1)
5162 emit_nop_after (max_cycles
- 1, insn
);
5168 if (c6x_flag_schedule_insns2
5169 && (next
== NULL_RTX
5170 || (GET_MODE (next
) == TImode
5171 && INSN_INFO_ENTRY (INSN_UID (next
)).ebb_start
))
5172 && earliest_bb_end
> 0)
5174 int cycles
= earliest_bb_end
- prev_clock
;
5177 prev
= emit_nop_after (cycles
- 1, prev
);
5178 insn_set_clock (prev
, prev_clock
+ prev_implicit_nops
+ 1);
5180 earliest_bb_end
= 0;
5185 emit_label_after (call_labels
[INSN_UID (last_call
)], prev
);
5186 last_call
= NULL_RTX
;
5192 /* If possible, split INSN, which we know is either a jump or a call, into a real
5193 insn and its shadow. */
5195 split_delayed_branch (rtx_insn
*insn
)
5197 int code
= recog_memoized (insn
);
5200 rtx pat
= PATTERN (insn
);
5202 if (GET_CODE (pat
) == COND_EXEC
)
5203 pat
= COND_EXEC_CODE (pat
);
5207 rtx src
= pat
, dest
= NULL_RTX
;
5209 if (GET_CODE (pat
) == SET
)
5211 dest
= SET_DEST (pat
);
5212 src
= SET_SRC (pat
);
5214 callee
= XEXP (XEXP (src
, 0), 0);
5215 if (SIBLING_CALL_P (insn
))
5218 newpat
= gen_indirect_sibcall_shadow ();
5220 newpat
= gen_sibcall_shadow (callee
);
5221 pat
= gen_real_jump (callee
);
5223 else if (dest
!= NULL_RTX
)
5226 newpat
= gen_indirect_call_value_shadow (dest
);
5228 newpat
= gen_call_value_shadow (dest
, callee
);
5229 pat
= gen_real_call (callee
);
5234 newpat
= gen_indirect_call_shadow ();
5236 newpat
= gen_call_shadow (callee
);
5237 pat
= gen_real_call (callee
);
5239 pat
= duplicate_cond (pat
, insn
);
5240 newpat
= duplicate_cond (newpat
, insn
);
5245 if (GET_CODE (pat
) == PARALLEL
5246 && GET_CODE (XVECEXP (pat
, 0, 0)) == RETURN
)
5248 newpat
= gen_return_shadow ();
5249 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5250 newpat
= duplicate_cond (newpat
, insn
);
5255 case CODE_FOR_br_true
:
5256 case CODE_FOR_br_false
:
5257 src
= SET_SRC (pat
);
5258 op
= XEXP (src
, code
== CODE_FOR_br_true
? 1 : 2);
5259 newpat
= gen_condjump_shadow (op
);
5260 pat
= gen_real_jump (op
);
5261 if (code
== CODE_FOR_br_true
)
5262 pat
= gen_rtx_COND_EXEC (VOIDmode
, XEXP (src
, 0), pat
);
5264 pat
= gen_rtx_COND_EXEC (VOIDmode
,
5265 reversed_comparison (XEXP (src
, 0),
5272 newpat
= gen_jump_shadow (op
);
5275 case CODE_FOR_indirect_jump
:
5276 newpat
= gen_indirect_jump_shadow ();
5279 case CODE_FOR_return_internal
:
5280 newpat
= gen_return_shadow ();
5281 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5288 i1
= emit_insn_before (pat
, insn
);
5289 PATTERN (insn
) = newpat
;
5290 INSN_CODE (insn
) = -1;
5291 record_delay_slot_pair (i1
, insn
, 5, 0);
5294 /* If INSN is a multi-cycle insn that should be handled properly in
5295 modulo-scheduling, split it into a real insn and a shadow.
5296 Return true if we made a change.
5298 It is valid for us to fail to split an insn; the caller has to deal
5299 with the possibility. Currently we handle loads and most mpy2 and
5302 split_delayed_nonbranch (rtx_insn
*insn
)
5304 int code
= recog_memoized (insn
);
5305 enum attr_type type
;
5307 rtx newpat
, src
, dest
;
5308 rtx pat
= PATTERN (insn
);
5312 if (GET_CODE (pat
) == COND_EXEC
)
5313 pat
= COND_EXEC_CODE (pat
);
5315 if (code
< 0 || GET_CODE (pat
) != SET
)
5317 src
= SET_SRC (pat
);
5318 dest
= SET_DEST (pat
);
5322 type
= get_attr_type (insn
);
5324 && (type
== TYPE_LOAD
5325 || type
== TYPE_LOADN
))
5328 && (GET_CODE (src
) != ZERO_EXTEND
5329 || !MEM_P (XEXP (src
, 0))))
5332 if (GET_MODE_SIZE (GET_MODE (dest
)) > 4
5333 && (GET_MODE_SIZE (GET_MODE (dest
)) != 8 || !TARGET_LDDW
))
5336 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5338 newpat
= gen_load_shadow (SET_DEST (pat
));
5339 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_LOAD
);
5343 && (type
== TYPE_MPY2
5344 || type
== TYPE_MPY4
))
5346 /* We don't handle floating point multiplies yet. */
5347 if (GET_MODE (dest
) == SFmode
)
5350 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5352 newpat
= gen_mult_shadow (SET_DEST (pat
));
5353 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_MULT
);
5354 delay
= type
== TYPE_MPY2
? 1 : 3;
5359 pat
= duplicate_cond (pat
, insn
);
5360 newpat
= duplicate_cond (newpat
, insn
);
5361 i1
= emit_insn_before (pat
, insn
);
5362 PATTERN (insn
) = newpat
;
5363 INSN_CODE (insn
) = -1;
5364 recog_memoized (insn
);
5365 recog_memoized (i1
);
5366 record_delay_slot_pair (i1
, insn
, delay
, 0);
5370 /* Examine if INSN is the result of splitting a load into a real load and a
5371 shadow, and if so, undo the transformation. */
5373 undo_split_delayed_nonbranch (rtx_insn
*insn
)
5375 int icode
= recog_memoized (insn
);
5376 enum attr_type type
;
5377 rtx prev_pat
, insn_pat
;
5382 type
= get_attr_type (insn
);
5383 if (type
!= TYPE_LOAD_SHADOW
&& type
!= TYPE_MULT_SHADOW
)
5385 prev
= PREV_INSN (insn
);
5386 prev_pat
= PATTERN (prev
);
5387 insn_pat
= PATTERN (insn
);
5388 if (GET_CODE (prev_pat
) == COND_EXEC
)
5390 prev_pat
= COND_EXEC_CODE (prev_pat
);
5391 insn_pat
= COND_EXEC_CODE (insn_pat
);
5394 gcc_assert (GET_CODE (prev_pat
) == UNSPEC
5395 && ((XINT (prev_pat
, 1) == UNSPEC_REAL_LOAD
5396 && type
== TYPE_LOAD_SHADOW
)
5397 || (XINT (prev_pat
, 1) == UNSPEC_REAL_MULT
5398 && type
== TYPE_MULT_SHADOW
)));
5399 insn_pat
= gen_rtx_SET (SET_DEST (insn_pat
),
5400 XVECEXP (prev_pat
, 0, 1));
5401 insn_pat
= duplicate_cond (insn_pat
, prev
);
5402 PATTERN (insn
) = insn_pat
;
5403 INSN_CODE (insn
) = -1;
5407 /* Split every insn (i.e. jumps and calls) which can have delay slots into
5408 two parts: the first one is scheduled normally and emits the instruction,
5409 while the second one is a shadow insn which shows the side effect taking
5410 place. The second one is placed in the right cycle by the scheduler, but
5411 not emitted as an assembly instruction. */
5414 split_delayed_insns (void)
5417 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5419 if (JUMP_P (insn
) || CALL_P (insn
))
5420 split_delayed_branch (insn
);
5424 /* For every insn that has an entry in the new_conditions vector, give it
5425 the appropriate predicate. */
5427 conditionalize_after_sched (void)
5431 FOR_EACH_BB_FN (bb
, cfun
)
5432 FOR_BB_INSNS (bb
, insn
)
5434 unsigned uid
= INSN_UID (insn
);
5436 if (!NONDEBUG_INSN_P (insn
) || uid
>= INSN_INFO_LENGTH
)
5438 cond
= INSN_INFO_ENTRY (uid
).new_cond
;
5439 if (cond
== NULL_RTX
)
5442 fprintf (dump_file
, "Conditionalizing insn %d\n", uid
);
5443 predicate_insn (insn
, cond
, true);
5447 /* A callback for the hw-doloop pass. This function examines INSN; if
5448 it is a loop_end pattern we recognize, return the reg rtx for the
5449 loop counter. Otherwise, return NULL_RTX. */
5452 hwloop_pattern_reg (rtx_insn
*insn
)
5456 if (!JUMP_P (insn
) || recog_memoized (insn
) != CODE_FOR_loop_end
)
5459 pat
= PATTERN (insn
);
5460 reg
= SET_DEST (XVECEXP (pat
, 0, 1));
5466 /* Return the number of cycles taken by BB, as computed by scheduling,
5467 including the latencies of all insns with delay slots. IGNORE is
5468 an insn we should ignore in the calculation, usually the final
5471 bb_earliest_end_cycle (basic_block bb
, rtx ignore
)
5476 FOR_BB_INSNS (bb
, insn
)
5478 int cycles
, this_clock
;
5480 if (LABEL_P (insn
) || NOTE_P (insn
) || DEBUG_INSN_P (insn
)
5481 || GET_CODE (PATTERN (insn
)) == USE
5482 || GET_CODE (PATTERN (insn
)) == CLOBBER
5486 this_clock
= insn_get_clock (insn
);
5487 cycles
= get_attr_cycles (insn
);
5489 if (earliest
< this_clock
+ cycles
)
5490 earliest
= this_clock
+ cycles
;
5495 /* Examine the insns in BB and remove all which have a uid greater or
5496 equal to MAX_UID. */
5498 filter_insns_above (basic_block bb
, int max_uid
)
5500 rtx_insn
*insn
, *next
;
5501 bool prev_ti
= false;
5502 int prev_cycle
= -1;
5504 FOR_BB_INSNS_SAFE (bb
, insn
, next
)
5507 if (!NONDEBUG_INSN_P (insn
))
5509 if (insn
== BB_END (bb
))
5511 this_cycle
= insn_get_clock (insn
);
5512 if (prev_ti
&& this_cycle
== prev_cycle
)
5514 gcc_assert (GET_MODE (insn
) != TImode
);
5515 PUT_MODE (insn
, TImode
);
5518 if (INSN_UID (insn
) >= max_uid
)
5520 if (GET_MODE (insn
) == TImode
)
5523 prev_cycle
= this_cycle
;
5530 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5533 c6x_asm_emit_except_personality (rtx personality
)
5535 fputs ("\t.personality\t", asm_out_file
);
5536 output_addr_const (asm_out_file
, personality
);
5537 fputc ('\n', asm_out_file
);
5540 /* Use a special assembly directive rather than a regular setion for
5541 unwind table data. */
5544 c6x_asm_init_sections (void)
5546 exception_section
= get_unnamed_section (0, output_section_asm_op
,
5550 /* A callback for the hw-doloop pass. Called to optimize LOOP in a
5551 machine-specific fashion; returns true if successful and false if
5552 the hwloop_fail function should be called. */
5555 hwloop_optimize (hwloop_info loop
)
5557 basic_block entry_bb
, bb
;
5558 rtx_insn
*seq
, *insn
, *prev
, *entry_after
, *end_packet
;
5559 rtx_insn
*head_insn
, *tail_insn
, *new_insns
, *last_insn
;
5561 int n_execute_packets
;
5564 int max_uid_before
, delayed_splits
;
5565 int i
, sp_ii
, min_ii
, max_ii
, max_parallel
, n_insns
, n_real_insns
, stages
;
5566 rtx_insn
**orig_vec
;
5568 rtx_insn
***insn_copies
;
5570 if (!c6x_flag_modulo_sched
|| !c6x_flag_schedule_insns2
5571 || !TARGET_INSNS_64PLUS
)
5574 if (loop
->iter_reg_used
|| loop
->depth
> 1)
5576 if (loop
->has_call
|| loop
->has_asm
)
5579 if (loop
->head
!= loop
->tail
)
5582 gcc_assert (loop
->incoming_dest
== loop
->head
);
5585 FOR_EACH_VEC_SAFE_ELT (loop
->incoming
, i
, entry_edge
)
5586 if (entry_edge
->flags
& EDGE_FALLTHRU
)
5588 if (entry_edge
== NULL
)
5591 reshuffle_units (loop
->head
);
5594 schedule_ebbs_init ();
5595 schedule_ebb (BB_HEAD (loop
->tail
), loop
->loop_end
, true);
5596 schedule_ebbs_finish ();
5600 loop_earliest
= bb_earliest_end_cycle (bb
, loop
->loop_end
) + 1;
5602 max_uid_before
= get_max_uid ();
5604 /* Split all multi-cycle operations, such as loads. For normal
5605 scheduling, we only do this for branches, as the generated code
5606 would otherwise not be interrupt-safe. When using sploop, it is
5607 safe and beneficial to split them. If any multi-cycle operations
5608 remain after splitting (because we don't handle them yet), we
5609 cannot pipeline the loop. */
5611 FOR_BB_INSNS (bb
, insn
)
5613 if (NONDEBUG_INSN_P (insn
))
5615 recog_memoized (insn
);
5616 if (split_delayed_nonbranch (insn
))
5618 else if (INSN_CODE (insn
) >= 0
5619 && get_attr_cycles (insn
) > 1)
5624 /* Count the number of insns as well as the number real insns, and save
5625 the original sequence of insns in case we must restore it later. */
5626 n_insns
= n_real_insns
= 0;
5627 FOR_BB_INSNS (bb
, insn
)
5630 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5633 orig_vec
= XNEWVEC (rtx_insn
*, n_insns
);
5635 FOR_BB_INSNS (bb
, insn
)
5636 orig_vec
[n_insns
++] = insn
;
5638 /* Count the unit reservations, and compute a minimum II from that
5640 count_unit_reqs (unit_reqs
, loop
->start_label
,
5641 PREV_INSN (loop
->loop_end
));
5642 merge_unit_reqs (unit_reqs
);
5644 min_ii
= res_mii (unit_reqs
);
5645 max_ii
= loop_earliest
< 15 ? loop_earliest
: 14;
5647 /* Make copies of the loop body, up to a maximum number of stages we want
5649 max_parallel
= loop_earliest
/ min_ii
+ 1;
5651 copies
= XCNEWVEC (rtx_insn
*, (max_parallel
+ 1) * n_real_insns
);
5652 insn_copies
= XNEWVEC (rtx_insn
**, max_parallel
+ 1);
5653 for (i
= 0; i
< max_parallel
+ 1; i
++)
5654 insn_copies
[i
] = copies
+ i
* n_real_insns
;
5656 head_insn
= next_nonnote_nondebug_insn (loop
->start_label
);
5657 tail_insn
= prev_real_insn (BB_END (bb
));
5660 FOR_BB_INSNS (bb
, insn
)
5661 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5662 insn_copies
[0][i
++] = insn
;
5664 sploop_max_uid_iter0
= get_max_uid ();
5666 /* Generate the copies of the loop body, and save them in the
5667 INSN_COPIES array. */
5669 for (i
= 0; i
< max_parallel
; i
++)
5672 rtx_insn
*this_iter
;
5674 this_iter
= duplicate_insn_chain (head_insn
, tail_insn
);
5678 rtx_insn
*prev_stage_insn
= insn_copies
[i
][j
];
5679 gcc_assert (INSN_CODE (this_iter
) == INSN_CODE (prev_stage_insn
));
5681 if (INSN_CODE (this_iter
) >= 0
5682 && (get_attr_type (this_iter
) == TYPE_LOAD_SHADOW
5683 || get_attr_type (this_iter
) == TYPE_MULT_SHADOW
))
5685 rtx_insn
*prev
= PREV_INSN (this_iter
);
5686 record_delay_slot_pair (prev
, this_iter
,
5687 get_attr_cycles (prev
) - 1, 0);
5690 record_delay_slot_pair (prev_stage_insn
, this_iter
, i
, 1);
5692 insn_copies
[i
+ 1][j
] = this_iter
;
5694 this_iter
= next_nonnote_nondebug_insn (this_iter
);
5697 new_insns
= get_insns ();
5698 last_insn
= insn_copies
[max_parallel
][n_real_insns
- 1];
5700 emit_insn_before (new_insns
, BB_END (bb
));
5702 /* Try to schedule the loop using varying initiation intervals,
5703 starting with the smallest possible and incrementing it
5705 for (sp_ii
= min_ii
; sp_ii
<= max_ii
; sp_ii
++)
5709 fprintf (dump_file
, "Trying to schedule for II %d\n", sp_ii
);
5711 df_clear_flags (DF_LR_RUN_DCE
);
5713 schedule_ebbs_init ();
5714 set_modulo_params (sp_ii
, max_parallel
, n_real_insns
,
5715 sploop_max_uid_iter0
);
5716 tmp_bb
= schedule_ebb (BB_HEAD (bb
), last_insn
, true);
5717 schedule_ebbs_finish ();
5722 fprintf (dump_file
, "Found schedule with II %d\n", sp_ii
);
5727 discard_delay_pairs_above (max_uid_before
);
5732 stages
= insn_get_clock (ss
.last_scheduled_iter0
) / sp_ii
+ 1;
5734 if (stages
== 1 && sp_ii
> 5)
5737 /* At this point, we know we've been successful, unless we find later that
5738 there are too many execute packets for the loop buffer to hold. */
5740 /* Assign reservations to the instructions in the loop. We must find
5741 the stage that contains the full loop kernel, and transfer the
5742 reservations of the instructions contained in it to the corresponding
5743 instructions from iteration 0, which are the only ones we'll keep. */
5744 assign_reservations (BB_HEAD (bb
), ss
.last_scheduled_insn
);
5745 SET_PREV_INSN (BB_END (bb
)) = ss
.last_scheduled_iter0
;
5746 SET_NEXT_INSN (ss
.last_scheduled_iter0
) = BB_END (bb
);
5747 filter_insns_above (bb
, sploop_max_uid_iter0
);
5749 for (i
= 0; i
< n_real_insns
; i
++)
5751 rtx insn
= insn_copies
[0][i
];
5752 int uid
= INSN_UID (insn
);
5753 int stage
= insn_uid_get_clock (uid
) / sp_ii
;
5755 if (stage
+ 1 < stages
)
5758 stage
= stages
- stage
- 1;
5759 copy_uid
= INSN_UID (insn_copies
[stage
][i
]);
5760 INSN_INFO_ENTRY (uid
).reservation
5761 = INSN_INFO_ENTRY (copy_uid
).reservation
;
5767 /* Compute the number of execute packets the pipelined form of the loop will
5770 n_execute_packets
= 0;
5771 for (insn
= loop
->start_label
;
5772 insn
!= loop
->loop_end
;
5773 insn
= NEXT_INSN (insn
))
5775 if (NONDEBUG_INSN_P (insn
) && GET_MODE (insn
) == TImode
5776 && !shadow_p (insn
))
5778 n_execute_packets
++;
5779 if (prev
&& insn_get_clock (prev
) + 1 != insn_get_clock (insn
))
5780 /* We need an extra NOP instruction. */
5781 n_execute_packets
++;
5787 end_packet
= ss
.last_scheduled_iter0
;
5788 while (!NONDEBUG_INSN_P (end_packet
) || GET_MODE (end_packet
) != TImode
)
5789 end_packet
= PREV_INSN (end_packet
);
5791 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5792 loop_earliest
= (stages
- 1) * sp_ii
;
5793 if (loop_earliest
> insn_get_clock (end_packet
))
5795 n_execute_packets
++;
5796 end_packet
= loop
->loop_end
;
5799 loop_earliest
= insn_get_clock (end_packet
);
5801 if (n_execute_packets
> 14)
5804 /* Generate the spkernel instruction, and place it at the appropriate
5806 PUT_MODE (end_packet
, VOIDmode
);
5808 insn
= emit_jump_insn_before (
5809 gen_spkernel (GEN_INT (stages
- 1),
5810 const0_rtx
, JUMP_LABEL (loop
->loop_end
)),
5812 JUMP_LABEL (insn
) = JUMP_LABEL (loop
->loop_end
);
5813 insn_set_clock (insn
, loop_earliest
);
5814 PUT_MODE (insn
, TImode
);
5815 INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
= false;
5816 delete_insn (loop
->loop_end
);
5818 /* Place the mvc and sploop instructions before the loop. */
5819 entry_bb
= entry_edge
->src
;
5823 insn
= emit_insn (gen_mvilc (loop
->iter_reg
));
5824 insn
= emit_insn (gen_sploop (GEN_INT (sp_ii
)));
5828 if (!single_succ_p (entry_bb
) || vec_safe_length (loop
->incoming
) > 1)
5834 emit_insn_before (seq
, BB_HEAD (loop
->head
));
5835 seq
= emit_label_before (gen_label_rtx (), seq
);
5837 new_bb
= create_basic_block (seq
, insn
, entry_bb
);
5838 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
5840 if (!(e
->flags
& EDGE_FALLTHRU
))
5841 redirect_edge_and_branch_force (e
, new_bb
);
5843 redirect_edge_succ (e
, new_bb
);
5845 make_edge (new_bb
, loop
->head
, 0);
5849 entry_after
= BB_END (entry_bb
);
5850 while (DEBUG_INSN_P (entry_after
)
5851 || (NOTE_P (entry_after
)
5852 && NOTE_KIND (entry_after
) != NOTE_INSN_BASIC_BLOCK
))
5853 entry_after
= PREV_INSN (entry_after
);
5854 emit_insn_after (seq
, entry_after
);
5859 /* Make sure we don't try to schedule this loop again. */
5860 for (ix
= 0; loop
->blocks
.iterate (ix
, &bb
); ix
++)
5861 bb
->flags
|= BB_DISABLE_SCHEDULE
;
5867 fprintf (dump_file
, "Unable to pipeline loop.\n");
5869 for (i
= 1; i
< n_insns
; i
++)
5871 SET_NEXT_INSN (orig_vec
[i
- 1]) = orig_vec
[i
];
5872 SET_PREV_INSN (orig_vec
[i
]) = orig_vec
[i
- 1];
5874 SET_PREV_INSN (orig_vec
[0]) = PREV_INSN (BB_HEAD (bb
));
5875 SET_NEXT_INSN (PREV_INSN (BB_HEAD (bb
))) = orig_vec
[0];
5876 SET_NEXT_INSN (orig_vec
[n_insns
- 1]) = NEXT_INSN (BB_END (bb
));
5877 SET_PREV_INSN (NEXT_INSN (BB_END (bb
))) = orig_vec
[n_insns
- 1];
5878 BB_HEAD (bb
) = orig_vec
[0];
5879 BB_END (bb
) = orig_vec
[n_insns
- 1];
5881 free_delay_pairs ();
5882 FOR_BB_INSNS (bb
, insn
)
5883 if (NONDEBUG_INSN_P (insn
))
5884 undo_split_delayed_nonbranch (insn
);
5888 /* A callback for the hw-doloop pass. Called when a loop we have discovered
5889 turns out not to be optimizable; we have to split the doloop_end pattern
5890 into a subtract and a test. */
5892 hwloop_fail (hwloop_info loop
)
5894 rtx insn
, test
, testreg
;
5897 fprintf (dump_file
, "splitting doloop insn %d\n",
5898 INSN_UID (loop
->loop_end
));
5899 insn
= gen_addsi3 (loop
->iter_reg
, loop
->iter_reg
, constm1_rtx
);
5900 /* See if we can emit the add at the head of the loop rather than at the
5902 if (loop
->head
== NULL
5903 || loop
->iter_reg_used_outside
5904 || loop
->iter_reg_used
5905 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REGNO (loop
->iter_reg
))
5906 || loop
->incoming_dest
!= loop
->head
5907 || EDGE_COUNT (loop
->head
->preds
) != 2)
5908 emit_insn_before (insn
, loop
->loop_end
);
5911 rtx_insn
*t
= loop
->start_label
;
5912 while (!NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_BASIC_BLOCK
)
5914 emit_insn_after (insn
, t
);
5917 testreg
= SET_DEST (XVECEXP (PATTERN (loop
->loop_end
), 0, 2));
5918 if (GET_CODE (testreg
) == SCRATCH
)
5919 testreg
= loop
->iter_reg
;
5921 emit_insn_before (gen_movsi (testreg
, loop
->iter_reg
), loop
->loop_end
);
5923 test
= gen_rtx_NE (VOIDmode
, testreg
, const0_rtx
);
5924 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
, testreg
, const0_rtx
,
5928 JUMP_LABEL (insn
) = loop
->start_label
;
5929 LABEL_NUSES (loop
->start_label
)++;
5930 delete_insn (loop
->loop_end
);
5933 static struct hw_doloop_hooks c6x_doloop_hooks
=
5940 /* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5941 doloop_end patterns where such optimizations are impossible. */
5946 reorg_loops (true, &c6x_doloop_hooks
);
5949 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5950 into a sequence that loads the return register and performs the call,
5951 and emit the return label.
5952 If scheduling after reload is requested, it happens here. */
5959 bool do_selsched
= (c6x_flag_schedule_insns2
&& flag_selective_scheduling2
5960 && !maybe_skip_selective_scheduling ());
5962 /* We are freeing block_for_insn in the toplev to keep compatibility
5963 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5964 compute_bb_for_insn ();
5966 df_clear_flags (DF_LR_RUN_DCE
);
5967 df_note_add_problem ();
5969 /* If optimizing, we'll have split before scheduling. */
5975 if (c6x_flag_schedule_insns2
)
5977 int sz
= get_max_uid () * 3 / 2 + 1;
5979 insn_info
.create (sz
);
5982 /* Make sure the real-jump insns we create are not deleted. When modulo-
5983 scheduling, situations where a reg is only stored in a loop can also
5984 cause dead code when doing the initial unrolling. */
5985 sched_no_dce
= true;
5989 if (c6x_flag_schedule_insns2
)
5991 split_delayed_insns ();
5992 timevar_push (TV_SCHED2
);
5994 run_selective_scheduling ();
5997 conditionalize_after_sched ();
5998 timevar_pop (TV_SCHED2
);
6000 free_delay_pairs ();
6002 sched_no_dce
= false;
6004 call_labels
= XCNEWVEC (rtx
, get_max_uid () + 1);
6006 reorg_split_calls (call_labels
);
6008 if (c6x_flag_schedule_insns2
)
6010 FOR_EACH_BB_FN (bb
, cfun
)
6011 if ((bb
->flags
& BB_DISABLE_SCHEDULE
) == 0)
6012 assign_reservations (BB_HEAD (bb
), BB_END (bb
));
6015 if (c6x_flag_var_tracking
)
6017 timevar_push (TV_VAR_TRACKING
);
6018 variable_tracking_main ();
6019 timevar_pop (TV_VAR_TRACKING
);
6022 reorg_emit_nops (call_labels
);
6024 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
6025 if (c6x_flag_schedule_insns2
)
6027 free_delay_pairs ();
6031 df_finish_pass (false);
6034 /* Called when a function has been assembled. It should perform all the
6035 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
6037 We free the reservation (and other scheduling) information here now that
6038 all insns have been output. */
6040 c6x_function_end (FILE *file
, const char *fname
)
6042 c6x_output_fn_unwind (file
);
6044 insn_info
.release ();
6046 if (!flag_inhibit_size_directive
)
6047 ASM_OUTPUT_MEASURED_SIZE (file
, fname
);
6050 /* Determine whether X is a shift with code CODE and an integer amount
6053 shift_p (rtx x
, enum rtx_code code
, int amount
)
6055 return (GET_CODE (x
) == code
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
6056 && INTVAL (XEXP (x
, 1)) == amount
);
6059 /* Compute a (partial) cost for rtx X. Return true if the complete
6060 cost has been computed, and false if subexpressions should be
6061 scanned. In either case, *TOTAL contains the cost result. */
6064 c6x_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
6067 int cost2
= COSTS_N_INSNS (1);
6073 if (outer_code
== SET
|| outer_code
== PLUS
)
6074 *total
= satisfies_constraint_IsB (x
) ? 0 : cost2
;
6075 else if (outer_code
== AND
|| outer_code
== IOR
|| outer_code
== XOR
6076 || outer_code
== MINUS
)
6077 *total
= satisfies_constraint_Is5 (x
) ? 0 : cost2
;
6078 else if (GET_RTX_CLASS (outer_code
) == RTX_COMPARE
6079 || GET_RTX_CLASS (outer_code
) == RTX_COMM_COMPARE
)
6080 *total
= satisfies_constraint_Iu4 (x
) ? 0 : cost2
;
6081 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
6082 || outer_code
== LSHIFTRT
)
6083 *total
= satisfies_constraint_Iu5 (x
) ? 0 : cost2
;
6092 *total
= COSTS_N_INSNS (2);
6096 /* Recognize a mult_highpart operation. */
6097 if ((GET_MODE (x
) == HImode
|| GET_MODE (x
) == SImode
)
6098 && GET_CODE (XEXP (x
, 0)) == LSHIFTRT
6099 && GET_MODE (XEXP (x
, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x
))
6100 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
6101 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
6102 && INTVAL (XEXP (XEXP (x
, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x
)))
6104 rtx mul
= XEXP (XEXP (x
, 0), 0);
6105 rtx op0
= XEXP (mul
, 0);
6106 rtx op1
= XEXP (mul
, 1);
6107 enum rtx_code code0
= GET_CODE (op0
);
6108 enum rtx_code code1
= GET_CODE (op1
);
6111 && (code0
== SIGN_EXTEND
|| code0
== ZERO_EXTEND
))
6112 || (GET_MODE (x
) == HImode
6113 && code0
== ZERO_EXTEND
&& code1
== SIGN_EXTEND
))
6115 if (GET_MODE (x
) == HImode
)
6116 *total
= COSTS_N_INSNS (2);
6118 *total
= COSTS_N_INSNS (12);
6119 *total
+= rtx_cost (XEXP (op0
, 0), code0
, 0, speed
);
6120 *total
+= rtx_cost (XEXP (op1
, 0), code1
, 0, speed
);
6129 if (GET_MODE (x
) == DImode
)
6130 *total
= COSTS_N_INSNS (CONSTANT_P (XEXP (x
, 1)) ? 4 : 15);
6132 *total
= COSTS_N_INSNS (1);
6137 *total
= COSTS_N_INSNS (1);
6138 op0
= code
== PLUS
? XEXP (x
, 0) : XEXP (x
, 1);
6139 op1
= code
== PLUS
? XEXP (x
, 1) : XEXP (x
, 0);
6140 if (GET_MODE_SIZE (GET_MODE (x
)) <= UNITS_PER_WORD
6141 && INTEGRAL_MODE_P (GET_MODE (x
))
6142 && GET_CODE (op0
) == MULT
6143 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
6144 && (INTVAL (XEXP (op0
, 1)) == 2
6145 || INTVAL (XEXP (op0
, 1)) == 4
6146 || (code
== PLUS
&& INTVAL (XEXP (op0
, 1)) == 8)))
6148 *total
+= rtx_cost (XEXP (op0
, 0), ASHIFT
, 0, speed
);
6149 *total
+= rtx_cost (op1
, (enum rtx_code
) code
, 1, speed
);
6157 if (GET_MODE (x
) == DFmode
)
6160 *total
= COSTS_N_INSNS (speed
? 10 : 1);
6162 *total
= COSTS_N_INSNS (speed
? 200 : 4);
6164 else if (GET_MODE (x
) == SFmode
)
6167 *total
= COSTS_N_INSNS (speed
? 4 : 1);
6169 *total
= COSTS_N_INSNS (speed
? 100 : 4);
6171 else if (GET_MODE (x
) == DImode
)
6174 && GET_CODE (op0
) == GET_CODE (op1
)
6175 && (GET_CODE (op0
) == ZERO_EXTEND
6176 || GET_CODE (op0
) == SIGN_EXTEND
))
6178 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6179 op0
= XEXP (op0
, 0);
6180 op1
= XEXP (op1
, 0);
6183 /* Maybe improve this laster. */
6184 *total
= COSTS_N_INSNS (20);
6186 else if (GET_MODE (x
) == SImode
)
6188 if (((GET_CODE (op0
) == ZERO_EXTEND
6189 || GET_CODE (op0
) == SIGN_EXTEND
6190 || shift_p (op0
, LSHIFTRT
, 16))
6191 && (GET_CODE (op1
) == SIGN_EXTEND
6192 || GET_CODE (op1
) == ZERO_EXTEND
6193 || scst5_operand (op1
, SImode
)
6194 || shift_p (op1
, ASHIFTRT
, 16)
6195 || shift_p (op1
, LSHIFTRT
, 16)))
6196 || (shift_p (op0
, ASHIFTRT
, 16)
6197 && (GET_CODE (op1
) == SIGN_EXTEND
6198 || shift_p (op1
, ASHIFTRT
, 16))))
6200 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6201 op0
= XEXP (op0
, 0);
6202 if (scst5_operand (op1
, SImode
))
6205 op1
= XEXP (op1
, 0);
6208 *total
= COSTS_N_INSNS (1);
6209 else if (TARGET_MPY32
)
6210 *total
= COSTS_N_INSNS (4);
6212 *total
= COSTS_N_INSNS (6);
6214 else if (GET_MODE (x
) == HImode
)
6215 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6217 if (GET_CODE (op0
) != REG
6218 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
6219 *total
+= rtx_cost (op0
, MULT
, 0, speed
);
6220 if (op1
&& GET_CODE (op1
) != REG
6221 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
6222 *total
+= rtx_cost (op1
, MULT
, 1, speed
);
6227 /* This is a bit random; assuming on average there'll be 16 leading
6228 zeros. FIXME: estimate better for constant dividends. */
6229 *total
= COSTS_N_INSNS (6 + 3 * 16);
6233 /* Recognize the cmp_and/ior patterns. */
6235 if ((GET_CODE (op0
) == EQ
|| GET_CODE (op0
) == NE
)
6236 && REG_P (XEXP (op0
, 0))
6237 && XEXP (op0
, 1) == const0_rtx
6238 && rtx_equal_p (XEXP (x
, 1), XEXP (op0
, 0)))
6240 *total
= rtx_cost (XEXP (x
, 1), (enum rtx_code
) outer_code
,
6251 /* Implements target hook vector_mode_supported_p. */
6254 c6x_vector_mode_supported_p (machine_mode mode
)
6269 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6271 c6x_preferred_simd_mode (machine_mode mode
)
6285 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6288 c6x_scalar_mode_supported_p (machine_mode mode
)
6290 if (ALL_FIXED_POINT_MODE_P (mode
)
6291 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
6294 return default_scalar_mode_supported_p (mode
);
6297 /* Output a reference from a function exception table to the type_info
6298 object X. Output these via a special assembly directive. */
6301 c6x_output_ttype (rtx x
)
6303 /* Use special relocations for symbol references. */
6304 if (GET_CODE (x
) != CONST_INT
)
6305 fputs ("\t.ehtype\t", asm_out_file
);
6307 fputs ("\t.word\t", asm_out_file
);
6308 output_addr_const (asm_out_file
, x
);
6309 fputc ('\n', asm_out_file
);
6314 /* Modify the return address of the current function. */
6317 c6x_set_return_address (rtx source
, rtx scratch
)
6319 struct c6x_frame frame
;
6321 HOST_WIDE_INT offset
;
6323 c6x_compute_frame_layout (&frame
);
6324 if (! c6x_save_reg (RETURN_ADDR_REGNO
))
6325 emit_move_insn (gen_rtx_REG (Pmode
, RETURN_ADDR_REGNO
), source
);
6329 if (frame_pointer_needed
)
6331 addr
= hard_frame_pointer_rtx
;
6332 offset
= frame
.b3_offset
;
6336 addr
= stack_pointer_rtx
;
6337 offset
= frame
.to_allocate
- frame
.b3_offset
;
6340 /* TODO: Use base+offset loads where possible. */
6343 HOST_WIDE_INT low
= trunc_int_for_mode (offset
, HImode
);
6345 emit_insn (gen_movsi_high (scratch
, GEN_INT (low
)));
6347 emit_insn (gen_movsi_lo_sum (scratch
, scratch
, GEN_INT(offset
)));
6348 emit_insn (gen_addsi3 (scratch
, addr
, scratch
));
6352 emit_move_insn (gen_frame_mem (Pmode
, addr
), source
);
6356 /* We save pairs of registers using a DImode store. Describe the component
6357 registers for DWARF generation code. */
6360 c6x_dwarf_register_span (rtx rtl
)
6363 unsigned real_regno
;
6368 regno
= REGNO (rtl
);
6369 nregs
= HARD_REGNO_NREGS (regno
, GET_MODE (rtl
));
6373 p
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc(nregs
));
6374 for (i
= 0; i
< nregs
; i
++)
6376 if (TARGET_BIG_ENDIAN
)
6377 real_regno
= regno
+ nregs
- (i
+ 1);
6379 real_regno
= regno
+ i
;
6381 XVECEXP (p
, 0, i
) = gen_rtx_REG (SImode
, real_regno
);
6387 /* Codes for all the C6X builtins. */
6422 static GTY(()) tree c6x_builtin_decls
[C6X_BUILTIN_MAX
];
6424 /* Return the C6X builtin for CODE. */
6426 c6x_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
6428 if (code
>= C6X_BUILTIN_MAX
)
6429 return error_mark_node
;
6431 return c6x_builtin_decls
[code
];
6434 #define def_builtin(NAME, TYPE, CODE) \
6437 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6439 c6x_builtin_decls[CODE] = bdecl; \
6442 /* Set up all builtin functions for this target. */
6444 c6x_init_builtins (void)
6446 tree V4QI_type_node
= build_vector_type (unsigned_intQI_type_node
, 4);
6447 tree V2HI_type_node
= build_vector_type (intHI_type_node
, 2);
6448 tree V2SI_type_node
= build_vector_type (intSI_type_node
, 2);
6450 = build_function_type_list (integer_type_node
, integer_type_node
,
6452 tree int_ftype_int_int
6453 = build_function_type_list (integer_type_node
, integer_type_node
,
6454 integer_type_node
, NULL_TREE
);
6455 tree v2hi_ftype_v2hi
6456 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
6457 tree v4qi_ftype_v4qi_v4qi
6458 = build_function_type_list (V4QI_type_node
, V4QI_type_node
,
6459 V4QI_type_node
, NULL_TREE
);
6460 tree v2hi_ftype_v2hi_v2hi
6461 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
6462 V2HI_type_node
, NULL_TREE
);
6463 tree v2si_ftype_v2hi_v2hi
6464 = build_function_type_list (V2SI_type_node
, V2HI_type_node
,
6465 V2HI_type_node
, NULL_TREE
);
6467 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int
,
6469 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int
,
6471 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi
,
6473 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi
,
6475 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi
,
6477 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi
,
6479 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi
,
6481 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi
,
6483 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi
,
6485 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi
,
6486 C6X_BUILTIN_SADDU4
);
6487 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi
,
6490 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int
,
6492 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int
,
6494 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int
,
6495 C6X_BUILTIN_SMPYHL
);
6496 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int
,
6497 C6X_BUILTIN_SMPYLH
);
6499 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int
,
6501 def_builtin ("__builtin_c6x_subc", int_ftype_int_int
,
6504 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi
,
6506 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi
,
6509 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int
,
6511 def_builtin ("__builtin_c6x_extr", int_ftype_int_int
,
6513 def_builtin ("__builtin_c6x_extru", int_ftype_int_int
,
6516 def_builtin ("__builtin_c6x_abs", int_ftype_int
, C6X_BUILTIN_ABS
);
6517 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi
, C6X_BUILTIN_ABS2
);
6521 struct builtin_description
6523 const enum insn_code icode
;
6524 const char *const name
;
6525 const enum c6x_builtins code
;
6528 static const struct builtin_description bdesc_2arg
[] =
6530 { CODE_FOR_saddsi3
, "__builtin_c6x_sadd", C6X_BUILTIN_SADD
},
6531 { CODE_FOR_ssubsi3
, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB
},
6532 { CODE_FOR_addv2hi3
, "__builtin_c6x_add2", C6X_BUILTIN_ADD2
},
6533 { CODE_FOR_subv2hi3
, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2
},
6534 { CODE_FOR_addv4qi3
, "__builtin_c6x_add4", C6X_BUILTIN_ADD4
},
6535 { CODE_FOR_subv4qi3
, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4
},
6536 { CODE_FOR_ss_addv2hi3
, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2
},
6537 { CODE_FOR_ss_subv2hi3
, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2
},
6538 { CODE_FOR_us_addv4qi3
, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4
},
6540 { CODE_FOR_subcsi3
, "__builtin_c6x_subc", C6X_BUILTIN_SUBC
},
6541 { CODE_FOR_ss_ashlsi3
, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL
},
6543 { CODE_FOR_avgv2hi3
, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2
},
6544 { CODE_FOR_uavgv4qi3
, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4
},
6546 { CODE_FOR_mulhqsq3
, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY
},
6547 { CODE_FOR_mulhqsq3_hh
, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH
},
6548 { CODE_FOR_mulhqsq3_lh
, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH
},
6549 { CODE_FOR_mulhqsq3_hl
, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL
},
6551 { CODE_FOR_mulv2hqv2sq3
, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2
},
6553 { CODE_FOR_clrr
, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR
},
6554 { CODE_FOR_extr
, "__builtin_c6x_extr", C6X_BUILTIN_EXTR
},
6555 { CODE_FOR_extru
, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU
}
6558 static const struct builtin_description bdesc_1arg
[] =
6560 { CODE_FOR_ssabssi2
, "__builtin_c6x_abs", C6X_BUILTIN_ABS
},
6561 { CODE_FOR_ssabsv2hi2
, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2
}
6564 /* Errors in the source file can cause expand_expr to return const0_rtx
6565 where we expect a vector. To avoid crashing, use one of the vector
6566 clear instructions. */
6568 safe_vector_operand (rtx x
, machine_mode mode
)
6570 if (x
!= const0_rtx
)
6572 x
= gen_reg_rtx (SImode
);
6574 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
6575 return gen_lowpart (mode
, x
);
6578 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6579 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6582 c6x_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
6585 int offs
= match_op
? 1 : 0;
6587 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6588 tree arg1
= CALL_EXPR_ARG (exp
, 1);
6589 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6590 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6591 machine_mode op0mode
= GET_MODE (op0
);
6592 machine_mode op1mode
= GET_MODE (op1
);
6593 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6594 machine_mode mode0
= insn_data
[icode
].operand
[1 + offs
].mode
;
6595 machine_mode mode1
= insn_data
[icode
].operand
[2 + offs
].mode
;
6598 if (VECTOR_MODE_P (mode0
))
6599 op0
= safe_vector_operand (op0
, mode0
);
6600 if (VECTOR_MODE_P (mode1
))
6601 op1
= safe_vector_operand (op1
, mode1
);
6604 || GET_MODE (target
) != tmode
6605 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6607 if (tmode
== SQmode
|| tmode
== V2SQmode
)
6609 ret
= gen_reg_rtx (tmode
== SQmode
? SImode
: V2SImode
);
6610 target
= gen_lowpart (tmode
, ret
);
6613 target
= gen_reg_rtx (tmode
);
6616 if ((op0mode
== V2HImode
|| op0mode
== SImode
|| op0mode
== VOIDmode
)
6617 && (mode0
== V2HQmode
|| mode0
== HQmode
|| mode0
== SQmode
))
6620 op0
= gen_lowpart (mode0
, op0
);
6622 if ((op1mode
== V2HImode
|| op1mode
== SImode
|| op1mode
== VOIDmode
)
6623 && (mode1
== V2HQmode
|| mode1
== HQmode
|| mode1
== SQmode
))
6626 op1
= gen_lowpart (mode1
, op1
);
6628 /* In case the insn wants input operands in modes different from
6629 the result, abort. */
6630 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
6631 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
6633 if (! (*insn_data
[icode
].operand
[1 + offs
].predicate
) (op0
, mode0
))
6634 op0
= copy_to_mode_reg (mode0
, op0
);
6635 if (! (*insn_data
[icode
].operand
[2 + offs
].predicate
) (op1
, mode1
))
6636 op1
= copy_to_mode_reg (mode1
, op1
);
6639 pat
= GEN_FCN (icode
) (target
, target
, op0
, op1
);
6641 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
6651 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
6654 c6x_expand_unop_builtin (enum insn_code icode
, tree exp
,
6658 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6659 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6660 machine_mode op0mode
= GET_MODE (op0
);
6661 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6662 machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6665 || GET_MODE (target
) != tmode
6666 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6667 target
= gen_reg_rtx (tmode
);
6669 if (VECTOR_MODE_P (mode0
))
6670 op0
= safe_vector_operand (op0
, mode0
);
6672 if (op0mode
== SImode
&& mode0
== HImode
)
6675 op0
= gen_lowpart (HImode
, op0
);
6677 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
6679 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6680 op0
= copy_to_mode_reg (mode0
, op0
);
6682 pat
= GEN_FCN (icode
) (target
, op0
);
6689 /* Expand an expression EXP that calls a built-in function,
6690 with result going to TARGET if that's convenient
6691 (and in mode MODE if that's convenient).
6692 SUBTARGET may be used as the target for computing one of EXP's operands.
6693 IGNORE is nonzero if the value is to be ignored. */
6696 c6x_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
6697 rtx subtarget ATTRIBUTE_UNUSED
,
6698 machine_mode mode ATTRIBUTE_UNUSED
,
6699 int ignore ATTRIBUTE_UNUSED
)
6702 const struct builtin_description
*d
;
6703 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
6704 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
6706 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6707 if (d
->code
== fcode
)
6708 return c6x_expand_binop_builtin (d
->icode
, exp
, target
,
6709 fcode
== C6X_BUILTIN_CLRR
);
6711 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6712 if (d
->code
== fcode
)
6713 return c6x_expand_unop_builtin (d
->icode
, exp
, target
);
6718 /* Target unwind frame info is generated from dwarf CFI directives, so
6719 always output dwarf2 unwind info. */
6721 static enum unwind_info_type
6722 c6x_debug_unwind_info (void)
6724 if (flag_unwind_tables
|| flag_exceptions
)
6727 return default_debug_unwind_info ();
6730 /* Target Structure. */
6732 /* Initialize the GCC target structure. */
6733 #undef TARGET_FUNCTION_ARG
6734 #define TARGET_FUNCTION_ARG c6x_function_arg
6735 #undef TARGET_FUNCTION_ARG_ADVANCE
6736 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6737 #undef TARGET_FUNCTION_ARG_BOUNDARY
6738 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6739 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6740 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6741 c6x_function_arg_round_boundary
6742 #undef TARGET_FUNCTION_VALUE_REGNO_P
6743 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6744 #undef TARGET_FUNCTION_VALUE
6745 #define TARGET_FUNCTION_VALUE c6x_function_value
6746 #undef TARGET_LIBCALL_VALUE
6747 #define TARGET_LIBCALL_VALUE c6x_libcall_value
6748 #undef TARGET_RETURN_IN_MEMORY
6749 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6750 #undef TARGET_RETURN_IN_MSB
6751 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
6752 #undef TARGET_PASS_BY_REFERENCE
6753 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6754 #undef TARGET_CALLEE_COPIES
6755 #define TARGET_CALLEE_COPIES c6x_callee_copies
6756 #undef TARGET_STRUCT_VALUE_RTX
6757 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6758 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6759 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6761 #undef TARGET_ASM_OUTPUT_MI_THUNK
6762 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6763 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6764 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6766 #undef TARGET_BUILD_BUILTIN_VA_LIST
6767 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6769 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6770 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6771 #undef TARGET_TRAMPOLINE_INIT
6772 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6774 #undef TARGET_LEGITIMATE_CONSTANT_P
6775 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6776 #undef TARGET_LEGITIMATE_ADDRESS_P
6777 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6779 #undef TARGET_IN_SMALL_DATA_P
6780 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6781 #undef TARGET_ASM_SELECT_RTX_SECTION
6782 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6783 #undef TARGET_ASM_SELECT_SECTION
6784 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6785 #undef TARGET_ASM_UNIQUE_SECTION
6786 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6787 #undef TARGET_SECTION_TYPE_FLAGS
6788 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6789 #undef TARGET_HAVE_SRODATA_SECTION
6790 #define TARGET_HAVE_SRODATA_SECTION true
6791 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6792 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6794 #undef TARGET_OPTION_OVERRIDE
6795 #define TARGET_OPTION_OVERRIDE c6x_option_override
6796 #undef TARGET_CONDITIONAL_REGISTER_USAGE
6797 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6799 #undef TARGET_INIT_LIBFUNCS
6800 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6801 #undef TARGET_LIBFUNC_GNU_PREFIX
6802 #define TARGET_LIBFUNC_GNU_PREFIX true
6804 #undef TARGET_SCALAR_MODE_SUPPORTED_P
6805 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6806 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6807 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6808 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6809 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6811 #undef TARGET_RTX_COSTS
6812 #define TARGET_RTX_COSTS c6x_rtx_costs
6814 #undef TARGET_SCHED_INIT
6815 #define TARGET_SCHED_INIT c6x_sched_init
6816 #undef TARGET_SCHED_SET_SCHED_FLAGS
6817 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6818 #undef TARGET_SCHED_ADJUST_COST
6819 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6820 #undef TARGET_SCHED_ISSUE_RATE
6821 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6822 #undef TARGET_SCHED_VARIABLE_ISSUE
6823 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6824 #undef TARGET_SCHED_REORDER
6825 #define TARGET_SCHED_REORDER c6x_sched_reorder
6826 #undef TARGET_SCHED_REORDER2
6827 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6828 #undef TARGET_SCHED_DFA_NEW_CYCLE
6829 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6830 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6831 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6832 #undef TARGET_SCHED_EXPOSED_PIPELINE
6833 #define TARGET_SCHED_EXPOSED_PIPELINE true
6835 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6836 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6837 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
6838 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6839 #undef TARGET_SCHED_SET_SCHED_CONTEXT
6840 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6841 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6842 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6843 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
6844 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6846 #undef TARGET_CAN_ELIMINATE
6847 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
6849 #undef TARGET_PREFERRED_RENAME_CLASS
6850 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6852 #undef TARGET_MACHINE_DEPENDENT_REORG
6853 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6855 #undef TARGET_ASM_FILE_START
6856 #define TARGET_ASM_FILE_START c6x_file_start
6858 #undef TARGET_PRINT_OPERAND
6859 #define TARGET_PRINT_OPERAND c6x_print_operand
6860 #undef TARGET_PRINT_OPERAND_ADDRESS
6861 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6862 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6863 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6865 /* C6x unwinding tables use a different format for the typeinfo tables. */
6866 #undef TARGET_ASM_TTYPE
6867 #define TARGET_ASM_TTYPE c6x_output_ttype
6869 /* The C6x ABI follows the ARM EABI exception handling rules. */
6870 #undef TARGET_ARM_EABI_UNWINDER
6871 #define TARGET_ARM_EABI_UNWINDER true
6873 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6874 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6876 #undef TARGET_ASM_INIT_SECTIONS
6877 #define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6879 #undef TARGET_DEBUG_UNWIND_INFO
6880 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6882 #undef TARGET_DWARF_REGISTER_SPAN
6883 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6885 #undef TARGET_INIT_BUILTINS
6886 #define TARGET_INIT_BUILTINS c6x_init_builtins
6887 #undef TARGET_EXPAND_BUILTIN
6888 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6889 #undef TARGET_BUILTIN_DECL
6890 #define TARGET_BUILTIN_DECL c6x_builtin_decl
6892 struct gcc_target targetm
= TARGET_INITIALIZER
;