1 /* Target Code for TI C6X
2 Copyright (C) 2010, 2011 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 "insn-flags.h"
30 #include "insn-attr.h"
31 #include "insn-codes.h"
37 #include "sched-int.h"
41 #include "tm-constrs.h"
43 #include "integrate.h"
44 #include "diagnostic-core.h"
46 #include "cfglayout.h"
47 #include "langhooks.h"
49 #include "target-def.h"
50 #include "sel-sched.h"
54 /* Table of supported architecture variants. */
58 enum c6x_cpu_type type
;
59 unsigned short features
;
62 /* A list of all ISAs, mapping each one to a representative device.
63 Used for -march selection. */
64 static const c6x_arch_table all_isas
[] =
66 #define C6X_ISA(NAME,DEVICE,FLAGS) \
67 { NAME, DEVICE, FLAGS },
68 #include "c6x-isas.def"
70 { NULL
, C6X_CPU_C62X
, 0 }
73 /* This is the parsed result of the "-march=" option, if given. */
74 enum c6x_cpu_type c6x_arch
= C6X_DEFAULT_ARCH
;
76 /* A mask of insn types that are allowed by the architecture selected by
78 unsigned long c6x_insn_mask
= C6X_DEFAULT_INSN_MASK
;
80 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
82 static rtx c6x_current_insn
= NULL_RTX
;
84 /* A decl we build to access __c6xabi_DSBT_base. */
85 static GTY(()) tree dsbt_decl
;
87 /* Determines whether we run our final scheduling pass or not. We always
88 avoid the normal second scheduling pass. */
89 static int c6x_flag_schedule_insns2
;
91 /* Determines whether we run variable tracking in machine dependent
93 static int c6x_flag_var_tracking
;
95 /* Determines whether we use modulo scheduling. */
96 static int c6x_flag_modulo_sched
;
98 /* Record the state of flag_pic before we set it to 1 for DSBT. */
99 int c6x_initial_flag_pic
;
103 /* We record the clock cycle for every insn during scheduling. */
105 /* After scheduling, we run assign_reservations to choose unit
106 reservations for all insns. These are recorded here. */
108 /* Records the new condition for insns which must be made
109 conditional after scheduling. An entry of NULL_RTX means no such
110 change is necessary. */
112 /* True for the first insn that was scheduled in an ebb. */
114 } c6x_sched_insn_info
;
116 DEF_VEC_O(c6x_sched_insn_info
);
117 DEF_VEC_ALLOC_O(c6x_sched_insn_info
, heap
);
119 /* Record a c6x_sched_insn_info structure for every insn in the function. */
120 static VEC(c6x_sched_insn_info
, heap
) *insn_info
;
122 #define INSN_INFO_LENGTH (VEC_length (c6x_sched_insn_info, insn_info))
123 #define INSN_INFO_ENTRY(N) (*VEC_index (c6x_sched_insn_info, insn_info, (N)))
125 static bool done_cfi_sections
;
127 /* The DFA names of the units, in packet order. */
128 static const char *const c6x_unit_names
[] =
130 "d1", "l1", "s1", "m1",
131 "d2", "l2", "s2", "m2",
134 #define RESERVATION_FLAG_D 1
135 #define RESERVATION_FLAG_L 2
136 #define RESERVATION_FLAG_S 4
137 #define RESERVATION_FLAG_M 8
138 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
139 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
140 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
141 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
143 #define RESERVATION_S1 2
144 #define RESERVATION_S2 6
146 /* Register map for debugging. */
147 int const dbx_register_map
[FIRST_PSEUDO_REGISTER
] =
149 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
150 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
152 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
154 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
156 -1, -1, -1 /* FP, ARGP, ILC. */
159 /* Allocate a new, cleared machine_function structure. */
161 static struct machine_function
*
162 c6x_init_machine_status (void)
164 return ggc_alloc_cleared_machine_function ();
167 /* Implement TARGET_OPTION_OVERRIDE. */
170 c6x_option_override (void)
172 if (global_options_set
.x_c6x_arch_option
)
174 c6x_arch
= all_isas
[c6x_arch_option
].type
;
175 c6x_insn_mask
&= ~C6X_INSNS_ALL_CPU_BITS
;
176 c6x_insn_mask
|= all_isas
[c6x_arch_option
].features
;
179 c6x_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
180 flag_schedule_insns_after_reload
= 0;
182 c6x_flag_modulo_sched
= flag_modulo_sched
;
183 flag_modulo_sched
= 0;
185 init_machine_status
= c6x_init_machine_status
;
187 if (flag_pic
&& !TARGET_DSBT
)
189 error ("-fpic and -fPIC not supported without -mdsbt on this target");
192 c6x_initial_flag_pic
= flag_pic
;
193 if (TARGET_DSBT
&& !flag_pic
)
198 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
201 c6x_conditional_register_usage (void)
204 if (c6x_arch
== C6X_CPU_C62X
|| c6x_arch
== C6X_CPU_C67X
)
205 for (i
= 16; i
< 32; i
++)
208 fixed_regs
[32 + i
] = 1;
212 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_A_REGS
],
214 SET_HARD_REG_BIT (reg_class_contents
[(int)PREDICATE_REGS
],
216 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_A_REGS
],
218 CLEAR_HARD_REG_BIT (reg_class_contents
[(int)NONPREDICATE_REGS
],
223 static GTY(()) rtx eqdf_libfunc
;
224 static GTY(()) rtx nedf_libfunc
;
225 static GTY(()) rtx ledf_libfunc
;
226 static GTY(()) rtx ltdf_libfunc
;
227 static GTY(()) rtx gedf_libfunc
;
228 static GTY(()) rtx gtdf_libfunc
;
229 static GTY(()) rtx eqsf_libfunc
;
230 static GTY(()) rtx nesf_libfunc
;
231 static GTY(()) rtx lesf_libfunc
;
232 static GTY(()) rtx ltsf_libfunc
;
233 static GTY(()) rtx gesf_libfunc
;
234 static GTY(()) rtx gtsf_libfunc
;
235 static GTY(()) rtx strasgi_libfunc
;
236 static GTY(()) rtx strasgi64p_libfunc
;
238 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
239 functions to match the C6x ABI. */
242 c6x_init_libfuncs (void)
244 /* Double-precision floating-point arithmetic. */
245 set_optab_libfunc (add_optab
, DFmode
, "__c6xabi_addd");
246 set_optab_libfunc (sdiv_optab
, DFmode
, "__c6xabi_divd");
247 set_optab_libfunc (smul_optab
, DFmode
, "__c6xabi_mpyd");
248 set_optab_libfunc (neg_optab
, DFmode
, "__c6xabi_negd");
249 set_optab_libfunc (sub_optab
, DFmode
, "__c6xabi_subd");
251 /* Single-precision floating-point arithmetic. */
252 set_optab_libfunc (add_optab
, SFmode
, "__c6xabi_addf");
253 set_optab_libfunc (sdiv_optab
, SFmode
, "__c6xabi_divf");
254 set_optab_libfunc (smul_optab
, SFmode
, "__c6xabi_mpyf");
255 set_optab_libfunc (neg_optab
, SFmode
, "__c6xabi_negf");
256 set_optab_libfunc (sub_optab
, SFmode
, "__c6xabi_subf");
258 /* Floating-point comparisons. */
259 eqsf_libfunc
= init_one_libfunc ("__c6xabi_eqf");
260 nesf_libfunc
= init_one_libfunc ("__c6xabi_neqf");
261 lesf_libfunc
= init_one_libfunc ("__c6xabi_lef");
262 ltsf_libfunc
= init_one_libfunc ("__c6xabi_ltf");
263 gesf_libfunc
= init_one_libfunc ("__c6xabi_gef");
264 gtsf_libfunc
= init_one_libfunc ("__c6xabi_gtf");
265 eqdf_libfunc
= init_one_libfunc ("__c6xabi_eqd");
266 nedf_libfunc
= init_one_libfunc ("__c6xabi_neqd");
267 ledf_libfunc
= init_one_libfunc ("__c6xabi_led");
268 ltdf_libfunc
= init_one_libfunc ("__c6xabi_ltd");
269 gedf_libfunc
= init_one_libfunc ("__c6xabi_ged");
270 gtdf_libfunc
= init_one_libfunc ("__c6xabi_gtd");
272 set_optab_libfunc (eq_optab
, SFmode
, NULL
);
273 set_optab_libfunc (ne_optab
, SFmode
, "__c6xabi_neqf");
274 set_optab_libfunc (gt_optab
, SFmode
, NULL
);
275 set_optab_libfunc (ge_optab
, SFmode
, NULL
);
276 set_optab_libfunc (lt_optab
, SFmode
, NULL
);
277 set_optab_libfunc (le_optab
, SFmode
, NULL
);
278 set_optab_libfunc (unord_optab
, SFmode
, "__c6xabi_unordf");
279 set_optab_libfunc (eq_optab
, DFmode
, NULL
);
280 set_optab_libfunc (ne_optab
, DFmode
, "__c6xabi_neqd");
281 set_optab_libfunc (gt_optab
, DFmode
, NULL
);
282 set_optab_libfunc (ge_optab
, DFmode
, NULL
);
283 set_optab_libfunc (lt_optab
, DFmode
, NULL
);
284 set_optab_libfunc (le_optab
, DFmode
, NULL
);
285 set_optab_libfunc (unord_optab
, DFmode
, "__c6xabi_unordd");
287 /* Floating-point to integer conversions. */
288 set_conv_libfunc (sfix_optab
, SImode
, DFmode
, "__c6xabi_fixdi");
289 set_conv_libfunc (ufix_optab
, SImode
, DFmode
, "__c6xabi_fixdu");
290 set_conv_libfunc (sfix_optab
, DImode
, DFmode
, "__c6xabi_fixdlli");
291 set_conv_libfunc (ufix_optab
, DImode
, DFmode
, "__c6xabi_fixdull");
292 set_conv_libfunc (sfix_optab
, SImode
, SFmode
, "__c6xabi_fixfi");
293 set_conv_libfunc (ufix_optab
, SImode
, SFmode
, "__c6xabi_fixfu");
294 set_conv_libfunc (sfix_optab
, DImode
, SFmode
, "__c6xabi_fixflli");
295 set_conv_libfunc (ufix_optab
, DImode
, SFmode
, "__c6xabi_fixfull");
297 /* Conversions between floating types. */
298 set_conv_libfunc (trunc_optab
, SFmode
, DFmode
, "__c6xabi_cvtdf");
299 set_conv_libfunc (sext_optab
, DFmode
, SFmode
, "__c6xabi_cvtfd");
301 /* Integer to floating-point conversions. */
302 set_conv_libfunc (sfloat_optab
, DFmode
, SImode
, "__c6xabi_fltid");
303 set_conv_libfunc (ufloat_optab
, DFmode
, SImode
, "__c6xabi_fltud");
304 set_conv_libfunc (sfloat_optab
, DFmode
, DImode
, "__c6xabi_fltllid");
305 set_conv_libfunc (ufloat_optab
, DFmode
, DImode
, "__c6xabi_fltulld");
306 set_conv_libfunc (sfloat_optab
, SFmode
, SImode
, "__c6xabi_fltif");
307 set_conv_libfunc (ufloat_optab
, SFmode
, SImode
, "__c6xabi_fltuf");
308 set_conv_libfunc (sfloat_optab
, SFmode
, DImode
, "__c6xabi_fltllif");
309 set_conv_libfunc (ufloat_optab
, SFmode
, DImode
, "__c6xabi_fltullf");
312 set_optab_libfunc (smul_optab
, DImode
, "__c6xabi_mpyll");
313 set_optab_libfunc (ashl_optab
, DImode
, "__c6xabi_llshl");
314 set_optab_libfunc (lshr_optab
, DImode
, "__c6xabi_llshru");
315 set_optab_libfunc (ashr_optab
, DImode
, "__c6xabi_llshr");
317 set_optab_libfunc (sdiv_optab
, SImode
, "__c6xabi_divi");
318 set_optab_libfunc (udiv_optab
, SImode
, "__c6xabi_divu");
319 set_optab_libfunc (smod_optab
, SImode
, "__c6xabi_remi");
320 set_optab_libfunc (umod_optab
, SImode
, "__c6xabi_remu");
321 set_optab_libfunc (sdivmod_optab
, SImode
, "__c6xabi_divremi");
322 set_optab_libfunc (udivmod_optab
, SImode
, "__c6xabi_divremu");
323 set_optab_libfunc (sdiv_optab
, DImode
, "__c6xabi_divlli");
324 set_optab_libfunc (udiv_optab
, DImode
, "__c6xabi_divull");
325 set_optab_libfunc (smod_optab
, DImode
, "__c6xabi_remlli");
326 set_optab_libfunc (umod_optab
, DImode
, "__c6xabi_remull");
327 set_optab_libfunc (udivmod_optab
, DImode
, "__c6xabi_divremull");
330 strasgi_libfunc
= init_one_libfunc ("__c6xabi_strasgi");
331 strasgi64p_libfunc
= init_one_libfunc ("__c6xabi_strasgi_64plus");
334 /* Begin the assembly file. */
337 c6x_file_start (void)
339 /* Variable tracking should be run after all optimizations which change order
340 of insns. It also needs a valid CFG. This can't be done in
341 c6x_override_options, because flag_var_tracking is finalized after
343 c6x_flag_var_tracking
= flag_var_tracking
;
344 flag_var_tracking
= 0;
346 done_cfi_sections
= false;
347 default_file_start ();
349 /* Arrays are aligned to 8-byte boundaries. */
350 asm_fprintf (asm_out_file
,
351 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
352 asm_fprintf (asm_out_file
,
353 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
355 /* Stack alignment is 8 bytes. */
356 asm_fprintf (asm_out_file
,
357 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
358 asm_fprintf (asm_out_file
,
359 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
361 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
362 /* ??? Ideally we'd check flag_short_wchar somehow. */
363 asm_fprintf (asm_out_file
, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
366 /* We conform to version 1.0 of the ABI. */
367 asm_fprintf (asm_out_file
,
368 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
372 /* The LTO frontend only enables exceptions when it sees a function that
373 uses it. This changes the return value of dwarf2out_do_frame, so we
374 have to check before every function. */
377 c6x_output_file_unwind (FILE * f
)
379 if (done_cfi_sections
)
382 /* Output a .cfi_sections directive if we aren't
383 already doing so for debug info. */
384 if (write_symbols
!= DWARF2_DEBUG
&& write_symbols
!= VMS_AND_DWARF2_DEBUG
385 && dwarf2out_do_frame ())
387 asm_fprintf (f
, "\t.cfi_sections .c6xabi.exidx\n");
388 done_cfi_sections
= true;
392 /* Output unwind directives at the end of a function. */
395 c6x_output_fn_unwind (FILE * f
)
397 /* Return immediately if we are not generating unwinding tables. */
398 if (! (flag_unwind_tables
|| flag_exceptions
))
401 /* If this function will never be unwound, then mark it as such. */
402 if (!(flag_unwind_tables
|| crtl
->uses_eh_lsda
)
403 && (TREE_NOTHROW (current_function_decl
)
404 || crtl
->all_throwers_are_sibcalls
))
405 fputs("\t.cantunwind\n", f
);
407 fputs ("\t.endp\n", f
);
411 /* Stack and Calling. */
413 int argument_registers
[10] =
422 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
425 c6x_init_cumulative_args (CUMULATIVE_ARGS
*cum
, const_tree fntype
, rtx libname
,
426 int n_named_args ATTRIBUTE_UNUSED
)
430 if (!libname
&& fntype
)
432 /* We need to find out the number of named arguments. Unfortunately,
433 for incoming arguments, N_NAMED_ARGS is set to -1. */
434 if (stdarg_p (fntype
))
435 cum
->nregs
= type_num_arguments (fntype
) - 1;
441 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
444 c6x_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
445 const_tree type
, bool named ATTRIBUTE_UNUSED
)
447 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
448 if (cum
->count
>= cum
->nregs
)
452 HOST_WIDE_INT size
= int_size_in_bytes (type
);
453 if (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (type
))
457 rtx reg1
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
] + 1);
458 rtx reg2
= gen_rtx_REG (SImode
, argument_registers
[cum
->count
]);
459 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
460 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
461 return gen_rtx_PARALLEL (mode
, vec
);
465 return gen_rtx_REG (mode
, argument_registers
[cum
->count
]);
469 c6x_function_arg_advance (cumulative_args_t cum_v
,
470 enum machine_mode mode ATTRIBUTE_UNUSED
,
471 const_tree type ATTRIBUTE_UNUSED
,
472 bool named ATTRIBUTE_UNUSED
)
474 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
479 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
480 upward rather than downward. */
483 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED
,
484 const_tree type
, bool first
)
488 if (!TARGET_BIG_ENDIAN
)
494 size
= int_size_in_bytes (type
);
498 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
501 c6x_function_arg_boundary (enum machine_mode mode
, const_tree type
)
503 unsigned int boundary
= type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
);
505 if (boundary
> BITS_PER_WORD
)
506 return 2 * BITS_PER_WORD
;
510 HOST_WIDE_INT size
= int_size_in_bytes (type
);
512 return 2 * BITS_PER_WORD
;
513 if (boundary
< BITS_PER_WORD
)
516 return BITS_PER_WORD
;
518 return 2 * BITS_PER_UNIT
;
524 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
526 c6x_function_arg_round_boundary (enum machine_mode mode
, const_tree type
)
528 return c6x_function_arg_boundary (mode
, type
);
531 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
532 where function FUNC returns or receives a value of data type TYPE. */
535 c6x_function_value (const_tree type
, const_tree func ATTRIBUTE_UNUSED
,
536 bool outgoing ATTRIBUTE_UNUSED
)
538 /* Functions return values in register A4. When returning aggregates, we may
539 have to adjust for endianness. */
540 if (TARGET_BIG_ENDIAN
&& type
&& AGGREGATE_TYPE_P (type
))
542 HOST_WIDE_INT size
= int_size_in_bytes (type
);
546 rtx reg1
= gen_rtx_REG (SImode
, REG_A4
+ 1);
547 rtx reg2
= gen_rtx_REG (SImode
, REG_A4
);
548 rtvec vec
= gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode
, reg1
, const0_rtx
),
549 gen_rtx_EXPR_LIST (VOIDmode
, reg2
, GEN_INT (4)));
550 return gen_rtx_PARALLEL (TYPE_MODE (type
), vec
);
553 return gen_rtx_REG (TYPE_MODE (type
), REG_A4
);
556 /* Implement TARGET_LIBCALL_VALUE. */
559 c6x_libcall_value (enum machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
561 return gen_rtx_REG (mode
, REG_A4
);
564 /* TARGET_STRUCT_VALUE_RTX implementation. */
567 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED
, int incoming ATTRIBUTE_UNUSED
)
569 return gen_rtx_REG (Pmode
, REG_A3
);
572 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
575 c6x_function_value_regno_p (const unsigned int regno
)
577 return regno
== REG_A4
;
580 /* Types larger than 64 bit, and variable sized types, are passed by
581 reference. The callee must copy them; see c6x_callee_copies. */
584 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
585 enum machine_mode mode
, const_tree type
,
586 bool named ATTRIBUTE_UNUSED
)
590 size
= int_size_in_bytes (type
);
591 else if (mode
!= VOIDmode
)
592 size
= GET_MODE_SIZE (mode
);
593 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
596 /* Decide whether a type should be returned in memory (true)
597 or in a register (false). This is called by the macro
598 TARGET_RETURN_IN_MEMORY. */
601 c6x_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
603 int size
= int_size_in_bytes (type
);
604 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
607 /* Values which must be returned in the most-significant end of the return
611 c6x_return_in_msb (const_tree valtype
)
613 HOST_WIDE_INT size
= int_size_in_bytes (valtype
);
614 return TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
) && size
== 3;
617 /* Implement TARGET_CALLEE_COPIES. */
620 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
621 enum machine_mode mode ATTRIBUTE_UNUSED
,
622 const_tree type ATTRIBUTE_UNUSED
,
623 bool named ATTRIBUTE_UNUSED
)
628 /* Return the type to use as __builtin_va_list. */
630 c6x_build_builtin_va_list (void)
632 return build_pointer_type (char_type_node
);
636 c6x_asm_trampoline_template (FILE *f
)
638 fprintf (f
, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
639 fprintf (f
, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
640 fprintf (f
, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
641 fprintf (f
, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
642 fprintf (f
, "\t.long\t0x00000362\n"); /* b .s2 B0 */
643 fprintf (f
, "\t.long\t0x00008000\n"); /* nop 5 */
644 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
645 fprintf (f
, "\t.long\t0x00000000\n"); /* nop */
648 /* Emit RTL insns to initialize the variable parts of a trampoline at
649 TRAMP. FNADDR is an RTX for the address of the function's pure
650 code. CXT is an RTX for the static chain value for the function. */
653 c6x_initialize_trampoline (rtx tramp
, tree fndecl
, rtx cxt
)
655 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
656 rtx t1
= copy_to_reg (fnaddr
);
657 rtx t2
= copy_to_reg (cxt
);
658 rtx mask
= gen_reg_rtx (SImode
);
661 emit_block_move (tramp
, assemble_trampoline_template (),
662 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
664 emit_move_insn (mask
, GEN_INT (0xffff << 7));
666 for (i
= 0; i
< 4; i
++)
668 rtx mem
= adjust_address (tramp
, SImode
, i
* 4);
669 rtx t
= (i
& 1) ? t2
: t1
;
670 rtx v1
= gen_reg_rtx (SImode
);
671 rtx v2
= gen_reg_rtx (SImode
);
672 emit_move_insn (v1
, mem
);
674 emit_insn (gen_ashlsi3 (v2
, t
, GEN_INT (7)));
676 emit_insn (gen_lshrsi3 (v2
, t
, GEN_INT (9)));
677 emit_insn (gen_andsi3 (v2
, v2
, mask
));
678 emit_insn (gen_iorsi3 (v2
, v2
, v1
));
679 emit_move_insn (mem
, v2
);
681 #ifdef CLEAR_INSN_CACHE
682 tramp
= XEXP (tramp
, 0);
683 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__gnu_clear_cache"),
684 LCT_NORMAL
, VOIDmode
, 2, tramp
, Pmode
,
685 plus_constant (tramp
, TRAMPOLINE_SIZE
), Pmode
);
689 /* Determine whether c6x_output_mi_thunk can succeed. */
692 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED
,
693 HOST_WIDE_INT delta ATTRIBUTE_UNUSED
,
694 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED
,
695 const_tree function ATTRIBUTE_UNUSED
)
697 return !TARGET_LONG_CALLS
;
700 /* Output the assembler code for a thunk function. THUNK is the
701 declaration for the thunk function itself, FUNCTION is the decl for
702 the target function. DELTA is an immediate constant offset to be
703 added to THIS. If VCALL_OFFSET is nonzero, the word at
704 *(*this + vcall_offset) should be added to THIS. */
707 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
708 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
709 HOST_WIDE_INT vcall_offset
, tree function
)
712 /* The this parameter is passed as the first argument. */
713 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_A4
);
715 c6x_current_insn
= NULL_RTX
;
717 xops
[4] = XEXP (DECL_RTL (function
), 0);
720 output_asm_insn ("b .s2 \t%4", xops
);
722 output_asm_insn ("nop 5", xops
);
725 /* Adjust the this parameter by a fixed constant. */
728 xops
[0] = GEN_INT (delta
);
730 if (delta
>= -16 && delta
<= 15)
732 output_asm_insn ("add .s1 %0, %1, %1", xops
);
734 output_asm_insn ("nop 4", xops
);
736 else if (delta
>= 16 && delta
< 32)
738 output_asm_insn ("add .d1 %0, %1, %1", xops
);
740 output_asm_insn ("nop 4", xops
);
742 else if (delta
>= -32768 && delta
< 32768)
744 output_asm_insn ("mvk .s1 %0, A0", xops
);
745 output_asm_insn ("add .d1 %1, A0, %1", xops
);
747 output_asm_insn ("nop 3", xops
);
751 output_asm_insn ("mvkl .s1 %0, A0", xops
);
752 output_asm_insn ("mvkh .s1 %0, A0", xops
);
753 output_asm_insn ("add .d1 %1, A0, %1", xops
);
755 output_asm_insn ("nop 3", xops
);
759 /* Adjust the this parameter by a value stored in the vtable. */
762 rtx a0tmp
= gen_rtx_REG (Pmode
, REG_A0
);
763 rtx a3tmp
= gen_rtx_REG (Pmode
, REG_A3
);
767 xops
[3] = gen_rtx_MEM (Pmode
, a0tmp
);
768 output_asm_insn ("mv .s1 a4, %2", xops
);
769 output_asm_insn ("ldw .d1t1 %3, %2", xops
);
771 /* Adjust the this parameter. */
772 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (a0tmp
, vcall_offset
));
773 if (!memory_operand (xops
[0], Pmode
))
775 rtx tmp2
= gen_rtx_REG (Pmode
, REG_A1
);
776 xops
[0] = GEN_INT (vcall_offset
);
778 output_asm_insn ("mvkl .s1 %0, %1", xops
);
779 output_asm_insn ("mvkh .s1 %0, %1", xops
);
780 output_asm_insn ("nop 2", xops
);
781 output_asm_insn ("add .d1 %2, %1, %2", xops
);
782 xops
[0] = gen_rtx_MEM (Pmode
, a0tmp
);
785 output_asm_insn ("nop 4", xops
);
787 output_asm_insn ("ldw .d1t1 %0, %1", xops
);
788 output_asm_insn ("|| b .s2 \t%4", xops
);
789 output_asm_insn ("nop 4", xops
);
790 output_asm_insn ("add .d1 %2, %1, %2", xops
);
794 /* Return true if EXP goes in small data/bss. */
797 c6x_in_small_data_p (const_tree exp
)
799 /* We want to merge strings, so we never consider them small data. */
800 if (TREE_CODE (exp
) == STRING_CST
)
803 /* Functions are never small data. */
804 if (TREE_CODE (exp
) == FUNCTION_DECL
)
807 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_WEAK (exp
))
810 if (TREE_CODE (exp
) == VAR_DECL
&& DECL_SECTION_NAME (exp
))
812 const char *section
= TREE_STRING_POINTER (DECL_SECTION_NAME (exp
));
814 if (strcmp (section
, ".neardata") == 0
815 || strncmp (section
, ".neardata.", 10) == 0
816 || strncmp (section
, ".gnu.linkonce.s.", 16) == 0
817 || strcmp (section
, ".bss") == 0
818 || strncmp (section
, ".bss.", 5) == 0
819 || strncmp (section
, ".gnu.linkonce.sb.", 17) == 0
820 || strcmp (section
, ".rodata") == 0
821 || strncmp (section
, ".rodata.", 8) == 0
822 || strncmp (section
, ".gnu.linkonce.s2.", 17) == 0)
826 return PLACE_IN_SDATA_P (exp
);
831 /* Return a section for X. The only special thing we do here is to
832 honor small data. We don't have a tree type, so we can't use the
833 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
834 everything sized 8 bytes or smaller into small data. */
837 c6x_select_rtx_section (enum machine_mode mode
, rtx x
,
838 unsigned HOST_WIDE_INT align
)
840 if (c6x_sdata_mode
== C6X_SDATA_ALL
841 || (c6x_sdata_mode
!= C6X_SDATA_NONE
&& GET_MODE_SIZE (mode
) <= 8))
842 /* ??? Consider using mergeable sdata sections. */
843 return sdata_section
;
845 return default_elf_select_rtx_section (mode
, x
, align
);
849 c6x_elf_select_section (tree decl
, int reloc
,
850 unsigned HOST_WIDE_INT align
)
852 const char *sname
= NULL
;
853 unsigned int flags
= SECTION_WRITE
;
854 if (c6x_in_small_data_p (decl
))
856 switch (categorize_decl_for_section (decl
, reloc
))
867 flags
|= SECTION_BSS
;
874 switch (categorize_decl_for_section (decl
, reloc
))
879 case SECCAT_DATA_REL
:
880 sname
= ".fardata.rel";
882 case SECCAT_DATA_REL_LOCAL
:
883 sname
= ".fardata.rel.local";
885 case SECCAT_DATA_REL_RO
:
886 sname
= ".fardata.rel.ro";
888 case SECCAT_DATA_REL_RO_LOCAL
:
889 sname
= ".fardata.rel.ro.local";
893 flags
|= SECTION_BSS
;
909 /* We might get called with string constants, but get_named_section
910 doesn't like them as they are not DECLs. Also, we need to set
911 flags in that case. */
913 return get_section (sname
, flags
, NULL
);
914 return get_named_section (decl
, sname
, reloc
);
917 return default_elf_select_section (decl
, reloc
, align
);
920 /* Build up a unique section name, expressed as a
921 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
922 RELOC indicates whether the initial value of EXP requires
923 link-time relocations. */
925 static void ATTRIBUTE_UNUSED
926 c6x_elf_unique_section (tree decl
, int reloc
)
928 const char *prefix
= NULL
;
929 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
930 bool one_only
= DECL_ONE_ONLY (decl
) && !HAVE_COMDAT_GROUP
;
932 if (c6x_in_small_data_p (decl
))
934 switch (categorize_decl_for_section (decl
, reloc
))
937 prefix
= one_only
? ".s" : ".neardata";
940 prefix
= one_only
? ".sb" : ".bss";
943 prefix
= one_only
? ".s2" : ".rodata";
945 case SECCAT_RODATA_MERGE_STR
:
946 case SECCAT_RODATA_MERGE_STR_INIT
:
947 case SECCAT_RODATA_MERGE_CONST
:
950 case SECCAT_DATA_REL
:
951 case SECCAT_DATA_REL_LOCAL
:
952 case SECCAT_DATA_REL_RO
:
953 case SECCAT_DATA_REL_RO_LOCAL
:
956 /* Everything else we place into default sections and hope for the
963 switch (categorize_decl_for_section (decl
, reloc
))
966 case SECCAT_DATA_REL
:
967 case SECCAT_DATA_REL_LOCAL
:
968 case SECCAT_DATA_REL_RO
:
969 case SECCAT_DATA_REL_RO_LOCAL
:
970 prefix
= one_only
? ".fd" : ".fardata";
973 prefix
= one_only
? ".fb" : ".far";
976 case SECCAT_RODATA_MERGE_STR
:
977 case SECCAT_RODATA_MERGE_STR_INIT
:
978 case SECCAT_RODATA_MERGE_CONST
:
979 prefix
= one_only
? ".fr" : ".const";
992 const char *name
, *linkonce
;
995 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
996 name
= targetm
.strip_name_encoding (name
);
998 /* If we're using one_only, then there needs to be a .gnu.linkonce
999 prefix to the section name. */
1000 linkonce
= one_only
? ".gnu.linkonce" : "";
1002 string
= ACONCAT ((linkonce
, prefix
, ".", name
, NULL
));
1004 DECL_SECTION_NAME (decl
) = build_string (strlen (string
), string
);
1007 default_unique_section (decl
, reloc
);
1011 c6x_section_type_flags (tree decl
, const char *name
, int reloc
)
1013 unsigned int flags
= 0;
1015 if (strcmp (name
, ".far") == 0
1016 || strncmp (name
, ".far.", 5) == 0)
1017 flags
|= SECTION_BSS
;
1019 flags
|= default_section_type_flags (decl
, name
, reloc
);
1024 /* Checks whether the given CALL_EXPR would use a caller saved
1025 register. This is used to decide whether sibling call optimization
1026 could be performed on the respective function call. */
1029 c6x_call_saved_register_used (tree call_expr
)
1031 CUMULATIVE_ARGS cum_v
;
1032 cumulative_args_t cum
;
1033 HARD_REG_SET call_saved_regset
;
1035 enum machine_mode mode
;
1040 INIT_CUMULATIVE_ARGS (cum_v
, NULL
, NULL
, 0, 0);
1041 cum
= pack_cumulative_args (&cum_v
);
1043 COMPL_HARD_REG_SET (call_saved_regset
, call_used_reg_set
);
1044 for (i
= 0; i
< call_expr_nargs (call_expr
); i
++)
1046 parameter
= CALL_EXPR_ARG (call_expr
, i
);
1047 gcc_assert (parameter
);
1049 /* For an undeclared variable passed as parameter we will get
1050 an ERROR_MARK node here. */
1051 if (TREE_CODE (parameter
) == ERROR_MARK
)
1054 type
= TREE_TYPE (parameter
);
1057 mode
= TYPE_MODE (type
);
1060 if (pass_by_reference (&cum_v
, mode
, type
, true))
1063 type
= build_pointer_type (type
);
1066 parm_rtx
= c6x_function_arg (cum
, mode
, type
, 0);
1068 c6x_function_arg_advance (cum
, mode
, type
, 0);
1073 if (REG_P (parm_rtx
)
1074 && overlaps_hard_reg_set_p (call_saved_regset
, GET_MODE (parm_rtx
),
1077 if (GET_CODE (parm_rtx
) == PARALLEL
)
1079 int n
= XVECLEN (parm_rtx
, 0);
1082 rtx x
= XEXP (XVECEXP (parm_rtx
, 0, n
), 0);
1084 && overlaps_hard_reg_set_p (call_saved_regset
,
1085 GET_MODE (x
), REGNO (x
)))
1093 /* Decide whether we can make a sibling call to a function. DECL is the
1094 declaration of the function being targeted by the call and EXP is the
1095 CALL_EXPR representing the call. */
1098 c6x_function_ok_for_sibcall (tree decl
, tree exp
)
1100 /* Registers A10, A12, B10 and B12 are available as arguments
1101 register but unfortunately caller saved. This makes functions
1102 needing these registers for arguments not suitable for
1104 if (c6x_call_saved_register_used (exp
))
1112 /* When compiling for DSBT, the calling function must be local,
1113 so that when we reload B14 in the sibcall epilogue, it will
1114 not change its value. */
1115 struct cgraph_local_info
*this_func
;
1118 /* Not enough information. */
1121 this_func
= cgraph_local_info (current_function_decl
);
1122 return this_func
->local
;
1128 /* Return true if DECL is known to be linked into section SECTION. */
1131 c6x_function_in_section_p (tree decl
, section
*section
)
1133 /* We can only be certain about functions defined in the same
1134 compilation unit. */
1135 if (!TREE_STATIC (decl
))
1138 /* Make sure that SYMBOL always binds to the definition in this
1139 compilation unit. */
1140 if (!targetm
.binds_local_p (decl
))
1143 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1144 if (!DECL_SECTION_NAME (decl
))
1146 /* Make sure that we will not create a unique section for DECL. */
1147 if (flag_function_sections
|| DECL_ONE_ONLY (decl
))
1151 return function_section (decl
) == section
;
1154 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1157 c6x_long_call_p (rtx op
)
1161 if (!TARGET_LONG_CALLS
)
1164 decl
= SYMBOL_REF_DECL (op
);
1166 /* Try to determine whether the symbol is in the same section as the current
1167 function. Be conservative, and only cater for cases in which the
1168 whole of the current function is placed in the same section. */
1169 if (decl
!= NULL_TREE
1170 && !flag_reorder_blocks_and_partition
1171 && TREE_CODE (decl
) == FUNCTION_DECL
1172 && c6x_function_in_section_p (decl
, current_function_section ()))
1178 /* Emit the sequence for a call. */
1180 c6x_expand_call (rtx retval
, rtx address
, bool sibcall
)
1182 rtx callee
= XEXP (address
, 0);
1185 if (!c6x_call_operand (callee
, Pmode
))
1187 callee
= force_reg (Pmode
, callee
);
1188 address
= change_address (address
, Pmode
, callee
);
1190 call_insn
= gen_rtx_CALL (VOIDmode
, address
, const0_rtx
);
1193 call_insn
= emit_call_insn (call_insn
);
1194 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
),
1195 gen_rtx_REG (Pmode
, REG_B3
));
1199 if (retval
== NULL_RTX
)
1200 call_insn
= emit_call_insn (call_insn
);
1202 call_insn
= emit_call_insn (gen_rtx_SET (GET_MODE (retval
), retval
,
1206 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn
), pic_offset_table_rtx
);
1209 /* Legitimize PIC addresses. If the address is already position-independent,
1210 we return ORIG. Newly generated position-independent addresses go into a
1211 reg. This is REG if nonzero, otherwise we allocate register(s) as
1212 necessary. PICREG is the register holding the pointer to the PIC offset
1216 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
1221 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
1223 int unspec
= UNSPEC_LOAD_GOT
;
1228 gcc_assert (can_create_pseudo_p ());
1229 reg
= gen_reg_rtx (Pmode
);
1233 if (can_create_pseudo_p ())
1234 tmp
= gen_reg_rtx (Pmode
);
1237 emit_insn (gen_movsi_gotoff_high (tmp
, addr
));
1238 emit_insn (gen_movsi_gotoff_lo_sum (tmp
, tmp
, addr
));
1239 emit_insn (gen_load_got_gotoff (reg
, picreg
, tmp
));
1243 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
1244 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
1246 emit_move_insn (reg
, new_rtx
);
1248 if (picreg
== pic_offset_table_rtx
)
1249 crtl
->uses_pic_offset_table
= 1;
1253 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
1257 if (GET_CODE (addr
) == CONST
)
1259 addr
= XEXP (addr
, 0);
1260 gcc_assert (GET_CODE (addr
) == PLUS
);
1263 if (XEXP (addr
, 0) == picreg
)
1268 gcc_assert (can_create_pseudo_p ());
1269 reg
= gen_reg_rtx (Pmode
);
1272 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
1273 addr
= legitimize_pic_address (XEXP (addr
, 1),
1274 base
== reg
? NULL_RTX
: reg
,
1277 if (GET_CODE (addr
) == CONST_INT
)
1279 gcc_assert (! reload_in_progress
&& ! reload_completed
);
1280 addr
= force_reg (Pmode
, addr
);
1283 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
1285 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
1286 addr
= XEXP (addr
, 1);
1289 return gen_rtx_PLUS (Pmode
, base
, addr
);
1295 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1296 Returns true if no further code must be generated, false if the caller
1297 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1300 expand_move (rtx
*operands
, enum machine_mode mode
)
1302 rtx dest
= operands
[0];
1303 rtx op
= operands
[1];
1305 if ((reload_in_progress
| reload_completed
) == 0
1306 && GET_CODE (dest
) == MEM
&& GET_CODE (op
) != REG
)
1307 operands
[1] = force_reg (mode
, op
);
1308 else if (mode
== SImode
&& symbolic_operand (op
, SImode
))
1312 if (sdata_symbolic_operand (op
, SImode
))
1314 emit_insn (gen_load_sdata_pic (dest
, pic_offset_table_rtx
, op
));
1315 crtl
->uses_pic_offset_table
= 1;
1320 rtx temp
= (reload_completed
|| reload_in_progress
1321 ? dest
: gen_reg_rtx (Pmode
));
1323 operands
[1] = legitimize_pic_address (op
, temp
,
1324 pic_offset_table_rtx
);
1327 else if (reload_completed
1328 && !sdata_symbolic_operand (op
, SImode
))
1330 emit_insn (gen_movsi_high (dest
, op
));
1331 emit_insn (gen_movsi_lo_sum (dest
, dest
, op
));
1338 /* This function is called when we're about to expand an integer compare
1339 operation which performs COMPARISON. It examines the second operand,
1340 and if it is an integer constant that cannot be used directly on the
1341 current machine in a comparison insn, it returns true. */
1343 c6x_force_op_for_comparison_p (enum rtx_code code
, rtx op
)
1345 if (!CONST_INT_P (op
) || satisfies_constraint_Iu4 (op
))
1348 if ((code
== EQ
|| code
== LT
|| code
== GT
)
1349 && !satisfies_constraint_Is5 (op
))
1351 if ((code
== GTU
|| code
== LTU
)
1352 && (!TARGET_INSNS_64
|| !satisfies_constraint_Iu5 (op
)))
1358 /* Emit comparison instruction if necessary, returning the expression
1359 that holds the compare result in the proper mode. Return the comparison
1360 that should be used in the jump insn. */
1363 c6x_expand_compare (rtx comparison
, enum machine_mode mode
)
1365 enum rtx_code code
= GET_CODE (comparison
);
1366 rtx op0
= XEXP (comparison
, 0);
1367 rtx op1
= XEXP (comparison
, 1);
1369 enum rtx_code jump_code
= code
;
1370 enum machine_mode op_mode
= GET_MODE (op0
);
1372 if (op_mode
== DImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1374 rtx t
= gen_reg_rtx (SImode
);
1375 emit_insn (gen_iorsi3 (t
, gen_lowpart (SImode
, op0
),
1376 gen_highpart (SImode
, op0
)));
1380 else if (op_mode
== DImode
)
1385 if (code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1387 code
= reverse_condition (code
);
1393 split_di (&op0
, 1, lo
, high
);
1394 split_di (&op1
, 1, lo
+ 1, high
+ 1);
1396 if (c6x_force_op_for_comparison_p (code
, high
[1])
1397 || c6x_force_op_for_comparison_p (EQ
, high
[1]))
1398 high
[1] = force_reg (SImode
, high
[1]);
1400 cmp1
= gen_reg_rtx (SImode
);
1401 cmp2
= gen_reg_rtx (SImode
);
1402 emit_insn (gen_rtx_SET (VOIDmode
, cmp1
,
1403 gen_rtx_fmt_ee (code
, SImode
, high
[0], high
[1])));
1406 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1407 lo
[1] = force_reg (SImode
, lo
[1]);
1408 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1409 gen_rtx_fmt_ee (code
, SImode
, lo
[0], lo
[1])));
1410 emit_insn (gen_andsi3 (cmp1
, cmp1
, cmp2
));
1414 emit_insn (gen_rtx_SET (VOIDmode
, cmp2
,
1415 gen_rtx_EQ (SImode
, high
[0], high
[1])));
1418 else if (code
== LT
)
1420 if (c6x_force_op_for_comparison_p (code
, lo
[1]))
1421 lo
[1] = force_reg (SImode
, lo
[1]);
1422 emit_insn (gen_cmpsi_and (cmp2
, gen_rtx_fmt_ee (code
, SImode
,
1424 lo
[0], lo
[1], cmp2
));
1425 emit_insn (gen_iorsi3 (cmp1
, cmp1
, cmp2
));
1429 else if (TARGET_FP
&& !flag_finite_math_only
1430 && (op_mode
== DFmode
|| op_mode
== SFmode
)
1431 && code
!= EQ
&& code
!= NE
&& code
!= LT
&& code
!= GT
1432 && code
!= UNLE
&& code
!= UNGE
)
1434 enum rtx_code code1
, code2
, code3
;
1435 rtx (*fn
) (rtx
, rtx
, rtx
, rtx
, rtx
);
1447 code1
= code
== LE
|| code
== UNGT
? LT
: GT
;
1472 cmp
= gen_reg_rtx (SImode
);
1473 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1474 gen_rtx_fmt_ee (code1
, SImode
, op0
, op1
)));
1475 fn
= op_mode
== DFmode
? gen_cmpdf_ior
: gen_cmpsf_ior
;
1476 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code2
, SImode
, op0
, op1
),
1478 if (code3
!= UNKNOWN
)
1479 emit_insn (fn (cmp
, gen_rtx_fmt_ee (code3
, SImode
, op0
, op1
),
1482 else if (op_mode
== SImode
&& (code
== NE
|| code
== EQ
) && op1
== const0_rtx
)
1487 is_fp_libfunc
= !TARGET_FP
&& (op_mode
== DFmode
|| op_mode
== SFmode
);
1489 if ((code
== NE
|| code
== GEU
|| code
== LEU
|| code
== GE
|| code
== LE
)
1492 code
= reverse_condition (code
);
1495 else if (code
== UNGE
)
1500 else if (code
== UNLE
)
1515 libfunc
= op_mode
== DFmode
? eqdf_libfunc
: eqsf_libfunc
;
1518 libfunc
= op_mode
== DFmode
? nedf_libfunc
: nesf_libfunc
;
1521 libfunc
= op_mode
== DFmode
? gtdf_libfunc
: gtsf_libfunc
;
1524 libfunc
= op_mode
== DFmode
? gedf_libfunc
: gesf_libfunc
;
1527 libfunc
= op_mode
== DFmode
? ltdf_libfunc
: ltsf_libfunc
;
1530 libfunc
= op_mode
== DFmode
? ledf_libfunc
: lesf_libfunc
;
1537 cmp
= emit_library_call_value (libfunc
, 0, LCT_CONST
, SImode
, 2,
1538 op0
, op_mode
, op1
, op_mode
);
1539 insns
= get_insns ();
1542 emit_libcall_block (insns
, cmp
, cmp
,
1543 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
));
1547 cmp
= gen_reg_rtx (SImode
);
1548 if (c6x_force_op_for_comparison_p (code
, op1
))
1549 op1
= force_reg (SImode
, op1
);
1550 emit_insn (gen_rtx_SET (VOIDmode
, cmp
,
1551 gen_rtx_fmt_ee (code
, SImode
, op0
, op1
)));
1555 return gen_rtx_fmt_ee (jump_code
, mode
, cmp
, const0_rtx
);
1558 /* Return one word of double-word value OP. HIGH_P is true to select the
1559 high part, false to select the low part. When encountering auto-increment
1560 addressing, we make the assumption that the low part is going to be accessed
1564 c6x_subword (rtx op
, bool high_p
)
1567 enum machine_mode mode
;
1569 mode
= GET_MODE (op
);
1570 if (mode
== VOIDmode
)
1573 if (TARGET_BIG_ENDIAN
? !high_p
: high_p
)
1574 byte
= UNITS_PER_WORD
;
1580 rtx addr
= XEXP (op
, 0);
1581 if (GET_CODE (addr
) == PLUS
|| REG_P (addr
))
1582 return adjust_address (op
, word_mode
, byte
);
1583 /* FIXME: should really support autoincrement addressing for
1584 multi-word modes. */
1588 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
1591 /* Split one or more DImode RTL references into pairs of SImode
1592 references. The RTL can be REG, offsettable MEM, integer constant, or
1593 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1594 split and "num" is its length. lo_half and hi_half are output arrays
1595 that parallel "operands". */
1598 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1602 rtx op
= operands
[num
];
1604 lo_half
[num
] = c6x_subword (op
, false);
1605 hi_half
[num
] = c6x_subword (op
, true);
1609 /* Return true if VAL is a mask valid for a clr instruction. */
1611 c6x_valid_mask_p (HOST_WIDE_INT val
)
1614 for (i
= 0; i
< 32; i
++)
1615 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1618 if (val
& ((unsigned HOST_WIDE_INT
)1 << i
))
1621 if (!(val
& ((unsigned HOST_WIDE_INT
)1 << i
)))
1626 /* Expand a block move for a movmemM pattern. */
1629 c6x_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
,
1630 rtx expected_align_exp ATTRIBUTE_UNUSED
,
1631 rtx expected_size_exp ATTRIBUTE_UNUSED
)
1633 unsigned HOST_WIDE_INT align
= 1;
1634 unsigned HOST_WIDE_INT src_mem_align
, dst_mem_align
, min_mem_align
;
1635 unsigned HOST_WIDE_INT count
= 0, offset
= 0;
1636 unsigned int biggest_move
= TARGET_STDW
? 8 : 4;
1638 if (CONST_INT_P (align_exp
))
1639 align
= INTVAL (align_exp
);
1641 src_mem_align
= MEM_ALIGN (src
) / BITS_PER_UNIT
;
1642 dst_mem_align
= MEM_ALIGN (dst
) / BITS_PER_UNIT
;
1643 min_mem_align
= MIN (src_mem_align
, dst_mem_align
);
1645 if (min_mem_align
> align
)
1646 align
= min_mem_align
/ BITS_PER_UNIT
;
1647 if (src_mem_align
< align
)
1648 src_mem_align
= align
;
1649 if (dst_mem_align
< align
)
1650 dst_mem_align
= align
;
1652 if (CONST_INT_P (count_exp
))
1653 count
= INTVAL (count_exp
);
1657 /* Make sure we don't need to care about overflow later on. */
1658 if (count
> ((unsigned HOST_WIDE_INT
) 1 << 30))
1661 if (count
>= 28 && (count
& 3) == 0 && align
>= 4)
1663 tree dst_expr
= MEM_EXPR (dst
);
1664 tree src_expr
= MEM_EXPR (src
);
1665 rtx fn
= TARGET_INSNS_64PLUS
? strasgi64p_libfunc
: strasgi_libfunc
;
1666 rtx srcreg
= force_reg (Pmode
, XEXP (src
, 0));
1667 rtx dstreg
= force_reg (Pmode
, XEXP (dst
, 0));
1670 mark_addressable (src_expr
);
1672 mark_addressable (dst_expr
);
1673 emit_library_call (fn
, LCT_NORMAL
, VOIDmode
, 3,
1674 dstreg
, Pmode
, srcreg
, Pmode
, count_exp
, SImode
);
1678 if (biggest_move
> align
&& !TARGET_INSNS_64
)
1679 biggest_move
= align
;
1681 if (count
/ biggest_move
> 7)
1686 rtx reg
, reg_lowpart
;
1687 enum machine_mode srcmode
, dstmode
;
1688 unsigned HOST_WIDE_INT src_size
, dst_size
, src_left
;
1692 while (biggest_move
> count
)
1695 src_size
= dst_size
= biggest_move
;
1696 if (src_size
> src_mem_align
&& src_size
== 2)
1698 if (dst_size
> dst_mem_align
&& dst_size
== 2)
1701 if (dst_size
> src_size
)
1702 dst_size
= src_size
;
1704 srcmode
= mode_for_size (src_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1705 dstmode
= mode_for_size (dst_size
* BITS_PER_UNIT
, MODE_INT
, 0);
1707 reg_lowpart
= reg
= gen_reg_rtx (srcmode
);
1710 reg
= gen_reg_rtx (SImode
);
1711 reg_lowpart
= gen_lowpart (srcmode
, reg
);
1714 srcmem
= adjust_address (copy_rtx (src
), srcmode
, offset
);
1716 if (src_size
> src_mem_align
)
1718 enum insn_code icode
= (srcmode
== SImode
? CODE_FOR_movmisalignsi
1719 : CODE_FOR_movmisaligndi
);
1720 emit_insn (GEN_FCN (icode
) (reg_lowpart
, srcmem
));
1723 emit_move_insn (reg_lowpart
, srcmem
);
1725 src_left
= src_size
;
1726 shift
= TARGET_BIG_ENDIAN
? (src_size
- dst_size
) * BITS_PER_UNIT
: 0;
1727 while (src_left
> 0)
1729 rtx dstreg
= reg_lowpart
;
1731 if (src_size
> dst_size
)
1734 int shift_amount
= shift
& (BITS_PER_WORD
- 1);
1736 srcword
= operand_subword_force (srcword
, src_left
>= 4 ? 0 : 4,
1738 if (shift_amount
> 0)
1740 dstreg
= gen_reg_rtx (SImode
);
1741 emit_insn (gen_lshrsi3 (dstreg
, srcword
,
1742 GEN_INT (shift_amount
)));
1746 dstreg
= gen_lowpart (dstmode
, dstreg
);
1749 dstmem
= adjust_address (copy_rtx (dst
), dstmode
, offset
);
1750 if (dst_size
> dst_mem_align
)
1752 enum insn_code icode
= (dstmode
== SImode
? CODE_FOR_movmisalignsi
1753 : CODE_FOR_movmisaligndi
);
1754 emit_insn (GEN_FCN (icode
) (dstmem
, dstreg
));
1757 emit_move_insn (dstmem
, dstreg
);
1759 if (TARGET_BIG_ENDIAN
)
1760 shift
-= dst_size
* BITS_PER_UNIT
;
1762 shift
+= dst_size
* BITS_PER_UNIT
;
1764 src_left
-= dst_size
;
1771 /* Subroutine of print_address_operand, print a single address offset OFF for
1772 a memory access of mode MEM_MODE, choosing between normal form and scaled
1773 form depending on the type of the insn. Misaligned memory references must
1774 use the scaled form. */
1777 print_address_offset (FILE *file
, rtx off
, enum machine_mode mem_mode
)
1781 if (c6x_current_insn
!= NULL_RTX
)
1783 pat
= PATTERN (c6x_current_insn
);
1784 if (GET_CODE (pat
) == COND_EXEC
)
1785 pat
= COND_EXEC_CODE (pat
);
1786 if (GET_CODE (pat
) == PARALLEL
)
1787 pat
= XVECEXP (pat
, 0, 0);
1789 if (GET_CODE (pat
) == SET
1790 && GET_CODE (SET_SRC (pat
)) == UNSPEC
1791 && XINT (SET_SRC (pat
), 1) == UNSPEC_MISALIGNED_ACCESS
)
1793 gcc_assert (CONST_INT_P (off
)
1794 && (INTVAL (off
) & (GET_MODE_SIZE (mem_mode
) - 1)) == 0);
1795 fprintf (file
, "[" HOST_WIDE_INT_PRINT_DEC
"]",
1796 INTVAL (off
) / GET_MODE_SIZE (mem_mode
));
1801 output_address (off
);
1806 c6x_print_operand_punct_valid_p (unsigned char c
)
1808 return c
== '$' || c
== '.' || c
== '|';
1811 static void c6x_print_operand (FILE *, rtx
, int);
1813 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1816 c6x_print_address_operand (FILE *file
, rtx x
, enum machine_mode mem_mode
)
1819 switch (GET_CODE (x
))
1823 if (GET_CODE (x
) == POST_MODIFY
)
1824 output_address (XEXP (x
, 0));
1825 off
= XEXP (XEXP (x
, 1), 1);
1826 if (XEXP (x
, 0) == stack_pointer_rtx
)
1828 if (GET_CODE (x
) == PRE_MODIFY
)
1829 gcc_assert (INTVAL (off
) > 0);
1831 gcc_assert (INTVAL (off
) < 0);
1833 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1835 fprintf (file
, "--");
1836 off
= GEN_INT (-INTVAL (off
));
1839 fprintf (file
, "++");
1840 if (GET_CODE (x
) == PRE_MODIFY
)
1841 output_address (XEXP (x
, 0));
1842 print_address_offset (file
, off
, mem_mode
);
1847 if (CONST_INT_P (off
) && INTVAL (off
) < 0)
1849 fprintf (file
, "-");
1850 off
= GEN_INT (-INTVAL (off
));
1853 fprintf (file
, "+");
1854 output_address (XEXP (x
, 0));
1855 print_address_offset (file
, off
, mem_mode
);
1859 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1860 fprintf (file
, "--");
1861 output_address (XEXP (x
, 0));
1862 fprintf (file
, "[1]");
1865 fprintf (file
, "++");
1866 output_address (XEXP (x
, 0));
1867 fprintf (file
, "[1]");
1870 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
1871 output_address (XEXP (x
, 0));
1872 fprintf (file
, "++[1]");
1875 output_address (XEXP (x
, 0));
1876 fprintf (file
, "--[1]");
1882 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
1883 fprintf (file
, "+B14(");
1884 output_addr_const (file
, x
);
1885 fprintf (file
, ")");
1889 switch (XINT (x
, 1))
1891 case UNSPEC_LOAD_GOT
:
1892 fputs ("$GOT(", file
);
1893 output_addr_const (file
, XVECEXP (x
, 0, 0));
1896 case UNSPEC_LOAD_SDATA
:
1897 output_addr_const (file
, XVECEXP (x
, 0, 0));
1905 gcc_assert (GET_CODE (x
) != MEM
);
1906 c6x_print_operand (file
, x
, 0);
1911 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1912 specifies the functional unit used by INSN. */
1915 c6x_get_unit_specifier (rtx insn
)
1917 enum attr_units units
;
1921 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
1922 return c6x_unit_names
[unit
][0];
1925 units
= get_attr_units (insn
);
1950 /* Prints the unit specifier field. */
1952 c6x_print_unit_specifier_field (FILE *file
, rtx insn
)
1954 enum attr_units units
= get_attr_units (insn
);
1955 enum attr_cross cross
= get_attr_cross (insn
);
1956 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
1960 if (units
== UNITS_D_ADDR
)
1962 enum attr_addr_regfile arf
= get_attr_addr_regfile (insn
);
1964 gcc_assert (arf
!= ADDR_REGFILE_UNKNOWN
);
1965 half
= arf
== ADDR_REGFILE_A
? 1 : 2;
1966 t_half
= rf
== DEST_REGFILE_A
? 1 : 2;
1967 fprintf (file
, ".d%dt%d", half
, t_half
);
1973 int unit
= INSN_INFO_ENTRY (INSN_UID (insn
)).reservation
;
1975 fputs (c6x_unit_names
[unit
], file
);
1976 if (cross
== CROSS_Y
)
1981 gcc_assert (rf
!= DEST_REGFILE_UNKNOWN
);
1982 unitspec
= c6x_get_unit_specifier (insn
);
1983 half
= rf
== DEST_REGFILE_A
? 1 : 2;
1984 fprintf (file
, ".%c%d%s", unitspec
, half
, cross
== CROSS_Y
? "x" : "");
1987 /* Output assembly language output for the address ADDR to FILE. */
1989 c6x_print_operand_address (FILE *file
, rtx addr
)
1991 c6x_print_address_operand (file
, addr
, VOIDmode
);
1994 /* Print an operand, X, to FILE, with an optional modifier in CODE.
1997 $ -- print the unit specifier field for the instruction.
1998 . -- print the predicate for the instruction or an emptry string for an
2000 | -- print "||" if the insn should be issued in parallel with the previous
2003 C -- print an opcode suffix for a reversed condition
2004 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2006 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2008 J -- print a predicate
2009 j -- like J, but use reverse predicate
2010 k -- treat a CONST_INT as a register number and print it as a register
2011 k -- like k, but print out a doubleword register
2012 n -- print an integer operand, negated
2013 p -- print the low part of a DImode register
2014 P -- print the high part of a DImode register
2015 r -- print the absolute value of an integer operand, shifted right by 1
2016 R -- print the absolute value of an integer operand, shifted right by 2
2017 f -- the first clear bit in an integer operand assumed to be a mask for
2019 F -- the last clear bit in such a mask
2020 s -- the first set bit in an integer operand assumed to be a mask for
2022 S -- the last set bit in such a mask
2023 U -- print either 1 or 2, depending on the side of the machine used by
2027 c6x_print_operand (FILE *file
, rtx x
, int code
)
2032 enum machine_mode mode
;
2036 if (GET_MODE (c6x_current_insn
) != TImode
)
2042 c6x_print_unit_specifier_field (file
, c6x_current_insn
);
2048 x
= current_insn_predicate
;
2051 unsigned int regno
= REGNO (XEXP (x
, 0));
2053 if (GET_CODE (x
) == EQ
)
2055 fputs (reg_names
[regno
], file
);
2061 mode
= GET_MODE (x
);
2068 enum rtx_code c
= GET_CODE (x
);
2070 c
= swap_condition (c
);
2071 fputs (GET_RTX_NAME (c
), file
);
2078 unsigned int regno
= REGNO (XEXP (x
, 0));
2079 if ((GET_CODE (x
) == EQ
) == (code
== 'J'))
2081 fputs (reg_names
[regno
], file
);
2086 gcc_assert (GET_CODE (x
) == CONST_INT
);
2088 fprintf (file
, "%s", reg_names
[v
]);
2091 gcc_assert (GET_CODE (x
) == CONST_INT
);
2093 gcc_assert ((v
& 1) == 0);
2094 fprintf (file
, "%s:%s", reg_names
[v
+ 1], reg_names
[v
]);
2101 gcc_assert (GET_CODE (x
) == CONST_INT
);
2103 for (i
= 0; i
< 32; i
++)
2105 HOST_WIDE_INT tst
= v
& 1;
2106 if (((code
== 'f' || code
== 'F') && !tst
)
2107 || ((code
== 's' || code
== 'S') && tst
))
2111 if (code
== 'f' || code
== 's')
2113 fprintf (file
, "%d", i
);
2118 HOST_WIDE_INT tst
= v
& 1;
2119 if ((code
== 'F' && tst
) || (code
== 'S' && !tst
))
2123 fprintf (file
, "%d", i
- 1);
2127 gcc_assert (GET_CODE (x
) == CONST_INT
);
2128 output_addr_const (file
, GEN_INT (-INTVAL (x
)));
2132 gcc_assert (GET_CODE (x
) == CONST_INT
);
2136 output_addr_const (file
, GEN_INT (v
>> 1));
2140 gcc_assert (GET_CODE (x
) == CONST_INT
);
2144 output_addr_const (file
, GEN_INT (v
>> 2));
2148 gcc_assert (GET_CODE (x
) == CONST_INT
);
2150 fputs (v
== 2 ? "h" : v
== 4 ? "w" : "d", file
);
2155 gcc_assert (GET_CODE (x
) == REG
);
2159 fputs (reg_names
[v
], file
);
2164 if (GET_CODE (x
) == CONST
)
2167 gcc_assert (GET_CODE (x
) == PLUS
);
2168 gcc_assert (GET_CODE (XEXP (x
, 1)) == CONST_INT
);
2169 v
= INTVAL (XEXP (x
, 1));
2173 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
2175 t
= SYMBOL_REF_DECL (x
);
2177 v
|= DECL_ALIGN_UNIT (t
);
2179 v
|= TYPE_ALIGN_UNIT (TREE_TYPE (t
));
2192 if (GET_CODE (x
) == PLUS
2193 || GET_RTX_CLASS (GET_CODE (x
)) == RTX_AUTOINC
)
2195 if (GET_CODE (x
) == CONST
|| GET_CODE (x
) == SYMBOL_REF
)
2197 gcc_assert (sdata_symbolic_operand (x
, Pmode
));
2202 gcc_assert (REG_P (x
));
2203 if (A_REGNO_P (REGNO (x
)))
2205 if (B_REGNO_P (REGNO (x
)))
2210 switch (GET_CODE (x
))
2213 if (GET_MODE_SIZE (mode
) == 8)
2214 fprintf (file
, "%s:%s", reg_names
[REGNO (x
) + 1],
2215 reg_names
[REGNO (x
)]);
2217 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
2222 gcc_assert (XEXP (x
, 0) != stack_pointer_rtx
);
2223 c6x_print_address_operand (file
, XEXP (x
, 0), GET_MODE (x
));
2228 output_addr_const (file
, x
);
2233 output_addr_const (file
, x
);
2237 output_operand_lossage ("invalid const_double operand");
2241 output_addr_const (file
, x
);
2246 /* Return TRUE if OP is a valid memory address with a base register of
2247 class C. If SMALL_OFFSET is true, we disallow memory references which would
2248 require a long offset with B14/B15. */
2251 c6x_mem_operand (rtx op
, enum reg_class c
, bool small_offset
)
2253 enum machine_mode mode
= GET_MODE (op
);
2254 rtx base
= XEXP (op
, 0);
2255 switch (GET_CODE (base
))
2261 && (XEXP (base
, 0) == stack_pointer_rtx
2262 || XEXP (base
, 0) == pic_offset_table_rtx
))
2264 if (!c6x_legitimate_address_p_1 (mode
, base
, true, true))
2275 base
= XEXP (base
, 0);
2281 gcc_assert (sdata_symbolic_operand (base
, Pmode
));
2282 return !small_offset
&& c
== B_REGS
;
2287 return TEST_HARD_REG_BIT (reg_class_contents
[ (int) (c
)], REGNO (base
));
2290 /* Returns true if X is a valid address for use in a memory reference
2291 of mode MODE. If STRICT is true, we do not allow pseudo registers
2292 in the address. NO_LARGE_OFFSET is true if we are examining an
2293 address for use in a load or store misaligned instruction, or
2294 recursively examining an operand inside a PRE/POST_MODIFY. */
2297 c6x_legitimate_address_p_1 (enum machine_mode mode
, rtx x
, bool strict
,
2298 bool no_large_offset
)
2302 enum rtx_code code
= GET_CODE (x
);
2308 /* We can't split these into word-sized pieces yet. */
2309 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2311 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
2313 if (!c6x_legitimate_address_p_1 (mode
, XEXP (x
, 1), strict
, true))
2315 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
2323 /* We can't split these into word-sized pieces yet. */
2324 if (!TARGET_STDW
&& GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
2333 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x
));
2335 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x
));
2338 if (!REG_P (XEXP (x
, 0))
2339 || !c6x_legitimate_address_p_1 (mode
, XEXP (x
, 0), strict
, false))
2341 /* We cannot ensure currently that both registers end up in the
2342 same register file. */
2343 if (REG_P (XEXP (x
, 1)))
2346 if (mode
== BLKmode
)
2348 else if (mode
== VOIDmode
)
2349 /* ??? This can happen during ivopts. */
2352 size
= GET_MODE_SIZE (mode
);
2355 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2356 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_SDATA
2357 && XEXP (x
, 0) == pic_offset_table_rtx
2358 && sdata_symbolic_operand (XVECEXP (XEXP (x
, 1), 0, 0), SImode
))
2359 return !no_large_offset
&& size
<= 4;
2362 && GET_CODE (XEXP (x
, 1)) == UNSPEC
2363 && XINT (XEXP (x
, 1), 1) == UNSPEC_LOAD_GOT
2364 && XEXP (x
, 0) == pic_offset_table_rtx
2365 && (GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == SYMBOL_REF
2366 || GET_CODE (XVECEXP (XEXP (x
, 1), 0, 0)) == LABEL_REF
))
2367 return !no_large_offset
;
2368 if (GET_CODE (XEXP (x
, 1)) != CONST_INT
)
2371 off
= INTVAL (XEXP (x
, 1));
2373 /* If the machine does not have doubleword load/stores, we'll use
2374 word size accesses. */
2376 if (size
== 2 * UNITS_PER_WORD
&& !TARGET_STDW
)
2377 size
= UNITS_PER_WORD
;
2379 if (((HOST_WIDE_INT
)size1
- 1) & off
)
2382 if (off
> -32 && off
< (size1
== size
? 32 : 28))
2384 if (no_large_offset
|| code
!= PLUS
|| XEXP (x
, 0) != stack_pointer_rtx
2385 || size1
> UNITS_PER_WORD
)
2387 return off
>= 0 && off
< 32768;
2392 return (!no_large_offset
2393 /* With -fpic, we must wrap it in an unspec to show the B14
2396 && GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
2397 && sdata_symbolic_operand (x
, Pmode
));
2405 c6x_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
2407 return c6x_legitimate_address_p_1 (mode
, x
, strict
, false);
2411 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
,
2412 rtx x ATTRIBUTE_UNUSED
)
2417 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2419 c6x_preferred_rename_class (reg_class_t cl
)
2422 return NONPREDICATE_A_REGS
;
2424 return NONPREDICATE_B_REGS
;
2425 if (cl
== ALL_REGS
|| cl
== GENERAL_REGS
)
2426 return NONPREDICATE_REGS
;
2430 /* Implements FINAL_PRESCAN_INSN. */
2432 c6x_final_prescan_insn (rtx insn
, rtx
*opvec ATTRIBUTE_UNUSED
,
2433 int noperands ATTRIBUTE_UNUSED
)
2435 c6x_current_insn
= insn
;
2438 /* A structure to describe the stack layout of a function. The layout is
2441 [saved frame pointer (or possibly padding0)]
2442 --> incoming stack pointer, new hard frame pointer
2443 [saved call-used regs]
2445 --> soft frame pointer
2447 [outgoing arguments]
2450 The structure members are laid out in this order. */
2455 /* Number of registers to save. */
2458 HOST_WIDE_INT frame
;
2459 int outgoing_arguments_size
;
2462 HOST_WIDE_INT to_allocate
;
2463 /* The offsets relative to the incoming stack pointer (which
2464 becomes HARD_FRAME_POINTER). */
2465 HOST_WIDE_INT frame_pointer_offset
;
2466 HOST_WIDE_INT b3_offset
;
2468 /* True if we should call push_rts/pop_rts to save and restore
2473 /* Return true if we need to save and modify the PIC register in the
2477 must_reload_pic_reg_p (void)
2479 struct cgraph_local_info
*i
= NULL
;
2484 i
= cgraph_local_info (current_function_decl
);
2486 if ((crtl
->uses_pic_offset_table
|| !current_function_is_leaf
) && !i
->local
)
2491 /* Return 1 if we need to save REGNO. */
2493 c6x_save_reg (unsigned int regno
)
2495 return ((df_regs_ever_live_p (regno
)
2496 && !call_used_regs
[regno
]
2497 && !fixed_regs
[regno
])
2498 || (regno
== RETURN_ADDR_REGNO
2499 && (df_regs_ever_live_p (regno
)
2500 || !current_function_is_leaf
))
2501 || (regno
== PIC_OFFSET_TABLE_REGNUM
&& must_reload_pic_reg_p ()));
2504 /* Examine the number of regs NREGS we've determined we must save.
2505 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2506 prologue and epilogue. */
2509 use_push_rts_p (int nregs
)
2511 if (TARGET_INSNS_64PLUS
&& optimize_function_for_size_p (cfun
)
2512 && !cfun
->machine
->contains_sibcall
2513 && !cfun
->returns_struct
2514 && !TARGET_LONG_CALLS
2515 && nregs
>= 6 && !frame_pointer_needed
)
2520 /* Return number of saved general prupose registers. */
2523 c6x_nsaved_regs (void)
2528 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
2529 if (c6x_save_reg (regno
))
2534 /* The safe debug order mandated by the ABI. */
2535 static unsigned reg_save_order
[] =
2537 REG_A10
, REG_A11
, REG_A12
, REG_A13
,
2539 REG_B10
, REG_B11
, REG_B12
, REG_B13
,
2543 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2545 /* Compute the layout of the stack frame and store it in FRAME. */
2548 c6x_compute_frame_layout (struct c6x_frame
*frame
)
2550 HOST_WIDE_INT size
= get_frame_size ();
2551 HOST_WIDE_INT offset
;
2554 /* We use the four bytes which are technically inside the caller's frame,
2555 usually to save the frame pointer. */
2557 frame
->padding0
= 0;
2558 nregs
= c6x_nsaved_regs ();
2559 frame
->push_rts
= false;
2560 frame
->b3_offset
= 0;
2561 if (use_push_rts_p (nregs
))
2563 frame
->push_rts
= true;
2564 frame
->b3_offset
= (TARGET_BIG_ENDIAN
? -12 : -13) * 4;
2567 else if (c6x_save_reg (REG_B3
))
2570 for (idx
= N_SAVE_ORDER
- 1; reg_save_order
[idx
] != REG_B3
; idx
--)
2572 if (c6x_save_reg (reg_save_order
[idx
]))
2573 frame
->b3_offset
-= 4;
2576 frame
->nregs
= nregs
;
2578 if (size
== 0 && nregs
== 0)
2580 frame
->padding0
= 4;
2581 frame
->padding1
= frame
->padding2
= 0;
2582 frame
->frame_pointer_offset
= frame
->to_allocate
= 0;
2583 frame
->outgoing_arguments_size
= 0;
2587 if (!frame
->push_rts
)
2588 offset
+= frame
->nregs
* 4;
2590 if (offset
== 0 && size
== 0 && crtl
->outgoing_args_size
== 0
2591 && !current_function_is_leaf
)
2592 /* Don't use the bottom of the caller's frame if we have no
2593 allocation of our own and call other functions. */
2594 frame
->padding0
= frame
->padding1
= 4;
2595 else if (offset
& 4)
2596 frame
->padding1
= 4;
2598 frame
->padding1
= 0;
2600 offset
+= frame
->padding0
+ frame
->padding1
;
2601 frame
->frame_pointer_offset
= offset
;
2604 frame
->outgoing_arguments_size
= crtl
->outgoing_args_size
;
2605 offset
+= frame
->outgoing_arguments_size
;
2607 if ((offset
& 4) == 0)
2608 frame
->padding2
= 8;
2610 frame
->padding2
= 4;
2611 frame
->to_allocate
= offset
+ frame
->padding2
;
2614 /* Return the offset between two registers, one to be eliminated, and the other
2615 its replacement, at the start of a routine. */
2618 c6x_initial_elimination_offset (int from
, int to
)
2620 struct c6x_frame frame
;
2621 c6x_compute_frame_layout (&frame
);
2623 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
2625 else if (from
== FRAME_POINTER_REGNUM
2626 && to
== HARD_FRAME_POINTER_REGNUM
)
2627 return -frame
.frame_pointer_offset
;
2630 gcc_assert (to
== STACK_POINTER_REGNUM
);
2632 if (from
== ARG_POINTER_REGNUM
)
2633 return frame
.to_allocate
+ (frame
.push_rts
? 56 : 0);
2635 gcc_assert (from
== FRAME_POINTER_REGNUM
);
2636 return frame
.to_allocate
- frame
.frame_pointer_offset
;
2640 /* Given FROM and TO register numbers, say whether this elimination is
2641 allowed. Frame pointer elimination is automatically handled. */
2644 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
2646 if (to
== STACK_POINTER_REGNUM
)
2647 return !frame_pointer_needed
;
2651 /* Emit insns to increment the stack pointer by OFFSET. If
2652 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2653 Does nothing if the offset is zero. */
2656 emit_add_sp_const (HOST_WIDE_INT offset
, bool frame_related_p
)
2658 rtx to_add
= GEN_INT (offset
);
2659 rtx orig_to_add
= to_add
;
2665 if (offset
< -32768 || offset
> 32767)
2667 rtx reg
= gen_rtx_REG (SImode
, REG_A0
);
2668 rtx low
= GEN_INT (trunc_int_for_mode (offset
, HImode
));
2670 insn
= emit_insn (gen_movsi_high (reg
, low
));
2671 if (frame_related_p
)
2672 RTX_FRAME_RELATED_P (insn
) = 1;
2673 insn
= emit_insn (gen_movsi_lo_sum (reg
, reg
, to_add
));
2674 if (frame_related_p
)
2675 RTX_FRAME_RELATED_P (insn
) = 1;
2678 insn
= emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2680 if (frame_related_p
)
2683 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
2684 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
2685 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2688 RTX_FRAME_RELATED_P (insn
) = 1;
2692 /* Prologue and epilogue. */
2694 c6x_expand_prologue (void)
2696 struct c6x_frame frame
;
2699 HOST_WIDE_INT initial_offset
, off
, added_already
;
2701 c6x_compute_frame_layout (&frame
);
2703 if (flag_stack_usage_info
)
2704 current_function_static_stack_size
= frame
.to_allocate
;
2706 initial_offset
= -frame
.to_allocate
;
2709 emit_insn (gen_push_rts ());
2710 nsaved
= frame
.nregs
;
2713 /* If the offsets would be too large for the memory references we will
2714 create to save registers, do the stack allocation in two parts.
2715 Ensure by subtracting 8 that we don't store to the word pointed to
2716 by the stack pointer. */
2717 if (initial_offset
< -32768)
2718 initial_offset
= -frame
.frame_pointer_offset
- 8;
2720 if (frame
.to_allocate
> 0)
2721 gcc_assert (initial_offset
!= 0);
2723 off
= -initial_offset
+ 4 - frame
.padding0
;
2725 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2728 if (frame_pointer_needed
)
2730 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2731 /* We go through some contortions here to both follow the ABI's
2732 recommendation that FP == incoming SP, and to avoid writing or
2733 reading the word pointed to by the stack pointer. */
2734 rtx addr
= gen_rtx_POST_MODIFY (Pmode
, stack_pointer_rtx
,
2735 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2737 insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), fp_reg
);
2738 RTX_FRAME_RELATED_P (insn
) = 1;
2740 insn
= emit_insn (gen_addsi3 (hard_frame_pointer_rtx
, stack_pointer_rtx
,
2742 RTX_FRAME_RELATED_P (insn
) = 1;
2747 emit_add_sp_const (initial_offset
- added_already
, true);
2749 if (nsaved
< frame
.nregs
)
2753 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2755 int idx
= N_SAVE_ORDER
- i
- 1;
2756 unsigned regno
= reg_save_order
[idx
];
2758 enum machine_mode save_mode
= SImode
;
2760 if (regno
== REG_A15
&& frame_pointer_needed
)
2761 /* Already saved. */
2763 if (!c6x_save_reg (regno
))
2766 if (TARGET_STDW
&& (off
& 4) == 0 && off
<= 256
2768 && i
+ 1 < N_SAVE_ORDER
2769 && reg_save_order
[idx
- 1] == regno
- 1
2770 && c6x_save_reg (regno
- 1))
2776 reg
= gen_rtx_REG (save_mode
, regno
);
2777 off
-= GET_MODE_SIZE (save_mode
);
2779 insn
= emit_move_insn (adjust_address (mem
, save_mode
, off
),
2781 RTX_FRAME_RELATED_P (insn
) = 1;
2783 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2786 gcc_assert (nsaved
== frame
.nregs
);
2787 emit_add_sp_const (-frame
.to_allocate
- initial_offset
, true);
2788 if (must_reload_pic_reg_p ())
2790 if (dsbt_decl
== NULL
)
2794 t
= build_index_type (integer_one_node
);
2795 t
= build_array_type (integer_type_node
, t
);
2796 t
= build_decl (BUILTINS_LOCATION
, VAR_DECL
,
2797 get_identifier ("__c6xabi_DSBT_BASE"), t
);
2798 DECL_ARTIFICIAL (t
) = 1;
2799 DECL_IGNORED_P (t
) = 1;
2800 DECL_EXTERNAL (t
) = 1;
2801 TREE_STATIC (t
) = 1;
2802 TREE_PUBLIC (t
) = 1;
2807 emit_insn (gen_setup_dsbt (pic_offset_table_rtx
,
2808 XEXP (DECL_RTL (dsbt_decl
), 0)));
2813 c6x_expand_epilogue (bool sibcall
)
2816 struct c6x_frame frame
;
2821 c6x_compute_frame_layout (&frame
);
2823 mem
= gen_frame_mem (Pmode
, stack_pointer_rtx
);
2825 /* Insert a dummy set/use of the stack pointer. This creates a
2826 scheduler barrier between the prologue saves and epilogue restores. */
2827 emit_insn (gen_epilogue_barrier (stack_pointer_rtx
, stack_pointer_rtx
));
2829 /* If the offsets would be too large for the memory references we will
2830 create to restore registers, do a preliminary stack adjustment here. */
2831 off
= frame
.to_allocate
- frame
.frame_pointer_offset
+ frame
.padding1
;
2834 nsaved
= frame
.nregs
;
2838 if (frame
.to_allocate
> 32768)
2840 /* Don't add the entire offset so that we leave an unused word
2841 above the stack pointer. */
2842 emit_add_sp_const ((off
- 16) & ~7, false);
2846 for (i
= 0; i
< N_SAVE_ORDER
; i
++)
2848 unsigned regno
= reg_save_order
[i
];
2850 enum machine_mode save_mode
= SImode
;
2852 if (!c6x_save_reg (regno
))
2854 if (regno
== REG_A15
&& frame_pointer_needed
)
2857 if (TARGET_STDW
&& (off
& 4) == 0 && off
< 256
2859 && i
+ 1 < N_SAVE_ORDER
2860 && reg_save_order
[i
+ 1] == regno
+ 1
2861 && c6x_save_reg (regno
+ 1))
2866 reg
= gen_rtx_REG (save_mode
, regno
);
2868 emit_move_insn (reg
, adjust_address (mem
, save_mode
, off
));
2870 off
+= GET_MODE_SIZE (save_mode
);
2871 nsaved
+= HARD_REGNO_NREGS (regno
, save_mode
);
2874 if (!frame_pointer_needed
)
2875 emit_add_sp_const (off
+ frame
.padding0
- 4, false);
2878 rtx fp_reg
= gen_rtx_REG (SImode
, REG_A15
);
2879 rtx addr
= gen_rtx_PRE_MODIFY (Pmode
, stack_pointer_rtx
,
2880 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2882 emit_insn (gen_addsi3 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
2884 emit_move_insn (fp_reg
, gen_frame_mem (Pmode
, addr
));
2887 gcc_assert (nsaved
== frame
.nregs
);
2891 emit_jump_insn (gen_pop_rts ());
2893 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode
,
2894 RETURN_ADDR_REGNO
)));
2898 /* Return the value of the return address for the frame COUNT steps up
2899 from the current frame, after the prologue.
2900 We punt for everything but the current frame by returning const0_rtx. */
2903 c6x_return_addr_rtx (int count
)
2908 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNO
);
2911 /* Return true iff TYPE is one of the shadow types. */
2913 shadow_type_p (enum attr_type type
)
2915 return (type
== TYPE_SHADOW
|| type
== TYPE_LOAD_SHADOW
2916 || type
== TYPE_MULT_SHADOW
);
2919 /* Return true iff INSN is a shadow pattern. */
2923 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
2925 return shadow_type_p (get_attr_type (insn
));
2928 /* Return true iff INSN is a shadow or blockage pattern. */
2930 shadow_or_blockage_p (rtx insn
)
2932 enum attr_type type
;
2933 if (!NONDEBUG_INSN_P (insn
) || recog_memoized (insn
) < 0)
2935 type
= get_attr_type (insn
);
2936 return shadow_type_p (type
) || type
== TYPE_BLOCKAGE
;
2939 /* Translate UNITS into a bitmask of units we can reserve for this
2942 get_reservation_flags (enum attr_units units
)
2948 return RESERVATION_FLAG_D
;
2950 return RESERVATION_FLAG_L
;
2952 return RESERVATION_FLAG_S
;
2954 return RESERVATION_FLAG_M
;
2956 return RESERVATION_FLAG_LS
;
2958 return RESERVATION_FLAG_DL
;
2960 return RESERVATION_FLAG_DS
;
2962 return RESERVATION_FLAG_DLS
;
2968 /* Compute the side of the machine used by INSN, which reserves UNITS.
2969 This must match the reservations in the scheduling description. */
2971 get_insn_side (rtx insn
, enum attr_units units
)
2973 if (units
== UNITS_D_ADDR
)
2974 return (get_attr_addr_regfile (insn
) == ADDR_REGFILE_A
? 0 : 1);
2977 enum attr_dest_regfile rf
= get_attr_dest_regfile (insn
);
2978 if (rf
== DEST_REGFILE_ANY
)
2979 return get_attr_type (insn
) == TYPE_BRANCH
? 0 : 1;
2981 return rf
== DEST_REGFILE_A
? 0 : 1;
2985 /* After scheduling, walk the insns between HEAD and END and assign unit
2988 assign_reservations (rtx head
, rtx end
)
2991 for (insn
= head
; insn
!= NEXT_INSN (end
); insn
= NEXT_INSN (insn
))
2996 int rsrv_count
[2][4];
2998 if (GET_MODE (insn
) != TImode
)
3001 rsrv
[0] = rsrv
[1] = 0;
3002 memset (rsrv_count
, 0, sizeof rsrv_count
);
3004 /* Walk through the insns that occur in the same cycle. We use multiple
3005 passes to assign units, assigning for insns with the most specific
3006 requirements first. */
3007 for (pass
= 0; pass
< 4; pass
++)
3009 (within
!= NEXT_INSN (end
)
3010 && (within
== insn
|| GET_MODE (within
) != TImode
));
3011 within
= NEXT_INSN (within
))
3013 int this_rsrv
, side
;
3015 enum attr_units units
;
3018 if (!NONDEBUG_INSN_P (within
))
3020 icode
= recog_memoized (within
);
3023 units
= get_attr_units (within
);
3024 this_rsrv
= get_reservation_flags (units
);
3027 side
= get_insn_side (within
, units
);
3029 if ((this_rsrv
& (this_rsrv
- 1)) == 0)
3031 int t
= exact_log2 (this_rsrv
) + side
* 4;
3032 rsrv
[side
] |= this_rsrv
;
3033 INSN_INFO_ENTRY (INSN_UID (within
)).reservation
= t
;
3039 for (j
= 0; j
< 4; j
++)
3040 if (this_rsrv
& (1 << j
))
3041 rsrv_count
[side
][j
]++;
3044 if ((pass
== 2 && this_rsrv
!= RESERVATION_FLAG_DLS
)
3045 || (pass
== 3 && this_rsrv
== RESERVATION_FLAG_DLS
))
3047 int best
= -1, best_cost
= INT_MAX
;
3048 for (j
= 0; j
< 4; j
++)
3049 if ((this_rsrv
& (1 << j
))
3050 && !(rsrv
[side
] & (1 << j
))
3051 && rsrv_count
[side
][j
] < best_cost
)
3053 best_cost
= rsrv_count
[side
][j
];
3056 gcc_assert (best
!= -1);
3057 rsrv
[side
] |= 1 << best
;
3058 for (j
= 0; j
< 4; j
++)
3059 if ((this_rsrv
& (1 << j
)) && j
!= best
)
3060 rsrv_count
[side
][j
]--;
3062 INSN_INFO_ENTRY (INSN_UID (within
)).reservation
3069 /* Backend scheduling state. */
3070 typedef struct c6x_sched_context
3072 /* The current scheduler clock, saved in the sched_reorder hook. */
3073 int curr_sched_clock
;
3075 /* Number of insns issued so far in this cycle. */
3076 int issued_this_cycle
;
3078 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3079 theoretical maximum for number of jumps in flight is 12: 2 every
3080 cycle, with a latency of 6 cycles each. This is a circular
3081 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3082 jumps have a higher index. This array should be accessed through
3083 the jump_cycle function. */
3084 int jump_cycles
[12];
3085 int jump_cycle_index
;
3087 /* In parallel with jump_cycles, this array records the opposite of
3088 the condition used in each pending jump. This is used to
3089 predicate insns that are scheduled in the jump's delay slots. If
3090 this is NULL_RTX no such predication happens. */
3093 /* Similar to the jump_cycles mechanism, but here we take into
3094 account all insns with delay slots, to avoid scheduling asms into
3096 int delays_finished_at
;
3098 /* The following variable value is the last issued insn. */
3099 rtx last_scheduled_insn
;
3101 int reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3102 int reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3103 int reg_set_in_cycle
[FIRST_PSEUDO_REGISTER
];
3105 int tmp_reg_n_accesses
[FIRST_PSEUDO_REGISTER
];
3106 int tmp_reg_n_xaccesses
[FIRST_PSEUDO_REGISTER
];
3107 } *c6x_sched_context_t
;
3109 /* The current scheduling state. */
3110 static struct c6x_sched_context ss
;
3112 /* Set when we discover while processing an insn that it would lead to too
3113 many accesses of the same register. */
3114 static bool reg_access_stall
;
3116 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3117 so the caller does not specifically have to test for it. */
3119 get_jump_cycle (int n
)
3123 n
+= ss
.jump_cycle_index
;
3126 return ss
.jump_cycles
[n
];
3129 /* Look up the jump condition with index N. */
3131 get_jump_cond (int n
)
3135 n
+= ss
.jump_cycle_index
;
3138 return ss
.jump_cond
[n
];
3141 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3142 has delay slots beyond CLOCK_VAR, return -1. */
3144 first_jump_index (int clock_var
)
3150 int t
= get_jump_cycle (n
);
3159 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3160 and has the opposite condition of COND. */
3162 record_jump (int cycle
, rtx cond
)
3164 if (ss
.jump_cycle_index
== 0)
3165 ss
.jump_cycle_index
= 11;
3167 ss
.jump_cycle_index
--;
3168 ss
.jump_cycles
[ss
.jump_cycle_index
] = cycle
;
3169 ss
.jump_cond
[ss
.jump_cycle_index
] = cond
;
3172 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3175 insn_set_clock (rtx insn
, int cycle
)
3177 unsigned uid
= INSN_UID (insn
);
3179 if (uid
>= INSN_INFO_LENGTH
)
3180 VEC_safe_grow (c6x_sched_insn_info
, heap
, insn_info
, uid
* 5 / 4 + 10);
3182 INSN_INFO_ENTRY (uid
).clock
= cycle
;
3183 INSN_INFO_ENTRY (uid
).new_cond
= NULL
;
3184 INSN_INFO_ENTRY (uid
).ebb_start
= false;
3187 /* Return the clock cycle we set for the insn with uid UID. */
3189 insn_uid_get_clock (int uid
)
3191 return INSN_INFO_ENTRY (uid
).clock
;
3194 /* Return the clock cycle we set for INSN. */
3196 insn_get_clock (rtx insn
)
3198 return insn_uid_get_clock (INSN_UID (insn
));
3201 /* Examine INSN, and if it is a conditional jump of any kind, return
3202 the opposite of the condition in which it branches. Otherwise,
3205 condjump_opposite_condition (rtx insn
)
3207 rtx pat
= PATTERN (insn
);
3208 int icode
= INSN_CODE (insn
);
3211 if (icode
== CODE_FOR_br_true
|| icode
== CODE_FOR_br_false
)
3213 x
= XEXP (SET_SRC (pat
), 0);
3214 if (icode
== CODE_FOR_br_false
)
3217 if (GET_CODE (pat
) == COND_EXEC
)
3219 rtx t
= COND_EXEC_CODE (pat
);
3220 if ((GET_CODE (t
) == PARALLEL
3221 && GET_CODE (XVECEXP (t
, 0, 0)) == RETURN
)
3222 || (GET_CODE (t
) == UNSPEC
&& XINT (t
, 1) == UNSPEC_REAL_JUMP
)
3223 || (GET_CODE (t
) == SET
&& SET_DEST (t
) == pc_rtx
))
3224 x
= COND_EXEC_TEST (pat
);
3229 enum rtx_code code
= GET_CODE (x
);
3230 x
= gen_rtx_fmt_ee (code
== EQ
? NE
: EQ
,
3231 GET_MODE (x
), XEXP (x
, 0),
3237 /* Return true iff COND1 and COND2 are exactly opposite conditions
3238 one of them NE and the other EQ. */
3240 conditions_opposite_p (rtx cond1
, rtx cond2
)
3242 return (rtx_equal_p (XEXP (cond1
, 0), XEXP (cond2
, 0))
3243 && rtx_equal_p (XEXP (cond1
, 1), XEXP (cond2
, 1))
3244 && GET_CODE (cond1
) == reverse_condition (GET_CODE (cond2
)));
3247 /* Return true if we can add a predicate COND to INSN, or if INSN
3248 already has that predicate. If DOIT is true, also perform the
3251 predicate_insn (rtx insn
, rtx cond
, bool doit
)
3254 if (cond
== NULL_RTX
)
3260 if (get_attr_predicable (insn
) == PREDICABLE_YES
3261 && GET_CODE (PATTERN (insn
)) != COND_EXEC
)
3265 rtx newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3266 PATTERN (insn
) = newpat
;
3267 INSN_CODE (insn
) = -1;
3271 if (GET_CODE (PATTERN (insn
)) == COND_EXEC
3272 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn
)), cond
))
3274 icode
= INSN_CODE (insn
);
3275 if (icode
== CODE_FOR_real_jump
3276 || icode
== CODE_FOR_jump
3277 || icode
== CODE_FOR_indirect_jump
)
3279 rtx pat
= PATTERN (insn
);
3280 rtx dest
= (icode
== CODE_FOR_real_jump
? XVECEXP (pat
, 0, 0)
3281 : icode
== CODE_FOR_jump
? XEXP (SET_SRC (pat
), 0)
3287 newpat
= gen_rtx_COND_EXEC (VOIDmode
, cond
, PATTERN (insn
));
3289 newpat
= gen_br_true (cond
, XEXP (cond
, 0), dest
);
3290 PATTERN (insn
) = newpat
;
3291 INSN_CODE (insn
) = -1;
3295 if (INSN_CODE (insn
) == CODE_FOR_br_true
)
3297 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3298 return rtx_equal_p (br_cond
, cond
);
3300 if (INSN_CODE (insn
) == CODE_FOR_br_false
)
3302 rtx br_cond
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3303 return conditions_opposite_p (br_cond
, cond
);
3308 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3310 init_sched_state (c6x_sched_context_t sc
)
3312 sc
->last_scheduled_insn
= NULL_RTX
;
3313 sc
->issued_this_cycle
= 0;
3314 memset (sc
->jump_cycles
, 0, sizeof sc
->jump_cycles
);
3315 memset (sc
->jump_cond
, 0, sizeof sc
->jump_cond
);
3316 sc
->jump_cycle_index
= 0;
3317 sc
->delays_finished_at
= 0;
3318 sc
->curr_sched_clock
= 0;
3320 memset (sc
->reg_n_accesses
, 0, sizeof sc
->reg_n_accesses
);
3321 memset (sc
->reg_n_xaccesses
, 0, sizeof sc
->reg_n_xaccesses
);
3322 memset (sc
->reg_set_in_cycle
, 0, sizeof sc
->reg_set_in_cycle
);
3325 /* Allocate store for new scheduling context. */
3327 c6x_alloc_sched_context (void)
3329 return xmalloc (sizeof (struct c6x_sched_context
));
3332 /* If CLEAN_P is true then initializes _SC with clean data,
3333 and from the global context otherwise. */
3335 c6x_init_sched_context (void *_sc
, bool clean_p
)
3337 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3341 init_sched_state (sc
);
3347 /* Sets the global scheduling context to the one pointed to by _SC. */
3349 c6x_set_sched_context (void *_sc
)
3351 c6x_sched_context_t sc
= (c6x_sched_context_t
) _sc
;
3353 gcc_assert (sc
!= NULL
);
3359 c6x_free_sched_context (void *_sc
)
3364 /* Provide information about speculation capabilities, and set the
3365 DO_BACKTRACKING flag. */
3367 c6x_set_sched_flags (spec_info_t spec_info
)
3369 unsigned int *flags
= &(current_sched_info
->flags
);
3371 if (*flags
& SCHED_EBB
)
3373 *flags
|= DO_BACKTRACKING
;
3376 spec_info
->mask
= 0;
3379 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3382 c6x_issue_rate (void)
3387 /* We're beginning a new block. Initialize data structures as necessary. */
3390 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED
,
3391 int sched_verbose ATTRIBUTE_UNUSED
,
3392 int max_ready ATTRIBUTE_UNUSED
)
3394 init_sched_state (&ss
);
3398 c6x_mark_regno_read (int regno
, bool cross
)
3400 int t
= ++ss
.tmp_reg_n_accesses
[regno
];
3403 reg_access_stall
= true;
3407 int set_cycle
= ss
.reg_set_in_cycle
[regno
];
3408 /* This must be done in this way rather than by tweaking things in
3409 adjust_cost, since the stall occurs even for insns with opposite
3410 predicates, and the scheduler may not even see a dependency. */
3411 if (set_cycle
> 0 && set_cycle
== ss
.curr_sched_clock
)
3412 reg_access_stall
= true;
3413 /* This doesn't quite do anything yet as we're only modeling one
3415 ++ss
.tmp_reg_n_xaccesses
[regno
];
3419 /* Note that REG is read in the insn being examined. If CROSS, it
3420 means the access is through a cross path. Update the temporary reg
3421 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
3422 in the current cycle. */
3425 c6x_mark_reg_read (rtx reg
, bool cross
)
3427 unsigned regno
= REGNO (reg
);
3428 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
3431 c6x_mark_regno_read (regno
+ nregs
, cross
);
3434 /* Note that register REG is written in cycle CYCLES. */
3437 c6x_mark_reg_written (rtx reg
, int cycles
)
3439 unsigned regno
= REGNO (reg
);
3440 unsigned nregs
= hard_regno_nregs
[regno
][GET_MODE (reg
)];
3443 ss
.reg_set_in_cycle
[regno
+ nregs
] = cycles
;
3446 /* Update the register state information for an instruction whose
3447 body is X. Return true if the instruction has to be delayed until the
3451 c6x_registers_update (rtx insn
)
3453 enum attr_cross cross
;
3454 enum attr_dest_regfile destrf
;
3458 if (!reload_completed
|| recog_memoized (insn
) < 0)
3461 reg_access_stall
= false;
3462 memcpy (ss
.tmp_reg_n_accesses
, ss
.reg_n_accesses
,
3463 sizeof ss
.tmp_reg_n_accesses
);
3464 memcpy (ss
.tmp_reg_n_xaccesses
, ss
.reg_n_xaccesses
,
3465 sizeof ss
.tmp_reg_n_xaccesses
);
3467 extract_insn (insn
);
3469 cross
= get_attr_cross (insn
);
3470 destrf
= get_attr_dest_regfile (insn
);
3472 nops
= recog_data
.n_operands
;
3474 if (GET_CODE (x
) == COND_EXEC
)
3476 c6x_mark_reg_read (XEXP (XEXP (x
, 0), 0), false);
3480 for (i
= 0; i
< nops
; i
++)
3482 rtx op
= recog_data
.operand
[i
];
3483 if (recog_data
.operand_type
[i
] == OP_OUT
)
3487 bool this_cross
= cross
;
3488 if (destrf
== DEST_REGFILE_A
&& A_REGNO_P (REGNO (op
)))
3490 if (destrf
== DEST_REGFILE_B
&& B_REGNO_P (REGNO (op
)))
3492 c6x_mark_reg_read (op
, this_cross
);
3494 else if (MEM_P (op
))
3497 switch (GET_CODE (op
))
3506 c6x_mark_reg_read (op
, false);
3511 gcc_assert (GET_CODE (op
) == PLUS
);
3514 c6x_mark_reg_read (XEXP (op
, 0), false);
3515 if (REG_P (XEXP (op
, 1)))
3516 c6x_mark_reg_read (XEXP (op
, 1), false);
3521 c6x_mark_regno_read (REG_B14
, false);
3527 else if (!CONSTANT_P (op
) && strlen (recog_data
.constraints
[i
]) > 0)
3530 return reg_access_stall
;
3533 /* Helper function for the TARGET_SCHED_REORDER and
3534 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
3535 in the current cycle, move it down in the ready list and return the
3536 number of non-unsafe insns. */
3539 c6x_sched_reorder_1 (rtx
*ready
, int *pn_ready
, int clock_var
)
3541 int n_ready
= *pn_ready
;
3542 rtx
*e_ready
= ready
+ n_ready
;
3546 /* Keep track of conflicts due to a limit number of register accesses,
3547 and due to stalls incurred by too early accesses of registers using
3550 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
3553 int icode
= recog_memoized (insn
);
3554 bool is_asm
= (icode
< 0
3555 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
3556 || asm_noperands (PATTERN (insn
)) >= 0));
3557 bool no_parallel
= (is_asm
3559 && get_attr_type (insn
) == TYPE_ATOMIC
));
3561 /* We delay asm insns until all delay slots are exhausted. We can't
3562 accurately tell how many cycles an asm takes, and the main scheduling
3563 code always assumes at least 1 cycle, which may be wrong. */
3565 && (ss
.issued_this_cycle
> 0 || clock_var
< ss
.delays_finished_at
))
3566 || c6x_registers_update (insn
))
3568 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
3573 else if (shadow_p (insn
))
3575 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
3580 /* Ensure that no other jump is scheduled in jump delay slots, since
3581 it would put the machine into the wrong state. Also, we must
3582 avoid scheduling insns that have a latency longer than the
3583 remaining jump delay slots, as the code at the jump destination
3584 won't be prepared for it.
3586 However, we can relax this condition somewhat. The rest of the
3587 scheduler will automatically avoid scheduling an insn on which
3588 the jump shadow depends so late that its side effect happens
3589 after the jump. This means that if we see an insn with a longer
3590 latency here, it can safely be scheduled if we can ensure that it
3591 has a predicate opposite of the previous jump: the side effect
3592 will happen in what we think of as the same basic block. In
3593 c6x_variable_issue, we will record the necessary predicate in
3594 new_conditions, and after scheduling is finished, we will modify
3597 Special care must be taken whenever there is more than one jump
3600 first_jump
= first_jump_index (clock_var
);
3601 if (first_jump
!= -1)
3603 int first_cycle
= get_jump_cycle (first_jump
);
3604 rtx first_cond
= get_jump_cond (first_jump
);
3605 int second_cycle
= 0;
3608 second_cycle
= get_jump_cycle (first_jump
- 1);
3610 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
3613 int icode
= recog_memoized (insn
);
3614 bool is_asm
= (icode
< 0
3615 && (GET_CODE (PATTERN (insn
)) == ASM_INPUT
3616 || asm_noperands (PATTERN (insn
)) >= 0));
3618 enum attr_type type
;
3620 gcc_assert (!is_asm
);
3623 this_cycles
= get_attr_cycles (insn
);
3624 type
= get_attr_type (insn
);
3625 /* Treat branches specially; there is also a hazard if two jumps
3626 end at the same cycle. */
3627 if (type
== TYPE_BRANCH
|| type
== TYPE_CALL
)
3629 if (clock_var
+ this_cycles
<= first_cycle
)
3631 if ((first_jump
> 0 && clock_var
+ this_cycles
> second_cycle
)
3632 || !predicate_insn (insn
, first_cond
, false))
3634 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
3645 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
3646 for later and clear the register access information for the new
3647 cycle. We also move asm statements out of the way if they would be
3648 scheduled in a delay slot. */
3651 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED
,
3652 int sched_verbose ATTRIBUTE_UNUSED
,
3653 rtx
*ready ATTRIBUTE_UNUSED
,
3654 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
3656 ss
.curr_sched_clock
= clock_var
;
3657 ss
.issued_this_cycle
= 0;
3658 memset (ss
.reg_n_accesses
, 0, sizeof ss
.reg_n_accesses
);
3659 memset (ss
.reg_n_xaccesses
, 0, sizeof ss
.reg_n_xaccesses
);
3664 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
3667 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
3668 cycle for every insn. */
3671 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED
,
3672 int sched_verbose ATTRIBUTE_UNUSED
,
3673 rtx
*ready ATTRIBUTE_UNUSED
,
3674 int *pn_ready ATTRIBUTE_UNUSED
, int clock_var
)
3676 /* FIXME: the assembler rejects labels inside an execute packet.
3677 This can occur if prologue insns are scheduled in parallel with
3678 others, so we avoid this here. Also make sure that nothing is
3679 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
3680 if (RTX_FRAME_RELATED_P (ss
.last_scheduled_insn
)
3681 || JUMP_P (ss
.last_scheduled_insn
)
3682 || (recog_memoized (ss
.last_scheduled_insn
) >= 0
3683 && get_attr_type (ss
.last_scheduled_insn
) == TYPE_ATOMIC
))
3685 int n_ready
= *pn_ready
;
3686 rtx
*e_ready
= ready
+ n_ready
;
3689 for (insnp
= ready
; insnp
< e_ready
; insnp
++)
3692 if (!shadow_p (insn
))
3694 memmove (ready
+ 1, ready
, (insnp
- ready
) * sizeof (rtx
));
3703 return c6x_sched_reorder_1 (ready
, pn_ready
, clock_var
);
3706 /* Subroutine of maybe_clobber_cond, called through note_stores. */
3709 clobber_cond_1 (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
, void *data1
)
3711 rtx
*cond
= (rtx
*)data1
;
3712 if (*cond
!= NULL_RTX
&& reg_overlap_mentioned_p (x
, *cond
))
3716 /* Examine INSN, and if it destroys the conditions have recorded for
3717 any of the jumps in flight, clear that condition so that we don't
3718 predicate any more insns. CLOCK_VAR helps us limit the search to
3719 only those jumps which are still in flight. */
3722 maybe_clobber_cond (rtx insn
, int clock_var
)
3725 idx
= ss
.jump_cycle_index
;
3726 for (n
= 0; n
< 12; n
++, idx
++)
3733 cycle
= ss
.jump_cycles
[idx
];
3734 if (cycle
<= clock_var
)
3737 cond
= ss
.jump_cond
[idx
];
3738 if (cond
== NULL_RTX
)
3743 ss
.jump_cond
[idx
] = NULL_RTX
;
3747 note_stores (PATTERN (insn
), clobber_cond_1
, ss
.jump_cond
+ idx
);
3748 for (link
= REG_NOTES (insn
); link
; link
= XEXP (link
, 1))
3749 if (REG_NOTE_KIND (link
) == REG_INC
)
3750 clobber_cond_1 (XEXP (link
, 0), NULL_RTX
, ss
.jump_cond
+ idx
);
3754 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
3755 issue INSN. Return the number of insns left on the ready queue
3756 that can be issued this cycle.
3757 We use this hook to record clock cycles and reservations for every insn. */
3760 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED
,
3761 int sched_verbose ATTRIBUTE_UNUSED
,
3762 rtx insn
, int can_issue_more ATTRIBUTE_UNUSED
)
3764 ss
.last_scheduled_insn
= insn
;
3765 if (GET_CODE (PATTERN (insn
)) != USE
&& GET_CODE (PATTERN (insn
)) != CLOBBER
)
3766 ss
.issued_this_cycle
++;
3769 int curr_clock
= ss
.curr_sched_clock
;
3770 int uid
= INSN_UID (insn
);
3771 int icode
= recog_memoized (insn
);
3773 int first
, first_cycle
;
3775 insn_set_clock (insn
, curr_clock
);
3776 INSN_INFO_ENTRY (uid
).ebb_start
3777 = curr_clock
== 0 && ss
.issued_this_cycle
== 1;
3779 first
= first_jump_index (ss
.curr_sched_clock
);
3783 first_cond
= NULL_RTX
;
3787 first_cycle
= get_jump_cycle (first
);
3788 first_cond
= get_jump_cond (first
);
3791 && first_cycle
> curr_clock
3792 && first_cond
!= NULL_RTX
3793 && (curr_clock
+ get_attr_cycles (insn
) > first_cycle
3794 || get_attr_type (insn
) == TYPE_BRANCH
3795 || get_attr_type (insn
) == TYPE_CALL
))
3796 INSN_INFO_ENTRY (uid
).new_cond
= first_cond
;
3798 maybe_clobber_cond (insn
, curr_clock
);
3804 c6x_registers_update (insn
);
3805 memcpy (ss
.reg_n_accesses
, ss
.tmp_reg_n_accesses
,
3806 sizeof ss
.reg_n_accesses
);
3807 memcpy (ss
.reg_n_xaccesses
, ss
.tmp_reg_n_accesses
,
3808 sizeof ss
.reg_n_xaccesses
);
3810 cycles
= get_attr_cycles (insn
);
3811 if (ss
.delays_finished_at
< ss
.curr_sched_clock
+ cycles
)
3812 ss
.delays_finished_at
= ss
.curr_sched_clock
+ cycles
;
3813 if (get_attr_type (insn
) == TYPE_BRANCH
3814 || get_attr_type (insn
) == TYPE_CALL
)
3816 rtx opposite
= condjump_opposite_condition (insn
);
3817 record_jump (ss
.curr_sched_clock
+ cycles
, opposite
);
3820 /* Mark the cycles in which the destination registers are written.
3821 This is used for calculating stalls when using cross units. */
3822 extract_insn (insn
);
3823 /* Cross-path stalls don't apply to results of load insns. */
3824 if (get_attr_type (insn
) == TYPE_LOAD
3825 || get_attr_type (insn
) == TYPE_LOADN
3826 || get_attr_type (insn
) == TYPE_LOAD_SHADOW
)
3828 for (i
= 0; i
< recog_data
.n_operands
; i
++)
3830 rtx op
= recog_data
.operand
[i
];
3833 rtx addr
= XEXP (op
, 0);
3834 if (GET_RTX_CLASS (GET_CODE (addr
)) == RTX_AUTOINC
)
3835 c6x_mark_reg_written (XEXP (addr
, 0),
3836 insn_uid_get_clock (uid
) + 1);
3838 if (recog_data
.operand_type
[i
] != OP_IN
3841 c6x_mark_reg_written (op
,
3842 insn_uid_get_clock (uid
) + cycles
);
3847 return can_issue_more
;
3850 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
3851 anti- and output dependencies. */
3854 c6x_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
3856 enum attr_type insn_type
= TYPE_UNKNOWN
, dep_insn_type
= TYPE_UNKNOWN
;
3857 int dep_insn_code_number
, insn_code_number
;
3858 int shadow_bonus
= 0;
3860 dep_insn_code_number
= recog_memoized (dep_insn
);
3861 insn_code_number
= recog_memoized (insn
);
3863 if (dep_insn_code_number
>= 0)
3864 dep_insn_type
= get_attr_type (dep_insn
);
3866 if (insn_code_number
>= 0)
3867 insn_type
= get_attr_type (insn
);
3869 kind
= REG_NOTE_KIND (link
);
3872 /* If we have a dependency on a load, and it's not for the result of
3873 the load, it must be for an autoincrement. Reduce the cost in that
3875 if (dep_insn_type
== TYPE_LOAD
)
3877 rtx set
= PATTERN (dep_insn
);
3878 if (GET_CODE (set
) == COND_EXEC
)
3879 set
= COND_EXEC_CODE (set
);
3880 if (GET_CODE (set
) == UNSPEC
)
3884 gcc_assert (GET_CODE (set
) == SET
);
3885 if (!reg_overlap_mentioned_p (SET_DEST (set
), PATTERN (insn
)))
3891 /* A jump shadow needs to have its latency decreased by one. Conceptually,
3892 it occurs in between two cycles, but we schedule it at the end of the
3894 if (shadow_type_p (insn_type
))
3897 /* Anti and output dependencies usually have zero cost, but we want
3898 to insert a stall after a jump, and after certain floating point
3899 insns that take more than one cycle to read their inputs. In the
3900 future, we should try to find a better algorithm for scheduling
3904 /* We can get anti-dependencies against shadow insns. Treat these
3905 like output dependencies, so that the insn is entirely finished
3906 before the branch takes place. */
3907 if (kind
== REG_DEP_ANTI
&& insn_type
== TYPE_SHADOW
)
3908 kind
= REG_DEP_OUTPUT
;
3909 switch (dep_insn_type
)
3915 if (get_attr_has_shadow (dep_insn
) == HAS_SHADOW_Y
)
3916 /* This is a real_jump/real_call insn. These don't have
3917 outputs, and ensuring the validity of scheduling things
3918 in the delay slot is the job of
3919 c6x_sched_reorder_1. */
3921 /* Unsplit calls can happen - e.g. for divide insns. */
3926 if (kind
== REG_DEP_OUTPUT
)
3927 return 5 - shadow_bonus
;
3931 if (kind
== REG_DEP_OUTPUT
)
3932 return 4 - shadow_bonus
;
3935 if (kind
== REG_DEP_OUTPUT
)
3936 return 2 - shadow_bonus
;
3939 if (kind
== REG_DEP_OUTPUT
)
3940 return 2 - shadow_bonus
;
3944 if (kind
== REG_DEP_OUTPUT
)
3945 return 7 - shadow_bonus
;
3948 if (kind
== REG_DEP_OUTPUT
)
3949 return 5 - shadow_bonus
;
3952 if (kind
== REG_DEP_OUTPUT
)
3953 return 9 - shadow_bonus
;
3957 if (kind
== REG_DEP_OUTPUT
)
3958 return 10 - shadow_bonus
;
3962 if (insn_type
== TYPE_SPKERNEL
)
3964 if (kind
== REG_DEP_OUTPUT
)
3965 return 1 - shadow_bonus
;
3971 return cost
- shadow_bonus
;
3974 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
3975 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
3976 first in the original stream. */
3979 gen_one_bundle (rtx
*slot
, int n_filled
, int real_first
)
3985 bundle
= gen_rtx_SEQUENCE (VOIDmode
, gen_rtvec_v (n_filled
, slot
));
3986 bundle
= make_insn_raw (bundle
);
3987 BLOCK_FOR_INSN (bundle
) = BLOCK_FOR_INSN (slot
[0]);
3988 INSN_LOCATOR (bundle
) = INSN_LOCATOR (slot
[0]);
3989 PREV_INSN (bundle
) = PREV_INSN (slot
[real_first
]);
3993 for (i
= 0; i
< n_filled
; i
++)
3997 PREV_INSN (insn
) = t
? t
: PREV_INSN (bundle
);
3999 NEXT_INSN (t
) = insn
;
4002 INSN_LOCATOR (slot
[i
]) = INSN_LOCATOR (bundle
);
4005 NEXT_INSN (bundle
) = NEXT_INSN (PREV_INSN (bundle
));
4006 NEXT_INSN (t
) = NEXT_INSN (bundle
);
4007 NEXT_INSN (PREV_INSN (bundle
)) = bundle
;
4008 PREV_INSN (NEXT_INSN (bundle
)) = bundle
;
4011 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4012 try to insert labels in the middle. */
4015 c6x_gen_bundles (void)
4018 rtx insn
, next
, last_call
;
4023 /* The machine is eight insns wide. We can have up to six shadow
4024 insns, plus an extra slot for merging the jump shadow. */
4029 for (insn
= BB_HEAD (bb
);; insn
= next
)
4032 rtx delete_this
= NULL_RTX
;
4034 if (NONDEBUG_INSN_P (insn
))
4036 /* Put calls at the start of the sequence. */
4042 memmove (&slot
[1], &slot
[0],
4043 n_filled
* sizeof (slot
[0]));
4045 if (!shadow_p (insn
))
4047 PUT_MODE (insn
, TImode
);
4049 PUT_MODE (slot
[1], VOIDmode
);
4056 slot
[n_filled
++] = insn
;
4060 next
= NEXT_INSN (insn
);
4061 while (next
&& insn
!= BB_END (bb
)
4062 && !(NONDEBUG_INSN_P (next
)
4063 && GET_CODE (PATTERN (next
)) != USE
4064 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4067 next
= NEXT_INSN (insn
);
4070 at_end
= insn
== BB_END (bb
);
4071 if (delete_this
== NULL_RTX
4072 && (at_end
|| (GET_MODE (next
) == TImode
4073 && !(shadow_p (next
) && CALL_P (next
)))))
4076 gen_one_bundle (slot
, n_filled
, first_slot
);
4085 /* Bundling, and emitting nops, can separate
4086 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4088 last_call
= NULL_RTX
;
4089 for (insn
= get_insns (); insn
; insn
= next
)
4091 next
= NEXT_INSN (insn
);
4093 || (INSN_P (insn
) && GET_CODE (PATTERN (insn
)) == SEQUENCE
4094 && CALL_P (XVECEXP (PATTERN (insn
), 0, 0))))
4096 if (!NOTE_P (insn
) || NOTE_KIND (insn
) != NOTE_INSN_CALL_ARG_LOCATION
)
4098 if (NEXT_INSN (last_call
) == insn
)
4100 NEXT_INSN (PREV_INSN (insn
)) = NEXT_INSN (insn
);
4101 PREV_INSN (NEXT_INSN (insn
)) = PREV_INSN (insn
);
4102 PREV_INSN (insn
) = last_call
;
4103 NEXT_INSN (insn
) = NEXT_INSN (last_call
);
4104 PREV_INSN (NEXT_INSN (insn
)) = insn
;
4105 NEXT_INSN (PREV_INSN (insn
)) = insn
;
4110 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4113 emit_nop_after (int cycles
, rtx after
)
4117 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4118 operation. We don't need the extra NOP since in this case, the hardware
4119 will automatically insert the required stall. */
4123 gcc_assert (cycles
< 10);
4125 insn
= emit_insn_after (gen_nop_count (GEN_INT (cycles
)), after
);
4126 PUT_MODE (insn
, TImode
);
4131 /* Determine whether INSN is a call that needs to have a return label
4135 returning_call_p (rtx insn
)
4138 return (!SIBLING_CALL_P (insn
)
4139 && get_attr_type (insn
) != TYPE_CALLP
4140 && get_attr_type (insn
) != TYPE_SHADOW
);
4141 if (recog_memoized (insn
) < 0)
4143 if (get_attr_type (insn
) == TYPE_CALL
)
4148 /* Determine whether INSN's pattern can be converted to use callp. */
4150 can_use_callp (rtx insn
)
4152 int icode
= recog_memoized (insn
);
4153 if (!TARGET_INSNS_64PLUS
4155 || GET_CODE (PATTERN (insn
)) == COND_EXEC
)
4158 return ((icode
== CODE_FOR_real_call
4159 || icode
== CODE_FOR_call_internal
4160 || icode
== CODE_FOR_call_value_internal
)
4161 && get_attr_dest_regfile (insn
) == DEST_REGFILE_ANY
);
4164 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4166 convert_to_callp (rtx insn
)
4169 extract_insn (insn
);
4170 if (GET_CODE (PATTERN (insn
)) == SET
)
4172 rtx dest
= recog_data
.operand
[0];
4173 lab
= recog_data
.operand
[1];
4174 PATTERN (insn
) = gen_callp_value (dest
, lab
);
4175 INSN_CODE (insn
) = CODE_FOR_callp_value
;
4179 lab
= recog_data
.operand
[0];
4180 PATTERN (insn
) = gen_callp (lab
);
4181 INSN_CODE (insn
) = CODE_FOR_callp
;
4185 /* Scan forwards from INSN until we find the next insn that has mode TImode
4186 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4187 Return it if we find such an insn, NULL_RTX otherwise. */
4189 find_next_cycle_insn (rtx insn
, int clock
)
4192 if (GET_MODE (t
) == TImode
)
4193 t
= next_real_insn (t
);
4194 while (t
&& GET_MODE (t
) != TImode
)
4195 t
= next_real_insn (t
);
4197 if (t
&& insn_get_clock (t
) == clock
)
4202 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4203 around PAT. Return PAT either unchanged or modified in this
4206 duplicate_cond (rtx pat
, rtx cond_insn
)
4208 rtx cond_pat
= PATTERN (cond_insn
);
4209 if (GET_CODE (cond_pat
) == COND_EXEC
)
4210 pat
= gen_rtx_COND_EXEC (VOIDmode
, copy_rtx (COND_EXEC_TEST (cond_pat
)),
4215 /* Walk forward from INSN to find the last insn that issues in the same clock
4218 find_last_same_clock (rtx insn
)
4221 rtx t
= next_real_insn (insn
);
4223 while (t
&& GET_MODE (t
) != TImode
)
4225 if (!DEBUG_INSN_P (t
) && recog_memoized (t
) >= 0)
4227 t
= next_real_insn (t
);
4232 /* For every call insn in the function, emit code to load the return
4233 address. For each call we create a return label and store it in
4234 CALL_LABELS. If are not scheduling, we emit the labels here,
4235 otherwise the caller will do it later.
4236 This function is called after final insn scheduling, but before creating
4237 the SEQUENCEs that represent execute packets. */
4240 reorg_split_calls (rtx
*call_labels
)
4242 unsigned int reservation_mask
= 0;
4243 rtx insn
= get_insns ();
4244 gcc_assert (GET_CODE (insn
) == NOTE
);
4245 insn
= next_real_insn (insn
);
4249 rtx next
= next_real_insn (insn
);
4251 if (DEBUG_INSN_P (insn
))
4254 if (GET_MODE (insn
) == TImode
)
4255 reservation_mask
= 0;
4256 uid
= INSN_UID (insn
);
4257 if (c6x_flag_schedule_insns2
&& recog_memoized (insn
) >= 0)
4258 reservation_mask
|= 1 << INSN_INFO_ENTRY (uid
).reservation
;
4260 if (returning_call_p (insn
))
4262 rtx label
= gen_label_rtx ();
4263 rtx labelref
= gen_rtx_LABEL_REF (Pmode
, label
);
4264 rtx reg
= gen_rtx_REG (SImode
, RETURN_ADDR_REGNO
);
4266 LABEL_NUSES (label
) = 2;
4267 if (!c6x_flag_schedule_insns2
)
4269 if (can_use_callp (insn
))
4270 convert_to_callp (insn
);
4275 emit_label_after (label
, insn
);
4277 /* Bundle the call and its delay slots into a single
4278 SEQUENCE. While these do not issue in parallel
4279 we need to group them into a single EH region. */
4281 PUT_MODE (insn
, TImode
);
4282 if (TARGET_INSNS_64
)
4284 t
= gen_addkpc (reg
, labelref
, GEN_INT (4));
4285 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4287 PUT_MODE (slot
[1], TImode
);
4288 gen_one_bundle (slot
, 2, 0);
4292 slot
[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4294 PUT_MODE (slot
[3], TImode
);
4295 t
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4296 slot
[2] = emit_insn_after (duplicate_cond (t
, insn
),
4298 PUT_MODE (slot
[2], TImode
);
4299 t
= gen_movsi_high (reg
, labelref
);
4300 slot
[1] = emit_insn_after (duplicate_cond (t
, insn
),
4302 PUT_MODE (slot
[1], TImode
);
4303 gen_one_bundle (slot
, 4, 0);
4309 /* If we scheduled, we reserved the .S2 unit for one or two
4310 cycles after the call. Emit the insns in these slots,
4311 unless it's possible to create a CALLP insn.
4312 Note that this works because the dependencies ensure that
4313 no insn setting/using B3 is scheduled in the delay slots of
4315 int this_clock
= insn_get_clock (insn
);
4316 rtx last_same_clock
;
4319 call_labels
[INSN_UID (insn
)] = label
;
4321 last_same_clock
= find_last_same_clock (insn
);
4323 if (can_use_callp (insn
))
4325 /* Find the first insn of the next execute packet. If it
4326 is outside the branch delay slots of this call, we may
4327 use a CALLP insn. */
4328 rtx next_cycle_start
= next_nonnote_nondebug_insn (last_same_clock
);
4330 if (CALL_P (next_cycle_start
)
4331 && (insn_get_clock (next_cycle_start
) == this_clock
+ 5))
4333 convert_to_callp (next_cycle_start
);
4334 insn_set_clock (next_cycle_start
, this_clock
);
4335 if (GET_MODE (insn
) == TImode
)
4337 rtx new_cycle_first
= NEXT_INSN (insn
);
4338 while (!NONDEBUG_INSN_P (new_cycle_first
)
4339 || GET_CODE (PATTERN (new_cycle_first
)) == USE
4340 || GET_CODE (PATTERN (new_cycle_first
)) == CLOBBER
)
4341 new_cycle_first
= NEXT_INSN (new_cycle_first
);
4342 PUT_MODE (new_cycle_first
, TImode
);
4343 if (new_cycle_first
!= next_cycle_start
)
4344 PUT_MODE (next_cycle_start
, VOIDmode
);
4345 INSN_INFO_ENTRY (INSN_UID (new_cycle_first
)).ebb_start
4346 = INSN_INFO_ENTRY (INSN_UID (insn
)).ebb_start
;
4349 PUT_MODE (next_cycle_start
, VOIDmode
);
4354 after1
= find_next_cycle_insn (last_same_clock
, this_clock
+ 1);
4355 if (after1
== NULL_RTX
)
4356 after1
= last_same_clock
;
4358 after1
= find_last_same_clock (after1
);
4359 if (TARGET_INSNS_64
)
4361 rtx x1
= gen_addkpc (reg
, labelref
, const0_rtx
);
4362 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
4363 insn_set_clock (x1
, this_clock
+ 1);
4364 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
4365 if (after1
== last_same_clock
)
4366 PUT_MODE (x1
, TImode
);
4371 rtx after2
= find_next_cycle_insn (after1
, this_clock
+ 2);
4372 if (after2
== NULL_RTX
)
4374 x2
= gen_movsi_lo_sum (reg
, reg
, labelref
);
4375 x2
= emit_insn_after (duplicate_cond (x2
, insn
), after2
);
4376 x1
= gen_movsi_high (reg
, labelref
);
4377 x1
= emit_insn_after (duplicate_cond (x1
, insn
), after1
);
4378 insn_set_clock (x1
, this_clock
+ 1);
4379 insn_set_clock (x2
, this_clock
+ 2);
4380 INSN_INFO_ENTRY (INSN_UID (x1
)).reservation
= RESERVATION_S2
;
4381 INSN_INFO_ENTRY (INSN_UID (x2
)).reservation
= RESERVATION_S2
;
4382 if (after1
== last_same_clock
)
4383 PUT_MODE (x1
, TImode
);
4384 if (after1
== after2
)
4385 PUT_MODE (x2
, TImode
);
4394 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
4395 insns as required for correctness. CALL_LABELS is the array that
4396 holds the return labels for call insns; we emit these here if
4397 scheduling was run earlier. */
4400 reorg_emit_nops (rtx
*call_labels
)
4403 rtx prev
, last_call
;
4404 int prev_clock
, earliest_bb_end
;
4405 int prev_implicit_nops
;
4406 rtx insn
= get_insns ();
4408 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
4409 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
4410 clocks, we must insert a NOP.
4411 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
4412 current basic block will finish. We must not allow the next basic block to
4413 begin before this cycle.
4414 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
4415 a multi-cycle nop. The code is scheduled such that subsequent insns will
4416 show the cycle gap, but we needn't insert a real NOP instruction. */
4417 insn
= next_real_insn (insn
);
4418 last_call
= prev
= NULL_RTX
;
4420 earliest_bb_end
= 0;
4421 prev_implicit_nops
= 0;
4425 int this_clock
= -1;
4429 next
= next_real_insn (insn
);
4431 if (DEBUG_INSN_P (insn
)
4432 || GET_CODE (PATTERN (insn
)) == USE
4433 || GET_CODE (PATTERN (insn
)) == CLOBBER
4434 || shadow_or_blockage_p (insn
)
4436 && (GET_CODE (PATTERN (insn
)) == ADDR_DIFF_VEC
4437 || GET_CODE (PATTERN (insn
)) == ADDR_VEC
)))
4440 if (!c6x_flag_schedule_insns2
)
4441 /* No scheduling; ensure that no parallel issue happens. */
4442 PUT_MODE (insn
, TImode
);
4447 this_clock
= insn_get_clock (insn
);
4448 if (this_clock
!= prev_clock
)
4450 PUT_MODE (insn
, TImode
);
4454 cycles
= this_clock
- prev_clock
;
4456 cycles
-= prev_implicit_nops
;
4459 rtx nop
= emit_nop_after (cycles
- 1, prev
);
4460 insn_set_clock (nop
, prev_clock
+ prev_implicit_nops
+ 1);
4463 prev_clock
= this_clock
;
4466 && insn_get_clock (last_call
) + 6 <= this_clock
)
4468 emit_label_before (call_labels
[INSN_UID (last_call
)], insn
);
4469 last_call
= NULL_RTX
;
4471 prev_implicit_nops
= 0;
4475 /* Examine how many cycles the current insn takes, and adjust
4476 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
4477 if (recog_memoized (insn
) >= 0
4478 /* If not scheduling, we've emitted NOPs after calls already. */
4479 && (c6x_flag_schedule_insns2
|| !returning_call_p (insn
)))
4481 max_cycles
= get_attr_cycles (insn
);
4482 if (get_attr_type (insn
) == TYPE_CALLP
)
4483 prev_implicit_nops
= 5;
4487 if (returning_call_p (insn
))
4490 if (c6x_flag_schedule_insns2
)
4492 gcc_assert (this_clock
>= 0);
4493 if (earliest_bb_end
< this_clock
+ max_cycles
)
4494 earliest_bb_end
= this_clock
+ max_cycles
;
4496 else if (max_cycles
> 1)
4497 emit_nop_after (max_cycles
- 1, insn
);
4503 if (c6x_flag_schedule_insns2
4504 && (next
== NULL_RTX
4505 || (GET_MODE (next
) == TImode
4506 && INSN_INFO_ENTRY (INSN_UID (next
)).ebb_start
))
4507 && earliest_bb_end
> 0)
4509 int cycles
= earliest_bb_end
- prev_clock
;
4512 prev
= emit_nop_after (cycles
- 1, prev
);
4513 insn_set_clock (prev
, prev_clock
+ prev_implicit_nops
+ 1);
4515 earliest_bb_end
= 0;
4520 emit_label_after (call_labels
[INSN_UID (last_call
)], prev
);
4521 last_call
= NULL_RTX
;
4527 /* If possible, split INSN, which we know is either a jump or a call, into a real
4528 insn and its shadow. */
4530 split_delayed_branch (rtx insn
)
4532 int code
= recog_memoized (insn
);
4534 rtx pat
= PATTERN (insn
);
4536 if (GET_CODE (pat
) == COND_EXEC
)
4537 pat
= COND_EXEC_CODE (pat
);
4541 rtx src
= pat
, dest
= NULL_RTX
;
4543 if (GET_CODE (pat
) == SET
)
4545 dest
= SET_DEST (pat
);
4546 src
= SET_SRC (pat
);
4548 callee
= XEXP (XEXP (src
, 0), 0);
4549 if (SIBLING_CALL_P (insn
))
4552 newpat
= gen_indirect_sibcall_shadow ();
4554 newpat
= gen_sibcall_shadow (callee
);
4555 pat
= gen_real_jump (callee
);
4557 else if (dest
!= NULL_RTX
)
4560 newpat
= gen_indirect_call_value_shadow (dest
);
4562 newpat
= gen_call_value_shadow (dest
, callee
);
4563 pat
= gen_real_call (callee
);
4568 newpat
= gen_indirect_call_shadow ();
4570 newpat
= gen_call_shadow (callee
);
4571 pat
= gen_real_call (callee
);
4573 pat
= duplicate_cond (pat
, insn
);
4574 newpat
= duplicate_cond (newpat
, insn
);
4579 if (GET_CODE (pat
) == PARALLEL
4580 && GET_CODE (XVECEXP (pat
, 0, 0)) == RETURN
)
4582 newpat
= gen_return_shadow ();
4583 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
4584 newpat
= duplicate_cond (newpat
, insn
);
4589 case CODE_FOR_br_true
:
4590 case CODE_FOR_br_false
:
4591 src
= SET_SRC (pat
);
4592 op
= XEXP (src
, code
== CODE_FOR_br_true
? 1 : 2);
4593 newpat
= gen_condjump_shadow (op
);
4594 pat
= gen_real_jump (op
);
4595 if (code
== CODE_FOR_br_true
)
4596 pat
= gen_rtx_COND_EXEC (VOIDmode
, XEXP (src
, 0), pat
);
4598 pat
= gen_rtx_COND_EXEC (VOIDmode
,
4599 reversed_comparison (XEXP (src
, 0),
4606 newpat
= gen_jump_shadow (op
);
4609 case CODE_FOR_indirect_jump
:
4610 newpat
= gen_indirect_jump_shadow ();
4613 case CODE_FOR_return_internal
:
4614 newpat
= gen_return_shadow ();
4615 pat
= gen_real_ret (XEXP (XVECEXP (pat
, 0, 1), 0));
4622 i1
= emit_insn_before (pat
, insn
);
4623 PATTERN (insn
) = newpat
;
4624 INSN_CODE (insn
) = -1;
4625 record_delay_slot_pair (i1
, insn
, 5);
4628 /* Split every insn (i.e. jumps and calls) which can have delay slots into
4629 two parts: the first one is scheduled normally and emits the instruction,
4630 while the second one is a shadow insn which shows the side effect taking
4631 place. The second one is placed in the right cycle by the scheduler, but
4632 not emitted as an assembly instruction. */
4635 split_delayed_insns (void)
4638 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4640 if (JUMP_P (insn
) || CALL_P (insn
))
4641 split_delayed_branch (insn
);
4645 /* For every insn that has an entry in the new_conditions vector, give it
4646 the appropriate predicate. */
4648 conditionalize_after_sched (void)
4653 FOR_BB_INSNS (bb
, insn
)
4655 unsigned uid
= INSN_UID (insn
);
4657 if (!NONDEBUG_INSN_P (insn
) || uid
>= INSN_INFO_LENGTH
)
4659 cond
= INSN_INFO_ENTRY (uid
).new_cond
;
4660 if (cond
== NULL_RTX
)
4663 fprintf (dump_file
, "Conditionalizing insn %d\n", uid
);
4664 predicate_insn (insn
, cond
, true);
4668 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
4669 into a sequence that loads the return register and performs the call,
4670 and emit the return label.
4671 If scheduling after reload is requested, it happens here. */
4678 bool do_selsched
= (c6x_flag_schedule_insns2
&& flag_selective_scheduling2
4679 && !maybe_skip_selective_scheduling ());
4681 /* We are freeing block_for_insn in the toplev to keep compatibility
4682 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4683 compute_bb_for_insn ();
4685 df_clear_flags (DF_LR_RUN_DCE
);
4687 /* If optimizing, we'll have split before scheduling. */
4691 if (c6x_flag_schedule_insns2
)
4693 int sz
= get_max_uid () * 3 / 2 + 1;
4695 insn_info
= VEC_alloc (c6x_sched_insn_info
, heap
, sz
);
4697 /* Make sure the real-jump insns we create are not deleted. */
4698 sched_no_dce
= true;
4700 split_delayed_insns ();
4701 timevar_push (TV_SCHED2
);
4703 run_selective_scheduling ();
4706 conditionalize_after_sched ();
4707 timevar_pop (TV_SCHED2
);
4709 free_delay_pairs ();
4710 sched_no_dce
= false;
4713 call_labels
= XCNEWVEC (rtx
, get_max_uid () + 1);
4715 reorg_split_calls (call_labels
);
4717 if (c6x_flag_schedule_insns2
)
4720 if ((bb
->flags
& BB_DISABLE_SCHEDULE
) == 0)
4721 assign_reservations (BB_HEAD (bb
), BB_END (bb
));
4724 if (c6x_flag_var_tracking
)
4726 timevar_push (TV_VAR_TRACKING
);
4727 variable_tracking_main ();
4728 timevar_pop (TV_VAR_TRACKING
);
4731 reorg_emit_nops (call_labels
);
4733 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
4734 if (c6x_flag_schedule_insns2
)
4736 free_delay_pairs ();
4740 df_finish_pass (false);
4743 /* Called when a function has been assembled. It should perform all the
4744 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
4746 We free the reservation (and other scheduling) information here now that
4747 all insns have been output. */
4749 c6x_function_end (FILE *file
, const char *fname
)
4751 c6x_output_fn_unwind (file
);
4754 VEC_free (c6x_sched_insn_info
, heap
, insn_info
);
4757 if (!flag_inhibit_size_directive
)
4758 ASM_OUTPUT_MEASURED_SIZE (file
, fname
);
4761 /* Determine whether X is a shift with code CODE and an integer amount
4764 shift_p (rtx x
, enum rtx_code code
, int amount
)
4766 return (GET_CODE (x
) == code
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
4767 && INTVAL (XEXP (x
, 1)) == amount
);
4770 /* Compute a (partial) cost for rtx X. Return true if the complete
4771 cost has been computed, and false if subexpressions should be
4772 scanned. In either case, *TOTAL contains the cost result. */
4775 c6x_rtx_costs (rtx x
, int code
, int outer_code
, int *total
, bool speed
)
4777 int cost2
= COSTS_N_INSNS (1);
4783 if (outer_code
== SET
|| outer_code
== PLUS
)
4784 *total
= satisfies_constraint_IsB (x
) ? 0 : cost2
;
4785 else if (outer_code
== AND
|| outer_code
== IOR
|| outer_code
== XOR
4786 || outer_code
== MINUS
)
4787 *total
= satisfies_constraint_Is5 (x
) ? 0 : cost2
;
4788 else if (GET_RTX_CLASS (outer_code
) == RTX_COMPARE
4789 || GET_RTX_CLASS (outer_code
) == RTX_COMM_COMPARE
)
4790 *total
= satisfies_constraint_Iu4 (x
) ? 0 : cost2
;
4791 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
4792 || outer_code
== LSHIFTRT
)
4793 *total
= satisfies_constraint_Iu5 (x
) ? 0 : cost2
;
4802 *total
= COSTS_N_INSNS (2);
4806 /* Recognize a mult_highpart operation. */
4807 if ((GET_MODE (x
) == HImode
|| GET_MODE (x
) == SImode
)
4808 && GET_CODE (XEXP (x
, 0)) == LSHIFTRT
4809 && GET_MODE (XEXP (x
, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x
))
4810 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
4811 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
4812 && INTVAL (XEXP (XEXP (x
, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x
)))
4814 rtx mul
= XEXP (XEXP (x
, 0), 0);
4815 rtx op0
= XEXP (mul
, 0);
4816 rtx op1
= XEXP (mul
, 1);
4817 enum rtx_code code0
= GET_CODE (op0
);
4818 enum rtx_code code1
= GET_CODE (op1
);
4821 && (code0
== SIGN_EXTEND
|| code0
== ZERO_EXTEND
))
4822 || (GET_MODE (x
) == HImode
4823 && code0
== ZERO_EXTEND
&& code1
== SIGN_EXTEND
))
4825 if (GET_MODE (x
) == HImode
)
4826 *total
= COSTS_N_INSNS (2);
4828 *total
= COSTS_N_INSNS (12);
4829 *total
+= rtx_cost (XEXP (op0
, 0), code0
, speed
);
4830 *total
+= rtx_cost (XEXP (op1
, 0), code1
, speed
);
4839 if (GET_MODE (x
) == DImode
)
4840 *total
= COSTS_N_INSNS (CONSTANT_P (XEXP (x
, 1)) ? 4 : 15);
4842 *total
= COSTS_N_INSNS (1);
4847 *total
= COSTS_N_INSNS (1);
4848 op0
= code
== PLUS
? XEXP (x
, 0) : XEXP (x
, 1);
4849 op1
= code
== PLUS
? XEXP (x
, 1) : XEXP (x
, 0);
4850 if (GET_MODE_SIZE (GET_MODE (x
)) <= UNITS_PER_WORD
4851 && INTEGRAL_MODE_P (GET_MODE (x
))
4852 && GET_CODE (op0
) == MULT
4853 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
4854 && (INTVAL (XEXP (op0
, 1)) == 2
4855 || INTVAL (XEXP (op0
, 1)) == 4
4856 || (code
== PLUS
&& INTVAL (XEXP (op0
, 1)) == 8)))
4858 *total
+= rtx_cost (XEXP (op0
, 0), ASHIFT
, speed
);
4859 *total
+= rtx_cost (op1
, (enum rtx_code
)code
, speed
);
4867 if (GET_MODE (x
) == DFmode
)
4870 *total
= COSTS_N_INSNS (speed
? 10 : 1);
4872 *total
= COSTS_N_INSNS (speed
? 200 : 4);
4874 else if (GET_MODE (x
) == SFmode
)
4877 *total
= COSTS_N_INSNS (speed
? 4 : 1);
4879 *total
= COSTS_N_INSNS (speed
? 100 : 4);
4881 else if (GET_MODE (x
) == DImode
)
4884 && GET_CODE (op0
) == GET_CODE (op1
)
4885 && (GET_CODE (op0
) == ZERO_EXTEND
4886 || GET_CODE (op0
) == SIGN_EXTEND
))
4888 *total
= COSTS_N_INSNS (speed
? 2 : 1);
4889 op0
= XEXP (op0
, 0);
4890 op1
= XEXP (op1
, 0);
4893 /* Maybe improve this laster. */
4894 *total
= COSTS_N_INSNS (20);
4896 else if (GET_MODE (x
) == SImode
)
4898 if (((GET_CODE (op0
) == ZERO_EXTEND
4899 || GET_CODE (op0
) == SIGN_EXTEND
4900 || shift_p (op0
, LSHIFTRT
, 16))
4901 && (GET_CODE (op1
) == SIGN_EXTEND
4902 || GET_CODE (op1
) == ZERO_EXTEND
4903 || scst5_operand (op1
, SImode
)
4904 || shift_p (op1
, ASHIFTRT
, 16)
4905 || shift_p (op1
, LSHIFTRT
, 16)))
4906 || (shift_p (op0
, ASHIFTRT
, 16)
4907 && (GET_CODE (op1
) == SIGN_EXTEND
4908 || shift_p (op1
, ASHIFTRT
, 16))))
4910 *total
= COSTS_N_INSNS (speed
? 2 : 1);
4911 op0
= XEXP (op0
, 0);
4912 if (scst5_operand (op1
, SImode
))
4915 op1
= XEXP (op1
, 0);
4918 *total
= COSTS_N_INSNS (1);
4919 else if (TARGET_MPY32
)
4920 *total
= COSTS_N_INSNS (4);
4922 *total
= COSTS_N_INSNS (6);
4924 else if (GET_MODE (x
) == HImode
)
4925 *total
= COSTS_N_INSNS (speed
? 2 : 1);
4927 if (GET_CODE (op0
) != REG
4928 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
4929 *total
+= rtx_cost (op0
, MULT
, speed
);
4930 if (op1
&& GET_CODE (op1
) != REG
4931 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
4932 *total
+= rtx_cost (op1
, MULT
, speed
);
4937 /* This is a bit random; assuming on average there'll be 16 leading
4938 zeros. FIXME: estimate better for constant dividends. */
4939 *total
= COSTS_N_INSNS (6 + 3 * 16);
4943 /* Recognize the cmp_and/ior patterns. */
4945 if ((GET_CODE (op0
) == EQ
|| GET_CODE (op0
) == NE
)
4946 && REG_P (XEXP (op0
, 0))
4947 && XEXP (op0
, 1) == const0_rtx
4948 && rtx_equal_p (XEXP (x
, 1), XEXP (op0
, 0)))
4950 *total
= rtx_cost (XEXP (x
, 1), (enum rtx_code
)outer_code
, speed
);
4960 /* Implements target hook vector_mode_supported_p. */
4963 c6x_vector_mode_supported_p (enum machine_mode mode
)
4978 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
4979 static enum machine_mode
4980 c6x_preferred_simd_mode (enum machine_mode mode
)
4994 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
4997 c6x_scalar_mode_supported_p (enum machine_mode mode
)
4999 if (ALL_FIXED_POINT_MODE_P (mode
)
5000 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
5003 return default_scalar_mode_supported_p (mode
);
5006 /* Output a reference from a function exception table to the type_info
5007 object X. Output these via a special assembly directive. */
5010 c6x_output_ttype (rtx x
)
5012 /* Use special relocations for symbol references. */
5013 if (GET_CODE (x
) != CONST_INT
)
5014 fputs ("\t.ehtype\t", asm_out_file
);
5016 fputs ("\t.word\t", asm_out_file
);
5017 output_addr_const (asm_out_file
, x
);
5018 fputc ('\n', asm_out_file
);
5023 /* Modify the return address of the current function. */
5026 c6x_set_return_address (rtx source
, rtx scratch
)
5028 struct c6x_frame frame
;
5030 HOST_WIDE_INT offset
;
5032 c6x_compute_frame_layout (&frame
);
5033 if (! c6x_save_reg (RETURN_ADDR_REGNO
))
5034 emit_move_insn (gen_rtx_REG (Pmode
, RETURN_ADDR_REGNO
), source
);
5038 if (frame_pointer_needed
)
5040 addr
= hard_frame_pointer_rtx
;
5041 offset
= frame
.b3_offset
;
5045 addr
= stack_pointer_rtx
;
5046 offset
= frame
.to_allocate
- frame
.b3_offset
;
5049 /* TODO: Use base+offset loads where possible. */
5052 HOST_WIDE_INT low
= trunc_int_for_mode (offset
, HImode
);
5054 emit_insn (gen_movsi_high (scratch
, GEN_INT (low
)));
5056 emit_insn (gen_movsi_lo_sum (scratch
, scratch
, GEN_INT(offset
)));
5057 emit_insn (gen_addsi3 (scratch
, addr
, scratch
));
5061 emit_move_insn (gen_frame_mem (Pmode
, addr
), source
);
5065 /* We save pairs of registers using a DImode store. Describe the component
5066 registers for DWARF generation code. */
5069 c6x_dwarf_register_span (rtx rtl
)
5072 unsigned real_regno
;
5077 regno
= REGNO (rtl
);
5078 nregs
= HARD_REGNO_NREGS (regno
, GET_MODE (rtl
));
5082 p
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc(nregs
));
5083 for (i
= 0; i
< nregs
; i
++)
5085 if (TARGET_BIG_ENDIAN
)
5086 real_regno
= regno
+ nregs
- (i
+ 1);
5088 real_regno
= regno
+ i
;
5090 XVECEXP (p
, 0, i
) = gen_rtx_REG (SImode
, real_regno
);
5096 /* Codes for all the C6X builtins. */
5131 static GTY(()) tree c6x_builtin_decls
[C6X_BUILTIN_MAX
];
5133 /* Return the C6X builtin for CODE. */
5135 c6x_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
5137 if (code
>= C6X_BUILTIN_MAX
)
5138 return error_mark_node
;
5140 return c6x_builtin_decls
[code
];
5143 #define def_builtin(NAME, TYPE, CODE) \
5146 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5148 c6x_builtin_decls[CODE] = bdecl; \
5151 /* Set up all builtin functions for this target. */
5153 c6x_init_builtins (void)
5155 tree V4QI_type_node
= build_vector_type (unsigned_intQI_type_node
, 4);
5156 tree V2HI_type_node
= build_vector_type (intHI_type_node
, 2);
5157 tree V2SI_type_node
= build_vector_type (intSI_type_node
, 2);
5159 = build_function_type_list (integer_type_node
, integer_type_node
,
5161 tree int_ftype_int_int
5162 = build_function_type_list (integer_type_node
, integer_type_node
,
5163 integer_type_node
, NULL_TREE
);
5164 tree v2hi_ftype_v2hi
5165 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5166 tree v4qi_ftype_v4qi_v4qi
5167 = build_function_type_list (V4QI_type_node
, V4QI_type_node
,
5168 V4QI_type_node
, NULL_TREE
);
5169 tree v2hi_ftype_v2hi_v2hi
5170 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5171 V2HI_type_node
, NULL_TREE
);
5172 tree v2si_ftype_v2hi_v2hi
5173 = build_function_type_list (V2SI_type_node
, V2HI_type_node
,
5174 V2HI_type_node
, NULL_TREE
);
5176 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int
,
5178 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int
,
5180 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi
,
5182 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi
,
5184 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi
,
5186 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi
,
5188 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi
,
5190 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi
,
5192 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi
,
5194 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi
,
5195 C6X_BUILTIN_SADDU4
);
5196 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi
,
5199 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int
,
5201 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int
,
5203 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int
,
5204 C6X_BUILTIN_SMPYHL
);
5205 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int
,
5206 C6X_BUILTIN_SMPYLH
);
5208 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int
,
5210 def_builtin ("__builtin_c6x_subc", int_ftype_int_int
,
5213 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi
,
5215 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi
,
5218 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int
,
5220 def_builtin ("__builtin_c6x_extr", int_ftype_int_int
,
5222 def_builtin ("__builtin_c6x_extru", int_ftype_int_int
,
5225 def_builtin ("__builtin_c6x_abs", int_ftype_int
, C6X_BUILTIN_ABS
);
5226 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi
, C6X_BUILTIN_ABS2
);
5230 struct builtin_description
5232 const enum insn_code icode
;
5233 const char *const name
;
5234 const enum c6x_builtins code
;
5237 static const struct builtin_description bdesc_2arg
[] =
5239 { CODE_FOR_saddsi3
, "__builtin_c6x_sadd", C6X_BUILTIN_SADD
},
5240 { CODE_FOR_ssubsi3
, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB
},
5241 { CODE_FOR_addv2hi3
, "__builtin_c6x_add2", C6X_BUILTIN_ADD2
},
5242 { CODE_FOR_subv2hi3
, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2
},
5243 { CODE_FOR_addv4qi3
, "__builtin_c6x_add4", C6X_BUILTIN_ADD4
},
5244 { CODE_FOR_subv4qi3
, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4
},
5245 { CODE_FOR_ss_addv2hi3
, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2
},
5246 { CODE_FOR_ss_subv2hi3
, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2
},
5247 { CODE_FOR_us_addv4qi3
, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4
},
5249 { CODE_FOR_subcsi3
, "__builtin_c6x_subc", C6X_BUILTIN_SUBC
},
5250 { CODE_FOR_ss_ashlsi3
, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL
},
5252 { CODE_FOR_avgv2hi3
, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2
},
5253 { CODE_FOR_uavgv4qi3
, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4
},
5255 { CODE_FOR_mulhqsq3
, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY
},
5256 { CODE_FOR_mulhqsq3_hh
, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH
},
5257 { CODE_FOR_mulhqsq3_lh
, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH
},
5258 { CODE_FOR_mulhqsq3_hl
, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL
},
5260 { CODE_FOR_mulv2hqv2sq3
, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2
},
5262 { CODE_FOR_clrr
, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR
},
5263 { CODE_FOR_extr
, "__builtin_c6x_extr", C6X_BUILTIN_EXTR
},
5264 { CODE_FOR_extru
, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU
}
5267 static const struct builtin_description bdesc_1arg
[] =
5269 { CODE_FOR_ssabssi2
, "__builtin_c6x_abs", C6X_BUILTIN_ABS
},
5270 { CODE_FOR_ssabsv2hi2
, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2
}
5273 /* Errors in the source file can cause expand_expr to return const0_rtx
5274 where we expect a vector. To avoid crashing, use one of the vector
5275 clear instructions. */
5277 safe_vector_operand (rtx x
, enum machine_mode mode
)
5279 if (x
!= const0_rtx
)
5281 x
= gen_reg_rtx (SImode
);
5283 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
5284 return gen_lowpart (mode
, x
);
5287 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
5288 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5291 c6x_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
5294 int offs
= match_op
? 1 : 0;
5296 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5297 tree arg1
= CALL_EXPR_ARG (exp
, 1);
5298 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
5299 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
5300 enum machine_mode op0mode
= GET_MODE (op0
);
5301 enum machine_mode op1mode
= GET_MODE (op1
);
5302 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5303 enum machine_mode mode0
= insn_data
[icode
].operand
[1 + offs
].mode
;
5304 enum machine_mode mode1
= insn_data
[icode
].operand
[2 + offs
].mode
;
5307 if (VECTOR_MODE_P (mode0
))
5308 op0
= safe_vector_operand (op0
, mode0
);
5309 if (VECTOR_MODE_P (mode1
))
5310 op1
= safe_vector_operand (op1
, mode1
);
5313 || GET_MODE (target
) != tmode
5314 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5316 if (tmode
== SQmode
|| tmode
== V2SQmode
)
5318 ret
= gen_reg_rtx (tmode
== SQmode
? SImode
: V2SImode
);
5319 target
= gen_lowpart (tmode
, ret
);
5322 target
= gen_reg_rtx (tmode
);
5325 if ((op0mode
== V2HImode
|| op0mode
== SImode
|| op0mode
== VOIDmode
)
5326 && (mode0
== V2HQmode
|| mode0
== HQmode
|| mode0
== SQmode
))
5329 op0
= gen_lowpart (mode0
, op0
);
5331 if ((op1mode
== V2HImode
|| op1mode
== SImode
|| op1mode
== VOIDmode
)
5332 && (mode1
== V2HQmode
|| mode1
== HQmode
|| mode1
== SQmode
))
5335 op1
= gen_lowpart (mode1
, op1
);
5337 /* In case the insn wants input operands in modes different from
5338 the result, abort. */
5339 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
5340 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
5342 if (! (*insn_data
[icode
].operand
[1 + offs
].predicate
) (op0
, mode0
))
5343 op0
= copy_to_mode_reg (mode0
, op0
);
5344 if (! (*insn_data
[icode
].operand
[2 + offs
].predicate
) (op1
, mode1
))
5345 op1
= copy_to_mode_reg (mode1
, op1
);
5348 pat
= GEN_FCN (icode
) (target
, target
, op0
, op1
);
5350 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
5360 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
5363 c6x_expand_unop_builtin (enum insn_code icode
, tree exp
,
5367 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5368 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, EXPAND_NORMAL
);
5369 enum machine_mode op0mode
= GET_MODE (op0
);
5370 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5371 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5374 || GET_MODE (target
) != tmode
5375 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5376 target
= gen_reg_rtx (tmode
);
5378 if (VECTOR_MODE_P (mode0
))
5379 op0
= safe_vector_operand (op0
, mode0
);
5381 if (op0mode
== SImode
&& mode0
== HImode
)
5384 op0
= gen_lowpart (HImode
, op0
);
5386 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
5388 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5389 op0
= copy_to_mode_reg (mode0
, op0
);
5391 pat
= GEN_FCN (icode
) (target
, op0
);
5398 /* Expand an expression EXP that calls a built-in function,
5399 with result going to TARGET if that's convenient
5400 (and in mode MODE if that's convenient).
5401 SUBTARGET may be used as the target for computing one of EXP's operands.
5402 IGNORE is nonzero if the value is to be ignored. */
5405 c6x_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
5406 rtx subtarget ATTRIBUTE_UNUSED
,
5407 enum machine_mode mode ATTRIBUTE_UNUSED
,
5408 int ignore ATTRIBUTE_UNUSED
)
5411 const struct builtin_description
*d
;
5412 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
5413 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
5415 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
5416 if (d
->code
== fcode
)
5417 return c6x_expand_binop_builtin (d
->icode
, exp
, target
,
5418 fcode
== C6X_BUILTIN_CLRR
);
5420 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
5421 if (d
->code
== fcode
)
5422 return c6x_expand_unop_builtin (d
->icode
, exp
, target
);
5427 /* Target Structure. */
5429 /* Initialize the GCC target structure. */
5430 #undef TARGET_FUNCTION_ARG
5431 #define TARGET_FUNCTION_ARG c6x_function_arg
5432 #undef TARGET_FUNCTION_ARG_ADVANCE
5433 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
5434 #undef TARGET_FUNCTION_ARG_BOUNDARY
5435 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
5436 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
5437 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
5438 c6x_function_arg_round_boundary
5439 #undef TARGET_FUNCTION_VALUE_REGNO_P
5440 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
5441 #undef TARGET_FUNCTION_VALUE
5442 #define TARGET_FUNCTION_VALUE c6x_function_value
5443 #undef TARGET_LIBCALL_VALUE
5444 #define TARGET_LIBCALL_VALUE c6x_libcall_value
5445 #undef TARGET_RETURN_IN_MEMORY
5446 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
5447 #undef TARGET_RETURN_IN_MSB
5448 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
5449 #undef TARGET_PASS_BY_REFERENCE
5450 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
5451 #undef TARGET_CALLEE_COPIES
5452 #define TARGET_CALLEE_COPIES c6x_callee_copies
5453 #undef TARGET_STRUCT_VALUE_RTX
5454 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
5455 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5456 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
5458 #undef TARGET_ASM_OUTPUT_MI_THUNK
5459 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
5460 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5461 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
5463 #undef TARGET_BUILD_BUILTIN_VA_LIST
5464 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
5466 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5467 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
5468 #undef TARGET_TRAMPOLINE_INIT
5469 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
5471 #undef TARGET_LEGITIMATE_CONSTANT_P
5472 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
5473 #undef TARGET_LEGITIMATE_ADDRESS_P
5474 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
5476 #undef TARGET_IN_SMALL_DATA_P
5477 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
5478 #undef TARGET_ASM_SELECT_RTX_SECTION
5479 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
5480 #undef TARGET_ASM_SELECT_SECTION
5481 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
5482 #undef TARGET_ASM_UNIQUE_SECTION
5483 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
5484 #undef TARGET_SECTION_TYPE_FLAGS
5485 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
5486 #undef TARGET_HAVE_SRODATA_SECTION
5487 #define TARGET_HAVE_SRODATA_SECTION true
5488 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
5489 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
5491 #undef TARGET_OPTION_OVERRIDE
5492 #define TARGET_OPTION_OVERRIDE c6x_option_override
5493 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5494 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
5496 #undef TARGET_INIT_LIBFUNCS
5497 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
5498 #undef TARGET_LIBFUNC_GNU_PREFIX
5499 #define TARGET_LIBFUNC_GNU_PREFIX true
5501 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5502 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
5503 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5504 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
5505 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
5506 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
5508 #undef TARGET_RTX_COSTS
5509 #define TARGET_RTX_COSTS c6x_rtx_costs
5511 #undef TARGET_SCHED_INIT
5512 #define TARGET_SCHED_INIT c6x_sched_init
5513 #undef TARGET_SCHED_SET_SCHED_FLAGS
5514 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
5515 #undef TARGET_SCHED_ADJUST_COST
5516 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
5517 #undef TARGET_SCHED_ISSUE_RATE
5518 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
5519 #undef TARGET_SCHED_VARIABLE_ISSUE
5520 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
5521 #undef TARGET_SCHED_REORDER
5522 #define TARGET_SCHED_REORDER c6x_sched_reorder
5523 #undef TARGET_SCHED_REORDER2
5524 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
5525 #undef TARGET_SCHED_EXPOSED_PIPELINE
5526 #define TARGET_SCHED_EXPOSED_PIPELINE true
5528 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
5529 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
5530 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
5531 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
5532 #undef TARGET_SCHED_SET_SCHED_CONTEXT
5533 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
5534 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
5535 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
5537 #undef TARGET_CAN_ELIMINATE
5538 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
5540 #undef TARGET_PREFERRED_RENAME_CLASS
5541 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
5543 #undef TARGET_MACHINE_DEPENDENT_REORG
5544 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
5546 #undef TARGET_ASM_FILE_START
5547 #define TARGET_ASM_FILE_START c6x_file_start
5549 #undef TARGET_PRINT_OPERAND
5550 #define TARGET_PRINT_OPERAND c6x_print_operand
5551 #undef TARGET_PRINT_OPERAND_ADDRESS
5552 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
5553 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
5554 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
5556 /* C6x unwinding tables use a different format for the typeinfo tables. */
5557 #undef TARGET_ASM_TTYPE
5558 #define TARGET_ASM_TTYPE c6x_output_ttype
5560 #undef TARGET_DWARF_REGISTER_SPAN
5561 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
5563 #undef TARGET_INIT_BUILTINS
5564 #define TARGET_INIT_BUILTINS c6x_init_builtins
5565 #undef TARGET_EXPAND_BUILTIN
5566 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
5567 #undef TARGET_BUILTIN_DECL
5568 #define TARGET_BUILTIN_DECL c6x_builtin_decl
5570 struct gcc_target targetm
= TARGET_INITIALIZER
;