1 /* Target Code for TI C6X
2 Copyright (C) 2010-2014 Free Software Foundation, Inc.
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "stor-layout.h"
31 #include "stringpool.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
35 #include "insn-codes.h"
41 #include "dominance.h"
47 #include "cfgcleanup.h"
49 #include "basic-block.h"
50 #include "sched-int.h"
54 #include "tm-constrs.h"
60 #include "hard-reg-set.h"
63 #include "diagnostic-core.h"
66 #include "plugin-api.h"
69 #include "langhooks.h"
71 #include "target-def.h"
72 #include "sel-sched.h"
75 #include "hw-doloop.h"
76 #include "regrename.h"
78 #include "gimple-expr.h"
81 /* Table of supported architecture variants. */
85 enum c6x_cpu_type type
;
86 unsigned short features
;
89 /* A list of all ISAs, mapping each one to a representative device.
90 Used for -march selection. */
91 static const c6x_arch_table all_isas
[] =
93 #define C6X_ISA(NAME,DEVICE,FLAGS) \
94 { NAME, DEVICE, FLAGS },
95 #include "c6x-isas.def"
97 { NULL
, C6X_CPU_C62X
, 0 }
100 /* This is the parsed result of the "-march=" option, if given. */
101 enum c6x_cpu_type c6x_arch
= C6X_DEFAULT_ARCH
;
103 /* A mask of insn types that are allowed by the architecture selected by
104 the -march option. */
105 unsigned long c6x_insn_mask
= C6X_DEFAULT_INSN_MASK
;
107 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
109 static rtx_insn
*c6x_current_insn
= NULL
;
111 /* A decl we build to access __c6xabi_DSBT_base. */
112 static GTY(()) tree dsbt_decl
;
114 /* Determines whether we run our final scheduling pass or not. We always
115 avoid the normal second scheduling pass. */
116 static int c6x_flag_schedule_insns2
;
118 /* Determines whether we run variable tracking in machine dependent
120 static int c6x_flag_var_tracking
;
122 /* Determines whether we use modulo scheduling. */
123 static int c6x_flag_modulo_sched
;
125 /* Record the state of flag_pic before we set it to 1 for DSBT. */
126 int c6x_initial_flag_pic
;
130 /* We record the clock cycle for every insn during scheduling. */
132 /* After scheduling, we run assign_reservations to choose unit
133 reservations for all insns. These are recorded here. */
135 /* Records the new condition for insns which must be made
136 conditional after scheduling. An entry of NULL_RTX means no such
137 change is necessary. */
139 /* True for the first insn that was scheduled in an ebb. */
141 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
142 bits rather than storing the state. Meaningful only for the last
144 unsigned int unit_mask
;
145 } c6x_sched_insn_info
;
148 /* Record a c6x_sched_insn_info structure for every insn in the function. */
149 static vec
<c6x_sched_insn_info
> insn_info
;
151 #define INSN_INFO_LENGTH (insn_info).length ()
152 #define INSN_INFO_ENTRY(N) (insn_info[(N)])
154 static bool done_cfi_sections
;
156 #define RESERVATION_FLAG_D 1
157 #define RESERVATION_FLAG_L 2
158 #define RESERVATION_FLAG_S 4
159 #define RESERVATION_FLAG_M 8
160 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
161 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
162 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
163 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
165 /* The DFA names of the units. */
166 static const char *const c6x_unit_names
[] =
168 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
169 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
172 /* The DFA unit number for each unit in c6x_unit_names[]. */
173 static int c6x_unit_codes
[ARRAY_SIZE (c6x_unit_names
)];
175 /* Unit query IDs. */
176 #define UNIT_QID_D1 0
177 #define UNIT_QID_L1 1
178 #define UNIT_QID_S1 2
179 #define UNIT_QID_M1 3
180 #define UNIT_QID_FPS1 4
181 #define UNIT_QID_FPL1 5
182 #define UNIT_QID_ADDDPS1 6
183 #define UNIT_QID_ADDDPL1 7
184 #define UNIT_QID_SIDE_OFFSET 8
186 #define RESERVATION_S1 2
187 #define RESERVATION_S2 10
189 /* An enum for the unit requirements we count in the UNIT_REQS table. */
205 /* A table used to count unit requirements. Used when computing minimum
206 iteration intervals. */
207 typedef int unit_req_table
[2][UNIT_REQ_MAX
];
208 static unit_req_table unit_reqs
;
210 /* Register map for debugging. */
211 unsigned const dbx_register_map
[FIRST_PSEUDO_REGISTER
] =
213 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
214 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
216 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
218 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
220 -1, -1, -1 /* FP, ARGP, ILC. */
223 /* Allocate a new, cleared machine_function structure. */
225 static struct machine_function
*
226 c6x_init_machine_status (void)
228 return ggc_cleared_alloc
<machine_function
> ();
231 /* Implement TARGET_OPTION_OVERRIDE. */
234 c6x_option_override (void)
238 if (global_options_set
.x_c6x_arch_option
)
240 c6x_arch
= all_isas
[c6x_arch_option
].type
;
241 c6x_insn_mask
&= ~C6X_INSNS_ALL_CPU_BITS
;
242 c6x_insn_mask
|= all_isas
[c6x_arch_option
].features
;
245 c6x_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
246 flag_schedule_insns_after_reload
= 0;
248 c6x_flag_modulo_sched
= flag_modulo_sched
;
249 flag_modulo_sched
= 0;
251 init_machine_status
= c6x_init_machine_status
;
253 for (i
= 0; i
< ARRAY_SIZE (c6x_unit_names
); i
++)
254 c6x_unit_codes
[i
] = get_cpu_unit_code (c6x_unit_names
[i
]);
256 if (flag_pic
&& !TARGET_DSBT
)
258 error ("-fpic and -fPIC not supported without -mdsbt on this target");
261 c6x_initial_flag_pic
= flag_pic
;
262 if (TARGET_DSBT
&& !flag_pic
)
267 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
270 c6x_conditional_register_usage (void)
273 if (c6x_arch
== C6X_CPU_C62X
|| c6x_arch
== C6X_CPU_C67X
)
274 for (i
= 16; i
< 32; i
++)
277 fixed_regs
[32 + i
] = 1;
281 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_A_REGS
],
283 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_REGS
],
285 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_A_REGS
],
287 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_REGS
],
292 static GTY(()) rtx eqdf_libfunc
;
293 static GTY(()) rtx nedf_libfunc
;
294 static GTY(()) rtx ledf_libfunc
;
295 static GTY(()) rtx ltdf_libfunc
;
296 static GTY(()) rtx gedf_libfunc
;
297 static GTY(()) rtx gtdf_libfunc
;
298 static GTY(()) rtx eqsf_libfunc
;
299 static GTY(()) rtx nesf_libfunc
;
300 static GTY(()) rtx lesf_libfunc
;
301 static GTY(()) rtx ltsf_libfunc
;
302 static GTY(()) rtx gesf_libfunc
;
303 static GTY(()) rtx gtsf_libfunc
;
304 static GTY(()) rtx strasgi_libfunc
;
305 static GTY(()) rtx strasgi64p_libfunc
;
307 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
308 functions to match the C6x ABI. */
311 c6x_init_libfuncs (void)
313 /* Double-precision floating-point arithmetic. */
314 set_optab_libfunc (add_optab
, DFmode
, "__c6xabi_addd");
315 set_optab_libfunc (sdiv_optab
, DFmode
, "__c6xabi_divd");
316 set_optab_libfunc (smul_optab
, DFmode
, "__c6xabi_mpyd");
317 set_optab_libfunc (neg_optab
, DFmode
, "__c6xabi_negd");
318 set_optab_libfunc (sub_optab
, DFmode
, "__c6xabi_subd");
320 /* Single-precision floating-point arithmetic. */
321 set_optab_libfunc (add_optab
, SFmode
, "__c6xabi_addf");
322 set_optab_libfunc (sdiv_optab
, SFmode
, "__c6xabi_divf");
323 set_optab_libfunc (smul_optab
, SFmode
, "__c6xabi_mpyf");
324 set_optab_libfunc (neg_optab
, SFmode
, "__c6xabi_negf");
325 set_optab_libfunc (sub_optab
, SFmode
, "__c6xabi_subf");
327 /* Floating-point comparisons. */
328 eqsf_libfunc
= init_one_libfunc ("__c6xabi_eqf");
329 nesf_libfunc
= init_one_libfunc ("__c6xabi_neqf");
330 lesf_libfunc
= init_one_libfunc ("__c6xabi_lef");
331 ltsf_libfunc
= init_one_libfunc ("__c6xabi_ltf");
332 gesf_libfunc
= init_one_libfunc ("__c6xabi_gef");
333 gtsf_libfunc
= init_one_libfunc ("__c6xabi_gtf");
334 eqdf_libfunc
= init_one_libfunc ("__c6xabi_eqd");
335 nedf_libfunc
= init_one_libfunc ("__c6xabi_neqd");
336 ledf_libfunc
= init_one_libfunc ("__c6xabi_led");
337 ltdf_libfunc
= init_one_libfunc ("__c6xabi_ltd");
338 gedf_libfunc
= init_one_libfunc ("__c6xabi_ged");
339 gtdf_libfunc
= init_one_libfunc ("__c6xabi_gtd");
341 set_optab_libfunc (eq_optab
, SFmode
, NULL
);
342 set_optab_libfunc (ne_optab
, SFmode
, "__c6xabi_neqf");
343 set_optab_libfunc (gt_optab
, SFmode
, NULL
);
344 set_optab_libfunc (ge_optab
, SFmode
, NULL
);
345 set_optab_libfunc (lt_optab
, SFmode
, NULL
);
346 set_optab_libfunc (le_optab
, SFmode
, NULL
);
347 set_optab_libfunc (unord_optab
, SFmode
, "__c6xabi_unordf");
348 set_optab_libfunc (eq_optab
, DFmode
, NULL
);
349 set_optab_libfunc (ne_optab
, DFmode
, "__c6xabi_neqd");
350 set_optab_libfunc (gt_optab
, DFmode
, NULL
);
351 set_optab_libfunc (ge_optab
, DFmode
, NULL
);
352 set_optab_libfunc (lt_optab
, DFmode
, NULL
);
353 set_optab_libfunc (le_optab
, DFmode
, NULL
);
354 set_optab_libfunc (unord_optab
, DFmode
, "__c6xabi_unordd");
356 /* Floating-point to integer conversions. */
357 set_conv_libfunc (sfix_optab
, SImode
, DFmode
, "__c6xabi_fixdi");
358 set_conv_libfunc (ufix_optab
, SImode
, DFmode
, "__c6xabi_fixdu");
359 set_conv_libfunc (sfix_optab
, DImode
, DFmode
, "__c6xabi_fixdlli");
360 set_conv_libfunc (ufix_optab
, DImode
, DFmode
, "__c6xabi_fixdull");
361 set_conv_libfunc (sfix_optab
, SImode
, SFmode
, "__c6xabi_fixfi");
362 set_conv_libfunc (ufix_optab
, SImode
, SFmode
, "__c6xabi_fixfu");
363 set_conv_libfunc (sfix_optab
, DImode
, SFmode
, "__c6xabi_fixflli");
364 set_conv_libfunc (ufix_optab
, DImode
, SFmode
, "__c6xabi_fixfull");
366 /* Conversions between floating types. */
367 set_conv_libfunc (trunc_optab
, SFmode
, DFmode
, "__c6xabi_cvtdf");
368 set_conv_libfunc (sext_optab
, DFmode
, SFmode
, "__c6xabi_cvtfd");
370 /* Integer to floating-point conversions. */
371 set_conv_libfunc (sfloat_optab
, DFmode
, SImode
, "__c6xabi_fltid");
372 set_conv_libfunc (ufloat_optab
, DFmode
, SImode
, "__c6xabi_fltud");
373 set_conv_libfunc (sfloat_optab
, DFmode
, DImode
, "__c6xabi_fltllid");
374 set_conv_libfunc (ufloat_optab
, DFmode
, DImode
, "__c6xabi_fltulld");
375 set_conv_libfunc (sfloat_optab
, SFmode
, SImode
, "__c6xabi_fltif");
376 set_conv_libfunc (ufloat_optab
, SFmode
, SImode
, "__c6xabi_fltuf");
377 set_conv_libfunc (sfloat_optab
, SFmode
, DImode
, "__c6xabi_fltllif");
378 set_conv_libfunc (ufloat_optab
, SFmode
, DImode
, "__c6xabi_fltullf");
381 set_optab_libfunc (smul_optab
, DImode
, "__c6xabi_mpyll");
382 set_optab_libfunc (ashl_optab
, DImode
, "__c6xabi_llshl");
383 set_optab_libfunc (lshr_optab
, DImode
, "__c6xabi_llshru");
384 set_optab_libfunc (ashr_optab
, DImode
, "__c6xabi_llshr");
386 set_optab_libfunc (sdiv_optab
, SImode
, "__c6xabi_divi");
387 set_optab_libfunc (udiv_optab
, SImode
, "__c6xabi_divu");
388 set_optab_libfunc (smod_optab
, SImode
, "__c6xabi_remi");
389 set_optab_libfunc (umod_optab
, SImode
, "__c6xabi_remu");
390 set_optab_libfunc (sdivmod_optab
, SImode
, "__c6xabi_divremi");
391 set_optab_libfunc (udivmod_optab
, SImode
, "__c6xabi_divremu");
392 set_optab_libfunc (sdiv_optab
, DImode
, "__c6xabi_divlli");
393 set_optab_libfunc (udiv_optab
, DImode
, "__c6xabi_divull");
394 set_optab_libfunc (smod_optab
, DImode
, "__c6xabi_remlli");
395 set_optab_libfunc (umod_optab
, DImode
, "__c6xabi_remull");
396 set_optab_libfunc (udivmod_optab
, DImode
, "__c6xabi_divremull");
399 strasgi_libfunc
= init_one_libfunc ("__c6xabi_strasgi");
400 strasgi64p_libfunc
= init_one_libfunc ("__c6xabi_strasgi_64plus");
403 /* Begin the assembly file. */
406 c6x_file_start (void)
408 /* Variable tracking should be run after all optimizations which change order
409 of insns. It also needs a valid CFG. This can't be done in
410 c6x_override_options, because flag_var_tracking is finalized after
412 c6x_flag_var_tracking
= flag_var_tracking
;
413 flag_var_tracking
= 0;
415 done_cfi_sections
= false;
416 default_file_start ();
418 /* Arrays are aligned to 8-byte boundaries. */
419 asm_fprintf (asm_out_file
,
420 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
421 asm_fprintf (asm_out_file
,
422 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
424 /* Stack alignment is 8 bytes. */
425 asm_fprintf (asm_out_file
,
426 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
427 asm_fprintf (asm_out_file
,
428 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
430 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
431 /* ??? Ideally we'd check flag_short_wchar somehow. */
432 asm_fprintf (asm_out_file
, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
435 /* We conform to version 1.0 of the ABI. */
436 asm_fprintf (asm_out_file
,
437 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
441 /* The LTO frontend only enables exceptions when it sees a function that
442 uses it. This changes the return value of dwarf2out_do_frame, so we
443 have to check before every function. */
446 c6x_output_file_unwind (FILE * f
)
448 if (done_cfi_sections
)
451 /* Output a .cfi_sections directive. */
452 if (dwarf2out_do_frame ())
454 if (flag_unwind_tables
|| flag_exceptions
)
456 if (write_symbols
== DWARF2_DEBUG
457 || write_symbols
== VMS_AND_DWARF2_DEBUG
)
458 asm_fprintf (f
, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
460 asm_fprintf (f
, "\t.cfi_sections .c6xabi.exidx\n");
463 asm_fprintf (f
, "\t.cfi_sections .debug_frame\n");
464 done_cfi_sections
= true;
468 /* Output unwind directives at the end of a function. */
471 c6x_output_fn_unwind (FILE * f
)
473 /* Return immediately if we are not generating unwinding tables. */
474 if (! (flag_unwind_tables
|| flag_exceptions
))
477 /* If this function will never be unwound, then mark it as such. */
478 if (!(flag_unwind_tables
|| crtl
->uses_eh_lsda
)
479 && (TREE_NOTHROW (current_function_decl
)
480 || crtl
->all_throwers_are_sibcalls
))
481 fputs("\t.cantunwind\n", f
);
483 fputs ("\t.endp\n", f
);
487 /* Stack and Calling. */
489 int argument_registers
[10] =
498 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
501 c6x_init_cumulative_args (CUMULATIVE_ARGS
*cum
, const_tree fntype
, rtx libname
,
502 int n_named_args ATTRIBUTE_UNUSED
)
506 if (!libname
&& fntype
)
508 /* We need to find out the number of named arguments. Unfortunately,
509 for incoming arguments, N_NAMED_ARGS is set to -1. */
510 if (stdarg_p (fntype
))
511 cum
->nregs
= type_num_arguments (fntype
) - 1;
517 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
520 c6x_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
521 const_tree type
, bool named ATTRIBUTE_UNUSED
)
523 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
524 if (cum
->count
>= cum
->nregs
)
528 HOST_WIDE_INT size
= int_size_in_bytes (type
);
529 if (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (type
))
533 rtx reg1
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
] + 1);
534 rtx reg2
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
]);
535 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
536 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
537 return gen_rtx_PARALLEL (mode
, vec
);
541 return gen_rtx_REG (mode
, argument_registers
[cum
->count
]);
545 c6x_function_arg_advance (cumulative_args_t cum_v
,
546 enum machine_mode mode ATTRIBUTE_UNUSED
,
547 const_tree type ATTRIBUTE_UNUSED
,
548 bool named ATTRIBUTE_UNUSED
)
550 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
555 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
556 upward rather than downward. */
559 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED
,
560 const_tree type
, bool first
)
564 if (!TARGET_BIG_ENDIAN
)
570 size
= int_size_in_bytes (type
);
574 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
577 c6x_function_arg_boundary (enum machine_mode mode
, const_tree type
)
579 unsigned int boundary
= type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
);
581 if (boundary
> BITS_PER_WORD
)
582 return 2 * BITS_PER_WORD
;
586 HOST_WIDE_INT size
= int_size_in_bytes (type
);
588 return 2 * BITS_PER_WORD
;
589 if (boundary
< BITS_PER_WORD
)
592 return BITS_PER_WORD
;
594 return 2 * BITS_PER_UNIT
;
600 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
602 c6x_function_arg_round_boundary (enum machine_mode mode
, const_tree type
)
604 return c6x_function_arg_boundary (mode
, type
);
607 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
608 where function FUNC returns or receives a value of data type TYPE. */
611 c6x_function_value (const_tree type
, const_tree func ATTRIBUTE_UNUSED
,
612 bool outgoing ATTRIBUTE_UNUSED
)
614 /* Functions return values in register A4. When returning aggregates, we may
615 have to adjust for endianness. */
616 if (TARGET_BIG_ENDIAN
&& type
&& AGGREGATE_TYPE_P (type
))
618 HOST_WIDE_INT size
= int_size_in_bytes (type
);
622 rtx reg1
= gen_rtx_REG (SImode
, REG_A4
+ 1);
623 rtx reg2
= gen_rtx_REG (SImode
, REG_A4
);
624 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
625 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
626 return gen_rtx_PARALLEL (TYPE_MODE (type
), vec
);
629 return gen_rtx_REG (TYPE_MODE (type
), REG_A4
);
632 /* Implement TARGET_LIBCALL_VALUE. */
635 c6x_libcall_value (enum machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
637 return gen_rtx_REG (mode
, REG_A4
);
640 /* TARGET_STRUCT_VALUE_RTX implementation. */
643 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED
, int incoming ATTRIBUTE_UNUSED
)
645 return gen_rtx_REG (Pmode
, REG_A3
);
648 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
651 c6x_function_value_regno_p (const unsigned int regno
)
653 return regno
== REG_A4
;
656 /* Types larger than 64 bit, and variable sized types, are passed by
657 reference. The callee must copy them; see c6x_callee_copies. */
660 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
661 enum machine_mode mode
, const_tree type
,
662 bool named ATTRIBUTE_UNUSED
)
666 size
= int_size_in_bytes (type
);
667 else if (mode
!= VOIDmode
)
668 size
= GET_MODE_SIZE (mode
);
669 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
672 /* Decide whether a type should be returned in memory (true)
673 or in a register (false). This is called by the macro
674 TARGET_RETURN_IN_MEMORY. */
677 c6x_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
679 int size
= int_size_in_bytes (type
);
680 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
683 /* Values which must be returned in the most-significant end of the return
687 c6x_return_in_msb (const_tree valtype
)
689 HOST_WIDE_INT size
= int_size_in_bytes (valtype
);
690 return TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
) && size
== 3;
693 /* Implement TARGET_CALLEE_COPIES. */
696 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
697 enum machine_mode mode ATTRIBUTE_UNUSED
,
698 const_tree type ATTRIBUTE_UNUSED
,
699 bool named ATTRIBUTE_UNUSED
)
704 /* Return the type to use as __builtin_va_list. */
706 c6x_build_builtin_va_list (void)
708 return build_pointer_type (char_type_node
);
712 c6x_asm_trampoline_template (FILE *f
)
714 fprintf (f
, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
715 fprintf (f
, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
716 fprintf (f
, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
717 fprintf (f
, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
718 fprintf (f
, "\t.long\t0x00000362\n"); /* b .s2 B0 */
719 fprintf (f
, "\t.long\t0x00008000\n"); /* nop 5 */
720 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
721 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
724 /* Emit RTL insns to initialize the variable parts of a trampoline at
725 TRAMP. FNADDR is an RTX for the address of the function's pure
726 code. CXT is an RTX for the static chain value for the function. */
729 c6x_initialize_trampoline (rtx tramp
, tree fndecl
, rtx cxt
)
731 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
732 rtx t1
= copy_to_reg (fnaddr
);
733 rtx t2
= copy_to_reg (cxt
);
734 rtx mask
= gen_reg_rtx (SImode
);
737 emit_block_move (tramp
, assemble_trampoline_template (),
738 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
740 emit_move_insn (mask
, GEN_INT (0xffff << 7));
742 for (i
= 0; i
< 4; i
++)
744 rtx mem
= adjust_address (tramp
, SImode
, i
* 4);
745 rtx t
= (i
& 1) ? t2
: t1
;
746 rtx v1
= gen_reg_rtx (SImode
);
747 rtx v2
= gen_reg_rtx (SImode
);
748 emit_move_insn (v1
, mem
);
750 emit_insn (gen_ashlsi3 (v2
, t
, GEN_INT (7)));
752 emit_insn (gen_lshrsi3 (v2
, t
, GEN_INT (9)));
753 emit_insn (gen_andsi3 (v2
, v2
, mask
));
754 emit_insn (gen_iorsi3 (v2
, v2
, v1
));
755 emit_move_insn (mem
, v2
);
757 #ifdef CLEAR_INSN_CACHE
758 tramp
= XEXP (tramp
, 0);
759 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__gnu_clear_cache"),
760 LCT_NORMAL
, VOIDmode
, 2, tramp
, Pmode
,
761 plus_constant (Pmode
, tramp
, TRAMPOLINE_SIZE
),
766 /* Determine whether c6x_output_mi_thunk can succeed. */
769 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED
,
770 HOST_WIDE_INT delta ATTRIBUTE_UNUSED
,
771 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED
,
772 const_tree function ATTRIBUTE_UNUSED
)
774 return !TARGET_LONG_CALLS
;
777 /* Output the assembler code for a thunk function. THUNK is the
778 declaration for the thunk function itself, FUNCTION is the decl for
779 the target function. DELTA is an immediate constant offset to be
780 added to THIS. If VCALL_OFFSET is nonzero, the word at
781 *(*this + vcall_offset) should be added to THIS. */
784 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
785 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
786 HOST_WIDE_INT vcall_offset
, tree function
)
789 /* The this parameter is passed as the first argument. */
790 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_A4
);
792 c6x_current_insn
= NULL
;
794 xops
[4] = XEXP (DECL_RTL (function
), 0);
797 output_asm_insn ("b .s2 \t%4", xops
);
799 output_asm_insn ("nop 5", xops
);
802 /* Adjust the this parameter by a fixed constant. */
805 xops
[0] = GEN_INT (delta
);
807 if (delta
>= -16 && delta
<= 15)
809 output_asm_insn ("add .s1 %0, %1, %1", xops
);
811 output_asm_insn ("nop 4", xops
);
813 else if (delta
>= 16 && delta
< 32)
815 output_asm_insn ("add .d1 %0, %1, %1", xops
);
817 output_asm_insn ("nop 4", xops
);
819 else if (delta
>= -32768 && delta
< 32768)
821 output_asm_insn ("mvk .s1 %0, A0", xops
);
822 output_asm_insn ("add .d1 %1, A0, %1", xops
);
824 output_asm_insn ("nop 3", xops
);
828 output_asm_insn ("mvkl .s1 %0, A0", xops
);
829 output_asm_insn ("mvkh .s1 %0, A0", xops
);
830 output_asm_insn ("add .d1 %1, A0, %1", xops
);
832 output_asm_insn ("nop 3", xops
);
836 /* Adjust the this parameter by a value stored in the vtable. */
839 rtx a0tmp
= gen_rtx_REG (Pmode
, REG_A0
);
840 rtx a3tmp
= gen_rtx_REG (Pmode
, REG_A3
);
844 xops
[3] = gen_rtx_MEM (Pmode
, a0tmp
);
845 output_asm_insn ("mv .s1 a4, %2", xops
);
846 output_asm_insn ("ldw .d1t1 %3, %2", xops
);
848 /* Adjust the this parameter. */
849 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (Pmode
, a0tmp
,
851 if (!memory_operand (xops
[0], Pmode
))
853 rtx tmp2
= gen_rtx_REG (Pmode
, REG_A1
);
854 xops
[0] = GEN_INT (vcall_offset
);
856 output_asm_insn ("mvkl .s1 %0, %1", xops
);
857 output_asm_insn ("mvkh .s1 %0, %1", xops
);
858 output_asm_insn ("nop 2", xops
);
859 output_asm_insn ("add .d1 %2, %1, %2", xops
);
860 xops
[0] = gen_rtx_MEM (Pmode
, a0tmp
);
863 output_asm_insn ("nop 4", xops
);
865 output_asm_insn ("ldw .d1t1 %0, %1", xops
);
866 output_asm_insn ("|| b .s2 \t%4", xops
);
867 output_asm_insn ("nop 4", xops
);
868 output_asm_insn ("add .d1 %2, %1, %2", xops
);
872 /* Return true if EXP goes in small data/bss. */
875 c6x_in_small_data_p (const_tree exp
)
877 /* We want to merge strings, so we never consider them small data. */
878 if (TREE_CODE (exp
) == STRING_CST
)
881 /* Functions are never small data. */
882 if (TREE_CODE (exp
) == FUNCTION_DECL
)
885 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_WEAK (exp
))
888 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_SECTION_NAME (exp
))
890 const char *section
= DECL_SECTION_NAME (exp
);
892 if (strcmp (section
, ".neardata") == 0
893 || strncmp (section
, ".neardata.", 10) == 0
894 || strncmp (section
, ".gnu.linkonce.s.", 16) == 0
895 || strcmp (section
, ".bss") == 0
896 || strncmp (section
, ".bss.", 5) == 0
897 || strncmp (section
, ".gnu.linkonce.sb.", 17) == 0
898 || strcmp (section
, ".rodata") == 0
899 || strncmp (section
, ".rodata.", 8) == 0
900 || strncmp (section
, ".gnu.linkonce.s2.", 17) == 0)
904 return PLACE_IN_SDATA_P (exp
);
909 /* Return a section for X. The only special thing we do here is to
910 honor small data. We don't have a tree type, so we can't use the
911 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
912 everything sized 8 bytes or smaller into small data. */
915 c6x_select_rtx_section (enum machine_mode mode
, rtx x
,
916 unsigned HOST_WIDE_INT align
)
918 if (c6x_sdata_mode
== C6X_SDATA_ALL
919 || (c6x_sdata_mode
!= C6X_SDATA_NONE
&& GET_MODE_SIZE (mode
) <= 8))
920 /* ??? Consider using mergeable sdata sections. */
921 return sdata_section
;
923 return default_elf_select_rtx_section (mode
, x
, align
);
927 c6x_elf_select_section (tree decl
, int reloc
,
928 unsigned HOST_WIDE_INT align
)
930 const char *sname
= NULL
;
931 unsigned int flags
= SECTION_WRITE
;
932 if (c6x_in_small_data_p (decl
))
934 switch (categorize_decl_for_section (decl
, reloc
))
945 flags
|= SECTION_BSS
;
952 switch (categorize_decl_for_section (decl
, reloc
))
957 case SECCAT_DATA_REL
:
958 sname
= ".fardata.rel";
960 case SECCAT_DATA_REL_LOCAL
:
961 sname
= ".fardata.rel.local";
963 case SECCAT_DATA_REL_RO
:
964 sname
= ".fardata.rel.ro";
966 case SECCAT_DATA_REL_RO_LOCAL
:
967 sname
= ".fardata.rel.ro.local";
971 flags
|= SECTION_BSS
;
987 /* We might get called with string constants, but get_named_section
988 doesn't like them as they are not DECLs. Also, we need to set
989 flags in that case. */
991 return get_section (sname
, flags
, NULL
);
992 return get_named_section (decl
, sname
, reloc
);
995 return default_elf_select_section (decl
, reloc
, align
);
998 /* Build up a unique section name, expressed as a
999 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
1000 RELOC indicates whether the initial value of EXP requires
1001 link-time relocations. */
1003 static void ATTRIBUTE_UNUSED
1004 c6x_elf_unique_section (tree decl
, int reloc
)
1006 const char *prefix
= NULL
;
1007 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
1008 bool one_only
= DECL_COMDAT_GROUP (decl
) && !HAVE_COMDAT_GROUP
;
1010 if (c6x_in_small_data_p (decl
))
1012 switch (categorize_decl_for_section (decl
, reloc
))
1015 prefix
= one_only
? ".s" : ".neardata";
1018 prefix
= one_only
? ".sb" : ".bss";
1020 case SECCAT_SRODATA
:
1021 prefix
= one_only
? ".s2" : ".rodata";
1023 case SECCAT_RODATA_MERGE_STR
:
1024 case SECCAT_RODATA_MERGE_STR_INIT
:
1025 case SECCAT_RODATA_MERGE_CONST
:
1028 case SECCAT_DATA_REL
:
1029 case SECCAT_DATA_REL_LOCAL
:
1030 case SECCAT_DATA_REL_RO
:
1031 case SECCAT_DATA_REL_RO_LOCAL
:
1034 /* Everything else we place into default sections and hope for the
1041 switch (categorize_decl_for_section (decl
, reloc
))
1044 case SECCAT_DATA_REL
:
1045 case SECCAT_DATA_REL_LOCAL
:
1046 case SECCAT_DATA_REL_RO
:
1047 case SECCAT_DATA_REL_RO_LOCAL
:
1048 prefix
= one_only
? ".fd" : ".fardata";
1051 prefix
= one_only
? ".fb" : ".far";
1054 case SECCAT_RODATA_MERGE_STR
:
1055 case SECCAT_RODATA_MERGE_STR_INIT
:
1056 case SECCAT_RODATA_MERGE_CONST
:
1057 prefix
= one_only
? ".fr" : ".const";
1059 case SECCAT_SRODATA
:
1070 const char *name
, *linkonce
;
1073 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
1074 name
= targetm
.strip_name_encoding (name
);
1076 /* If we're using one_only, then there needs to be a .gnu.linkonce
1077 prefix to the section name. */
1078 linkonce
= one_only
? ".gnu.linkonce" : "";
1080 string
= ACONCAT ((linkonce
, prefix
, ".", name
, NULL
));
1082 set_decl_section_name (decl
, string
);
1085 default_unique_section (decl
, reloc
);
1089 c6x_section_type_flags (tree decl
, const char *name
, int reloc
)
1091 unsigned int flags
= 0;
1093 if (strcmp (name
, ".far") == 0
1094 || strncmp (name
, ".far.", 5) == 0)
1095 flags
|= SECTION_BSS
;
1097 flags
|= default_section_type_flags (decl
, name
, reloc
);
1102 /* Checks whether the given CALL_EXPR would use a caller saved
1103 register. This is used to decide whether sibling call optimization
1104 could be performed on the respective function call. */
1107 c6x_call_saved_register_used (tree call_expr
)
1109 CUMULATIVE_ARGS cum_v
;
1110 cumulative_args_t cum
;
1111 HARD_REG_SET call_saved_regset
;
1113 enum machine_mode mode
;
1118 INIT_CUMULATIVE_ARGS (cum_v
, NULL
, NULL
, 0, 0);
1119 cum
= pack_cumulative_args (&cum_v
);
1121 COMPL_HARD_REG_SET (call_saved_regset
, call_used_reg_set
);
1122 for (i
= 0; i
< call_expr_nargs (call_expr
); i
++)
1124 parameter
= CALL_EXPR_ARG (call_expr
, i
);
1125 gcc_assert (parameter
);
1127 /* For an undeclared variable passed as parameter we will get
1128 an ERROR_MARK node here. */
1129 if (TREE_CODE (parameter
) == ERROR_MARK
)
1132 type
= TREE_TYPE (parameter
);
1135 mode
= TYPE_MODE (type
);
1138 if (pass_by_reference (&cum_v
, mode
, type
, true))
1141 type
= build_pointer_type (type
);
1144 parm_rtx
= c6x_function_arg (cum
, mode
, type
, 0);
1146 c6x_function_arg_advance (cum
, mode
, type
, 0);
1151 if (REG_P (parm_rtx
)
1152 && overlaps_hard_reg_set_p (call_saved_regset
, GET_MODE (parm_rtx
),
1155 if (GET_CODE (parm_rtx
) == PARALLEL
)
1157 int n
= XVECLEN (parm_rtx
, 0);
1160 rtx x
= XEXP (XVECEXP (parm_rtx
, 0, n
), 0);
1162 && overlaps_hard_reg_set_p (call_saved_regset
,
1163 GET_MODE (x
), REGNO (x
)))
1171 /* Decide whether we can make a sibling call to a function. DECL is the
1172 declaration of the function being targeted by the call and EXP is the
1173 CALL_EXPR representing the call. */
1176 c6x_function_ok_for_sibcall (tree decl
, tree exp
)
1178 /* Registers A10, A12, B10 and B12 are available as arguments
1179 register but unfortunately caller saved. This makes functions
1180 needing these registers for arguments not suitable for
1182 if (c6x_call_saved_register_used (exp
))
1190 /* When compiling for DSBT, the calling function must be local,
1191 so that when we reload B14 in the sibcall epilogue, it will
1192 not change its value. */
1193 struct cgraph_local_info
*this_func
;
1196 /* Not enough information. */
1199 this_func
= cgraph_node::local_info (current_function_decl
);
1200 return this_func
->local
;
1206 /* Return true if DECL is known to be linked into section SECTION. */
1209 c6x_function_in_section_p (tree decl
, section
*section
)
1211 /* We can only be certain about functions defined in the same
1212 compilation unit. */
1213 if (!TREE_STATIC (decl
))
1216 /* Make sure that SYMBOL always binds to the definition in this
1217 compilation unit. */
1218 if (!targetm
.binds_local_p (decl
))
1221 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1222 if (!DECL_SECTION_NAME (decl
))
1224 /* Make sure that we will not create a unique section for DECL. */
1225 if (flag_function_sections
|| DECL_COMDAT_GROUP (decl
))
1229 return function_section (decl
) == section
;
1232 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1235 c6x_long_call_p (rtx op
)
1239 if (!TARGET_LONG_CALLS
)
1242 decl
= SYMBOL_REF_DECL (op
);
1244 /* Try to determine whether the symbol is in the same section as the current
1245 function. Be conservative, and only cater for cases in which the
1246 whole of the current function is placed in the same section. */
1247 if (decl
!= NULL_TREE
1248 && !flag_reorder_blocks_and_partition
1249 && TREE_CODE (decl
) == FUNCTION_DECL
1250 && c6x_function_in_section_p (decl
, current_function_section ()))
1256 /* Emit the sequence for a call. */
1258 c6x_expand_call (rtx retval
, rtx address
, bool sibcall
)
1260 rtx callee
= XEXP (address
, 0);
1263 if (!c6x_call_operand (callee
, Pmode
))
1265 callee
= force_reg (Pmode
, callee
);
1266 address
= change_address (address
, Pmode
, callee
);
1268 call_insn
= gen_rtx_CALL (VOIDmode
, address
, const0_rtx
);
1271 call_insn
= emit_call_insn (call_insn
);
1272 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
),
1273 gen_rtx_REG (Pmode
, REG_B3
));
1277 if (retval
== NULL_RTX
)
1278 call_insn
= emit_call_insn (call_insn
);
1280 call_insn
= emit_call_insn (gen_rtx_SET (GET_MODE (retval
), retval
,
1284 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
), pic_offset_table_rtx
);
1287 /* Legitimize PIC addresses. If the address is already position-independent,
1288 we return ORIG. Newly generated position-independent addresses go into a
1289 reg. This is REG if nonzero, otherwise we allocate register(s) as
1290 necessary. PICREG is the register holding the pointer to the PIC offset
1294 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
1299 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
1301 int unspec
= UNSPEC_LOAD_GOT
;
1306 gcc_assert (can_create_pseudo_p ());
1307 reg
= gen_reg_rtx (Pmode
);
1311 if (can_create_pseudo_p ())
1312 tmp
= gen_reg_rtx (Pmode
);
1315 emit_insn (gen_movsi_gotoff_high (tmp
, addr
));
1316 emit_insn (gen_movsi_gotoff_lo_sum (tmp
, tmp
, addr
));
1317 emit_insn (gen_load_got_gotoff (reg
, picreg
, tmp
));
1321 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
1322 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
1324 emit_move_insn (reg
, new_rtx
);
1326 if (picreg
== pic_offset_table_rtx
)
1327 crtl
->uses_pic_offset_table
= 1;
1331 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
1335 if (GET_CODE (addr
) == CONST
)
1337 addr
= XEXP (addr
, 0);
1338 gcc_assert (GET_CODE (addr
) == PLUS
);
1341 if (XEXP (addr
, 0) == picreg
)
1346 gcc_assert (can_create_pseudo_p ());
1347 reg
= gen_reg_rtx (Pmode
);
1350 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
1351 addr
= legitimize_pic_address (XEXP (addr
, 1),
1352 base
== reg
? NULL_RTX
: reg
,
1355 if (GET_CODE (addr
) == CONST_INT
)
1357 gcc_assert (! reload_in_progress
&& ! reload_completed
);
1358 addr
= force_reg (Pmode
, addr
);
1361 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
1363 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
1364 addr
= XEXP (addr
, 1);
1367 return gen_rtx_PLUS (Pmode
, base
, addr
);
1373 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1374 Returns true if no further code must be generated, false if the caller
1375 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1378 expand_move (rtx
*operands
, enum machine_mode mode
)
1380 rtx dest
= operands
[0];
1381 rtx op
= operands
[1];
1383 if ((reload_in_progress
| reload_completed
) == 0
1384 && GET_CODE (dest
) == MEM
&& GET_CODE (op
) != REG
)
1385 operands
[1] = force_reg (mode
, op
);
1386 else if (mode
== SImode
&& symbolic_operand (op
, SImode
))
1390 if (sdata_symbolic_operand (op
, SImode
))
1392 emit_insn (gen_load_sdata_pic (dest
, pic_offset_table_rtx
, op
));
1393 crtl
->uses_pic_offset_table
= 1;
1398 rtx temp
= (reload_completed
|| reload_in_progress
1399 ? dest
: gen_reg_rtx (Pmode
));
1401 operands
[1] = legitimize_pic_address (op
, temp
,
1402 pic_offset_table_rtx
);
1405 else if (reload_completed
1406 && !sdata_symbolic_operand (op
, SImode
))
1408 emit_insn (gen_movsi_high (dest
, op
));
1409 emit_insn (gen_movsi_lo_sum (dest
, dest
, op
));
1416 /* This function is called when we're about to expand an integer compare
1417 operation which performs COMPARISON. It examines the second operand,
1418 and if it is an integer constant that cannot be used directly on the
1419 current machine in a comparison insn, it returns true. */
1421 c6x_force_op_for_comparison_p (enum rtx_code code
, rtx op
)
1423 if (!CONST_INT_P (op
) || satisfies_constraint_Iu4 (op
))
1426 if ((code
== EQ
|| code
== LT
|| code
== GT
)
1427 && !satisfies_constraint_Is5 (op
))
1429 if ((code
== GTU
|| code
== LTU
)
1430 && (!TARGET_INSNS_64
|| !satisfies_constraint_Iu5 (op
)))
1436 /* Emit comparison instruction if necessary, returning the expression
1437 that holds the compare result in the proper mode. Return the comparison
1438 that should be used in the jump insn. */
1441 c6x_expand_compare (rtx comparison
, enum machine_mode mode
)
1443 enum rtx_code code
= GET_CODE (comparison
);
1444 rtx op0
= XEXP (comparison
, 0);
1445 rtx op1
= XEXP (comparison
, 1);
1447 enum rtx_code jump_code
= code
;
1448 enum machine_mode op_mode
= GET_MODE (op0
);
1450 if (op_mode
== DImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1452 rtx t
= gen_reg_rtx (SImode
);
1453 emit_insn (gen_iorsi3 (t
, gen_lowpart (SImode
, op0
),
1454 gen_highpart (SImode
, op0
)));
1458 else if (op_mode
== DImode
)
1463 if (code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1465 code
= reverse_condition (code
);
1471 split_di (&op0
, 1, lo
, high
);
1472 split_di (&op1
, 1, lo
+ 1, high
+ 1);
1474 if (c6x_force_op_for_comparison_p (code
, high
[1])
1475 || c6x_force_op_for_comparison_p (EQ
, high
[1]))
1476 high
[1] = force_reg (SImode
, high
[1]);
1478 cmp1
= gen_reg_rtx (SImode
);
1479 cmp2
= gen_reg_rtx (SImode
);
1480 emit_insn (gen_rtx_SET (VOIDmode
, cmp1
,
1481 gen_rtx_fmt_ee (code
, SImode
, high
[0], high
[1])));
1484 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1485 lo
[1] = force_reg (SImode
, lo
[1]);
1486 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1487 gen_rtx_fmt_ee (code
, SImode
, lo
[0], lo
[1])));
1488 emit_insn (gen_andsi3 (cmp1
, cmp1
, cmp2
));
1492 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1493 gen_rtx_EQ (SImode
, high
[0], high
[1])));
1496 else if (code
== LT
)
1498 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1499 lo
[1] = force_reg (SImode
, lo
[1]);
1500 emit_insn (gen_cmpsi_and (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1502 lo
[0], lo
[1], cmp2
));
1503 emit_insn (gen_iorsi3 (cmp1
, cmp1
, cmp2
));
1507 else if (TARGET_FP
&& !flag_finite_math_only
1508 && (op_mode
== DFmode
|| op_mode
== SFmode
)
1509 && code
!= EQ
&& code
!= NE
&& code
!= LT
&& code
!= GT
1510 && code
!= UNLE
&& code
!= UNGE
)
1512 enum rtx_code code1
, code2
, code3
;
1513 rtx (*fn
) (rtx
, rtx
, rtx
, rtx
, rtx
);
1525 code1
= code
== LE
|| code
== UNGT
? LT
: GT
;
1550 cmp
= gen_reg_rtx (SImode
);
1551 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1552 gen_rtx_fmt_ee (code1
, SImode
, op0
, op1
)));
1553 fn
= op_mode
== DFmode
? gen_cmpdf_ior
: gen_cmpsf_ior
;
1554 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code2
, SImode
, op0
, op1
),
1556 if (code3
!= UNKNOWN
)
1557 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code3
, SImode
, op0
, op1
),
1560 else if (op_mode
== SImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1565 is_fp_libfunc
= !TARGET_FP
&& (op_mode
== DFmode
|| op_mode
== SFmode
);
1567 if ((code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1570 code
= reverse_condition (code
);
1573 else if (code
== UNGE
)
1578 else if (code
== UNLE
)
1593 libfunc
= op_mode
== DFmode
? eqdf_libfunc
: eqsf_libfunc
;
1596 libfunc
= op_mode
== DFmode
? nedf_libfunc
: nesf_libfunc
;
1599 libfunc
= op_mode
== DFmode
? gtdf_libfunc
: gtsf_libfunc
;
1602 libfunc
= op_mode
== DFmode
? gedf_libfunc
: gesf_libfunc
;
1605 libfunc
= op_mode
== DFmode
? ltdf_libfunc
: ltsf_libfunc
;
1608 libfunc
= op_mode
== DFmode
? ledf_libfunc
: lesf_libfunc
;
1615 cmp
= emit_library_call_value (libfunc
, 0, LCT_CONST
, SImode
, 2,
1616 op0
, op_mode
, op1
, op_mode
);
1617 insns
= get_insns ();
1620 emit_libcall_block (insns
, cmp
, cmp
,
1621 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
));
1625 cmp
= gen_reg_rtx (SImode
);
1626 if (c6x_force_op_for_comparison_p (code
, op1
))
1627 op1
= force_reg (SImode
, op1
);
1628 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1629 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
)));
1633 return gen_rtx_fmt_ee (jump_code
, mode
, cmp
, const0_rtx
);
1636 /* Return one word of double-word value OP. HIGH_P is true to select the
1637 high part, false to select the low part. When encountering auto-increment
1638 addressing, we make the assumption that the low part is going to be accessed
1642 c6x_subword (rtx op
, bool high_p
)
1645 enum machine_mode mode
;
1647 mode
= GET_MODE (op
);
1648 if (mode
== VOIDmode
)
1651 if (TARGET_BIG_ENDIAN
? !high_p
: high_p
)
1652 byte
= UNITS_PER_WORD
;
1658 rtx addr
= XEXP (op
, 0);
1659 if (GET_CODE (addr
) == PLUS
|| REG_P (addr
))
1660 return adjust_address (op
, word_mode
, byte
);
1661 /* FIXME: should really support autoincrement addressing for
1662 multi-word modes. */
1666 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
1669 /* Split one or more DImode RTL references into pairs of SImode
1670 references. The RTL can be REG, offsettable MEM, integer constant, or
1671 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1672 split and "num" is its length. lo_half and hi_half are output arrays
1673 that parallel "operands". */
1676 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1680 rtx op
= operands
[num
];
1682 lo_half
[num
] = c6x_subword (op
, false);
1683 hi_half
[num
] = c6x_subword (op
, true);
1687 /* Return true if VAL is a mask valid for a clr instruction. */
1689 c6x_valid_mask_p (HOST_WIDE_INT val
)
1692 for (i
= 0; i
< 32; i
++)
1693 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1696 if (val
& ((unsigned HOST_WIDE_INT
)1 << i
))
1699 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1704 /* Expand a block move for a movmemM pattern. */
1707 c6x_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
,
1708 rtx expected_align_exp ATTRIBUTE_UNUSED
,
1709 rtx expected_size_exp ATTRIBUTE_UNUSED
)
1711 unsigned HOST_WIDE_INT align
= 1;
1712 unsigned HOST_WIDE_INT src_mem_align
, dst_mem_align
, min_mem_align
;
1713 unsigned HOST_WIDE_INT count
= 0, offset
= 0;
1714 unsigned int biggest_move
= TARGET_STDW
? 8 : 4;
1716 if (CONST_INT_P (align_exp
))
1717 align
= INTVAL (align_exp
);
1719 src_mem_align
= MEM_ALIGN (src
) / BITS_PER_UNIT
;
1720 dst_mem_align
= MEM_ALIGN (dst
) / BITS_PER_UNIT
;
1721 min_mem_align
= MIN (src_mem_align
, dst_mem_align
);
1723 if (min_mem_align
> align
)
1724 align
= min_mem_align
/ BITS_PER_UNIT
;
1725 if (src_mem_align
< align
)
1726 src_mem_align
= align
;
1727 if (dst_mem_align
< align
)
1728 dst_mem_align
= align
;
1730 if (CONST_INT_P (count_exp
))
1731 count
= INTVAL (count_exp
);
1735 /* Make sure we don't need to care about overflow later on. */
1736 if (count
> ((unsigned HOST_WIDE_INT
) 1 << 30))
1739 if (count
>= 28 && (count
& 3) == 0 && align
>= 4)
1741 tree dst_expr
= MEM_EXPR (dst
);
1742 tree src_expr
= MEM_EXPR (src
);
1743 rtx fn
= TARGET_INSNS_64PLUS
? strasgi64p_libfunc
: strasgi_libfunc
;
1744 rtx srcreg
= force_reg (Pmode
, XEXP (src
, 0));
1745 rtx dstreg
= force_reg (Pmode
, XEXP (dst
, 0));
1748 mark_addressable (src_expr
);
1750 mark_addressable (dst_expr
);
1751 emit_library_call (fn
, LCT_NORMAL
, VOIDmode
, 3,
1752 dstreg
, Pmode
, srcreg
, Pmode
, count_exp
, SImode
);
1756 if (biggest_move
> align
&& !TARGET_INSNS_64
)
1757 biggest_move
= align
;
1759 if (count
/ biggest_move
> 7)
1764 rtx reg
, reg_lowpart
;
1765 enum machine_mode srcmode
, dstmode
;
1766 unsigned HOST_WIDE_INT src_size
, dst_size
, src_left
;
1770 while (biggest_move
> count
)
1773 src_size
= dst_size
= biggest_move
;
1774 if (src_size
> src_mem_align
&& src_size
== 2)
1776 if (dst_size
> dst_mem_align
&& dst_size
== 2)
1779 if (dst_size
> src_size
)
1780 dst_size
= src_size
;
1782 srcmode
= mode_for_size (src_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1783 dstmode
= mode_for_size (dst_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1785 reg_lowpart
= reg
= gen_reg_rtx (srcmode
);
1788 reg
= gen_reg_rtx (SImode
);
1789 reg_lowpart
= gen_lowpart (srcmode
, reg
);
1792 srcmem
= adjust_address (copy_rtx (src
), srcmode
, offset
);
1794 if (src_size
> src_mem_align
)
1796 enum insn_code icode
= (srcmode
== SImode
? CODE_FOR_movmisalignsi
1797 : CODE_FOR_movmisaligndi
);
1798 emit_insn (GEN_FCN (icode
) (reg_lowpart
, srcmem
));
1801 emit_move_insn (reg_lowpart
, srcmem
);
1803 src_left
= src_size
;
1804 shift
= TARGET_BIG_ENDIAN
? (src_size
- dst_size
) * BITS_PER_UNIT
: 0;
1805 while (src_left
> 0)
1807 rtx dstreg
= reg_lowpart
;
1809 if (src_size
> dst_size
)
1812 int shift_amount
= shift
& (BITS_PER_WORD
- 1);
1814 srcword
= operand_subword_force (srcword
, src_left
>= 4 ? 0 : 4,
1816 if (shift_amount
> 0)
1818 dstreg
= gen_reg_rtx (SImode
);
1819 emit_insn (gen_lshrsi3 (dstreg
, srcword
,
1820 GEN_INT (shift_amount
)));
1824 dstreg
= gen_lowpart (dstmode
, dstreg
);
1827 dstmem
= adjust_address (copy_rtx (dst
), dstmode
, offset
);
1828 if (dst_size
> dst_mem_align
)
1830 enum insn_code icode
= (dstmode
== SImode
? CODE_FOR_movmisalignsi
1831 : CODE_FOR_movmisaligndi
);
1832 emit_insn (GEN_FCN (icode
) (dstmem
, dstreg
));
1835 emit_move_insn (dstmem
, dstreg
);
1837 if (TARGET_BIG_ENDIAN
)
1838 shift
-= dst_size
* BITS_PER_UNIT
;
1840 shift
+= dst_size
* BITS_PER_UNIT
;
1842 src_left
-= dst_size
;
1849 /* Subroutine of print_address_operand, print a single address offset OFF for
1850 a memory access of mode MEM_MODE, choosing between normal form and scaled
1851 form depending on the type of the insn. Misaligned memory references must
1852 use the scaled form. */
1855 print_address_offset (FILE *file
, rtx off
, enum machine_mode mem_mode
)
1859 if (c6x_current_insn
!= NULL_RTX
)
1861 pat
= PATTERN (c6x_current_insn
);
1862 if (GET_CODE (pat
) == COND_EXEC
)
1863 pat
= COND_EXEC_CODE (pat
);
1864 if (GET_CODE (pat
) == PARALLEL
)
1865 pat
= XVECEXP (pat
, 0, 0);
1867 if (GET_CODE (pat
) == SET
1868 && GET_CODE (SET_SRC (pat
)) == UNSPEC
1869 && XINT (SET_SRC (pat
), 1) == UNSPEC_MISALIGNED_ACCESS
)
1871 gcc_assert (CONST_INT_P (off
)
1872 && (INTVAL (off
) & (GET_MODE_SIZE (mem_mode
) - 1)) == 0);
1873 fprintf (file
, "[" HOST_WIDE_INT_PRINT_DEC
"]",
1874 INTVAL (off
) / GET_MODE_SIZE (mem_mode
));
1879 output_address (off
);
1884 c6x_print_operand_punct_valid_p (unsigned char c
)
1886 return c
== '$' || c
== '.' || c
== '|';
1889 static void c6x_print_operand (FILE *, rtx
, int);
1891 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1894 c6x_print_address_operand (FILE *file
, rtx x
, enum machine_mode mem_mode
)
1897 switch (GET_CODE (x
))
1901 if (GET_CODE (x
) == POST_MODIFY
)
1902 output_address (XEXP (x
, 0));
1903 off
= XEXP (XEXP (x
, 1), 1);
1904 if (XEXP (x
, 0) == stack_pointer_rtx
)
1906 if (GET_CODE (x
) == PRE_MODIFY
)
1907 gcc_assert (INTVAL (off
) > 0);
1909 gcc_assert (INTVAL (off
) < 0);
1911 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1913 fprintf (file
, "--");
1914 off
= GEN_INT (-INTVAL (off
));
1917 fprintf (file
, "++");
1918 if (GET_CODE (x
) == PRE_MODIFY
)
1919 output_address (XEXP (x
, 0));
1920 print_address_offset (file
, off
, mem_mode
);
1925 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1927 fprintf (file
, "-");
1928 off
= GEN_INT (-INTVAL (off
));
1931 fprintf (file
, "+");
1932 output_address (XEXP (x
, 0));
1933 print_address_offset (file
, off
, mem_mode
);
1937 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1938 fprintf (file
, "--");
1939 output_address (XEXP (x
, 0));
1940 fprintf (file
, "[1]");
1943 fprintf (file
, "++");
1944 output_address (XEXP (x
, 0));
1945 fprintf (file
, "[1]");
1948 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1949 output_address (XEXP (x
, 0));
1950 fprintf (file
, "++[1]");
1953 output_address (XEXP (x
, 0));
1954 fprintf (file
, "--[1]");
1960 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
1961 fprintf (file
, "+B14(");
1962 output_addr_const (file
, x
);
1963 fprintf (file
, ")");
1967 switch (XINT (x
, 1))
1969 case UNSPEC_LOAD_GOT
:
1970 fputs ("$GOT(", file
);
1971 output_addr_const (file
, XVECEXP (x
, 0, 0));
1974 case UNSPEC_LOAD_SDATA
:
1975 output_addr_const (file
, XVECEXP (x
, 0, 0));
1983 gcc_assert (GET_CODE (x
) != MEM
);
1984 c6x_print_operand (file
, x
, 0);
1989 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1990 specifies the functional unit used by INSN. */
1993 c6x_get_unit_specifier (rtx_insn
*insn
)
1995 enum attr_units units
;
1997 if (insn_info
.exists ())
1999 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2000 return c6x_unit_names
[unit
][0];
2003 units
= get_attr_units (insn
);
2028 /* Prints the unit specifier field. */
2030 c6x_print_unit_specifier_field (FILE *file
, rtx_insn
*insn
)
2032 enum attr_units units
= get_attr_units (insn
);
2033 enum attr_cross cross
= get_attr_cross (insn
);
2034 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
2038 if (units
== UNITS_D_ADDR
)
2040 enum attr_addr_regfile arf
= get_attr_addr_regfile (insn
);
2042 gcc_assert (arf
!= ADDR_REGFILE_UNKNOWN
);
2043 half
= arf
== ADDR_REGFILE_A
? 1 : 2;
2044 t_half
= rf
== DEST_REGFILE_A
? 1 : 2;
2045 fprintf (file
, ".d%dt%d", half
, t_half
);
2049 if (insn_info
.exists ())
2051 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
2053 fputs (c6x_unit_names
[unit
], file
);
2054 if (cross
== CROSS_Y
)
2059 gcc_assert (rf
!= DEST_REGFILE_UNKNOWN
);
2060 unitspec
= c6x_get_unit_specifier (insn
);
2061 half
= rf
== DEST_REGFILE_A
? 1 : 2;
2062 fprintf (file
, ".%c%d%s", unitspec
, half
, cross
== CROSS_Y
? "x" : "");
2065 /* Output assembly language output for the address ADDR to FILE. */
2067 c6x_print_operand_address (FILE *file
, rtx addr
)
2069 c6x_print_address_operand (file
, addr
, VOIDmode
);
2072 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2075 $ -- print the unit specifier field for the instruction.
2076 . -- print the predicate for the instruction or an emptry string for an
2078 | -- print "||" if the insn should be issued in parallel with the previous
2081 C -- print an opcode suffix for a reversed condition
2082 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2084 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2086 J -- print a predicate
2087 j -- like J, but use reverse predicate
2088 k -- treat a CONST_INT as a register number and print it as a register
2089 k -- like k, but print out a doubleword register
2090 n -- print an integer operand, negated
2091 p -- print the low part of a DImode register
2092 P -- print the high part of a DImode register
2093 r -- print the absolute value of an integer operand, shifted right by 1
2094 R -- print the absolute value of an integer operand, shifted right by 2
2095 f -- the first clear bit in an integer operand assumed to be a mask for
2097 F -- the last clear bit in such a mask
2098 s -- the first set bit in an integer operand assumed to be a mask for
2100 S -- the last set bit in such a mask
2101 U -- print either 1 or 2, depending on the side of the machine used by
2105 c6x_print_operand (FILE *file
, rtx x
, int code
)
2110 enum machine_mode mode
;
2114 if (GET_MODE (c6x_current_insn
) != TImode
)
2120 c6x_print_unit_specifier_field (file
, c6x_current_insn
);
2126 x
= current_insn_predicate
;
2129 unsigned int regno
= REGNO (XEXP (x
, 0));
2131 if (GET_CODE (x
) == EQ
)
2133 fputs (reg_names
[regno
], file
);
2139 mode
= GET_MODE (x
);
2146 enum rtx_code c
= GET_CODE (x
);
2148 c
= swap_condition (c
);
2149 fputs (GET_RTX_NAME (c
), file
);
2156 unsigned int regno
= REGNO (XEXP (x
, 0));
2157 if ((GET_CODE (x
) == EQ
) == (code
== 'J'))
2159 fputs (reg_names
[regno
], file
);
2164 gcc_assert (GET_CODE (x
) == CONST_INT
);
2166 fprintf (file
, "%s", reg_names
[v
]);
2169 gcc_assert (GET_CODE (x
) == CONST_INT
);
2171 gcc_assert ((v
& 1) == 0);
2172 fprintf (file
, "%s:%s", reg_names
[v
+ 1], reg_names
[v
]);
2179 gcc_assert (GET_CODE (x
) == CONST_INT
);
2181 for (i
= 0; i
< 32; i
++)
2183 HOST_WIDE_INT tst
= v
& 1;
2184 if (((code
== 'f' || code
== 'F') && !tst
)
2185 || ((code
== 's' || code
== 'S') && tst
))
2189 if (code
== 'f' || code
== 's')
2191 fprintf (file
, "%d", i
);
2196 HOST_WIDE_INT tst
= v
& 1;
2197 if ((code
== 'F' && tst
) || (code
== 'S' && !tst
))
2201 fprintf (file
, "%d", i
- 1);
2205 gcc_assert (GET_CODE (x
) == CONST_INT
);
2206 output_addr_const (file
, GEN_INT (-INTVAL (x
)));
2210 gcc_assert (GET_CODE (x
) == CONST_INT
);
2214 output_addr_const (file
, GEN_INT (v
>> 1));
2218 gcc_assert (GET_CODE (x
) == CONST_INT
);
2222 output_addr_const (file
, GEN_INT (v
>> 2));
2226 gcc_assert (GET_CODE (x
) == CONST_INT
);
2228 fputs (v
== 2 ? "h" : v
== 4 ? "w" : "d", file
);
2233 gcc_assert (GET_CODE (x
) == REG
);
2237 fputs (reg_names
[v
], file
);
2242 if (GET_CODE (x
) == CONST
)
2245 gcc_assert (GET_CODE (x
) == PLUS
);
2246 gcc_assert (GET_CODE (XEXP (x
, 1)) == CONST_INT
);
2247 v
= INTVAL (XEXP (x
, 1));
2251 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
2253 t
= SYMBOL_REF_DECL (x
);
2255 v
|= DECL_ALIGN_UNIT (t
);
2257 v
|= TYPE_ALIGN_UNIT (TREE_TYPE (t
));
2270 if (GET_CODE (x
) == PLUS
2271 || GET_RTX_CLASS (GET_CODE (x
)) == RTX_AUTOINC
)
2273 if (GET_CODE (x
) == CONST
|| GET_CODE (x
) == SYMBOL_REF
)
2275 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
2280 gcc_assert (REG_P (x
));
2281 if (A_REGNO_P (REGNO (x
)))
2283 if (B_REGNO_P (REGNO (x
)))
2288 switch (GET_CODE (x
))
2291 if (GET_MODE_SIZE (mode
) == 8)
2292 fprintf (file
, "%s:%s", reg_names
[REGNO (x
) + 1],
2293 reg_names
[REGNO (x
)]);
2295 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
2300 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
2301 c6x_print_address_operand (file
, XEXP (x
, 0), GET_MODE (x
));
2306 output_addr_const (file
, x
);
2311 output_addr_const (file
, x
);
2315 output_operand_lossage ("invalid const_double operand");
2319 output_addr_const (file
, x
);
2324 /* Return TRUE if OP is a valid memory address with a base register of
2325 class C. If SMALL_OFFSET is true, we disallow memory references which would
2326 require a long offset with B14/B15. */
2329 c6x_mem_operand (rtx op
, enum reg_class c
, bool small_offset
)
2331 enum machine_mode mode
= GET_MODE (op
);
2332 rtx base
= XEXP (op
, 0);
2333 switch (GET_CODE (base
))
2339 && (XEXP (base
, 0) == stack_pointer_rtx
2340 || XEXP (base
, 0) == pic_offset_table_rtx
))
2342 if (!c6x_legitimate_address_p_1 (mode
, base
, true, true))
2353 base
= XEXP (base
, 0);
2359 gcc_assert (sdata_symbolic_operand (base
, Pmode
));
2360 return !small_offset
&& c
== B_REGS
;
2365 return TEST_HARD_REG_BIT (reg_class_contents
[ (int) (c
)], REGNO (base
));
2368 /* Returns true if X is a valid address for use in a memory reference
2369 of mode MODE. If STRICT is true, we do not allow pseudo registers
2370 in the address. NO_LARGE_OFFSET is true if we are examining an
2371 address for use in a load or store misaligned instruction, or
2372 recursively examining an operand inside a PRE/POST_MODIFY. */
2375 c6x_legitimate_address_p_1 (enum machine_mode mode
, rtx x
, bool strict
,
2376 bool no_large_offset
)
2380 enum rtx_code code
= GET_CODE (x
);
2386 /* We can't split these into word-sized pieces yet. */
2387 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2389 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
2391 if (!c6x_legitimate_address_p_1 (mode
, XEXP (x
, 1), strict
, true))
2393 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
2401 /* We can't split these into word-sized pieces yet. */
2402 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2411 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x
));
2413 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x
));
2416 if (!REG_P (XEXP (x
, 0))
2417 || !c6x_legitimate_address_p_1 (mode
, XEXP (x
, 0), strict
, false))
2419 /* We cannot ensure currently that both registers end up in the
2420 same register file. */
2421 if (REG_P (XEXP (x
, 1)))
2424 if (mode
== BLKmode
)
2426 else if (mode
== VOIDmode
)
2427 /* ??? This can happen during ivopts. */
2430 size
= GET_MODE_SIZE (mode
);
2433 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2434 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_SDATA
2435 && XEXP (x
, 0) == pic_offset_table_rtx
2436 && sdata_symbolic_operand (XVECEXP (XEXP (x
, 1), 0, 0), SImode
))
2437 return !no_large_offset
&& size
<= 4;
2440 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2441 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_GOT
2442 && XEXP (x
, 0) == pic_offset_table_rtx
2443 && (GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == SYMBOL_REF
2444 || GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == LABEL_REF
))
2445 return !no_large_offset
;
2446 if (GET_CODE (XEXP (x
, 1)) != CONST_INT
)
2449 off
= INTVAL (XEXP (x
, 1));
2451 /* If the machine does not have doubleword load/stores, we'll use
2452 word size accesses. */
2454 if (size
== 2 * UNITS_PER_WORD
&& !TARGET_STDW
)
2455 size
= UNITS_PER_WORD
;
2457 if (((HOST_WIDE_INT
)size1
- 1) & off
)
2460 if (off
> -32 && off
< (size1
== size
? 32 : 28))
2462 if (no_large_offset
|| code
!= PLUS
|| XEXP (x
, 0) != stack_pointer_rtx
2463 || size1
> UNITS_PER_WORD
)
2465 return off
>= 0 && off
< 32768;
2470 return (!no_large_offset
2471 /* With -fpic, we must wrap it in an unspec to show the B14
2474 && GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
2475 && sdata_symbolic_operand (x
, Pmode
));
2483 c6x_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
2485 return c6x_legitimate_address_p_1 (mode
, x
, strict
, false);
2489 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
,
2490 rtx x ATTRIBUTE_UNUSED
)
2495 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2497 c6x_preferred_rename_class (reg_class_t cl
)
2500 return NONPREDICATE_A_REGS
;
2502 return NONPREDICATE_B_REGS
;
2503 if (cl
== ALL_REGS
|| cl
== GENERAL_REGS
)
2504 return NONPREDICATE_REGS
;
2508 /* Implements FINAL_PRESCAN_INSN. */
2510 c6x_final_prescan_insn (rtx_insn
*insn
, rtx
*opvec ATTRIBUTE_UNUSED
,
2511 int noperands ATTRIBUTE_UNUSED
)
2513 c6x_current_insn
= insn
;
2516 /* A structure to describe the stack layout of a function. The layout is
2519 [saved frame pointer (or possibly padding0)]
2520 --> incoming stack pointer, new hard frame pointer
2521 [saved call-used regs]
2523 --> soft frame pointer
2525 [outgoing arguments]
2528 The structure members are laid out in this order. */
2533 /* Number of registers to save. */
2536 HOST_WIDE_INT frame
;
2537 int outgoing_arguments_size
;
2540 HOST_WIDE_INT to_allocate
;
2541 /* The offsets relative to the incoming stack pointer (which
2542 becomes HARD_FRAME_POINTER). */
2543 HOST_WIDE_INT frame_pointer_offset
;
2544 HOST_WIDE_INT b3_offset
;
2546 /* True if we should call push_rts/pop_rts to save and restore
2551 /* Return true if we need to save and modify the PIC register in the
2555 must_reload_pic_reg_p (void)
2557 struct cgraph_local_info
*i
= NULL
;
2562 i
= cgraph_node::local_info (current_function_decl
);
2564 if ((crtl
->uses_pic_offset_table
|| !crtl
->is_leaf
) && !i
->local
)
2569 /* Return 1 if we need to save REGNO. */
2571 c6x_save_reg (unsigned int regno
)
2573 return ((df_regs_ever_live_p (regno
)
2574 && !call_used_regs
[regno
]
2575 && !fixed_regs
[regno
])
2576 || (regno
== RETURN_ADDR_REGNO
2577 && (df_regs_ever_live_p (regno
)
2579 || (regno
== PIC_OFFSET_TABLE_REGNUM
&& must_reload_pic_reg_p ()));
2582 /* Examine the number of regs NREGS we've determined we must save.
2583 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2584 prologue and epilogue. */
2587 use_push_rts_p (int nregs
)
2589 if (TARGET_INSNS_64PLUS
&& optimize_function_for_size_p (cfun
)
2590 && !cfun
->machine
->contains_sibcall
2591 && !cfun
->returns_struct
2592 && !TARGET_LONG_CALLS
2593 && nregs
>= 6 && !frame_pointer_needed
)
2598 /* Return number of saved general prupose registers. */
2601 c6x_nsaved_regs (void)
2606 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
2607 if (c6x_save_reg (regno
))
2612 /* The safe debug order mandated by the ABI. */
2613 static unsigned reg_save_order
[] =
2615 REG_A10
, REG_A11
, REG_A12
, REG_A13
,
2617 REG_B10
, REG_B11
, REG_B12
, REG_B13
,
2621 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2623 /* Compute the layout of the stack frame and store it in FRAME. */
2626 c6x_compute_frame_layout (struct c6x_frame
*frame
)
2628 HOST_WIDE_INT size
= get_frame_size ();
2629 HOST_WIDE_INT offset
;
2632 /* We use the four bytes which are technically inside the caller's frame,
2633 usually to save the frame pointer. */
2635 frame
->padding0
= 0;
2636 nregs
= c6x_nsaved_regs ();
2637 frame
->push_rts
= false;
2638 frame
->b3_offset
= 0;
2639 if (use_push_rts_p (nregs
))
2641 frame
->push_rts
= true;
2642 frame
->b3_offset
= (TARGET_BIG_ENDIAN
? -12 : -13) * 4;
2645 else if (c6x_save_reg (REG_B3
))
2648 for (idx
= N_SAVE_ORDER
- 1; reg_save_order
[idx
] != REG_B3
; idx
--)
2650 if (c6x_save_reg (reg_save_order
[idx
]))
2651 frame
->b3_offset
-= 4;
2654 frame
->nregs
= nregs
;
2656 if (size
== 0 && nregs
== 0)
2658 frame
->padding0
= 4;
2659 frame
->padding1
= frame
->padding2
= 0;
2660 frame
->frame_pointer_offset
= frame
->to_allocate
= 0;
2661 frame
->outgoing_arguments_size
= 0;
2665 if (!frame
->push_rts
)
2666 offset
+= frame
->nregs
* 4;
2668 if (offset
== 0 && size
== 0 && crtl
->outgoing_args_size
== 0
2670 /* Don't use the bottom of the caller's frame if we have no
2671 allocation of our own and call other functions. */
2672 frame
->padding0
= frame
->padding1
= 4;
2673 else if (offset
& 4)
2674 frame
->padding1
= 4;
2676 frame
->padding1
= 0;
2678 offset
+= frame
->padding0
+ frame
->padding1
;
2679 frame
->frame_pointer_offset
= offset
;
2682 frame
->outgoing_arguments_size
= crtl
->outgoing_args_size
;
2683 offset
+= frame
->outgoing_arguments_size
;
2685 if ((offset
& 4) == 0)
2686 frame
->padding2
= 8;
2688 frame
->padding2
= 4;
2689 frame
->to_allocate
= offset
+ frame
->padding2
;
2692 /* Return the offset between two registers, one to be eliminated, and the other
2693 its replacement, at the start of a routine. */
2696 c6x_initial_elimination_offset (int from
, int to
)
2698 struct c6x_frame frame
;
2699 c6x_compute_frame_layout (&frame
);
2701 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
2703 else if (from
== FRAME_POINTER_REGNUM
2704 && to
== HARD_FRAME_POINTER_REGNUM
)
2705 return -frame
.frame_pointer_offset
;
2708 gcc_assert (to
== STACK_POINTER_REGNUM
);
2710 if (from
== ARG_POINTER_REGNUM
)
2711 return frame
.to_allocate
+ (frame
.push_rts
? 56 : 0);
2713 gcc_assert (from
== FRAME_POINTER_REGNUM
);
2714 return frame
.to_allocate
- frame
.frame_pointer_offset
;
2718 /* Given FROM and TO register numbers, say whether this elimination is
2719 allowed. Frame pointer elimination is automatically handled. */
2722 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
2724 if (to
== STACK_POINTER_REGNUM
)
2725 return !frame_pointer_needed
;
2729 /* Emit insns to increment the stack pointer by OFFSET. If
2730 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2731 Does nothing if the offset is zero. */
2734 emit_add_sp_const (HOST_WIDE_INT offset
, bool frame_related_p
)
2736 rtx to_add
= GEN_INT (offset
);
2737 rtx orig_to_add
= to_add
;
2743 if (offset
< -32768 || offset
> 32767)
2745 rtx reg
= gen_rtx_REG (SImode
, REG_A0
);
2746 rtx low
= GEN_INT (trunc_int_for_mode (offset
, HImode
));
2748 insn
= emit_insn (gen_movsi_high (reg
, low
));
2749 if (frame_related_p
)
2750 RTX_FRAME_RELATED_P (insn
) = 1;
2751 insn
= emit_insn (gen_movsi_lo_sum (reg
, reg
, to_add
));
2752 if (frame_related_p
)
2753 RTX_FRAME_RELATED_P (insn
) = 1;
2756 insn
= emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2758 if (frame_related_p
)
2761 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
2762 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
2763 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2766 RTX_FRAME_RELATED_P (insn
) = 1;
2770 /* Prologue and epilogue. */
2772 c6x_expand_prologue (void)
2774 struct c6x_frame frame
;
2778 HOST_WIDE_INT initial_offset
, off
, added_already
;
2780 c6x_compute_frame_layout (&frame
);
2782 if (flag_stack_usage_info
)
2783 current_function_static_stack_size
= frame
.to_allocate
;
2785 initial_offset
= -frame
.to_allocate
;
2788 emit_insn (gen_push_rts ());
2789 nsaved
= frame
.nregs
;
2792 /* If the offsets would be too large for the memory references we will
2793 create to save registers, do the stack allocation in two parts.
2794 Ensure by subtracting 8 that we don't store to the word pointed to
2795 by the stack pointer. */
2796 if (initial_offset
< -32768)
2797 initial_offset
= -frame
.frame_pointer_offset
- 8;
2799 if (frame
.to_allocate
> 0)
2800 gcc_assert (initial_offset
!= 0);
2802 off
= -initial_offset
+ 4 - frame
.padding0
;
2804 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2807 if (frame_pointer_needed
)
2809 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2810 /* We go through some contortions here to both follow the ABI's
2811 recommendation that FP == incoming SP, and to avoid writing or
2812 reading the word pointed to by the stack pointer. */
2813 rtx addr
= gen_rtx_POST_MODIFY (Pmode
, stack_pointer_rtx
,
2814 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2816 insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), fp_reg
);
2817 RTX_FRAME_RELATED_P (insn
) = 1;
2819 insn
= emit_insn (gen_addsi3 (hard_frame_pointer_rtx
, stack_pointer_rtx
,
2821 RTX_FRAME_RELATED_P (insn
) = 1;
2826 emit_add_sp_const (initial_offset
- added_already
, true);
2828 if (nsaved
< frame
.nregs
)
2832 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2834 int idx
= N_SAVE_ORDER
- i
- 1;
2835 unsigned regno
= reg_save_order
[idx
];
2837 enum machine_mode save_mode
= SImode
;
2839 if (regno
== REG_A15
&& frame_pointer_needed
)
2840 /* Already saved. */
2842 if (!c6x_save_reg (regno
))
2845 if (TARGET_STDW
&& (off
& 4) == 0 && off
<= 256
2847 && i
+ 1 < N_SAVE_ORDER
2848 && reg_save_order
[idx
- 1] == regno
- 1
2849 && c6x_save_reg (regno
- 1))
2855 reg
= gen_rtx_REG (save_mode
, regno
);
2856 off
-= GET_MODE_SIZE (save_mode
);
2858 insn
= emit_move_insn (adjust_address (mem
, save_mode
, off
),
2860 RTX_FRAME_RELATED_P (insn
) = 1;
2862 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2865 gcc_assert (nsaved
== frame
.nregs
);
2866 emit_add_sp_const (-frame
.to_allocate
- initial_offset
, true);
2867 if (must_reload_pic_reg_p ())
2869 if (dsbt_decl
== NULL
)
2873 t
= build_index_type (integer_one_node
);
2874 t
= build_array_type (integer_type_node
, t
);
2875 t
= build_decl (BUILTINS_LOCATION
, VAR_DECL
,
2876 get_identifier ("__c6xabi_DSBT_BASE"), t
);
2877 DECL_ARTIFICIAL (t
) = 1;
2878 DECL_IGNORED_P (t
) = 1;
2879 DECL_EXTERNAL (t
) = 1;
2880 TREE_STATIC (t
) = 1;
2881 TREE_PUBLIC (t
) = 1;
2886 emit_insn (gen_setup_dsbt (pic_offset_table_rtx
,
2887 XEXP (DECL_RTL (dsbt_decl
), 0)));
2892 c6x_expand_epilogue (bool sibcall
)
2895 struct c6x_frame frame
;
2900 c6x_compute_frame_layout (&frame
);
2902 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2904 /* Insert a dummy set/use of the stack pointer. This creates a
2905 scheduler barrier between the prologue saves and epilogue restores. */
2906 emit_insn (gen_epilogue_barrier (stack_pointer_rtx
, stack_pointer_rtx
));
2908 /* If the offsets would be too large for the memory references we will
2909 create to restore registers, do a preliminary stack adjustment here. */
2910 off
= frame
.to_allocate
- frame
.frame_pointer_offset
+ frame
.padding1
;
2913 nsaved
= frame
.nregs
;
2917 if (frame
.to_allocate
> 32768)
2919 /* Don't add the entire offset so that we leave an unused word
2920 above the stack pointer. */
2921 emit_add_sp_const ((off
- 16) & ~7, false);
2925 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2927 unsigned regno
= reg_save_order
[i
];
2929 enum machine_mode save_mode
= SImode
;
2931 if (!c6x_save_reg (regno
))
2933 if (regno
== REG_A15
&& frame_pointer_needed
)
2936 if (TARGET_STDW
&& (off
& 4) == 0 && off
< 256
2938 && i
+ 1 < N_SAVE_ORDER
2939 && reg_save_order
[i
+ 1] == regno
+ 1
2940 && c6x_save_reg (regno
+ 1))
2945 reg
= gen_rtx_REG (save_mode
, regno
);
2947 emit_move_insn (reg
, adjust_address (mem
, save_mode
, off
));
2949 off
+= GET_MODE_SIZE (save_mode
);
2950 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2953 if (!frame_pointer_needed
)
2954 emit_add_sp_const (off
+ frame
.padding0
- 4, false);
2957 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2958 rtx addr
= gen_rtx_PRE_MODIFY (Pmode
, stack_pointer_rtx
,
2959 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2961 emit_insn (gen_addsi3 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
2963 emit_move_insn (fp_reg
, gen_frame_mem (Pmode
, addr
));
2966 gcc_assert (nsaved
== frame
.nregs
);
2970 emit_jump_insn (gen_pop_rts ());
2972 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode
,
2973 RETURN_ADDR_REGNO
)));
2977 /* Return the value of the return address for the frame COUNT steps up
2978 from the current frame, after the prologue.
2979 We punt for everything but the current frame by returning const0_rtx. */
2982 c6x_return_addr_rtx (int count
)
2987 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNO
);
2990 /* Return true iff TYPE is one of the shadow types. */
2992 shadow_type_p (enum attr_type type
)
2994 return (type
== TYPE_SHADOW
|| type
== TYPE_LOAD_SHADOW
2995 || type
== TYPE_MULT_SHADOW
);
2998 /* Return true iff INSN is a shadow pattern. */
3000 shadow_p (rtx_insn
*insn
)
3002 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3004 return shadow_type_p (get_attr_type (insn
));
3007 /* Return true iff INSN is a shadow or blockage pattern. */
3009 shadow_or_blockage_p (rtx_insn
*insn
)
3011 enum attr_type type
;
3012 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3014 type
= get_attr_type (insn
);
3015 return shadow_type_p (type
) || type
== TYPE_BLOCKAGE
;
3018 /* Translate UNITS into a bitmask of units we can reserve for this
3021 get_reservation_flags (enum attr_units units
)
3027 return RESERVATION_FLAG_D
;
3029 return RESERVATION_FLAG_L
;
3031 return RESERVATION_FLAG_S
;
3033 return RESERVATION_FLAG_M
;
3035 return RESERVATION_FLAG_LS
;
3037 return RESERVATION_FLAG_DL
;
3039 return RESERVATION_FLAG_DS
;
3041 return RESERVATION_FLAG_DLS
;
3047 /* Compute the side of the machine used by INSN, which reserves UNITS.
3048 This must match the reservations in the scheduling description. */
3050 get_insn_side (rtx_insn
*insn
, enum attr_units units
)
3052 if (units
== UNITS_D_ADDR
)
3053 return (get_attr_addr_regfile (insn
) == ADDR_REGFILE_A
? 0 : 1);
3056 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
3057 if (rf
== DEST_REGFILE_ANY
)
3058 return get_attr_type (insn
) == TYPE_BRANCH
? 0 : 1;
3060 return rf
== DEST_REGFILE_A
? 0 : 1;
3064 /* After scheduling, walk the insns between HEAD and END and assign unit
3067 assign_reservations (rtx_insn
*head
, rtx_insn
*end
)
3070 for (insn
= head
; insn
!= NEXT_INSN (end
); insn
= NEXT_INSN (insn
))
3072 unsigned int sched_mask
, reserved
;
3073 rtx_insn
*within
, *last
;
3076 int rsrv_count
[2][4];
3079 if (GET_MODE (insn
) != TImode
)
3084 /* Find the last insn in the packet. It has a state recorded for it,
3085 which we can use to determine the units we should be using. */
3087 (within
!= NEXT_INSN (end
)
3088 && (within
== insn
|| GET_MODE (within
) != TImode
));
3089 within
= NEXT_INSN (within
))
3092 if (!NONDEBUG_INSN_P (within
))
3094 icode
= recog_memoized (within
);
3097 if (shadow_p (within
))
3099 if (INSN_INFO_ENTRY (INSN_UID (within
)).reservation
!= 0)
3100 reserved
|= 1 << INSN_INFO_ENTRY (INSN_UID (within
)).reservation
;
3103 if (last
== NULL_RTX
)
3106 sched_mask
= INSN_INFO_ENTRY (INSN_UID (last
)).unit_mask
;
3107 sched_mask
&= ~reserved
;
3109 memset (rsrv_count
, 0, sizeof rsrv_count
);
3110 rsrv
[0] = rsrv
[1] = ~0;
3111 for (i
= 0; i
< 8; i
++)
3115 unsigned unit_bit
= 1 << (unit
+ side
* UNIT_QID_SIDE_OFFSET
);
3116 /* Clear the bits which we expect to reserve in the following loop,
3117 leaving the ones set which aren't present in the scheduler's
3118 state and shouldn't be reserved. */
3119 if (sched_mask
& unit_bit
)
3120 rsrv
[i
/ 4] &= ~(1 << unit
);
3123 /* Walk through the insns that occur in the same cycle. We use multiple
3124 passes to assign units, assigning for insns with the most specific
3125 requirements first. */
3126 for (pass
= 0; pass
< 4; pass
++)
3128 (within
!= NEXT_INSN (end
)
3129 && (within
== insn
|| GET_MODE (within
) != TImode
));
3130 within
= NEXT_INSN (within
))
3132 int uid
= INSN_UID (within
);
3133 int this_rsrv
, side
;
3135 enum attr_units units
;
3136 enum attr_type type
;
3139 if (!NONDEBUG_INSN_P (within
))
3141 icode
= recog_memoized (within
);
3144 if (INSN_INFO_ENTRY (uid
).reservation
!= 0)
3146 units
= get_attr_units (within
);
3147 type
= get_attr_type (within
);
3148 this_rsrv
= get_reservation_flags (units
);
3151 side
= get_insn_side (within
, units
);
3153 /* Certain floating point instructions are treated specially. If
3154 an insn can choose between units it can reserve, and its
3155 reservation spans more than one cycle, the reservation contains
3156 special markers in the first cycle to help us reconstruct what
3157 the automaton chose. */
3158 if ((type
== TYPE_ADDDP
|| type
== TYPE_FP4
)
3159 && units
== UNITS_LS
)
3161 int test1_code
= ((type
== TYPE_FP4
? UNIT_QID_FPL1
: UNIT_QID_ADDDPL1
)
3162 + side
* UNIT_QID_SIDE_OFFSET
);
3163 int test2_code
= ((type
== TYPE_FP4
? UNIT_QID_FPS1
: UNIT_QID_ADDDPS1
)
3164 + side
* UNIT_QID_SIDE_OFFSET
);
3165 if ((sched_mask
& (1 << test1_code
)) != 0)
3167 this_rsrv
= RESERVATION_FLAG_L
;
3168 sched_mask
&= ~(1 << test1_code
);
3170 else if ((sched_mask
& (1 << test2_code
)) != 0)
3172 this_rsrv
= RESERVATION_FLAG_S
;
3173 sched_mask
&= ~(1 << test2_code
);
3177 if ((this_rsrv
& (this_rsrv
- 1)) == 0)
3179 int t
= exact_log2 (this_rsrv
) + side
* UNIT_QID_SIDE_OFFSET
;
3180 rsrv
[side
] |= this_rsrv
;
3181 INSN_INFO_ENTRY (uid
).reservation
= t
;
3187 for (j
= 0; j
< 4; j
++)
3188 if (this_rsrv
& (1 << j
))
3189 rsrv_count
[side
][j
]++;
3192 if ((pass
== 2 && this_rsrv
!= RESERVATION_FLAG_DLS
)
3193 || (pass
== 3 && this_rsrv
== RESERVATION_FLAG_DLS
))
3195 int best
= -1, best_cost
= INT_MAX
;
3196 for (j
= 0; j
< 4; j
++)
3197 if ((this_rsrv
& (1 << j
))
3198 && !(rsrv
[side
] & (1 << j
))
3199 && rsrv_count
[side
][j
] < best_cost
)
3201 best_cost
= rsrv_count
[side
][j
];
3204 gcc_assert (best
!= -1);
3205 rsrv
[side
] |= 1 << best
;
3206 for (j
= 0; j
< 4; j
++)
3207 if ((this_rsrv
& (1 << j
)) && j
!= best
)
3208 rsrv_count
[side
][j
]--;
3210 INSN_INFO_ENTRY (uid
).reservation
3211 = best
+ side
* UNIT_QID_SIDE_OFFSET
;
3217 /* Return a factor by which to weight unit imbalances for a reservation
3220 unit_req_factor (enum unitreqs r
)
3242 /* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3243 requirements. Returns zero if INSN can't be handled, otherwise
3244 either one or two to show how many of the two pairs are in use.
3245 REQ1 is always used, it holds what is normally thought of as the
3246 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3247 describe a cross path, or for loads/stores, the T unit. */
3249 get_unit_reqs (rtx_insn
*insn
, int *req1
, int *side1
, int *req2
, int *side2
)
3251 enum attr_units units
;
3252 enum attr_cross cross
;
3255 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
3257 units
= get_attr_units (insn
);
3258 if (units
== UNITS_UNKNOWN
)
3260 side
= get_insn_side (insn
, units
);
3261 cross
= get_attr_cross (insn
);
3263 req
= (units
== UNITS_D
? UNIT_REQ_D
3264 : units
== UNITS_D_ADDR
? UNIT_REQ_D
3265 : units
== UNITS_DL
? UNIT_REQ_DL
3266 : units
== UNITS_DS
? UNIT_REQ_DS
3267 : units
== UNITS_L
? UNIT_REQ_L
3268 : units
== UNITS_LS
? UNIT_REQ_LS
3269 : units
== UNITS_S
? UNIT_REQ_S
3270 : units
== UNITS_M
? UNIT_REQ_M
3271 : units
== UNITS_DLS
? UNIT_REQ_DLS
3273 gcc_assert (req
!= -1);
3276 if (units
== UNITS_D_ADDR
)
3279 *side2
= side
^ (cross
== CROSS_Y
? 1 : 0);
3282 else if (cross
== CROSS_Y
)
3291 /* Walk the insns between and including HEAD and TAIL, and mark the
3292 resource requirements in the unit_reqs table. */
3294 count_unit_reqs (unit_req_table reqs
, rtx_insn
*head
, rtx_insn
*tail
)
3298 memset (reqs
, 0, sizeof (unit_req_table
));
3300 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3302 int side1
, side2
, req1
, req2
;
3304 switch (get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
))
3307 reqs
[side2
][req2
]++;
3310 reqs
[side1
][req1
]++;
3316 /* Update the table REQS by merging more specific unit reservations into
3317 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3318 UNIT_REQ_DL, DS, and DLS. */
3320 merge_unit_reqs (unit_req_table reqs
)
3323 for (side
= 0; side
< 2; side
++)
3325 int d
= reqs
[side
][UNIT_REQ_D
];
3326 int l
= reqs
[side
][UNIT_REQ_L
];
3327 int s
= reqs
[side
][UNIT_REQ_S
];
3328 int dl
= reqs
[side
][UNIT_REQ_DL
];
3329 int ls
= reqs
[side
][UNIT_REQ_LS
];
3330 int ds
= reqs
[side
][UNIT_REQ_DS
];
3332 reqs
[side
][UNIT_REQ_DL
] += d
;
3333 reqs
[side
][UNIT_REQ_DL
] += l
;
3334 reqs
[side
][UNIT_REQ_DS
] += d
;
3335 reqs
[side
][UNIT_REQ_DS
] += s
;
3336 reqs
[side
][UNIT_REQ_LS
] += l
;
3337 reqs
[side
][UNIT_REQ_LS
] += s
;
3338 reqs
[side
][UNIT_REQ_DLS
] += ds
+ dl
+ ls
+ d
+ l
+ s
;
3342 /* Examine the table REQS and return a measure of unit imbalance by comparing
3343 the two sides of the machine. If, for example, D1 is used twice and D2
3344 used not at all, the return value should be 1 in the absence of other
3347 unit_req_imbalance (unit_req_table reqs
)
3352 for (i
= 0; i
< UNIT_REQ_MAX
; i
++)
3354 int factor
= unit_req_factor ((enum unitreqs
) i
);
3355 int diff
= abs (reqs
[0][i
] - reqs
[1][i
]);
3356 val
+= (diff
+ factor
- 1) / factor
/ 2;
3361 /* Return the resource-constrained minimum iteration interval given the
3362 data in the REQS table. This must have been processed with
3363 merge_unit_reqs already. */
3365 res_mii (unit_req_table reqs
)
3369 for (side
= 0; side
< 2; side
++)
3370 for (req
= 0; req
< UNIT_REQ_MAX
; req
++)
3372 int factor
= unit_req_factor ((enum unitreqs
) req
);
3373 worst
= MAX ((reqs
[side
][UNIT_REQ_D
] + factor
- 1) / factor
, worst
);
3379 /* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3380 the operands that are involved in the (up to) two reservations, as
3381 found by get_unit_reqs. Return true if we did this successfully, false
3382 if we couldn't identify what to do with INSN. */
3384 get_unit_operand_masks (rtx_insn
*insn
, unsigned int *pmask1
,
3385 unsigned int *pmask2
)
3387 enum attr_op_pattern op_pat
;
3389 if (recog_memoized (insn
) < 0)
3391 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
)
3393 extract_insn (insn
);
3394 op_pat
= get_attr_op_pattern (insn
);
3395 if (op_pat
== OP_PATTERN_DT
)
3397 gcc_assert (recog_data
.n_operands
== 2);
3402 else if (op_pat
== OP_PATTERN_TD
)
3404 gcc_assert (recog_data
.n_operands
== 2);
3409 else if (op_pat
== OP_PATTERN_SXS
)
3411 gcc_assert (recog_data
.n_operands
== 3);
3412 *pmask1
= (1 << 0) | (1 << 2);
3416 else if (op_pat
== OP_PATTERN_SX
)
3418 gcc_assert (recog_data
.n_operands
== 2);
3423 else if (op_pat
== OP_PATTERN_SSX
)
3425 gcc_assert (recog_data
.n_operands
== 3);
3426 *pmask1
= (1 << 0) | (1 << 1);
3433 /* Try to replace a register in INSN, which has corresponding rename info
3434 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3435 about the operands that must be renamed and the side they are on.
3436 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3437 We recompute this information locally after our transformation, and keep
3438 it only if we managed to improve the balance. */
3440 try_rename_operands (rtx_insn
*head
, rtx_insn
*tail
, unit_req_table reqs
,
3442 insn_rr_info
*info
, unsigned int op_mask
, int orig_side
)
3444 enum reg_class super_class
= orig_side
== 0 ? B_REGS
: A_REGS
;
3445 HARD_REG_SET unavailable
;
3446 du_head_p this_head
;
3447 struct du_chain
*chain
;
3450 int best_reg
, old_reg
;
3451 vec
<du_head_p
> involved_chains
= vNULL
;
3452 unit_req_table new_reqs
;
3454 for (i
= 0, tmp_mask
= op_mask
; tmp_mask
; i
++)
3457 if ((tmp_mask
& (1 << i
)) == 0)
3459 if (info
->op_info
[i
].n_chains
!= 1)
3461 op_chain
= regrename_chain_from_id (info
->op_info
[i
].heads
[0]->id
);
3462 involved_chains
.safe_push (op_chain
);
3463 tmp_mask
&= ~(1 << i
);
3466 if (involved_chains
.length () > 1)
3469 this_head
= involved_chains
[0];
3470 if (this_head
->cannot_rename
)
3473 for (chain
= this_head
->first
; chain
; chain
= chain
->next_use
)
3475 unsigned int mask1
, mask2
, mask_changed
;
3476 int count
, side1
, side2
, req1
, req2
;
3477 insn_rr_info
*this_rr
= &insn_rr
[INSN_UID (chain
->insn
)];
3479 count
= get_unit_reqs (chain
->insn
, &req1
, &side1
, &req2
, &side2
);
3484 if (!get_unit_operand_masks (chain
->insn
, &mask1
, &mask2
))
3487 extract_insn (chain
->insn
);
3490 for (i
= 0; i
< recog_data
.n_operands
; i
++)
3493 int n_this_op
= this_rr
->op_info
[i
].n_chains
;
3494 for (j
= 0; j
< n_this_op
; j
++)
3496 du_head_p other
= this_rr
->op_info
[i
].heads
[j
];
3497 if (regrename_chain_from_id (other
->id
) == this_head
)
3505 mask_changed
|= 1 << i
;
3507 gcc_assert (mask_changed
!= 0);
3508 if (mask_changed
!= mask1
&& mask_changed
!= mask2
)
3512 /* If we get here, we can do the renaming. */
3513 COMPL_HARD_REG_SET (unavailable
, reg_class_contents
[(int) super_class
]);
3515 old_reg
= this_head
->regno
;
3516 best_reg
= find_best_rename_reg (this_head
, super_class
, &unavailable
, old_reg
);
3518 regrename_do_replace (this_head
, best_reg
);
3520 count_unit_reqs (new_reqs
, head
, PREV_INSN (tail
));
3521 merge_unit_reqs (new_reqs
);
3524 fprintf (dump_file
, "reshuffle for insn %d, op_mask %x, "
3525 "original side %d, new reg %d\n",
3526 INSN_UID (insn
), op_mask
, orig_side
, best_reg
);
3527 fprintf (dump_file
, " imbalance %d -> %d\n",
3528 unit_req_imbalance (reqs
), unit_req_imbalance (new_reqs
));
3530 if (unit_req_imbalance (new_reqs
) > unit_req_imbalance (reqs
))
3531 regrename_do_replace (this_head
, old_reg
);
3533 memcpy (reqs
, new_reqs
, sizeof (unit_req_table
));
3536 involved_chains
.release ();
3539 /* Find insns in LOOP which would, if shifted to the other side
3540 of the machine, reduce an imbalance in the unit reservations. */
3542 reshuffle_units (basic_block loop
)
3544 rtx_insn
*head
= BB_HEAD (loop
);
3545 rtx_insn
*tail
= BB_END (loop
);
3547 unit_req_table reqs
;
3552 count_unit_reqs (reqs
, head
, PREV_INSN (tail
));
3553 merge_unit_reqs (reqs
);
3555 regrename_init (true);
3557 bitmap_initialize (&bbs
, &bitmap_default_obstack
);
3559 FOR_EACH_EDGE (e
, ei
, loop
->preds
)
3560 bitmap_set_bit (&bbs
, e
->src
->index
);
3562 bitmap_set_bit (&bbs
, loop
->index
);
3563 regrename_analyze (&bbs
);
3565 for (insn
= head
; insn
!= NEXT_INSN (tail
); insn
= NEXT_INSN (insn
))
3567 enum attr_units units
;
3568 int count
, side1
, side2
, req1
, req2
;
3569 unsigned int mask1
, mask2
;
3572 if (!NONDEBUG_INSN_P (insn
))
3575 count
= get_unit_reqs (insn
, &req1
, &side1
, &req2
, &side2
);
3580 if (!get_unit_operand_masks (insn
, &mask1
, &mask2
))
3583 info
= &insn_rr
[INSN_UID (insn
)];
3584 if (info
->op_info
== NULL
)
3587 if (reqs
[side1
][req1
] > 1
3588 && reqs
[side1
][req1
] > 2 * reqs
[side1
^ 1][req1
])
3590 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask1
, side1
);
3593 units
= get_attr_units (insn
);
3594 if (units
== UNITS_D_ADDR
)
3596 gcc_assert (count
== 2);
3597 if (reqs
[side2
][req2
] > 1
3598 && reqs
[side2
][req2
] > 2 * reqs
[side2
^ 1][req2
])
3600 try_rename_operands (head
, tail
, reqs
, insn
, info
, mask2
, side2
);
3604 regrename_finish ();
3607 /* Backend scheduling state. */
3608 typedef struct c6x_sched_context
3610 /* The current scheduler clock, saved in the sched_reorder hook. */
3611 int curr_sched_clock
;
3613 /* Number of insns issued so far in this cycle. */
3614 int issued_this_cycle
;
3616 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3617 theoretical maximum for number of jumps in flight is 12: 2 every
3618 cycle, with a latency of 6 cycles each. This is a circular
3619 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3620 jumps have a higher index. This array should be accessed through
3621 the jump_cycle function. */
3622 int jump_cycles
[12];
3623 int jump_cycle_index
;
3625 /* In parallel with jump_cycles, this array records the opposite of
3626 the condition used in each pending jump. This is used to
3627 predicate insns that are scheduled in the jump's delay slots. If
3628 this is NULL_RTX no such predication happens. */
3631 /* Similar to the jump_cycles mechanism, but here we take into
3632 account all insns with delay slots, to avoid scheduling asms into
3634 int delays_finished_at
;
3636 /* The following variable value is the last issued insn. */
3637 rtx_insn
*last_scheduled_insn
;
3638 /* The last issued insn that isn't a shadow of another. */
3639 rtx_insn
*last_scheduled_iter0
;
3641 /* The following variable value is DFA state before issuing the
3642 first insn in the current clock cycle. We do not use this member
3643 of the structure directly; we copy the data in and out of
3644 prev_cycle_state. */
3645 state_t prev_cycle_state_ctx
;
3647 int reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3648 int reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3649 int reg_set_in_cycle
[FIRST_PSEUDO_REGISTER
];
3651 int tmp_reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3652 int tmp_reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3653 } *c6x_sched_context_t
;
3655 /* The current scheduling state. */
3656 static struct c6x_sched_context ss
;
3658 /* The following variable value is DFA state before issuing the first insn
3659 in the current clock cycle. This is used in c6x_variable_issue for
3660 comparison with the state after issuing the last insn in a cycle. */
3661 static state_t prev_cycle_state
;
3663 /* Set when we discover while processing an insn that it would lead to too
3664 many accesses of the same register. */
3665 static bool reg_access_stall
;
3667 /* The highest insn uid after delayed insns were split, but before loop bodies
3668 were copied by the modulo scheduling code. */
3669 static int sploop_max_uid_iter0
;
3671 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3672 so the caller does not specifically have to test for it. */
3674 get_jump_cycle (int n
)
3678 n
+= ss
.jump_cycle_index
;
3681 return ss
.jump_cycles
[n
];
3684 /* Look up the jump condition with index N. */
3686 get_jump_cond (int n
)
3690 n
+= ss
.jump_cycle_index
;
3693 return ss
.jump_cond
[n
];
3696 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3697 has delay slots beyond CLOCK_VAR, return -1. */
3699 first_jump_index (int clock_var
)
3705 int t
= get_jump_cycle (n
);
3714 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3715 and has the opposite condition of COND. */
3717 record_jump (int cycle
, rtx cond
)
3719 if (ss
.jump_cycle_index
== 0)
3720 ss
.jump_cycle_index
= 11;
3722 ss
.jump_cycle_index
--;
3723 ss
.jump_cycles
[ss
.jump_cycle_index
] = cycle
;
3724 ss
.jump_cond
[ss
.jump_cycle_index
] = cond
;
3727 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3730 insn_set_clock (rtx insn
, int cycle
)
3732 unsigned uid
= INSN_UID (insn
);
3734 if (uid
>= INSN_INFO_LENGTH
)
3735 insn_info
.safe_grow (uid
* 5 / 4 + 10);
3737 INSN_INFO_ENTRY (uid
).clock
= cycle
;
3738 INSN_INFO_ENTRY (uid
).new_cond
= NULL
;
3739 INSN_INFO_ENTRY (uid
).reservation
= 0;
3740 INSN_INFO_ENTRY (uid
).ebb_start
= false;
3743 /* Return the clock cycle we set for the insn with uid UID. */
3745 insn_uid_get_clock (int uid
)
3747 return INSN_INFO_ENTRY (uid
).clock
;
3750 /* Return the clock cycle we set for INSN. */
3752 insn_get_clock (rtx insn
)
3754 return insn_uid_get_clock (INSN_UID (insn
));
3757 /* Examine INSN, and if it is a conditional jump of any kind, return
3758 the opposite of the condition in which it branches. Otherwise,
3761 condjump_opposite_condition (rtx insn
)
3763 rtx pat
= PATTERN (insn
);
3764 int icode
= INSN_CODE (insn
);
3767 if (icode
== CODE_FOR_br_true
|| icode
== CODE_FOR_br_false
)
3769 x
= XEXP (SET_SRC (pat
), 0);
3770 if (icode
== CODE_FOR_br_false
)
3773 if (GET_CODE (pat
) == COND_EXEC
)
3775 rtx t
= COND_EXEC_CODE (pat
);
3776 if ((GET_CODE (t
) == PARALLEL
3777 && GET_CODE (XVECEXP (t
, 0, 0)) == RETURN
)
3778 || (GET_CODE (t
) == UNSPEC
&& XINT (t
, 1) == UNSPEC_REAL_JUMP
)
3779 || (GET_CODE (t
) == SET
&& SET_DEST (t
) == pc_rtx
))
3780 x
= COND_EXEC_TEST (pat
);
3785 enum rtx_code code
= GET_CODE (x
);
3786 x
= gen_rtx_fmt_ee (code
== EQ
? NE
: EQ
,
3787 GET_MODE (x
), XEXP (x
, 0),
3793 /* Return true iff COND1 and COND2 are exactly opposite conditions
3794 one of them NE and the other EQ. */
3796 conditions_opposite_p (rtx cond1
, rtx cond2
)
3798 return (rtx_equal_p (XEXP (cond1
, 0), XEXP (cond2
, 0))
3799 && rtx_equal_p (XEXP (cond1
, 1), XEXP (cond2
, 1))
3800 && GET_CODE (cond1
) == reverse_condition (GET_CODE (cond2
)));
3803 /* Return true if we can add a predicate COND to INSN, or if INSN
3804 already has that predicate. If DOIT is true, also perform the
3807 predicate_insn (rtx_insn
*insn
, rtx cond
, bool doit
)
3810 if (cond
== NULL_RTX
)
3816 if (get_attr_predicable (insn
) == PREDICABLE_YES
3817 && GET_CODE (PATTERN (insn
)) != COND_EXEC
)
3821 rtx newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3822 PATTERN (insn
) = newpat
;
3823 INSN_CODE (insn
) = -1;
3827 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
3828 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn
)), cond
))
3830 icode
= INSN_CODE (insn
);
3831 if (icode
== CODE_FOR_real_jump
3832 || icode
== CODE_FOR_jump
3833 || icode
== CODE_FOR_indirect_jump
)
3835 rtx pat
= PATTERN (insn
);
3836 rtx dest
= (icode
== CODE_FOR_real_jump
? XVECEXP (pat
, 0, 0)
3837 : icode
== CODE_FOR_jump
? XEXP (SET_SRC (pat
), 0)
3843 newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3845 newpat
= gen_br_true (cond
, XEXP (cond
, 0), dest
);
3846 PATTERN (insn
) = newpat
;
3847 INSN_CODE (insn
) = -1;
3851 if (INSN_CODE (insn
) == CODE_FOR_br_true
)
3853 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3854 return rtx_equal_p (br_cond
, cond
);
3856 if (INSN_CODE (insn
) == CODE_FOR_br_false
)
3858 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3859 return conditions_opposite_p (br_cond
, cond
);
3864 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3866 init_sched_state (c6x_sched_context_t sc
)
3868 sc
->last_scheduled_insn
= NULL
;
3869 sc
->last_scheduled_iter0
= NULL
;
3870 sc
->issued_this_cycle
= 0;
3871 memset (sc
->jump_cycles
, 0, sizeof sc
->jump_cycles
);
3872 memset (sc
->jump_cond
, 0, sizeof sc
->jump_cond
);
3873 sc
->jump_cycle_index
= 0;
3874 sc
->delays_finished_at
= 0;
3875 sc
->curr_sched_clock
= 0;
3877 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3879 memset (sc
->reg_n_accesses
, 0, sizeof sc
->reg_n_accesses
);
3880 memset (sc
->reg_n_xaccesses
, 0, sizeof sc
->reg_n_xaccesses
);
3881 memset (sc
->reg_set_in_cycle
, 0, sizeof sc
->reg_set_in_cycle
);
3883 state_reset (sc
->prev_cycle_state_ctx
);
3886 /* Allocate store for new scheduling context. */
3888 c6x_alloc_sched_context (void)
3890 return xmalloc (sizeof (struct c6x_sched_context
));
3893 /* If CLEAN_P is true then initializes _SC with clean data,
3894 and from the global context otherwise. */
3896 c6x_init_sched_context (void *_sc
, bool clean_p
)
3898 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3902 init_sched_state (sc
);
3907 sc
->prev_cycle_state_ctx
= xmalloc (dfa_state_size
);
3908 memcpy (sc
->prev_cycle_state_ctx
, prev_cycle_state
, dfa_state_size
);
3912 /* Sets the global scheduling context to the one pointed to by _SC. */
3914 c6x_set_sched_context (void *_sc
)
3916 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3918 gcc_assert (sc
!= NULL
);
3920 memcpy (prev_cycle_state
, sc
->prev_cycle_state_ctx
, dfa_state_size
);
3923 /* Clear data in _SC. */
3925 c6x_clear_sched_context (void *_sc
)
3927 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3928 gcc_assert (_sc
!= NULL
);
3930 free (sc
->prev_cycle_state_ctx
);
3935 c6x_free_sched_context (void *_sc
)
3940 /* True if we are currently performing a preliminary scheduling
3941 pass before modulo scheduling; we can't allow the scheduler to
3942 modify instruction patterns using packetization assumptions,
3943 since there will be another scheduling pass later if modulo
3944 scheduling fails. */
3945 static bool in_hwloop
;
3947 /* Provide information about speculation capabilities, and set the
3948 DO_BACKTRACKING flag. */
3950 c6x_set_sched_flags (spec_info_t spec_info
)
3952 unsigned int *flags
= &(current_sched_info
->flags
);
3954 if (*flags
& SCHED_EBB
)
3956 *flags
|= DO_BACKTRACKING
| DO_PREDICATION
;
3959 *flags
|= DONT_BREAK_DEPENDENCIES
;
3961 spec_info
->mask
= 0;
3964 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3967 c6x_issue_rate (void)
3972 /* Used together with the collapse_ndfa option, this ensures that we reach a
3973 deterministic automaton state before trying to advance a cycle.
3974 With collapse_ndfa, genautomata creates advance cycle arcs only for
3975 such deterministic states. */
3978 c6x_sched_dfa_pre_cycle_insn (void)
3983 /* We're beginning a new block. Initialize data structures as necessary. */
3986 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED
,
3987 int sched_verbose ATTRIBUTE_UNUSED
,
3988 int max_ready ATTRIBUTE_UNUSED
)
3990 if (prev_cycle_state
== NULL
)
3992 prev_cycle_state
= xmalloc (dfa_state_size
);
3994 init_sched_state (&ss
);
3995 state_reset (prev_cycle_state
);
3998 /* We are about to being issuing INSN. Return nonzero if we cannot
3999 issue it on given cycle CLOCK and return zero if we should not sort
4000 the ready queue on the next clock start.
4001 For C6X, we use this function just to copy the previous DFA state
4002 for comparison purposes. */
4005 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED
, int verbose ATTRIBUTE_UNUSED
,
4006 rtx_insn
*insn ATTRIBUTE_UNUSED
,
4007 int last_clock ATTRIBUTE_UNUSED
,
4008 int clock ATTRIBUTE_UNUSED
, int *sort_p ATTRIBUTE_UNUSED
)
4010 if (clock
!= last_clock
)
4011 memcpy (prev_cycle_state
, curr_state
, dfa_state_size
);
4016 c6x_mark_regno_read (int regno
, bool cross
)
4018 int t
= ++ss
.tmp_reg_n_accesses
[regno
];
4021 reg_access_stall
= true;
4025 int set_cycle
= ss
.reg_set_in_cycle
[regno
];
4026 /* This must be done in this way rather than by tweaking things in
4027 adjust_cost, since the stall occurs even for insns with opposite
4028 predicates, and the scheduler may not even see a dependency. */
4029 if (set_cycle
> 0 && set_cycle
== ss
.curr_sched_clock
)
4030 reg_access_stall
= true;
4031 /* This doesn't quite do anything yet as we're only modeling one
4033 ++ss
.tmp_reg_n_xaccesses
[regno
];
4037 /* Note that REG is read in the insn being examined. If CROSS, it
4038 means the access is through a cross path. Update the temporary reg
4039 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4040 in the current cycle. */
4043 c6x_mark_reg_read (rtx reg
, bool cross
)
4045 unsigned regno
= REGNO (reg
);
4046 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4049 c6x_mark_regno_read (regno
+ nregs
, cross
);
4052 /* Note that register REG is written in cycle CYCLES. */
4055 c6x_mark_reg_written (rtx reg
, int cycles
)
4057 unsigned regno
= REGNO (reg
);
4058 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
4061 ss
.reg_set_in_cycle
[regno
+ nregs
] = cycles
;
4064 /* Update the register state information for an instruction whose
4065 body is X. Return true if the instruction has to be delayed until the
4069 c6x_registers_update (rtx_insn
*insn
)
4071 enum attr_cross cross
;
4072 enum attr_dest_regfile destrf
;
4076 if (!reload_completed
|| recog_memoized (insn
) < 0)
4079 reg_access_stall
= false;
4080 memcpy (ss
.tmp_reg_n_accesses
, ss
.reg_n_accesses
,
4081 sizeof ss
.tmp_reg_n_accesses
);
4082 memcpy (ss
.tmp_reg_n_xaccesses
, ss
.reg_n_xaccesses
,
4083 sizeof ss
.tmp_reg_n_xaccesses
);
4085 extract_insn (insn
);
4087 cross
= get_attr_cross (insn
);
4088 destrf
= get_attr_dest_regfile (insn
);
4090 nops
= recog_data
.n_operands
;
4092 if (GET_CODE (x
) == COND_EXEC
)
4094 c6x_mark_reg_read (XEXP (XEXP (x
, 0), 0), false);
4098 for (i
= 0; i
< nops
; i
++)
4100 rtx op
= recog_data
.operand
[i
];
4101 if (recog_data
.operand_type
[i
] == OP_OUT
)
4105 bool this_cross
= cross
;
4106 if (destrf
== DEST_REGFILE_A
&& A_REGNO_P (REGNO (op
)))
4108 if (destrf
== DEST_REGFILE_B
&& B_REGNO_P (REGNO (op
)))
4110 c6x_mark_reg_read (op
, this_cross
);
4112 else if (MEM_P (op
))
4115 switch (GET_CODE (op
))
4124 c6x_mark_reg_read (op
, false);
4129 gcc_assert (GET_CODE (op
) == PLUS
);
4132 c6x_mark_reg_read (XEXP (op
, 0), false);
4133 if (REG_P (XEXP (op
, 1)))
4134 c6x_mark_reg_read (XEXP (op
, 1), false);
4139 c6x_mark_regno_read (REG_B14
, false);
4145 else if (!CONSTANT_P (op
) && strlen (recog_data
.constraints
[i
]) > 0)
4148 return reg_access_stall
;
4151 /* Helper function for the TARGET_SCHED_REORDER and
4152 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4153 in the current cycle, move it down in the ready list and return the
4154 number of non-unsafe insns. */
4157 c6x_sched_reorder_1 (rtx_insn
**ready
, int *pn_ready
, int clock_var
)
4159 int n_ready
= *pn_ready
;
4160 rtx_insn
**e_ready
= ready
+ n_ready
;
4164 /* Keep track of conflicts due to a limit number of register accesses,
4165 and due to stalls incurred by too early accesses of registers using
4168 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4170 rtx_insn
*insn
= *insnp
;
4171 int icode
= recog_memoized (insn
);
4172 bool is_asm
= (icode
< 0
4173 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4174 || asm_noperands (PATTERN (insn
)) >= 0));
4175 bool no_parallel
= (is_asm
|| icode
== CODE_FOR_sploop
4177 && get_attr_type (insn
) == TYPE_ATOMIC
));
4179 /* We delay asm insns until all delay slots are exhausted. We can't
4180 accurately tell how many cycles an asm takes, and the main scheduling
4181 code always assumes at least 1 cycle, which may be wrong. */
4183 && (ss
.issued_this_cycle
> 0 || clock_var
< ss
.delays_finished_at
))
4184 || c6x_registers_update (insn
)
4185 || (ss
.issued_this_cycle
> 0 && icode
== CODE_FOR_sploop
))
4187 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4192 else if (shadow_p (insn
))
4194 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4199 /* Ensure that no other jump is scheduled in jump delay slots, since
4200 it would put the machine into the wrong state. Also, we must
4201 avoid scheduling insns that have a latency longer than the
4202 remaining jump delay slots, as the code at the jump destination
4203 won't be prepared for it.
4205 However, we can relax this condition somewhat. The rest of the
4206 scheduler will automatically avoid scheduling an insn on which
4207 the jump shadow depends so late that its side effect happens
4208 after the jump. This means that if we see an insn with a longer
4209 latency here, it can safely be scheduled if we can ensure that it
4210 has a predicate opposite of the previous jump: the side effect
4211 will happen in what we think of as the same basic block. In
4212 c6x_variable_issue, we will record the necessary predicate in
4213 new_conditions, and after scheduling is finished, we will modify
4216 Special care must be taken whenever there is more than one jump
4219 first_jump
= first_jump_index (clock_var
);
4220 if (first_jump
!= -1)
4222 int first_cycle
= get_jump_cycle (first_jump
);
4223 rtx first_cond
= get_jump_cond (first_jump
);
4224 int second_cycle
= 0;
4227 second_cycle
= get_jump_cycle (first_jump
- 1);
4229 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4231 rtx_insn
*insn
= *insnp
;
4232 int icode
= recog_memoized (insn
);
4233 bool is_asm
= (icode
< 0
4234 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
4235 || asm_noperands (PATTERN (insn
)) >= 0));
4236 int this_cycles
, rsrv_cycles
;
4237 enum attr_type type
;
4239 gcc_assert (!is_asm
);
4242 this_cycles
= get_attr_cycles (insn
);
4243 rsrv_cycles
= get_attr_reserve_cycles (insn
);
4244 type
= get_attr_type (insn
);
4245 /* Treat branches specially; there is also a hazard if two jumps
4246 end at the same cycle. */
4247 if (type
== TYPE_BRANCH
|| type
== TYPE_CALL
)
4249 if (clock_var
+ this_cycles
<= first_cycle
)
4251 if ((first_jump
> 0 && clock_var
+ this_cycles
> second_cycle
)
4252 || clock_var
+ rsrv_cycles
> first_cycle
4253 || !predicate_insn (insn
, first_cond
, false))
4255 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4266 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4267 for later and clear the register access information for the new
4268 cycle. We also move asm statements out of the way if they would be
4269 scheduled in a delay slot. */
4272 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED
,
4273 int sched_verbose ATTRIBUTE_UNUSED
,
4274 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4275 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4277 ss
.curr_sched_clock
= clock_var
;
4278 ss
.issued_this_cycle
= 0;
4279 memset (ss
.reg_n_accesses
, 0, sizeof ss
.reg_n_accesses
);
4280 memset (ss
.reg_n_xaccesses
, 0, sizeof ss
.reg_n_xaccesses
);
4285 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4288 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4289 cycle for every insn. */
4292 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED
,
4293 int sched_verbose ATTRIBUTE_UNUSED
,
4294 rtx_insn
**ready ATTRIBUTE_UNUSED
,
4295 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
4297 /* FIXME: the assembler rejects labels inside an execute packet.
4298 This can occur if prologue insns are scheduled in parallel with
4299 others, so we avoid this here. Also make sure that nothing is
4300 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4301 if (RTX_FRAME_RELATED_P (ss
.last_scheduled_insn
)
4302 || JUMP_P (ss
.last_scheduled_insn
)
4303 || (recog_memoized (ss
.last_scheduled_insn
) >= 0
4304 && get_attr_type (ss
.last_scheduled_insn
) == TYPE_ATOMIC
))
4306 int n_ready
= *pn_ready
;
4307 rtx_insn
**e_ready
= ready
+ n_ready
;
4310 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
4312 rtx_insn
*insn
= *insnp
;
4313 if (!shadow_p (insn
))
4315 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
4324 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
4327 /* Subroutine of maybe_clobber_cond, called through note_stores. */
4330 clobber_cond_1 (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
, void *data1
)
4332 rtx
*cond
= (rtx
*)data1
;
4333 if (*cond
!= NULL_RTX
&& reg_overlap_mentioned_p (x
, *cond
))
4337 /* Examine INSN, and if it destroys the conditions have recorded for
4338 any of the jumps in flight, clear that condition so that we don't
4339 predicate any more insns. CLOCK_VAR helps us limit the search to
4340 only those jumps which are still in flight. */
4343 maybe_clobber_cond (rtx insn
, int clock_var
)
4346 idx
= ss
.jump_cycle_index
;
4347 for (n
= 0; n
< 12; n
++, idx
++)
4354 cycle
= ss
.jump_cycles
[idx
];
4355 if (cycle
<= clock_var
)
4358 cond
= ss
.jump_cond
[idx
];
4359 if (cond
== NULL_RTX
)
4364 ss
.jump_cond
[idx
] = NULL_RTX
;
4368 note_stores (PATTERN (insn
), clobber_cond_1
, ss
.jump_cond
+ idx
);
4369 for (link
= REG_NOTES (insn
); link
; link
= XEXP (link
, 1))
4370 if (REG_NOTE_KIND (link
) == REG_INC
)
4371 clobber_cond_1 (XEXP (link
, 0), NULL_RTX
, ss
.jump_cond
+ idx
);
4375 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4376 issue INSN. Return the number of insns left on the ready queue
4377 that can be issued this cycle.
4378 We use this hook to record clock cycles and reservations for every insn. */
4381 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED
,
4382 int sched_verbose ATTRIBUTE_UNUSED
,
4383 rtx_insn
*insn
, int can_issue_more ATTRIBUTE_UNUSED
)
4385 ss
.last_scheduled_insn
= insn
;
4386 if (INSN_UID (insn
) < sploop_max_uid_iter0
&& !JUMP_P (insn
))
4387 ss
.last_scheduled_iter0
= insn
;
4388 if (GET_CODE (PATTERN (insn
)) != USE
&& GET_CODE (PATTERN (insn
)) != CLOBBER
)
4389 ss
.issued_this_cycle
++;
4390 if (insn_info
.exists ())
4392 state_t st_after
= alloca (dfa_state_size
);
4393 int curr_clock
= ss
.curr_sched_clock
;
4394 int uid
= INSN_UID (insn
);
4395 int icode
= recog_memoized (insn
);
4397 int first
, first_cycle
;
4401 insn_set_clock (insn
, curr_clock
);
4402 INSN_INFO_ENTRY (uid
).ebb_start
4403 = curr_clock
== 0 && ss
.issued_this_cycle
== 1;
4405 first
= first_jump_index (ss
.curr_sched_clock
);
4409 first_cond
= NULL_RTX
;
4413 first_cycle
= get_jump_cycle (first
);
4414 first_cond
= get_jump_cond (first
);
4417 && first_cycle
> curr_clock
4418 && first_cond
!= NULL_RTX
4419 && (curr_clock
+ get_attr_cycles (insn
) > first_cycle
4420 || get_attr_type (insn
) == TYPE_BRANCH
4421 || get_attr_type (insn
) == TYPE_CALL
))
4422 INSN_INFO_ENTRY (uid
).new_cond
= first_cond
;
4424 memcpy (st_after
, curr_state
, dfa_state_size
);
4425 state_transition (st_after
, const0_rtx
);
4428 for (i
= 0; i
< 2 * UNIT_QID_SIDE_OFFSET
; i
++)
4429 if (cpu_unit_reservation_p (st_after
, c6x_unit_codes
[i
])
4430 && !cpu_unit_reservation_p (prev_cycle_state
, c6x_unit_codes
[i
]))
4432 INSN_INFO_ENTRY (uid
).unit_mask
= mask
;
4434 maybe_clobber_cond (insn
, curr_clock
);
4440 c6x_registers_update (insn
);
4441 memcpy (ss
.reg_n_accesses
, ss
.tmp_reg_n_accesses
,
4442 sizeof ss
.reg_n_accesses
);
4443 memcpy (ss
.reg_n_xaccesses
, ss
.tmp_reg_n_accesses
,
4444 sizeof ss
.reg_n_xaccesses
);
4446 cycles
= get_attr_cycles (insn
);
4447 if (ss
.delays_finished_at
< ss
.curr_sched_clock
+ cycles
)
4448 ss
.delays_finished_at
= ss
.curr_sched_clock
+ cycles
;
4449 if (get_attr_type (insn
) == TYPE_BRANCH
4450 || get_attr_type (insn
) == TYPE_CALL
)
4452 rtx opposite
= condjump_opposite_condition (insn
);
4453 record_jump (ss
.curr_sched_clock
+ cycles
, opposite
);
4456 /* Mark the cycles in which the destination registers are written.
4457 This is used for calculating stalls when using cross units. */
4458 extract_insn (insn
);
4459 /* Cross-path stalls don't apply to results of load insns. */
4460 if (get_attr_type (insn
) == TYPE_LOAD
4461 || get_attr_type (insn
) == TYPE_LOADN
4462 || get_attr_type (insn
) == TYPE_LOAD_SHADOW
)
4464 for (i
= 0; i
< recog_data
.n_operands
; i
++)
4466 rtx op
= recog_data
.operand
[i
];
4469 rtx addr
= XEXP (op
, 0);
4470 if (GET_RTX_CLASS (GET_CODE (addr
)) == RTX_AUTOINC
)
4471 c6x_mark_reg_written (XEXP (addr
, 0),
4472 insn_uid_get_clock (uid
) + 1);
4474 if (recog_data
.operand_type
[i
] != OP_IN
4477 c6x_mark_reg_written (op
,
4478 insn_uid_get_clock (uid
) + cycles
);
4483 return can_issue_more
;
4486 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4487 anti- and output dependencies. */
4490 c6x_adjust_cost (rtx_insn
*insn
, rtx link
, rtx_insn
*dep_insn
, int cost
)
4492 enum attr_type insn_type
= TYPE_UNKNOWN
, dep_insn_type
= TYPE_UNKNOWN
;
4493 int dep_insn_code_number
, insn_code_number
;
4494 int shadow_bonus
= 0;
4496 dep_insn_code_number
= recog_memoized (dep_insn
);
4497 insn_code_number
= recog_memoized (insn
);
4499 if (dep_insn_code_number
>= 0)
4500 dep_insn_type
= get_attr_type (dep_insn
);
4502 if (insn_code_number
>= 0)
4503 insn_type
= get_attr_type (insn
);
4505 kind
= REG_NOTE_KIND (link
);
4508 /* If we have a dependency on a load, and it's not for the result of
4509 the load, it must be for an autoincrement. Reduce the cost in that
4511 if (dep_insn_type
== TYPE_LOAD
)
4513 rtx set
= PATTERN (dep_insn
);
4514 if (GET_CODE (set
) == COND_EXEC
)
4515 set
= COND_EXEC_CODE (set
);
4516 if (GET_CODE (set
) == UNSPEC
)
4520 gcc_assert (GET_CODE (set
) == SET
);
4521 if (!reg_overlap_mentioned_p (SET_DEST (set
), PATTERN (insn
)))
4527 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4528 it occurs in between two cycles, but we schedule it at the end of the
4530 if (shadow_type_p (insn_type
))
4533 /* Anti and output dependencies usually have zero cost, but we want
4534 to insert a stall after a jump, and after certain floating point
4535 insns that take more than one cycle to read their inputs. In the
4536 future, we should try to find a better algorithm for scheduling
4540 /* We can get anti-dependencies against shadow insns. Treat these
4541 like output dependencies, so that the insn is entirely finished
4542 before the branch takes place. */
4543 if (kind
== REG_DEP_ANTI
&& insn_type
== TYPE_SHADOW
)
4544 kind
= REG_DEP_OUTPUT
;
4545 switch (dep_insn_type
)
4551 if (get_attr_has_shadow (dep_insn
) == HAS_SHADOW_Y
)
4552 /* This is a real_jump/real_call insn. These don't have
4553 outputs, and ensuring the validity of scheduling things
4554 in the delay slot is the job of
4555 c6x_sched_reorder_1. */
4557 /* Unsplit calls can happen - e.g. for divide insns. */
4562 if (kind
== REG_DEP_OUTPUT
)
4563 return 5 - shadow_bonus
;
4567 if (kind
== REG_DEP_OUTPUT
)
4568 return 4 - shadow_bonus
;
4571 if (kind
== REG_DEP_OUTPUT
)
4572 return 2 - shadow_bonus
;
4575 if (kind
== REG_DEP_OUTPUT
)
4576 return 2 - shadow_bonus
;
4580 if (kind
== REG_DEP_OUTPUT
)
4581 return 7 - shadow_bonus
;
4584 if (kind
== REG_DEP_OUTPUT
)
4585 return 5 - shadow_bonus
;
4588 if (kind
== REG_DEP_OUTPUT
)
4589 return 9 - shadow_bonus
;
4593 if (kind
== REG_DEP_OUTPUT
)
4594 return 10 - shadow_bonus
;
4598 if (insn_type
== TYPE_SPKERNEL
)
4600 if (kind
== REG_DEP_OUTPUT
)
4601 return 1 - shadow_bonus
;
4607 return cost
- shadow_bonus
;
4610 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4611 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4612 first in the original stream. */
4615 gen_one_bundle (rtx_insn
**slot
, int n_filled
, int real_first
)
4622 seq
= gen_rtx_SEQUENCE (VOIDmode
, gen_rtvec_v (n_filled
, slot
));
4623 bundle
= make_insn_raw (seq
);
4624 BLOCK_FOR_INSN (bundle
) = BLOCK_FOR_INSN (slot
[0]);
4625 INSN_LOCATION (bundle
) = INSN_LOCATION (slot
[0]);
4626 SET_PREV_INSN (bundle
) = SET_PREV_INSN (slot
[real_first
]);
4630 for (i
= 0; i
< n_filled
; i
++)
4632 rtx_insn
*insn
= slot
[i
];
4634 SET_PREV_INSN (insn
) = t
? t
: PREV_INSN (bundle
);
4636 SET_NEXT_INSN (t
) = insn
;
4639 INSN_LOCATION (slot
[i
]) = INSN_LOCATION (bundle
);
4642 SET_NEXT_INSN (bundle
) = NEXT_INSN (PREV_INSN (bundle
));
4643 SET_NEXT_INSN (t
) = NEXT_INSN (bundle
);
4644 SET_NEXT_INSN (PREV_INSN (bundle
)) = bundle
;
4645 SET_PREV_INSN (NEXT_INSN (bundle
)) = bundle
;
4648 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4649 try to insert labels in the middle. */
4652 c6x_gen_bundles (void)
4655 rtx_insn
*insn
, *next
, *last_call
;
4657 FOR_EACH_BB_FN (bb
, cfun
)
4659 rtx_insn
*insn
, *next
;
4660 /* The machine is eight insns wide. We can have up to six shadow
4661 insns, plus an extra slot for merging the jump shadow. */
4666 for (insn
= BB_HEAD (bb
);; insn
= next
)
4669 rtx delete_this
= NULL_RTX
;
4671 if (NONDEBUG_INSN_P (insn
))
4673 /* Put calls at the start of the sequence. */
4679 memmove (&slot
[1], &slot
[0],
4680 n_filled
* sizeof (slot
[0]));
4682 if (!shadow_p (insn
))
4684 PUT_MODE (insn
, TImode
);
4686 PUT_MODE (slot
[1], VOIDmode
);
4693 slot
[n_filled
++] = insn
;
4697 next
= NEXT_INSN (insn
);
4698 while (next
&& insn
!= BB_END (bb
)
4699 && !(NONDEBUG_INSN_P (next
)
4700 && GET_CODE (PATTERN (next
)) != USE
4701 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4704 next
= NEXT_INSN (insn
);
4707 at_end
= insn
== BB_END (bb
);
4708 if (delete_this
== NULL_RTX
4709 && (at_end
|| (GET_MODE (next
) == TImode
4710 && !(shadow_p (next
) && CALL_P (next
)))))
4713 gen_one_bundle (slot
, n_filled
, first_slot
);
4722 /* Bundling, and emitting nops, can separate
4723 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4726 for (insn
= get_insns (); insn
; insn
= next
)
4728 next
= NEXT_INSN (insn
);
4730 || (INSN_P (insn
) && GET_CODE (PATTERN (insn
)) == SEQUENCE
4731 && CALL_P (XVECEXP (PATTERN (insn
), 0, 0))))
4733 if (!NOTE_P (insn
) || NOTE_KIND (insn
) != NOTE_INSN_CALL_ARG_LOCATION
)
4735 if (NEXT_INSN (last_call
) == insn
)
4737 SET_NEXT_INSN (PREV_INSN (insn
)) = NEXT_INSN (insn
);
4738 SET_PREV_INSN (NEXT_INSN (insn
)) = PREV_INSN (insn
);
4739 SET_PREV_INSN (insn
) = last_call
;
4740 SET_NEXT_INSN (insn
) = NEXT_INSN (last_call
);
4741 SET_PREV_INSN (NEXT_INSN (insn
)) = insn
;
4742 SET_NEXT_INSN (PREV_INSN (insn
)) = insn
;
4747 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4750 emit_nop_after (int cycles
, rtx after
)
4754 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4755 operation. We don't need the extra NOP since in this case, the hardware
4756 will automatically insert the required stall. */
4760 gcc_assert (cycles
< 10);
4762 insn
= emit_insn_after (gen_nop_count (GEN_INT (cycles
)), after
);
4763 PUT_MODE (insn
, TImode
);
4768 /* Determine whether INSN is a call that needs to have a return label
4772 returning_call_p (rtx_insn
*insn
)
4775 return (!SIBLING_CALL_P (insn
)
4776 && get_attr_type (insn
) != TYPE_CALLP
4777 && get_attr_type (insn
) != TYPE_SHADOW
);
4778 if (recog_memoized (insn
) < 0)
4780 if (get_attr_type (insn
) == TYPE_CALL
)
4785 /* Determine whether INSN's pattern can be converted to use callp. */
4787 can_use_callp (rtx_insn
*insn
)
4789 int icode
= recog_memoized (insn
);
4790 if (!TARGET_INSNS_64PLUS
4792 || GET_CODE (PATTERN (insn
)) == COND_EXEC
)
4795 return ((icode
== CODE_FOR_real_call
4796 || icode
== CODE_FOR_call_internal
4797 || icode
== CODE_FOR_call_value_internal
)
4798 && get_attr_dest_regfile (insn
) == DEST_REGFILE_ANY
);
4801 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4803 convert_to_callp (rtx_insn
*insn
)
4806 extract_insn (insn
);
4807 if (GET_CODE (PATTERN (insn
)) == SET
)
4809 rtx dest
= recog_data
.operand
[0];
4810 lab
= recog_data
.operand
[1];
4811 PATTERN (insn
) = gen_callp_value (dest
, lab
);
4812 INSN_CODE (insn
) = CODE_FOR_callp_value
;
4816 lab
= recog_data
.operand
[0];
4817 PATTERN (insn
) = gen_callp (lab
);
4818 INSN_CODE (insn
) = CODE_FOR_callp
;
4822 /* Scan forwards from INSN until we find the next insn that has mode TImode
4823 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4824 Return it if we find such an insn, NULL_RTX otherwise. */
4826 find_next_cycle_insn (rtx insn
, int clock
)
4829 if (GET_MODE (t
) == TImode
)
4830 t
= next_real_insn (t
);
4831 while (t
&& GET_MODE (t
) != TImode
)
4832 t
= next_real_insn (t
);
4834 if (t
&& insn_get_clock (t
) == clock
)
4839 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4840 around PAT. Return PAT either unchanged or modified in this
4843 duplicate_cond (rtx pat
, rtx cond_insn
)
4845 rtx cond_pat
= PATTERN (cond_insn
);
4846 if (GET_CODE (cond_pat
) == COND_EXEC
)
4847 pat
= gen_rtx_COND_EXEC (VOIDmode
, copy_rtx (COND_EXEC_TEST (cond_pat
)),
4852 /* Walk forward from INSN to find the last insn that issues in the same clock
4855 find_last_same_clock (rtx insn
)
4858 rtx_insn
*t
= next_real_insn (insn
);
4860 while (t
&& GET_MODE (t
) != TImode
)
4862 if (!DEBUG_INSN_P (t
) && recog_memoized (t
) >= 0)
4864 t
= next_real_insn (t
);
4869 /* For every call insn in the function, emit code to load the return
4870 address. For each call we create a return label and store it in
4871 CALL_LABELS. If are not scheduling, we emit the labels here,
4872 otherwise the caller will do it later.
4873 This function is called after final insn scheduling, but before creating
4874 the SEQUENCEs that represent execute packets. */
4877 reorg_split_calls (rtx
*call_labels
)
4879 unsigned int reservation_mask
= 0;
4880 rtx_insn
*insn
= get_insns ();
4881 gcc_assert (NOTE_P (insn
));
4882 insn
= next_real_insn (insn
);
4886 rtx_insn
*next
= next_real_insn (insn
);
4888 if (DEBUG_INSN_P (insn
))
4891 if (GET_MODE (insn
) == TImode
)
4892 reservation_mask
= 0;
4893 uid
= INSN_UID (insn
);
4894 if (c6x_flag_schedule_insns2
&& recog_memoized (insn
) >= 0)
4895 reservation_mask
|= 1 << INSN_INFO_ENTRY (uid
).reservation
;
4897 if (returning_call_p (insn
))
4899 rtx label
= gen_label_rtx ();
4900 rtx labelref
= gen_rtx_LABEL_REF (Pmode
, label
);
4901 rtx reg
= gen_rtx_REG (SImode
, RETURN_ADDR_REGNO
);
4903 LABEL_NUSES (label
) = 2;
4904 if (!c6x_flag_schedule_insns2
)
4906 if (can_use_callp (insn
))
4907 convert_to_callp (insn
);
4912 emit_label_after (label
, insn
);
4914 /* Bundle the call and its delay slots into a single
4915 SEQUENCE. While these do not issue in parallel
4916 we need to group them into a single EH region. */
4918 PUT_MODE (insn
, TImode
);
4919 if (TARGET_INSNS_64
)
4921 t
= gen_addkpc (reg
, labelref
, GEN_INT (4));
4922 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4924 PUT_MODE (slot
[1], TImode
);
4925 gen_one_bundle (slot
, 2, 0);
4929 slot
[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4931 PUT_MODE (slot
[3], TImode
);
4932 t
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4933 slot
[2] = emit_insn_after (duplicate_cond (t
, insn
),
4935 PUT_MODE (slot
[2], TImode
);
4936 t
= gen_movsi_high (reg
, labelref
);
4937 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4939 PUT_MODE (slot
[1], TImode
);
4940 gen_one_bundle (slot
, 4, 0);
4946 /* If we scheduled, we reserved the .S2 unit for one or two
4947 cycles after the call. Emit the insns in these slots,
4948 unless it's possible to create a CALLP insn.
4949 Note that this works because the dependencies ensure that
4950 no insn setting/using B3 is scheduled in the delay slots of
4952 int this_clock
= insn_get_clock (insn
);
4953 rtx last_same_clock
;
4956 call_labels
[INSN_UID (insn
)] = label
;
4958 last_same_clock
= find_last_same_clock (insn
);
4960 if (can_use_callp (insn
))
4962 /* Find the first insn of the next execute packet. If it
4963 is the shadow insn corresponding to this call, we may
4964 use a CALLP insn. */
4966 next_nonnote_nondebug_insn (last_same_clock
);
4969 && insn_get_clock (shadow
) == this_clock
+ 5)
4971 convert_to_callp (shadow
);
4972 insn_set_clock (shadow
, this_clock
);
4973 INSN_INFO_ENTRY (INSN_UID (shadow
)).reservation
4975 INSN_INFO_ENTRY (INSN_UID (shadow
)).unit_mask
4976 = INSN_INFO_ENTRY (INSN_UID (last_same_clock
)).unit_mask
;
4977 if (GET_MODE (insn
) == TImode
)
4979 rtx_insn
*new_cycle_first
= NEXT_INSN (insn
);
4980 while (!NONDEBUG_INSN_P (new_cycle_first
)
4981 || GET_CODE (PATTERN (new_cycle_first
)) == USE
4982 || GET_CODE (PATTERN (new_cycle_first
)) == CLOBBER
)
4983 new_cycle_first
= NEXT_INSN (new_cycle_first
);
4984 PUT_MODE (new_cycle_first
, TImode
);
4985 if (new_cycle_first
!= shadow
)
4986 PUT_MODE (shadow
, VOIDmode
);
4987 INSN_INFO_ENTRY (INSN_UID (new_cycle_first
)).ebb_start
4988 = INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
;
4991 PUT_MODE (shadow
, VOIDmode
);
4996 after1
= find_next_cycle_insn (last_same_clock
, this_clock
+ 1);
4997 if (after1
== NULL_RTX
)
4998 after1
= last_same_clock
;
5000 after1
= find_last_same_clock (after1
);
5001 if (TARGET_INSNS_64
)
5003 rtx x1
= gen_addkpc (reg
, labelref
, const0_rtx
);
5004 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5005 insn_set_clock (x1
, this_clock
+ 1);
5006 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5007 if (after1
== last_same_clock
)
5008 PUT_MODE (x1
, TImode
);
5010 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5011 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5016 rtx after2
= find_next_cycle_insn (after1
, this_clock
+ 2);
5017 if (after2
== NULL_RTX
)
5019 x2
= gen_movsi_lo_sum (reg
, reg
, labelref
);
5020 x2
= emit_insn_after (duplicate_cond (x2
, insn
), after2
);
5021 x1
= gen_movsi_high (reg
, labelref
);
5022 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
5023 insn_set_clock (x1
, this_clock
+ 1);
5024 insn_set_clock (x2
, this_clock
+ 2);
5025 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
5026 INSN_INFO_ENTRY (INSN_UID (x2
)).reservation
= RESERVATION_S2
;
5027 if (after1
== last_same_clock
)
5028 PUT_MODE (x1
, TImode
);
5030 INSN_INFO_ENTRY (INSN_UID (x1
)).unit_mask
5031 = INSN_INFO_ENTRY (INSN_UID (after1
)).unit_mask
;
5032 if (after1
== after2
)
5033 PUT_MODE (x2
, TImode
);
5035 INSN_INFO_ENTRY (INSN_UID (x2
)).unit_mask
5036 = INSN_INFO_ENTRY (INSN_UID (after2
)).unit_mask
;
5045 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
5046 insns as required for correctness. CALL_LABELS is the array that
5047 holds the return labels for call insns; we emit these here if
5048 scheduling was run earlier. */
5051 reorg_emit_nops (rtx
*call_labels
)
5056 int prev_clock
, earliest_bb_end
;
5057 int prev_implicit_nops
;
5058 rtx_insn
*insn
= get_insns ();
5060 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5061 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5062 clocks, we must insert a NOP.
5063 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5064 current basic block will finish. We must not allow the next basic block to
5065 begin before this cycle.
5066 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5067 a multi-cycle nop. The code is scheduled such that subsequent insns will
5068 show the cycle gap, but we needn't insert a real NOP instruction. */
5069 insn
= next_real_insn (insn
);
5070 last_call
= prev
= NULL
;
5072 earliest_bb_end
= 0;
5073 prev_implicit_nops
= 0;
5077 int this_clock
= -1;
5081 next
= next_real_insn (insn
);
5083 if (DEBUG_INSN_P (insn
)
5084 || GET_CODE (PATTERN (insn
)) == USE
5085 || GET_CODE (PATTERN (insn
)) == CLOBBER
5086 || shadow_or_blockage_p (insn
)
5087 || JUMP_TABLE_DATA_P (insn
))
5090 if (!c6x_flag_schedule_insns2
)
5091 /* No scheduling; ensure that no parallel issue happens. */
5092 PUT_MODE (insn
, TImode
);
5097 this_clock
= insn_get_clock (insn
);
5098 if (this_clock
!= prev_clock
)
5100 PUT_MODE (insn
, TImode
);
5104 cycles
= this_clock
- prev_clock
;
5106 cycles
-= prev_implicit_nops
;
5109 rtx nop
= emit_nop_after (cycles
- 1, prev
);
5110 insn_set_clock (nop
, prev_clock
+ prev_implicit_nops
+ 1);
5113 prev_clock
= this_clock
;
5116 && insn_get_clock (last_call
) + 6 <= this_clock
)
5118 emit_label_before (call_labels
[INSN_UID (last_call
)], insn
);
5119 last_call
= NULL_RTX
;
5121 prev_implicit_nops
= 0;
5125 /* Examine how many cycles the current insn takes, and adjust
5126 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5127 if (recog_memoized (insn
) >= 0
5128 /* If not scheduling, we've emitted NOPs after calls already. */
5129 && (c6x_flag_schedule_insns2
|| !returning_call_p (insn
)))
5131 max_cycles
= get_attr_cycles (insn
);
5132 if (get_attr_type (insn
) == TYPE_CALLP
)
5133 prev_implicit_nops
= 5;
5137 if (returning_call_p (insn
))
5140 if (c6x_flag_schedule_insns2
)
5142 gcc_assert (this_clock
>= 0);
5143 if (earliest_bb_end
< this_clock
+ max_cycles
)
5144 earliest_bb_end
= this_clock
+ max_cycles
;
5146 else if (max_cycles
> 1)
5147 emit_nop_after (max_cycles
- 1, insn
);
5153 if (c6x_flag_schedule_insns2
5154 && (next
== NULL_RTX
5155 || (GET_MODE (next
) == TImode
5156 && INSN_INFO_ENTRY (INSN_UID (next
)).ebb_start
))
5157 && earliest_bb_end
> 0)
5159 int cycles
= earliest_bb_end
- prev_clock
;
5162 prev
= emit_nop_after (cycles
- 1, prev
);
5163 insn_set_clock (prev
, prev_clock
+ prev_implicit_nops
+ 1);
5165 earliest_bb_end
= 0;
5170 emit_label_after (call_labels
[INSN_UID (last_call
)], prev
);
5171 last_call
= NULL_RTX
;
5177 /* If possible, split INSN, which we know is either a jump or a call, into a real
5178 insn and its shadow. */
5180 split_delayed_branch (rtx_insn
*insn
)
5182 int code
= recog_memoized (insn
);
5185 rtx pat
= PATTERN (insn
);
5187 if (GET_CODE (pat
) == COND_EXEC
)
5188 pat
= COND_EXEC_CODE (pat
);
5192 rtx src
= pat
, dest
= NULL_RTX
;
5194 if (GET_CODE (pat
) == SET
)
5196 dest
= SET_DEST (pat
);
5197 src
= SET_SRC (pat
);
5199 callee
= XEXP (XEXP (src
, 0), 0);
5200 if (SIBLING_CALL_P (insn
))
5203 newpat
= gen_indirect_sibcall_shadow ();
5205 newpat
= gen_sibcall_shadow (callee
);
5206 pat
= gen_real_jump (callee
);
5208 else if (dest
!= NULL_RTX
)
5211 newpat
= gen_indirect_call_value_shadow (dest
);
5213 newpat
= gen_call_value_shadow (dest
, callee
);
5214 pat
= gen_real_call (callee
);
5219 newpat
= gen_indirect_call_shadow ();
5221 newpat
= gen_call_shadow (callee
);
5222 pat
= gen_real_call (callee
);
5224 pat
= duplicate_cond (pat
, insn
);
5225 newpat
= duplicate_cond (newpat
, insn
);
5230 if (GET_CODE (pat
) == PARALLEL
5231 && GET_CODE (XVECEXP (pat
, 0, 0)) == RETURN
)
5233 newpat
= gen_return_shadow ();
5234 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5235 newpat
= duplicate_cond (newpat
, insn
);
5240 case CODE_FOR_br_true
:
5241 case CODE_FOR_br_false
:
5242 src
= SET_SRC (pat
);
5243 op
= XEXP (src
, code
== CODE_FOR_br_true
? 1 : 2);
5244 newpat
= gen_condjump_shadow (op
);
5245 pat
= gen_real_jump (op
);
5246 if (code
== CODE_FOR_br_true
)
5247 pat
= gen_rtx_COND_EXEC (VOIDmode
, XEXP (src
, 0), pat
);
5249 pat
= gen_rtx_COND_EXEC (VOIDmode
,
5250 reversed_comparison (XEXP (src
, 0),
5257 newpat
= gen_jump_shadow (op
);
5260 case CODE_FOR_indirect_jump
:
5261 newpat
= gen_indirect_jump_shadow ();
5264 case CODE_FOR_return_internal
:
5265 newpat
= gen_return_shadow ();
5266 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
5273 i1
= emit_insn_before (pat
, insn
);
5274 PATTERN (insn
) = newpat
;
5275 INSN_CODE (insn
) = -1;
5276 record_delay_slot_pair (i1
, insn
, 5, 0);
5279 /* If INSN is a multi-cycle insn that should be handled properly in
5280 modulo-scheduling, split it into a real insn and a shadow.
5281 Return true if we made a change.
5283 It is valid for us to fail to split an insn; the caller has to deal
5284 with the possibility. Currently we handle loads and most mpy2 and
5287 split_delayed_nonbranch (rtx_insn
*insn
)
5289 int code
= recog_memoized (insn
);
5290 enum attr_type type
;
5292 rtx newpat
, src
, dest
;
5293 rtx pat
= PATTERN (insn
);
5297 if (GET_CODE (pat
) == COND_EXEC
)
5298 pat
= COND_EXEC_CODE (pat
);
5300 if (code
< 0 || GET_CODE (pat
) != SET
)
5302 src
= SET_SRC (pat
);
5303 dest
= SET_DEST (pat
);
5307 type
= get_attr_type (insn
);
5309 && (type
== TYPE_LOAD
5310 || type
== TYPE_LOADN
))
5313 && (GET_CODE (src
) != ZERO_EXTEND
5314 || !MEM_P (XEXP (src
, 0))))
5317 if (GET_MODE_SIZE (GET_MODE (dest
)) > 4
5318 && (GET_MODE_SIZE (GET_MODE (dest
)) != 8 || !TARGET_LDDW
))
5321 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5323 newpat
= gen_load_shadow (SET_DEST (pat
));
5324 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_LOAD
);
5328 && (type
== TYPE_MPY2
5329 || type
== TYPE_MPY4
))
5331 /* We don't handle floating point multiplies yet. */
5332 if (GET_MODE (dest
) == SFmode
)
5335 rtv
= gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat
))),
5337 newpat
= gen_mult_shadow (SET_DEST (pat
));
5338 pat
= gen_rtx_UNSPEC (VOIDmode
, rtv
, UNSPEC_REAL_MULT
);
5339 delay
= type
== TYPE_MPY2
? 1 : 3;
5344 pat
= duplicate_cond (pat
, insn
);
5345 newpat
= duplicate_cond (newpat
, insn
);
5346 i1
= emit_insn_before (pat
, insn
);
5347 PATTERN (insn
) = newpat
;
5348 INSN_CODE (insn
) = -1;
5349 recog_memoized (insn
);
5350 recog_memoized (i1
);
5351 record_delay_slot_pair (i1
, insn
, delay
, 0);
5355 /* Examine if INSN is the result of splitting a load into a real load and a
5356 shadow, and if so, undo the transformation. */
5358 undo_split_delayed_nonbranch (rtx_insn
*insn
)
5360 int icode
= recog_memoized (insn
);
5361 enum attr_type type
;
5362 rtx prev_pat
, insn_pat
;
5367 type
= get_attr_type (insn
);
5368 if (type
!= TYPE_LOAD_SHADOW
&& type
!= TYPE_MULT_SHADOW
)
5370 prev
= PREV_INSN (insn
);
5371 prev_pat
= PATTERN (prev
);
5372 insn_pat
= PATTERN (insn
);
5373 if (GET_CODE (prev_pat
) == COND_EXEC
)
5375 prev_pat
= COND_EXEC_CODE (prev_pat
);
5376 insn_pat
= COND_EXEC_CODE (insn_pat
);
5379 gcc_assert (GET_CODE (prev_pat
) == UNSPEC
5380 && ((XINT (prev_pat
, 1) == UNSPEC_REAL_LOAD
5381 && type
== TYPE_LOAD_SHADOW
)
5382 || (XINT (prev_pat
, 1) == UNSPEC_REAL_MULT
5383 && type
== TYPE_MULT_SHADOW
)));
5384 insn_pat
= gen_rtx_SET (VOIDmode
, SET_DEST (insn_pat
),
5385 XVECEXP (prev_pat
, 0, 1));
5386 insn_pat
= duplicate_cond (insn_pat
, prev
);
5387 PATTERN (insn
) = insn_pat
;
5388 INSN_CODE (insn
) = -1;
5392 /* Split every insn (i.e. jumps and calls) which can have delay slots into
5393 two parts: the first one is scheduled normally and emits the instruction,
5394 while the second one is a shadow insn which shows the side effect taking
5395 place. The second one is placed in the right cycle by the scheduler, but
5396 not emitted as an assembly instruction. */
5399 split_delayed_insns (void)
5402 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5404 if (JUMP_P (insn
) || CALL_P (insn
))
5405 split_delayed_branch (insn
);
5409 /* For every insn that has an entry in the new_conditions vector, give it
5410 the appropriate predicate. */
5412 conditionalize_after_sched (void)
5416 FOR_EACH_BB_FN (bb
, cfun
)
5417 FOR_BB_INSNS (bb
, insn
)
5419 unsigned uid
= INSN_UID (insn
);
5421 if (!NONDEBUG_INSN_P (insn
) || uid
>= INSN_INFO_LENGTH
)
5423 cond
= INSN_INFO_ENTRY (uid
).new_cond
;
5424 if (cond
== NULL_RTX
)
5427 fprintf (dump_file
, "Conditionalizing insn %d\n", uid
);
5428 predicate_insn (insn
, cond
, true);
5432 /* A callback for the hw-doloop pass. This function examines INSN; if
5433 it is a loop_end pattern we recognize, return the reg rtx for the
5434 loop counter. Otherwise, return NULL_RTX. */
5437 hwloop_pattern_reg (rtx_insn
*insn
)
5441 if (!JUMP_P (insn
) || recog_memoized (insn
) != CODE_FOR_loop_end
)
5444 pat
= PATTERN (insn
);
5445 reg
= SET_DEST (XVECEXP (pat
, 0, 1));
5451 /* Return the number of cycles taken by BB, as computed by scheduling,
5452 including the latencies of all insns with delay slots. IGNORE is
5453 an insn we should ignore in the calculation, usually the final
5456 bb_earliest_end_cycle (basic_block bb
, rtx ignore
)
5461 FOR_BB_INSNS (bb
, insn
)
5463 int cycles
, this_clock
;
5465 if (LABEL_P (insn
) || NOTE_P (insn
) || DEBUG_INSN_P (insn
)
5466 || GET_CODE (PATTERN (insn
)) == USE
5467 || GET_CODE (PATTERN (insn
)) == CLOBBER
5471 this_clock
= insn_get_clock (insn
);
5472 cycles
= get_attr_cycles (insn
);
5474 if (earliest
< this_clock
+ cycles
)
5475 earliest
= this_clock
+ cycles
;
5480 /* Examine the insns in BB and remove all which have a uid greater or
5481 equal to MAX_UID. */
5483 filter_insns_above (basic_block bb
, int max_uid
)
5485 rtx_insn
*insn
, *next
;
5486 bool prev_ti
= false;
5487 int prev_cycle
= -1;
5489 FOR_BB_INSNS_SAFE (bb
, insn
, next
)
5492 if (!NONDEBUG_INSN_P (insn
))
5494 if (insn
== BB_END (bb
))
5496 this_cycle
= insn_get_clock (insn
);
5497 if (prev_ti
&& this_cycle
== prev_cycle
)
5499 gcc_assert (GET_MODE (insn
) != TImode
);
5500 PUT_MODE (insn
, TImode
);
5503 if (INSN_UID (insn
) >= max_uid
)
5505 if (GET_MODE (insn
) == TImode
)
5508 prev_cycle
= this_cycle
;
5515 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5518 c6x_asm_emit_except_personality (rtx personality
)
5520 fputs ("\t.personality\t", asm_out_file
);
5521 output_addr_const (asm_out_file
, personality
);
5522 fputc ('\n', asm_out_file
);
5525 /* Use a special assembly directive rather than a regular setion for
5526 unwind table data. */
5529 c6x_asm_init_sections (void)
5531 exception_section
= get_unnamed_section (0, output_section_asm_op
,
5535 /* A callback for the hw-doloop pass. Called to optimize LOOP in a
5536 machine-specific fashion; returns true if successful and false if
5537 the hwloop_fail function should be called. */
5540 hwloop_optimize (hwloop_info loop
)
5542 basic_block entry_bb
, bb
;
5543 rtx_insn
*seq
, *insn
, *prev
, *entry_after
, *end_packet
;
5544 rtx_insn
*head_insn
, *tail_insn
, *new_insns
, *last_insn
;
5546 int n_execute_packets
;
5549 int max_uid_before
, delayed_splits
;
5550 int i
, sp_ii
, min_ii
, max_ii
, max_parallel
, n_insns
, n_real_insns
, stages
;
5551 rtx_insn
**orig_vec
;
5553 rtx_insn
***insn_copies
;
5555 if (!c6x_flag_modulo_sched
|| !c6x_flag_schedule_insns2
5556 || !TARGET_INSNS_64PLUS
)
5559 if (loop
->iter_reg_used
|| loop
->depth
> 1)
5561 if (loop
->has_call
|| loop
->has_asm
)
5564 if (loop
->head
!= loop
->tail
)
5567 gcc_assert (loop
->incoming_dest
== loop
->head
);
5570 FOR_EACH_VEC_SAFE_ELT (loop
->incoming
, i
, entry_edge
)
5571 if (entry_edge
->flags
& EDGE_FALLTHRU
)
5573 if (entry_edge
== NULL
)
5576 reshuffle_units (loop
->head
);
5579 schedule_ebbs_init ();
5580 schedule_ebb (BB_HEAD (loop
->tail
), loop
->loop_end
, true);
5581 schedule_ebbs_finish ();
5585 loop_earliest
= bb_earliest_end_cycle (bb
, loop
->loop_end
) + 1;
5587 max_uid_before
= get_max_uid ();
5589 /* Split all multi-cycle operations, such as loads. For normal
5590 scheduling, we only do this for branches, as the generated code
5591 would otherwise not be interrupt-safe. When using sploop, it is
5592 safe and beneficial to split them. If any multi-cycle operations
5593 remain after splitting (because we don't handle them yet), we
5594 cannot pipeline the loop. */
5596 FOR_BB_INSNS (bb
, insn
)
5598 if (NONDEBUG_INSN_P (insn
))
5600 recog_memoized (insn
);
5601 if (split_delayed_nonbranch (insn
))
5603 else if (INSN_CODE (insn
) >= 0
5604 && get_attr_cycles (insn
) > 1)
5609 /* Count the number of insns as well as the number real insns, and save
5610 the original sequence of insns in case we must restore it later. */
5611 n_insns
= n_real_insns
= 0;
5612 FOR_BB_INSNS (bb
, insn
)
5615 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5618 orig_vec
= XNEWVEC (rtx_insn
*, n_insns
);
5620 FOR_BB_INSNS (bb
, insn
)
5621 orig_vec
[n_insns
++] = insn
;
5623 /* Count the unit reservations, and compute a minimum II from that
5625 count_unit_reqs (unit_reqs
, loop
->start_label
,
5626 PREV_INSN (loop
->loop_end
));
5627 merge_unit_reqs (unit_reqs
);
5629 min_ii
= res_mii (unit_reqs
);
5630 max_ii
= loop_earliest
< 15 ? loop_earliest
: 14;
5632 /* Make copies of the loop body, up to a maximum number of stages we want
5634 max_parallel
= loop_earliest
/ min_ii
+ 1;
5636 copies
= XCNEWVEC (rtx_insn
*, (max_parallel
+ 1) * n_real_insns
);
5637 insn_copies
= XNEWVEC (rtx_insn
**, max_parallel
+ 1);
5638 for (i
= 0; i
< max_parallel
+ 1; i
++)
5639 insn_copies
[i
] = copies
+ i
* n_real_insns
;
5641 head_insn
= next_nonnote_nondebug_insn (loop
->start_label
);
5642 tail_insn
= prev_real_insn (BB_END (bb
));
5645 FOR_BB_INSNS (bb
, insn
)
5646 if (NONDEBUG_INSN_P (insn
) && insn
!= loop
->loop_end
)
5647 insn_copies
[0][i
++] = insn
;
5649 sploop_max_uid_iter0
= get_max_uid ();
5651 /* Generate the copies of the loop body, and save them in the
5652 INSN_COPIES array. */
5654 for (i
= 0; i
< max_parallel
; i
++)
5657 rtx_insn
*this_iter
;
5659 this_iter
= duplicate_insn_chain (head_insn
, tail_insn
);
5663 rtx_insn
*prev_stage_insn
= insn_copies
[i
][j
];
5664 gcc_assert (INSN_CODE (this_iter
) == INSN_CODE (prev_stage_insn
));
5666 if (INSN_CODE (this_iter
) >= 0
5667 && (get_attr_type (this_iter
) == TYPE_LOAD_SHADOW
5668 || get_attr_type (this_iter
) == TYPE_MULT_SHADOW
))
5670 rtx_insn
*prev
= PREV_INSN (this_iter
);
5671 record_delay_slot_pair (prev
, this_iter
,
5672 get_attr_cycles (prev
) - 1, 0);
5675 record_delay_slot_pair (prev_stage_insn
, this_iter
, i
, 1);
5677 insn_copies
[i
+ 1][j
] = this_iter
;
5679 this_iter
= next_nonnote_nondebug_insn (this_iter
);
5682 new_insns
= get_insns ();
5683 last_insn
= insn_copies
[max_parallel
][n_real_insns
- 1];
5685 emit_insn_before (new_insns
, BB_END (bb
));
5687 /* Try to schedule the loop using varying initiation intervals,
5688 starting with the smallest possible and incrementing it
5690 for (sp_ii
= min_ii
; sp_ii
<= max_ii
; sp_ii
++)
5694 fprintf (dump_file
, "Trying to schedule for II %d\n", sp_ii
);
5696 df_clear_flags (DF_LR_RUN_DCE
);
5698 schedule_ebbs_init ();
5699 set_modulo_params (sp_ii
, max_parallel
, n_real_insns
,
5700 sploop_max_uid_iter0
);
5701 tmp_bb
= schedule_ebb (BB_HEAD (bb
), last_insn
, true);
5702 schedule_ebbs_finish ();
5707 fprintf (dump_file
, "Found schedule with II %d\n", sp_ii
);
5712 discard_delay_pairs_above (max_uid_before
);
5717 stages
= insn_get_clock (ss
.last_scheduled_iter0
) / sp_ii
+ 1;
5719 if (stages
== 1 && sp_ii
> 5)
5722 /* At this point, we know we've been successful, unless we find later that
5723 there are too many execute packets for the loop buffer to hold. */
5725 /* Assign reservations to the instructions in the loop. We must find
5726 the stage that contains the full loop kernel, and transfer the
5727 reservations of the instructions contained in it to the corresponding
5728 instructions from iteration 0, which are the only ones we'll keep. */
5729 assign_reservations (BB_HEAD (bb
), ss
.last_scheduled_insn
);
5730 SET_PREV_INSN (BB_END (bb
)) = ss
.last_scheduled_iter0
;
5731 SET_NEXT_INSN (ss
.last_scheduled_iter0
) = BB_END (bb
);
5732 filter_insns_above (bb
, sploop_max_uid_iter0
);
5734 for (i
= 0; i
< n_real_insns
; i
++)
5736 rtx insn
= insn_copies
[0][i
];
5737 int uid
= INSN_UID (insn
);
5738 int stage
= insn_uid_get_clock (uid
) / sp_ii
;
5740 if (stage
+ 1 < stages
)
5743 stage
= stages
- stage
- 1;
5744 copy_uid
= INSN_UID (insn_copies
[stage
][i
]);
5745 INSN_INFO_ENTRY (uid
).reservation
5746 = INSN_INFO_ENTRY (copy_uid
).reservation
;
5752 /* Compute the number of execute packets the pipelined form of the loop will
5755 n_execute_packets
= 0;
5756 for (insn
= loop
->start_label
;
5757 insn
!= loop
->loop_end
;
5758 insn
= NEXT_INSN (insn
))
5760 if (NONDEBUG_INSN_P (insn
) && GET_MODE (insn
) == TImode
5761 && !shadow_p (insn
))
5763 n_execute_packets
++;
5764 if (prev
&& insn_get_clock (prev
) + 1 != insn_get_clock (insn
))
5765 /* We need an extra NOP instruction. */
5766 n_execute_packets
++;
5772 end_packet
= ss
.last_scheduled_iter0
;
5773 while (!NONDEBUG_INSN_P (end_packet
) || GET_MODE (end_packet
) != TImode
)
5774 end_packet
= PREV_INSN (end_packet
);
5776 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5777 loop_earliest
= (stages
- 1) * sp_ii
;
5778 if (loop_earliest
> insn_get_clock (end_packet
))
5780 n_execute_packets
++;
5781 end_packet
= loop
->loop_end
;
5784 loop_earliest
= insn_get_clock (end_packet
);
5786 if (n_execute_packets
> 14)
5789 /* Generate the spkernel instruction, and place it at the appropriate
5791 PUT_MODE (end_packet
, VOIDmode
);
5793 insn
= emit_jump_insn_before (
5794 gen_spkernel (GEN_INT (stages
- 1),
5795 const0_rtx
, JUMP_LABEL (loop
->loop_end
)),
5797 JUMP_LABEL (insn
) = JUMP_LABEL (loop
->loop_end
);
5798 insn_set_clock (insn
, loop_earliest
);
5799 PUT_MODE (insn
, TImode
);
5800 INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
= false;
5801 delete_insn (loop
->loop_end
);
5803 /* Place the mvc and sploop instructions before the loop. */
5804 entry_bb
= entry_edge
->src
;
5808 insn
= emit_insn (gen_mvilc (loop
->iter_reg
));
5809 insn
= emit_insn (gen_sploop (GEN_INT (sp_ii
)));
5813 if (!single_succ_p (entry_bb
) || vec_safe_length (loop
->incoming
) > 1)
5819 emit_insn_before (seq
, BB_HEAD (loop
->head
));
5820 seq
= emit_label_before (gen_label_rtx (), seq
);
5822 new_bb
= create_basic_block (seq
, insn
, entry_bb
);
5823 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
5825 if (!(e
->flags
& EDGE_FALLTHRU
))
5826 redirect_edge_and_branch_force (e
, new_bb
);
5828 redirect_edge_succ (e
, new_bb
);
5830 make_edge (new_bb
, loop
->head
, 0);
5834 entry_after
= BB_END (entry_bb
);
5835 while (DEBUG_INSN_P (entry_after
)
5836 || (NOTE_P (entry_after
)
5837 && NOTE_KIND (entry_after
) != NOTE_INSN_BASIC_BLOCK
))
5838 entry_after
= PREV_INSN (entry_after
);
5839 emit_insn_after (seq
, entry_after
);
5844 /* Make sure we don't try to schedule this loop again. */
5845 for (ix
= 0; loop
->blocks
.iterate (ix
, &bb
); ix
++)
5846 bb
->flags
|= BB_DISABLE_SCHEDULE
;
5852 fprintf (dump_file
, "Unable to pipeline loop.\n");
5854 for (i
= 1; i
< n_insns
; i
++)
5856 SET_NEXT_INSN (orig_vec
[i
- 1]) = orig_vec
[i
];
5857 SET_PREV_INSN (orig_vec
[i
]) = orig_vec
[i
- 1];
5859 SET_PREV_INSN (orig_vec
[0]) = PREV_INSN (BB_HEAD (bb
));
5860 SET_NEXT_INSN (PREV_INSN (BB_HEAD (bb
))) = orig_vec
[0];
5861 SET_NEXT_INSN (orig_vec
[n_insns
- 1]) = NEXT_INSN (BB_END (bb
));
5862 SET_PREV_INSN (NEXT_INSN (BB_END (bb
))) = orig_vec
[n_insns
- 1];
5863 BB_HEAD (bb
) = orig_vec
[0];
5864 BB_END (bb
) = orig_vec
[n_insns
- 1];
5866 free_delay_pairs ();
5867 FOR_BB_INSNS (bb
, insn
)
5868 if (NONDEBUG_INSN_P (insn
))
5869 undo_split_delayed_nonbranch (insn
);
5873 /* A callback for the hw-doloop pass. Called when a loop we have discovered
5874 turns out not to be optimizable; we have to split the doloop_end pattern
5875 into a subtract and a test. */
5877 hwloop_fail (hwloop_info loop
)
5879 rtx insn
, test
, testreg
;
5882 fprintf (dump_file
, "splitting doloop insn %d\n",
5883 INSN_UID (loop
->loop_end
));
5884 insn
= gen_addsi3 (loop
->iter_reg
, loop
->iter_reg
, constm1_rtx
);
5885 /* See if we can emit the add at the head of the loop rather than at the
5887 if (loop
->head
== NULL
5888 || loop
->iter_reg_used_outside
5889 || loop
->iter_reg_used
5890 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REGNO (loop
->iter_reg
))
5891 || loop
->incoming_dest
!= loop
->head
5892 || EDGE_COUNT (loop
->head
->preds
) != 2)
5893 emit_insn_before (insn
, loop
->loop_end
);
5896 rtx_insn
*t
= loop
->start_label
;
5897 while (!NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_BASIC_BLOCK
)
5899 emit_insn_after (insn
, t
);
5902 testreg
= SET_DEST (XVECEXP (PATTERN (loop
->loop_end
), 0, 2));
5903 if (GET_CODE (testreg
) == SCRATCH
)
5904 testreg
= loop
->iter_reg
;
5906 emit_insn_before (gen_movsi (testreg
, loop
->iter_reg
), loop
->loop_end
);
5908 test
= gen_rtx_NE (VOIDmode
, testreg
, const0_rtx
);
5909 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
, testreg
, const0_rtx
,
5913 JUMP_LABEL (insn
) = loop
->start_label
;
5914 LABEL_NUSES (loop
->start_label
)++;
5915 delete_insn (loop
->loop_end
);
5918 static struct hw_doloop_hooks c6x_doloop_hooks
=
5925 /* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5926 doloop_end patterns where such optimizations are impossible. */
5931 reorg_loops (true, &c6x_doloop_hooks
);
5934 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5935 into a sequence that loads the return register and performs the call,
5936 and emit the return label.
5937 If scheduling after reload is requested, it happens here. */
5944 bool do_selsched
= (c6x_flag_schedule_insns2
&& flag_selective_scheduling2
5945 && !maybe_skip_selective_scheduling ());
5947 /* We are freeing block_for_insn in the toplev to keep compatibility
5948 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5949 compute_bb_for_insn ();
5951 df_clear_flags (DF_LR_RUN_DCE
);
5952 df_note_add_problem ();
5954 /* If optimizing, we'll have split before scheduling. */
5960 if (c6x_flag_schedule_insns2
)
5962 int sz
= get_max_uid () * 3 / 2 + 1;
5964 insn_info
.create (sz
);
5967 /* Make sure the real-jump insns we create are not deleted. When modulo-
5968 scheduling, situations where a reg is only stored in a loop can also
5969 cause dead code when doing the initial unrolling. */
5970 sched_no_dce
= true;
5974 if (c6x_flag_schedule_insns2
)
5976 split_delayed_insns ();
5977 timevar_push (TV_SCHED2
);
5979 run_selective_scheduling ();
5982 conditionalize_after_sched ();
5983 timevar_pop (TV_SCHED2
);
5985 free_delay_pairs ();
5987 sched_no_dce
= false;
5989 call_labels
= XCNEWVEC (rtx
, get_max_uid () + 1);
5991 reorg_split_calls (call_labels
);
5993 if (c6x_flag_schedule_insns2
)
5995 FOR_EACH_BB_FN (bb
, cfun
)
5996 if ((bb
->flags
& BB_DISABLE_SCHEDULE
) == 0)
5997 assign_reservations (BB_HEAD (bb
), BB_END (bb
));
6000 if (c6x_flag_var_tracking
)
6002 timevar_push (TV_VAR_TRACKING
);
6003 variable_tracking_main ();
6004 timevar_pop (TV_VAR_TRACKING
);
6007 reorg_emit_nops (call_labels
);
6009 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
6010 if (c6x_flag_schedule_insns2
)
6012 free_delay_pairs ();
6016 df_finish_pass (false);
6019 /* Called when a function has been assembled. It should perform all the
6020 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
6022 We free the reservation (and other scheduling) information here now that
6023 all insns have been output. */
6025 c6x_function_end (FILE *file
, const char *fname
)
6027 c6x_output_fn_unwind (file
);
6029 insn_info
.release ();
6031 if (!flag_inhibit_size_directive
)
6032 ASM_OUTPUT_MEASURED_SIZE (file
, fname
);
6035 /* Determine whether X is a shift with code CODE and an integer amount
6038 shift_p (rtx x
, enum rtx_code code
, int amount
)
6040 return (GET_CODE (x
) == code
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
6041 && INTVAL (XEXP (x
, 1)) == amount
);
6044 /* Compute a (partial) cost for rtx X. Return true if the complete
6045 cost has been computed, and false if subexpressions should be
6046 scanned. In either case, *TOTAL contains the cost result. */
6049 c6x_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
6052 int cost2
= COSTS_N_INSNS (1);
6058 if (outer_code
== SET
|| outer_code
== PLUS
)
6059 *total
= satisfies_constraint_IsB (x
) ? 0 : cost2
;
6060 else if (outer_code
== AND
|| outer_code
== IOR
|| outer_code
== XOR
6061 || outer_code
== MINUS
)
6062 *total
= satisfies_constraint_Is5 (x
) ? 0 : cost2
;
6063 else if (GET_RTX_CLASS (outer_code
) == RTX_COMPARE
6064 || GET_RTX_CLASS (outer_code
) == RTX_COMM_COMPARE
)
6065 *total
= satisfies_constraint_Iu4 (x
) ? 0 : cost2
;
6066 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
6067 || outer_code
== LSHIFTRT
)
6068 *total
= satisfies_constraint_Iu5 (x
) ? 0 : cost2
;
6077 *total
= COSTS_N_INSNS (2);
6081 /* Recognize a mult_highpart operation. */
6082 if ((GET_MODE (x
) == HImode
|| GET_MODE (x
) == SImode
)
6083 && GET_CODE (XEXP (x
, 0)) == LSHIFTRT
6084 && GET_MODE (XEXP (x
, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x
))
6085 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
6086 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
6087 && INTVAL (XEXP (XEXP (x
, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x
)))
6089 rtx mul
= XEXP (XEXP (x
, 0), 0);
6090 rtx op0
= XEXP (mul
, 0);
6091 rtx op1
= XEXP (mul
, 1);
6092 enum rtx_code code0
= GET_CODE (op0
);
6093 enum rtx_code code1
= GET_CODE (op1
);
6096 && (code0
== SIGN_EXTEND
|| code0
== ZERO_EXTEND
))
6097 || (GET_MODE (x
) == HImode
6098 && code0
== ZERO_EXTEND
&& code1
== SIGN_EXTEND
))
6100 if (GET_MODE (x
) == HImode
)
6101 *total
= COSTS_N_INSNS (2);
6103 *total
= COSTS_N_INSNS (12);
6104 *total
+= rtx_cost (XEXP (op0
, 0), code0
, 0, speed
);
6105 *total
+= rtx_cost (XEXP (op1
, 0), code1
, 0, speed
);
6114 if (GET_MODE (x
) == DImode
)
6115 *total
= COSTS_N_INSNS (CONSTANT_P (XEXP (x
, 1)) ? 4 : 15);
6117 *total
= COSTS_N_INSNS (1);
6122 *total
= COSTS_N_INSNS (1);
6123 op0
= code
== PLUS
? XEXP (x
, 0) : XEXP (x
, 1);
6124 op1
= code
== PLUS
? XEXP (x
, 1) : XEXP (x
, 0);
6125 if (GET_MODE_SIZE (GET_MODE (x
)) <= UNITS_PER_WORD
6126 && INTEGRAL_MODE_P (GET_MODE (x
))
6127 && GET_CODE (op0
) == MULT
6128 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
6129 && (INTVAL (XEXP (op0
, 1)) == 2
6130 || INTVAL (XEXP (op0
, 1)) == 4
6131 || (code
== PLUS
&& INTVAL (XEXP (op0
, 1)) == 8)))
6133 *total
+= rtx_cost (XEXP (op0
, 0), ASHIFT
, 0, speed
);
6134 *total
+= rtx_cost (op1
, (enum rtx_code
) code
, 1, speed
);
6142 if (GET_MODE (x
) == DFmode
)
6145 *total
= COSTS_N_INSNS (speed
? 10 : 1);
6147 *total
= COSTS_N_INSNS (speed
? 200 : 4);
6149 else if (GET_MODE (x
) == SFmode
)
6152 *total
= COSTS_N_INSNS (speed
? 4 : 1);
6154 *total
= COSTS_N_INSNS (speed
? 100 : 4);
6156 else if (GET_MODE (x
) == DImode
)
6159 && GET_CODE (op0
) == GET_CODE (op1
)
6160 && (GET_CODE (op0
) == ZERO_EXTEND
6161 || GET_CODE (op0
) == SIGN_EXTEND
))
6163 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6164 op0
= XEXP (op0
, 0);
6165 op1
= XEXP (op1
, 0);
6168 /* Maybe improve this laster. */
6169 *total
= COSTS_N_INSNS (20);
6171 else if (GET_MODE (x
) == SImode
)
6173 if (((GET_CODE (op0
) == ZERO_EXTEND
6174 || GET_CODE (op0
) == SIGN_EXTEND
6175 || shift_p (op0
, LSHIFTRT
, 16))
6176 && (GET_CODE (op1
) == SIGN_EXTEND
6177 || GET_CODE (op1
) == ZERO_EXTEND
6178 || scst5_operand (op1
, SImode
)
6179 || shift_p (op1
, ASHIFTRT
, 16)
6180 || shift_p (op1
, LSHIFTRT
, 16)))
6181 || (shift_p (op0
, ASHIFTRT
, 16)
6182 && (GET_CODE (op1
) == SIGN_EXTEND
6183 || shift_p (op1
, ASHIFTRT
, 16))))
6185 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6186 op0
= XEXP (op0
, 0);
6187 if (scst5_operand (op1
, SImode
))
6190 op1
= XEXP (op1
, 0);
6193 *total
= COSTS_N_INSNS (1);
6194 else if (TARGET_MPY32
)
6195 *total
= COSTS_N_INSNS (4);
6197 *total
= COSTS_N_INSNS (6);
6199 else if (GET_MODE (x
) == HImode
)
6200 *total
= COSTS_N_INSNS (speed
? 2 : 1);
6202 if (GET_CODE (op0
) != REG
6203 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
6204 *total
+= rtx_cost (op0
, MULT
, 0, speed
);
6205 if (op1
&& GET_CODE (op1
) != REG
6206 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
6207 *total
+= rtx_cost (op1
, MULT
, 1, speed
);
6212 /* This is a bit random; assuming on average there'll be 16 leading
6213 zeros. FIXME: estimate better for constant dividends. */
6214 *total
= COSTS_N_INSNS (6 + 3 * 16);
6218 /* Recognize the cmp_and/ior patterns. */
6220 if ((GET_CODE (op0
) == EQ
|| GET_CODE (op0
) == NE
)
6221 && REG_P (XEXP (op0
, 0))
6222 && XEXP (op0
, 1) == const0_rtx
6223 && rtx_equal_p (XEXP (x
, 1), XEXP (op0
, 0)))
6225 *total
= rtx_cost (XEXP (x
, 1), (enum rtx_code
) outer_code
,
6236 /* Implements target hook vector_mode_supported_p. */
6239 c6x_vector_mode_supported_p (enum machine_mode mode
)
6254 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6255 static enum machine_mode
6256 c6x_preferred_simd_mode (enum machine_mode mode
)
6270 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6273 c6x_scalar_mode_supported_p (enum machine_mode mode
)
6275 if (ALL_FIXED_POINT_MODE_P (mode
)
6276 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
6279 return default_scalar_mode_supported_p (mode
);
6282 /* Output a reference from a function exception table to the type_info
6283 object X. Output these via a special assembly directive. */
6286 c6x_output_ttype (rtx x
)
6288 /* Use special relocations for symbol references. */
6289 if (GET_CODE (x
) != CONST_INT
)
6290 fputs ("\t.ehtype\t", asm_out_file
);
6292 fputs ("\t.word\t", asm_out_file
);
6293 output_addr_const (asm_out_file
, x
);
6294 fputc ('\n', asm_out_file
);
6299 /* Modify the return address of the current function. */
6302 c6x_set_return_address (rtx source
, rtx scratch
)
6304 struct c6x_frame frame
;
6306 HOST_WIDE_INT offset
;
6308 c6x_compute_frame_layout (&frame
);
6309 if (! c6x_save_reg (RETURN_ADDR_REGNO
))
6310 emit_move_insn (gen_rtx_REG (Pmode
, RETURN_ADDR_REGNO
), source
);
6314 if (frame_pointer_needed
)
6316 addr
= hard_frame_pointer_rtx
;
6317 offset
= frame
.b3_offset
;
6321 addr
= stack_pointer_rtx
;
6322 offset
= frame
.to_allocate
- frame
.b3_offset
;
6325 /* TODO: Use base+offset loads where possible. */
6328 HOST_WIDE_INT low
= trunc_int_for_mode (offset
, HImode
);
6330 emit_insn (gen_movsi_high (scratch
, GEN_INT (low
)));
6332 emit_insn (gen_movsi_lo_sum (scratch
, scratch
, GEN_INT(offset
)));
6333 emit_insn (gen_addsi3 (scratch
, addr
, scratch
));
6337 emit_move_insn (gen_frame_mem (Pmode
, addr
), source
);
6341 /* We save pairs of registers using a DImode store. Describe the component
6342 registers for DWARF generation code. */
6345 c6x_dwarf_register_span (rtx rtl
)
6348 unsigned real_regno
;
6353 regno
= REGNO (rtl
);
6354 nregs
= HARD_REGNO_NREGS (regno
, GET_MODE (rtl
));
6358 p
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc(nregs
));
6359 for (i
= 0; i
< nregs
; i
++)
6361 if (TARGET_BIG_ENDIAN
)
6362 real_regno
= regno
+ nregs
- (i
+ 1);
6364 real_regno
= regno
+ i
;
6366 XVECEXP (p
, 0, i
) = gen_rtx_REG (SImode
, real_regno
);
6372 /* Codes for all the C6X builtins. */
6407 static GTY(()) tree c6x_builtin_decls
[C6X_BUILTIN_MAX
];
6409 /* Return the C6X builtin for CODE. */
6411 c6x_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
6413 if (code
>= C6X_BUILTIN_MAX
)
6414 return error_mark_node
;
6416 return c6x_builtin_decls
[code
];
6419 #define def_builtin(NAME, TYPE, CODE) \
6422 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6424 c6x_builtin_decls[CODE] = bdecl; \
6427 /* Set up all builtin functions for this target. */
6429 c6x_init_builtins (void)
6431 tree V4QI_type_node
= build_vector_type (unsigned_intQI_type_node
, 4);
6432 tree V2HI_type_node
= build_vector_type (intHI_type_node
, 2);
6433 tree V2SI_type_node
= build_vector_type (intSI_type_node
, 2);
6435 = build_function_type_list (integer_type_node
, integer_type_node
,
6437 tree int_ftype_int_int
6438 = build_function_type_list (integer_type_node
, integer_type_node
,
6439 integer_type_node
, NULL_TREE
);
6440 tree v2hi_ftype_v2hi
6441 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
6442 tree v4qi_ftype_v4qi_v4qi
6443 = build_function_type_list (V4QI_type_node
, V4QI_type_node
,
6444 V4QI_type_node
, NULL_TREE
);
6445 tree v2hi_ftype_v2hi_v2hi
6446 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
6447 V2HI_type_node
, NULL_TREE
);
6448 tree v2si_ftype_v2hi_v2hi
6449 = build_function_type_list (V2SI_type_node
, V2HI_type_node
,
6450 V2HI_type_node
, NULL_TREE
);
6452 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int
,
6454 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int
,
6456 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi
,
6458 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi
,
6460 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi
,
6462 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi
,
6464 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi
,
6466 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi
,
6468 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi
,
6470 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi
,
6471 C6X_BUILTIN_SADDU4
);
6472 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi
,
6475 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int
,
6477 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int
,
6479 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int
,
6480 C6X_BUILTIN_SMPYHL
);
6481 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int
,
6482 C6X_BUILTIN_SMPYLH
);
6484 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int
,
6486 def_builtin ("__builtin_c6x_subc", int_ftype_int_int
,
6489 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi
,
6491 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi
,
6494 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int
,
6496 def_builtin ("__builtin_c6x_extr", int_ftype_int_int
,
6498 def_builtin ("__builtin_c6x_extru", int_ftype_int_int
,
6501 def_builtin ("__builtin_c6x_abs", int_ftype_int
, C6X_BUILTIN_ABS
);
6502 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi
, C6X_BUILTIN_ABS2
);
6506 struct builtin_description
6508 const enum insn_code icode
;
6509 const char *const name
;
6510 const enum c6x_builtins code
;
6513 static const struct builtin_description bdesc_2arg
[] =
6515 { CODE_FOR_saddsi3
, "__builtin_c6x_sadd", C6X_BUILTIN_SADD
},
6516 { CODE_FOR_ssubsi3
, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB
},
6517 { CODE_FOR_addv2hi3
, "__builtin_c6x_add2", C6X_BUILTIN_ADD2
},
6518 { CODE_FOR_subv2hi3
, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2
},
6519 { CODE_FOR_addv4qi3
, "__builtin_c6x_add4", C6X_BUILTIN_ADD4
},
6520 { CODE_FOR_subv4qi3
, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4
},
6521 { CODE_FOR_ss_addv2hi3
, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2
},
6522 { CODE_FOR_ss_subv2hi3
, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2
},
6523 { CODE_FOR_us_addv4qi3
, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4
},
6525 { CODE_FOR_subcsi3
, "__builtin_c6x_subc", C6X_BUILTIN_SUBC
},
6526 { CODE_FOR_ss_ashlsi3
, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL
},
6528 { CODE_FOR_avgv2hi3
, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2
},
6529 { CODE_FOR_uavgv4qi3
, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4
},
6531 { CODE_FOR_mulhqsq3
, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY
},
6532 { CODE_FOR_mulhqsq3_hh
, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH
},
6533 { CODE_FOR_mulhqsq3_lh
, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH
},
6534 { CODE_FOR_mulhqsq3_hl
, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL
},
6536 { CODE_FOR_mulv2hqv2sq3
, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2
},
6538 { CODE_FOR_clrr
, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR
},
6539 { CODE_FOR_extr
, "__builtin_c6x_extr", C6X_BUILTIN_EXTR
},
6540 { CODE_FOR_extru
, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU
}
6543 static const struct builtin_description bdesc_1arg
[] =
6545 { CODE_FOR_ssabssi2
, "__builtin_c6x_abs", C6X_BUILTIN_ABS
},
6546 { CODE_FOR_ssabsv2hi2
, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2
}
6549 /* Errors in the source file can cause expand_expr to return const0_rtx
6550 where we expect a vector. To avoid crashing, use one of the vector
6551 clear instructions. */
6553 safe_vector_operand (rtx x
, enum machine_mode mode
)
6555 if (x
!= const0_rtx
)
6557 x
= gen_reg_rtx (SImode
);
6559 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
6560 return gen_lowpart (mode
, x
);
6563 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6564 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6567 c6x_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
6570 int offs
= match_op
? 1 : 0;
6572 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6573 tree arg1
= CALL_EXPR_ARG (exp
, 1);
6574 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6575 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6576 enum machine_mode op0mode
= GET_MODE (op0
);
6577 enum machine_mode op1mode
= GET_MODE (op1
);
6578 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6579 enum machine_mode mode0
= insn_data
[icode
].operand
[1 + offs
].mode
;
6580 enum machine_mode mode1
= insn_data
[icode
].operand
[2 + offs
].mode
;
6583 if (VECTOR_MODE_P (mode0
))
6584 op0
= safe_vector_operand (op0
, mode0
);
6585 if (VECTOR_MODE_P (mode1
))
6586 op1
= safe_vector_operand (op1
, mode1
);
6589 || GET_MODE (target
) != tmode
6590 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6592 if (tmode
== SQmode
|| tmode
== V2SQmode
)
6594 ret
= gen_reg_rtx (tmode
== SQmode
? SImode
: V2SImode
);
6595 target
= gen_lowpart (tmode
, ret
);
6598 target
= gen_reg_rtx (tmode
);
6601 if ((op0mode
== V2HImode
|| op0mode
== SImode
|| op0mode
== VOIDmode
)
6602 && (mode0
== V2HQmode
|| mode0
== HQmode
|| mode0
== SQmode
))
6605 op0
= gen_lowpart (mode0
, op0
);
6607 if ((op1mode
== V2HImode
|| op1mode
== SImode
|| op1mode
== VOIDmode
)
6608 && (mode1
== V2HQmode
|| mode1
== HQmode
|| mode1
== SQmode
))
6611 op1
= gen_lowpart (mode1
, op1
);
6613 /* In case the insn wants input operands in modes different from
6614 the result, abort. */
6615 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
6616 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
6618 if (! (*insn_data
[icode
].operand
[1 + offs
].predicate
) (op0
, mode0
))
6619 op0
= copy_to_mode_reg (mode0
, op0
);
6620 if (! (*insn_data
[icode
].operand
[2 + offs
].predicate
) (op1
, mode1
))
6621 op1
= copy_to_mode_reg (mode1
, op1
);
6624 pat
= GEN_FCN (icode
) (target
, target
, op0
, op1
);
6626 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
6636 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
6639 c6x_expand_unop_builtin (enum insn_code icode
, tree exp
,
6643 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6644 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
6645 enum machine_mode op0mode
= GET_MODE (op0
);
6646 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6647 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6650 || GET_MODE (target
) != tmode
6651 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6652 target
= gen_reg_rtx (tmode
);
6654 if (VECTOR_MODE_P (mode0
))
6655 op0
= safe_vector_operand (op0
, mode0
);
6657 if (op0mode
== SImode
&& mode0
== HImode
)
6660 op0
= gen_lowpart (HImode
, op0
);
6662 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
6664 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6665 op0
= copy_to_mode_reg (mode0
, op0
);
6667 pat
= GEN_FCN (icode
) (target
, op0
);
6674 /* Expand an expression EXP that calls a built-in function,
6675 with result going to TARGET if that's convenient
6676 (and in mode MODE if that's convenient).
6677 SUBTARGET may be used as the target for computing one of EXP's operands.
6678 IGNORE is nonzero if the value is to be ignored. */
6681 c6x_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
6682 rtx subtarget ATTRIBUTE_UNUSED
,
6683 enum machine_mode mode ATTRIBUTE_UNUSED
,
6684 int ignore ATTRIBUTE_UNUSED
)
6687 const struct builtin_description
*d
;
6688 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
6689 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
6691 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6692 if (d
->code
== fcode
)
6693 return c6x_expand_binop_builtin (d
->icode
, exp
, target
,
6694 fcode
== C6X_BUILTIN_CLRR
);
6696 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6697 if (d
->code
== fcode
)
6698 return c6x_expand_unop_builtin (d
->icode
, exp
, target
);
6703 /* Target unwind frame info is generated from dwarf CFI directives, so
6704 always output dwarf2 unwind info. */
6706 static enum unwind_info_type
6707 c6x_debug_unwind_info (void)
6709 if (flag_unwind_tables
|| flag_exceptions
)
6712 return default_debug_unwind_info ();
6715 /* Target Structure. */
6717 /* Initialize the GCC target structure. */
6718 #undef TARGET_FUNCTION_ARG
6719 #define TARGET_FUNCTION_ARG c6x_function_arg
6720 #undef TARGET_FUNCTION_ARG_ADVANCE
6721 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6722 #undef TARGET_FUNCTION_ARG_BOUNDARY
6723 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6724 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6725 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6726 c6x_function_arg_round_boundary
6727 #undef TARGET_FUNCTION_VALUE_REGNO_P
6728 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6729 #undef TARGET_FUNCTION_VALUE
6730 #define TARGET_FUNCTION_VALUE c6x_function_value
6731 #undef TARGET_LIBCALL_VALUE
6732 #define TARGET_LIBCALL_VALUE c6x_libcall_value
6733 #undef TARGET_RETURN_IN_MEMORY
6734 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6735 #undef TARGET_RETURN_IN_MSB
6736 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
6737 #undef TARGET_PASS_BY_REFERENCE
6738 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6739 #undef TARGET_CALLEE_COPIES
6740 #define TARGET_CALLEE_COPIES c6x_callee_copies
6741 #undef TARGET_STRUCT_VALUE_RTX
6742 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6743 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6744 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6746 #undef TARGET_ASM_OUTPUT_MI_THUNK
6747 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6748 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6749 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6751 #undef TARGET_BUILD_BUILTIN_VA_LIST
6752 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6754 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6755 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6756 #undef TARGET_TRAMPOLINE_INIT
6757 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6759 #undef TARGET_LEGITIMATE_CONSTANT_P
6760 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6761 #undef TARGET_LEGITIMATE_ADDRESS_P
6762 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6764 #undef TARGET_IN_SMALL_DATA_P
6765 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6766 #undef TARGET_ASM_SELECT_RTX_SECTION
6767 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6768 #undef TARGET_ASM_SELECT_SECTION
6769 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6770 #undef TARGET_ASM_UNIQUE_SECTION
6771 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6772 #undef TARGET_SECTION_TYPE_FLAGS
6773 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6774 #undef TARGET_HAVE_SRODATA_SECTION
6775 #define TARGET_HAVE_SRODATA_SECTION true
6776 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6777 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6779 #undef TARGET_OPTION_OVERRIDE
6780 #define TARGET_OPTION_OVERRIDE c6x_option_override
6781 #undef TARGET_CONDITIONAL_REGISTER_USAGE
6782 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6784 #undef TARGET_INIT_LIBFUNCS
6785 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6786 #undef TARGET_LIBFUNC_GNU_PREFIX
6787 #define TARGET_LIBFUNC_GNU_PREFIX true
6789 #undef TARGET_SCALAR_MODE_SUPPORTED_P
6790 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6791 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6792 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6793 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6794 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6796 #undef TARGET_RTX_COSTS
6797 #define TARGET_RTX_COSTS c6x_rtx_costs
6799 #undef TARGET_SCHED_INIT
6800 #define TARGET_SCHED_INIT c6x_sched_init
6801 #undef TARGET_SCHED_SET_SCHED_FLAGS
6802 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6803 #undef TARGET_SCHED_ADJUST_COST
6804 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6805 #undef TARGET_SCHED_ISSUE_RATE
6806 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6807 #undef TARGET_SCHED_VARIABLE_ISSUE
6808 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6809 #undef TARGET_SCHED_REORDER
6810 #define TARGET_SCHED_REORDER c6x_sched_reorder
6811 #undef TARGET_SCHED_REORDER2
6812 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6813 #undef TARGET_SCHED_DFA_NEW_CYCLE
6814 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6815 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6816 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6817 #undef TARGET_SCHED_EXPOSED_PIPELINE
6818 #define TARGET_SCHED_EXPOSED_PIPELINE true
6820 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6821 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6822 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
6823 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6824 #undef TARGET_SCHED_SET_SCHED_CONTEXT
6825 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6826 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6827 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6828 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
6829 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6831 #undef TARGET_CAN_ELIMINATE
6832 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
6834 #undef TARGET_PREFERRED_RENAME_CLASS
6835 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6837 #undef TARGET_MACHINE_DEPENDENT_REORG
6838 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6840 #undef TARGET_ASM_FILE_START
6841 #define TARGET_ASM_FILE_START c6x_file_start
6843 #undef TARGET_PRINT_OPERAND
6844 #define TARGET_PRINT_OPERAND c6x_print_operand
6845 #undef TARGET_PRINT_OPERAND_ADDRESS
6846 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6847 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6848 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6850 /* C6x unwinding tables use a different format for the typeinfo tables. */
6851 #undef TARGET_ASM_TTYPE
6852 #define TARGET_ASM_TTYPE c6x_output_ttype
6854 /* The C6x ABI follows the ARM EABI exception handling rules. */
6855 #undef TARGET_ARM_EABI_UNWINDER
6856 #define TARGET_ARM_EABI_UNWINDER true
6858 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6859 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6861 #undef TARGET_ASM_INIT_SECTIONS
6862 #define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6864 #undef TARGET_DEBUG_UNWIND_INFO
6865 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6867 #undef TARGET_DWARF_REGISTER_SPAN
6868 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6870 #undef TARGET_INIT_BUILTINS
6871 #define TARGET_INIT_BUILTINS c6x_init_builtins
6872 #undef TARGET_EXPAND_BUILTIN
6873 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6874 #undef TARGET_BUILTIN_DECL
6875 #define TARGET_BUILTIN_DECL c6x_builtin_decl
6877 struct gcc_target targetm
= TARGET_INITIALIZER
;