1 /* Target Code for TI C6X
2 Copyright (C) 2010-2014 Free Software Foundation, Inc.
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "stor-layout.h"
31 #include "stringpool.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
35 #include "insn-codes.h"
41 #include "sched-int.h"
45 #include "tm-constrs.h"
48 #include "diagnostic-core.h"
50 #include "langhooks.h"
52 #include "target-def.h"
53 #include "sel-sched.h"
56 #include "hw-doloop.h"
57 #include "regrename.h"
59 #include "gimple-expr.h"
62 /* Table of supported architecture variants. */
66 enum c6x_cpu_type type;
67 unsigned short features;
70 /* A list of all ISAs, mapping each one to a representative device.
71 Used for -march selection. */
72 static const c6x_arch_table all_isas[] =
74 #define C6X_ISA(NAME,DEVICE,FLAGS) \
75 { NAME, DEVICE, FLAGS },
76 #include "c6x-isas.def"
78 { NULL, C6X_CPU_C62X, 0 }
81 /* This is the parsed result of the "-march=" option, if given. */
82 enum c6x_cpu_type c6x_arch = C6X_DEFAULT_ARCH;
84 /* A mask of insn types that are allowed by the architecture selected by
86 unsigned long c6x_insn_mask = C6X_DEFAULT_INSN_MASK;
88 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
90 static rtx_insn *c6x_current_insn = NULL;
92 /* A decl we build to access __c6xabi_DSBT_base. */
93 static GTY(()) tree dsbt_decl;
95 /* Determines whether we run our final scheduling pass or not. We always
96 avoid the normal second scheduling pass. */
97 static int c6x_flag_schedule_insns2;
99 /* Determines whether we run variable tracking in machine dependent
101 static int c6x_flag_var_tracking;
103 /* Determines whether we use modulo scheduling. */
104 static int c6x_flag_modulo_sched;
106 /* Record the state of flag_pic before we set it to 1 for DSBT. */
107 int c6x_initial_flag_pic;
111 /* We record the clock cycle for every insn during scheduling. */
113 /* After scheduling, we run assign_reservations to choose unit
114 reservations for all insns. These are recorded here. */
116 /* Records the new condition for insns which must be made
117 conditional after scheduling. An entry of NULL_RTX means no such
118 change is necessary. */
120 /* True for the first insn that was scheduled in an ebb. */
122 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
123 bits rather than storing the state. Meaningful only for the last
125 unsigned int unit_mask;
126 } c6x_sched_insn_info;
129 /* Record a c6x_sched_insn_info structure for every insn in the function. */
130 static vec<c6x_sched_insn_info> insn_info;
132 #define INSN_INFO_LENGTH (insn_info).length ()
133 #define INSN_INFO_ENTRY(N) (insn_info[(N)])
135 static bool done_cfi_sections;
137 #define RESERVATION_FLAG_D 1
138 #define RESERVATION_FLAG_L 2
139 #define RESERVATION_FLAG_S 4
140 #define RESERVATION_FLAG_M 8
141 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
142 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
143 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
144 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
146 /* The DFA names of the units. */
147 static const char *const c6x_unit_names[] =
149 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
150 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
153 /* The DFA unit number for each unit in c6x_unit_names[]. */
154 static int c6x_unit_codes[ARRAY_SIZE (c6x_unit_names)];
156 /* Unit query IDs. */
157 #define UNIT_QID_D1 0
158 #define UNIT_QID_L1 1
159 #define UNIT_QID_S1 2
160 #define UNIT_QID_M1 3
161 #define UNIT_QID_FPS1 4
162 #define UNIT_QID_FPL1 5
163 #define UNIT_QID_ADDDPS1 6
164 #define UNIT_QID_ADDDPL1 7
165 #define UNIT_QID_SIDE_OFFSET 8
167 #define RESERVATION_S1 2
168 #define RESERVATION_S2 10
170 /* An enum for the unit requirements we count in the UNIT_REQS table. */
186 /* A table used to count unit requirements. Used when computing minimum
187 iteration intervals. */
188 typedef int unit_req_table[2][UNIT_REQ_MAX];
189 static unit_req_table unit_reqs;
191 /* Register map for debugging. */
192 unsigned const dbx_register_map[FIRST_PSEUDO_REGISTER] =
194 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
195 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
197 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
199 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
201 -1, -1, -1 /* FP, ARGP, ILC. */
204 /* Allocate a new, cleared machine_function structure. */
206 static struct machine_function *
207 c6x_init_machine_status (void)
209 return ggc_cleared_alloc<machine_function> ();
212 /* Implement TARGET_OPTION_OVERRIDE. */
215 c6x_option_override (void)
219 if (global_options_set.x_c6x_arch_option)
221 c6x_arch = all_isas[c6x_arch_option].type;
222 c6x_insn_mask &= ~C6X_INSNS_ALL_CPU_BITS;
223 c6x_insn_mask |= all_isas[c6x_arch_option].features;
226 c6x_flag_schedule_insns2 = flag_schedule_insns_after_reload;
227 flag_schedule_insns_after_reload = 0;
229 c6x_flag_modulo_sched = flag_modulo_sched;
230 flag_modulo_sched = 0;
232 init_machine_status = c6x_init_machine_status;
234 for (i = 0; i < ARRAY_SIZE (c6x_unit_names); i++)
235 c6x_unit_codes[i] = get_cpu_unit_code (c6x_unit_names[i]);
237 if (flag_pic && !TARGET_DSBT)
239 error ("-fpic and -fPIC not supported without -mdsbt on this target");
242 c6x_initial_flag_pic = flag_pic;
243 if (TARGET_DSBT && !flag_pic)
248 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
251 c6x_conditional_register_usage (void)
254 if (c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X)
255 for (i = 16; i < 32; i++)
258 fixed_regs[32 + i] = 1;
262 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_A_REGS],
264 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_REGS],
266 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_A_REGS],
268 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_REGS],
273 static GTY(()) rtx eqdf_libfunc;
274 static GTY(()) rtx nedf_libfunc;
275 static GTY(()) rtx ledf_libfunc;
276 static GTY(()) rtx ltdf_libfunc;
277 static GTY(()) rtx gedf_libfunc;
278 static GTY(()) rtx gtdf_libfunc;
279 static GTY(()) rtx eqsf_libfunc;
280 static GTY(()) rtx nesf_libfunc;
281 static GTY(()) rtx lesf_libfunc;
282 static GTY(()) rtx ltsf_libfunc;
283 static GTY(()) rtx gesf_libfunc;
284 static GTY(()) rtx gtsf_libfunc;
285 static GTY(()) rtx strasgi_libfunc;
286 static GTY(()) rtx strasgi64p_libfunc;
288 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
289 functions to match the C6x ABI. */
292 c6x_init_libfuncs (void)
294 /* Double-precision floating-point arithmetic. */
295 set_optab_libfunc (add_optab, DFmode, "__c6xabi_addd");
296 set_optab_libfunc (sdiv_optab, DFmode, "__c6xabi_divd");
297 set_optab_libfunc (smul_optab, DFmode, "__c6xabi_mpyd");
298 set_optab_libfunc (neg_optab, DFmode, "__c6xabi_negd");
299 set_optab_libfunc (sub_optab, DFmode, "__c6xabi_subd");
301 /* Single-precision floating-point arithmetic. */
302 set_optab_libfunc (add_optab, SFmode, "__c6xabi_addf");
303 set_optab_libfunc (sdiv_optab, SFmode, "__c6xabi_divf");
304 set_optab_libfunc (smul_optab, SFmode, "__c6xabi_mpyf");
305 set_optab_libfunc (neg_optab, SFmode, "__c6xabi_negf");
306 set_optab_libfunc (sub_optab, SFmode, "__c6xabi_subf");
308 /* Floating-point comparisons. */
309 eqsf_libfunc = init_one_libfunc ("__c6xabi_eqf");
310 nesf_libfunc = init_one_libfunc ("__c6xabi_neqf");
311 lesf_libfunc = init_one_libfunc ("__c6xabi_lef");
312 ltsf_libfunc = init_one_libfunc ("__c6xabi_ltf");
313 gesf_libfunc = init_one_libfunc ("__c6xabi_gef");
314 gtsf_libfunc = init_one_libfunc ("__c6xabi_gtf");
315 eqdf_libfunc = init_one_libfunc ("__c6xabi_eqd");
316 nedf_libfunc = init_one_libfunc ("__c6xabi_neqd");
317 ledf_libfunc = init_one_libfunc ("__c6xabi_led");
318 ltdf_libfunc = init_one_libfunc ("__c6xabi_ltd");
319 gedf_libfunc = init_one_libfunc ("__c6xabi_ged");
320 gtdf_libfunc = init_one_libfunc ("__c6xabi_gtd");
322 set_optab_libfunc (eq_optab, SFmode, NULL);
323 set_optab_libfunc (ne_optab, SFmode, "__c6xabi_neqf");
324 set_optab_libfunc (gt_optab, SFmode, NULL);
325 set_optab_libfunc (ge_optab, SFmode, NULL);
326 set_optab_libfunc (lt_optab, SFmode, NULL);
327 set_optab_libfunc (le_optab, SFmode, NULL);
328 set_optab_libfunc (unord_optab, SFmode, "__c6xabi_unordf");
329 set_optab_libfunc (eq_optab, DFmode, NULL);
330 set_optab_libfunc (ne_optab, DFmode, "__c6xabi_neqd");
331 set_optab_libfunc (gt_optab, DFmode, NULL);
332 set_optab_libfunc (ge_optab, DFmode, NULL);
333 set_optab_libfunc (lt_optab, DFmode, NULL);
334 set_optab_libfunc (le_optab, DFmode, NULL);
335 set_optab_libfunc (unord_optab, DFmode, "__c6xabi_unordd");
337 /* Floating-point to integer conversions. */
338 set_conv_libfunc (sfix_optab, SImode, DFmode, "__c6xabi_fixdi");
339 set_conv_libfunc (ufix_optab, SImode, DFmode, "__c6xabi_fixdu");
340 set_conv_libfunc (sfix_optab, DImode, DFmode, "__c6xabi_fixdlli");
341 set_conv_libfunc (ufix_optab, DImode, DFmode, "__c6xabi_fixdull");
342 set_conv_libfunc (sfix_optab, SImode, SFmode, "__c6xabi_fixfi");
343 set_conv_libfunc (ufix_optab, SImode, SFmode, "__c6xabi_fixfu");
344 set_conv_libfunc (sfix_optab, DImode, SFmode, "__c6xabi_fixflli");
345 set_conv_libfunc (ufix_optab, DImode, SFmode, "__c6xabi_fixfull");
347 /* Conversions between floating types. */
348 set_conv_libfunc (trunc_optab, SFmode, DFmode, "__c6xabi_cvtdf");
349 set_conv_libfunc (sext_optab, DFmode, SFmode, "__c6xabi_cvtfd");
351 /* Integer to floating-point conversions. */
352 set_conv_libfunc (sfloat_optab, DFmode, SImode, "__c6xabi_fltid");
353 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__c6xabi_fltud");
354 set_conv_libfunc (sfloat_optab, DFmode, DImode, "__c6xabi_fltllid");
355 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__c6xabi_fltulld");
356 set_conv_libfunc (sfloat_optab, SFmode, SImode, "__c6xabi_fltif");
357 set_conv_libfunc (ufloat_optab, SFmode, SImode, "__c6xabi_fltuf");
358 set_conv_libfunc (sfloat_optab, SFmode, DImode, "__c6xabi_fltllif");
359 set_conv_libfunc (ufloat_optab, SFmode, DImode, "__c6xabi_fltullf");
362 set_optab_libfunc (smul_optab, DImode, "__c6xabi_mpyll");
363 set_optab_libfunc (ashl_optab, DImode, "__c6xabi_llshl");
364 set_optab_libfunc (lshr_optab, DImode, "__c6xabi_llshru");
365 set_optab_libfunc (ashr_optab, DImode, "__c6xabi_llshr");
367 set_optab_libfunc (sdiv_optab, SImode, "__c6xabi_divi");
368 set_optab_libfunc (udiv_optab, SImode, "__c6xabi_divu");
369 set_optab_libfunc (smod_optab, SImode, "__c6xabi_remi");
370 set_optab_libfunc (umod_optab, SImode, "__c6xabi_remu");
371 set_optab_libfunc (sdivmod_optab, SImode, "__c6xabi_divremi");
372 set_optab_libfunc (udivmod_optab, SImode, "__c6xabi_divremu");
373 set_optab_libfunc (sdiv_optab, DImode, "__c6xabi_divlli");
374 set_optab_libfunc (udiv_optab, DImode, "__c6xabi_divull");
375 set_optab_libfunc (smod_optab, DImode, "__c6xabi_remlli");
376 set_optab_libfunc (umod_optab, DImode, "__c6xabi_remull");
377 set_optab_libfunc (udivmod_optab, DImode, "__c6xabi_divremull");
380 strasgi_libfunc = init_one_libfunc ("__c6xabi_strasgi");
381 strasgi64p_libfunc = init_one_libfunc ("__c6xabi_strasgi_64plus");
384 /* Begin the assembly file. */
387 c6x_file_start (void)
389 /* Variable tracking should be run after all optimizations which change order
390 of insns. It also needs a valid CFG. This can't be done in
391 c6x_override_options, because flag_var_tracking is finalized after
393 c6x_flag_var_tracking = flag_var_tracking;
394 flag_var_tracking = 0;
396 done_cfi_sections = false;
397 default_file_start ();
399 /* Arrays are aligned to 8-byte boundaries. */
400 asm_fprintf (asm_out_file,
401 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
402 asm_fprintf (asm_out_file,
403 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
405 /* Stack alignment is 8 bytes. */
406 asm_fprintf (asm_out_file,
407 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
408 asm_fprintf (asm_out_file,
409 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
411 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
412 /* ??? Ideally we'd check flag_short_wchar somehow. */
413 asm_fprintf (asm_out_file, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
416 /* We conform to version 1.0 of the ABI. */
417 asm_fprintf (asm_out_file,
418 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
422 /* The LTO frontend only enables exceptions when it sees a function that
423 uses it. This changes the return value of dwarf2out_do_frame, so we
424 have to check before every function. */
427 c6x_output_file_unwind (FILE * f)
429 if (done_cfi_sections)
432 /* Output a .cfi_sections directive. */
433 if (dwarf2out_do_frame ())
435 if (flag_unwind_tables || flag_exceptions)
437 if (write_symbols == DWARF2_DEBUG
438 || write_symbols == VMS_AND_DWARF2_DEBUG)
439 asm_fprintf (f, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
441 asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
444 asm_fprintf (f, "\t.cfi_sections .debug_frame\n");
445 done_cfi_sections = true;
449 /* Output unwind directives at the end of a function. */
452 c6x_output_fn_unwind (FILE * f)
454 /* Return immediately if we are not generating unwinding tables. */
455 if (! (flag_unwind_tables || flag_exceptions))
458 /* If this function will never be unwound, then mark it as such. */
459 if (!(flag_unwind_tables || crtl->uses_eh_lsda)
460 && (TREE_NOTHROW (current_function_decl)
461 || crtl->all_throwers_are_sibcalls))
462 fputs("\t.cantunwind\n", f);
464 fputs ("\t.endp\n", f);
468 /* Stack and Calling. */
470 int argument_registers[10] =
479 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
482 c6x_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, rtx libname,
483 int n_named_args ATTRIBUTE_UNUSED)
487 if (!libname && fntype)
489 /* We need to find out the number of named arguments. Unfortunately,
490 for incoming arguments, N_NAMED_ARGS is set to -1. */
491 if (stdarg_p (fntype))
492 cum->nregs = type_num_arguments (fntype) - 1;
498 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
501 c6x_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
502 const_tree type, bool named ATTRIBUTE_UNUSED)
504 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
505 if (cum->count >= cum->nregs)
509 HOST_WIDE_INT size = int_size_in_bytes (type);
510 if (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (type))
514 rtx reg1 = gen_rtx_REG (SImode, argument_registers[cum->count] + 1);
515 rtx reg2 = gen_rtx_REG (SImode, argument_registers[cum->count]);
516 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
517 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
518 return gen_rtx_PARALLEL (mode, vec);
522 return gen_rtx_REG (mode, argument_registers[cum->count]);
526 c6x_function_arg_advance (cumulative_args_t cum_v,
527 enum machine_mode mode ATTRIBUTE_UNUSED,
528 const_tree type ATTRIBUTE_UNUSED,
529 bool named ATTRIBUTE_UNUSED)
531 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
536 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
537 upward rather than downward. */
540 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
541 const_tree type, bool first)
545 if (!TARGET_BIG_ENDIAN)
551 size = int_size_in_bytes (type);
555 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
558 c6x_function_arg_boundary (enum machine_mode mode, const_tree type)
560 unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
562 if (boundary > BITS_PER_WORD)
563 return 2 * BITS_PER_WORD;
567 HOST_WIDE_INT size = int_size_in_bytes (type);
569 return 2 * BITS_PER_WORD;
570 if (boundary < BITS_PER_WORD)
573 return BITS_PER_WORD;
575 return 2 * BITS_PER_UNIT;
581 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
583 c6x_function_arg_round_boundary (enum machine_mode mode, const_tree type)
585 return c6x_function_arg_boundary (mode, type);
588 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
589 where function FUNC returns or receives a value of data type TYPE. */
592 c6x_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
593 bool outgoing ATTRIBUTE_UNUSED)
595 /* Functions return values in register A4. When returning aggregates, we may
596 have to adjust for endianness. */
597 if (TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P (type))
599 HOST_WIDE_INT size = int_size_in_bytes (type);
603 rtx reg1 = gen_rtx_REG (SImode, REG_A4 + 1);
604 rtx reg2 = gen_rtx_REG (SImode, REG_A4);
605 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
606 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
607 return gen_rtx_PARALLEL (TYPE_MODE (type), vec);
610 return gen_rtx_REG (TYPE_MODE (type), REG_A4);
613 /* Implement TARGET_LIBCALL_VALUE. */
616 c6x_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
618 return gen_rtx_REG (mode, REG_A4);
621 /* TARGET_STRUCT_VALUE_RTX implementation. */
624 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED)
626 return gen_rtx_REG (Pmode, REG_A3);
629 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
632 c6x_function_value_regno_p (const unsigned int regno)
634 return regno == REG_A4;
637 /* Types larger than 64 bit, and variable sized types, are passed by
638 reference. The callee must copy them; see c6x_callee_copies. */
641 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
642 enum machine_mode mode, const_tree type,
643 bool named ATTRIBUTE_UNUSED)
647 size = int_size_in_bytes (type);
648 else if (mode != VOIDmode)
649 size = GET_MODE_SIZE (mode);
650 return size > 2 * UNITS_PER_WORD || size == -1;
653 /* Decide whether a type should be returned in memory (true)
654 or in a register (false). This is called by the macro
655 TARGET_RETURN_IN_MEMORY. */
658 c6x_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
660 int size = int_size_in_bytes (type);
661 return size > 2 * UNITS_PER_WORD || size == -1;
664 /* Values which must be returned in the most-significant end of the return
668 c6x_return_in_msb (const_tree valtype)
670 HOST_WIDE_INT size = int_size_in_bytes (valtype);
671 return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && size == 3;
674 /* Implement TARGET_CALLEE_COPIES. */
677 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
678 enum machine_mode mode ATTRIBUTE_UNUSED,
679 const_tree type ATTRIBUTE_UNUSED,
680 bool named ATTRIBUTE_UNUSED)
685 /* Return the type to use as __builtin_va_list. */
687 c6x_build_builtin_va_list (void)
689 return build_pointer_type (char_type_node);
693 c6x_asm_trampoline_template (FILE *f)
695 fprintf (f, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
696 fprintf (f, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
697 fprintf (f, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
698 fprintf (f, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
699 fprintf (f, "\t.long\t0x00000362\n"); /* b .s2 B0 */
700 fprintf (f, "\t.long\t0x00008000\n"); /* nop 5 */
701 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
702 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
705 /* Emit RTL insns to initialize the variable parts of a trampoline at
706 TRAMP. FNADDR is an RTX for the address of the function's pure
707 code. CXT is an RTX for the static chain value for the function. */
710 c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt)
712 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
713 rtx t1 = copy_to_reg (fnaddr);
714 rtx t2 = copy_to_reg (cxt);
715 rtx mask = gen_reg_rtx (SImode);
718 emit_block_move (tramp, assemble_trampoline_template (),
719 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
721 emit_move_insn (mask, GEN_INT (0xffff << 7));
723 for (i = 0; i < 4; i++)
725 rtx mem = adjust_address (tramp, SImode, i * 4);
726 rtx t = (i & 1) ? t2 : t1;
727 rtx v1 = gen_reg_rtx (SImode);
728 rtx v2 = gen_reg_rtx (SImode);
729 emit_move_insn (v1, mem);
731 emit_insn (gen_ashlsi3 (v2, t, GEN_INT (7)));
733 emit_insn (gen_lshrsi3 (v2, t, GEN_INT (9)));
734 emit_insn (gen_andsi3 (v2, v2, mask));
735 emit_insn (gen_iorsi3 (v2, v2, v1));
736 emit_move_insn (mem, v2);
738 #ifdef CLEAR_INSN_CACHE
739 tramp = XEXP (tramp, 0);
740 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"),
741 LCT_NORMAL, VOIDmode, 2, tramp, Pmode,
742 plus_constant (Pmode, tramp, TRAMPOLINE_SIZE),
747 /* Determine whether c6x_output_mi_thunk can succeed. */
750 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
751 HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
752 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
753 const_tree function ATTRIBUTE_UNUSED)
755 return !TARGET_LONG_CALLS;
758 /* Output the assembler code for a thunk function. THUNK is the
759 declaration for the thunk function itself, FUNCTION is the decl for
760 the target function. DELTA is an immediate constant offset to be
761 added to THIS. If VCALL_OFFSET is nonzero, the word at
762 *(*this + vcall_offset) should be added to THIS. */
765 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
766 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
767 HOST_WIDE_INT vcall_offset, tree function)
770 /* The this parameter is passed as the first argument. */
771 rtx this_rtx = gen_rtx_REG (Pmode, REG_A4);
773 c6x_current_insn = NULL;
775 xops[4] = XEXP (DECL_RTL (function), 0);
778 output_asm_insn ("b .s2 \t%4", xops);
780 output_asm_insn ("nop 5", xops);
783 /* Adjust the this parameter by a fixed constant. */
786 xops[0] = GEN_INT (delta);
788 if (delta >= -16 && delta <= 15)
790 output_asm_insn ("add .s1 %0, %1, %1", xops);
792 output_asm_insn ("nop 4", xops);
794 else if (delta >= 16 && delta < 32)
796 output_asm_insn ("add .d1 %0, %1, %1", xops);
798 output_asm_insn ("nop 4", xops);
800 else if (delta >= -32768 && delta < 32768)
802 output_asm_insn ("mvk .s1 %0, A0", xops);
803 output_asm_insn ("add .d1 %1, A0, %1", xops);
805 output_asm_insn ("nop 3", xops);
809 output_asm_insn ("mvkl .s1 %0, A0", xops);
810 output_asm_insn ("mvkh .s1 %0, A0", xops);
811 output_asm_insn ("add .d1 %1, A0, %1", xops);
813 output_asm_insn ("nop 3", xops);
817 /* Adjust the this parameter by a value stored in the vtable. */
820 rtx a0tmp = gen_rtx_REG (Pmode, REG_A0);
821 rtx a3tmp = gen_rtx_REG (Pmode, REG_A3);
825 xops[3] = gen_rtx_MEM (Pmode, a0tmp);
826 output_asm_insn ("mv .s1 a4, %2", xops);
827 output_asm_insn ("ldw .d1t1 %3, %2", xops);
829 /* Adjust the this parameter. */
830 xops[0] = gen_rtx_MEM (Pmode, plus_constant (Pmode, a0tmp,
832 if (!memory_operand (xops[0], Pmode))
834 rtx tmp2 = gen_rtx_REG (Pmode, REG_A1);
835 xops[0] = GEN_INT (vcall_offset);
837 output_asm_insn ("mvkl .s1 %0, %1", xops);
838 output_asm_insn ("mvkh .s1 %0, %1", xops);
839 output_asm_insn ("nop 2", xops);
840 output_asm_insn ("add .d1 %2, %1, %2", xops);
841 xops[0] = gen_rtx_MEM (Pmode, a0tmp);
844 output_asm_insn ("nop 4", xops);
846 output_asm_insn ("ldw .d1t1 %0, %1", xops);
847 output_asm_insn ("|| b .s2 \t%4", xops);
848 output_asm_insn ("nop 4", xops);
849 output_asm_insn ("add .d1 %2, %1, %2", xops);
853 /* Return true if EXP goes in small data/bss. */
856 c6x_in_small_data_p (const_tree exp)
858 /* We want to merge strings, so we never consider them small data. */
859 if (TREE_CODE (exp) == STRING_CST)
862 /* Functions are never small data. */
863 if (TREE_CODE (exp) == FUNCTION_DECL)
866 if (TREE_CODE (exp) == VAR_DECL && DECL_WEAK (exp))
869 if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
871 const char *section = DECL_SECTION_NAME (exp);
873 if (strcmp (section, ".neardata") == 0
874 || strncmp (section, ".neardata.", 10) == 0
875 || strncmp (section, ".gnu.linkonce.s.", 16) == 0
876 || strcmp (section, ".bss") == 0
877 || strncmp (section, ".bss.", 5) == 0
878 || strncmp (section, ".gnu.linkonce.sb.", 17) == 0
879 || strcmp (section, ".rodata") == 0
880 || strncmp (section, ".rodata.", 8) == 0
881 || strncmp (section, ".gnu.linkonce.s2.", 17) == 0)
885 return PLACE_IN_SDATA_P (exp);
890 /* Return a section for X. The only special thing we do here is to
891 honor small data. We don't have a tree type, so we can't use the
892 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
893 everything sized 8 bytes or smaller into small data. */
896 c6x_select_rtx_section (enum machine_mode mode, rtx x,
897 unsigned HOST_WIDE_INT align)
899 if (c6x_sdata_mode == C6X_SDATA_ALL
900 || (c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE (mode) <= 8))
901 /* ??? Consider using mergeable sdata sections. */
902 return sdata_section;
904 return default_elf_select_rtx_section (mode, x, align);
908 c6x_elf_select_section (tree decl, int reloc,
909 unsigned HOST_WIDE_INT align)
911 const char *sname = NULL;
912 unsigned int flags = SECTION_WRITE;
913 if (c6x_in_small_data_p (decl))
915 switch (categorize_decl_for_section (decl, reloc))
926 flags |= SECTION_BSS;
933 switch (categorize_decl_for_section (decl, reloc))
938 case SECCAT_DATA_REL:
939 sname = ".fardata.rel";
941 case SECCAT_DATA_REL_LOCAL:
942 sname = ".fardata.rel.local";
944 case SECCAT_DATA_REL_RO:
945 sname = ".fardata.rel.ro";
947 case SECCAT_DATA_REL_RO_LOCAL:
948 sname = ".fardata.rel.ro.local";
952 flags |= SECTION_BSS;
968 /* We might get called with string constants, but get_named_section
969 doesn't like them as they are not DECLs. Also, we need to set
970 flags in that case. */
972 return get_section (sname, flags, NULL);
973 return get_named_section (decl, sname, reloc);
976 return default_elf_select_section (decl, reloc, align);
979 /* Build up a unique section name, expressed as a
980 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
981 RELOC indicates whether the initial value of EXP requires
982 link-time relocations. */
984 static void ATTRIBUTE_UNUSED
985 c6x_elf_unique_section (tree decl, int reloc)
987 const char *prefix = NULL;
988 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
989 bool one_only = DECL_COMDAT_GROUP (decl) && !HAVE_COMDAT_GROUP;
991 if (c6x_in_small_data_p (decl))
993 switch (categorize_decl_for_section (decl, reloc))
996 prefix = one_only ? ".s" : ".neardata";
999 prefix = one_only ? ".sb" : ".bss";
1001 case SECCAT_SRODATA:
1002 prefix = one_only ? ".s2" : ".rodata";
1004 case SECCAT_RODATA_MERGE_STR:
1005 case SECCAT_RODATA_MERGE_STR_INIT:
1006 case SECCAT_RODATA_MERGE_CONST:
1009 case SECCAT_DATA_REL:
1010 case SECCAT_DATA_REL_LOCAL:
1011 case SECCAT_DATA_REL_RO:
1012 case SECCAT_DATA_REL_RO_LOCAL:
1015 /* Everything else we place into default sections and hope for the
1022 switch (categorize_decl_for_section (decl, reloc))
1025 case SECCAT_DATA_REL:
1026 case SECCAT_DATA_REL_LOCAL:
1027 case SECCAT_DATA_REL_RO:
1028 case SECCAT_DATA_REL_RO_LOCAL:
1029 prefix = one_only ? ".fd" : ".fardata";
1032 prefix = one_only ? ".fb" : ".far";
1035 case SECCAT_RODATA_MERGE_STR:
1036 case SECCAT_RODATA_MERGE_STR_INIT:
1037 case SECCAT_RODATA_MERGE_CONST:
1038 prefix = one_only ? ".fr" : ".const";
1040 case SECCAT_SRODATA:
1051 const char *name, *linkonce;
1054 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1055 name = targetm.strip_name_encoding (name);
1057 /* If we're using one_only, then there needs to be a .gnu.linkonce
1058 prefix to the section name. */
1059 linkonce = one_only ? ".gnu.linkonce" : "";
1061 string = ACONCAT ((linkonce, prefix, ".", name, NULL));
1063 set_decl_section_name (decl, string);
1066 default_unique_section (decl, reloc);
1070 c6x_section_type_flags (tree decl, const char *name, int reloc)
1072 unsigned int flags = 0;
1074 if (strcmp (name, ".far") == 0
1075 || strncmp (name, ".far.", 5) == 0)
1076 flags |= SECTION_BSS;
1078 flags |= default_section_type_flags (decl, name, reloc);
1083 /* Checks whether the given CALL_EXPR would use a caller saved
1084 register. This is used to decide whether sibling call optimization
1085 could be performed on the respective function call. */
1088 c6x_call_saved_register_used (tree call_expr)
1090 CUMULATIVE_ARGS cum_v;
1091 cumulative_args_t cum;
1092 HARD_REG_SET call_saved_regset;
1094 enum machine_mode mode;
1099 INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0);
1100 cum = pack_cumulative_args (&cum_v);
1102 COMPL_HARD_REG_SET (call_saved_regset, call_used_reg_set);
1103 for (i = 0; i < call_expr_nargs (call_expr); i++)
1105 parameter = CALL_EXPR_ARG (call_expr, i);
1106 gcc_assert (parameter);
1108 /* For an undeclared variable passed as parameter we will get
1109 an ERROR_MARK node here. */
1110 if (TREE_CODE (parameter) == ERROR_MARK)
1113 type = TREE_TYPE (parameter);
1116 mode = TYPE_MODE (type);
1119 if (pass_by_reference (&cum_v, mode, type, true))
1122 type = build_pointer_type (type);
1125 parm_rtx = c6x_function_arg (cum, mode, type, 0);
1127 c6x_function_arg_advance (cum, mode, type, 0);
1132 if (REG_P (parm_rtx)
1133 && overlaps_hard_reg_set_p (call_saved_regset, GET_MODE (parm_rtx),
1136 if (GET_CODE (parm_rtx) == PARALLEL)
1138 int n = XVECLEN (parm_rtx, 0);
1141 rtx x = XEXP (XVECEXP (parm_rtx, 0, n), 0);
1143 && overlaps_hard_reg_set_p (call_saved_regset,
1144 GET_MODE (x), REGNO (x)))
1152 /* Decide whether we can make a sibling call to a function. DECL is the
1153 declaration of the function being targeted by the call and EXP is the
1154 CALL_EXPR representing the call. */
1157 c6x_function_ok_for_sibcall (tree decl, tree exp)
1159 /* Registers A10, A12, B10 and B12 are available as arguments
1160 register but unfortunately caller saved. This makes functions
1161 needing these registers for arguments not suitable for
1163 if (c6x_call_saved_register_used (exp))
1171 /* When compiling for DSBT, the calling function must be local,
1172 so that when we reload B14 in the sibcall epilogue, it will
1173 not change its value. */
1174 struct cgraph_local_info *this_func;
1177 /* Not enough information. */
1180 this_func = cgraph_node::local_info (current_function_decl);
1181 return this_func->local;
1187 /* Return true if DECL is known to be linked into section SECTION. */
1190 c6x_function_in_section_p (tree decl, section *section)
1192 /* We can only be certain about functions defined in the same
1193 compilation unit. */
1194 if (!TREE_STATIC (decl))
1197 /* Make sure that SYMBOL always binds to the definition in this
1198 compilation unit. */
1199 if (!targetm.binds_local_p (decl))
1202 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1203 if (!DECL_SECTION_NAME (decl))
1205 /* Make sure that we will not create a unique section for DECL. */
1206 if (flag_function_sections || DECL_COMDAT_GROUP (decl))
1210 return function_section (decl) == section;
1213 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1216 c6x_long_call_p (rtx op)
1220 if (!TARGET_LONG_CALLS)
1223 decl = SYMBOL_REF_DECL (op);
1225 /* Try to determine whether the symbol is in the same section as the current
1226 function. Be conservative, and only cater for cases in which the
1227 whole of the current function is placed in the same section. */
1228 if (decl != NULL_TREE
1229 && !flag_reorder_blocks_and_partition
1230 && TREE_CODE (decl) == FUNCTION_DECL
1231 && c6x_function_in_section_p (decl, current_function_section ()))
1237 /* Emit the sequence for a call. */
1239 c6x_expand_call (rtx retval, rtx address, bool sibcall)
1241 rtx callee = XEXP (address, 0);
1244 if (!c6x_call_operand (callee, Pmode))
1246 callee = force_reg (Pmode, callee);
1247 address = change_address (address, Pmode, callee);
1249 call_insn = gen_rtx_CALL (VOIDmode, address, const0_rtx);
1252 call_insn = emit_call_insn (call_insn);
1253 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
1254 gen_rtx_REG (Pmode, REG_B3));
1258 if (retval == NULL_RTX)
1259 call_insn = emit_call_insn (call_insn);
1261 call_insn = emit_call_insn (gen_rtx_SET (GET_MODE (retval), retval,
1265 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
1268 /* Legitimize PIC addresses. If the address is already position-independent,
1269 we return ORIG. Newly generated position-independent addresses go into a
1270 reg. This is REG if nonzero, otherwise we allocate register(s) as
1271 necessary. PICREG is the register holding the pointer to the PIC offset
1275 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
1280 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
1282 int unspec = UNSPEC_LOAD_GOT;
1287 gcc_assert (can_create_pseudo_p ());
1288 reg = gen_reg_rtx (Pmode);
1292 if (can_create_pseudo_p ())
1293 tmp = gen_reg_rtx (Pmode);
1296 emit_insn (gen_movsi_gotoff_high (tmp, addr));
1297 emit_insn (gen_movsi_gotoff_lo_sum (tmp, tmp, addr));
1298 emit_insn (gen_load_got_gotoff (reg, picreg, tmp));
1302 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
1303 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
1305 emit_move_insn (reg, new_rtx);
1307 if (picreg == pic_offset_table_rtx)
1308 crtl->uses_pic_offset_table = 1;
1312 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1316 if (GET_CODE (addr) == CONST)
1318 addr = XEXP (addr, 0);
1319 gcc_assert (GET_CODE (addr) == PLUS);
1322 if (XEXP (addr, 0) == picreg)
1327 gcc_assert (can_create_pseudo_p ());
1328 reg = gen_reg_rtx (Pmode);
1331 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
1332 addr = legitimize_pic_address (XEXP (addr, 1),
1333 base == reg ? NULL_RTX : reg,
1336 if (GET_CODE (addr) == CONST_INT)
1338 gcc_assert (! reload_in_progress && ! reload_completed);
1339 addr = force_reg (Pmode, addr);
1342 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
1344 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
1345 addr = XEXP (addr, 1);
1348 return gen_rtx_PLUS (Pmode, base, addr);
1354 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1355 Returns true if no further code must be generated, false if the caller
1356 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1359 expand_move (rtx *operands, enum machine_mode mode)
1361 rtx dest = operands[0];
1362 rtx op = operands[1];
1364 if ((reload_in_progress | reload_completed) == 0
1365 && GET_CODE (dest) == MEM && GET_CODE (op) != REG)
1366 operands[1] = force_reg (mode, op);
1367 else if (mode == SImode && symbolic_operand (op, SImode))
1371 if (sdata_symbolic_operand (op, SImode))
1373 emit_insn (gen_load_sdata_pic (dest, pic_offset_table_rtx, op));
1374 crtl->uses_pic_offset_table = 1;
1379 rtx temp = (reload_completed || reload_in_progress
1380 ? dest : gen_reg_rtx (Pmode));
1382 operands[1] = legitimize_pic_address (op, temp,
1383 pic_offset_table_rtx);
1386 else if (reload_completed
1387 && !sdata_symbolic_operand (op, SImode))
1389 emit_insn (gen_movsi_high (dest, op));
1390 emit_insn (gen_movsi_lo_sum (dest, dest, op));
1397 /* This function is called when we're about to expand an integer compare
1398 operation which performs COMPARISON. It examines the second operand,
1399 and if it is an integer constant that cannot be used directly on the
1400 current machine in a comparison insn, it returns true. */
1402 c6x_force_op_for_comparison_p (enum rtx_code code, rtx op)
1404 if (!CONST_INT_P (op) || satisfies_constraint_Iu4 (op))
1407 if ((code == EQ || code == LT || code == GT)
1408 && !satisfies_constraint_Is5 (op))
1410 if ((code == GTU || code == LTU)
1411 && (!TARGET_INSNS_64 || !satisfies_constraint_Iu5 (op)))
1417 /* Emit comparison instruction if necessary, returning the expression
1418 that holds the compare result in the proper mode. Return the comparison
1419 that should be used in the jump insn. */
1422 c6x_expand_compare (rtx comparison, enum machine_mode mode)
1424 enum rtx_code code = GET_CODE (comparison);
1425 rtx op0 = XEXP (comparison, 0);
1426 rtx op1 = XEXP (comparison, 1);
1428 enum rtx_code jump_code = code;
1429 enum machine_mode op_mode = GET_MODE (op0);
1431 if (op_mode == DImode && (code == NE || code == EQ) && op1 == const0_rtx)
1433 rtx t = gen_reg_rtx (SImode);
1434 emit_insn (gen_iorsi3 (t, gen_lowpart (SImode, op0),
1435 gen_highpart (SImode, op0)));
1439 else if (op_mode == DImode)
1444 if (code == NE || code == GEU || code == LEU || code == GE || code == LE)
1446 code = reverse_condition (code);
1452 split_di (&op0, 1, lo, high);
1453 split_di (&op1, 1, lo + 1, high + 1);
1455 if (c6x_force_op_for_comparison_p (code, high[1])
1456 || c6x_force_op_for_comparison_p (EQ, high[1]))
1457 high[1] = force_reg (SImode, high[1]);
1459 cmp1 = gen_reg_rtx (SImode);
1460 cmp2 = gen_reg_rtx (SImode);
1461 emit_insn (gen_rtx_SET (VOIDmode, cmp1,
1462 gen_rtx_fmt_ee (code, SImode, high[0], high[1])));
1465 if (c6x_force_op_for_comparison_p (code, lo[1]))
1466 lo[1] = force_reg (SImode, lo[1]);
1467 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1468 gen_rtx_fmt_ee (code, SImode, lo[0], lo[1])));
1469 emit_insn (gen_andsi3 (cmp1, cmp1, cmp2));
1473 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1474 gen_rtx_EQ (SImode, high[0], high[1])));
1477 else if (code == LT)
1479 if (c6x_force_op_for_comparison_p (code, lo[1]))
1480 lo[1] = force_reg (SImode, lo[1]);
1481 emit_insn (gen_cmpsi_and (cmp2, gen_rtx_fmt_ee (code, SImode,
1483 lo[0], lo[1], cmp2));
1484 emit_insn (gen_iorsi3 (cmp1, cmp1, cmp2));
1488 else if (TARGET_FP && !flag_finite_math_only
1489 && (op_mode == DFmode || op_mode == SFmode)
1490 && code != EQ && code != NE && code != LT && code != GT
1491 && code != UNLE && code != UNGE)
1493 enum rtx_code code1, code2, code3;
1494 rtx (*fn) (rtx, rtx, rtx, rtx, rtx);
1506 code1 = code == LE || code == UNGT ? LT : GT;
1531 cmp = gen_reg_rtx (SImode);
1532 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1533 gen_rtx_fmt_ee (code1, SImode, op0, op1)));
1534 fn = op_mode == DFmode ? gen_cmpdf_ior : gen_cmpsf_ior;
1535 emit_insn (fn (cmp, gen_rtx_fmt_ee (code2, SImode, op0, op1),
1537 if (code3 != UNKNOWN)
1538 emit_insn (fn (cmp, gen_rtx_fmt_ee (code3, SImode, op0, op1),
1541 else if (op_mode == SImode && (code == NE || code == EQ) && op1 == const0_rtx)
1546 is_fp_libfunc = !TARGET_FP && (op_mode == DFmode || op_mode == SFmode);
1548 if ((code == NE || code == GEU || code == LEU || code == GE || code == LE)
1551 code = reverse_condition (code);
1554 else if (code == UNGE)
1559 else if (code == UNLE)
1574 libfunc = op_mode == DFmode ? eqdf_libfunc : eqsf_libfunc;
1577 libfunc = op_mode == DFmode ? nedf_libfunc : nesf_libfunc;
1580 libfunc = op_mode == DFmode ? gtdf_libfunc : gtsf_libfunc;
1583 libfunc = op_mode == DFmode ? gedf_libfunc : gesf_libfunc;
1586 libfunc = op_mode == DFmode ? ltdf_libfunc : ltsf_libfunc;
1589 libfunc = op_mode == DFmode ? ledf_libfunc : lesf_libfunc;
1596 cmp = emit_library_call_value (libfunc, 0, LCT_CONST, SImode, 2,
1597 op0, op_mode, op1, op_mode);
1598 insns = get_insns ();
1601 emit_libcall_block (insns, cmp, cmp,
1602 gen_rtx_fmt_ee (code, SImode, op0, op1));
1606 cmp = gen_reg_rtx (SImode);
1607 if (c6x_force_op_for_comparison_p (code, op1))
1608 op1 = force_reg (SImode, op1);
1609 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1610 gen_rtx_fmt_ee (code, SImode, op0, op1)));
1614 return gen_rtx_fmt_ee (jump_code, mode, cmp, const0_rtx);
1617 /* Return one word of double-word value OP. HIGH_P is true to select the
1618 high part, false to select the low part. When encountering auto-increment
1619 addressing, we make the assumption that the low part is going to be accessed
1623 c6x_subword (rtx op, bool high_p)
1626 enum machine_mode mode;
1628 mode = GET_MODE (op);
1629 if (mode == VOIDmode)
1632 if (TARGET_BIG_ENDIAN ? !high_p : high_p)
1633 byte = UNITS_PER_WORD;
1639 rtx addr = XEXP (op, 0);
1640 if (GET_CODE (addr) == PLUS || REG_P (addr))
1641 return adjust_address (op, word_mode, byte);
1642 /* FIXME: should really support autoincrement addressing for
1643 multi-word modes. */
1647 return simplify_gen_subreg (word_mode, op, mode, byte);
1650 /* Split one or more DImode RTL references into pairs of SImode
1651 references. The RTL can be REG, offsettable MEM, integer constant, or
1652 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1653 split and "num" is its length. lo_half and hi_half are output arrays
1654 that parallel "operands". */
1657 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1661 rtx op = operands[num];
1663 lo_half[num] = c6x_subword (op, false);
1664 hi_half[num] = c6x_subword (op, true);
1668 /* Return true if VAL is a mask valid for a clr instruction. */
1670 c6x_valid_mask_p (HOST_WIDE_INT val)
1673 for (i = 0; i < 32; i++)
1674 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1677 if (val & ((unsigned HOST_WIDE_INT)1 << i))
1680 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1685 /* Expand a block move for a movmemM pattern. */
1688 c6x_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
1689 rtx expected_align_exp ATTRIBUTE_UNUSED,
1690 rtx expected_size_exp ATTRIBUTE_UNUSED)
1692 unsigned HOST_WIDE_INT align = 1;
1693 unsigned HOST_WIDE_INT src_mem_align, dst_mem_align, min_mem_align;
1694 unsigned HOST_WIDE_INT count = 0, offset = 0;
1695 unsigned int biggest_move = TARGET_STDW ? 8 : 4;
1697 if (CONST_INT_P (align_exp))
1698 align = INTVAL (align_exp);
1700 src_mem_align = MEM_ALIGN (src) / BITS_PER_UNIT;
1701 dst_mem_align = MEM_ALIGN (dst) / BITS_PER_UNIT;
1702 min_mem_align = MIN (src_mem_align, dst_mem_align);
1704 if (min_mem_align > align)
1705 align = min_mem_align / BITS_PER_UNIT;
1706 if (src_mem_align < align)
1707 src_mem_align = align;
1708 if (dst_mem_align < align)
1709 dst_mem_align = align;
1711 if (CONST_INT_P (count_exp))
1712 count = INTVAL (count_exp);
1716 /* Make sure we don't need to care about overflow later on. */
1717 if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
1720 if (count >= 28 && (count & 3) == 0 && align >= 4)
1722 tree dst_expr = MEM_EXPR (dst);
1723 tree src_expr = MEM_EXPR (src);
1724 rtx fn = TARGET_INSNS_64PLUS ? strasgi64p_libfunc : strasgi_libfunc;
1725 rtx srcreg = force_reg (Pmode, XEXP (src, 0));
1726 rtx dstreg = force_reg (Pmode, XEXP (dst, 0));
1729 mark_addressable (src_expr);
1731 mark_addressable (dst_expr);
1732 emit_library_call (fn, LCT_NORMAL, VOIDmode, 3,
1733 dstreg, Pmode, srcreg, Pmode, count_exp, SImode);
1737 if (biggest_move > align && !TARGET_INSNS_64)
1738 biggest_move = align;
1740 if (count / biggest_move > 7)
1745 rtx reg, reg_lowpart;
1746 enum machine_mode srcmode, dstmode;
1747 unsigned HOST_WIDE_INT src_size, dst_size, src_left;
1751 while (biggest_move > count)
1754 src_size = dst_size = biggest_move;
1755 if (src_size > src_mem_align && src_size == 2)
1757 if (dst_size > dst_mem_align && dst_size == 2)
1760 if (dst_size > src_size)
1761 dst_size = src_size;
1763 srcmode = mode_for_size (src_size * BITS_PER_UNIT, MODE_INT, 0);
1764 dstmode = mode_for_size (dst_size * BITS_PER_UNIT, MODE_INT, 0);
1766 reg_lowpart = reg = gen_reg_rtx (srcmode);
1769 reg = gen_reg_rtx (SImode);
1770 reg_lowpart = gen_lowpart (srcmode, reg);
1773 srcmem = adjust_address (copy_rtx (src), srcmode, offset);
1775 if (src_size > src_mem_align)
1777 enum insn_code icode = (srcmode == SImode ? CODE_FOR_movmisalignsi
1778 : CODE_FOR_movmisaligndi);
1779 emit_insn (GEN_FCN (icode) (reg_lowpart, srcmem));
1782 emit_move_insn (reg_lowpart, srcmem);
1784 src_left = src_size;
1785 shift = TARGET_BIG_ENDIAN ? (src_size - dst_size) * BITS_PER_UNIT : 0;
1786 while (src_left > 0)
1788 rtx dstreg = reg_lowpart;
1790 if (src_size > dst_size)
1793 int shift_amount = shift & (BITS_PER_WORD - 1);
1795 srcword = operand_subword_force (srcword, src_left >= 4 ? 0 : 4,
1797 if (shift_amount > 0)
1799 dstreg = gen_reg_rtx (SImode);
1800 emit_insn (gen_lshrsi3 (dstreg, srcword,
1801 GEN_INT (shift_amount)));
1805 dstreg = gen_lowpart (dstmode, dstreg);
1808 dstmem = adjust_address (copy_rtx (dst), dstmode, offset);
1809 if (dst_size > dst_mem_align)
1811 enum insn_code icode = (dstmode == SImode ? CODE_FOR_movmisalignsi
1812 : CODE_FOR_movmisaligndi);
1813 emit_insn (GEN_FCN (icode) (dstmem, dstreg));
1816 emit_move_insn (dstmem, dstreg);
1818 if (TARGET_BIG_ENDIAN)
1819 shift -= dst_size * BITS_PER_UNIT;
1821 shift += dst_size * BITS_PER_UNIT;
1823 src_left -= dst_size;
1830 /* Subroutine of print_address_operand, print a single address offset OFF for
1831 a memory access of mode MEM_MODE, choosing between normal form and scaled
1832 form depending on the type of the insn. Misaligned memory references must
1833 use the scaled form. */
1836 print_address_offset (FILE *file, rtx off, enum machine_mode mem_mode)
1840 if (c6x_current_insn != NULL_RTX)
1842 pat = PATTERN (c6x_current_insn);
1843 if (GET_CODE (pat) == COND_EXEC)
1844 pat = COND_EXEC_CODE (pat);
1845 if (GET_CODE (pat) == PARALLEL)
1846 pat = XVECEXP (pat, 0, 0);
1848 if (GET_CODE (pat) == SET
1849 && GET_CODE (SET_SRC (pat)) == UNSPEC
1850 && XINT (SET_SRC (pat), 1) == UNSPEC_MISALIGNED_ACCESS)
1852 gcc_assert (CONST_INT_P (off)
1853 && (INTVAL (off) & (GET_MODE_SIZE (mem_mode) - 1)) == 0);
1854 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1855 INTVAL (off) / GET_MODE_SIZE (mem_mode));
1860 output_address (off);
1865 c6x_print_operand_punct_valid_p (unsigned char c)
1867 return c == '$' || c == '.' || c == '|';
1870 static void c6x_print_operand (FILE *, rtx, int);
1872 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1875 c6x_print_address_operand (FILE *file, rtx x, enum machine_mode mem_mode)
1878 switch (GET_CODE (x))
1882 if (GET_CODE (x) == POST_MODIFY)
1883 output_address (XEXP (x, 0));
1884 off = XEXP (XEXP (x, 1), 1);
1885 if (XEXP (x, 0) == stack_pointer_rtx)
1887 if (GET_CODE (x) == PRE_MODIFY)
1888 gcc_assert (INTVAL (off) > 0);
1890 gcc_assert (INTVAL (off) < 0);
1892 if (CONST_INT_P (off) && INTVAL (off) < 0)
1894 fprintf (file, "--");
1895 off = GEN_INT (-INTVAL (off));
1898 fprintf (file, "++");
1899 if (GET_CODE (x) == PRE_MODIFY)
1900 output_address (XEXP (x, 0));
1901 print_address_offset (file, off, mem_mode);
1906 if (CONST_INT_P (off) && INTVAL (off) < 0)
1908 fprintf (file, "-");
1909 off = GEN_INT (-INTVAL (off));
1912 fprintf (file, "+");
1913 output_address (XEXP (x, 0));
1914 print_address_offset (file, off, mem_mode);
1918 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1919 fprintf (file, "--");
1920 output_address (XEXP (x, 0));
1921 fprintf (file, "[1]");
1924 fprintf (file, "++");
1925 output_address (XEXP (x, 0));
1926 fprintf (file, "[1]");
1929 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1930 output_address (XEXP (x, 0));
1931 fprintf (file, "++[1]");
1934 output_address (XEXP (x, 0));
1935 fprintf (file, "--[1]");
1941 gcc_assert (sdata_symbolic_operand (x, Pmode));
1942 fprintf (file, "+B14(");
1943 output_addr_const (file, x);
1944 fprintf (file, ")");
1948 switch (XINT (x, 1))
1950 case UNSPEC_LOAD_GOT:
1951 fputs ("$GOT(", file);
1952 output_addr_const (file, XVECEXP (x, 0, 0));
1955 case UNSPEC_LOAD_SDATA:
1956 output_addr_const (file, XVECEXP (x, 0, 0));
1964 gcc_assert (GET_CODE (x) != MEM);
1965 c6x_print_operand (file, x, 0);
1970 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1971 specifies the functional unit used by INSN. */
1974 c6x_get_unit_specifier (rtx_insn *insn)
1976 enum attr_units units;
1978 if (insn_info.exists ())
1980 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
1981 return c6x_unit_names[unit][0];
1984 units = get_attr_units (insn);
2009 /* Prints the unit specifier field. */
2011 c6x_print_unit_specifier_field (FILE *file, rtx_insn *insn)
2013 enum attr_units units = get_attr_units (insn);
2014 enum attr_cross cross = get_attr_cross (insn);
2015 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
2019 if (units == UNITS_D_ADDR)
2021 enum attr_addr_regfile arf = get_attr_addr_regfile (insn);
2023 gcc_assert (arf != ADDR_REGFILE_UNKNOWN);
2024 half = arf == ADDR_REGFILE_A ? 1 : 2;
2025 t_half = rf == DEST_REGFILE_A ? 1 : 2;
2026 fprintf (file, ".d%dt%d", half, t_half);
2030 if (insn_info.exists ())
2032 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
2034 fputs (c6x_unit_names[unit], file);
2035 if (cross == CROSS_Y)
2040 gcc_assert (rf != DEST_REGFILE_UNKNOWN);
2041 unitspec = c6x_get_unit_specifier (insn);
2042 half = rf == DEST_REGFILE_A ? 1 : 2;
2043 fprintf (file, ".%c%d%s", unitspec, half, cross == CROSS_Y ? "x" : "");
2046 /* Output assembly language output for the address ADDR to FILE. */
2048 c6x_print_operand_address (FILE *file, rtx addr)
2050 c6x_print_address_operand (file, addr, VOIDmode);
2053 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2056 $ -- print the unit specifier field for the instruction.
2057 . -- print the predicate for the instruction or an emptry string for an
2059 | -- print "||" if the insn should be issued in parallel with the previous
2062 C -- print an opcode suffix for a reversed condition
2063 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2065 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2067 J -- print a predicate
2068 j -- like J, but use reverse predicate
2069 k -- treat a CONST_INT as a register number and print it as a register
2070 k -- like k, but print out a doubleword register
2071 n -- print an integer operand, negated
2072 p -- print the low part of a DImode register
2073 P -- print the high part of a DImode register
2074 r -- print the absolute value of an integer operand, shifted right by 1
2075 R -- print the absolute value of an integer operand, shifted right by 2
2076 f -- the first clear bit in an integer operand assumed to be a mask for
2078 F -- the last clear bit in such a mask
2079 s -- the first set bit in an integer operand assumed to be a mask for
2081 S -- the last set bit in such a mask
2082 U -- print either 1 or 2, depending on the side of the machine used by
2086 c6x_print_operand (FILE *file, rtx x, int code)
2091 enum machine_mode mode;
2095 if (GET_MODE (c6x_current_insn) != TImode)
2101 c6x_print_unit_specifier_field (file, c6x_current_insn);
2107 x = current_insn_predicate;
2110 unsigned int regno = REGNO (XEXP (x, 0));
2112 if (GET_CODE (x) == EQ)
2114 fputs (reg_names [regno], file);
2120 mode = GET_MODE (x);
2127 enum rtx_code c = GET_CODE (x);
2129 c = swap_condition (c);
2130 fputs (GET_RTX_NAME (c), file);
2137 unsigned int regno = REGNO (XEXP (x, 0));
2138 if ((GET_CODE (x) == EQ) == (code == 'J'))
2140 fputs (reg_names [regno], file);
2145 gcc_assert (GET_CODE (x) == CONST_INT);
2147 fprintf (file, "%s", reg_names[v]);
2150 gcc_assert (GET_CODE (x) == CONST_INT);
2152 gcc_assert ((v & 1) == 0);
2153 fprintf (file, "%s:%s", reg_names[v + 1], reg_names[v]);
2160 gcc_assert (GET_CODE (x) == CONST_INT);
2162 for (i = 0; i < 32; i++)
2164 HOST_WIDE_INT tst = v & 1;
2165 if (((code == 'f' || code == 'F') && !tst)
2166 || ((code == 's' || code == 'S') && tst))
2170 if (code == 'f' || code == 's')
2172 fprintf (file, "%d", i);
2177 HOST_WIDE_INT tst = v & 1;
2178 if ((code == 'F' && tst) || (code == 'S' && !tst))
2182 fprintf (file, "%d", i - 1);
2186 gcc_assert (GET_CODE (x) == CONST_INT);
2187 output_addr_const (file, GEN_INT (-INTVAL (x)));
2191 gcc_assert (GET_CODE (x) == CONST_INT);
2195 output_addr_const (file, GEN_INT (v >> 1));
2199 gcc_assert (GET_CODE (x) == CONST_INT);
2203 output_addr_const (file, GEN_INT (v >> 2));
2207 gcc_assert (GET_CODE (x) == CONST_INT);
2209 fputs (v == 2 ? "h" : v == 4 ? "w" : "d", file);
2214 gcc_assert (GET_CODE (x) == REG);
2218 fputs (reg_names[v], file);
2223 if (GET_CODE (x) == CONST)
2226 gcc_assert (GET_CODE (x) == PLUS);
2227 gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
2228 v = INTVAL (XEXP (x, 1));
2232 gcc_assert (GET_CODE (x) == SYMBOL_REF);
2234 t = SYMBOL_REF_DECL (x);
2236 v |= DECL_ALIGN_UNIT (t);
2238 v |= TYPE_ALIGN_UNIT (TREE_TYPE (t));
2251 if (GET_CODE (x) == PLUS
2252 || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
2254 if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
2256 gcc_assert (sdata_symbolic_operand (x, Pmode));
2261 gcc_assert (REG_P (x));
2262 if (A_REGNO_P (REGNO (x)))
2264 if (B_REGNO_P (REGNO (x)))
2269 switch (GET_CODE (x))
2272 if (GET_MODE_SIZE (mode) == 8)
2273 fprintf (file, "%s:%s", reg_names[REGNO (x) + 1],
2274 reg_names[REGNO (x)]);
2276 fprintf (file, "%s", reg_names[REGNO (x)]);
2281 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
2282 c6x_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
2287 output_addr_const (file, x);
2292 output_addr_const (file, x);
2296 output_operand_lossage ("invalid const_double operand");
2300 output_addr_const (file, x);
2305 /* Return TRUE if OP is a valid memory address with a base register of
2306 class C. If SMALL_OFFSET is true, we disallow memory references which would
2307 require a long offset with B14/B15. */
2310 c6x_mem_operand (rtx op, enum reg_class c, bool small_offset)
2312 enum machine_mode mode = GET_MODE (op);
2313 rtx base = XEXP (op, 0);
2314 switch (GET_CODE (base))
2320 && (XEXP (base, 0) == stack_pointer_rtx
2321 || XEXP (base, 0) == pic_offset_table_rtx))
2323 if (!c6x_legitimate_address_p_1 (mode, base, true, true))
2334 base = XEXP (base, 0);
2340 gcc_assert (sdata_symbolic_operand (base, Pmode));
2341 return !small_offset && c == B_REGS;
2346 return TEST_HARD_REG_BIT (reg_class_contents[ (int) (c)], REGNO (base));
2349 /* Returns true if X is a valid address for use in a memory reference
2350 of mode MODE. If STRICT is true, we do not allow pseudo registers
2351 in the address. NO_LARGE_OFFSET is true if we are examining an
2352 address for use in a load or store misaligned instruction, or
2353 recursively examining an operand inside a PRE/POST_MODIFY. */
2356 c6x_legitimate_address_p_1 (enum machine_mode mode, rtx x, bool strict,
2357 bool no_large_offset)
2361 enum rtx_code code = GET_CODE (x);
2367 /* We can't split these into word-sized pieces yet. */
2368 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2370 if (GET_CODE (XEXP (x, 1)) != PLUS)
2372 if (!c6x_legitimate_address_p_1 (mode, XEXP (x, 1), strict, true))
2374 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
2382 /* We can't split these into word-sized pieces yet. */
2383 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2392 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x));
2394 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x));
2397 if (!REG_P (XEXP (x, 0))
2398 || !c6x_legitimate_address_p_1 (mode, XEXP (x, 0), strict, false))
2400 /* We cannot ensure currently that both registers end up in the
2401 same register file. */
2402 if (REG_P (XEXP (x, 1)))
2405 if (mode == BLKmode)
2407 else if (mode == VOIDmode)
2408 /* ??? This can happen during ivopts. */
2411 size = GET_MODE_SIZE (mode);
2414 && GET_CODE (XEXP (x, 1)) == UNSPEC
2415 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_SDATA
2416 && XEXP (x, 0) == pic_offset_table_rtx
2417 && sdata_symbolic_operand (XVECEXP (XEXP (x, 1), 0, 0), SImode))
2418 return !no_large_offset && size <= 4;
2421 && GET_CODE (XEXP (x, 1)) == UNSPEC
2422 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_GOT
2423 && XEXP (x, 0) == pic_offset_table_rtx
2424 && (GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == SYMBOL_REF
2425 || GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == LABEL_REF))
2426 return !no_large_offset;
2427 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2430 off = INTVAL (XEXP (x, 1));
2432 /* If the machine does not have doubleword load/stores, we'll use
2433 word size accesses. */
2435 if (size == 2 * UNITS_PER_WORD && !TARGET_STDW)
2436 size = UNITS_PER_WORD;
2438 if (((HOST_WIDE_INT)size1 - 1) & off)
2441 if (off > -32 && off < (size1 == size ? 32 : 28))
2443 if (no_large_offset || code != PLUS || XEXP (x, 0) != stack_pointer_rtx
2444 || size1 > UNITS_PER_WORD)
2446 return off >= 0 && off < 32768;
2451 return (!no_large_offset
2452 /* With -fpic, we must wrap it in an unspec to show the B14
2455 && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
2456 && sdata_symbolic_operand (x, Pmode));
2464 c6x_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
2466 return c6x_legitimate_address_p_1 (mode, x, strict, false);
2470 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
2471 rtx x ATTRIBUTE_UNUSED)
2476 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2478 c6x_preferred_rename_class (reg_class_t cl)
2481 return NONPREDICATE_A_REGS;
2483 return NONPREDICATE_B_REGS;
2484 if (cl == ALL_REGS || cl == GENERAL_REGS)
2485 return NONPREDICATE_REGS;
2489 /* Implements FINAL_PRESCAN_INSN. */
2491 c6x_final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED,
2492 int noperands ATTRIBUTE_UNUSED)
2494 c6x_current_insn = insn;
2497 /* A structure to describe the stack layout of a function. The layout is
2500 [saved frame pointer (or possibly padding0)]
2501 --> incoming stack pointer, new hard frame pointer
2502 [saved call-used regs]
2504 --> soft frame pointer
2506 [outgoing arguments]
2509 The structure members are laid out in this order. */
2514 /* Number of registers to save. */
2517 HOST_WIDE_INT frame;
2518 int outgoing_arguments_size;
2521 HOST_WIDE_INT to_allocate;
2522 /* The offsets relative to the incoming stack pointer (which
2523 becomes HARD_FRAME_POINTER). */
2524 HOST_WIDE_INT frame_pointer_offset;
2525 HOST_WIDE_INT b3_offset;
2527 /* True if we should call push_rts/pop_rts to save and restore
2532 /* Return true if we need to save and modify the PIC register in the
2536 must_reload_pic_reg_p (void)
2538 struct cgraph_local_info *i = NULL;
2543 i = cgraph_node::local_info (current_function_decl);
2545 if ((crtl->uses_pic_offset_table || !crtl->is_leaf) && !i->local)
2550 /* Return 1 if we need to save REGNO. */
2552 c6x_save_reg (unsigned int regno)
2554 return ((df_regs_ever_live_p (regno)
2555 && !call_used_regs[regno]
2556 && !fixed_regs[regno])
2557 || (regno == RETURN_ADDR_REGNO
2558 && (df_regs_ever_live_p (regno)
2560 || (regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ()));
2563 /* Examine the number of regs NREGS we've determined we must save.
2564 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2565 prologue and epilogue. */
2568 use_push_rts_p (int nregs)
2570 if (TARGET_INSNS_64PLUS && optimize_function_for_size_p (cfun)
2571 && !cfun->machine->contains_sibcall
2572 && !cfun->returns_struct
2573 && !TARGET_LONG_CALLS
2574 && nregs >= 6 && !frame_pointer_needed)
2579 /* Return number of saved general prupose registers. */
2582 c6x_nsaved_regs (void)
2587 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
2588 if (c6x_save_reg (regno))
2593 /* The safe debug order mandated by the ABI. */
2594 static unsigned reg_save_order[] =
2596 REG_A10, REG_A11, REG_A12, REG_A13,
2598 REG_B10, REG_B11, REG_B12, REG_B13,
2602 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2604 /* Compute the layout of the stack frame and store it in FRAME. */
2607 c6x_compute_frame_layout (struct c6x_frame *frame)
2609 HOST_WIDE_INT size = get_frame_size ();
2610 HOST_WIDE_INT offset;
2613 /* We use the four bytes which are technically inside the caller's frame,
2614 usually to save the frame pointer. */
2616 frame->padding0 = 0;
2617 nregs = c6x_nsaved_regs ();
2618 frame->push_rts = false;
2619 frame->b3_offset = 0;
2620 if (use_push_rts_p (nregs))
2622 frame->push_rts = true;
2623 frame->b3_offset = (TARGET_BIG_ENDIAN ? -12 : -13) * 4;
2626 else if (c6x_save_reg (REG_B3))
2629 for (idx = N_SAVE_ORDER - 1; reg_save_order[idx] != REG_B3; idx--)
2631 if (c6x_save_reg (reg_save_order[idx]))
2632 frame->b3_offset -= 4;
2635 frame->nregs = nregs;
2637 if (size == 0 && nregs == 0)
2639 frame->padding0 = 4;
2640 frame->padding1 = frame->padding2 = 0;
2641 frame->frame_pointer_offset = frame->to_allocate = 0;
2642 frame->outgoing_arguments_size = 0;
2646 if (!frame->push_rts)
2647 offset += frame->nregs * 4;
2649 if (offset == 0 && size == 0 && crtl->outgoing_args_size == 0
2651 /* Don't use the bottom of the caller's frame if we have no
2652 allocation of our own and call other functions. */
2653 frame->padding0 = frame->padding1 = 4;
2654 else if (offset & 4)
2655 frame->padding1 = 4;
2657 frame->padding1 = 0;
2659 offset += frame->padding0 + frame->padding1;
2660 frame->frame_pointer_offset = offset;
2663 frame->outgoing_arguments_size = crtl->outgoing_args_size;
2664 offset += frame->outgoing_arguments_size;
2666 if ((offset & 4) == 0)
2667 frame->padding2 = 8;
2669 frame->padding2 = 4;
2670 frame->to_allocate = offset + frame->padding2;
2673 /* Return the offset between two registers, one to be eliminated, and the other
2674 its replacement, at the start of a routine. */
2677 c6x_initial_elimination_offset (int from, int to)
2679 struct c6x_frame frame;
2680 c6x_compute_frame_layout (&frame);
2682 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
2684 else if (from == FRAME_POINTER_REGNUM
2685 && to == HARD_FRAME_POINTER_REGNUM)
2686 return -frame.frame_pointer_offset;
2689 gcc_assert (to == STACK_POINTER_REGNUM);
2691 if (from == ARG_POINTER_REGNUM)
2692 return frame.to_allocate + (frame.push_rts ? 56 : 0);
2694 gcc_assert (from == FRAME_POINTER_REGNUM);
2695 return frame.to_allocate - frame.frame_pointer_offset;
2699 /* Given FROM and TO register numbers, say whether this elimination is
2700 allowed. Frame pointer elimination is automatically handled. */
2703 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
2705 if (to == STACK_POINTER_REGNUM)
2706 return !frame_pointer_needed;
2710 /* Emit insns to increment the stack pointer by OFFSET. If
2711 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2712 Does nothing if the offset is zero. */
2715 emit_add_sp_const (HOST_WIDE_INT offset, bool frame_related_p)
2717 rtx to_add = GEN_INT (offset);
2718 rtx orig_to_add = to_add;
2724 if (offset < -32768 || offset > 32767)
2726 rtx reg = gen_rtx_REG (SImode, REG_A0);
2727 rtx low = GEN_INT (trunc_int_for_mode (offset, HImode));
2729 insn = emit_insn (gen_movsi_high (reg, low));
2730 if (frame_related_p)
2731 RTX_FRAME_RELATED_P (insn) = 1;
2732 insn = emit_insn (gen_movsi_lo_sum (reg, reg, to_add));
2733 if (frame_related_p)
2734 RTX_FRAME_RELATED_P (insn) = 1;
2737 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2739 if (frame_related_p)
2742 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2743 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
2744 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2747 RTX_FRAME_RELATED_P (insn) = 1;
2751 /* Prologue and epilogue. */
2753 c6x_expand_prologue (void)
2755 struct c6x_frame frame;
2759 HOST_WIDE_INT initial_offset, off, added_already;
2761 c6x_compute_frame_layout (&frame);
2763 if (flag_stack_usage_info)
2764 current_function_static_stack_size = frame.to_allocate;
2766 initial_offset = -frame.to_allocate;
2769 emit_insn (gen_push_rts ());
2770 nsaved = frame.nregs;
2773 /* If the offsets would be too large for the memory references we will
2774 create to save registers, do the stack allocation in two parts.
2775 Ensure by subtracting 8 that we don't store to the word pointed to
2776 by the stack pointer. */
2777 if (initial_offset < -32768)
2778 initial_offset = -frame.frame_pointer_offset - 8;
2780 if (frame.to_allocate > 0)
2781 gcc_assert (initial_offset != 0);
2783 off = -initial_offset + 4 - frame.padding0;
2785 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2788 if (frame_pointer_needed)
2790 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2791 /* We go through some contortions here to both follow the ABI's
2792 recommendation that FP == incoming SP, and to avoid writing or
2793 reading the word pointed to by the stack pointer. */
2794 rtx addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
2795 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2797 insn = emit_move_insn (gen_frame_mem (Pmode, addr), fp_reg);
2798 RTX_FRAME_RELATED_P (insn) = 1;
2800 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, stack_pointer_rtx,
2802 RTX_FRAME_RELATED_P (insn) = 1;
2807 emit_add_sp_const (initial_offset - added_already, true);
2809 if (nsaved < frame.nregs)
2813 for (i = 0; i < N_SAVE_ORDER; i++)
2815 int idx = N_SAVE_ORDER - i - 1;
2816 unsigned regno = reg_save_order[idx];
2818 enum machine_mode save_mode = SImode;
2820 if (regno == REG_A15 && frame_pointer_needed)
2821 /* Already saved. */
2823 if (!c6x_save_reg (regno))
2826 if (TARGET_STDW && (off & 4) == 0 && off <= 256
2828 && i + 1 < N_SAVE_ORDER
2829 && reg_save_order[idx - 1] == regno - 1
2830 && c6x_save_reg (regno - 1))
2836 reg = gen_rtx_REG (save_mode, regno);
2837 off -= GET_MODE_SIZE (save_mode);
2839 insn = emit_move_insn (adjust_address (mem, save_mode, off),
2841 RTX_FRAME_RELATED_P (insn) = 1;
2843 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2846 gcc_assert (nsaved == frame.nregs);
2847 emit_add_sp_const (-frame.to_allocate - initial_offset, true);
2848 if (must_reload_pic_reg_p ())
2850 if (dsbt_decl == NULL)
2854 t = build_index_type (integer_one_node);
2855 t = build_array_type (integer_type_node, t);
2856 t = build_decl (BUILTINS_LOCATION, VAR_DECL,
2857 get_identifier ("__c6xabi_DSBT_BASE"), t);
2858 DECL_ARTIFICIAL (t) = 1;
2859 DECL_IGNORED_P (t) = 1;
2860 DECL_EXTERNAL (t) = 1;
2861 TREE_STATIC (t) = 1;
2862 TREE_PUBLIC (t) = 1;
2867 emit_insn (gen_setup_dsbt (pic_offset_table_rtx,
2868 XEXP (DECL_RTL (dsbt_decl), 0)));
2873 c6x_expand_epilogue (bool sibcall)
2876 struct c6x_frame frame;
2881 c6x_compute_frame_layout (&frame);
2883 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2885 /* Insert a dummy set/use of the stack pointer. This creates a
2886 scheduler barrier between the prologue saves and epilogue restores. */
2887 emit_insn (gen_epilogue_barrier (stack_pointer_rtx, stack_pointer_rtx));
2889 /* If the offsets would be too large for the memory references we will
2890 create to restore registers, do a preliminary stack adjustment here. */
2891 off = frame.to_allocate - frame.frame_pointer_offset + frame.padding1;
2894 nsaved = frame.nregs;
2898 if (frame.to_allocate > 32768)
2900 /* Don't add the entire offset so that we leave an unused word
2901 above the stack pointer. */
2902 emit_add_sp_const ((off - 16) & ~7, false);
2906 for (i = 0; i < N_SAVE_ORDER; i++)
2908 unsigned regno = reg_save_order[i];
2910 enum machine_mode save_mode = SImode;
2912 if (!c6x_save_reg (regno))
2914 if (regno == REG_A15 && frame_pointer_needed)
2917 if (TARGET_STDW && (off & 4) == 0 && off < 256
2919 && i + 1 < N_SAVE_ORDER
2920 && reg_save_order[i + 1] == regno + 1
2921 && c6x_save_reg (regno + 1))
2926 reg = gen_rtx_REG (save_mode, regno);
2928 emit_move_insn (reg, adjust_address (mem, save_mode, off));
2930 off += GET_MODE_SIZE (save_mode);
2931 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2934 if (!frame_pointer_needed)
2935 emit_add_sp_const (off + frame.padding0 - 4, false);
2938 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2939 rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
2940 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2942 emit_insn (gen_addsi3 (stack_pointer_rtx, hard_frame_pointer_rtx,
2944 emit_move_insn (fp_reg, gen_frame_mem (Pmode, addr));
2947 gcc_assert (nsaved == frame.nregs);
2951 emit_jump_insn (gen_pop_rts ());
2953 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
2954 RETURN_ADDR_REGNO)));
2958 /* Return the value of the return address for the frame COUNT steps up
2959 from the current frame, after the prologue.
2960 We punt for everything but the current frame by returning const0_rtx. */
2963 c6x_return_addr_rtx (int count)
2968 return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNO);
2971 /* Return true iff TYPE is one of the shadow types. */
2973 shadow_type_p (enum attr_type type)
2975 return (type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW
2976 || type == TYPE_MULT_SHADOW);
2979 /* Return true iff INSN is a shadow pattern. */
2983 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2985 return shadow_type_p (get_attr_type (insn));
2988 /* Return true iff INSN is a shadow or blockage pattern. */
2990 shadow_or_blockage_p (rtx insn)
2992 enum attr_type type;
2993 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2995 type = get_attr_type (insn);
2996 return shadow_type_p (type) || type == TYPE_BLOCKAGE;
2999 /* Translate UNITS into a bitmask of units we can reserve for this
3002 get_reservation_flags (enum attr_units units)
3008 return RESERVATION_FLAG_D;
3010 return RESERVATION_FLAG_L;
3012 return RESERVATION_FLAG_S;
3014 return RESERVATION_FLAG_M;
3016 return RESERVATION_FLAG_LS;
3018 return RESERVATION_FLAG_DL;
3020 return RESERVATION_FLAG_DS;
3022 return RESERVATION_FLAG_DLS;
3028 /* Compute the side of the machine used by INSN, which reserves UNITS.
3029 This must match the reservations in the scheduling description. */
3031 get_insn_side (rtx insn, enum attr_units units)
3033 if (units == UNITS_D_ADDR)
3034 return (get_attr_addr_regfile (insn) == ADDR_REGFILE_A ? 0 : 1);
3037 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
3038 if (rf == DEST_REGFILE_ANY)
3039 return get_attr_type (insn) == TYPE_BRANCH ? 0 : 1;
3041 return rf == DEST_REGFILE_A ? 0 : 1;
3045 /* After scheduling, walk the insns between HEAD and END and assign unit
3048 assign_reservations (rtx head, rtx end)
3051 for (insn = head; insn != NEXT_INSN (end); insn = NEXT_INSN (insn))
3053 unsigned int sched_mask, reserved;
3057 int rsrv_count[2][4];
3060 if (GET_MODE (insn) != TImode)
3065 /* Find the last insn in the packet. It has a state recorded for it,
3066 which we can use to determine the units we should be using. */
3068 (within != NEXT_INSN (end)
3069 && (within == insn || GET_MODE (within) != TImode));
3070 within = NEXT_INSN (within))
3073 if (!NONDEBUG_INSN_P (within))
3075 icode = recog_memoized (within);
3078 if (shadow_p (within))
3080 if (INSN_INFO_ENTRY (INSN_UID (within)).reservation != 0)
3081 reserved |= 1 << INSN_INFO_ENTRY (INSN_UID (within)).reservation;
3084 if (last == NULL_RTX)
3087 sched_mask = INSN_INFO_ENTRY (INSN_UID (last)).unit_mask;
3088 sched_mask &= ~reserved;
3090 memset (rsrv_count, 0, sizeof rsrv_count);
3091 rsrv[0] = rsrv[1] = ~0;
3092 for (i = 0; i < 8; i++)
3096 unsigned unit_bit = 1 << (unit + side * UNIT_QID_SIDE_OFFSET);
3097 /* Clear the bits which we expect to reserve in the following loop,
3098 leaving the ones set which aren't present in the scheduler's
3099 state and shouldn't be reserved. */
3100 if (sched_mask & unit_bit)
3101 rsrv[i / 4] &= ~(1 << unit);
3104 /* Walk through the insns that occur in the same cycle. We use multiple
3105 passes to assign units, assigning for insns with the most specific
3106 requirements first. */
3107 for (pass = 0; pass < 4; pass++)
3109 (within != NEXT_INSN (end)
3110 && (within == insn || GET_MODE (within) != TImode));
3111 within = NEXT_INSN (within))
3113 int uid = INSN_UID (within);
3114 int this_rsrv, side;
3116 enum attr_units units;
3117 enum attr_type type;
3120 if (!NONDEBUG_INSN_P (within))
3122 icode = recog_memoized (within);
3125 if (INSN_INFO_ENTRY (uid).reservation != 0)
3127 units = get_attr_units (within);
3128 type = get_attr_type (within);
3129 this_rsrv = get_reservation_flags (units);
3132 side = get_insn_side (within, units);
3134 /* Certain floating point instructions are treated specially. If
3135 an insn can choose between units it can reserve, and its
3136 reservation spans more than one cycle, the reservation contains
3137 special markers in the first cycle to help us reconstruct what
3138 the automaton chose. */
3139 if ((type == TYPE_ADDDP || type == TYPE_FP4)
3140 && units == UNITS_LS)
3142 int test1_code = ((type == TYPE_FP4 ? UNIT_QID_FPL1 : UNIT_QID_ADDDPL1)
3143 + side * UNIT_QID_SIDE_OFFSET);
3144 int test2_code = ((type == TYPE_FP4 ? UNIT_QID_FPS1 : UNIT_QID_ADDDPS1)
3145 + side * UNIT_QID_SIDE_OFFSET);
3146 if ((sched_mask & (1 << test1_code)) != 0)
3148 this_rsrv = RESERVATION_FLAG_L;
3149 sched_mask &= ~(1 << test1_code);
3151 else if ((sched_mask & (1 << test2_code)) != 0)
3153 this_rsrv = RESERVATION_FLAG_S;
3154 sched_mask &= ~(1 << test2_code);
3158 if ((this_rsrv & (this_rsrv - 1)) == 0)
3160 int t = exact_log2 (this_rsrv) + side * UNIT_QID_SIDE_OFFSET;
3161 rsrv[side] |= this_rsrv;
3162 INSN_INFO_ENTRY (uid).reservation = t;
3168 for (j = 0; j < 4; j++)
3169 if (this_rsrv & (1 << j))
3170 rsrv_count[side][j]++;
3173 if ((pass == 2 && this_rsrv != RESERVATION_FLAG_DLS)
3174 || (pass == 3 && this_rsrv == RESERVATION_FLAG_DLS))
3176 int best = -1, best_cost = INT_MAX;
3177 for (j = 0; j < 4; j++)
3178 if ((this_rsrv & (1 << j))
3179 && !(rsrv[side] & (1 << j))
3180 && rsrv_count[side][j] < best_cost)
3182 best_cost = rsrv_count[side][j];
3185 gcc_assert (best != -1);
3186 rsrv[side] |= 1 << best;
3187 for (j = 0; j < 4; j++)
3188 if ((this_rsrv & (1 << j)) && j != best)
3189 rsrv_count[side][j]--;
3191 INSN_INFO_ENTRY (uid).reservation
3192 = best + side * UNIT_QID_SIDE_OFFSET;
3198 /* Return a factor by which to weight unit imbalances for a reservation
3201 unit_req_factor (enum unitreqs r)
3223 /* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3224 requirements. Returns zero if INSN can't be handled, otherwise
3225 either one or two to show how many of the two pairs are in use.
3226 REQ1 is always used, it holds what is normally thought of as the
3227 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3228 describe a cross path, or for loads/stores, the T unit. */
3230 get_unit_reqs (rtx insn, int *req1, int *side1, int *req2, int *side2)
3232 enum attr_units units;
3233 enum attr_cross cross;
3236 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
3238 units = get_attr_units (insn);
3239 if (units == UNITS_UNKNOWN)
3241 side = get_insn_side (insn, units);
3242 cross = get_attr_cross (insn);
3244 req = (units == UNITS_D ? UNIT_REQ_D
3245 : units == UNITS_D_ADDR ? UNIT_REQ_D
3246 : units == UNITS_DL ? UNIT_REQ_DL
3247 : units == UNITS_DS ? UNIT_REQ_DS
3248 : units == UNITS_L ? UNIT_REQ_L
3249 : units == UNITS_LS ? UNIT_REQ_LS
3250 : units == UNITS_S ? UNIT_REQ_S
3251 : units == UNITS_M ? UNIT_REQ_M
3252 : units == UNITS_DLS ? UNIT_REQ_DLS
3254 gcc_assert (req != -1);
3257 if (units == UNITS_D_ADDR)
3260 *side2 = side ^ (cross == CROSS_Y ? 1 : 0);
3263 else if (cross == CROSS_Y)
3272 /* Walk the insns between and including HEAD and TAIL, and mark the
3273 resource requirements in the unit_reqs table. */
3275 count_unit_reqs (unit_req_table reqs, rtx head, rtx tail)
3279 memset (reqs, 0, sizeof (unit_req_table));
3281 for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
3283 int side1, side2, req1, req2;
3285 switch (get_unit_reqs (insn, &req1, &side1, &req2, &side2))
3288 reqs[side2][req2]++;
3291 reqs[side1][req1]++;
3297 /* Update the table REQS by merging more specific unit reservations into
3298 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3299 UNIT_REQ_DL, DS, and DLS. */
3301 merge_unit_reqs (unit_req_table reqs)
3304 for (side = 0; side < 2; side++)
3306 int d = reqs[side][UNIT_REQ_D];
3307 int l = reqs[side][UNIT_REQ_L];
3308 int s = reqs[side][UNIT_REQ_S];
3309 int dl = reqs[side][UNIT_REQ_DL];
3310 int ls = reqs[side][UNIT_REQ_LS];
3311 int ds = reqs[side][UNIT_REQ_DS];
3313 reqs[side][UNIT_REQ_DL] += d;
3314 reqs[side][UNIT_REQ_DL] += l;
3315 reqs[side][UNIT_REQ_DS] += d;
3316 reqs[side][UNIT_REQ_DS] += s;
3317 reqs[side][UNIT_REQ_LS] += l;
3318 reqs[side][UNIT_REQ_LS] += s;
3319 reqs[side][UNIT_REQ_DLS] += ds + dl + ls + d + l + s;
3323 /* Examine the table REQS and return a measure of unit imbalance by comparing
3324 the two sides of the machine. If, for example, D1 is used twice and D2
3325 used not at all, the return value should be 1 in the absence of other
3328 unit_req_imbalance (unit_req_table reqs)
3333 for (i = 0; i < UNIT_REQ_MAX; i++)
3335 int factor = unit_req_factor ((enum unitreqs) i);
3336 int diff = abs (reqs[0][i] - reqs[1][i]);
3337 val += (diff + factor - 1) / factor / 2;
3342 /* Return the resource-constrained minimum iteration interval given the
3343 data in the REQS table. This must have been processed with
3344 merge_unit_reqs already. */
3346 res_mii (unit_req_table reqs)
3350 for (side = 0; side < 2; side++)
3351 for (req = 0; req < UNIT_REQ_MAX; req++)
3353 int factor = unit_req_factor ((enum unitreqs) req);
3354 worst = MAX ((reqs[side][UNIT_REQ_D] + factor - 1) / factor, worst);
3360 /* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3361 the operands that are involved in the (up to) two reservations, as
3362 found by get_unit_reqs. Return true if we did this successfully, false
3363 if we couldn't identify what to do with INSN. */
3365 get_unit_operand_masks (rtx insn, unsigned int *pmask1, unsigned int *pmask2)
3367 enum attr_op_pattern op_pat;
3369 if (recog_memoized (insn) < 0)
3371 if (GET_CODE (PATTERN (insn)) == COND_EXEC)
3373 extract_insn (insn);
3374 op_pat = get_attr_op_pattern (insn);
3375 if (op_pat == OP_PATTERN_DT)
3377 gcc_assert (recog_data.n_operands == 2);
3382 else if (op_pat == OP_PATTERN_TD)
3384 gcc_assert (recog_data.n_operands == 2);
3389 else if (op_pat == OP_PATTERN_SXS)
3391 gcc_assert (recog_data.n_operands == 3);
3392 *pmask1 = (1 << 0) | (1 << 2);
3396 else if (op_pat == OP_PATTERN_SX)
3398 gcc_assert (recog_data.n_operands == 2);
3403 else if (op_pat == OP_PATTERN_SSX)
3405 gcc_assert (recog_data.n_operands == 3);
3406 *pmask1 = (1 << 0) | (1 << 1);
3413 /* Try to replace a register in INSN, which has corresponding rename info
3414 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3415 about the operands that must be renamed and the side they are on.
3416 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3417 We recompute this information locally after our transformation, and keep
3418 it only if we managed to improve the balance. */
3420 try_rename_operands (rtx head, rtx tail, unit_req_table reqs, rtx insn,
3421 insn_rr_info *info, unsigned int op_mask, int orig_side)
3423 enum reg_class super_class = orig_side == 0 ? B_REGS : A_REGS;
3424 HARD_REG_SET unavailable;
3425 du_head_p this_head;
3426 struct du_chain *chain;
3429 int best_reg, old_reg;
3430 vec<du_head_p> involved_chains = vNULL;
3431 unit_req_table new_reqs;
3433 for (i = 0, tmp_mask = op_mask; tmp_mask; i++)
3436 if ((tmp_mask & (1 << i)) == 0)
3438 if (info->op_info[i].n_chains != 1)
3440 op_chain = regrename_chain_from_id (info->op_info[i].heads[0]->id);
3441 involved_chains.safe_push (op_chain);
3442 tmp_mask &= ~(1 << i);
3445 if (involved_chains.length () > 1)
3448 this_head = involved_chains[0];
3449 if (this_head->cannot_rename)
3452 for (chain = this_head->first; chain; chain = chain->next_use)
3454 unsigned int mask1, mask2, mask_changed;
3455 int count, side1, side2, req1, req2;
3456 insn_rr_info *this_rr = &insn_rr[INSN_UID (chain->insn)];
3458 count = get_unit_reqs (chain->insn, &req1, &side1, &req2, &side2);
3463 if (!get_unit_operand_masks (chain->insn, &mask1, &mask2))
3466 extract_insn (chain->insn);
3469 for (i = 0; i < recog_data.n_operands; i++)
3472 int n_this_op = this_rr->op_info[i].n_chains;
3473 for (j = 0; j < n_this_op; j++)
3475 du_head_p other = this_rr->op_info[i].heads[j];
3476 if (regrename_chain_from_id (other->id) == this_head)
3484 mask_changed |= 1 << i;
3486 gcc_assert (mask_changed != 0);
3487 if (mask_changed != mask1 && mask_changed != mask2)
3491 /* If we get here, we can do the renaming. */
3492 COMPL_HARD_REG_SET (unavailable, reg_class_contents[(int) super_class]);
3494 old_reg = this_head->regno;
3495 best_reg = find_best_rename_reg (this_head, super_class, &unavailable, old_reg);
3497 regrename_do_replace (this_head, best_reg);
3499 count_unit_reqs (new_reqs, head, PREV_INSN (tail));
3500 merge_unit_reqs (new_reqs);
3503 fprintf (dump_file, "reshuffle for insn %d, op_mask %x, "
3504 "original side %d, new reg %d\n",
3505 INSN_UID (insn), op_mask, orig_side, best_reg);
3506 fprintf (dump_file, " imbalance %d -> %d\n",
3507 unit_req_imbalance (reqs), unit_req_imbalance (new_reqs));
3509 if (unit_req_imbalance (new_reqs) > unit_req_imbalance (reqs))
3510 regrename_do_replace (this_head, old_reg);
3512 memcpy (reqs, new_reqs, sizeof (unit_req_table));
3515 involved_chains.release ();
3518 /* Find insns in LOOP which would, if shifted to the other side
3519 of the machine, reduce an imbalance in the unit reservations. */
3521 reshuffle_units (basic_block loop)
3523 rtx head = BB_HEAD (loop);
3524 rtx tail = BB_END (loop);
3526 unit_req_table reqs;
3531 count_unit_reqs (reqs, head, PREV_INSN (tail));
3532 merge_unit_reqs (reqs);
3534 regrename_init (true);
3536 bitmap_initialize (&bbs, &bitmap_default_obstack);
3538 FOR_EACH_EDGE (e, ei, loop->preds)
3539 bitmap_set_bit (&bbs, e->src->index);
3541 bitmap_set_bit (&bbs, loop->index);
3542 regrename_analyze (&bbs);
3544 for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
3546 enum attr_units units;
3547 int count, side1, side2, req1, req2;
3548 unsigned int mask1, mask2;
3551 if (!NONDEBUG_INSN_P (insn))
3554 count = get_unit_reqs (insn, &req1, &side1, &req2, &side2);
3559 if (!get_unit_operand_masks (insn, &mask1, &mask2))
3562 info = &insn_rr[INSN_UID (insn)];
3563 if (info->op_info == NULL)
3566 if (reqs[side1][req1] > 1
3567 && reqs[side1][req1] > 2 * reqs[side1 ^ 1][req1])
3569 try_rename_operands (head, tail, reqs, insn, info, mask1, side1);
3572 units = get_attr_units (insn);
3573 if (units == UNITS_D_ADDR)
3575 gcc_assert (count == 2);
3576 if (reqs[side2][req2] > 1
3577 && reqs[side2][req2] > 2 * reqs[side2 ^ 1][req2])
3579 try_rename_operands (head, tail, reqs, insn, info, mask2, side2);
3583 regrename_finish ();
3586 /* Backend scheduling state. */
3587 typedef struct c6x_sched_context
3589 /* The current scheduler clock, saved in the sched_reorder hook. */
3590 int curr_sched_clock;
3592 /* Number of insns issued so far in this cycle. */
3593 int issued_this_cycle;
3595 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3596 theoretical maximum for number of jumps in flight is 12: 2 every
3597 cycle, with a latency of 6 cycles each. This is a circular
3598 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3599 jumps have a higher index. This array should be accessed through
3600 the jump_cycle function. */
3601 int jump_cycles[12];
3602 int jump_cycle_index;
3604 /* In parallel with jump_cycles, this array records the opposite of
3605 the condition used in each pending jump. This is used to
3606 predicate insns that are scheduled in the jump's delay slots. If
3607 this is NULL_RTX no such predication happens. */
3610 /* Similar to the jump_cycles mechanism, but here we take into
3611 account all insns with delay slots, to avoid scheduling asms into
3613 int delays_finished_at;
3615 /* The following variable value is the last issued insn. */
3616 rtx last_scheduled_insn;
3617 /* The last issued insn that isn't a shadow of another. */
3618 rtx_insn *last_scheduled_iter0;
3620 /* The following variable value is DFA state before issuing the
3621 first insn in the current clock cycle. We do not use this member
3622 of the structure directly; we copy the data in and out of
3623 prev_cycle_state. */
3624 state_t prev_cycle_state_ctx;
3626 int reg_n_accesses[FIRST_PSEUDO_REGISTER];
3627 int reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3628 int reg_set_in_cycle[FIRST_PSEUDO_REGISTER];
3630 int tmp_reg_n_accesses[FIRST_PSEUDO_REGISTER];
3631 int tmp_reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3632 } *c6x_sched_context_t;
3634 /* The current scheduling state. */
3635 static struct c6x_sched_context ss;
3637 /* The following variable value is DFA state before issuing the first insn
3638 in the current clock cycle. This is used in c6x_variable_issue for
3639 comparison with the state after issuing the last insn in a cycle. */
3640 static state_t prev_cycle_state;
3642 /* Set when we discover while processing an insn that it would lead to too
3643 many accesses of the same register. */
3644 static bool reg_access_stall;
3646 /* The highest insn uid after delayed insns were split, but before loop bodies
3647 were copied by the modulo scheduling code. */
3648 static int sploop_max_uid_iter0;
3650 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3651 so the caller does not specifically have to test for it. */
3653 get_jump_cycle (int n)
3657 n += ss.jump_cycle_index;
3660 return ss.jump_cycles[n];
3663 /* Look up the jump condition with index N. */
3665 get_jump_cond (int n)
3669 n += ss.jump_cycle_index;
3672 return ss.jump_cond[n];
3675 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3676 has delay slots beyond CLOCK_VAR, return -1. */
3678 first_jump_index (int clock_var)
3684 int t = get_jump_cycle (n);
3693 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3694 and has the opposite condition of COND. */
3696 record_jump (int cycle, rtx cond)
3698 if (ss.jump_cycle_index == 0)
3699 ss.jump_cycle_index = 11;
3701 ss.jump_cycle_index--;
3702 ss.jump_cycles[ss.jump_cycle_index] = cycle;
3703 ss.jump_cond[ss.jump_cycle_index] = cond;
3706 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3709 insn_set_clock (rtx insn, int cycle)
3711 unsigned uid = INSN_UID (insn);
3713 if (uid >= INSN_INFO_LENGTH)
3714 insn_info.safe_grow (uid * 5 / 4 + 10);
3716 INSN_INFO_ENTRY (uid).clock = cycle;
3717 INSN_INFO_ENTRY (uid).new_cond = NULL;
3718 INSN_INFO_ENTRY (uid).reservation = 0;
3719 INSN_INFO_ENTRY (uid).ebb_start = false;
3722 /* Return the clock cycle we set for the insn with uid UID. */
3724 insn_uid_get_clock (int uid)
3726 return INSN_INFO_ENTRY (uid).clock;
3729 /* Return the clock cycle we set for INSN. */
3731 insn_get_clock (rtx insn)
3733 return insn_uid_get_clock (INSN_UID (insn));
3736 /* Examine INSN, and if it is a conditional jump of any kind, return
3737 the opposite of the condition in which it branches. Otherwise,
3740 condjump_opposite_condition (rtx insn)
3742 rtx pat = PATTERN (insn);
3743 int icode = INSN_CODE (insn);
3746 if (icode == CODE_FOR_br_true || icode == CODE_FOR_br_false)
3748 x = XEXP (SET_SRC (pat), 0);
3749 if (icode == CODE_FOR_br_false)
3752 if (GET_CODE (pat) == COND_EXEC)
3754 rtx t = COND_EXEC_CODE (pat);
3755 if ((GET_CODE (t) == PARALLEL
3756 && GET_CODE (XVECEXP (t, 0, 0)) == RETURN)
3757 || (GET_CODE (t) == UNSPEC && XINT (t, 1) == UNSPEC_REAL_JUMP)
3758 || (GET_CODE (t) == SET && SET_DEST (t) == pc_rtx))
3759 x = COND_EXEC_TEST (pat);
3764 enum rtx_code code = GET_CODE (x);
3765 x = gen_rtx_fmt_ee (code == EQ ? NE : EQ,
3766 GET_MODE (x), XEXP (x, 0),
3772 /* Return true iff COND1 and COND2 are exactly opposite conditions
3773 one of them NE and the other EQ. */
3775 conditions_opposite_p (rtx cond1, rtx cond2)
3777 return (rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
3778 && rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1))
3779 && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)));
3782 /* Return true if we can add a predicate COND to INSN, or if INSN
3783 already has that predicate. If DOIT is true, also perform the
3786 predicate_insn (rtx insn, rtx cond, bool doit)
3789 if (cond == NULL_RTX)
3795 if (get_attr_predicable (insn) == PREDICABLE_YES
3796 && GET_CODE (PATTERN (insn)) != COND_EXEC)
3800 rtx newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3801 PATTERN (insn) = newpat;
3802 INSN_CODE (insn) = -1;
3806 if (GET_CODE (PATTERN (insn)) == COND_EXEC
3807 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn)), cond))
3809 icode = INSN_CODE (insn);
3810 if (icode == CODE_FOR_real_jump
3811 || icode == CODE_FOR_jump
3812 || icode == CODE_FOR_indirect_jump)
3814 rtx pat = PATTERN (insn);
3815 rtx dest = (icode == CODE_FOR_real_jump ? XVECEXP (pat, 0, 0)
3816 : icode == CODE_FOR_jump ? XEXP (SET_SRC (pat), 0)
3822 newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3824 newpat = gen_br_true (cond, XEXP (cond, 0), dest);
3825 PATTERN (insn) = newpat;
3826 INSN_CODE (insn) = -1;
3830 if (INSN_CODE (insn) == CODE_FOR_br_true)
3832 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3833 return rtx_equal_p (br_cond, cond);
3835 if (INSN_CODE (insn) == CODE_FOR_br_false)
3837 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3838 return conditions_opposite_p (br_cond, cond);
3843 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3845 init_sched_state (c6x_sched_context_t sc)
3847 sc->last_scheduled_insn = NULL_RTX;
3848 sc->last_scheduled_iter0 = NULL;
3849 sc->issued_this_cycle = 0;
3850 memset (sc->jump_cycles, 0, sizeof sc->jump_cycles);
3851 memset (sc->jump_cond, 0, sizeof sc->jump_cond);
3852 sc->jump_cycle_index = 0;
3853 sc->delays_finished_at = 0;
3854 sc->curr_sched_clock = 0;
3856 sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3858 memset (sc->reg_n_accesses, 0, sizeof sc->reg_n_accesses);
3859 memset (sc->reg_n_xaccesses, 0, sizeof sc->reg_n_xaccesses);
3860 memset (sc->reg_set_in_cycle, 0, sizeof sc->reg_set_in_cycle);
3862 state_reset (sc->prev_cycle_state_ctx);
3865 /* Allocate store for new scheduling context. */
3867 c6x_alloc_sched_context (void)
3869 return xmalloc (sizeof (struct c6x_sched_context));
3872 /* If CLEAN_P is true then initializes _SC with clean data,
3873 and from the global context otherwise. */
3875 c6x_init_sched_context (void *_sc, bool clean_p)
3877 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3881 init_sched_state (sc);
3886 sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3887 memcpy (sc->prev_cycle_state_ctx, prev_cycle_state, dfa_state_size);
3891 /* Sets the global scheduling context to the one pointed to by _SC. */
3893 c6x_set_sched_context (void *_sc)
3895 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3897 gcc_assert (sc != NULL);
3899 memcpy (prev_cycle_state, sc->prev_cycle_state_ctx, dfa_state_size);
3902 /* Clear data in _SC. */
3904 c6x_clear_sched_context (void *_sc)
3906 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3907 gcc_assert (_sc != NULL);
3909 free (sc->prev_cycle_state_ctx);
3914 c6x_free_sched_context (void *_sc)
3919 /* True if we are currently performing a preliminary scheduling
3920 pass before modulo scheduling; we can't allow the scheduler to
3921 modify instruction patterns using packetization assumptions,
3922 since there will be another scheduling pass later if modulo
3923 scheduling fails. */
3924 static bool in_hwloop;
3926 /* Provide information about speculation capabilities, and set the
3927 DO_BACKTRACKING flag. */
3929 c6x_set_sched_flags (spec_info_t spec_info)
3931 unsigned int *flags = &(current_sched_info->flags);
3933 if (*flags & SCHED_EBB)
3935 *flags |= DO_BACKTRACKING | DO_PREDICATION;
3938 *flags |= DONT_BREAK_DEPENDENCIES;
3940 spec_info->mask = 0;
3943 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3946 c6x_issue_rate (void)
3951 /* Used together with the collapse_ndfa option, this ensures that we reach a
3952 deterministic automaton state before trying to advance a cycle.
3953 With collapse_ndfa, genautomata creates advance cycle arcs only for
3954 such deterministic states. */
3957 c6x_sched_dfa_pre_cycle_insn (void)
3962 /* We're beginning a new block. Initialize data structures as necessary. */
3965 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED,
3966 int sched_verbose ATTRIBUTE_UNUSED,
3967 int max_ready ATTRIBUTE_UNUSED)
3969 if (prev_cycle_state == NULL)
3971 prev_cycle_state = xmalloc (dfa_state_size);
3973 init_sched_state (&ss);
3974 state_reset (prev_cycle_state);
3977 /* We are about to being issuing INSN. Return nonzero if we cannot
3978 issue it on given cycle CLOCK and return zero if we should not sort
3979 the ready queue on the next clock start.
3980 For C6X, we use this function just to copy the previous DFA state
3981 for comparison purposes. */
3984 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
3985 rtx insn ATTRIBUTE_UNUSED, int last_clock ATTRIBUTE_UNUSED,
3986 int clock ATTRIBUTE_UNUSED, int *sort_p ATTRIBUTE_UNUSED)
3988 if (clock != last_clock)
3989 memcpy (prev_cycle_state, curr_state, dfa_state_size);
3994 c6x_mark_regno_read (int regno, bool cross)
3996 int t = ++ss.tmp_reg_n_accesses[regno];
3999 reg_access_stall = true;
4003 int set_cycle = ss.reg_set_in_cycle[regno];
4004 /* This must be done in this way rather than by tweaking things in
4005 adjust_cost, since the stall occurs even for insns with opposite
4006 predicates, and the scheduler may not even see a dependency. */
4007 if (set_cycle > 0 && set_cycle == ss.curr_sched_clock)
4008 reg_access_stall = true;
4009 /* This doesn't quite do anything yet as we're only modeling one
4011 ++ss.tmp_reg_n_xaccesses[regno];
4015 /* Note that REG is read in the insn being examined. If CROSS, it
4016 means the access is through a cross path. Update the temporary reg
4017 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4018 in the current cycle. */
4021 c6x_mark_reg_read (rtx reg, bool cross)
4023 unsigned regno = REGNO (reg);
4024 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
4027 c6x_mark_regno_read (regno + nregs, cross);
4030 /* Note that register REG is written in cycle CYCLES. */
4033 c6x_mark_reg_written (rtx reg, int cycles)
4035 unsigned regno = REGNO (reg);
4036 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
4039 ss.reg_set_in_cycle[regno + nregs] = cycles;
4042 /* Update the register state information for an instruction whose
4043 body is X. Return true if the instruction has to be delayed until the
4047 c6x_registers_update (rtx insn)
4049 enum attr_cross cross;
4050 enum attr_dest_regfile destrf;
4054 if (!reload_completed || recog_memoized (insn) < 0)
4057 reg_access_stall = false;
4058 memcpy (ss.tmp_reg_n_accesses, ss.reg_n_accesses,
4059 sizeof ss.tmp_reg_n_accesses);
4060 memcpy (ss.tmp_reg_n_xaccesses, ss.reg_n_xaccesses,
4061 sizeof ss.tmp_reg_n_xaccesses);
4063 extract_insn (insn);
4065 cross = get_attr_cross (insn);
4066 destrf = get_attr_dest_regfile (insn);
4068 nops = recog_data.n_operands;
4070 if (GET_CODE (x) == COND_EXEC)
4072 c6x_mark_reg_read (XEXP (XEXP (x, 0), 0), false);
4076 for (i = 0; i < nops; i++)
4078 rtx op = recog_data.operand[i];
4079 if (recog_data.operand_type[i] == OP_OUT)
4083 bool this_cross = cross;
4084 if (destrf == DEST_REGFILE_A && A_REGNO_P (REGNO (op)))
4086 if (destrf == DEST_REGFILE_B && B_REGNO_P (REGNO (op)))
4088 c6x_mark_reg_read (op, this_cross);
4090 else if (MEM_P (op))
4093 switch (GET_CODE (op))
4102 c6x_mark_reg_read (op, false);
4107 gcc_assert (GET_CODE (op) == PLUS);
4110 c6x_mark_reg_read (XEXP (op, 0), false);
4111 if (REG_P (XEXP (op, 1)))
4112 c6x_mark_reg_read (XEXP (op, 1), false);
4117 c6x_mark_regno_read (REG_B14, false);
4123 else if (!CONSTANT_P (op) && strlen (recog_data.constraints[i]) > 0)
4126 return reg_access_stall;
4129 /* Helper function for the TARGET_SCHED_REORDER and
4130 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4131 in the current cycle, move it down in the ready list and return the
4132 number of non-unsafe insns. */
4135 c6x_sched_reorder_1 (rtx_insn **ready, int *pn_ready, int clock_var)
4137 int n_ready = *pn_ready;
4138 rtx_insn **e_ready = ready + n_ready;
4142 /* Keep track of conflicts due to a limit number of register accesses,
4143 and due to stalls incurred by too early accesses of registers using
4146 for (insnp = ready; insnp < e_ready; insnp++)
4148 rtx_insn *insn = *insnp;
4149 int icode = recog_memoized (insn);
4150 bool is_asm = (icode < 0
4151 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
4152 || asm_noperands (PATTERN (insn)) >= 0));
4153 bool no_parallel = (is_asm || icode == CODE_FOR_sploop
4155 && get_attr_type (insn) == TYPE_ATOMIC));
4157 /* We delay asm insns until all delay slots are exhausted. We can't
4158 accurately tell how many cycles an asm takes, and the main scheduling
4159 code always assumes at least 1 cycle, which may be wrong. */
4161 && (ss.issued_this_cycle > 0 || clock_var < ss.delays_finished_at))
4162 || c6x_registers_update (insn)
4163 || (ss.issued_this_cycle > 0 && icode == CODE_FOR_sploop))
4165 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4170 else if (shadow_p (insn))
4172 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4177 /* Ensure that no other jump is scheduled in jump delay slots, since
4178 it would put the machine into the wrong state. Also, we must
4179 avoid scheduling insns that have a latency longer than the
4180 remaining jump delay slots, as the code at the jump destination
4181 won't be prepared for it.
4183 However, we can relax this condition somewhat. The rest of the
4184 scheduler will automatically avoid scheduling an insn on which
4185 the jump shadow depends so late that its side effect happens
4186 after the jump. This means that if we see an insn with a longer
4187 latency here, it can safely be scheduled if we can ensure that it
4188 has a predicate opposite of the previous jump: the side effect
4189 will happen in what we think of as the same basic block. In
4190 c6x_variable_issue, we will record the necessary predicate in
4191 new_conditions, and after scheduling is finished, we will modify
4194 Special care must be taken whenever there is more than one jump
4197 first_jump = first_jump_index (clock_var);
4198 if (first_jump != -1)
4200 int first_cycle = get_jump_cycle (first_jump);
4201 rtx first_cond = get_jump_cond (first_jump);
4202 int second_cycle = 0;
4205 second_cycle = get_jump_cycle (first_jump - 1);
4207 for (insnp = ready; insnp < e_ready; insnp++)
4209 rtx_insn *insn = *insnp;
4210 int icode = recog_memoized (insn);
4211 bool is_asm = (icode < 0
4212 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
4213 || asm_noperands (PATTERN (insn)) >= 0));
4214 int this_cycles, rsrv_cycles;
4215 enum attr_type type;
4217 gcc_assert (!is_asm);
4220 this_cycles = get_attr_cycles (insn);
4221 rsrv_cycles = get_attr_reserve_cycles (insn);
4222 type = get_attr_type (insn);
4223 /* Treat branches specially; there is also a hazard if two jumps
4224 end at the same cycle. */
4225 if (type == TYPE_BRANCH || type == TYPE_CALL)
4227 if (clock_var + this_cycles <= first_cycle)
4229 if ((first_jump > 0 && clock_var + this_cycles > second_cycle)
4230 || clock_var + rsrv_cycles > first_cycle
4231 || !predicate_insn (insn, first_cond, false))
4233 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4244 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4245 for later and clear the register access information for the new
4246 cycle. We also move asm statements out of the way if they would be
4247 scheduled in a delay slot. */
4250 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
4251 int sched_verbose ATTRIBUTE_UNUSED,
4252 rtx_insn **ready ATTRIBUTE_UNUSED,
4253 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
4255 ss.curr_sched_clock = clock_var;
4256 ss.issued_this_cycle = 0;
4257 memset (ss.reg_n_accesses, 0, sizeof ss.reg_n_accesses);
4258 memset (ss.reg_n_xaccesses, 0, sizeof ss.reg_n_xaccesses);
4263 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
4266 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4267 cycle for every insn. */
4270 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
4271 int sched_verbose ATTRIBUTE_UNUSED,
4272 rtx_insn **ready ATTRIBUTE_UNUSED,
4273 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
4275 /* FIXME: the assembler rejects labels inside an execute packet.
4276 This can occur if prologue insns are scheduled in parallel with
4277 others, so we avoid this here. Also make sure that nothing is
4278 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4279 if (RTX_FRAME_RELATED_P (ss.last_scheduled_insn)
4280 || JUMP_P (ss.last_scheduled_insn)
4281 || (recog_memoized (ss.last_scheduled_insn) >= 0
4282 && get_attr_type (ss.last_scheduled_insn) == TYPE_ATOMIC))
4284 int n_ready = *pn_ready;
4285 rtx_insn **e_ready = ready + n_ready;
4288 for (insnp = ready; insnp < e_ready; insnp++)
4290 rtx_insn *insn = *insnp;
4291 if (!shadow_p (insn))
4293 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4302 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
4305 /* Subroutine of maybe_clobber_cond, called through note_stores. */
4308 clobber_cond_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data1)
4310 rtx *cond = (rtx *)data1;
4311 if (*cond != NULL_RTX && reg_overlap_mentioned_p (x, *cond))
4315 /* Examine INSN, and if it destroys the conditions have recorded for
4316 any of the jumps in flight, clear that condition so that we don't
4317 predicate any more insns. CLOCK_VAR helps us limit the search to
4318 only those jumps which are still in flight. */
4321 maybe_clobber_cond (rtx insn, int clock_var)
4324 idx = ss.jump_cycle_index;
4325 for (n = 0; n < 12; n++, idx++)
4332 cycle = ss.jump_cycles[idx];
4333 if (cycle <= clock_var)
4336 cond = ss.jump_cond[idx];
4337 if (cond == NULL_RTX)
4342 ss.jump_cond[idx] = NULL_RTX;
4346 note_stores (PATTERN (insn), clobber_cond_1, ss.jump_cond + idx);
4347 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
4348 if (REG_NOTE_KIND (link) == REG_INC)
4349 clobber_cond_1 (XEXP (link, 0), NULL_RTX, ss.jump_cond + idx);
4353 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4354 issue INSN. Return the number of insns left on the ready queue
4355 that can be issued this cycle.
4356 We use this hook to record clock cycles and reservations for every insn. */
4359 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
4360 int sched_verbose ATTRIBUTE_UNUSED,
4361 rtx insn, int can_issue_more ATTRIBUTE_UNUSED)
4363 ss.last_scheduled_insn = insn;
4364 if (INSN_UID (insn) < sploop_max_uid_iter0 && !JUMP_P (insn))
4365 ss.last_scheduled_iter0 = as_a <rtx_insn *> (insn);
4366 if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
4367 ss.issued_this_cycle++;
4368 if (insn_info.exists ())
4370 state_t st_after = alloca (dfa_state_size);
4371 int curr_clock = ss.curr_sched_clock;
4372 int uid = INSN_UID (insn);
4373 int icode = recog_memoized (insn);
4375 int first, first_cycle;
4379 insn_set_clock (insn, curr_clock);
4380 INSN_INFO_ENTRY (uid).ebb_start
4381 = curr_clock == 0 && ss.issued_this_cycle == 1;
4383 first = first_jump_index (ss.curr_sched_clock);
4387 first_cond = NULL_RTX;
4391 first_cycle = get_jump_cycle (first);
4392 first_cond = get_jump_cond (first);
4395 && first_cycle > curr_clock
4396 && first_cond != NULL_RTX
4397 && (curr_clock + get_attr_cycles (insn) > first_cycle
4398 || get_attr_type (insn) == TYPE_BRANCH
4399 || get_attr_type (insn) == TYPE_CALL))
4400 INSN_INFO_ENTRY (uid).new_cond = first_cond;
4402 memcpy (st_after, curr_state, dfa_state_size);
4403 state_transition (st_after, const0_rtx);
4406 for (i = 0; i < 2 * UNIT_QID_SIDE_OFFSET; i++)
4407 if (cpu_unit_reservation_p (st_after, c6x_unit_codes[i])
4408 && !cpu_unit_reservation_p (prev_cycle_state, c6x_unit_codes[i]))
4410 INSN_INFO_ENTRY (uid).unit_mask = mask;
4412 maybe_clobber_cond (insn, curr_clock);
4418 c6x_registers_update (insn);
4419 memcpy (ss.reg_n_accesses, ss.tmp_reg_n_accesses,
4420 sizeof ss.reg_n_accesses);
4421 memcpy (ss.reg_n_xaccesses, ss.tmp_reg_n_accesses,
4422 sizeof ss.reg_n_xaccesses);
4424 cycles = get_attr_cycles (insn);
4425 if (ss.delays_finished_at < ss.curr_sched_clock + cycles)
4426 ss.delays_finished_at = ss.curr_sched_clock + cycles;
4427 if (get_attr_type (insn) == TYPE_BRANCH
4428 || get_attr_type (insn) == TYPE_CALL)
4430 rtx opposite = condjump_opposite_condition (insn);
4431 record_jump (ss.curr_sched_clock + cycles, opposite);
4434 /* Mark the cycles in which the destination registers are written.
4435 This is used for calculating stalls when using cross units. */
4436 extract_insn (insn);
4437 /* Cross-path stalls don't apply to results of load insns. */
4438 if (get_attr_type (insn) == TYPE_LOAD
4439 || get_attr_type (insn) == TYPE_LOADN
4440 || get_attr_type (insn) == TYPE_LOAD_SHADOW)
4442 for (i = 0; i < recog_data.n_operands; i++)
4444 rtx op = recog_data.operand[i];
4447 rtx addr = XEXP (op, 0);
4448 if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
4449 c6x_mark_reg_written (XEXP (addr, 0),
4450 insn_uid_get_clock (uid) + 1);
4452 if (recog_data.operand_type[i] != OP_IN
4455 c6x_mark_reg_written (op,
4456 insn_uid_get_clock (uid) + cycles);
4461 return can_issue_more;
4464 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4465 anti- and output dependencies. */
4468 c6x_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4470 enum attr_type insn_type = TYPE_UNKNOWN, dep_insn_type = TYPE_UNKNOWN;
4471 int dep_insn_code_number, insn_code_number;
4472 int shadow_bonus = 0;
4474 dep_insn_code_number = recog_memoized (dep_insn);
4475 insn_code_number = recog_memoized (insn);
4477 if (dep_insn_code_number >= 0)
4478 dep_insn_type = get_attr_type (dep_insn);
4480 if (insn_code_number >= 0)
4481 insn_type = get_attr_type (insn);
4483 kind = REG_NOTE_KIND (link);
4486 /* If we have a dependency on a load, and it's not for the result of
4487 the load, it must be for an autoincrement. Reduce the cost in that
4489 if (dep_insn_type == TYPE_LOAD)
4491 rtx set = PATTERN (dep_insn);
4492 if (GET_CODE (set) == COND_EXEC)
4493 set = COND_EXEC_CODE (set);
4494 if (GET_CODE (set) == UNSPEC)
4498 gcc_assert (GET_CODE (set) == SET);
4499 if (!reg_overlap_mentioned_p (SET_DEST (set), PATTERN (insn)))
4505 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4506 it occurs in between two cycles, but we schedule it at the end of the
4508 if (shadow_type_p (insn_type))
4511 /* Anti and output dependencies usually have zero cost, but we want
4512 to insert a stall after a jump, and after certain floating point
4513 insns that take more than one cycle to read their inputs. In the
4514 future, we should try to find a better algorithm for scheduling
4518 /* We can get anti-dependencies against shadow insns. Treat these
4519 like output dependencies, so that the insn is entirely finished
4520 before the branch takes place. */
4521 if (kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW)
4522 kind = REG_DEP_OUTPUT;
4523 switch (dep_insn_type)
4529 if (get_attr_has_shadow (dep_insn) == HAS_SHADOW_Y)
4530 /* This is a real_jump/real_call insn. These don't have
4531 outputs, and ensuring the validity of scheduling things
4532 in the delay slot is the job of
4533 c6x_sched_reorder_1. */
4535 /* Unsplit calls can happen - e.g. for divide insns. */
4540 if (kind == REG_DEP_OUTPUT)
4541 return 5 - shadow_bonus;
4545 if (kind == REG_DEP_OUTPUT)
4546 return 4 - shadow_bonus;
4549 if (kind == REG_DEP_OUTPUT)
4550 return 2 - shadow_bonus;
4553 if (kind == REG_DEP_OUTPUT)
4554 return 2 - shadow_bonus;
4558 if (kind == REG_DEP_OUTPUT)
4559 return 7 - shadow_bonus;
4562 if (kind == REG_DEP_OUTPUT)
4563 return 5 - shadow_bonus;
4566 if (kind == REG_DEP_OUTPUT)
4567 return 9 - shadow_bonus;
4571 if (kind == REG_DEP_OUTPUT)
4572 return 10 - shadow_bonus;
4576 if (insn_type == TYPE_SPKERNEL)
4578 if (kind == REG_DEP_OUTPUT)
4579 return 1 - shadow_bonus;
4585 return cost - shadow_bonus;
4588 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4589 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4590 first in the original stream. */
4593 gen_one_bundle (rtx *slot, int n_filled, int real_first)
4599 bundle = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec_v (n_filled, slot));
4600 bundle = make_insn_raw (bundle);
4601 BLOCK_FOR_INSN (bundle) = BLOCK_FOR_INSN (slot[0]);
4602 INSN_LOCATION (bundle) = INSN_LOCATION (slot[0]);
4603 SET_PREV_INSN (bundle) = SET_PREV_INSN (slot[real_first]);
4607 for (i = 0; i < n_filled; i++)
4611 SET_PREV_INSN (insn) = t ? t : PREV_INSN (bundle);
4613 SET_NEXT_INSN (t) = insn;
4616 INSN_LOCATION (slot[i]) = INSN_LOCATION (bundle);
4619 SET_NEXT_INSN (bundle) = NEXT_INSN (PREV_INSN (bundle));
4620 SET_NEXT_INSN (t) = NEXT_INSN (bundle);
4621 SET_NEXT_INSN (PREV_INSN (bundle)) = bundle;
4622 SET_PREV_INSN (NEXT_INSN (bundle)) = bundle;
4625 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4626 try to insert labels in the middle. */
4629 c6x_gen_bundles (void)
4632 rtx insn, next, last_call;
4634 FOR_EACH_BB_FN (bb, cfun)
4637 /* The machine is eight insns wide. We can have up to six shadow
4638 insns, plus an extra slot for merging the jump shadow. */
4643 for (insn = BB_HEAD (bb);; insn = next)
4646 rtx delete_this = NULL_RTX;
4648 if (NONDEBUG_INSN_P (insn))
4650 /* Put calls at the start of the sequence. */
4656 memmove (&slot[1], &slot[0],
4657 n_filled * sizeof (slot[0]));
4659 if (!shadow_p (insn))
4661 PUT_MODE (insn, TImode);
4663 PUT_MODE (slot[1], VOIDmode);
4670 slot[n_filled++] = insn;
4674 next = NEXT_INSN (insn);
4675 while (next && insn != BB_END (bb)
4676 && !(NONDEBUG_INSN_P (next)
4677 && GET_CODE (PATTERN (next)) != USE
4678 && GET_CODE (PATTERN (next)) != CLOBBER))
4681 next = NEXT_INSN (insn);
4684 at_end = insn == BB_END (bb);
4685 if (delete_this == NULL_RTX
4686 && (at_end || (GET_MODE (next) == TImode
4687 && !(shadow_p (next) && CALL_P (next)))))
4690 gen_one_bundle (slot, n_filled, first_slot);
4699 /* Bundling, and emitting nops, can separate
4700 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4702 last_call = NULL_RTX;
4703 for (insn = get_insns (); insn; insn = next)
4705 next = NEXT_INSN (insn);
4707 || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE
4708 && CALL_P (XVECEXP (PATTERN (insn), 0, 0))))
4710 if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION)
4712 if (NEXT_INSN (last_call) == insn)
4714 SET_NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
4715 SET_PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
4716 SET_PREV_INSN (insn) = last_call;
4717 SET_NEXT_INSN (insn) = NEXT_INSN (last_call);
4718 SET_PREV_INSN (NEXT_INSN (insn)) = insn;
4719 SET_NEXT_INSN (PREV_INSN (insn)) = insn;
4724 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4727 emit_nop_after (int cycles, rtx after)
4731 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4732 operation. We don't need the extra NOP since in this case, the hardware
4733 will automatically insert the required stall. */
4737 gcc_assert (cycles < 10);
4739 insn = emit_insn_after (gen_nop_count (GEN_INT (cycles)), after);
4740 PUT_MODE (insn, TImode);
4745 /* Determine whether INSN is a call that needs to have a return label
4749 returning_call_p (rtx insn)
4752 return (!SIBLING_CALL_P (insn)
4753 && get_attr_type (insn) != TYPE_CALLP
4754 && get_attr_type (insn) != TYPE_SHADOW);
4755 if (recog_memoized (insn) < 0)
4757 if (get_attr_type (insn) == TYPE_CALL)
4762 /* Determine whether INSN's pattern can be converted to use callp. */
4764 can_use_callp (rtx insn)
4766 int icode = recog_memoized (insn);
4767 if (!TARGET_INSNS_64PLUS
4769 || GET_CODE (PATTERN (insn)) == COND_EXEC)
4772 return ((icode == CODE_FOR_real_call
4773 || icode == CODE_FOR_call_internal
4774 || icode == CODE_FOR_call_value_internal)
4775 && get_attr_dest_regfile (insn) == DEST_REGFILE_ANY);
4778 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4780 convert_to_callp (rtx insn)
4783 extract_insn (insn);
4784 if (GET_CODE (PATTERN (insn)) == SET)
4786 rtx dest = recog_data.operand[0];
4787 lab = recog_data.operand[1];
4788 PATTERN (insn) = gen_callp_value (dest, lab);
4789 INSN_CODE (insn) = CODE_FOR_callp_value;
4793 lab = recog_data.operand[0];
4794 PATTERN (insn) = gen_callp (lab);
4795 INSN_CODE (insn) = CODE_FOR_callp;
4799 /* Scan forwards from INSN until we find the next insn that has mode TImode
4800 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4801 Return it if we find such an insn, NULL_RTX otherwise. */
4803 find_next_cycle_insn (rtx insn, int clock)
4806 if (GET_MODE (t) == TImode)
4807 t = next_real_insn (t);
4808 while (t && GET_MODE (t) != TImode)
4809 t = next_real_insn (t);
4811 if (t && insn_get_clock (t) == clock)
4816 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4817 around PAT. Return PAT either unchanged or modified in this
4820 duplicate_cond (rtx pat, rtx cond_insn)
4822 rtx cond_pat = PATTERN (cond_insn);
4823 if (GET_CODE (cond_pat) == COND_EXEC)
4824 pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (cond_pat)),
4829 /* Walk forward from INSN to find the last insn that issues in the same clock
4832 find_last_same_clock (rtx insn)
4835 rtx t = next_real_insn (insn);
4837 while (t && GET_MODE (t) != TImode)
4839 if (!DEBUG_INSN_P (t) && recog_memoized (t) >= 0)
4841 t = next_real_insn (t);
4846 /* For every call insn in the function, emit code to load the return
4847 address. For each call we create a return label and store it in
4848 CALL_LABELS. If are not scheduling, we emit the labels here,
4849 otherwise the caller will do it later.
4850 This function is called after final insn scheduling, but before creating
4851 the SEQUENCEs that represent execute packets. */
4854 reorg_split_calls (rtx *call_labels)
4856 unsigned int reservation_mask = 0;
4857 rtx insn = get_insns ();
4858 gcc_assert (NOTE_P (insn));
4859 insn = next_real_insn (insn);
4863 rtx next = next_real_insn (insn);
4865 if (DEBUG_INSN_P (insn))
4868 if (GET_MODE (insn) == TImode)
4869 reservation_mask = 0;
4870 uid = INSN_UID (insn);
4871 if (c6x_flag_schedule_insns2 && recog_memoized (insn) >= 0)
4872 reservation_mask |= 1 << INSN_INFO_ENTRY (uid).reservation;
4874 if (returning_call_p (insn))
4876 rtx label = gen_label_rtx ();
4877 rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
4878 rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
4880 LABEL_NUSES (label) = 2;
4881 if (!c6x_flag_schedule_insns2)
4883 if (can_use_callp (insn))
4884 convert_to_callp (insn);
4889 emit_label_after (label, insn);
4891 /* Bundle the call and its delay slots into a single
4892 SEQUENCE. While these do not issue in parallel
4893 we need to group them into a single EH region. */
4895 PUT_MODE (insn, TImode);
4896 if (TARGET_INSNS_64)
4898 t = gen_addkpc (reg, labelref, GEN_INT (4));
4899 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4901 PUT_MODE (slot[1], TImode);
4902 gen_one_bundle (slot, 2, 0);
4906 slot[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4908 PUT_MODE (slot[3], TImode);
4909 t = gen_movsi_lo_sum (reg, reg, labelref);
4910 slot[2] = emit_insn_after (duplicate_cond (t, insn),
4912 PUT_MODE (slot[2], TImode);
4913 t = gen_movsi_high (reg, labelref);
4914 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4916 PUT_MODE (slot[1], TImode);
4917 gen_one_bundle (slot, 4, 0);
4923 /* If we scheduled, we reserved the .S2 unit for one or two
4924 cycles after the call. Emit the insns in these slots,
4925 unless it's possible to create a CALLP insn.
4926 Note that this works because the dependencies ensure that
4927 no insn setting/using B3 is scheduled in the delay slots of
4929 int this_clock = insn_get_clock (insn);
4930 rtx last_same_clock;
4933 call_labels[INSN_UID (insn)] = label;
4935 last_same_clock = find_last_same_clock (insn);
4937 if (can_use_callp (insn))
4939 /* Find the first insn of the next execute packet. If it
4940 is the shadow insn corresponding to this call, we may
4941 use a CALLP insn. */
4942 rtx shadow = next_nonnote_nondebug_insn (last_same_clock);
4945 && insn_get_clock (shadow) == this_clock + 5)
4947 convert_to_callp (shadow);
4948 insn_set_clock (shadow, this_clock);
4949 INSN_INFO_ENTRY (INSN_UID (shadow)).reservation
4951 INSN_INFO_ENTRY (INSN_UID (shadow)).unit_mask
4952 = INSN_INFO_ENTRY (INSN_UID (last_same_clock)).unit_mask;
4953 if (GET_MODE (insn) == TImode)
4955 rtx new_cycle_first = NEXT_INSN (insn);
4956 while (!NONDEBUG_INSN_P (new_cycle_first)
4957 || GET_CODE (PATTERN (new_cycle_first)) == USE
4958 || GET_CODE (PATTERN (new_cycle_first)) == CLOBBER)
4959 new_cycle_first = NEXT_INSN (new_cycle_first);
4960 PUT_MODE (new_cycle_first, TImode);
4961 if (new_cycle_first != shadow)
4962 PUT_MODE (shadow, VOIDmode);
4963 INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
4964 = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
4967 PUT_MODE (shadow, VOIDmode);
4972 after1 = find_next_cycle_insn (last_same_clock, this_clock + 1);
4973 if (after1 == NULL_RTX)
4974 after1 = last_same_clock;
4976 after1 = find_last_same_clock (after1);
4977 if (TARGET_INSNS_64)
4979 rtx x1 = gen_addkpc (reg, labelref, const0_rtx);
4980 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4981 insn_set_clock (x1, this_clock + 1);
4982 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4983 if (after1 == last_same_clock)
4984 PUT_MODE (x1, TImode);
4986 INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
4987 = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
4992 rtx after2 = find_next_cycle_insn (after1, this_clock + 2);
4993 if (after2 == NULL_RTX)
4995 x2 = gen_movsi_lo_sum (reg, reg, labelref);
4996 x2 = emit_insn_after (duplicate_cond (x2, insn), after2);
4997 x1 = gen_movsi_high (reg, labelref);
4998 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4999 insn_set_clock (x1, this_clock + 1);
5000 insn_set_clock (x2, this_clock + 2);
5001 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
5002 INSN_INFO_ENTRY (INSN_UID (x2)).reservation = RESERVATION_S2;
5003 if (after1 == last_same_clock)
5004 PUT_MODE (x1, TImode);
5006 INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
5007 = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
5008 if (after1 == after2)
5009 PUT_MODE (x2, TImode);
5011 INSN_INFO_ENTRY (INSN_UID (x2)).unit_mask
5012 = INSN_INFO_ENTRY (INSN_UID (after2)).unit_mask;
5021 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
5022 insns as required for correctness. CALL_LABELS is the array that
5023 holds the return labels for call insns; we emit these here if
5024 scheduling was run earlier. */
5027 reorg_emit_nops (rtx *call_labels)
5030 rtx prev, last_call;
5031 int prev_clock, earliest_bb_end;
5032 int prev_implicit_nops;
5033 rtx insn = get_insns ();
5035 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5036 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5037 clocks, we must insert a NOP.
5038 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5039 current basic block will finish. We must not allow the next basic block to
5040 begin before this cycle.
5041 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5042 a multi-cycle nop. The code is scheduled such that subsequent insns will
5043 show the cycle gap, but we needn't insert a real NOP instruction. */
5044 insn = next_real_insn (insn);
5045 last_call = prev = NULL_RTX;
5047 earliest_bb_end = 0;
5048 prev_implicit_nops = 0;
5052 int this_clock = -1;
5056 next = next_real_insn (insn);
5058 if (DEBUG_INSN_P (insn)
5059 || GET_CODE (PATTERN (insn)) == USE
5060 || GET_CODE (PATTERN (insn)) == CLOBBER
5061 || shadow_or_blockage_p (insn)
5062 || JUMP_TABLE_DATA_P (insn))
5065 if (!c6x_flag_schedule_insns2)
5066 /* No scheduling; ensure that no parallel issue happens. */
5067 PUT_MODE (insn, TImode);
5072 this_clock = insn_get_clock (insn);
5073 if (this_clock != prev_clock)
5075 PUT_MODE (insn, TImode);
5079 cycles = this_clock - prev_clock;
5081 cycles -= prev_implicit_nops;
5084 rtx nop = emit_nop_after (cycles - 1, prev);
5085 insn_set_clock (nop, prev_clock + prev_implicit_nops + 1);
5088 prev_clock = this_clock;
5091 && insn_get_clock (last_call) + 6 <= this_clock)
5093 emit_label_before (call_labels[INSN_UID (last_call)], insn);
5094 last_call = NULL_RTX;
5096 prev_implicit_nops = 0;
5100 /* Examine how many cycles the current insn takes, and adjust
5101 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5102 if (recog_memoized (insn) >= 0
5103 /* If not scheduling, we've emitted NOPs after calls already. */
5104 && (c6x_flag_schedule_insns2 || !returning_call_p (insn)))
5106 max_cycles = get_attr_cycles (insn);
5107 if (get_attr_type (insn) == TYPE_CALLP)
5108 prev_implicit_nops = 5;
5112 if (returning_call_p (insn))
5115 if (c6x_flag_schedule_insns2)
5117 gcc_assert (this_clock >= 0);
5118 if (earliest_bb_end < this_clock + max_cycles)
5119 earliest_bb_end = this_clock + max_cycles;
5121 else if (max_cycles > 1)
5122 emit_nop_after (max_cycles - 1, insn);
5128 if (c6x_flag_schedule_insns2
5129 && (next == NULL_RTX
5130 || (GET_MODE (next) == TImode
5131 && INSN_INFO_ENTRY (INSN_UID (next)).ebb_start))
5132 && earliest_bb_end > 0)
5134 int cycles = earliest_bb_end - prev_clock;
5137 prev = emit_nop_after (cycles - 1, prev);
5138 insn_set_clock (prev, prev_clock + prev_implicit_nops + 1);
5140 earliest_bb_end = 0;
5145 emit_label_after (call_labels[INSN_UID (last_call)], prev);
5146 last_call = NULL_RTX;
5152 /* If possible, split INSN, which we know is either a jump or a call, into a real
5153 insn and its shadow. */
5155 split_delayed_branch (rtx_insn *insn)
5157 int code = recog_memoized (insn);
5160 rtx pat = PATTERN (insn);
5162 if (GET_CODE (pat) == COND_EXEC)
5163 pat = COND_EXEC_CODE (pat);
5167 rtx src = pat, dest = NULL_RTX;
5169 if (GET_CODE (pat) == SET)
5171 dest = SET_DEST (pat);
5172 src = SET_SRC (pat);
5174 callee = XEXP (XEXP (src, 0), 0);
5175 if (SIBLING_CALL_P (insn))
5178 newpat = gen_indirect_sibcall_shadow ();
5180 newpat = gen_sibcall_shadow (callee);
5181 pat = gen_real_jump (callee);
5183 else if (dest != NULL_RTX)
5186 newpat = gen_indirect_call_value_shadow (dest);
5188 newpat = gen_call_value_shadow (dest, callee);
5189 pat = gen_real_call (callee);
5194 newpat = gen_indirect_call_shadow ();
5196 newpat = gen_call_shadow (callee);
5197 pat = gen_real_call (callee);
5199 pat = duplicate_cond (pat, insn);
5200 newpat = duplicate_cond (newpat, insn);
5205 if (GET_CODE (pat) == PARALLEL
5206 && GET_CODE (XVECEXP (pat, 0, 0)) == RETURN)
5208 newpat = gen_return_shadow ();
5209 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
5210 newpat = duplicate_cond (newpat, insn);
5215 case CODE_FOR_br_true:
5216 case CODE_FOR_br_false:
5217 src = SET_SRC (pat);
5218 op = XEXP (src, code == CODE_FOR_br_true ? 1 : 2);
5219 newpat = gen_condjump_shadow (op);
5220 pat = gen_real_jump (op);
5221 if (code == CODE_FOR_br_true)
5222 pat = gen_rtx_COND_EXEC (VOIDmode, XEXP (src, 0), pat);
5224 pat = gen_rtx_COND_EXEC (VOIDmode,
5225 reversed_comparison (XEXP (src, 0),
5232 newpat = gen_jump_shadow (op);
5235 case CODE_FOR_indirect_jump:
5236 newpat = gen_indirect_jump_shadow ();
5239 case CODE_FOR_return_internal:
5240 newpat = gen_return_shadow ();
5241 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
5248 i1 = emit_insn_before (pat, insn);
5249 PATTERN (insn) = newpat;
5250 INSN_CODE (insn) = -1;
5251 record_delay_slot_pair (i1, insn, 5, 0);
5254 /* If INSN is a multi-cycle insn that should be handled properly in
5255 modulo-scheduling, split it into a real insn and a shadow.
5256 Return true if we made a change.
5258 It is valid for us to fail to split an insn; the caller has to deal
5259 with the possibility. Currently we handle loads and most mpy2 and
5262 split_delayed_nonbranch (rtx_insn *insn)
5264 int code = recog_memoized (insn);
5265 enum attr_type type;
5267 rtx newpat, src, dest;
5268 rtx pat = PATTERN (insn);
5272 if (GET_CODE (pat) == COND_EXEC)
5273 pat = COND_EXEC_CODE (pat);
5275 if (code < 0 || GET_CODE (pat) != SET)
5277 src = SET_SRC (pat);
5278 dest = SET_DEST (pat);
5282 type = get_attr_type (insn);
5284 && (type == TYPE_LOAD
5285 || type == TYPE_LOADN))
5288 && (GET_CODE (src) != ZERO_EXTEND
5289 || !MEM_P (XEXP (src, 0))))
5292 if (GET_MODE_SIZE (GET_MODE (dest)) > 4
5293 && (GET_MODE_SIZE (GET_MODE (dest)) != 8 || !TARGET_LDDW))
5296 rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
5298 newpat = gen_load_shadow (SET_DEST (pat));
5299 pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_LOAD);
5303 && (type == TYPE_MPY2
5304 || type == TYPE_MPY4))
5306 /* We don't handle floating point multiplies yet. */
5307 if (GET_MODE (dest) == SFmode)
5310 rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
5312 newpat = gen_mult_shadow (SET_DEST (pat));
5313 pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_MULT);
5314 delay = type == TYPE_MPY2 ? 1 : 3;
5319 pat = duplicate_cond (pat, insn);
5320 newpat = duplicate_cond (newpat, insn);
5321 i1 = emit_insn_before (pat, insn);
5322 PATTERN (insn) = newpat;
5323 INSN_CODE (insn) = -1;
5324 recog_memoized (insn);
5325 recog_memoized (i1);
5326 record_delay_slot_pair (i1, insn, delay, 0);
5330 /* Examine if INSN is the result of splitting a load into a real load and a
5331 shadow, and if so, undo the transformation. */
5333 undo_split_delayed_nonbranch (rtx insn)
5335 int icode = recog_memoized (insn);
5336 enum attr_type type;
5337 rtx prev_pat, insn_pat, prev;
5341 type = get_attr_type (insn);
5342 if (type != TYPE_LOAD_SHADOW && type != TYPE_MULT_SHADOW)
5344 prev = PREV_INSN (insn);
5345 prev_pat = PATTERN (prev);
5346 insn_pat = PATTERN (insn);
5347 if (GET_CODE (prev_pat) == COND_EXEC)
5349 prev_pat = COND_EXEC_CODE (prev_pat);
5350 insn_pat = COND_EXEC_CODE (insn_pat);
5353 gcc_assert (GET_CODE (prev_pat) == UNSPEC
5354 && ((XINT (prev_pat, 1) == UNSPEC_REAL_LOAD
5355 && type == TYPE_LOAD_SHADOW)
5356 || (XINT (prev_pat, 1) == UNSPEC_REAL_MULT
5357 && type == TYPE_MULT_SHADOW)));
5358 insn_pat = gen_rtx_SET (VOIDmode, SET_DEST (insn_pat),
5359 XVECEXP (prev_pat, 0, 1));
5360 insn_pat = duplicate_cond (insn_pat, prev);
5361 PATTERN (insn) = insn_pat;
5362 INSN_CODE (insn) = -1;
5366 /* Split every insn (i.e. jumps and calls) which can have delay slots into
5367 two parts: the first one is scheduled normally and emits the instruction,
5368 while the second one is a shadow insn which shows the side effect taking
5369 place. The second one is placed in the right cycle by the scheduler, but
5370 not emitted as an assembly instruction. */
5373 split_delayed_insns (void)
5376 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5378 if (JUMP_P (insn) || CALL_P (insn))
5379 split_delayed_branch (insn);
5383 /* For every insn that has an entry in the new_conditions vector, give it
5384 the appropriate predicate. */
5386 conditionalize_after_sched (void)
5390 FOR_EACH_BB_FN (bb, cfun)
5391 FOR_BB_INSNS (bb, insn)
5393 unsigned uid = INSN_UID (insn);
5395 if (!NONDEBUG_INSN_P (insn) || uid >= INSN_INFO_LENGTH)
5397 cond = INSN_INFO_ENTRY (uid).new_cond;
5398 if (cond == NULL_RTX)
5401 fprintf (dump_file, "Conditionalizing insn %d\n", uid);
5402 predicate_insn (insn, cond, true);
5406 /* A callback for the hw-doloop pass. This function examines INSN; if
5407 it is a loop_end pattern we recognize, return the reg rtx for the
5408 loop counter. Otherwise, return NULL_RTX. */
5411 hwloop_pattern_reg (rtx insn)
5415 if (!JUMP_P (insn) || recog_memoized (insn) != CODE_FOR_loop_end)
5418 pat = PATTERN (insn);
5419 reg = SET_DEST (XVECEXP (pat, 0, 1));
5425 /* Return the number of cycles taken by BB, as computed by scheduling,
5426 including the latencies of all insns with delay slots. IGNORE is
5427 an insn we should ignore in the calculation, usually the final
5430 bb_earliest_end_cycle (basic_block bb, rtx ignore)
5435 FOR_BB_INSNS (bb, insn)
5437 int cycles, this_clock;
5439 if (LABEL_P (insn) || NOTE_P (insn) || DEBUG_INSN_P (insn)
5440 || GET_CODE (PATTERN (insn)) == USE
5441 || GET_CODE (PATTERN (insn)) == CLOBBER
5445 this_clock = insn_get_clock (insn);
5446 cycles = get_attr_cycles (insn);
5448 if (earliest < this_clock + cycles)
5449 earliest = this_clock + cycles;
5454 /* Examine the insns in BB and remove all which have a uid greater or
5455 equal to MAX_UID. */
5457 filter_insns_above (basic_block bb, int max_uid)
5460 bool prev_ti = false;
5461 int prev_cycle = -1;
5463 FOR_BB_INSNS_SAFE (bb, insn, next)
5466 if (!NONDEBUG_INSN_P (insn))
5468 if (insn == BB_END (bb))
5470 this_cycle = insn_get_clock (insn);
5471 if (prev_ti && this_cycle == prev_cycle)
5473 gcc_assert (GET_MODE (insn) != TImode);
5474 PUT_MODE (insn, TImode);
5477 if (INSN_UID (insn) >= max_uid)
5479 if (GET_MODE (insn) == TImode)
5482 prev_cycle = this_cycle;
5489 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5492 c6x_asm_emit_except_personality (rtx personality)
5494 fputs ("\t.personality\t", asm_out_file);
5495 output_addr_const (asm_out_file, personality);
5496 fputc ('\n', asm_out_file);
5499 /* Use a special assembly directive rather than a regular setion for
5500 unwind table data. */
5503 c6x_asm_init_sections (void)
5505 exception_section = get_unnamed_section (0, output_section_asm_op,
5509 /* A callback for the hw-doloop pass. Called to optimize LOOP in a
5510 machine-specific fashion; returns true if successful and false if
5511 the hwloop_fail function should be called. */
5514 hwloop_optimize (hwloop_info loop)
5516 basic_block entry_bb, bb;
5517 rtx_insn *seq, *insn, *prev, *entry_after, *end_packet;
5518 rtx_insn *head_insn, *tail_insn, *new_insns, *last_insn;
5520 int n_execute_packets;
5523 int max_uid_before, delayed_splits;
5524 int i, sp_ii, min_ii, max_ii, max_parallel, n_insns, n_real_insns, stages;
5525 rtx_insn **orig_vec;
5527 rtx_insn ***insn_copies;
5529 if (!c6x_flag_modulo_sched || !c6x_flag_schedule_insns2
5530 || !TARGET_INSNS_64PLUS)
5533 if (loop->iter_reg_used || loop->depth > 1)
5535 if (loop->has_call || loop->has_asm)
5538 if (loop->head != loop->tail)
5541 gcc_assert (loop->incoming_dest == loop->head);
5544 FOR_EACH_VEC_SAFE_ELT (loop->incoming, i, entry_edge)
5545 if (entry_edge->flags & EDGE_FALLTHRU)
5547 if (entry_edge == NULL)
5550 reshuffle_units (loop->head);
5553 schedule_ebbs_init ();
5554 schedule_ebb (BB_HEAD (loop->tail), loop->loop_end, true);
5555 schedule_ebbs_finish ();
5559 loop_earliest = bb_earliest_end_cycle (bb, loop->loop_end) + 1;
5561 max_uid_before = get_max_uid ();
5563 /* Split all multi-cycle operations, such as loads. For normal
5564 scheduling, we only do this for branches, as the generated code
5565 would otherwise not be interrupt-safe. When using sploop, it is
5566 safe and beneficial to split them. If any multi-cycle operations
5567 remain after splitting (because we don't handle them yet), we
5568 cannot pipeline the loop. */
5570 FOR_BB_INSNS (bb, insn)
5572 if (NONDEBUG_INSN_P (insn))
5574 recog_memoized (insn);
5575 if (split_delayed_nonbranch (insn))
5577 else if (INSN_CODE (insn) >= 0
5578 && get_attr_cycles (insn) > 1)
5583 /* Count the number of insns as well as the number real insns, and save
5584 the original sequence of insns in case we must restore it later. */
5585 n_insns = n_real_insns = 0;
5586 FOR_BB_INSNS (bb, insn)
5589 if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
5592 orig_vec = XNEWVEC (rtx_insn *, n_insns);
5594 FOR_BB_INSNS (bb, insn)
5595 orig_vec[n_insns++] = insn;
5597 /* Count the unit reservations, and compute a minimum II from that
5599 count_unit_reqs (unit_reqs, loop->start_label,
5600 PREV_INSN (loop->loop_end));
5601 merge_unit_reqs (unit_reqs);
5603 min_ii = res_mii (unit_reqs);
5604 max_ii = loop_earliest < 15 ? loop_earliest : 14;
5606 /* Make copies of the loop body, up to a maximum number of stages we want
5608 max_parallel = loop_earliest / min_ii + 1;
5610 copies = XCNEWVEC (rtx_insn *, (max_parallel + 1) * n_real_insns);
5611 insn_copies = XNEWVEC (rtx_insn **, max_parallel + 1);
5612 for (i = 0; i < max_parallel + 1; i++)
5613 insn_copies[i] = copies + i * n_real_insns;
5615 head_insn = next_nonnote_nondebug_insn (loop->start_label);
5616 tail_insn = prev_real_insn (BB_END (bb));
5619 FOR_BB_INSNS (bb, insn)
5620 if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
5621 insn_copies[0][i++] = insn;
5623 sploop_max_uid_iter0 = get_max_uid ();
5625 /* Generate the copies of the loop body, and save them in the
5626 INSN_COPIES array. */
5628 for (i = 0; i < max_parallel; i++)
5631 rtx_insn *this_iter;
5633 this_iter = duplicate_insn_chain (head_insn, tail_insn);
5637 rtx_insn *prev_stage_insn = insn_copies[i][j];
5638 gcc_assert (INSN_CODE (this_iter) == INSN_CODE (prev_stage_insn));
5640 if (INSN_CODE (this_iter) >= 0
5641 && (get_attr_type (this_iter) == TYPE_LOAD_SHADOW
5642 || get_attr_type (this_iter) == TYPE_MULT_SHADOW))
5644 rtx_insn *prev = PREV_INSN (this_iter);
5645 record_delay_slot_pair (prev, this_iter,
5646 get_attr_cycles (prev) - 1, 0);
5649 record_delay_slot_pair (prev_stage_insn, this_iter, i, 1);
5651 insn_copies[i + 1][j] = this_iter;
5653 this_iter = next_nonnote_nondebug_insn (this_iter);
5656 new_insns = get_insns ();
5657 last_insn = insn_copies[max_parallel][n_real_insns - 1];
5659 emit_insn_before (new_insns, BB_END (bb));
5661 /* Try to schedule the loop using varying initiation intervals,
5662 starting with the smallest possible and incrementing it
5664 for (sp_ii = min_ii; sp_ii <= max_ii; sp_ii++)
5668 fprintf (dump_file, "Trying to schedule for II %d\n", sp_ii);
5670 df_clear_flags (DF_LR_RUN_DCE);
5672 schedule_ebbs_init ();
5673 set_modulo_params (sp_ii, max_parallel, n_real_insns,
5674 sploop_max_uid_iter0);
5675 tmp_bb = schedule_ebb (BB_HEAD (bb), last_insn, true);
5676 schedule_ebbs_finish ();
5681 fprintf (dump_file, "Found schedule with II %d\n", sp_ii);
5686 discard_delay_pairs_above (max_uid_before);
5691 stages = insn_get_clock (ss.last_scheduled_iter0) / sp_ii + 1;
5693 if (stages == 1 && sp_ii > 5)
5696 /* At this point, we know we've been successful, unless we find later that
5697 there are too many execute packets for the loop buffer to hold. */
5699 /* Assign reservations to the instructions in the loop. We must find
5700 the stage that contains the full loop kernel, and transfer the
5701 reservations of the instructions contained in it to the corresponding
5702 instructions from iteration 0, which are the only ones we'll keep. */
5703 assign_reservations (BB_HEAD (bb), ss.last_scheduled_insn);
5704 SET_PREV_INSN (BB_END (bb)) = ss.last_scheduled_iter0;
5705 SET_NEXT_INSN (ss.last_scheduled_iter0) = BB_END (bb);
5706 filter_insns_above (bb, sploop_max_uid_iter0);
5708 for (i = 0; i < n_real_insns; i++)
5710 rtx insn = insn_copies[0][i];
5711 int uid = INSN_UID (insn);
5712 int stage = insn_uid_get_clock (uid) / sp_ii;
5714 if (stage + 1 < stages)
5717 stage = stages - stage - 1;
5718 copy_uid = INSN_UID (insn_copies[stage][i]);
5719 INSN_INFO_ENTRY (uid).reservation
5720 = INSN_INFO_ENTRY (copy_uid).reservation;
5726 /* Compute the number of execute packets the pipelined form of the loop will
5729 n_execute_packets = 0;
5730 for (insn = as_a <rtx_insn *> (loop->start_label);
5731 insn != loop->loop_end;
5732 insn = NEXT_INSN (insn))
5734 if (NONDEBUG_INSN_P (insn) && GET_MODE (insn) == TImode
5735 && !shadow_p (insn))
5737 n_execute_packets++;
5738 if (prev && insn_get_clock (prev) + 1 != insn_get_clock (insn))
5739 /* We need an extra NOP instruction. */
5740 n_execute_packets++;
5746 end_packet = ss.last_scheduled_iter0;
5747 while (!NONDEBUG_INSN_P (end_packet) || GET_MODE (end_packet) != TImode)
5748 end_packet = PREV_INSN (end_packet);
5750 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5751 loop_earliest = (stages - 1) * sp_ii;
5752 if (loop_earliest > insn_get_clock (end_packet))
5754 n_execute_packets++;
5755 end_packet = loop->loop_end;
5758 loop_earliest = insn_get_clock (end_packet);
5760 if (n_execute_packets > 14)
5763 /* Generate the spkernel instruction, and place it at the appropriate
5765 PUT_MODE (end_packet, VOIDmode);
5767 insn = emit_jump_insn_before (
5768 gen_spkernel (GEN_INT (stages - 1),
5769 const0_rtx, JUMP_LABEL (loop->loop_end)),
5771 JUMP_LABEL (insn) = JUMP_LABEL (loop->loop_end);
5772 insn_set_clock (insn, loop_earliest);
5773 PUT_MODE (insn, TImode);
5774 INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start = false;
5775 delete_insn (loop->loop_end);
5777 /* Place the mvc and sploop instructions before the loop. */
5778 entry_bb = entry_edge->src;
5782 insn = emit_insn (gen_mvilc (loop->iter_reg));
5783 insn = emit_insn (gen_sploop (GEN_INT (sp_ii)));
5787 if (!single_succ_p (entry_bb) || vec_safe_length (loop->incoming) > 1)
5793 emit_insn_before (seq, BB_HEAD (loop->head));
5794 seq = emit_label_before (gen_label_rtx (), seq);
5796 new_bb = create_basic_block (seq, insn, entry_bb);
5797 FOR_EACH_EDGE (e, ei, loop->incoming)
5799 if (!(e->flags & EDGE_FALLTHRU))
5800 redirect_edge_and_branch_force (e, new_bb);
5802 redirect_edge_succ (e, new_bb);
5804 make_edge (new_bb, loop->head, 0);
5808 entry_after = BB_END (entry_bb);
5809 while (DEBUG_INSN_P (entry_after)
5810 || (NOTE_P (entry_after)
5811 && NOTE_KIND (entry_after) != NOTE_INSN_BASIC_BLOCK))
5812 entry_after = PREV_INSN (entry_after);
5813 emit_insn_after (seq, entry_after);
5818 /* Make sure we don't try to schedule this loop again. */
5819 for (ix = 0; loop->blocks.iterate (ix, &bb); ix++)
5820 bb->flags |= BB_DISABLE_SCHEDULE;
5826 fprintf (dump_file, "Unable to pipeline loop.\n");
5828 for (i = 1; i < n_insns; i++)
5830 SET_NEXT_INSN (orig_vec[i - 1]) = orig_vec[i];
5831 SET_PREV_INSN (orig_vec[i]) = orig_vec[i - 1];
5833 SET_PREV_INSN (orig_vec[0]) = PREV_INSN (BB_HEAD (bb));
5834 SET_NEXT_INSN (PREV_INSN (BB_HEAD (bb))) = orig_vec[0];
5835 SET_NEXT_INSN (orig_vec[n_insns - 1]) = NEXT_INSN (BB_END (bb));
5836 SET_PREV_INSN (NEXT_INSN (BB_END (bb))) = orig_vec[n_insns - 1];
5837 BB_HEAD (bb) = orig_vec[0];
5838 BB_END (bb) = orig_vec[n_insns - 1];
5840 free_delay_pairs ();
5841 FOR_BB_INSNS (bb, insn)
5842 if (NONDEBUG_INSN_P (insn))
5843 undo_split_delayed_nonbranch (insn);
5847 /* A callback for the hw-doloop pass. Called when a loop we have discovered
5848 turns out not to be optimizable; we have to split the doloop_end pattern
5849 into a subtract and a test. */
5851 hwloop_fail (hwloop_info loop)
5853 rtx insn, test, testreg;
5856 fprintf (dump_file, "splitting doloop insn %d\n",
5857 INSN_UID (loop->loop_end));
5858 insn = gen_addsi3 (loop->iter_reg, loop->iter_reg, constm1_rtx);
5859 /* See if we can emit the add at the head of the loop rather than at the
5861 if (loop->head == NULL
5862 || loop->iter_reg_used_outside
5863 || loop->iter_reg_used
5864 || TEST_HARD_REG_BIT (loop->regs_set_in_loop, REGNO (loop->iter_reg))
5865 || loop->incoming_dest != loop->head
5866 || EDGE_COUNT (loop->head->preds) != 2)
5867 emit_insn_before (insn, loop->loop_end);
5870 rtx t = loop->start_label;
5871 while (!NOTE_P (t) || NOTE_KIND (t) != NOTE_INSN_BASIC_BLOCK)
5873 emit_insn_after (insn, t);
5876 testreg = SET_DEST (XVECEXP (PATTERN (loop->loop_end), 0, 2));
5877 if (GET_CODE (testreg) == SCRATCH)
5878 testreg = loop->iter_reg;
5880 emit_insn_before (gen_movsi (testreg, loop->iter_reg), loop->loop_end);
5882 test = gen_rtx_NE (VOIDmode, testreg, const0_rtx);
5883 insn = emit_jump_insn_before (gen_cbranchsi4 (test, testreg, const0_rtx,
5887 JUMP_LABEL (insn) = loop->start_label;
5888 LABEL_NUSES (loop->start_label)++;
5889 delete_insn (loop->loop_end);
5892 static struct hw_doloop_hooks c6x_doloop_hooks =
5899 /* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5900 doloop_end patterns where such optimizations are impossible. */
5905 reorg_loops (true, &c6x_doloop_hooks);
5908 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5909 into a sequence that loads the return register and performs the call,
5910 and emit the return label.
5911 If scheduling after reload is requested, it happens here. */
5918 bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
5919 && !maybe_skip_selective_scheduling ());
5921 /* We are freeing block_for_insn in the toplev to keep compatibility
5922 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5923 compute_bb_for_insn ();
5925 df_clear_flags (DF_LR_RUN_DCE);
5926 df_note_add_problem ();
5928 /* If optimizing, we'll have split before scheduling. */
5934 if (c6x_flag_schedule_insns2)
5936 int sz = get_max_uid () * 3 / 2 + 1;
5938 insn_info.create (sz);
5941 /* Make sure the real-jump insns we create are not deleted. When modulo-
5942 scheduling, situations where a reg is only stored in a loop can also
5943 cause dead code when doing the initial unrolling. */
5944 sched_no_dce = true;
5948 if (c6x_flag_schedule_insns2)
5950 split_delayed_insns ();
5951 timevar_push (TV_SCHED2);
5953 run_selective_scheduling ();
5956 conditionalize_after_sched ();
5957 timevar_pop (TV_SCHED2);
5959 free_delay_pairs ();
5961 sched_no_dce = false;
5963 call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
5965 reorg_split_calls (call_labels);
5967 if (c6x_flag_schedule_insns2)
5969 FOR_EACH_BB_FN (bb, cfun)
5970 if ((bb->flags & BB_DISABLE_SCHEDULE) == 0)
5971 assign_reservations (BB_HEAD (bb), BB_END (bb));
5974 if (c6x_flag_var_tracking)
5976 timevar_push (TV_VAR_TRACKING);
5977 variable_tracking_main ();
5978 timevar_pop (TV_VAR_TRACKING);
5981 reorg_emit_nops (call_labels);
5983 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
5984 if (c6x_flag_schedule_insns2)
5986 free_delay_pairs ();
5990 df_finish_pass (false);
5993 /* Called when a function has been assembled. It should perform all the
5994 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
5996 We free the reservation (and other scheduling) information here now that
5997 all insns have been output. */
5999 c6x_function_end (FILE *file, const char *fname)
6001 c6x_output_fn_unwind (file);
6003 insn_info.release ();
6005 if (!flag_inhibit_size_directive)
6006 ASM_OUTPUT_MEASURED_SIZE (file, fname);
6009 /* Determine whether X is a shift with code CODE and an integer amount
6012 shift_p (rtx x, enum rtx_code code, int amount)
6014 return (GET_CODE (x) == code && GET_CODE (XEXP (x, 1)) == CONST_INT
6015 && INTVAL (XEXP (x, 1)) == amount);
6018 /* Compute a (partial) cost for rtx X. Return true if the complete
6019 cost has been computed, and false if subexpressions should be
6020 scanned. In either case, *TOTAL contains the cost result. */
6023 c6x_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
6026 int cost2 = COSTS_N_INSNS (1);
6032 if (outer_code == SET || outer_code == PLUS)
6033 *total = satisfies_constraint_IsB (x) ? 0 : cost2;
6034 else if (outer_code == AND || outer_code == IOR || outer_code == XOR
6035 || outer_code == MINUS)
6036 *total = satisfies_constraint_Is5 (x) ? 0 : cost2;
6037 else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
6038 || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
6039 *total = satisfies_constraint_Iu4 (x) ? 0 : cost2;
6040 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
6041 || outer_code == LSHIFTRT)
6042 *total = satisfies_constraint_Iu5 (x) ? 0 : cost2;
6051 *total = COSTS_N_INSNS (2);
6055 /* Recognize a mult_highpart operation. */
6056 if ((GET_MODE (x) == HImode || GET_MODE (x) == SImode)
6057 && GET_CODE (XEXP (x, 0)) == LSHIFTRT
6058 && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x))
6059 && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
6060 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
6061 && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x)))
6063 rtx mul = XEXP (XEXP (x, 0), 0);
6064 rtx op0 = XEXP (mul, 0);
6065 rtx op1 = XEXP (mul, 1);
6066 enum rtx_code code0 = GET_CODE (op0);
6067 enum rtx_code code1 = GET_CODE (op1);
6070 && (code0 == SIGN_EXTEND || code0 == ZERO_EXTEND))
6071 || (GET_MODE (x) == HImode
6072 && code0 == ZERO_EXTEND && code1 == SIGN_EXTEND))
6074 if (GET_MODE (x) == HImode)
6075 *total = COSTS_N_INSNS (2);
6077 *total = COSTS_N_INSNS (12);
6078 *total += rtx_cost (XEXP (op0, 0), code0, 0, speed);
6079 *total += rtx_cost (XEXP (op1, 0), code1, 0, speed);
6088 if (GET_MODE (x) == DImode)
6089 *total = COSTS_N_INSNS (CONSTANT_P (XEXP (x, 1)) ? 4 : 15);
6091 *total = COSTS_N_INSNS (1);
6096 *total = COSTS_N_INSNS (1);
6097 op0 = code == PLUS ? XEXP (x, 0) : XEXP (x, 1);
6098 op1 = code == PLUS ? XEXP (x, 1) : XEXP (x, 0);
6099 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
6100 && INTEGRAL_MODE_P (GET_MODE (x))
6101 && GET_CODE (op0) == MULT
6102 && GET_CODE (XEXP (op0, 1)) == CONST_INT
6103 && (INTVAL (XEXP (op0, 1)) == 2
6104 || INTVAL (XEXP (op0, 1)) == 4
6105 || (code == PLUS && INTVAL (XEXP (op0, 1)) == 8)))
6107 *total += rtx_cost (XEXP (op0, 0), ASHIFT, 0, speed);
6108 *total += rtx_cost (op1, (enum rtx_code) code, 1, speed);
6116 if (GET_MODE (x) == DFmode)
6119 *total = COSTS_N_INSNS (speed ? 10 : 1);
6121 *total = COSTS_N_INSNS (speed ? 200 : 4);
6123 else if (GET_MODE (x) == SFmode)
6126 *total = COSTS_N_INSNS (speed ? 4 : 1);
6128 *total = COSTS_N_INSNS (speed ? 100 : 4);
6130 else if (GET_MODE (x) == DImode)
6133 && GET_CODE (op0) == GET_CODE (op1)
6134 && (GET_CODE (op0) == ZERO_EXTEND
6135 || GET_CODE (op0) == SIGN_EXTEND))
6137 *total = COSTS_N_INSNS (speed ? 2 : 1);
6138 op0 = XEXP (op0, 0);
6139 op1 = XEXP (op1, 0);
6142 /* Maybe improve this laster. */
6143 *total = COSTS_N_INSNS (20);
6145 else if (GET_MODE (x) == SImode)
6147 if (((GET_CODE (op0) == ZERO_EXTEND
6148 || GET_CODE (op0) == SIGN_EXTEND
6149 || shift_p (op0, LSHIFTRT, 16))
6150 && (GET_CODE (op1) == SIGN_EXTEND
6151 || GET_CODE (op1) == ZERO_EXTEND
6152 || scst5_operand (op1, SImode)
6153 || shift_p (op1, ASHIFTRT, 16)
6154 || shift_p (op1, LSHIFTRT, 16)))
6155 || (shift_p (op0, ASHIFTRT, 16)
6156 && (GET_CODE (op1) == SIGN_EXTEND
6157 || shift_p (op1, ASHIFTRT, 16))))
6159 *total = COSTS_N_INSNS (speed ? 2 : 1);
6160 op0 = XEXP (op0, 0);
6161 if (scst5_operand (op1, SImode))
6164 op1 = XEXP (op1, 0);
6167 *total = COSTS_N_INSNS (1);
6168 else if (TARGET_MPY32)
6169 *total = COSTS_N_INSNS (4);
6171 *total = COSTS_N_INSNS (6);
6173 else if (GET_MODE (x) == HImode)
6174 *total = COSTS_N_INSNS (speed ? 2 : 1);
6176 if (GET_CODE (op0) != REG
6177 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
6178 *total += rtx_cost (op0, MULT, 0, speed);
6179 if (op1 && GET_CODE (op1) != REG
6180 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
6181 *total += rtx_cost (op1, MULT, 1, speed);
6186 /* This is a bit random; assuming on average there'll be 16 leading
6187 zeros. FIXME: estimate better for constant dividends. */
6188 *total = COSTS_N_INSNS (6 + 3 * 16);
6192 /* Recognize the cmp_and/ior patterns. */
6194 if ((GET_CODE (op0) == EQ || GET_CODE (op0) == NE)
6195 && REG_P (XEXP (op0, 0))
6196 && XEXP (op0, 1) == const0_rtx
6197 && rtx_equal_p (XEXP (x, 1), XEXP (op0, 0)))
6199 *total = rtx_cost (XEXP (x, 1), (enum rtx_code) outer_code,
6210 /* Implements target hook vector_mode_supported_p. */
6213 c6x_vector_mode_supported_p (enum machine_mode mode)
6228 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6229 static enum machine_mode
6230 c6x_preferred_simd_mode (enum machine_mode mode)
6244 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6247 c6x_scalar_mode_supported_p (enum machine_mode mode)
6249 if (ALL_FIXED_POINT_MODE_P (mode)
6250 && GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
6253 return default_scalar_mode_supported_p (mode);
6256 /* Output a reference from a function exception table to the type_info
6257 object X. Output these via a special assembly directive. */
6260 c6x_output_ttype (rtx x)
6262 /* Use special relocations for symbol references. */
6263 if (GET_CODE (x) != CONST_INT)
6264 fputs ("\t.ehtype\t", asm_out_file);
6266 fputs ("\t.word\t", asm_out_file);
6267 output_addr_const (asm_out_file, x);
6268 fputc ('\n', asm_out_file);
6273 /* Modify the return address of the current function. */
6276 c6x_set_return_address (rtx source, rtx scratch)
6278 struct c6x_frame frame;
6280 HOST_WIDE_INT offset;
6282 c6x_compute_frame_layout (&frame);
6283 if (! c6x_save_reg (RETURN_ADDR_REGNO))
6284 emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNO), source);
6288 if (frame_pointer_needed)
6290 addr = hard_frame_pointer_rtx;
6291 offset = frame.b3_offset;
6295 addr = stack_pointer_rtx;
6296 offset = frame.to_allocate - frame.b3_offset;
6299 /* TODO: Use base+offset loads where possible. */
6302 HOST_WIDE_INT low = trunc_int_for_mode (offset, HImode);
6304 emit_insn (gen_movsi_high (scratch, GEN_INT (low)));
6306 emit_insn (gen_movsi_lo_sum (scratch, scratch, GEN_INT(offset)));
6307 emit_insn (gen_addsi3 (scratch, addr, scratch));
6311 emit_move_insn (gen_frame_mem (Pmode, addr), source);
6315 /* We save pairs of registers using a DImode store. Describe the component
6316 registers for DWARF generation code. */
6319 c6x_dwarf_register_span (rtx rtl)
6322 unsigned real_regno;
6327 regno = REGNO (rtl);
6328 nregs = HARD_REGNO_NREGS (regno, GET_MODE (rtl));
6332 p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc(nregs));
6333 for (i = 0; i < nregs; i++)
6335 if (TARGET_BIG_ENDIAN)
6336 real_regno = regno + nregs - (i + 1);
6338 real_regno = regno + i;
6340 XVECEXP (p, 0, i) = gen_rtx_REG (SImode, real_regno);
6346 /* Codes for all the C6X builtins. */
6381 static GTY(()) tree c6x_builtin_decls[C6X_BUILTIN_MAX];
6383 /* Return the C6X builtin for CODE. */
6385 c6x_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
6387 if (code >= C6X_BUILTIN_MAX)
6388 return error_mark_node;
6390 return c6x_builtin_decls[code];
6393 #define def_builtin(NAME, TYPE, CODE) \
6396 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6398 c6x_builtin_decls[CODE] = bdecl; \
6401 /* Set up all builtin functions for this target. */
6403 c6x_init_builtins (void)
6405 tree V4QI_type_node = build_vector_type (unsigned_intQI_type_node, 4);
6406 tree V2HI_type_node = build_vector_type (intHI_type_node, 2);
6407 tree V2SI_type_node = build_vector_type (intSI_type_node, 2);
6409 = build_function_type_list (integer_type_node, integer_type_node,
6411 tree int_ftype_int_int
6412 = build_function_type_list (integer_type_node, integer_type_node,
6413 integer_type_node, NULL_TREE);
6414 tree v2hi_ftype_v2hi
6415 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
6416 tree v4qi_ftype_v4qi_v4qi
6417 = build_function_type_list (V4QI_type_node, V4QI_type_node,
6418 V4QI_type_node, NULL_TREE);
6419 tree v2hi_ftype_v2hi_v2hi
6420 = build_function_type_list (V2HI_type_node, V2HI_type_node,
6421 V2HI_type_node, NULL_TREE);
6422 tree v2si_ftype_v2hi_v2hi
6423 = build_function_type_list (V2SI_type_node, V2HI_type_node,
6424 V2HI_type_node, NULL_TREE);
6426 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int,
6428 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int,
6430 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi,
6432 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi,
6434 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi,
6436 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi,
6438 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi,
6440 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi,
6442 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi,
6444 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi,
6445 C6X_BUILTIN_SADDU4);
6446 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi,
6449 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int,
6451 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int,
6453 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int,
6454 C6X_BUILTIN_SMPYHL);
6455 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int,
6456 C6X_BUILTIN_SMPYLH);
6458 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int,
6460 def_builtin ("__builtin_c6x_subc", int_ftype_int_int,
6463 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi,
6465 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi,
6468 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int,
6470 def_builtin ("__builtin_c6x_extr", int_ftype_int_int,
6472 def_builtin ("__builtin_c6x_extru", int_ftype_int_int,
6475 def_builtin ("__builtin_c6x_abs", int_ftype_int, C6X_BUILTIN_ABS);
6476 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi, C6X_BUILTIN_ABS2);
6480 struct builtin_description
6482 const enum insn_code icode;
6483 const char *const name;
6484 const enum c6x_builtins code;
6487 static const struct builtin_description bdesc_2arg[] =
6489 { CODE_FOR_saddsi3, "__builtin_c6x_sadd", C6X_BUILTIN_SADD },
6490 { CODE_FOR_ssubsi3, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB },
6491 { CODE_FOR_addv2hi3, "__builtin_c6x_add2", C6X_BUILTIN_ADD2 },
6492 { CODE_FOR_subv2hi3, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2 },
6493 { CODE_FOR_addv4qi3, "__builtin_c6x_add4", C6X_BUILTIN_ADD4 },
6494 { CODE_FOR_subv4qi3, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4 },
6495 { CODE_FOR_ss_addv2hi3, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2 },
6496 { CODE_FOR_ss_subv2hi3, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2 },
6497 { CODE_FOR_us_addv4qi3, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4 },
6499 { CODE_FOR_subcsi3, "__builtin_c6x_subc", C6X_BUILTIN_SUBC },
6500 { CODE_FOR_ss_ashlsi3, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL },
6502 { CODE_FOR_avgv2hi3, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2 },
6503 { CODE_FOR_uavgv4qi3, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4 },
6505 { CODE_FOR_mulhqsq3, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY },
6506 { CODE_FOR_mulhqsq3_hh, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH },
6507 { CODE_FOR_mulhqsq3_lh, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH },
6508 { CODE_FOR_mulhqsq3_hl, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL },
6510 { CODE_FOR_mulv2hqv2sq3, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2 },
6512 { CODE_FOR_clrr, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR },
6513 { CODE_FOR_extr, "__builtin_c6x_extr", C6X_BUILTIN_EXTR },
6514 { CODE_FOR_extru, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU }
6517 static const struct builtin_description bdesc_1arg[] =
6519 { CODE_FOR_ssabssi2, "__builtin_c6x_abs", C6X_BUILTIN_ABS },
6520 { CODE_FOR_ssabsv2hi2, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2 }
6523 /* Errors in the source file can cause expand_expr to return const0_rtx
6524 where we expect a vector. To avoid crashing, use one of the vector
6525 clear instructions. */
6527 safe_vector_operand (rtx x, enum machine_mode mode)
6529 if (x != const0_rtx)
6531 x = gen_reg_rtx (SImode);
6533 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
6534 return gen_lowpart (mode, x);
6537 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6538 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6541 c6x_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
6544 int offs = match_op ? 1 : 0;
6546 tree arg0 = CALL_EXPR_ARG (exp, 0);
6547 tree arg1 = CALL_EXPR_ARG (exp, 1);
6548 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6549 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6550 enum machine_mode op0mode = GET_MODE (op0);
6551 enum machine_mode op1mode = GET_MODE (op1);
6552 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6553 enum machine_mode mode0 = insn_data[icode].operand[1 + offs].mode;
6554 enum machine_mode mode1 = insn_data[icode].operand[2 + offs].mode;
6557 if (VECTOR_MODE_P (mode0))
6558 op0 = safe_vector_operand (op0, mode0);
6559 if (VECTOR_MODE_P (mode1))
6560 op1 = safe_vector_operand (op1, mode1);
6563 || GET_MODE (target) != tmode
6564 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6566 if (tmode == SQmode || tmode == V2SQmode)
6568 ret = gen_reg_rtx (tmode == SQmode ? SImode : V2SImode);
6569 target = gen_lowpart (tmode, ret);
6572 target = gen_reg_rtx (tmode);
6575 if ((op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode)
6576 && (mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode))
6579 op0 = gen_lowpart (mode0, op0);
6581 if ((op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode)
6582 && (mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode))
6585 op1 = gen_lowpart (mode1, op1);
6587 /* In case the insn wants input operands in modes different from
6588 the result, abort. */
6589 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
6590 && (op1mode == mode1 || op1mode == VOIDmode));
6592 if (! (*insn_data[icode].operand[1 + offs].predicate) (op0, mode0))
6593 op0 = copy_to_mode_reg (mode0, op0);
6594 if (! (*insn_data[icode].operand[2 + offs].predicate) (op1, mode1))
6595 op1 = copy_to_mode_reg (mode1, op1);
6598 pat = GEN_FCN (icode) (target, target, op0, op1);
6600 pat = GEN_FCN (icode) (target, op0, op1);
6610 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
6613 c6x_expand_unop_builtin (enum insn_code icode, tree exp,
6617 tree arg0 = CALL_EXPR_ARG (exp, 0);
6618 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6619 enum machine_mode op0mode = GET_MODE (op0);
6620 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6621 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6624 || GET_MODE (target) != tmode
6625 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6626 target = gen_reg_rtx (tmode);
6628 if (VECTOR_MODE_P (mode0))
6629 op0 = safe_vector_operand (op0, mode0);
6631 if (op0mode == SImode && mode0 == HImode)
6634 op0 = gen_lowpart (HImode, op0);
6636 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
6638 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6639 op0 = copy_to_mode_reg (mode0, op0);
6641 pat = GEN_FCN (icode) (target, op0);
6648 /* Expand an expression EXP that calls a built-in function,
6649 with result going to TARGET if that's convenient
6650 (and in mode MODE if that's convenient).
6651 SUBTARGET may be used as the target for computing one of EXP's operands.
6652 IGNORE is nonzero if the value is to be ignored. */
6655 c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6656 rtx subtarget ATTRIBUTE_UNUSED,
6657 enum machine_mode mode ATTRIBUTE_UNUSED,
6658 int ignore ATTRIBUTE_UNUSED)
6661 const struct builtin_description *d;
6662 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6663 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6665 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6666 if (d->code == fcode)
6667 return c6x_expand_binop_builtin (d->icode, exp, target,
6668 fcode == C6X_BUILTIN_CLRR);
6670 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6671 if (d->code == fcode)
6672 return c6x_expand_unop_builtin (d->icode, exp, target);
6677 /* Target unwind frame info is generated from dwarf CFI directives, so
6678 always output dwarf2 unwind info. */
6680 static enum unwind_info_type
6681 c6x_debug_unwind_info (void)
6683 if (flag_unwind_tables || flag_exceptions)
6686 return default_debug_unwind_info ();
6689 /* Target Structure. */
6691 /* Initialize the GCC target structure. */
6692 #undef TARGET_FUNCTION_ARG
6693 #define TARGET_FUNCTION_ARG c6x_function_arg
6694 #undef TARGET_FUNCTION_ARG_ADVANCE
6695 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6696 #undef TARGET_FUNCTION_ARG_BOUNDARY
6697 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6698 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6699 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6700 c6x_function_arg_round_boundary
6701 #undef TARGET_FUNCTION_VALUE_REGNO_P
6702 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6703 #undef TARGET_FUNCTION_VALUE
6704 #define TARGET_FUNCTION_VALUE c6x_function_value
6705 #undef TARGET_LIBCALL_VALUE
6706 #define TARGET_LIBCALL_VALUE c6x_libcall_value
6707 #undef TARGET_RETURN_IN_MEMORY
6708 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6709 #undef TARGET_RETURN_IN_MSB
6710 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
6711 #undef TARGET_PASS_BY_REFERENCE
6712 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6713 #undef TARGET_CALLEE_COPIES
6714 #define TARGET_CALLEE_COPIES c6x_callee_copies
6715 #undef TARGET_STRUCT_VALUE_RTX
6716 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6717 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6718 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6720 #undef TARGET_ASM_OUTPUT_MI_THUNK
6721 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6722 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6723 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6725 #undef TARGET_BUILD_BUILTIN_VA_LIST
6726 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6728 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6729 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6730 #undef TARGET_TRAMPOLINE_INIT
6731 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6733 #undef TARGET_LEGITIMATE_CONSTANT_P
6734 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6735 #undef TARGET_LEGITIMATE_ADDRESS_P
6736 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6738 #undef TARGET_IN_SMALL_DATA_P
6739 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6740 #undef TARGET_ASM_SELECT_RTX_SECTION
6741 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6742 #undef TARGET_ASM_SELECT_SECTION
6743 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6744 #undef TARGET_ASM_UNIQUE_SECTION
6745 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6746 #undef TARGET_SECTION_TYPE_FLAGS
6747 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6748 #undef TARGET_HAVE_SRODATA_SECTION
6749 #define TARGET_HAVE_SRODATA_SECTION true
6750 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6751 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6753 #undef TARGET_OPTION_OVERRIDE
6754 #define TARGET_OPTION_OVERRIDE c6x_option_override
6755 #undef TARGET_CONDITIONAL_REGISTER_USAGE
6756 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6758 #undef TARGET_INIT_LIBFUNCS
6759 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6760 #undef TARGET_LIBFUNC_GNU_PREFIX
6761 #define TARGET_LIBFUNC_GNU_PREFIX true
6763 #undef TARGET_SCALAR_MODE_SUPPORTED_P
6764 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6765 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6766 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6767 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6768 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6770 #undef TARGET_RTX_COSTS
6771 #define TARGET_RTX_COSTS c6x_rtx_costs
6773 #undef TARGET_SCHED_INIT
6774 #define TARGET_SCHED_INIT c6x_sched_init
6775 #undef TARGET_SCHED_SET_SCHED_FLAGS
6776 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6777 #undef TARGET_SCHED_ADJUST_COST
6778 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6779 #undef TARGET_SCHED_ISSUE_RATE
6780 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6781 #undef TARGET_SCHED_VARIABLE_ISSUE
6782 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6783 #undef TARGET_SCHED_REORDER
6784 #define TARGET_SCHED_REORDER c6x_sched_reorder
6785 #undef TARGET_SCHED_REORDER2
6786 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6787 #undef TARGET_SCHED_DFA_NEW_CYCLE
6788 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6789 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6790 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
6791 #undef TARGET_SCHED_EXPOSED_PIPELINE
6792 #define TARGET_SCHED_EXPOSED_PIPELINE true
6794 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6795 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6796 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
6797 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6798 #undef TARGET_SCHED_SET_SCHED_CONTEXT
6799 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6800 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6801 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
6802 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
6803 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6805 #undef TARGET_CAN_ELIMINATE
6806 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
6808 #undef TARGET_PREFERRED_RENAME_CLASS
6809 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6811 #undef TARGET_MACHINE_DEPENDENT_REORG
6812 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6814 #undef TARGET_ASM_FILE_START
6815 #define TARGET_ASM_FILE_START c6x_file_start
6817 #undef TARGET_PRINT_OPERAND
6818 #define TARGET_PRINT_OPERAND c6x_print_operand
6819 #undef TARGET_PRINT_OPERAND_ADDRESS
6820 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6821 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6822 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6824 /* C6x unwinding tables use a different format for the typeinfo tables. */
6825 #undef TARGET_ASM_TTYPE
6826 #define TARGET_ASM_TTYPE c6x_output_ttype
6828 /* The C6x ABI follows the ARM EABI exception handling rules. */
6829 #undef TARGET_ARM_EABI_UNWINDER
6830 #define TARGET_ARM_EABI_UNWINDER true
6832 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6833 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6835 #undef TARGET_ASM_INIT_SECTIONS
6836 #define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6838 #undef TARGET_DEBUG_UNWIND_INFO
6839 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6841 #undef TARGET_DWARF_REGISTER_SPAN
6842 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6844 #undef TARGET_INIT_BUILTINS
6845 #define TARGET_INIT_BUILTINS c6x_init_builtins
6846 #undef TARGET_EXPAND_BUILTIN
6847 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6848 #undef TARGET_BUILTIN_DECL
6849 #define TARGET_BUILTIN_DECL c6x_builtin_decl
6851 struct gcc_target targetm = TARGET_INITIALIZER;