gcc/
[official-gcc.git] / gcc / config / c6x / c6x.c
blobdeb2f5395dd723bb48a9052723999c436d887845
1 /* Target Code for TI C6X
2 Copyright (C) 2010, 2011 Free Software Foundation, Inc.
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "insn-flags.h"
29 #include "output.h"
30 #include "insn-attr.h"
31 #include "insn-codes.h"
32 #include "expr.h"
33 #include "regs.h"
34 #include "optabs.h"
35 #include "recog.h"
36 #include "ggc.h"
37 #include "sched-int.h"
38 #include "timevar.h"
39 #include "tm_p.h"
40 #include "tm-preds.h"
41 #include "tm-constrs.h"
42 #include "df.h"
43 #include "integrate.h"
44 #include "diagnostic-core.h"
45 #include "cgraph.h"
46 #include "cfglayout.h"
47 #include "langhooks.h"
48 #include "target.h"
49 #include "target-def.h"
50 #include "sel-sched.h"
51 #include "debug.h"
52 #include "opts.h"
54 /* Table of supported architecture variants. */
55 typedef struct
57 const char *arch;
58 enum c6x_cpu_type type;
59 unsigned short features;
60 } c6x_arch_table;
62 /* A list of all ISAs, mapping each one to a representative device.
63 Used for -march selection. */
64 static const c6x_arch_table all_isas[] =
66 #define C6X_ISA(NAME,DEVICE,FLAGS) \
67 { NAME, DEVICE, FLAGS },
68 #include "c6x-isas.def"
69 #undef C6X_ISA
70 { NULL, C6X_CPU_C62X, 0 }
73 /* This is the parsed result of the "-march=" option, if given. */
74 enum c6x_cpu_type c6x_arch = C6X_DEFAULT_ARCH;
76 /* A mask of insn types that are allowed by the architecture selected by
77 the -march option. */
78 unsigned long c6x_insn_mask = C6X_DEFAULT_INSN_MASK;
80 /* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
82 static rtx c6x_current_insn = NULL_RTX;
84 /* A decl we build to access __c6xabi_DSBT_base. */
85 static GTY(()) tree dsbt_decl;
87 /* Determines whether we run our final scheduling pass or not. We always
88 avoid the normal second scheduling pass. */
89 static int c6x_flag_schedule_insns2;
91 /* Determines whether we run variable tracking in machine dependent
92 reorganization. */
93 static int c6x_flag_var_tracking;
95 /* Determines whether we use modulo scheduling. */
96 static int c6x_flag_modulo_sched;
98 /* Record the state of flag_pic before we set it to 1 for DSBT. */
99 int c6x_initial_flag_pic;
101 typedef struct
103 /* We record the clock cycle for every insn during scheduling. */
104 int clock;
105 /* After scheduling, we run assign_reservations to choose unit
106 reservations for all insns. These are recorded here. */
107 int reservation;
108 /* Records the new condition for insns which must be made
109 conditional after scheduling. An entry of NULL_RTX means no such
110 change is necessary. */
111 rtx new_cond;
112 /* True for the first insn that was scheduled in an ebb. */
113 bool ebb_start;
114 } c6x_sched_insn_info;
116 DEF_VEC_O(c6x_sched_insn_info);
117 DEF_VEC_ALLOC_O(c6x_sched_insn_info, heap);
119 /* Record a c6x_sched_insn_info structure for every insn in the function. */
120 static VEC(c6x_sched_insn_info, heap) *insn_info;
122 #define INSN_INFO_LENGTH (VEC_length (c6x_sched_insn_info, insn_info))
123 #define INSN_INFO_ENTRY(N) (*VEC_index (c6x_sched_insn_info, insn_info, (N)))
125 static bool done_cfi_sections;
127 /* The DFA names of the units, in packet order. */
128 static const char *const c6x_unit_names[] =
130 "d1", "l1", "s1", "m1",
131 "d2", "l2", "s2", "m2",
134 #define RESERVATION_FLAG_D 1
135 #define RESERVATION_FLAG_L 2
136 #define RESERVATION_FLAG_S 4
137 #define RESERVATION_FLAG_M 8
138 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
139 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
140 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
141 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
143 #define RESERVATION_S1 2
144 #define RESERVATION_S2 6
146 /* Register map for debugging. */
147 int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
149 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
150 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
151 50, 51, 52,
152 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
153 29, 30, 31,
154 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
155 66, 67, 68,
156 -1, -1, -1 /* FP, ARGP, ILC. */
159 /* Allocate a new, cleared machine_function structure. */
161 static struct machine_function *
162 c6x_init_machine_status (void)
164 return ggc_alloc_cleared_machine_function ();
167 /* Implement TARGET_OPTION_OVERRIDE. */
169 static void
170 c6x_option_override (void)
172 if (global_options_set.x_c6x_arch_option)
174 c6x_arch = all_isas[c6x_arch_option].type;
175 c6x_insn_mask &= ~C6X_INSNS_ALL_CPU_BITS;
176 c6x_insn_mask |= all_isas[c6x_arch_option].features;
179 c6x_flag_schedule_insns2 = flag_schedule_insns_after_reload;
180 flag_schedule_insns_after_reload = 0;
182 c6x_flag_modulo_sched = flag_modulo_sched;
183 flag_modulo_sched = 0;
185 init_machine_status = c6x_init_machine_status;
187 if (flag_pic && !TARGET_DSBT)
189 error ("-fpic and -fPIC not supported without -mdsbt on this target");
190 flag_pic = 0;
192 c6x_initial_flag_pic = flag_pic;
193 if (TARGET_DSBT && !flag_pic)
194 flag_pic = 1;
198 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
200 static void
201 c6x_conditional_register_usage (void)
203 int i;
204 if (c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X)
205 for (i = 16; i < 32; i++)
207 fixed_regs[i] = 1;
208 fixed_regs[32 + i] = 1;
210 if (TARGET_INSNS_64)
212 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_A_REGS],
213 REG_A0);
214 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_REGS],
215 REG_A0);
216 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_A_REGS],
217 REG_A0);
218 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_REGS],
219 REG_A0);
223 static GTY(()) rtx eqdf_libfunc;
224 static GTY(()) rtx nedf_libfunc;
225 static GTY(()) rtx ledf_libfunc;
226 static GTY(()) rtx ltdf_libfunc;
227 static GTY(()) rtx gedf_libfunc;
228 static GTY(()) rtx gtdf_libfunc;
229 static GTY(()) rtx eqsf_libfunc;
230 static GTY(()) rtx nesf_libfunc;
231 static GTY(()) rtx lesf_libfunc;
232 static GTY(()) rtx ltsf_libfunc;
233 static GTY(()) rtx gesf_libfunc;
234 static GTY(()) rtx gtsf_libfunc;
235 static GTY(()) rtx strasgi_libfunc;
236 static GTY(()) rtx strasgi64p_libfunc;
238 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
239 functions to match the C6x ABI. */
241 static void
242 c6x_init_libfuncs (void)
244 /* Double-precision floating-point arithmetic. */
245 set_optab_libfunc (add_optab, DFmode, "__c6xabi_addd");
246 set_optab_libfunc (sdiv_optab, DFmode, "__c6xabi_divd");
247 set_optab_libfunc (smul_optab, DFmode, "__c6xabi_mpyd");
248 set_optab_libfunc (neg_optab, DFmode, "__c6xabi_negd");
249 set_optab_libfunc (sub_optab, DFmode, "__c6xabi_subd");
251 /* Single-precision floating-point arithmetic. */
252 set_optab_libfunc (add_optab, SFmode, "__c6xabi_addf");
253 set_optab_libfunc (sdiv_optab, SFmode, "__c6xabi_divf");
254 set_optab_libfunc (smul_optab, SFmode, "__c6xabi_mpyf");
255 set_optab_libfunc (neg_optab, SFmode, "__c6xabi_negf");
256 set_optab_libfunc (sub_optab, SFmode, "__c6xabi_subf");
258 /* Floating-point comparisons. */
259 eqsf_libfunc = init_one_libfunc ("__c6xabi_eqf");
260 nesf_libfunc = init_one_libfunc ("__c6xabi_neqf");
261 lesf_libfunc = init_one_libfunc ("__c6xabi_lef");
262 ltsf_libfunc = init_one_libfunc ("__c6xabi_ltf");
263 gesf_libfunc = init_one_libfunc ("__c6xabi_gef");
264 gtsf_libfunc = init_one_libfunc ("__c6xabi_gtf");
265 eqdf_libfunc = init_one_libfunc ("__c6xabi_eqd");
266 nedf_libfunc = init_one_libfunc ("__c6xabi_neqd");
267 ledf_libfunc = init_one_libfunc ("__c6xabi_led");
268 ltdf_libfunc = init_one_libfunc ("__c6xabi_ltd");
269 gedf_libfunc = init_one_libfunc ("__c6xabi_ged");
270 gtdf_libfunc = init_one_libfunc ("__c6xabi_gtd");
272 set_optab_libfunc (eq_optab, SFmode, NULL);
273 set_optab_libfunc (ne_optab, SFmode, "__c6xabi_neqf");
274 set_optab_libfunc (gt_optab, SFmode, NULL);
275 set_optab_libfunc (ge_optab, SFmode, NULL);
276 set_optab_libfunc (lt_optab, SFmode, NULL);
277 set_optab_libfunc (le_optab, SFmode, NULL);
278 set_optab_libfunc (unord_optab, SFmode, "__c6xabi_unordf");
279 set_optab_libfunc (eq_optab, DFmode, NULL);
280 set_optab_libfunc (ne_optab, DFmode, "__c6xabi_neqd");
281 set_optab_libfunc (gt_optab, DFmode, NULL);
282 set_optab_libfunc (ge_optab, DFmode, NULL);
283 set_optab_libfunc (lt_optab, DFmode, NULL);
284 set_optab_libfunc (le_optab, DFmode, NULL);
285 set_optab_libfunc (unord_optab, DFmode, "__c6xabi_unordd");
287 /* Floating-point to integer conversions. */
288 set_conv_libfunc (sfix_optab, SImode, DFmode, "__c6xabi_fixdi");
289 set_conv_libfunc (ufix_optab, SImode, DFmode, "__c6xabi_fixdu");
290 set_conv_libfunc (sfix_optab, DImode, DFmode, "__c6xabi_fixdlli");
291 set_conv_libfunc (ufix_optab, DImode, DFmode, "__c6xabi_fixdull");
292 set_conv_libfunc (sfix_optab, SImode, SFmode, "__c6xabi_fixfi");
293 set_conv_libfunc (ufix_optab, SImode, SFmode, "__c6xabi_fixfu");
294 set_conv_libfunc (sfix_optab, DImode, SFmode, "__c6xabi_fixflli");
295 set_conv_libfunc (ufix_optab, DImode, SFmode, "__c6xabi_fixfull");
297 /* Conversions between floating types. */
298 set_conv_libfunc (trunc_optab, SFmode, DFmode, "__c6xabi_cvtdf");
299 set_conv_libfunc (sext_optab, DFmode, SFmode, "__c6xabi_cvtfd");
301 /* Integer to floating-point conversions. */
302 set_conv_libfunc (sfloat_optab, DFmode, SImode, "__c6xabi_fltid");
303 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__c6xabi_fltud");
304 set_conv_libfunc (sfloat_optab, DFmode, DImode, "__c6xabi_fltllid");
305 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__c6xabi_fltulld");
306 set_conv_libfunc (sfloat_optab, SFmode, SImode, "__c6xabi_fltif");
307 set_conv_libfunc (ufloat_optab, SFmode, SImode, "__c6xabi_fltuf");
308 set_conv_libfunc (sfloat_optab, SFmode, DImode, "__c6xabi_fltllif");
309 set_conv_libfunc (ufloat_optab, SFmode, DImode, "__c6xabi_fltullf");
311 /* Long long. */
312 set_optab_libfunc (smul_optab, DImode, "__c6xabi_mpyll");
313 set_optab_libfunc (ashl_optab, DImode, "__c6xabi_llshl");
314 set_optab_libfunc (lshr_optab, DImode, "__c6xabi_llshru");
315 set_optab_libfunc (ashr_optab, DImode, "__c6xabi_llshr");
317 set_optab_libfunc (sdiv_optab, SImode, "__c6xabi_divi");
318 set_optab_libfunc (udiv_optab, SImode, "__c6xabi_divu");
319 set_optab_libfunc (smod_optab, SImode, "__c6xabi_remi");
320 set_optab_libfunc (umod_optab, SImode, "__c6xabi_remu");
321 set_optab_libfunc (sdivmod_optab, SImode, "__c6xabi_divremi");
322 set_optab_libfunc (udivmod_optab, SImode, "__c6xabi_divremu");
323 set_optab_libfunc (sdiv_optab, DImode, "__c6xabi_divlli");
324 set_optab_libfunc (udiv_optab, DImode, "__c6xabi_divull");
325 set_optab_libfunc (smod_optab, DImode, "__c6xabi_remlli");
326 set_optab_libfunc (umod_optab, DImode, "__c6xabi_remull");
327 set_optab_libfunc (udivmod_optab, DImode, "__c6xabi_divremull");
329 /* Block move. */
330 strasgi_libfunc = init_one_libfunc ("__c6xabi_strasgi");
331 strasgi64p_libfunc = init_one_libfunc ("__c6xabi_strasgi_64plus");
334 /* Begin the assembly file. */
336 static void
337 c6x_file_start (void)
339 /* Variable tracking should be run after all optimizations which change order
340 of insns. It also needs a valid CFG. This can't be done in
341 c6x_override_options, because flag_var_tracking is finalized after
342 that. */
343 c6x_flag_var_tracking = flag_var_tracking;
344 flag_var_tracking = 0;
346 done_cfi_sections = false;
347 default_file_start ();
349 /* Arrays are aligned to 8-byte boundaries. */
350 asm_fprintf (asm_out_file,
351 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
352 asm_fprintf (asm_out_file,
353 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
355 /* Stack alignment is 8 bytes. */
356 asm_fprintf (asm_out_file,
357 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
358 asm_fprintf (asm_out_file,
359 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
361 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
362 /* ??? Ideally we'd check flag_short_wchar somehow. */
363 asm_fprintf (asm_out_file, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
364 #endif
366 /* We conform to version 1.0 of the ABI. */
367 asm_fprintf (asm_out_file,
368 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
372 /* The LTO frontend only enables exceptions when it sees a function that
373 uses it. This changes the return value of dwarf2out_do_frame, so we
374 have to check before every function. */
376 void
377 c6x_output_file_unwind (FILE * f)
379 if (done_cfi_sections)
380 return;
382 /* Output a .cfi_sections directive if we aren't
383 already doing so for debug info. */
384 if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
385 && dwarf2out_do_frame ())
387 asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
388 done_cfi_sections = true;
392 /* Output unwind directives at the end of a function. */
394 static void
395 c6x_output_fn_unwind (FILE * f)
397 /* Return immediately if we are not generating unwinding tables. */
398 if (! (flag_unwind_tables || flag_exceptions))
399 return;
401 /* If this function will never be unwound, then mark it as such. */
402 if (!(flag_unwind_tables || crtl->uses_eh_lsda)
403 && (TREE_NOTHROW (current_function_decl)
404 || crtl->all_throwers_are_sibcalls))
405 fputs("\t.cantunwind\n", f);
407 fputs ("\t.endp\n", f);
411 /* Stack and Calling. */
413 int argument_registers[10] =
415 REG_A4, REG_B4,
416 REG_A6, REG_B6,
417 REG_A8, REG_B8,
418 REG_A10, REG_B10,
419 REG_A12, REG_B12
422 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
424 void
425 c6x_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, rtx libname,
426 int n_named_args ATTRIBUTE_UNUSED)
428 cum->count = 0;
429 cum->nregs = 10;
430 if (!libname && fntype)
432 /* We need to find out the number of named arguments. Unfortunately,
433 for incoming arguments, N_NAMED_ARGS is set to -1. */
434 if (stdarg_p (fntype))
435 cum->nregs = type_num_arguments (fntype) - 1;
436 if (cum->nregs > 10)
437 cum->nregs = 10;
441 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
443 static rtx
444 c6x_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
445 const_tree type, bool named ATTRIBUTE_UNUSED)
447 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
448 if (cum->count >= cum->nregs)
449 return NULL_RTX;
450 if (type)
452 HOST_WIDE_INT size = int_size_in_bytes (type);
453 if (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (type))
455 if (size > 4)
457 rtx reg1 = gen_rtx_REG (SImode, argument_registers[cum->count] + 1);
458 rtx reg2 = gen_rtx_REG (SImode, argument_registers[cum->count]);
459 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
460 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
461 return gen_rtx_PARALLEL (mode, vec);
465 return gen_rtx_REG (mode, argument_registers[cum->count]);
468 static void
469 c6x_function_arg_advance (cumulative_args_t cum_v,
470 enum machine_mode mode ATTRIBUTE_UNUSED,
471 const_tree type ATTRIBUTE_UNUSED,
472 bool named ATTRIBUTE_UNUSED)
474 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
475 cum->count++;
479 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
480 upward rather than downward. */
482 bool
483 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
484 const_tree type, bool first)
486 HOST_WIDE_INT size;
488 if (!TARGET_BIG_ENDIAN)
489 return true;
490 if (!first)
491 return true;
492 if (!type)
493 return true;
494 size = int_size_in_bytes (type);
495 return size == 3;
498 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
500 static unsigned int
501 c6x_function_arg_boundary (enum machine_mode mode, const_tree type)
503 unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
505 if (boundary > BITS_PER_WORD)
506 return 2 * BITS_PER_WORD;
508 if (mode == BLKmode)
510 HOST_WIDE_INT size = int_size_in_bytes (type);
511 if (size > 4)
512 return 2 * BITS_PER_WORD;
513 if (boundary < BITS_PER_WORD)
515 if (size >= 3)
516 return BITS_PER_WORD;
517 if (size >= 2)
518 return 2 * BITS_PER_UNIT;
521 return boundary;
524 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
525 static unsigned int
526 c6x_function_arg_round_boundary (enum machine_mode mode, const_tree type)
528 return c6x_function_arg_boundary (mode, type);
531 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
532 where function FUNC returns or receives a value of data type TYPE. */
534 static rtx
535 c6x_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
536 bool outgoing ATTRIBUTE_UNUSED)
538 /* Functions return values in register A4. When returning aggregates, we may
539 have to adjust for endianness. */
540 if (TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P (type))
542 HOST_WIDE_INT size = int_size_in_bytes (type);
543 if (size > 4)
546 rtx reg1 = gen_rtx_REG (SImode, REG_A4 + 1);
547 rtx reg2 = gen_rtx_REG (SImode, REG_A4);
548 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
549 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
550 return gen_rtx_PARALLEL (TYPE_MODE (type), vec);
553 return gen_rtx_REG (TYPE_MODE (type), REG_A4);
556 /* Implement TARGET_LIBCALL_VALUE. */
558 static rtx
559 c6x_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
561 return gen_rtx_REG (mode, REG_A4);
564 /* TARGET_STRUCT_VALUE_RTX implementation. */
566 static rtx
567 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED)
569 return gen_rtx_REG (Pmode, REG_A3);
572 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
574 static bool
575 c6x_function_value_regno_p (const unsigned int regno)
577 return regno == REG_A4;
580 /* Types larger than 64 bit, and variable sized types, are passed by
581 reference. The callee must copy them; see c6x_callee_copies. */
583 static bool
584 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
585 enum machine_mode mode, const_tree type,
586 bool named ATTRIBUTE_UNUSED)
588 int size = -1;
589 if (type)
590 size = int_size_in_bytes (type);
591 else if (mode != VOIDmode)
592 size = GET_MODE_SIZE (mode);
593 return size > 2 * UNITS_PER_WORD || size == -1;
596 /* Decide whether a type should be returned in memory (true)
597 or in a register (false). This is called by the macro
598 TARGET_RETURN_IN_MEMORY. */
600 static bool
601 c6x_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
603 int size = int_size_in_bytes (type);
604 return size > 2 * UNITS_PER_WORD || size == -1;
607 /* Values which must be returned in the most-significant end of the return
608 register. */
610 static bool
611 c6x_return_in_msb (const_tree valtype)
613 HOST_WIDE_INT size = int_size_in_bytes (valtype);
614 return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && size == 3;
617 /* Implement TARGET_CALLEE_COPIES. */
619 static bool
620 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
621 enum machine_mode mode ATTRIBUTE_UNUSED,
622 const_tree type ATTRIBUTE_UNUSED,
623 bool named ATTRIBUTE_UNUSED)
625 return true;
628 /* Return the type to use as __builtin_va_list. */
629 static tree
630 c6x_build_builtin_va_list (void)
632 return build_pointer_type (char_type_node);
635 static void
636 c6x_asm_trampoline_template (FILE *f)
638 fprintf (f, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
639 fprintf (f, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
640 fprintf (f, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
641 fprintf (f, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
642 fprintf (f, "\t.long\t0x00000362\n"); /* b .s2 B0 */
643 fprintf (f, "\t.long\t0x00008000\n"); /* nop 5 */
644 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
645 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
648 /* Emit RTL insns to initialize the variable parts of a trampoline at
649 TRAMP. FNADDR is an RTX for the address of the function's pure
650 code. CXT is an RTX for the static chain value for the function. */
652 static void
653 c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt)
655 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
656 rtx t1 = copy_to_reg (fnaddr);
657 rtx t2 = copy_to_reg (cxt);
658 rtx mask = gen_reg_rtx (SImode);
659 int i;
661 emit_block_move (tramp, assemble_trampoline_template (),
662 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
664 emit_move_insn (mask, GEN_INT (0xffff << 7));
666 for (i = 0; i < 4; i++)
668 rtx mem = adjust_address (tramp, SImode, i * 4);
669 rtx t = (i & 1) ? t2 : t1;
670 rtx v1 = gen_reg_rtx (SImode);
671 rtx v2 = gen_reg_rtx (SImode);
672 emit_move_insn (v1, mem);
673 if (i < 2)
674 emit_insn (gen_ashlsi3 (v2, t, GEN_INT (7)));
675 else
676 emit_insn (gen_lshrsi3 (v2, t, GEN_INT (9)));
677 emit_insn (gen_andsi3 (v2, v2, mask));
678 emit_insn (gen_iorsi3 (v2, v2, v1));
679 emit_move_insn (mem, v2);
681 #ifdef CLEAR_INSN_CACHE
682 tramp = XEXP (tramp, 0);
683 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"),
684 LCT_NORMAL, VOIDmode, 2, tramp, Pmode,
685 plus_constant (tramp, TRAMPOLINE_SIZE), Pmode);
686 #endif
689 /* Determine whether c6x_output_mi_thunk can succeed. */
691 static bool
692 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
693 HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
694 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
695 const_tree function ATTRIBUTE_UNUSED)
697 return !TARGET_LONG_CALLS;
700 /* Output the assembler code for a thunk function. THUNK is the
701 declaration for the thunk function itself, FUNCTION is the decl for
702 the target function. DELTA is an immediate constant offset to be
703 added to THIS. If VCALL_OFFSET is nonzero, the word at
704 *(*this + vcall_offset) should be added to THIS. */
706 static void
707 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
708 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
709 HOST_WIDE_INT vcall_offset, tree function)
711 rtx xops[5];
712 /* The this parameter is passed as the first argument. */
713 rtx this_rtx = gen_rtx_REG (Pmode, REG_A4);
715 c6x_current_insn = NULL_RTX;
717 xops[4] = XEXP (DECL_RTL (function), 0);
718 if (!vcall_offset)
720 output_asm_insn ("b .s2 \t%4", xops);
721 if (!delta)
722 output_asm_insn ("nop 5", xops);
725 /* Adjust the this parameter by a fixed constant. */
726 if (delta)
728 xops[0] = GEN_INT (delta);
729 xops[1] = this_rtx;
730 if (delta >= -16 && delta <= 15)
732 output_asm_insn ("add .s1 %0, %1, %1", xops);
733 if (!vcall_offset)
734 output_asm_insn ("nop 4", xops);
736 else if (delta >= 16 && delta < 32)
738 output_asm_insn ("add .d1 %0, %1, %1", xops);
739 if (!vcall_offset)
740 output_asm_insn ("nop 4", xops);
742 else if (delta >= -32768 && delta < 32768)
744 output_asm_insn ("mvk .s1 %0, A0", xops);
745 output_asm_insn ("add .d1 %1, A0, %1", xops);
746 if (!vcall_offset)
747 output_asm_insn ("nop 3", xops);
749 else
751 output_asm_insn ("mvkl .s1 %0, A0", xops);
752 output_asm_insn ("mvkh .s1 %0, A0", xops);
753 output_asm_insn ("add .d1 %1, A0, %1", xops);
754 if (!vcall_offset)
755 output_asm_insn ("nop 3", xops);
759 /* Adjust the this parameter by a value stored in the vtable. */
760 if (vcall_offset)
762 rtx a0tmp = gen_rtx_REG (Pmode, REG_A0);
763 rtx a3tmp = gen_rtx_REG (Pmode, REG_A3);
765 xops[1] = a3tmp;
766 xops[2] = a0tmp;
767 xops[3] = gen_rtx_MEM (Pmode, a0tmp);
768 output_asm_insn ("mv .s1 a4, %2", xops);
769 output_asm_insn ("ldw .d1t1 %3, %2", xops);
771 /* Adjust the this parameter. */
772 xops[0] = gen_rtx_MEM (Pmode, plus_constant (a0tmp, vcall_offset));
773 if (!memory_operand (xops[0], Pmode))
775 rtx tmp2 = gen_rtx_REG (Pmode, REG_A1);
776 xops[0] = GEN_INT (vcall_offset);
777 xops[1] = tmp2;
778 output_asm_insn ("mvkl .s1 %0, %1", xops);
779 output_asm_insn ("mvkh .s1 %0, %1", xops);
780 output_asm_insn ("nop 2", xops);
781 output_asm_insn ("add .d1 %2, %1, %2", xops);
782 xops[0] = gen_rtx_MEM (Pmode, a0tmp);
784 else
785 output_asm_insn ("nop 4", xops);
786 xops[2] = this_rtx;
787 output_asm_insn ("ldw .d1t1 %0, %1", xops);
788 output_asm_insn ("|| b .s2 \t%4", xops);
789 output_asm_insn ("nop 4", xops);
790 output_asm_insn ("add .d1 %2, %1, %2", xops);
794 /* Return true if EXP goes in small data/bss. */
796 static bool
797 c6x_in_small_data_p (const_tree exp)
799 /* We want to merge strings, so we never consider them small data. */
800 if (TREE_CODE (exp) == STRING_CST)
801 return false;
803 /* Functions are never small data. */
804 if (TREE_CODE (exp) == FUNCTION_DECL)
805 return false;
807 if (TREE_CODE (exp) == VAR_DECL && DECL_WEAK (exp))
808 return false;
810 if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
812 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
814 if (strcmp (section, ".neardata") == 0
815 || strncmp (section, ".neardata.", 10) == 0
816 || strncmp (section, ".gnu.linkonce.s.", 16) == 0
817 || strcmp (section, ".bss") == 0
818 || strncmp (section, ".bss.", 5) == 0
819 || strncmp (section, ".gnu.linkonce.sb.", 17) == 0
820 || strcmp (section, ".rodata") == 0
821 || strncmp (section, ".rodata.", 8) == 0
822 || strncmp (section, ".gnu.linkonce.s2.", 17) == 0)
823 return true;
825 else
826 return PLACE_IN_SDATA_P (exp);
828 return false;
831 /* Return a section for X. The only special thing we do here is to
832 honor small data. We don't have a tree type, so we can't use the
833 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
834 everything sized 8 bytes or smaller into small data. */
836 static section *
837 c6x_select_rtx_section (enum machine_mode mode, rtx x,
838 unsigned HOST_WIDE_INT align)
840 if (c6x_sdata_mode == C6X_SDATA_ALL
841 || (c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE (mode) <= 8))
842 /* ??? Consider using mergeable sdata sections. */
843 return sdata_section;
844 else
845 return default_elf_select_rtx_section (mode, x, align);
848 static section *
849 c6x_elf_select_section (tree decl, int reloc,
850 unsigned HOST_WIDE_INT align)
852 const char *sname = NULL;
853 unsigned int flags = SECTION_WRITE;
854 if (c6x_in_small_data_p (decl))
856 switch (categorize_decl_for_section (decl, reloc))
858 case SECCAT_SRODATA:
859 sname = ".rodata";
860 flags = 0;
861 break;
862 case SECCAT_SDATA:
863 sname = ".neardata";
864 break;
865 case SECCAT_SBSS:
866 sname = ".bss";
867 flags |= SECTION_BSS;
868 default:
869 break;
872 else
874 switch (categorize_decl_for_section (decl, reloc))
876 case SECCAT_DATA:
877 sname = ".fardata";
878 break;
879 case SECCAT_DATA_REL:
880 sname = ".fardata.rel";
881 break;
882 case SECCAT_DATA_REL_LOCAL:
883 sname = ".fardata.rel.local";
884 break;
885 case SECCAT_DATA_REL_RO:
886 sname = ".fardata.rel.ro";
887 break;
888 case SECCAT_DATA_REL_RO_LOCAL:
889 sname = ".fardata.rel.ro.local";
890 break;
891 case SECCAT_BSS:
892 sname = ".far";
893 flags |= SECTION_BSS;
894 break;
895 case SECCAT_RODATA:
896 sname = ".const";
897 flags = 0;
898 break;
899 case SECCAT_SRODATA:
900 case SECCAT_SDATA:
901 case SECCAT_SBSS:
902 gcc_unreachable ();
903 default:
904 break;
907 if (sname)
909 /* We might get called with string constants, but get_named_section
910 doesn't like them as they are not DECLs. Also, we need to set
911 flags in that case. */
912 if (!DECL_P (decl))
913 return get_section (sname, flags, NULL);
914 return get_named_section (decl, sname, reloc);
917 return default_elf_select_section (decl, reloc, align);
920 /* Build up a unique section name, expressed as a
921 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
922 RELOC indicates whether the initial value of EXP requires
923 link-time relocations. */
925 static void ATTRIBUTE_UNUSED
926 c6x_elf_unique_section (tree decl, int reloc)
928 const char *prefix = NULL;
929 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
930 bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
932 if (c6x_in_small_data_p (decl))
934 switch (categorize_decl_for_section (decl, reloc))
936 case SECCAT_SDATA:
937 prefix = one_only ? ".s" : ".neardata";
938 break;
939 case SECCAT_SBSS:
940 prefix = one_only ? ".sb" : ".bss";
941 break;
942 case SECCAT_SRODATA:
943 prefix = one_only ? ".s2" : ".rodata";
944 break;
945 case SECCAT_RODATA_MERGE_STR:
946 case SECCAT_RODATA_MERGE_STR_INIT:
947 case SECCAT_RODATA_MERGE_CONST:
948 case SECCAT_RODATA:
949 case SECCAT_DATA:
950 case SECCAT_DATA_REL:
951 case SECCAT_DATA_REL_LOCAL:
952 case SECCAT_DATA_REL_RO:
953 case SECCAT_DATA_REL_RO_LOCAL:
954 gcc_unreachable ();
955 default:
956 /* Everything else we place into default sections and hope for the
957 best. */
958 break;
961 else
963 switch (categorize_decl_for_section (decl, reloc))
965 case SECCAT_DATA:
966 case SECCAT_DATA_REL:
967 case SECCAT_DATA_REL_LOCAL:
968 case SECCAT_DATA_REL_RO:
969 case SECCAT_DATA_REL_RO_LOCAL:
970 prefix = one_only ? ".fd" : ".fardata";
971 break;
972 case SECCAT_BSS:
973 prefix = one_only ? ".fb" : ".far";
974 break;
975 case SECCAT_RODATA:
976 case SECCAT_RODATA_MERGE_STR:
977 case SECCAT_RODATA_MERGE_STR_INIT:
978 case SECCAT_RODATA_MERGE_CONST:
979 prefix = one_only ? ".fr" : ".const";
980 break;
981 case SECCAT_SRODATA:
982 case SECCAT_SDATA:
983 case SECCAT_SBSS:
984 gcc_unreachable ();
985 default:
986 break;
990 if (prefix)
992 const char *name, *linkonce;
993 char *string;
995 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
996 name = targetm.strip_name_encoding (name);
998 /* If we're using one_only, then there needs to be a .gnu.linkonce
999 prefix to the section name. */
1000 linkonce = one_only ? ".gnu.linkonce" : "";
1002 string = ACONCAT ((linkonce, prefix, ".", name, NULL));
1004 DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
1005 return;
1007 default_unique_section (decl, reloc);
1010 static unsigned int
1011 c6x_section_type_flags (tree decl, const char *name, int reloc)
1013 unsigned int flags = 0;
1015 if (strcmp (name, ".far") == 0
1016 || strncmp (name, ".far.", 5) == 0)
1017 flags |= SECTION_BSS;
1019 flags |= default_section_type_flags (decl, name, reloc);
1021 return flags;
1024 /* Checks whether the given CALL_EXPR would use a caller saved
1025 register. This is used to decide whether sibling call optimization
1026 could be performed on the respective function call. */
1028 static bool
1029 c6x_call_saved_register_used (tree call_expr)
1031 CUMULATIVE_ARGS cum_v;
1032 cumulative_args_t cum;
1033 HARD_REG_SET call_saved_regset;
1034 tree parameter;
1035 enum machine_mode mode;
1036 tree type;
1037 rtx parm_rtx;
1038 int i;
1040 INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0);
1041 cum = pack_cumulative_args (&cum_v);
1043 COMPL_HARD_REG_SET (call_saved_regset, call_used_reg_set);
1044 for (i = 0; i < call_expr_nargs (call_expr); i++)
1046 parameter = CALL_EXPR_ARG (call_expr, i);
1047 gcc_assert (parameter);
1049 /* For an undeclared variable passed as parameter we will get
1050 an ERROR_MARK node here. */
1051 if (TREE_CODE (parameter) == ERROR_MARK)
1052 return true;
1054 type = TREE_TYPE (parameter);
1055 gcc_assert (type);
1057 mode = TYPE_MODE (type);
1058 gcc_assert (mode);
1060 if (pass_by_reference (&cum_v, mode, type, true))
1062 mode = Pmode;
1063 type = build_pointer_type (type);
1066 parm_rtx = c6x_function_arg (cum, mode, type, 0);
1068 c6x_function_arg_advance (cum, mode, type, 0);
1070 if (!parm_rtx)
1071 continue;
1073 if (REG_P (parm_rtx)
1074 && overlaps_hard_reg_set_p (call_saved_regset, GET_MODE (parm_rtx),
1075 REGNO (parm_rtx)))
1076 return true;
1077 if (GET_CODE (parm_rtx) == PARALLEL)
1079 int n = XVECLEN (parm_rtx, 0);
1080 while (n-- > 0)
1082 rtx x = XEXP (XVECEXP (parm_rtx, 0, n), 0);
1083 if (REG_P (x)
1084 && overlaps_hard_reg_set_p (call_saved_regset,
1085 GET_MODE (x), REGNO (x)))
1086 return true;
1090 return false;
1093 /* Decide whether we can make a sibling call to a function. DECL is the
1094 declaration of the function being targeted by the call and EXP is the
1095 CALL_EXPR representing the call. */
1097 static bool
1098 c6x_function_ok_for_sibcall (tree decl, tree exp)
1100 /* Registers A10, A12, B10 and B12 are available as arguments
1101 register but unfortunately caller saved. This makes functions
1102 needing these registers for arguments not suitable for
1103 sibcalls. */
1104 if (c6x_call_saved_register_used (exp))
1105 return false;
1107 if (!flag_pic)
1108 return true;
1110 if (TARGET_DSBT)
1112 /* When compiling for DSBT, the calling function must be local,
1113 so that when we reload B14 in the sibcall epilogue, it will
1114 not change its value. */
1115 struct cgraph_local_info *this_func;
1117 if (!decl)
1118 /* Not enough information. */
1119 return false;
1121 this_func = cgraph_local_info (current_function_decl);
1122 return this_func->local;
1125 return true;
1128 /* Return true if DECL is known to be linked into section SECTION. */
1130 static bool
1131 c6x_function_in_section_p (tree decl, section *section)
1133 /* We can only be certain about functions defined in the same
1134 compilation unit. */
1135 if (!TREE_STATIC (decl))
1136 return false;
1138 /* Make sure that SYMBOL always binds to the definition in this
1139 compilation unit. */
1140 if (!targetm.binds_local_p (decl))
1141 return false;
1143 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1144 if (!DECL_SECTION_NAME (decl))
1146 /* Make sure that we will not create a unique section for DECL. */
1147 if (flag_function_sections || DECL_ONE_ONLY (decl))
1148 return false;
1151 return function_section (decl) == section;
1154 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1155 as a long call. */
1156 bool
1157 c6x_long_call_p (rtx op)
1159 tree decl;
1161 if (!TARGET_LONG_CALLS)
1162 return false;
1164 decl = SYMBOL_REF_DECL (op);
1166 /* Try to determine whether the symbol is in the same section as the current
1167 function. Be conservative, and only cater for cases in which the
1168 whole of the current function is placed in the same section. */
1169 if (decl != NULL_TREE
1170 && !flag_reorder_blocks_and_partition
1171 && TREE_CODE (decl) == FUNCTION_DECL
1172 && c6x_function_in_section_p (decl, current_function_section ()))
1173 return false;
1175 return true;
1178 /* Emit the sequence for a call. */
1179 void
1180 c6x_expand_call (rtx retval, rtx address, bool sibcall)
1182 rtx callee = XEXP (address, 0);
1183 rtx call_insn;
1185 if (!c6x_call_operand (callee, Pmode))
1187 callee = force_reg (Pmode, callee);
1188 address = change_address (address, Pmode, callee);
1190 call_insn = gen_rtx_CALL (VOIDmode, address, const0_rtx);
1191 if (sibcall)
1193 call_insn = emit_call_insn (call_insn);
1194 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
1195 gen_rtx_REG (Pmode, REG_B3));
1197 else
1199 if (retval == NULL_RTX)
1200 call_insn = emit_call_insn (call_insn);
1201 else
1202 call_insn = emit_call_insn (gen_rtx_SET (GET_MODE (retval), retval,
1203 call_insn));
1205 if (flag_pic)
1206 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
1209 /* Legitimize PIC addresses. If the address is already position-independent,
1210 we return ORIG. Newly generated position-independent addresses go into a
1211 reg. This is REG if nonzero, otherwise we allocate register(s) as
1212 necessary. PICREG is the register holding the pointer to the PIC offset
1213 table. */
1215 static rtx
1216 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
1218 rtx addr = orig;
1219 rtx new_rtx = orig;
1221 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
1223 int unspec = UNSPEC_LOAD_GOT;
1224 rtx tmp;
1226 if (reg == 0)
1228 gcc_assert (can_create_pseudo_p ());
1229 reg = gen_reg_rtx (Pmode);
1231 if (flag_pic == 2)
1233 if (can_create_pseudo_p ())
1234 tmp = gen_reg_rtx (Pmode);
1235 else
1236 tmp = reg;
1237 emit_insn (gen_movsi_gotoff_high (tmp, addr));
1238 emit_insn (gen_movsi_gotoff_lo_sum (tmp, tmp, addr));
1239 emit_insn (gen_load_got_gotoff (reg, picreg, tmp));
1241 else
1243 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
1244 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
1246 emit_move_insn (reg, new_rtx);
1248 if (picreg == pic_offset_table_rtx)
1249 crtl->uses_pic_offset_table = 1;
1250 return reg;
1253 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1255 rtx base;
1257 if (GET_CODE (addr) == CONST)
1259 addr = XEXP (addr, 0);
1260 gcc_assert (GET_CODE (addr) == PLUS);
1263 if (XEXP (addr, 0) == picreg)
1264 return orig;
1266 if (reg == 0)
1268 gcc_assert (can_create_pseudo_p ());
1269 reg = gen_reg_rtx (Pmode);
1272 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
1273 addr = legitimize_pic_address (XEXP (addr, 1),
1274 base == reg ? NULL_RTX : reg,
1275 picreg);
1277 if (GET_CODE (addr) == CONST_INT)
1279 gcc_assert (! reload_in_progress && ! reload_completed);
1280 addr = force_reg (Pmode, addr);
1283 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
1285 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
1286 addr = XEXP (addr, 1);
1289 return gen_rtx_PLUS (Pmode, base, addr);
1292 return new_rtx;
1295 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1296 Returns true if no further code must be generated, false if the caller
1297 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1299 bool
1300 expand_move (rtx *operands, enum machine_mode mode)
1302 rtx dest = operands[0];
1303 rtx op = operands[1];
1305 if ((reload_in_progress | reload_completed) == 0
1306 && GET_CODE (dest) == MEM && GET_CODE (op) != REG)
1307 operands[1] = force_reg (mode, op);
1308 else if (mode == SImode && symbolic_operand (op, SImode))
1310 if (flag_pic)
1312 if (sdata_symbolic_operand (op, SImode))
1314 emit_insn (gen_load_sdata_pic (dest, pic_offset_table_rtx, op));
1315 crtl->uses_pic_offset_table = 1;
1316 return true;
1318 else
1320 rtx temp = (reload_completed || reload_in_progress
1321 ? dest : gen_reg_rtx (Pmode));
1323 operands[1] = legitimize_pic_address (op, temp,
1324 pic_offset_table_rtx);
1327 else if (reload_completed
1328 && !sdata_symbolic_operand (op, SImode))
1330 emit_insn (gen_movsi_high (dest, op));
1331 emit_insn (gen_movsi_lo_sum (dest, dest, op));
1332 return true;
1335 return false;
1338 /* This function is called when we're about to expand an integer compare
1339 operation which performs COMPARISON. It examines the second operand,
1340 and if it is an integer constant that cannot be used directly on the
1341 current machine in a comparison insn, it returns true. */
1342 bool
1343 c6x_force_op_for_comparison_p (enum rtx_code code, rtx op)
1345 if (!CONST_INT_P (op) || satisfies_constraint_Iu4 (op))
1346 return false;
1348 if ((code == EQ || code == LT || code == GT)
1349 && !satisfies_constraint_Is5 (op))
1350 return true;
1351 if ((code == GTU || code == LTU)
1352 && (!TARGET_INSNS_64 || !satisfies_constraint_Iu5 (op)))
1353 return true;
1355 return false;
1358 /* Emit comparison instruction if necessary, returning the expression
1359 that holds the compare result in the proper mode. Return the comparison
1360 that should be used in the jump insn. */
1363 c6x_expand_compare (rtx comparison, enum machine_mode mode)
1365 enum rtx_code code = GET_CODE (comparison);
1366 rtx op0 = XEXP (comparison, 0);
1367 rtx op1 = XEXP (comparison, 1);
1368 rtx cmp;
1369 enum rtx_code jump_code = code;
1370 enum machine_mode op_mode = GET_MODE (op0);
1372 if (op_mode == DImode && (code == NE || code == EQ) && op1 == const0_rtx)
1374 rtx t = gen_reg_rtx (SImode);
1375 emit_insn (gen_iorsi3 (t, gen_lowpart (SImode, op0),
1376 gen_highpart (SImode, op0)));
1377 op_mode = SImode;
1378 cmp = t;
1380 else if (op_mode == DImode)
1382 rtx lo[2], high[2];
1383 rtx cmp1, cmp2;
1385 if (code == NE || code == GEU || code == LEU || code == GE || code == LE)
1387 code = reverse_condition (code);
1388 jump_code = EQ;
1390 else
1391 jump_code = NE;
1393 split_di (&op0, 1, lo, high);
1394 split_di (&op1, 1, lo + 1, high + 1);
1396 if (c6x_force_op_for_comparison_p (code, high[1])
1397 || c6x_force_op_for_comparison_p (EQ, high[1]))
1398 high[1] = force_reg (SImode, high[1]);
1400 cmp1 = gen_reg_rtx (SImode);
1401 cmp2 = gen_reg_rtx (SImode);
1402 emit_insn (gen_rtx_SET (VOIDmode, cmp1,
1403 gen_rtx_fmt_ee (code, SImode, high[0], high[1])));
1404 if (code == EQ)
1406 if (c6x_force_op_for_comparison_p (code, lo[1]))
1407 lo[1] = force_reg (SImode, lo[1]);
1408 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1409 gen_rtx_fmt_ee (code, SImode, lo[0], lo[1])));
1410 emit_insn (gen_andsi3 (cmp1, cmp1, cmp2));
1412 else
1414 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1415 gen_rtx_EQ (SImode, high[0], high[1])));
1416 if (code == GT)
1417 code = GTU;
1418 else if (code == LT)
1419 code = LTU;
1420 if (c6x_force_op_for_comparison_p (code, lo[1]))
1421 lo[1] = force_reg (SImode, lo[1]);
1422 emit_insn (gen_cmpsi_and (cmp2, gen_rtx_fmt_ee (code, SImode,
1423 lo[0], lo[1]),
1424 lo[0], lo[1], cmp2));
1425 emit_insn (gen_iorsi3 (cmp1, cmp1, cmp2));
1427 cmp = cmp1;
1429 else if (TARGET_FP && !flag_finite_math_only
1430 && (op_mode == DFmode || op_mode == SFmode)
1431 && code != EQ && code != NE && code != LT && code != GT
1432 && code != UNLE && code != UNGE)
1434 enum rtx_code code1, code2, code3;
1435 rtx (*fn) (rtx, rtx, rtx, rtx, rtx);
1437 jump_code = NE;
1438 code3 = UNKNOWN;
1439 switch (code)
1441 case UNLT:
1442 case UNGT:
1443 jump_code = EQ;
1444 /* fall through */
1445 case LE:
1446 case GE:
1447 code1 = code == LE || code == UNGT ? LT : GT;
1448 code2 = EQ;
1449 break;
1451 case UNORDERED:
1452 jump_code = EQ;
1453 /* fall through */
1454 case ORDERED:
1455 code3 = EQ;
1456 /* fall through */
1457 case LTGT:
1458 code1 = LT;
1459 code2 = GT;
1460 break;
1462 case UNEQ:
1463 code1 = LT;
1464 code2 = GT;
1465 jump_code = EQ;
1466 break;
1468 default:
1469 gcc_unreachable ();
1472 cmp = gen_reg_rtx (SImode);
1473 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1474 gen_rtx_fmt_ee (code1, SImode, op0, op1)));
1475 fn = op_mode == DFmode ? gen_cmpdf_ior : gen_cmpsf_ior;
1476 emit_insn (fn (cmp, gen_rtx_fmt_ee (code2, SImode, op0, op1),
1477 op0, op1, cmp));
1478 if (code3 != UNKNOWN)
1479 emit_insn (fn (cmp, gen_rtx_fmt_ee (code3, SImode, op0, op1),
1480 op0, op1, cmp));
1482 else if (op_mode == SImode && (code == NE || code == EQ) && op1 == const0_rtx)
1483 cmp = op0;
1484 else
1486 bool is_fp_libfunc;
1487 is_fp_libfunc = !TARGET_FP && (op_mode == DFmode || op_mode == SFmode);
1489 if ((code == NE || code == GEU || code == LEU || code == GE || code == LE)
1490 && !is_fp_libfunc)
1492 code = reverse_condition (code);
1493 jump_code = EQ;
1495 else if (code == UNGE)
1497 code = LT;
1498 jump_code = EQ;
1500 else if (code == UNLE)
1502 code = GT;
1503 jump_code = EQ;
1505 else
1506 jump_code = NE;
1508 if (is_fp_libfunc)
1510 rtx insns;
1511 rtx libfunc;
1512 switch (code)
1514 case EQ:
1515 libfunc = op_mode == DFmode ? eqdf_libfunc : eqsf_libfunc;
1516 break;
1517 case NE:
1518 libfunc = op_mode == DFmode ? nedf_libfunc : nesf_libfunc;
1519 break;
1520 case GT:
1521 libfunc = op_mode == DFmode ? gtdf_libfunc : gtsf_libfunc;
1522 break;
1523 case GE:
1524 libfunc = op_mode == DFmode ? gedf_libfunc : gesf_libfunc;
1525 break;
1526 case LT:
1527 libfunc = op_mode == DFmode ? ltdf_libfunc : ltsf_libfunc;
1528 break;
1529 case LE:
1530 libfunc = op_mode == DFmode ? ledf_libfunc : lesf_libfunc;
1531 break;
1532 default:
1533 gcc_unreachable ();
1535 start_sequence ();
1537 cmp = emit_library_call_value (libfunc, 0, LCT_CONST, SImode, 2,
1538 op0, op_mode, op1, op_mode);
1539 insns = get_insns ();
1540 end_sequence ();
1542 emit_libcall_block (insns, cmp, cmp,
1543 gen_rtx_fmt_ee (code, SImode, op0, op1));
1545 else
1547 cmp = gen_reg_rtx (SImode);
1548 if (c6x_force_op_for_comparison_p (code, op1))
1549 op1 = force_reg (SImode, op1);
1550 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1551 gen_rtx_fmt_ee (code, SImode, op0, op1)));
1555 return gen_rtx_fmt_ee (jump_code, mode, cmp, const0_rtx);
1558 /* Return one word of double-word value OP. HIGH_P is true to select the
1559 high part, false to select the low part. When encountering auto-increment
1560 addressing, we make the assumption that the low part is going to be accessed
1561 first. */
1564 c6x_subword (rtx op, bool high_p)
1566 unsigned int byte;
1567 enum machine_mode mode;
1569 mode = GET_MODE (op);
1570 if (mode == VOIDmode)
1571 mode = DImode;
1573 if (TARGET_BIG_ENDIAN ? !high_p : high_p)
1574 byte = UNITS_PER_WORD;
1575 else
1576 byte = 0;
1578 if (MEM_P (op))
1580 rtx addr = XEXP (op, 0);
1581 if (GET_CODE (addr) == PLUS || REG_P (addr))
1582 return adjust_address (op, word_mode, byte);
1583 /* FIXME: should really support autoincrement addressing for
1584 multi-word modes. */
1585 gcc_unreachable ();
1588 return simplify_gen_subreg (word_mode, op, mode, byte);
1591 /* Split one or more DImode RTL references into pairs of SImode
1592 references. The RTL can be REG, offsettable MEM, integer constant, or
1593 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1594 split and "num" is its length. lo_half and hi_half are output arrays
1595 that parallel "operands". */
1597 void
1598 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1600 while (num--)
1602 rtx op = operands[num];
1604 lo_half[num] = c6x_subword (op, false);
1605 hi_half[num] = c6x_subword (op, true);
1609 /* Return true if VAL is a mask valid for a clr instruction. */
1610 bool
1611 c6x_valid_mask_p (HOST_WIDE_INT val)
1613 int i;
1614 for (i = 0; i < 32; i++)
1615 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1616 break;
1617 for (; i < 32; i++)
1618 if (val & ((unsigned HOST_WIDE_INT)1 << i))
1619 break;
1620 for (; i < 32; i++)
1621 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1622 return false;
1623 return true;
1626 /* Expand a block move for a movmemM pattern. */
1628 bool
1629 c6x_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
1630 rtx expected_align_exp ATTRIBUTE_UNUSED,
1631 rtx expected_size_exp ATTRIBUTE_UNUSED)
1633 unsigned HOST_WIDE_INT align = 1;
1634 unsigned HOST_WIDE_INT src_mem_align, dst_mem_align, min_mem_align;
1635 unsigned HOST_WIDE_INT count = 0, offset = 0;
1636 unsigned int biggest_move = TARGET_STDW ? 8 : 4;
1638 if (CONST_INT_P (align_exp))
1639 align = INTVAL (align_exp);
1641 src_mem_align = MEM_ALIGN (src) / BITS_PER_UNIT;
1642 dst_mem_align = MEM_ALIGN (dst) / BITS_PER_UNIT;
1643 min_mem_align = MIN (src_mem_align, dst_mem_align);
1645 if (min_mem_align > align)
1646 align = min_mem_align / BITS_PER_UNIT;
1647 if (src_mem_align < align)
1648 src_mem_align = align;
1649 if (dst_mem_align < align)
1650 dst_mem_align = align;
1652 if (CONST_INT_P (count_exp))
1653 count = INTVAL (count_exp);
1654 else
1655 return false;
1657 /* Make sure we don't need to care about overflow later on. */
1658 if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
1659 return false;
1661 if (count >= 28 && (count & 3) == 0 && align >= 4)
1663 tree dst_expr = MEM_EXPR (dst);
1664 tree src_expr = MEM_EXPR (src);
1665 rtx fn = TARGET_INSNS_64PLUS ? strasgi64p_libfunc : strasgi_libfunc;
1666 rtx srcreg = force_reg (Pmode, XEXP (src, 0));
1667 rtx dstreg = force_reg (Pmode, XEXP (dst, 0));
1669 if (src_expr)
1670 mark_addressable (src_expr);
1671 if (dst_expr)
1672 mark_addressable (dst_expr);
1673 emit_library_call (fn, LCT_NORMAL, VOIDmode, 3,
1674 dstreg, Pmode, srcreg, Pmode, count_exp, SImode);
1675 return true;
1678 if (biggest_move > align && !TARGET_INSNS_64)
1679 biggest_move = align;
1681 if (count / biggest_move > 7)
1682 return false;
1684 while (count > 0)
1686 rtx reg, reg_lowpart;
1687 enum machine_mode srcmode, dstmode;
1688 unsigned HOST_WIDE_INT src_size, dst_size, src_left;
1689 int shift;
1690 rtx srcmem, dstmem;
1692 while (biggest_move > count)
1693 biggest_move /= 2;
1695 src_size = dst_size = biggest_move;
1696 if (src_size > src_mem_align && src_size == 2)
1697 src_size = 1;
1698 if (dst_size > dst_mem_align && dst_size == 2)
1699 dst_size = 1;
1701 if (dst_size > src_size)
1702 dst_size = src_size;
1704 srcmode = mode_for_size (src_size * BITS_PER_UNIT, MODE_INT, 0);
1705 dstmode = mode_for_size (dst_size * BITS_PER_UNIT, MODE_INT, 0);
1706 if (src_size >= 4)
1707 reg_lowpart = reg = gen_reg_rtx (srcmode);
1708 else
1710 reg = gen_reg_rtx (SImode);
1711 reg_lowpart = gen_lowpart (srcmode, reg);
1714 srcmem = adjust_address (copy_rtx (src), srcmode, offset);
1716 if (src_size > src_mem_align)
1718 enum insn_code icode = (srcmode == SImode ? CODE_FOR_movmisalignsi
1719 : CODE_FOR_movmisaligndi);
1720 emit_insn (GEN_FCN (icode) (reg_lowpart, srcmem));
1722 else
1723 emit_move_insn (reg_lowpart, srcmem);
1725 src_left = src_size;
1726 shift = TARGET_BIG_ENDIAN ? (src_size - dst_size) * BITS_PER_UNIT : 0;
1727 while (src_left > 0)
1729 rtx dstreg = reg_lowpart;
1731 if (src_size > dst_size)
1733 rtx srcword = reg;
1734 int shift_amount = shift & (BITS_PER_WORD - 1);
1735 if (src_size > 4)
1736 srcword = operand_subword_force (srcword, src_left >= 4 ? 0 : 4,
1737 SImode);
1738 if (shift_amount > 0)
1740 dstreg = gen_reg_rtx (SImode);
1741 emit_insn (gen_lshrsi3 (dstreg, srcword,
1742 GEN_INT (shift_amount)));
1744 else
1745 dstreg = srcword;
1746 dstreg = gen_lowpart (dstmode, dstreg);
1749 dstmem = adjust_address (copy_rtx (dst), dstmode, offset);
1750 if (dst_size > dst_mem_align)
1752 enum insn_code icode = (dstmode == SImode ? CODE_FOR_movmisalignsi
1753 : CODE_FOR_movmisaligndi);
1754 emit_insn (GEN_FCN (icode) (dstmem, dstreg));
1756 else
1757 emit_move_insn (dstmem, dstreg);
1759 if (TARGET_BIG_ENDIAN)
1760 shift -= dst_size * BITS_PER_UNIT;
1761 else
1762 shift += dst_size * BITS_PER_UNIT;
1763 offset += dst_size;
1764 src_left -= dst_size;
1766 count -= src_size;
1768 return true;
1771 /* Subroutine of print_address_operand, print a single address offset OFF for
1772 a memory access of mode MEM_MODE, choosing between normal form and scaled
1773 form depending on the type of the insn. Misaligned memory references must
1774 use the scaled form. */
1776 static void
1777 print_address_offset (FILE *file, rtx off, enum machine_mode mem_mode)
1779 rtx pat;
1781 if (c6x_current_insn != NULL_RTX)
1783 pat = PATTERN (c6x_current_insn);
1784 if (GET_CODE (pat) == COND_EXEC)
1785 pat = COND_EXEC_CODE (pat);
1786 if (GET_CODE (pat) == PARALLEL)
1787 pat = XVECEXP (pat, 0, 0);
1789 if (GET_CODE (pat) == SET
1790 && GET_CODE (SET_SRC (pat)) == UNSPEC
1791 && XINT (SET_SRC (pat), 1) == UNSPEC_MISALIGNED_ACCESS)
1793 gcc_assert (CONST_INT_P (off)
1794 && (INTVAL (off) & (GET_MODE_SIZE (mem_mode) - 1)) == 0);
1795 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1796 INTVAL (off) / GET_MODE_SIZE (mem_mode));
1797 return;
1800 fputs ("(", file);
1801 output_address (off);
1802 fputs (")", file);
1805 static bool
1806 c6x_print_operand_punct_valid_p (unsigned char c)
1808 return c == '$' || c == '.' || c == '|';
1811 static void c6x_print_operand (FILE *, rtx, int);
1813 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1815 static void
1816 c6x_print_address_operand (FILE *file, rtx x, enum machine_mode mem_mode)
1818 rtx off;
1819 switch (GET_CODE (x))
1821 case PRE_MODIFY:
1822 case POST_MODIFY:
1823 if (GET_CODE (x) == POST_MODIFY)
1824 output_address (XEXP (x, 0));
1825 off = XEXP (XEXP (x, 1), 1);
1826 if (XEXP (x, 0) == stack_pointer_rtx)
1828 if (GET_CODE (x) == PRE_MODIFY)
1829 gcc_assert (INTVAL (off) > 0);
1830 else
1831 gcc_assert (INTVAL (off) < 0);
1833 if (CONST_INT_P (off) && INTVAL (off) < 0)
1835 fprintf (file, "--");
1836 off = GEN_INT (-INTVAL (off));
1838 else
1839 fprintf (file, "++");
1840 if (GET_CODE (x) == PRE_MODIFY)
1841 output_address (XEXP (x, 0));
1842 print_address_offset (file, off, mem_mode);
1843 break;
1845 case PLUS:
1846 off = XEXP (x, 1);
1847 if (CONST_INT_P (off) && INTVAL (off) < 0)
1849 fprintf (file, "-");
1850 off = GEN_INT (-INTVAL (off));
1852 else
1853 fprintf (file, "+");
1854 output_address (XEXP (x, 0));
1855 print_address_offset (file, off, mem_mode);
1856 break;
1858 case PRE_DEC:
1859 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1860 fprintf (file, "--");
1861 output_address (XEXP (x, 0));
1862 fprintf (file, "[1]");
1863 break;
1864 case PRE_INC:
1865 fprintf (file, "++");
1866 output_address (XEXP (x, 0));
1867 fprintf (file, "[1]");
1868 break;
1869 case POST_INC:
1870 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1871 output_address (XEXP (x, 0));
1872 fprintf (file, "++[1]");
1873 break;
1874 case POST_DEC:
1875 output_address (XEXP (x, 0));
1876 fprintf (file, "--[1]");
1877 break;
1879 case SYMBOL_REF:
1880 case CONST:
1881 case LABEL_REF:
1882 gcc_assert (sdata_symbolic_operand (x, Pmode));
1883 fprintf (file, "+B14(");
1884 output_addr_const (file, x);
1885 fprintf (file, ")");
1886 break;
1888 case UNSPEC:
1889 switch (XINT (x, 1))
1891 case UNSPEC_LOAD_GOT:
1892 fputs ("$GOT(", file);
1893 output_addr_const (file, XVECEXP (x, 0, 0));
1894 fputs (")", file);
1895 break;
1896 case UNSPEC_LOAD_SDATA:
1897 output_addr_const (file, XVECEXP (x, 0, 0));
1898 break;
1899 default:
1900 gcc_unreachable ();
1902 break;
1904 default:
1905 gcc_assert (GET_CODE (x) != MEM);
1906 c6x_print_operand (file, x, 0);
1907 break;
1911 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1912 specifies the functional unit used by INSN. */
1914 char
1915 c6x_get_unit_specifier (rtx insn)
1917 enum attr_units units;
1919 if (insn_info)
1921 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
1922 return c6x_unit_names[unit][0];
1925 units = get_attr_units (insn);
1926 switch (units)
1928 case UNITS_D:
1929 case UNITS_DL:
1930 case UNITS_DS:
1931 case UNITS_DLS:
1932 case UNITS_D_ADDR:
1933 return 'd';
1934 break;
1935 case UNITS_L:
1936 case UNITS_LS:
1937 return 'l';
1938 break;
1939 case UNITS_S:
1940 return 's';
1941 break;
1942 case UNITS_M:
1943 return 'm';
1944 break;
1945 default:
1946 gcc_unreachable ();
1950 /* Prints the unit specifier field. */
1951 static void
1952 c6x_print_unit_specifier_field (FILE *file, rtx insn)
1954 enum attr_units units = get_attr_units (insn);
1955 enum attr_cross cross = get_attr_cross (insn);
1956 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
1957 int half;
1958 char unitspec;
1960 if (units == UNITS_D_ADDR)
1962 enum attr_addr_regfile arf = get_attr_addr_regfile (insn);
1963 int t_half;
1964 gcc_assert (arf != ADDR_REGFILE_UNKNOWN);
1965 half = arf == ADDR_REGFILE_A ? 1 : 2;
1966 t_half = rf == DEST_REGFILE_A ? 1 : 2;
1967 fprintf (file, ".d%dt%d", half, t_half);
1968 return;
1971 if (insn_info)
1973 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
1974 fputs (".", file);
1975 fputs (c6x_unit_names[unit], file);
1976 if (cross == CROSS_Y)
1977 fputs ("x", file);
1978 return;
1981 gcc_assert (rf != DEST_REGFILE_UNKNOWN);
1982 unitspec = c6x_get_unit_specifier (insn);
1983 half = rf == DEST_REGFILE_A ? 1 : 2;
1984 fprintf (file, ".%c%d%s", unitspec, half, cross == CROSS_Y ? "x" : "");
1987 /* Output assembly language output for the address ADDR to FILE. */
1988 static void
1989 c6x_print_operand_address (FILE *file, rtx addr)
1991 c6x_print_address_operand (file, addr, VOIDmode);
1994 /* Print an operand, X, to FILE, with an optional modifier in CODE.
1996 Meaning of CODE:
1997 $ -- print the unit specifier field for the instruction.
1998 . -- print the predicate for the instruction or an emptry string for an
1999 unconditional one.
2000 | -- print "||" if the insn should be issued in parallel with the previous
2001 one.
2003 C -- print an opcode suffix for a reversed condition
2004 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2005 operand
2006 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2007 the operand
2008 J -- print a predicate
2009 j -- like J, but use reverse predicate
2010 k -- treat a CONST_INT as a register number and print it as a register
2011 k -- like k, but print out a doubleword register
2012 n -- print an integer operand, negated
2013 p -- print the low part of a DImode register
2014 P -- print the high part of a DImode register
2015 r -- print the absolute value of an integer operand, shifted right by 1
2016 R -- print the absolute value of an integer operand, shifted right by 2
2017 f -- the first clear bit in an integer operand assumed to be a mask for
2018 a clr instruction
2019 F -- the last clear bit in such a mask
2020 s -- the first set bit in an integer operand assumed to be a mask for
2021 a set instruction
2022 S -- the last set bit in such a mask
2023 U -- print either 1 or 2, depending on the side of the machine used by
2024 the operand */
2026 static void
2027 c6x_print_operand (FILE *file, rtx x, int code)
2029 int i;
2030 HOST_WIDE_INT v;
2031 tree t;
2032 enum machine_mode mode;
2034 if (code == '|')
2036 if (GET_MODE (c6x_current_insn) != TImode)
2037 fputs ("||", file);
2038 return;
2040 if (code == '$')
2042 c6x_print_unit_specifier_field (file, c6x_current_insn);
2043 return;
2046 if (code == '.')
2048 x = current_insn_predicate;
2049 if (x)
2051 unsigned int regno = REGNO (XEXP (x, 0));
2052 fputs ("[", file);
2053 if (GET_CODE (x) == EQ)
2054 fputs ("!", file);
2055 fputs (reg_names [regno], file);
2056 fputs ("]", file);
2058 return;
2061 mode = GET_MODE (x);
2063 switch (code)
2065 case 'C':
2066 case 'c':
2068 enum rtx_code c = GET_CODE (x);
2069 if (code == 'C')
2070 c = swap_condition (c);
2071 fputs (GET_RTX_NAME (c), file);
2073 return;
2075 case 'J':
2076 case 'j':
2078 unsigned int regno = REGNO (XEXP (x, 0));
2079 if ((GET_CODE (x) == EQ) == (code == 'J'))
2080 fputs ("!", file);
2081 fputs (reg_names [regno], file);
2083 return;
2085 case 'k':
2086 gcc_assert (GET_CODE (x) == CONST_INT);
2087 v = INTVAL (x);
2088 fprintf (file, "%s", reg_names[v]);
2089 return;
2090 case 'K':
2091 gcc_assert (GET_CODE (x) == CONST_INT);
2092 v = INTVAL (x);
2093 gcc_assert ((v & 1) == 0);
2094 fprintf (file, "%s:%s", reg_names[v + 1], reg_names[v]);
2095 return;
2097 case 's':
2098 case 'S':
2099 case 'f':
2100 case 'F':
2101 gcc_assert (GET_CODE (x) == CONST_INT);
2102 v = INTVAL (x);
2103 for (i = 0; i < 32; i++)
2105 HOST_WIDE_INT tst = v & 1;
2106 if (((code == 'f' || code == 'F') && !tst)
2107 || ((code == 's' || code == 'S') && tst))
2108 break;
2109 v >>= 1;
2111 if (code == 'f' || code == 's')
2113 fprintf (file, "%d", i);
2114 return;
2116 for (;i < 32; i++)
2118 HOST_WIDE_INT tst = v & 1;
2119 if ((code == 'F' && tst) || (code == 'S' && !tst))
2120 break;
2121 v >>= 1;
2123 fprintf (file, "%d", i - 1);
2124 return;
2126 case 'n':
2127 gcc_assert (GET_CODE (x) == CONST_INT);
2128 output_addr_const (file, GEN_INT (-INTVAL (x)));
2129 return;
2131 case 'r':
2132 gcc_assert (GET_CODE (x) == CONST_INT);
2133 v = INTVAL (x);
2134 if (v < 0)
2135 v = -v;
2136 output_addr_const (file, GEN_INT (v >> 1));
2137 return;
2139 case 'R':
2140 gcc_assert (GET_CODE (x) == CONST_INT);
2141 v = INTVAL (x);
2142 if (v < 0)
2143 v = -v;
2144 output_addr_const (file, GEN_INT (v >> 2));
2145 return;
2147 case 'd':
2148 gcc_assert (GET_CODE (x) == CONST_INT);
2149 v = INTVAL (x);
2150 fputs (v == 2 ? "h" : v == 4 ? "w" : "d", file);
2151 return;
2153 case 'p':
2154 case 'P':
2155 gcc_assert (GET_CODE (x) == REG);
2156 v = REGNO (x);
2157 if (code == 'P')
2158 v++;
2159 fputs (reg_names[v], file);
2160 return;
2162 case 'D':
2163 v = 0;
2164 if (GET_CODE (x) == CONST)
2166 x = XEXP (x, 0);
2167 gcc_assert (GET_CODE (x) == PLUS);
2168 gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
2169 v = INTVAL (XEXP (x, 1));
2170 x = XEXP (x, 0);
2173 gcc_assert (GET_CODE (x) == SYMBOL_REF);
2175 t = SYMBOL_REF_DECL (x);
2176 if (DECL_P (t))
2177 v |= DECL_ALIGN_UNIT (t);
2178 else
2179 v |= TYPE_ALIGN_UNIT (TREE_TYPE (t));
2180 if (v & 1)
2181 fputs ("b", file);
2182 else if (v & 2)
2183 fputs ("h", file);
2184 else
2185 fputs ("w", file);
2186 return;
2188 case 'U':
2189 if (MEM_P (x))
2191 x = XEXP (x, 0);
2192 if (GET_CODE (x) == PLUS
2193 || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
2194 x = XEXP (x, 0);
2195 if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
2197 gcc_assert (sdata_symbolic_operand (x, Pmode));
2198 fputs ("2", file);
2199 return;
2202 gcc_assert (REG_P (x));
2203 if (A_REGNO_P (REGNO (x)))
2204 fputs ("1", file);
2205 if (B_REGNO_P (REGNO (x)))
2206 fputs ("2", file);
2207 return;
2209 default:
2210 switch (GET_CODE (x))
2212 case REG:
2213 if (GET_MODE_SIZE (mode) == 8)
2214 fprintf (file, "%s:%s", reg_names[REGNO (x) + 1],
2215 reg_names[REGNO (x)]);
2216 else
2217 fprintf (file, "%s", reg_names[REGNO (x)]);
2218 break;
2220 case MEM:
2221 fputc ('*', file);
2222 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
2223 c6x_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
2224 break;
2226 case SYMBOL_REF:
2227 fputc ('(', file);
2228 output_addr_const (file, x);
2229 fputc (')', file);
2230 break;
2232 case CONST_INT:
2233 output_addr_const (file, x);
2234 break;
2236 case CONST_DOUBLE:
2237 output_operand_lossage ("invalid const_double operand");
2238 break;
2240 default:
2241 output_addr_const (file, x);
2246 /* Return TRUE if OP is a valid memory address with a base register of
2247 class C. If SMALL_OFFSET is true, we disallow memory references which would
2248 require a long offset with B14/B15. */
2250 bool
2251 c6x_mem_operand (rtx op, enum reg_class c, bool small_offset)
2253 enum machine_mode mode = GET_MODE (op);
2254 rtx base = XEXP (op, 0);
2255 switch (GET_CODE (base))
2257 case REG:
2258 break;
2259 case PLUS:
2260 if (small_offset
2261 && (XEXP (base, 0) == stack_pointer_rtx
2262 || XEXP (base, 0) == pic_offset_table_rtx))
2264 if (!c6x_legitimate_address_p_1 (mode, base, true, true))
2265 return false;
2268 /* fall through */
2269 case PRE_INC:
2270 case PRE_DEC:
2271 case PRE_MODIFY:
2272 case POST_INC:
2273 case POST_DEC:
2274 case POST_MODIFY:
2275 base = XEXP (base, 0);
2276 break;
2278 case CONST:
2279 case LABEL_REF:
2280 case SYMBOL_REF:
2281 gcc_assert (sdata_symbolic_operand (base, Pmode));
2282 return !small_offset && c == B_REGS;
2284 default:
2285 return false;
2287 return TEST_HARD_REG_BIT (reg_class_contents[ (int) (c)], REGNO (base));
2290 /* Returns true if X is a valid address for use in a memory reference
2291 of mode MODE. If STRICT is true, we do not allow pseudo registers
2292 in the address. NO_LARGE_OFFSET is true if we are examining an
2293 address for use in a load or store misaligned instruction, or
2294 recursively examining an operand inside a PRE/POST_MODIFY. */
2296 bool
2297 c6x_legitimate_address_p_1 (enum machine_mode mode, rtx x, bool strict,
2298 bool no_large_offset)
2300 int size, size1;
2301 HOST_WIDE_INT off;
2302 enum rtx_code code = GET_CODE (x);
2304 switch (code)
2306 case PRE_MODIFY:
2307 case POST_MODIFY:
2308 /* We can't split these into word-sized pieces yet. */
2309 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2310 return false;
2311 if (GET_CODE (XEXP (x, 1)) != PLUS)
2312 return false;
2313 if (!c6x_legitimate_address_p_1 (mode, XEXP (x, 1), strict, true))
2314 return false;
2315 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
2316 return false;
2318 /* fall through */
2319 case PRE_INC:
2320 case PRE_DEC:
2321 case POST_INC:
2322 case POST_DEC:
2323 /* We can't split these into word-sized pieces yet. */
2324 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2325 return false;
2326 x = XEXP (x, 0);
2327 if (!REG_P (x))
2328 return false;
2330 /* fall through */
2331 case REG:
2332 if (strict)
2333 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x));
2334 else
2335 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x));
2337 case PLUS:
2338 if (!REG_P (XEXP (x, 0))
2339 || !c6x_legitimate_address_p_1 (mode, XEXP (x, 0), strict, false))
2340 return false;
2341 /* We cannot ensure currently that both registers end up in the
2342 same register file. */
2343 if (REG_P (XEXP (x, 1)))
2344 return false;
2346 if (mode == BLKmode)
2347 size = 4;
2348 else if (mode == VOIDmode)
2349 /* ??? This can happen during ivopts. */
2350 size = 1;
2351 else
2352 size = GET_MODE_SIZE (mode);
2354 if (flag_pic
2355 && GET_CODE (XEXP (x, 1)) == UNSPEC
2356 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_SDATA
2357 && XEXP (x, 0) == pic_offset_table_rtx
2358 && sdata_symbolic_operand (XVECEXP (XEXP (x, 1), 0, 0), SImode))
2359 return !no_large_offset && size <= 4;
2360 if (flag_pic == 1
2361 && mode == Pmode
2362 && GET_CODE (XEXP (x, 1)) == UNSPEC
2363 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_GOT
2364 && XEXP (x, 0) == pic_offset_table_rtx
2365 && (GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == SYMBOL_REF
2366 || GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == LABEL_REF))
2367 return !no_large_offset;
2368 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2369 return false;
2371 off = INTVAL (XEXP (x, 1));
2373 /* If the machine does not have doubleword load/stores, we'll use
2374 word size accesses. */
2375 size1 = size;
2376 if (size == 2 * UNITS_PER_WORD && !TARGET_STDW)
2377 size = UNITS_PER_WORD;
2379 if (((HOST_WIDE_INT)size1 - 1) & off)
2380 return false;
2381 off /= size;
2382 if (off > -32 && off < (size1 == size ? 32 : 28))
2383 return true;
2384 if (no_large_offset || code != PLUS || XEXP (x, 0) != stack_pointer_rtx
2385 || size1 > UNITS_PER_WORD)
2386 return false;
2387 return off >= 0 && off < 32768;
2389 case CONST:
2390 case SYMBOL_REF:
2391 case LABEL_REF:
2392 return (!no_large_offset
2393 /* With -fpic, we must wrap it in an unspec to show the B14
2394 dependency. */
2395 && !flag_pic
2396 && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
2397 && sdata_symbolic_operand (x, Pmode));
2399 default:
2400 return false;
2404 static bool
2405 c6x_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
2407 return c6x_legitimate_address_p_1 (mode, x, strict, false);
2410 static bool
2411 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
2412 rtx x ATTRIBUTE_UNUSED)
2414 return true;
2417 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2418 static reg_class_t
2419 c6x_preferred_rename_class (reg_class_t cl)
2421 if (cl == A_REGS)
2422 return NONPREDICATE_A_REGS;
2423 if (cl == B_REGS)
2424 return NONPREDICATE_B_REGS;
2425 if (cl == ALL_REGS || cl == GENERAL_REGS)
2426 return NONPREDICATE_REGS;
2427 return NO_REGS;
2430 /* Implements FINAL_PRESCAN_INSN. */
2431 void
2432 c6x_final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
2433 int noperands ATTRIBUTE_UNUSED)
2435 c6x_current_insn = insn;
2438 /* A structure to describe the stack layout of a function. The layout is
2439 as follows:
2441 [saved frame pointer (or possibly padding0)]
2442 --> incoming stack pointer, new hard frame pointer
2443 [saved call-used regs]
2444 [optional padding1]
2445 --> soft frame pointer
2446 [frame]
2447 [outgoing arguments]
2448 [optional padding2]
2450 The structure members are laid out in this order. */
2452 struct c6x_frame
2454 int padding0;
2455 /* Number of registers to save. */
2456 int nregs;
2457 int padding1;
2458 HOST_WIDE_INT frame;
2459 int outgoing_arguments_size;
2460 int padding2;
2462 HOST_WIDE_INT to_allocate;
2463 /* The offsets relative to the incoming stack pointer (which
2464 becomes HARD_FRAME_POINTER). */
2465 HOST_WIDE_INT frame_pointer_offset;
2466 HOST_WIDE_INT b3_offset;
2468 /* True if we should call push_rts/pop_rts to save and restore
2469 registers. */
2470 bool push_rts;
2473 /* Return true if we need to save and modify the PIC register in the
2474 prologue. */
2476 static bool
2477 must_reload_pic_reg_p (void)
2479 struct cgraph_local_info *i = NULL;
2481 if (!TARGET_DSBT)
2482 return false;
2484 i = cgraph_local_info (current_function_decl);
2486 if ((crtl->uses_pic_offset_table || !current_function_is_leaf) && !i->local)
2487 return true;
2488 return false;
2491 /* Return 1 if we need to save REGNO. */
2492 static int
2493 c6x_save_reg (unsigned int regno)
2495 return ((df_regs_ever_live_p (regno)
2496 && !call_used_regs[regno]
2497 && !fixed_regs[regno])
2498 || (regno == RETURN_ADDR_REGNO
2499 && (df_regs_ever_live_p (regno)
2500 || !current_function_is_leaf))
2501 || (regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ()));
2504 /* Examine the number of regs NREGS we've determined we must save.
2505 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2506 prologue and epilogue. */
2508 static bool
2509 use_push_rts_p (int nregs)
2511 if (TARGET_INSNS_64PLUS && optimize_function_for_size_p (cfun)
2512 && !cfun->machine->contains_sibcall
2513 && !cfun->returns_struct
2514 && !TARGET_LONG_CALLS
2515 && nregs >= 6 && !frame_pointer_needed)
2516 return true;
2517 return false;
2520 /* Return number of saved general prupose registers. */
2523 c6x_nsaved_regs (void)
2525 int nregs = 0;
2526 int regno;
2528 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
2529 if (c6x_save_reg (regno))
2530 nregs++;
2531 return nregs;
2534 /* The safe debug order mandated by the ABI. */
2535 static unsigned reg_save_order[] =
2537 REG_A10, REG_A11, REG_A12, REG_A13,
2538 REG_A14, REG_B3,
2539 REG_B10, REG_B11, REG_B12, REG_B13,
2540 REG_B14, REG_A15
2543 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2545 /* Compute the layout of the stack frame and store it in FRAME. */
2547 static void
2548 c6x_compute_frame_layout (struct c6x_frame *frame)
2550 HOST_WIDE_INT size = get_frame_size ();
2551 HOST_WIDE_INT offset;
2552 int nregs;
2554 /* We use the four bytes which are technically inside the caller's frame,
2555 usually to save the frame pointer. */
2556 offset = -4;
2557 frame->padding0 = 0;
2558 nregs = c6x_nsaved_regs ();
2559 frame->push_rts = false;
2560 frame->b3_offset = 0;
2561 if (use_push_rts_p (nregs))
2563 frame->push_rts = true;
2564 frame->b3_offset = (TARGET_BIG_ENDIAN ? -12 : -13) * 4;
2565 nregs = 14;
2567 else if (c6x_save_reg (REG_B3))
2569 int idx;
2570 for (idx = N_SAVE_ORDER - 1; reg_save_order[idx] != REG_B3; idx--)
2572 if (c6x_save_reg (reg_save_order[idx]))
2573 frame->b3_offset -= 4;
2576 frame->nregs = nregs;
2578 if (size == 0 && nregs == 0)
2580 frame->padding0 = 4;
2581 frame->padding1 = frame->padding2 = 0;
2582 frame->frame_pointer_offset = frame->to_allocate = 0;
2583 frame->outgoing_arguments_size = 0;
2584 return;
2587 if (!frame->push_rts)
2588 offset += frame->nregs * 4;
2590 if (offset == 0 && size == 0 && crtl->outgoing_args_size == 0
2591 && !current_function_is_leaf)
2592 /* Don't use the bottom of the caller's frame if we have no
2593 allocation of our own and call other functions. */
2594 frame->padding0 = frame->padding1 = 4;
2595 else if (offset & 4)
2596 frame->padding1 = 4;
2597 else
2598 frame->padding1 = 0;
2600 offset += frame->padding0 + frame->padding1;
2601 frame->frame_pointer_offset = offset;
2602 offset += size;
2604 frame->outgoing_arguments_size = crtl->outgoing_args_size;
2605 offset += frame->outgoing_arguments_size;
2607 if ((offset & 4) == 0)
2608 frame->padding2 = 8;
2609 else
2610 frame->padding2 = 4;
2611 frame->to_allocate = offset + frame->padding2;
2614 /* Return the offset between two registers, one to be eliminated, and the other
2615 its replacement, at the start of a routine. */
2617 HOST_WIDE_INT
2618 c6x_initial_elimination_offset (int from, int to)
2620 struct c6x_frame frame;
2621 c6x_compute_frame_layout (&frame);
2623 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
2624 return 0;
2625 else if (from == FRAME_POINTER_REGNUM
2626 && to == HARD_FRAME_POINTER_REGNUM)
2627 return -frame.frame_pointer_offset;
2628 else
2630 gcc_assert (to == STACK_POINTER_REGNUM);
2632 if (from == ARG_POINTER_REGNUM)
2633 return frame.to_allocate + (frame.push_rts ? 56 : 0);
2635 gcc_assert (from == FRAME_POINTER_REGNUM);
2636 return frame.to_allocate - frame.frame_pointer_offset;
2640 /* Given FROM and TO register numbers, say whether this elimination is
2641 allowed. Frame pointer elimination is automatically handled. */
2643 static bool
2644 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
2646 if (to == STACK_POINTER_REGNUM)
2647 return !frame_pointer_needed;
2648 return true;
2651 /* Emit insns to increment the stack pointer by OFFSET. If
2652 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2653 Does nothing if the offset is zero. */
2655 static void
2656 emit_add_sp_const (HOST_WIDE_INT offset, bool frame_related_p)
2658 rtx to_add = GEN_INT (offset);
2659 rtx orig_to_add = to_add;
2660 rtx insn;
2662 if (offset == 0)
2663 return;
2665 if (offset < -32768 || offset > 32767)
2667 rtx reg = gen_rtx_REG (SImode, REG_A0);
2668 rtx low = GEN_INT (trunc_int_for_mode (offset, HImode));
2670 insn = emit_insn (gen_movsi_high (reg, low));
2671 if (frame_related_p)
2672 RTX_FRAME_RELATED_P (insn) = 1;
2673 insn = emit_insn (gen_movsi_lo_sum (reg, reg, to_add));
2674 if (frame_related_p)
2675 RTX_FRAME_RELATED_P (insn) = 1;
2676 to_add = reg;
2678 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2679 to_add));
2680 if (frame_related_p)
2682 if (REG_P (to_add))
2683 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2684 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
2685 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2686 orig_to_add)));
2688 RTX_FRAME_RELATED_P (insn) = 1;
2692 /* Prologue and epilogue. */
2693 void
2694 c6x_expand_prologue (void)
2696 struct c6x_frame frame;
2697 rtx insn, mem;
2698 int nsaved = 0;
2699 HOST_WIDE_INT initial_offset, off, added_already;
2701 c6x_compute_frame_layout (&frame);
2703 if (flag_stack_usage_info)
2704 current_function_static_stack_size = frame.to_allocate;
2706 initial_offset = -frame.to_allocate;
2707 if (frame.push_rts)
2709 emit_insn (gen_push_rts ());
2710 nsaved = frame.nregs;
2713 /* If the offsets would be too large for the memory references we will
2714 create to save registers, do the stack allocation in two parts.
2715 Ensure by subtracting 8 that we don't store to the word pointed to
2716 by the stack pointer. */
2717 if (initial_offset < -32768)
2718 initial_offset = -frame.frame_pointer_offset - 8;
2720 if (frame.to_allocate > 0)
2721 gcc_assert (initial_offset != 0);
2723 off = -initial_offset + 4 - frame.padding0;
2725 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2727 added_already = 0;
2728 if (frame_pointer_needed)
2730 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2731 /* We go through some contortions here to both follow the ABI's
2732 recommendation that FP == incoming SP, and to avoid writing or
2733 reading the word pointed to by the stack pointer. */
2734 rtx addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
2735 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2736 GEN_INT (-8)));
2737 insn = emit_move_insn (gen_frame_mem (Pmode, addr), fp_reg);
2738 RTX_FRAME_RELATED_P (insn) = 1;
2739 nsaved++;
2740 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, stack_pointer_rtx,
2741 GEN_INT (8)));
2742 RTX_FRAME_RELATED_P (insn) = 1;
2743 off -= 4;
2744 added_already = -8;
2747 emit_add_sp_const (initial_offset - added_already, true);
2749 if (nsaved < frame.nregs)
2751 unsigned i;
2753 for (i = 0; i < N_SAVE_ORDER; i++)
2755 int idx = N_SAVE_ORDER - i - 1;
2756 unsigned regno = reg_save_order[idx];
2757 rtx reg;
2758 enum machine_mode save_mode = SImode;
2760 if (regno == REG_A15 && frame_pointer_needed)
2761 /* Already saved. */
2762 continue;
2763 if (!c6x_save_reg (regno))
2764 continue;
2766 if (TARGET_STDW && (off & 4) == 0 && off <= 256
2767 && (regno & 1) == 1
2768 && i + 1 < N_SAVE_ORDER
2769 && reg_save_order[idx - 1] == regno - 1
2770 && c6x_save_reg (regno - 1))
2772 save_mode = DImode;
2773 regno--;
2774 i++;
2776 reg = gen_rtx_REG (save_mode, regno);
2777 off -= GET_MODE_SIZE (save_mode);
2779 insn = emit_move_insn (adjust_address (mem, save_mode, off),
2780 reg);
2781 RTX_FRAME_RELATED_P (insn) = 1;
2783 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2786 gcc_assert (nsaved == frame.nregs);
2787 emit_add_sp_const (-frame.to_allocate - initial_offset, true);
2788 if (must_reload_pic_reg_p ())
2790 if (dsbt_decl == NULL)
2792 tree t;
2794 t = build_index_type (integer_one_node);
2795 t = build_array_type (integer_type_node, t);
2796 t = build_decl (BUILTINS_LOCATION, VAR_DECL,
2797 get_identifier ("__c6xabi_DSBT_BASE"), t);
2798 DECL_ARTIFICIAL (t) = 1;
2799 DECL_IGNORED_P (t) = 1;
2800 DECL_EXTERNAL (t) = 1;
2801 TREE_STATIC (t) = 1;
2802 TREE_PUBLIC (t) = 1;
2803 TREE_USED (t) = 1;
2805 dsbt_decl = t;
2807 emit_insn (gen_setup_dsbt (pic_offset_table_rtx,
2808 XEXP (DECL_RTL (dsbt_decl), 0)));
2812 void
2813 c6x_expand_epilogue (bool sibcall)
2815 unsigned i;
2816 struct c6x_frame frame;
2817 rtx mem;
2818 HOST_WIDE_INT off;
2819 int nsaved = 0;
2821 c6x_compute_frame_layout (&frame);
2823 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2825 /* Insert a dummy set/use of the stack pointer. This creates a
2826 scheduler barrier between the prologue saves and epilogue restores. */
2827 emit_insn (gen_epilogue_barrier (stack_pointer_rtx, stack_pointer_rtx));
2829 /* If the offsets would be too large for the memory references we will
2830 create to restore registers, do a preliminary stack adjustment here. */
2831 off = frame.to_allocate - frame.frame_pointer_offset + frame.padding1;
2832 if (frame.push_rts)
2834 nsaved = frame.nregs;
2836 else
2838 if (frame.to_allocate > 32768)
2840 /* Don't add the entire offset so that we leave an unused word
2841 above the stack pointer. */
2842 emit_add_sp_const ((off - 16) & ~7, false);
2843 off &= 7;
2844 off += 16;
2846 for (i = 0; i < N_SAVE_ORDER; i++)
2848 unsigned regno = reg_save_order[i];
2849 rtx reg;
2850 enum machine_mode save_mode = SImode;
2852 if (!c6x_save_reg (regno))
2853 continue;
2854 if (regno == REG_A15 && frame_pointer_needed)
2855 continue;
2857 if (TARGET_STDW && (off & 4) == 0 && off < 256
2858 && (regno & 1) == 0
2859 && i + 1 < N_SAVE_ORDER
2860 && reg_save_order[i + 1] == regno + 1
2861 && c6x_save_reg (regno + 1))
2863 save_mode = DImode;
2864 i++;
2866 reg = gen_rtx_REG (save_mode, regno);
2868 emit_move_insn (reg, adjust_address (mem, save_mode, off));
2870 off += GET_MODE_SIZE (save_mode);
2871 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2874 if (!frame_pointer_needed)
2875 emit_add_sp_const (off + frame.padding0 - 4, false);
2876 else
2878 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2879 rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
2880 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2881 GEN_INT (8)));
2882 emit_insn (gen_addsi3 (stack_pointer_rtx, hard_frame_pointer_rtx,
2883 GEN_INT (-8)));
2884 emit_move_insn (fp_reg, gen_frame_mem (Pmode, addr));
2885 nsaved++;
2887 gcc_assert (nsaved == frame.nregs);
2888 if (!sibcall)
2890 if (frame.push_rts)
2891 emit_jump_insn (gen_pop_rts ());
2892 else
2893 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
2894 RETURN_ADDR_REGNO)));
2898 /* Return the value of the return address for the frame COUNT steps up
2899 from the current frame, after the prologue.
2900 We punt for everything but the current frame by returning const0_rtx. */
2903 c6x_return_addr_rtx (int count)
2905 if (count != 0)
2906 return const0_rtx;
2908 return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNO);
2911 /* Return true iff TYPE is one of the shadow types. */
2912 static bool
2913 shadow_type_p (enum attr_type type)
2915 return (type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW
2916 || type == TYPE_MULT_SHADOW);
2919 /* Return true iff INSN is a shadow pattern. */
2920 static bool
2921 shadow_p (rtx insn)
2923 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2924 return false;
2925 return shadow_type_p (get_attr_type (insn));
2928 /* Return true iff INSN is a shadow or blockage pattern. */
2929 static bool
2930 shadow_or_blockage_p (rtx insn)
2932 enum attr_type type;
2933 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2934 return false;
2935 type = get_attr_type (insn);
2936 return shadow_type_p (type) || type == TYPE_BLOCKAGE;
2939 /* Translate UNITS into a bitmask of units we can reserve for this
2940 insn. */
2941 static int
2942 get_reservation_flags (enum attr_units units)
2944 switch (units)
2946 case UNITS_D:
2947 case UNITS_D_ADDR:
2948 return RESERVATION_FLAG_D;
2949 case UNITS_L:
2950 return RESERVATION_FLAG_L;
2951 case UNITS_S:
2952 return RESERVATION_FLAG_S;
2953 case UNITS_M:
2954 return RESERVATION_FLAG_M;
2955 case UNITS_LS:
2956 return RESERVATION_FLAG_LS;
2957 case UNITS_DL:
2958 return RESERVATION_FLAG_DL;
2959 case UNITS_DS:
2960 return RESERVATION_FLAG_DS;
2961 case UNITS_DLS:
2962 return RESERVATION_FLAG_DLS;
2963 default:
2964 return 0;
2968 /* Compute the side of the machine used by INSN, which reserves UNITS.
2969 This must match the reservations in the scheduling description. */
2970 static int
2971 get_insn_side (rtx insn, enum attr_units units)
2973 if (units == UNITS_D_ADDR)
2974 return (get_attr_addr_regfile (insn) == ADDR_REGFILE_A ? 0 : 1);
2975 else
2977 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
2978 if (rf == DEST_REGFILE_ANY)
2979 return get_attr_type (insn) == TYPE_BRANCH ? 0 : 1;
2980 else
2981 return rf == DEST_REGFILE_A ? 0 : 1;
2985 /* After scheduling, walk the insns between HEAD and END and assign unit
2986 reservations. */
2987 static void
2988 assign_reservations (rtx head, rtx end)
2990 rtx insn;
2991 for (insn = head; insn != NEXT_INSN (end); insn = NEXT_INSN (insn))
2993 rtx within;
2994 int pass;
2995 int rsrv[2];
2996 int rsrv_count[2][4];
2998 if (GET_MODE (insn) != TImode)
2999 continue;
3001 rsrv[0] = rsrv[1] = 0;
3002 memset (rsrv_count, 0, sizeof rsrv_count);
3004 /* Walk through the insns that occur in the same cycle. We use multiple
3005 passes to assign units, assigning for insns with the most specific
3006 requirements first. */
3007 for (pass = 0; pass < 4; pass++)
3008 for (within = insn;
3009 (within != NEXT_INSN (end)
3010 && (within == insn || GET_MODE (within) != TImode));
3011 within = NEXT_INSN (within))
3013 int this_rsrv, side;
3014 int icode;
3015 enum attr_units units;
3016 int j;
3018 if (!NONDEBUG_INSN_P (within))
3019 continue;
3020 icode = recog_memoized (within);
3021 if (icode < 0)
3022 continue;
3023 units = get_attr_units (within);
3024 this_rsrv = get_reservation_flags (units);
3025 if (this_rsrv == 0)
3026 continue;
3027 side = get_insn_side (within, units);
3029 if ((this_rsrv & (this_rsrv - 1)) == 0)
3031 int t = exact_log2 (this_rsrv) + side * 4;
3032 rsrv[side] |= this_rsrv;
3033 INSN_INFO_ENTRY (INSN_UID (within)).reservation = t;
3034 continue;
3037 if (pass == 1)
3039 for (j = 0; j < 4; j++)
3040 if (this_rsrv & (1 << j))
3041 rsrv_count[side][j]++;
3042 continue;
3044 if ((pass == 2 && this_rsrv != RESERVATION_FLAG_DLS)
3045 || (pass == 3 && this_rsrv == RESERVATION_FLAG_DLS))
3047 int best = -1, best_cost = INT_MAX;
3048 for (j = 0; j < 4; j++)
3049 if ((this_rsrv & (1 << j))
3050 && !(rsrv[side] & (1 << j))
3051 && rsrv_count[side][j] < best_cost)
3053 best_cost = rsrv_count[side][j];
3054 best = j;
3056 gcc_assert (best != -1);
3057 rsrv[side] |= 1 << best;
3058 for (j = 0; j < 4; j++)
3059 if ((this_rsrv & (1 << j)) && j != best)
3060 rsrv_count[side][j]--;
3062 INSN_INFO_ENTRY (INSN_UID (within)).reservation
3063 = best + side * 4;
3069 /* Backend scheduling state. */
3070 typedef struct c6x_sched_context
3072 /* The current scheduler clock, saved in the sched_reorder hook. */
3073 int curr_sched_clock;
3075 /* Number of insns issued so far in this cycle. */
3076 int issued_this_cycle;
3078 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3079 theoretical maximum for number of jumps in flight is 12: 2 every
3080 cycle, with a latency of 6 cycles each. This is a circular
3081 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3082 jumps have a higher index. This array should be accessed through
3083 the jump_cycle function. */
3084 int jump_cycles[12];
3085 int jump_cycle_index;
3087 /* In parallel with jump_cycles, this array records the opposite of
3088 the condition used in each pending jump. This is used to
3089 predicate insns that are scheduled in the jump's delay slots. If
3090 this is NULL_RTX no such predication happens. */
3091 rtx jump_cond[12];
3093 /* Similar to the jump_cycles mechanism, but here we take into
3094 account all insns with delay slots, to avoid scheduling asms into
3095 the delay slots. */
3096 int delays_finished_at;
3098 /* The following variable value is the last issued insn. */
3099 rtx last_scheduled_insn;
3101 int reg_n_accesses[FIRST_PSEUDO_REGISTER];
3102 int reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3103 int reg_set_in_cycle[FIRST_PSEUDO_REGISTER];
3105 int tmp_reg_n_accesses[FIRST_PSEUDO_REGISTER];
3106 int tmp_reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3107 } *c6x_sched_context_t;
3109 /* The current scheduling state. */
3110 static struct c6x_sched_context ss;
3112 /* Set when we discover while processing an insn that it would lead to too
3113 many accesses of the same register. */
3114 static bool reg_access_stall;
3116 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3117 so the caller does not specifically have to test for it. */
3118 static int
3119 get_jump_cycle (int n)
3121 if (n >= 12)
3122 return 0;
3123 n += ss.jump_cycle_index;
3124 if (n >= 12)
3125 n -= 12;
3126 return ss.jump_cycles[n];
3129 /* Look up the jump condition with index N. */
3130 static rtx
3131 get_jump_cond (int n)
3133 if (n >= 12)
3134 return NULL_RTX;
3135 n += ss.jump_cycle_index;
3136 if (n >= 12)
3137 n -= 12;
3138 return ss.jump_cond[n];
3141 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3142 has delay slots beyond CLOCK_VAR, return -1. */
3143 static int
3144 first_jump_index (int clock_var)
3146 int retval = -1;
3147 int n = 0;
3148 for (;;)
3150 int t = get_jump_cycle (n);
3151 if (t <= clock_var)
3152 break;
3153 retval = n;
3154 n++;
3156 return retval;
3159 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3160 and has the opposite condition of COND. */
3161 static void
3162 record_jump (int cycle, rtx cond)
3164 if (ss.jump_cycle_index == 0)
3165 ss.jump_cycle_index = 11;
3166 else
3167 ss.jump_cycle_index--;
3168 ss.jump_cycles[ss.jump_cycle_index] = cycle;
3169 ss.jump_cond[ss.jump_cycle_index] = cond;
3172 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3173 new_conditions. */
3174 static void
3175 insn_set_clock (rtx insn, int cycle)
3177 unsigned uid = INSN_UID (insn);
3179 if (uid >= INSN_INFO_LENGTH)
3180 VEC_safe_grow (c6x_sched_insn_info, heap, insn_info, uid * 5 / 4 + 10);
3182 INSN_INFO_ENTRY (uid).clock = cycle;
3183 INSN_INFO_ENTRY (uid).new_cond = NULL;
3184 INSN_INFO_ENTRY (uid).ebb_start = false;
3187 /* Return the clock cycle we set for the insn with uid UID. */
3188 static int
3189 insn_uid_get_clock (int uid)
3191 return INSN_INFO_ENTRY (uid).clock;
3194 /* Return the clock cycle we set for INSN. */
3195 static int
3196 insn_get_clock (rtx insn)
3198 return insn_uid_get_clock (INSN_UID (insn));
3201 /* Examine INSN, and if it is a conditional jump of any kind, return
3202 the opposite of the condition in which it branches. Otherwise,
3203 return NULL_RTX. */
3204 static rtx
3205 condjump_opposite_condition (rtx insn)
3207 rtx pat = PATTERN (insn);
3208 int icode = INSN_CODE (insn);
3209 rtx x = NULL;
3211 if (icode == CODE_FOR_br_true || icode == CODE_FOR_br_false)
3213 x = XEXP (SET_SRC (pat), 0);
3214 if (icode == CODE_FOR_br_false)
3215 return x;
3217 if (GET_CODE (pat) == COND_EXEC)
3219 rtx t = COND_EXEC_CODE (pat);
3220 if ((GET_CODE (t) == PARALLEL
3221 && GET_CODE (XVECEXP (t, 0, 0)) == RETURN)
3222 || (GET_CODE (t) == UNSPEC && XINT (t, 1) == UNSPEC_REAL_JUMP)
3223 || (GET_CODE (t) == SET && SET_DEST (t) == pc_rtx))
3224 x = COND_EXEC_TEST (pat);
3227 if (x != NULL_RTX)
3229 enum rtx_code code = GET_CODE (x);
3230 x = gen_rtx_fmt_ee (code == EQ ? NE : EQ,
3231 GET_MODE (x), XEXP (x, 0),
3232 XEXP (x, 1));
3234 return x;
3237 /* Return true iff COND1 and COND2 are exactly opposite conditions
3238 one of them NE and the other EQ. */
3239 static bool
3240 conditions_opposite_p (rtx cond1, rtx cond2)
3242 return (rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
3243 && rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1))
3244 && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)));
3247 /* Return true if we can add a predicate COND to INSN, or if INSN
3248 already has that predicate. If DOIT is true, also perform the
3249 modification. */
3250 static bool
3251 predicate_insn (rtx insn, rtx cond, bool doit)
3253 int icode;
3254 if (cond == NULL_RTX)
3256 gcc_assert (!doit);
3257 return false;
3260 if (get_attr_predicable (insn) == PREDICABLE_YES
3261 && GET_CODE (PATTERN (insn)) != COND_EXEC)
3263 if (doit)
3265 rtx newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3266 PATTERN (insn) = newpat;
3267 INSN_CODE (insn) = -1;
3269 return true;
3271 if (GET_CODE (PATTERN (insn)) == COND_EXEC
3272 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn)), cond))
3273 return true;
3274 icode = INSN_CODE (insn);
3275 if (icode == CODE_FOR_real_jump
3276 || icode == CODE_FOR_jump
3277 || icode == CODE_FOR_indirect_jump)
3279 rtx pat = PATTERN (insn);
3280 rtx dest = (icode == CODE_FOR_real_jump ? XVECEXP (pat, 0, 0)
3281 : icode == CODE_FOR_jump ? XEXP (SET_SRC (pat), 0)
3282 : SET_SRC (pat));
3283 if (doit)
3285 rtx newpat;
3286 if (REG_P (dest))
3287 newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3288 else
3289 newpat = gen_br_true (cond, XEXP (cond, 0), dest);
3290 PATTERN (insn) = newpat;
3291 INSN_CODE (insn) = -1;
3293 return true;
3295 if (INSN_CODE (insn) == CODE_FOR_br_true)
3297 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3298 return rtx_equal_p (br_cond, cond);
3300 if (INSN_CODE (insn) == CODE_FOR_br_false)
3302 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3303 return conditions_opposite_p (br_cond, cond);
3305 return false;
3308 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3309 static void
3310 init_sched_state (c6x_sched_context_t sc)
3312 sc->last_scheduled_insn = NULL_RTX;
3313 sc->issued_this_cycle = 0;
3314 memset (sc->jump_cycles, 0, sizeof sc->jump_cycles);
3315 memset (sc->jump_cond, 0, sizeof sc->jump_cond);
3316 sc->jump_cycle_index = 0;
3317 sc->delays_finished_at = 0;
3318 sc->curr_sched_clock = 0;
3320 memset (sc->reg_n_accesses, 0, sizeof sc->reg_n_accesses);
3321 memset (sc->reg_n_xaccesses, 0, sizeof sc->reg_n_xaccesses);
3322 memset (sc->reg_set_in_cycle, 0, sizeof sc->reg_set_in_cycle);
3325 /* Allocate store for new scheduling context. */
3326 static void *
3327 c6x_alloc_sched_context (void)
3329 return xmalloc (sizeof (struct c6x_sched_context));
3332 /* If CLEAN_P is true then initializes _SC with clean data,
3333 and from the global context otherwise. */
3334 static void
3335 c6x_init_sched_context (void *_sc, bool clean_p)
3337 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3339 if (clean_p)
3341 init_sched_state (sc);
3343 else
3344 *sc = ss;
3347 /* Sets the global scheduling context to the one pointed to by _SC. */
3348 static void
3349 c6x_set_sched_context (void *_sc)
3351 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3353 gcc_assert (sc != NULL);
3354 ss = *sc;
3357 /* Free _SC. */
3358 static void
3359 c6x_free_sched_context (void *_sc)
3361 free (_sc);
3364 /* Provide information about speculation capabilities, and set the
3365 DO_BACKTRACKING flag. */
3366 static void
3367 c6x_set_sched_flags (spec_info_t spec_info)
3369 unsigned int *flags = &(current_sched_info->flags);
3371 if (*flags & SCHED_EBB)
3373 *flags |= DO_BACKTRACKING;
3376 spec_info->mask = 0;
3379 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3381 static int
3382 c6x_issue_rate (void)
3384 return 8;
3387 /* We're beginning a new block. Initialize data structures as necessary. */
3389 static void
3390 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED,
3391 int sched_verbose ATTRIBUTE_UNUSED,
3392 int max_ready ATTRIBUTE_UNUSED)
3394 init_sched_state (&ss);
3397 static void
3398 c6x_mark_regno_read (int regno, bool cross)
3400 int t = ++ss.tmp_reg_n_accesses[regno];
3402 if (t > 4)
3403 reg_access_stall = true;
3405 if (cross)
3407 int set_cycle = ss.reg_set_in_cycle[regno];
3408 /* This must be done in this way rather than by tweaking things in
3409 adjust_cost, since the stall occurs even for insns with opposite
3410 predicates, and the scheduler may not even see a dependency. */
3411 if (set_cycle > 0 && set_cycle == ss.curr_sched_clock)
3412 reg_access_stall = true;
3413 /* This doesn't quite do anything yet as we're only modeling one
3414 x unit. */
3415 ++ss.tmp_reg_n_xaccesses[regno];
3419 /* Note that REG is read in the insn being examined. If CROSS, it
3420 means the access is through a cross path. Update the temporary reg
3421 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
3422 in the current cycle. */
3424 static void
3425 c6x_mark_reg_read (rtx reg, bool cross)
3427 unsigned regno = REGNO (reg);
3428 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
3430 while (nregs-- > 0)
3431 c6x_mark_regno_read (regno + nregs, cross);
3434 /* Note that register REG is written in cycle CYCLES. */
3436 static void
3437 c6x_mark_reg_written (rtx reg, int cycles)
3439 unsigned regno = REGNO (reg);
3440 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
3442 while (nregs-- > 0)
3443 ss.reg_set_in_cycle[regno + nregs] = cycles;
3446 /* Update the register state information for an instruction whose
3447 body is X. Return true if the instruction has to be delayed until the
3448 next cycle. */
3450 static bool
3451 c6x_registers_update (rtx insn)
3453 enum attr_cross cross;
3454 enum attr_dest_regfile destrf;
3455 int i, nops;
3456 rtx x;
3458 if (!reload_completed || recog_memoized (insn) < 0)
3459 return false;
3461 reg_access_stall = false;
3462 memcpy (ss.tmp_reg_n_accesses, ss.reg_n_accesses,
3463 sizeof ss.tmp_reg_n_accesses);
3464 memcpy (ss.tmp_reg_n_xaccesses, ss.reg_n_xaccesses,
3465 sizeof ss.tmp_reg_n_xaccesses);
3467 extract_insn (insn);
3469 cross = get_attr_cross (insn);
3470 destrf = get_attr_dest_regfile (insn);
3472 nops = recog_data.n_operands;
3473 x = PATTERN (insn);
3474 if (GET_CODE (x) == COND_EXEC)
3476 c6x_mark_reg_read (XEXP (XEXP (x, 0), 0), false);
3477 nops -= 2;
3480 for (i = 0; i < nops; i++)
3482 rtx op = recog_data.operand[i];
3483 if (recog_data.operand_type[i] == OP_OUT)
3484 continue;
3485 if (REG_P (op))
3487 bool this_cross = cross;
3488 if (destrf == DEST_REGFILE_A && A_REGNO_P (REGNO (op)))
3489 this_cross = false;
3490 if (destrf == DEST_REGFILE_B && B_REGNO_P (REGNO (op)))
3491 this_cross = false;
3492 c6x_mark_reg_read (op, this_cross);
3494 else if (MEM_P (op))
3496 op = XEXP (op, 0);
3497 switch (GET_CODE (op))
3499 case POST_INC:
3500 case PRE_INC:
3501 case POST_DEC:
3502 case PRE_DEC:
3503 op = XEXP (op, 0);
3504 /* fall through */
3505 case REG:
3506 c6x_mark_reg_read (op, false);
3507 break;
3508 case POST_MODIFY:
3509 case PRE_MODIFY:
3510 op = XEXP (op, 1);
3511 gcc_assert (GET_CODE (op) == PLUS);
3512 /* fall through */
3513 case PLUS:
3514 c6x_mark_reg_read (XEXP (op, 0), false);
3515 if (REG_P (XEXP (op, 1)))
3516 c6x_mark_reg_read (XEXP (op, 1), false);
3517 break;
3518 case SYMBOL_REF:
3519 case LABEL_REF:
3520 case CONST:
3521 c6x_mark_regno_read (REG_B14, false);
3522 break;
3523 default:
3524 gcc_unreachable ();
3527 else if (!CONSTANT_P (op) && strlen (recog_data.constraints[i]) > 0)
3528 gcc_unreachable ();
3530 return reg_access_stall;
3533 /* Helper function for the TARGET_SCHED_REORDER and
3534 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
3535 in the current cycle, move it down in the ready list and return the
3536 number of non-unsafe insns. */
3538 static int
3539 c6x_sched_reorder_1 (rtx *ready, int *pn_ready, int clock_var)
3541 int n_ready = *pn_ready;
3542 rtx *e_ready = ready + n_ready;
3543 rtx *insnp;
3544 int first_jump;
3546 /* Keep track of conflicts due to a limit number of register accesses,
3547 and due to stalls incurred by too early accesses of registers using
3548 cross paths. */
3550 for (insnp = ready; insnp < e_ready; insnp++)
3552 rtx insn = *insnp;
3553 int icode = recog_memoized (insn);
3554 bool is_asm = (icode < 0
3555 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
3556 || asm_noperands (PATTERN (insn)) >= 0));
3557 bool no_parallel = (is_asm
3558 || (icode >= 0
3559 && get_attr_type (insn) == TYPE_ATOMIC));
3561 /* We delay asm insns until all delay slots are exhausted. We can't
3562 accurately tell how many cycles an asm takes, and the main scheduling
3563 code always assumes at least 1 cycle, which may be wrong. */
3564 if ((no_parallel
3565 && (ss.issued_this_cycle > 0 || clock_var < ss.delays_finished_at))
3566 || c6x_registers_update (insn))
3568 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3569 *ready = insn;
3570 n_ready--;
3571 ready++;
3573 else if (shadow_p (insn))
3575 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3576 *ready = insn;
3580 /* Ensure that no other jump is scheduled in jump delay slots, since
3581 it would put the machine into the wrong state. Also, we must
3582 avoid scheduling insns that have a latency longer than the
3583 remaining jump delay slots, as the code at the jump destination
3584 won't be prepared for it.
3586 However, we can relax this condition somewhat. The rest of the
3587 scheduler will automatically avoid scheduling an insn on which
3588 the jump shadow depends so late that its side effect happens
3589 after the jump. This means that if we see an insn with a longer
3590 latency here, it can safely be scheduled if we can ensure that it
3591 has a predicate opposite of the previous jump: the side effect
3592 will happen in what we think of as the same basic block. In
3593 c6x_variable_issue, we will record the necessary predicate in
3594 new_conditions, and after scheduling is finished, we will modify
3595 the insn.
3597 Special care must be taken whenever there is more than one jump
3598 in flight. */
3600 first_jump = first_jump_index (clock_var);
3601 if (first_jump != -1)
3603 int first_cycle = get_jump_cycle (first_jump);
3604 rtx first_cond = get_jump_cond (first_jump);
3605 int second_cycle = 0;
3607 if (first_jump > 0)
3608 second_cycle = get_jump_cycle (first_jump - 1);
3610 for (insnp = ready; insnp < e_ready; insnp++)
3612 rtx insn = *insnp;
3613 int icode = recog_memoized (insn);
3614 bool is_asm = (icode < 0
3615 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
3616 || asm_noperands (PATTERN (insn)) >= 0));
3617 int this_cycles;
3618 enum attr_type type;
3620 gcc_assert (!is_asm);
3621 if (icode < 0)
3622 continue;
3623 this_cycles = get_attr_cycles (insn);
3624 type = get_attr_type (insn);
3625 /* Treat branches specially; there is also a hazard if two jumps
3626 end at the same cycle. */
3627 if (type == TYPE_BRANCH || type == TYPE_CALL)
3628 this_cycles++;
3629 if (clock_var + this_cycles <= first_cycle)
3630 continue;
3631 if ((first_jump > 0 && clock_var + this_cycles > second_cycle)
3632 || !predicate_insn (insn, first_cond, false))
3634 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3635 *ready = insn;
3636 n_ready--;
3637 ready++;
3642 return n_ready;
3645 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
3646 for later and clear the register access information for the new
3647 cycle. We also move asm statements out of the way if they would be
3648 scheduled in a delay slot. */
3650 static int
3651 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
3652 int sched_verbose ATTRIBUTE_UNUSED,
3653 rtx *ready ATTRIBUTE_UNUSED,
3654 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
3656 ss.curr_sched_clock = clock_var;
3657 ss.issued_this_cycle = 0;
3658 memset (ss.reg_n_accesses, 0, sizeof ss.reg_n_accesses);
3659 memset (ss.reg_n_xaccesses, 0, sizeof ss.reg_n_xaccesses);
3661 if (ready == NULL)
3662 return 0;
3664 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
3667 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
3668 cycle for every insn. */
3670 static int
3671 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
3672 int sched_verbose ATTRIBUTE_UNUSED,
3673 rtx *ready ATTRIBUTE_UNUSED,
3674 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
3676 /* FIXME: the assembler rejects labels inside an execute packet.
3677 This can occur if prologue insns are scheduled in parallel with
3678 others, so we avoid this here. Also make sure that nothing is
3679 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
3680 if (RTX_FRAME_RELATED_P (ss.last_scheduled_insn)
3681 || JUMP_P (ss.last_scheduled_insn)
3682 || (recog_memoized (ss.last_scheduled_insn) >= 0
3683 && get_attr_type (ss.last_scheduled_insn) == TYPE_ATOMIC))
3685 int n_ready = *pn_ready;
3686 rtx *e_ready = ready + n_ready;
3687 rtx *insnp;
3689 for (insnp = ready; insnp < e_ready; insnp++)
3691 rtx insn = *insnp;
3692 if (!shadow_p (insn))
3694 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3695 *ready = insn;
3696 n_ready--;
3697 ready++;
3700 return n_ready;
3703 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
3706 /* Subroutine of maybe_clobber_cond, called through note_stores. */
3708 static void
3709 clobber_cond_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data1)
3711 rtx *cond = (rtx *)data1;
3712 if (*cond != NULL_RTX && reg_overlap_mentioned_p (x, *cond))
3713 *cond = NULL_RTX;
3716 /* Examine INSN, and if it destroys the conditions have recorded for
3717 any of the jumps in flight, clear that condition so that we don't
3718 predicate any more insns. CLOCK_VAR helps us limit the search to
3719 only those jumps which are still in flight. */
3721 static void
3722 maybe_clobber_cond (rtx insn, int clock_var)
3724 int n, idx;
3725 idx = ss.jump_cycle_index;
3726 for (n = 0; n < 12; n++, idx++)
3728 rtx cond, link;
3729 int cycle;
3731 if (idx >= 12)
3732 idx -= 12;
3733 cycle = ss.jump_cycles[idx];
3734 if (cycle <= clock_var)
3735 return;
3737 cond = ss.jump_cond[idx];
3738 if (cond == NULL_RTX)
3739 continue;
3741 if (CALL_P (insn))
3743 ss.jump_cond[idx] = NULL_RTX;
3744 continue;
3747 note_stores (PATTERN (insn), clobber_cond_1, ss.jump_cond + idx);
3748 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
3749 if (REG_NOTE_KIND (link) == REG_INC)
3750 clobber_cond_1 (XEXP (link, 0), NULL_RTX, ss.jump_cond + idx);
3754 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
3755 issue INSN. Return the number of insns left on the ready queue
3756 that can be issued this cycle.
3757 We use this hook to record clock cycles and reservations for every insn. */
3759 static int
3760 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
3761 int sched_verbose ATTRIBUTE_UNUSED,
3762 rtx insn, int can_issue_more ATTRIBUTE_UNUSED)
3764 ss.last_scheduled_insn = insn;
3765 if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
3766 ss.issued_this_cycle++;
3767 if (insn_info)
3769 int curr_clock = ss.curr_sched_clock;
3770 int uid = INSN_UID (insn);
3771 int icode = recog_memoized (insn);
3772 rtx first_cond;
3773 int first, first_cycle;
3775 insn_set_clock (insn, curr_clock);
3776 INSN_INFO_ENTRY (uid).ebb_start
3777 = curr_clock == 0 && ss.issued_this_cycle == 1;
3779 first = first_jump_index (ss.curr_sched_clock);
3780 if (first == -1)
3782 first_cycle = 0;
3783 first_cond = NULL_RTX;
3785 else
3787 first_cycle = get_jump_cycle (first);
3788 first_cond = get_jump_cond (first);
3790 if (icode >= 0
3791 && first_cycle > curr_clock
3792 && first_cond != NULL_RTX
3793 && (curr_clock + get_attr_cycles (insn) > first_cycle
3794 || get_attr_type (insn) == TYPE_BRANCH
3795 || get_attr_type (insn) == TYPE_CALL))
3796 INSN_INFO_ENTRY (uid).new_cond = first_cond;
3798 maybe_clobber_cond (insn, curr_clock);
3800 if (icode >= 0)
3802 int i, cycles;
3804 c6x_registers_update (insn);
3805 memcpy (ss.reg_n_accesses, ss.tmp_reg_n_accesses,
3806 sizeof ss.reg_n_accesses);
3807 memcpy (ss.reg_n_xaccesses, ss.tmp_reg_n_accesses,
3808 sizeof ss.reg_n_xaccesses);
3810 cycles = get_attr_cycles (insn);
3811 if (ss.delays_finished_at < ss.curr_sched_clock + cycles)
3812 ss.delays_finished_at = ss.curr_sched_clock + cycles;
3813 if (get_attr_type (insn) == TYPE_BRANCH
3814 || get_attr_type (insn) == TYPE_CALL)
3816 rtx opposite = condjump_opposite_condition (insn);
3817 record_jump (ss.curr_sched_clock + cycles, opposite);
3820 /* Mark the cycles in which the destination registers are written.
3821 This is used for calculating stalls when using cross units. */
3822 extract_insn (insn);
3823 /* Cross-path stalls don't apply to results of load insns. */
3824 if (get_attr_type (insn) == TYPE_LOAD
3825 || get_attr_type (insn) == TYPE_LOADN
3826 || get_attr_type (insn) == TYPE_LOAD_SHADOW)
3827 cycles--;
3828 for (i = 0; i < recog_data.n_operands; i++)
3830 rtx op = recog_data.operand[i];
3831 if (MEM_P (op))
3833 rtx addr = XEXP (op, 0);
3834 if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
3835 c6x_mark_reg_written (XEXP (addr, 0),
3836 insn_uid_get_clock (uid) + 1);
3838 if (recog_data.operand_type[i] != OP_IN
3839 && REG_P (op))
3841 c6x_mark_reg_written (op,
3842 insn_uid_get_clock (uid) + cycles);
3847 return can_issue_more;
3850 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
3851 anti- and output dependencies. */
3853 static int
3854 c6x_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3856 enum attr_type insn_type = TYPE_UNKNOWN, dep_insn_type = TYPE_UNKNOWN;
3857 int dep_insn_code_number, insn_code_number;
3858 int shadow_bonus = 0;
3859 enum reg_note kind;
3860 dep_insn_code_number = recog_memoized (dep_insn);
3861 insn_code_number = recog_memoized (insn);
3863 if (dep_insn_code_number >= 0)
3864 dep_insn_type = get_attr_type (dep_insn);
3866 if (insn_code_number >= 0)
3867 insn_type = get_attr_type (insn);
3869 kind = REG_NOTE_KIND (link);
3870 if (kind == 0)
3872 /* If we have a dependency on a load, and it's not for the result of
3873 the load, it must be for an autoincrement. Reduce the cost in that
3874 case. */
3875 if (dep_insn_type == TYPE_LOAD)
3877 rtx set = PATTERN (dep_insn);
3878 if (GET_CODE (set) == COND_EXEC)
3879 set = COND_EXEC_CODE (set);
3880 if (GET_CODE (set) == UNSPEC)
3881 cost = 1;
3882 else
3884 gcc_assert (GET_CODE (set) == SET);
3885 if (!reg_overlap_mentioned_p (SET_DEST (set), PATTERN (insn)))
3886 cost = 1;
3891 /* A jump shadow needs to have its latency decreased by one. Conceptually,
3892 it occurs in between two cycles, but we schedule it at the end of the
3893 first cycle. */
3894 if (shadow_type_p (insn_type))
3895 shadow_bonus = 1;
3897 /* Anti and output dependencies usually have zero cost, but we want
3898 to insert a stall after a jump, and after certain floating point
3899 insns that take more than one cycle to read their inputs. In the
3900 future, we should try to find a better algorithm for scheduling
3901 jumps. */
3902 if (kind != 0)
3904 /* We can get anti-dependencies against shadow insns. Treat these
3905 like output dependencies, so that the insn is entirely finished
3906 before the branch takes place. */
3907 if (kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW)
3908 kind = REG_DEP_OUTPUT;
3909 switch (dep_insn_type)
3911 case TYPE_CALLP:
3912 return 1;
3913 case TYPE_BRANCH:
3914 case TYPE_CALL:
3915 if (get_attr_has_shadow (dep_insn) == HAS_SHADOW_Y)
3916 /* This is a real_jump/real_call insn. These don't have
3917 outputs, and ensuring the validity of scheduling things
3918 in the delay slot is the job of
3919 c6x_sched_reorder_1. */
3920 return 0;
3921 /* Unsplit calls can happen - e.g. for divide insns. */
3922 return 6;
3923 case TYPE_LOAD:
3924 case TYPE_LOADN:
3925 case TYPE_INTDP:
3926 if (kind == REG_DEP_OUTPUT)
3927 return 5 - shadow_bonus;
3928 return 0;
3929 case TYPE_MPY4:
3930 case TYPE_FP4:
3931 if (kind == REG_DEP_OUTPUT)
3932 return 4 - shadow_bonus;
3933 return 0;
3934 case TYPE_MPY2:
3935 if (kind == REG_DEP_OUTPUT)
3936 return 2 - shadow_bonus;
3937 return 0;
3938 case TYPE_CMPDP:
3939 if (kind == REG_DEP_OUTPUT)
3940 return 2 - shadow_bonus;
3941 return 2;
3942 case TYPE_ADDDP:
3943 case TYPE_MPYSPDP:
3944 if (kind == REG_DEP_OUTPUT)
3945 return 7 - shadow_bonus;
3946 return 2;
3947 case TYPE_MPYSP2DP:
3948 if (kind == REG_DEP_OUTPUT)
3949 return 5 - shadow_bonus;
3950 return 2;
3951 case TYPE_MPYI:
3952 if (kind == REG_DEP_OUTPUT)
3953 return 9 - shadow_bonus;
3954 return 4;
3955 case TYPE_MPYID:
3956 case TYPE_MPYDP:
3957 if (kind == REG_DEP_OUTPUT)
3958 return 10 - shadow_bonus;
3959 return 4;
3961 default:
3962 if (insn_type == TYPE_SPKERNEL)
3963 return 0;
3964 if (kind == REG_DEP_OUTPUT)
3965 return 1 - shadow_bonus;
3967 return 0;
3971 return cost - shadow_bonus;
3974 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
3975 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
3976 first in the original stream. */
3978 static void
3979 gen_one_bundle (rtx *slot, int n_filled, int real_first)
3981 rtx bundle;
3982 rtx t;
3983 int i;
3985 bundle = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec_v (n_filled, slot));
3986 bundle = make_insn_raw (bundle);
3987 BLOCK_FOR_INSN (bundle) = BLOCK_FOR_INSN (slot[0]);
3988 INSN_LOCATOR (bundle) = INSN_LOCATOR (slot[0]);
3989 PREV_INSN (bundle) = PREV_INSN (slot[real_first]);
3991 t = NULL_RTX;
3993 for (i = 0; i < n_filled; i++)
3995 rtx insn = slot[i];
3996 remove_insn (insn);
3997 PREV_INSN (insn) = t ? t : PREV_INSN (bundle);
3998 if (t != NULL_RTX)
3999 NEXT_INSN (t) = insn;
4000 t = insn;
4001 if (i > 0)
4002 INSN_LOCATOR (slot[i]) = INSN_LOCATOR (bundle);
4005 NEXT_INSN (bundle) = NEXT_INSN (PREV_INSN (bundle));
4006 NEXT_INSN (t) = NEXT_INSN (bundle);
4007 NEXT_INSN (PREV_INSN (bundle)) = bundle;
4008 PREV_INSN (NEXT_INSN (bundle)) = bundle;
4011 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4012 try to insert labels in the middle. */
4014 static void
4015 c6x_gen_bundles (void)
4017 basic_block bb;
4018 rtx insn, next, last_call;
4020 FOR_EACH_BB (bb)
4022 rtx insn, next;
4023 /* The machine is eight insns wide. We can have up to six shadow
4024 insns, plus an extra slot for merging the jump shadow. */
4025 rtx slot[15];
4026 int n_filled = 0;
4027 int first_slot = 0;
4029 for (insn = BB_HEAD (bb);; insn = next)
4031 int at_end;
4032 rtx delete_this = NULL_RTX;
4034 if (NONDEBUG_INSN_P (insn))
4036 /* Put calls at the start of the sequence. */
4037 if (CALL_P (insn))
4039 first_slot++;
4040 if (n_filled)
4042 memmove (&slot[1], &slot[0],
4043 n_filled * sizeof (slot[0]));
4045 if (!shadow_p (insn))
4047 PUT_MODE (insn, TImode);
4048 if (n_filled)
4049 PUT_MODE (slot[1], VOIDmode);
4051 n_filled++;
4052 slot[0] = insn;
4054 else
4056 slot[n_filled++] = insn;
4060 next = NEXT_INSN (insn);
4061 while (next && insn != BB_END (bb)
4062 && !(NONDEBUG_INSN_P (next)
4063 && GET_CODE (PATTERN (next)) != USE
4064 && GET_CODE (PATTERN (next)) != CLOBBER))
4066 insn = next;
4067 next = NEXT_INSN (insn);
4070 at_end = insn == BB_END (bb);
4071 if (delete_this == NULL_RTX
4072 && (at_end || (GET_MODE (next) == TImode
4073 && !(shadow_p (next) && CALL_P (next)))))
4075 if (n_filled >= 2)
4076 gen_one_bundle (slot, n_filled, first_slot);
4078 n_filled = 0;
4079 first_slot = 0;
4081 if (at_end)
4082 break;
4085 /* Bundling, and emitting nops, can separate
4086 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4087 that up here. */
4088 last_call = NULL_RTX;
4089 for (insn = get_insns (); insn; insn = next)
4091 next = NEXT_INSN (insn);
4092 if (CALL_P (insn)
4093 || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE
4094 && CALL_P (XVECEXP (PATTERN (insn), 0, 0))))
4095 last_call = insn;
4096 if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION)
4097 continue;
4098 if (NEXT_INSN (last_call) == insn)
4099 continue;
4100 NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
4101 PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
4102 PREV_INSN (insn) = last_call;
4103 NEXT_INSN (insn) = NEXT_INSN (last_call);
4104 PREV_INSN (NEXT_INSN (insn)) = insn;
4105 NEXT_INSN (PREV_INSN (insn)) = insn;
4106 last_call = insn;
4110 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4112 static rtx
4113 emit_nop_after (int cycles, rtx after)
4115 rtx insn;
4117 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4118 operation. We don't need the extra NOP since in this case, the hardware
4119 will automatically insert the required stall. */
4120 if (cycles == 10)
4121 cycles--;
4123 gcc_assert (cycles < 10);
4125 insn = emit_insn_after (gen_nop_count (GEN_INT (cycles)), after);
4126 PUT_MODE (insn, TImode);
4128 return insn;
4131 /* Determine whether INSN is a call that needs to have a return label
4132 placed. */
4134 static bool
4135 returning_call_p (rtx insn)
4137 if (CALL_P (insn))
4138 return (!SIBLING_CALL_P (insn)
4139 && get_attr_type (insn) != TYPE_CALLP
4140 && get_attr_type (insn) != TYPE_SHADOW);
4141 if (recog_memoized (insn) < 0)
4142 return false;
4143 if (get_attr_type (insn) == TYPE_CALL)
4144 return true;
4145 return false;
4148 /* Determine whether INSN's pattern can be converted to use callp. */
4149 static bool
4150 can_use_callp (rtx insn)
4152 int icode = recog_memoized (insn);
4153 if (!TARGET_INSNS_64PLUS
4154 || icode < 0
4155 || GET_CODE (PATTERN (insn)) == COND_EXEC)
4156 return false;
4158 return ((icode == CODE_FOR_real_call
4159 || icode == CODE_FOR_call_internal
4160 || icode == CODE_FOR_call_value_internal)
4161 && get_attr_dest_regfile (insn) == DEST_REGFILE_ANY);
4164 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4165 static void
4166 convert_to_callp (rtx insn)
4168 rtx lab;
4169 extract_insn (insn);
4170 if (GET_CODE (PATTERN (insn)) == SET)
4172 rtx dest = recog_data.operand[0];
4173 lab = recog_data.operand[1];
4174 PATTERN (insn) = gen_callp_value (dest, lab);
4175 INSN_CODE (insn) = CODE_FOR_callp_value;
4177 else
4179 lab = recog_data.operand[0];
4180 PATTERN (insn) = gen_callp (lab);
4181 INSN_CODE (insn) = CODE_FOR_callp;
4185 /* Scan forwards from INSN until we find the next insn that has mode TImode
4186 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4187 Return it if we find such an insn, NULL_RTX otherwise. */
4188 static rtx
4189 find_next_cycle_insn (rtx insn, int clock)
4191 rtx t = insn;
4192 if (GET_MODE (t) == TImode)
4193 t = next_real_insn (t);
4194 while (t && GET_MODE (t) != TImode)
4195 t = next_real_insn (t);
4197 if (t && insn_get_clock (t) == clock)
4198 return t;
4199 return NULL_RTX;
4202 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4203 around PAT. Return PAT either unchanged or modified in this
4204 way. */
4205 static rtx
4206 duplicate_cond (rtx pat, rtx cond_insn)
4208 rtx cond_pat = PATTERN (cond_insn);
4209 if (GET_CODE (cond_pat) == COND_EXEC)
4210 pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (cond_pat)),
4211 pat);
4212 return pat;
4215 /* Walk forward from INSN to find the last insn that issues in the same clock
4216 cycle. */
4217 static rtx
4218 find_last_same_clock (rtx insn)
4220 rtx retval = insn;
4221 rtx t = next_real_insn (insn);
4223 while (t && GET_MODE (t) != TImode)
4225 if (!DEBUG_INSN_P (t) && recog_memoized (t) >= 0)
4226 retval = t;
4227 t = next_real_insn (t);
4229 return retval;
4232 /* For every call insn in the function, emit code to load the return
4233 address. For each call we create a return label and store it in
4234 CALL_LABELS. If are not scheduling, we emit the labels here,
4235 otherwise the caller will do it later.
4236 This function is called after final insn scheduling, but before creating
4237 the SEQUENCEs that represent execute packets. */
4239 static void
4240 reorg_split_calls (rtx *call_labels)
4242 unsigned int reservation_mask = 0;
4243 rtx insn = get_insns ();
4244 gcc_assert (GET_CODE (insn) == NOTE);
4245 insn = next_real_insn (insn);
4246 while (insn)
4248 int uid;
4249 rtx next = next_real_insn (insn);
4251 if (DEBUG_INSN_P (insn))
4252 goto done;
4254 if (GET_MODE (insn) == TImode)
4255 reservation_mask = 0;
4256 uid = INSN_UID (insn);
4257 if (c6x_flag_schedule_insns2 && recog_memoized (insn) >= 0)
4258 reservation_mask |= 1 << INSN_INFO_ENTRY (uid).reservation;
4260 if (returning_call_p (insn))
4262 rtx label = gen_label_rtx ();
4263 rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
4264 rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
4266 LABEL_NUSES (label) = 2;
4267 if (!c6x_flag_schedule_insns2)
4269 if (can_use_callp (insn))
4270 convert_to_callp (insn);
4271 else
4273 rtx t;
4274 rtx slot[4];
4275 emit_label_after (label, insn);
4277 /* Bundle the call and its delay slots into a single
4278 SEQUENCE. While these do not issue in parallel
4279 we need to group them into a single EH region. */
4280 slot[0] = insn;
4281 PUT_MODE (insn, TImode);
4282 if (TARGET_INSNS_64)
4284 t = gen_addkpc (reg, labelref, GEN_INT (4));
4285 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4286 insn);
4287 PUT_MODE (slot[1], TImode);
4288 gen_one_bundle (slot, 2, 0);
4290 else
4292 slot[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4293 insn);
4294 PUT_MODE (slot[3], TImode);
4295 t = gen_movsi_lo_sum (reg, reg, labelref);
4296 slot[2] = emit_insn_after (duplicate_cond (t, insn),
4297 insn);
4298 PUT_MODE (slot[2], TImode);
4299 t = gen_movsi_high (reg, labelref);
4300 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4301 insn);
4302 PUT_MODE (slot[1], TImode);
4303 gen_one_bundle (slot, 4, 0);
4307 else
4309 /* If we scheduled, we reserved the .S2 unit for one or two
4310 cycles after the call. Emit the insns in these slots,
4311 unless it's possible to create a CALLP insn.
4312 Note that this works because the dependencies ensure that
4313 no insn setting/using B3 is scheduled in the delay slots of
4314 a call. */
4315 int this_clock = insn_get_clock (insn);
4316 rtx last_same_clock;
4317 rtx after1;
4319 call_labels[INSN_UID (insn)] = label;
4321 last_same_clock = find_last_same_clock (insn);
4323 if (can_use_callp (insn))
4325 /* Find the first insn of the next execute packet. If it
4326 is outside the branch delay slots of this call, we may
4327 use a CALLP insn. */
4328 rtx next_cycle_start = next_nonnote_nondebug_insn (last_same_clock);
4330 if (CALL_P (next_cycle_start)
4331 && (insn_get_clock (next_cycle_start) == this_clock + 5))
4333 convert_to_callp (next_cycle_start);
4334 insn_set_clock (next_cycle_start, this_clock);
4335 if (GET_MODE (insn) == TImode)
4337 rtx new_cycle_first = NEXT_INSN (insn);
4338 while (!NONDEBUG_INSN_P (new_cycle_first)
4339 || GET_CODE (PATTERN (new_cycle_first)) == USE
4340 || GET_CODE (PATTERN (new_cycle_first)) == CLOBBER)
4341 new_cycle_first = NEXT_INSN (new_cycle_first);
4342 PUT_MODE (new_cycle_first, TImode);
4343 if (new_cycle_first != next_cycle_start)
4344 PUT_MODE (next_cycle_start, VOIDmode);
4345 INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
4346 = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
4348 else
4349 PUT_MODE (next_cycle_start, VOIDmode);
4350 delete_insn (insn);
4351 goto done;
4354 after1 = find_next_cycle_insn (last_same_clock, this_clock + 1);
4355 if (after1 == NULL_RTX)
4356 after1 = last_same_clock;
4357 else
4358 after1 = find_last_same_clock (after1);
4359 if (TARGET_INSNS_64)
4361 rtx x1 = gen_addkpc (reg, labelref, const0_rtx);
4362 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4363 insn_set_clock (x1, this_clock + 1);
4364 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4365 if (after1 == last_same_clock)
4366 PUT_MODE (x1, TImode);
4368 else
4370 rtx x1, x2;
4371 rtx after2 = find_next_cycle_insn (after1, this_clock + 2);
4372 if (after2 == NULL_RTX)
4373 after2 = after1;
4374 x2 = gen_movsi_lo_sum (reg, reg, labelref);
4375 x2 = emit_insn_after (duplicate_cond (x2, insn), after2);
4376 x1 = gen_movsi_high (reg, labelref);
4377 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4378 insn_set_clock (x1, this_clock + 1);
4379 insn_set_clock (x2, this_clock + 2);
4380 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4381 INSN_INFO_ENTRY (INSN_UID (x2)).reservation = RESERVATION_S2;
4382 if (after1 == last_same_clock)
4383 PUT_MODE (x1, TImode);
4384 if (after1 == after2)
4385 PUT_MODE (x2, TImode);
4389 done:
4390 insn = next;
4394 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
4395 insns as required for correctness. CALL_LABELS is the array that
4396 holds the return labels for call insns; we emit these here if
4397 scheduling was run earlier. */
4399 static void
4400 reorg_emit_nops (rtx *call_labels)
4402 bool first;
4403 rtx prev, last_call;
4404 int prev_clock, earliest_bb_end;
4405 int prev_implicit_nops;
4406 rtx insn = get_insns ();
4408 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
4409 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
4410 clocks, we must insert a NOP.
4411 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
4412 current basic block will finish. We must not allow the next basic block to
4413 begin before this cycle.
4414 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
4415 a multi-cycle nop. The code is scheduled such that subsequent insns will
4416 show the cycle gap, but we needn't insert a real NOP instruction. */
4417 insn = next_real_insn (insn);
4418 last_call = prev = NULL_RTX;
4419 prev_clock = -1;
4420 earliest_bb_end = 0;
4421 prev_implicit_nops = 0;
4422 first = true;
4423 while (insn)
4425 int this_clock = -1;
4426 rtx next;
4427 int max_cycles = 0;
4429 next = next_real_insn (insn);
4431 if (DEBUG_INSN_P (insn)
4432 || GET_CODE (PATTERN (insn)) == USE
4433 || GET_CODE (PATTERN (insn)) == CLOBBER
4434 || shadow_or_blockage_p (insn)
4435 || (JUMP_P (insn)
4436 && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
4437 || GET_CODE (PATTERN (insn)) == ADDR_VEC)))
4438 goto next_insn;
4440 if (!c6x_flag_schedule_insns2)
4441 /* No scheduling; ensure that no parallel issue happens. */
4442 PUT_MODE (insn, TImode);
4443 else
4445 int cycles;
4447 this_clock = insn_get_clock (insn);
4448 if (this_clock != prev_clock)
4450 PUT_MODE (insn, TImode);
4452 if (!first)
4454 cycles = this_clock - prev_clock;
4456 cycles -= prev_implicit_nops;
4457 if (cycles > 1)
4459 rtx nop = emit_nop_after (cycles - 1, prev);
4460 insn_set_clock (nop, prev_clock + prev_implicit_nops + 1);
4463 prev_clock = this_clock;
4465 if (last_call
4466 && insn_get_clock (last_call) + 6 <= this_clock)
4468 emit_label_before (call_labels[INSN_UID (last_call)], insn);
4469 last_call = NULL_RTX;
4471 prev_implicit_nops = 0;
4475 /* Examine how many cycles the current insn takes, and adjust
4476 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
4477 if (recog_memoized (insn) >= 0
4478 /* If not scheduling, we've emitted NOPs after calls already. */
4479 && (c6x_flag_schedule_insns2 || !returning_call_p (insn)))
4481 max_cycles = get_attr_cycles (insn);
4482 if (get_attr_type (insn) == TYPE_CALLP)
4483 prev_implicit_nops = 5;
4485 else
4486 max_cycles = 1;
4487 if (returning_call_p (insn))
4488 last_call = insn;
4490 if (c6x_flag_schedule_insns2)
4492 gcc_assert (this_clock >= 0);
4493 if (earliest_bb_end < this_clock + max_cycles)
4494 earliest_bb_end = this_clock + max_cycles;
4496 else if (max_cycles > 1)
4497 emit_nop_after (max_cycles - 1, insn);
4499 prev = insn;
4500 first = false;
4502 next_insn:
4503 if (c6x_flag_schedule_insns2
4504 && (next == NULL_RTX
4505 || (GET_MODE (next) == TImode
4506 && INSN_INFO_ENTRY (INSN_UID (next)).ebb_start))
4507 && earliest_bb_end > 0)
4509 int cycles = earliest_bb_end - prev_clock;
4510 if (cycles > 1)
4512 prev = emit_nop_after (cycles - 1, prev);
4513 insn_set_clock (prev, prev_clock + prev_implicit_nops + 1);
4515 earliest_bb_end = 0;
4516 prev_clock = -1;
4517 first = true;
4519 if (last_call)
4520 emit_label_after (call_labels[INSN_UID (last_call)], prev);
4521 last_call = NULL_RTX;
4523 insn = next;
4527 /* If possible, split INSN, which we know is either a jump or a call, into a real
4528 insn and its shadow. */
4529 static void
4530 split_delayed_branch (rtx insn)
4532 int code = recog_memoized (insn);
4533 rtx i1, newpat;
4534 rtx pat = PATTERN (insn);
4536 if (GET_CODE (pat) == COND_EXEC)
4537 pat = COND_EXEC_CODE (pat);
4539 if (CALL_P (insn))
4541 rtx src = pat, dest = NULL_RTX;
4542 rtx callee;
4543 if (GET_CODE (pat) == SET)
4545 dest = SET_DEST (pat);
4546 src = SET_SRC (pat);
4548 callee = XEXP (XEXP (src, 0), 0);
4549 if (SIBLING_CALL_P (insn))
4551 if (REG_P (callee))
4552 newpat = gen_indirect_sibcall_shadow ();
4553 else
4554 newpat = gen_sibcall_shadow (callee);
4555 pat = gen_real_jump (callee);
4557 else if (dest != NULL_RTX)
4559 if (REG_P (callee))
4560 newpat = gen_indirect_call_value_shadow (dest);
4561 else
4562 newpat = gen_call_value_shadow (dest, callee);
4563 pat = gen_real_call (callee);
4565 else
4567 if (REG_P (callee))
4568 newpat = gen_indirect_call_shadow ();
4569 else
4570 newpat = gen_call_shadow (callee);
4571 pat = gen_real_call (callee);
4573 pat = duplicate_cond (pat, insn);
4574 newpat = duplicate_cond (newpat, insn);
4576 else
4578 rtx src, op;
4579 if (GET_CODE (pat) == PARALLEL
4580 && GET_CODE (XVECEXP (pat, 0, 0)) == RETURN)
4582 newpat = gen_return_shadow ();
4583 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
4584 newpat = duplicate_cond (newpat, insn);
4586 else
4587 switch (code)
4589 case CODE_FOR_br_true:
4590 case CODE_FOR_br_false:
4591 src = SET_SRC (pat);
4592 op = XEXP (src, code == CODE_FOR_br_true ? 1 : 2);
4593 newpat = gen_condjump_shadow (op);
4594 pat = gen_real_jump (op);
4595 if (code == CODE_FOR_br_true)
4596 pat = gen_rtx_COND_EXEC (VOIDmode, XEXP (src, 0), pat);
4597 else
4598 pat = gen_rtx_COND_EXEC (VOIDmode,
4599 reversed_comparison (XEXP (src, 0),
4600 VOIDmode),
4601 pat);
4602 break;
4604 case CODE_FOR_jump:
4605 op = SET_SRC (pat);
4606 newpat = gen_jump_shadow (op);
4607 break;
4609 case CODE_FOR_indirect_jump:
4610 newpat = gen_indirect_jump_shadow ();
4611 break;
4613 case CODE_FOR_return_internal:
4614 newpat = gen_return_shadow ();
4615 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
4616 break;
4618 default:
4619 return;
4622 i1 = emit_insn_before (pat, insn);
4623 PATTERN (insn) = newpat;
4624 INSN_CODE (insn) = -1;
4625 record_delay_slot_pair (i1, insn, 5);
4628 /* Split every insn (i.e. jumps and calls) which can have delay slots into
4629 two parts: the first one is scheduled normally and emits the instruction,
4630 while the second one is a shadow insn which shows the side effect taking
4631 place. The second one is placed in the right cycle by the scheduler, but
4632 not emitted as an assembly instruction. */
4634 static void
4635 split_delayed_insns (void)
4637 rtx insn;
4638 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4640 if (JUMP_P (insn) || CALL_P (insn))
4641 split_delayed_branch (insn);
4645 /* For every insn that has an entry in the new_conditions vector, give it
4646 the appropriate predicate. */
4647 static void
4648 conditionalize_after_sched (void)
4650 basic_block bb;
4651 rtx insn;
4652 FOR_EACH_BB (bb)
4653 FOR_BB_INSNS (bb, insn)
4655 unsigned uid = INSN_UID (insn);
4656 rtx cond;
4657 if (!NONDEBUG_INSN_P (insn) || uid >= INSN_INFO_LENGTH)
4658 continue;
4659 cond = INSN_INFO_ENTRY (uid).new_cond;
4660 if (cond == NULL_RTX)
4661 continue;
4662 if (dump_file)
4663 fprintf (dump_file, "Conditionalizing insn %d\n", uid);
4664 predicate_insn (insn, cond, true);
4668 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
4669 into a sequence that loads the return register and performs the call,
4670 and emit the return label.
4671 If scheduling after reload is requested, it happens here. */
4673 static void
4674 c6x_reorg (void)
4676 basic_block bb;
4677 rtx *call_labels;
4678 bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
4679 && !maybe_skip_selective_scheduling ());
4681 /* We are freeing block_for_insn in the toplev to keep compatibility
4682 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4683 compute_bb_for_insn ();
4685 df_clear_flags (DF_LR_RUN_DCE);
4687 /* If optimizing, we'll have split before scheduling. */
4688 if (optimize == 0)
4689 split_all_insns ();
4691 if (c6x_flag_schedule_insns2)
4693 int sz = get_max_uid () * 3 / 2 + 1;
4695 insn_info = VEC_alloc (c6x_sched_insn_info, heap, sz);
4697 /* Make sure the real-jump insns we create are not deleted. */
4698 sched_no_dce = true;
4700 split_delayed_insns ();
4701 timevar_push (TV_SCHED2);
4702 if (do_selsched)
4703 run_selective_scheduling ();
4704 else
4705 schedule_ebbs ();
4706 conditionalize_after_sched ();
4707 timevar_pop (TV_SCHED2);
4709 free_delay_pairs ();
4710 sched_no_dce = false;
4713 call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
4715 reorg_split_calls (call_labels);
4717 if (c6x_flag_schedule_insns2)
4719 FOR_EACH_BB (bb)
4720 if ((bb->flags & BB_DISABLE_SCHEDULE) == 0)
4721 assign_reservations (BB_HEAD (bb), BB_END (bb));
4724 if (c6x_flag_var_tracking)
4726 timevar_push (TV_VAR_TRACKING);
4727 variable_tracking_main ();
4728 timevar_pop (TV_VAR_TRACKING);
4731 reorg_emit_nops (call_labels);
4733 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
4734 if (c6x_flag_schedule_insns2)
4736 free_delay_pairs ();
4737 c6x_gen_bundles ();
4740 df_finish_pass (false);
4743 /* Called when a function has been assembled. It should perform all the
4744 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
4745 tasks.
4746 We free the reservation (and other scheduling) information here now that
4747 all insns have been output. */
4748 void
4749 c6x_function_end (FILE *file, const char *fname)
4751 c6x_output_fn_unwind (file);
4753 if (insn_info)
4754 VEC_free (c6x_sched_insn_info, heap, insn_info);
4755 insn_info = NULL;
4757 if (!flag_inhibit_size_directive)
4758 ASM_OUTPUT_MEASURED_SIZE (file, fname);
4761 /* Determine whether X is a shift with code CODE and an integer amount
4762 AMOUNT. */
4763 static bool
4764 shift_p (rtx x, enum rtx_code code, int amount)
4766 return (GET_CODE (x) == code && GET_CODE (XEXP (x, 1)) == CONST_INT
4767 && INTVAL (XEXP (x, 1)) == amount);
4770 /* Compute a (partial) cost for rtx X. Return true if the complete
4771 cost has been computed, and false if subexpressions should be
4772 scanned. In either case, *TOTAL contains the cost result. */
4774 static bool
4775 c6x_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
4777 int cost2 = COSTS_N_INSNS (1);
4778 rtx op0, op1;
4780 switch (code)
4782 case CONST_INT:
4783 if (outer_code == SET || outer_code == PLUS)
4784 *total = satisfies_constraint_IsB (x) ? 0 : cost2;
4785 else if (outer_code == AND || outer_code == IOR || outer_code == XOR
4786 || outer_code == MINUS)
4787 *total = satisfies_constraint_Is5 (x) ? 0 : cost2;
4788 else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
4789 || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
4790 *total = satisfies_constraint_Iu4 (x) ? 0 : cost2;
4791 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
4792 || outer_code == LSHIFTRT)
4793 *total = satisfies_constraint_Iu5 (x) ? 0 : cost2;
4794 else
4795 *total = cost2;
4796 return true;
4798 case CONST:
4799 case LABEL_REF:
4800 case SYMBOL_REF:
4801 case CONST_DOUBLE:
4802 *total = COSTS_N_INSNS (2);
4803 return true;
4805 case TRUNCATE:
4806 /* Recognize a mult_highpart operation. */
4807 if ((GET_MODE (x) == HImode || GET_MODE (x) == SImode)
4808 && GET_CODE (XEXP (x, 0)) == LSHIFTRT
4809 && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x))
4810 && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
4811 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
4812 && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x)))
4814 rtx mul = XEXP (XEXP (x, 0), 0);
4815 rtx op0 = XEXP (mul, 0);
4816 rtx op1 = XEXP (mul, 1);
4817 enum rtx_code code0 = GET_CODE (op0);
4818 enum rtx_code code1 = GET_CODE (op1);
4820 if ((code0 == code1
4821 && (code0 == SIGN_EXTEND || code0 == ZERO_EXTEND))
4822 || (GET_MODE (x) == HImode
4823 && code0 == ZERO_EXTEND && code1 == SIGN_EXTEND))
4825 if (GET_MODE (x) == HImode)
4826 *total = COSTS_N_INSNS (2);
4827 else
4828 *total = COSTS_N_INSNS (12);
4829 *total += rtx_cost (XEXP (op0, 0), code0, speed);
4830 *total += rtx_cost (XEXP (op1, 0), code1, speed);
4831 return true;
4834 return false;
4836 case ASHIFT:
4837 case ASHIFTRT:
4838 case LSHIFTRT:
4839 if (GET_MODE (x) == DImode)
4840 *total = COSTS_N_INSNS (CONSTANT_P (XEXP (x, 1)) ? 4 : 15);
4841 else
4842 *total = COSTS_N_INSNS (1);
4843 return false;
4845 case PLUS:
4846 case MINUS:
4847 *total = COSTS_N_INSNS (1);
4848 op0 = code == PLUS ? XEXP (x, 0) : XEXP (x, 1);
4849 op1 = code == PLUS ? XEXP (x, 1) : XEXP (x, 0);
4850 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
4851 && INTEGRAL_MODE_P (GET_MODE (x))
4852 && GET_CODE (op0) == MULT
4853 && GET_CODE (XEXP (op0, 1)) == CONST_INT
4854 && (INTVAL (XEXP (op0, 1)) == 2
4855 || INTVAL (XEXP (op0, 1)) == 4
4856 || (code == PLUS && INTVAL (XEXP (op0, 1)) == 8)))
4858 *total += rtx_cost (XEXP (op0, 0), ASHIFT, speed);
4859 *total += rtx_cost (op1, (enum rtx_code)code, speed);
4860 return true;
4862 return false;
4864 case MULT:
4865 op0 = XEXP (x, 0);
4866 op1 = XEXP (x, 1);
4867 if (GET_MODE (x) == DFmode)
4869 if (TARGET_FP)
4870 *total = COSTS_N_INSNS (speed ? 10 : 1);
4871 else
4872 *total = COSTS_N_INSNS (speed ? 200 : 4);
4874 else if (GET_MODE (x) == SFmode)
4876 if (TARGET_FP)
4877 *total = COSTS_N_INSNS (speed ? 4 : 1);
4878 else
4879 *total = COSTS_N_INSNS (speed ? 100 : 4);
4881 else if (GET_MODE (x) == DImode)
4883 if (TARGET_MPY32
4884 && GET_CODE (op0) == GET_CODE (op1)
4885 && (GET_CODE (op0) == ZERO_EXTEND
4886 || GET_CODE (op0) == SIGN_EXTEND))
4888 *total = COSTS_N_INSNS (speed ? 2 : 1);
4889 op0 = XEXP (op0, 0);
4890 op1 = XEXP (op1, 0);
4892 else
4893 /* Maybe improve this laster. */
4894 *total = COSTS_N_INSNS (20);
4896 else if (GET_MODE (x) == SImode)
4898 if (((GET_CODE (op0) == ZERO_EXTEND
4899 || GET_CODE (op0) == SIGN_EXTEND
4900 || shift_p (op0, LSHIFTRT, 16))
4901 && (GET_CODE (op1) == SIGN_EXTEND
4902 || GET_CODE (op1) == ZERO_EXTEND
4903 || scst5_operand (op1, SImode)
4904 || shift_p (op1, ASHIFTRT, 16)
4905 || shift_p (op1, LSHIFTRT, 16)))
4906 || (shift_p (op0, ASHIFTRT, 16)
4907 && (GET_CODE (op1) == SIGN_EXTEND
4908 || shift_p (op1, ASHIFTRT, 16))))
4910 *total = COSTS_N_INSNS (speed ? 2 : 1);
4911 op0 = XEXP (op0, 0);
4912 if (scst5_operand (op1, SImode))
4913 op1 = NULL_RTX;
4914 else
4915 op1 = XEXP (op1, 0);
4917 else if (!speed)
4918 *total = COSTS_N_INSNS (1);
4919 else if (TARGET_MPY32)
4920 *total = COSTS_N_INSNS (4);
4921 else
4922 *total = COSTS_N_INSNS (6);
4924 else if (GET_MODE (x) == HImode)
4925 *total = COSTS_N_INSNS (speed ? 2 : 1);
4927 if (GET_CODE (op0) != REG
4928 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
4929 *total += rtx_cost (op0, MULT, speed);
4930 if (op1 && GET_CODE (op1) != REG
4931 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
4932 *total += rtx_cost (op1, MULT, speed);
4933 return true;
4935 case UDIV:
4936 case DIV:
4937 /* This is a bit random; assuming on average there'll be 16 leading
4938 zeros. FIXME: estimate better for constant dividends. */
4939 *total = COSTS_N_INSNS (6 + 3 * 16);
4940 return false;
4942 case IF_THEN_ELSE:
4943 /* Recognize the cmp_and/ior patterns. */
4944 op0 = XEXP (x, 0);
4945 if ((GET_CODE (op0) == EQ || GET_CODE (op0) == NE)
4946 && REG_P (XEXP (op0, 0))
4947 && XEXP (op0, 1) == const0_rtx
4948 && rtx_equal_p (XEXP (x, 1), XEXP (op0, 0)))
4950 *total = rtx_cost (XEXP (x, 1), (enum rtx_code)outer_code, speed);
4951 return false;
4953 return false;
4955 default:
4956 return false;
4960 /* Implements target hook vector_mode_supported_p. */
4962 static bool
4963 c6x_vector_mode_supported_p (enum machine_mode mode)
4965 switch (mode)
4967 case V2HImode:
4968 case V4QImode:
4969 case V2SImode:
4970 case V4HImode:
4971 case V8QImode:
4972 return true;
4973 default:
4974 return false;
4978 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
4979 static enum machine_mode
4980 c6x_preferred_simd_mode (enum machine_mode mode)
4982 switch (mode)
4984 case HImode:
4985 return V2HImode;
4986 case QImode:
4987 return V4QImode;
4989 default:
4990 return word_mode;
4994 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
4996 static bool
4997 c6x_scalar_mode_supported_p (enum machine_mode mode)
4999 if (ALL_FIXED_POINT_MODE_P (mode)
5000 && GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
5001 return true;
5003 return default_scalar_mode_supported_p (mode);
5006 /* Output a reference from a function exception table to the type_info
5007 object X. Output these via a special assembly directive. */
5009 static bool
5010 c6x_output_ttype (rtx x)
5012 /* Use special relocations for symbol references. */
5013 if (GET_CODE (x) != CONST_INT)
5014 fputs ("\t.ehtype\t", asm_out_file);
5015 else
5016 fputs ("\t.word\t", asm_out_file);
5017 output_addr_const (asm_out_file, x);
5018 fputc ('\n', asm_out_file);
5020 return TRUE;
5023 /* Modify the return address of the current function. */
5025 void
5026 c6x_set_return_address (rtx source, rtx scratch)
5028 struct c6x_frame frame;
5029 rtx addr;
5030 HOST_WIDE_INT offset;
5032 c6x_compute_frame_layout (&frame);
5033 if (! c6x_save_reg (RETURN_ADDR_REGNO))
5034 emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNO), source);
5035 else
5038 if (frame_pointer_needed)
5040 addr = hard_frame_pointer_rtx;
5041 offset = frame.b3_offset;
5043 else
5045 addr = stack_pointer_rtx;
5046 offset = frame.to_allocate - frame.b3_offset;
5049 /* TODO: Use base+offset loads where possible. */
5050 if (offset)
5052 HOST_WIDE_INT low = trunc_int_for_mode (offset, HImode);
5054 emit_insn (gen_movsi_high (scratch, GEN_INT (low)));
5055 if (low != offset)
5056 emit_insn (gen_movsi_lo_sum (scratch, scratch, GEN_INT(offset)));
5057 emit_insn (gen_addsi3 (scratch, addr, scratch));
5058 addr = scratch;
5061 emit_move_insn (gen_frame_mem (Pmode, addr), source);
5065 /* We save pairs of registers using a DImode store. Describe the component
5066 registers for DWARF generation code. */
5068 static rtx
5069 c6x_dwarf_register_span (rtx rtl)
5071 unsigned regno;
5072 unsigned real_regno;
5073 int nregs;
5074 int i;
5075 rtx p;
5077 regno = REGNO (rtl);
5078 nregs = HARD_REGNO_NREGS (regno, GET_MODE (rtl));
5079 if (nregs == 1)
5080 return NULL_RTX;
5082 p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc(nregs));
5083 for (i = 0; i < nregs; i++)
5085 if (TARGET_BIG_ENDIAN)
5086 real_regno = regno + nregs - (i + 1);
5087 else
5088 real_regno = regno + i;
5090 XVECEXP (p, 0, i) = gen_rtx_REG (SImode, real_regno);
5093 return p;
5096 /* Codes for all the C6X builtins. */
5097 enum c6x_builtins
5099 C6X_BUILTIN_SADD,
5100 C6X_BUILTIN_SSUB,
5101 C6X_BUILTIN_ADD2,
5102 C6X_BUILTIN_SUB2,
5103 C6X_BUILTIN_ADD4,
5104 C6X_BUILTIN_SUB4,
5105 C6X_BUILTIN_SADD2,
5106 C6X_BUILTIN_SSUB2,
5107 C6X_BUILTIN_SADDU4,
5109 C6X_BUILTIN_SMPY,
5110 C6X_BUILTIN_SMPYH,
5111 C6X_BUILTIN_SMPYHL,
5112 C6X_BUILTIN_SMPYLH,
5113 C6X_BUILTIN_MPY2,
5114 C6X_BUILTIN_SMPY2,
5116 C6X_BUILTIN_CLRR,
5117 C6X_BUILTIN_EXTR,
5118 C6X_BUILTIN_EXTRU,
5120 C6X_BUILTIN_SSHL,
5121 C6X_BUILTIN_SUBC,
5122 C6X_BUILTIN_ABS,
5123 C6X_BUILTIN_ABS2,
5124 C6X_BUILTIN_AVG2,
5125 C6X_BUILTIN_AVGU4,
5127 C6X_BUILTIN_MAX
5131 static GTY(()) tree c6x_builtin_decls[C6X_BUILTIN_MAX];
5133 /* Return the C6X builtin for CODE. */
5134 static tree
5135 c6x_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
5137 if (code >= C6X_BUILTIN_MAX)
5138 return error_mark_node;
5140 return c6x_builtin_decls[code];
5143 #define def_builtin(NAME, TYPE, CODE) \
5144 do { \
5145 tree bdecl; \
5146 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5147 NULL, NULL_TREE); \
5148 c6x_builtin_decls[CODE] = bdecl; \
5149 } while (0)
5151 /* Set up all builtin functions for this target. */
5152 static void
5153 c6x_init_builtins (void)
5155 tree V4QI_type_node = build_vector_type (unsigned_intQI_type_node, 4);
5156 tree V2HI_type_node = build_vector_type (intHI_type_node, 2);
5157 tree V2SI_type_node = build_vector_type (intSI_type_node, 2);
5158 tree int_ftype_int
5159 = build_function_type_list (integer_type_node, integer_type_node,
5160 NULL_TREE);
5161 tree int_ftype_int_int
5162 = build_function_type_list (integer_type_node, integer_type_node,
5163 integer_type_node, NULL_TREE);
5164 tree v2hi_ftype_v2hi
5165 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5166 tree v4qi_ftype_v4qi_v4qi
5167 = build_function_type_list (V4QI_type_node, V4QI_type_node,
5168 V4QI_type_node, NULL_TREE);
5169 tree v2hi_ftype_v2hi_v2hi
5170 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5171 V2HI_type_node, NULL_TREE);
5172 tree v2si_ftype_v2hi_v2hi
5173 = build_function_type_list (V2SI_type_node, V2HI_type_node,
5174 V2HI_type_node, NULL_TREE);
5176 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int,
5177 C6X_BUILTIN_SADD);
5178 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int,
5179 C6X_BUILTIN_SSUB);
5180 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi,
5181 C6X_BUILTIN_ADD2);
5182 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi,
5183 C6X_BUILTIN_SUB2);
5184 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi,
5185 C6X_BUILTIN_ADD4);
5186 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi,
5187 C6X_BUILTIN_SUB4);
5188 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi,
5189 C6X_BUILTIN_MPY2);
5190 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi,
5191 C6X_BUILTIN_SADD2);
5192 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi,
5193 C6X_BUILTIN_SSUB2);
5194 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi,
5195 C6X_BUILTIN_SADDU4);
5196 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi,
5197 C6X_BUILTIN_SMPY2);
5199 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int,
5200 C6X_BUILTIN_SMPY);
5201 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int,
5202 C6X_BUILTIN_SMPYH);
5203 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int,
5204 C6X_BUILTIN_SMPYHL);
5205 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int,
5206 C6X_BUILTIN_SMPYLH);
5208 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int,
5209 C6X_BUILTIN_SSHL);
5210 def_builtin ("__builtin_c6x_subc", int_ftype_int_int,
5211 C6X_BUILTIN_SUBC);
5213 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi,
5214 C6X_BUILTIN_AVG2);
5215 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi,
5216 C6X_BUILTIN_AVGU4);
5218 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int,
5219 C6X_BUILTIN_CLRR);
5220 def_builtin ("__builtin_c6x_extr", int_ftype_int_int,
5221 C6X_BUILTIN_EXTR);
5222 def_builtin ("__builtin_c6x_extru", int_ftype_int_int,
5223 C6X_BUILTIN_EXTRU);
5225 def_builtin ("__builtin_c6x_abs", int_ftype_int, C6X_BUILTIN_ABS);
5226 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi, C6X_BUILTIN_ABS2);
5230 struct builtin_description
5232 const enum insn_code icode;
5233 const char *const name;
5234 const enum c6x_builtins code;
5237 static const struct builtin_description bdesc_2arg[] =
5239 { CODE_FOR_saddsi3, "__builtin_c6x_sadd", C6X_BUILTIN_SADD },
5240 { CODE_FOR_ssubsi3, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB },
5241 { CODE_FOR_addv2hi3, "__builtin_c6x_add2", C6X_BUILTIN_ADD2 },
5242 { CODE_FOR_subv2hi3, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2 },
5243 { CODE_FOR_addv4qi3, "__builtin_c6x_add4", C6X_BUILTIN_ADD4 },
5244 { CODE_FOR_subv4qi3, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4 },
5245 { CODE_FOR_ss_addv2hi3, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2 },
5246 { CODE_FOR_ss_subv2hi3, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2 },
5247 { CODE_FOR_us_addv4qi3, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4 },
5249 { CODE_FOR_subcsi3, "__builtin_c6x_subc", C6X_BUILTIN_SUBC },
5250 { CODE_FOR_ss_ashlsi3, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL },
5252 { CODE_FOR_avgv2hi3, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2 },
5253 { CODE_FOR_uavgv4qi3, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4 },
5255 { CODE_FOR_mulhqsq3, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY },
5256 { CODE_FOR_mulhqsq3_hh, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH },
5257 { CODE_FOR_mulhqsq3_lh, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH },
5258 { CODE_FOR_mulhqsq3_hl, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL },
5260 { CODE_FOR_mulv2hqv2sq3, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2 },
5262 { CODE_FOR_clrr, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR },
5263 { CODE_FOR_extr, "__builtin_c6x_extr", C6X_BUILTIN_EXTR },
5264 { CODE_FOR_extru, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU }
5267 static const struct builtin_description bdesc_1arg[] =
5269 { CODE_FOR_ssabssi2, "__builtin_c6x_abs", C6X_BUILTIN_ABS },
5270 { CODE_FOR_ssabsv2hi2, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2 }
5273 /* Errors in the source file can cause expand_expr to return const0_rtx
5274 where we expect a vector. To avoid crashing, use one of the vector
5275 clear instructions. */
5276 static rtx
5277 safe_vector_operand (rtx x, enum machine_mode mode)
5279 if (x != const0_rtx)
5280 return x;
5281 x = gen_reg_rtx (SImode);
5283 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5284 return gen_lowpart (mode, x);
5287 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
5288 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5290 static rtx
5291 c6x_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5292 bool match_op)
5294 int offs = match_op ? 1 : 0;
5295 rtx pat;
5296 tree arg0 = CALL_EXPR_ARG (exp, 0);
5297 tree arg1 = CALL_EXPR_ARG (exp, 1);
5298 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
5299 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
5300 enum machine_mode op0mode = GET_MODE (op0);
5301 enum machine_mode op1mode = GET_MODE (op1);
5302 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5303 enum machine_mode mode0 = insn_data[icode].operand[1 + offs].mode;
5304 enum machine_mode mode1 = insn_data[icode].operand[2 + offs].mode;
5305 rtx ret = target;
5307 if (VECTOR_MODE_P (mode0))
5308 op0 = safe_vector_operand (op0, mode0);
5309 if (VECTOR_MODE_P (mode1))
5310 op1 = safe_vector_operand (op1, mode1);
5312 if (! target
5313 || GET_MODE (target) != tmode
5314 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5316 if (tmode == SQmode || tmode == V2SQmode)
5318 ret = gen_reg_rtx (tmode == SQmode ? SImode : V2SImode);
5319 target = gen_lowpart (tmode, ret);
5321 else
5322 target = gen_reg_rtx (tmode);
5325 if ((op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode)
5326 && (mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode))
5328 op0mode = mode0;
5329 op0 = gen_lowpart (mode0, op0);
5331 if ((op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode)
5332 && (mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode))
5334 op1mode = mode1;
5335 op1 = gen_lowpart (mode1, op1);
5337 /* In case the insn wants input operands in modes different from
5338 the result, abort. */
5339 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5340 && (op1mode == mode1 || op1mode == VOIDmode));
5342 if (! (*insn_data[icode].operand[1 + offs].predicate) (op0, mode0))
5343 op0 = copy_to_mode_reg (mode0, op0);
5344 if (! (*insn_data[icode].operand[2 + offs].predicate) (op1, mode1))
5345 op1 = copy_to_mode_reg (mode1, op1);
5347 if (match_op)
5348 pat = GEN_FCN (icode) (target, target, op0, op1);
5349 else
5350 pat = GEN_FCN (icode) (target, op0, op1);
5352 if (! pat)
5353 return 0;
5355 emit_insn (pat);
5357 return ret;
5360 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
5362 static rtx
5363 c6x_expand_unop_builtin (enum insn_code icode, tree exp,
5364 rtx target)
5366 rtx pat;
5367 tree arg0 = CALL_EXPR_ARG (exp, 0);
5368 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
5369 enum machine_mode op0mode = GET_MODE (op0);
5370 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5371 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5373 if (! target
5374 || GET_MODE (target) != tmode
5375 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5376 target = gen_reg_rtx (tmode);
5378 if (VECTOR_MODE_P (mode0))
5379 op0 = safe_vector_operand (op0, mode0);
5381 if (op0mode == SImode && mode0 == HImode)
5383 op0mode = HImode;
5384 op0 = gen_lowpart (HImode, op0);
5386 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5388 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5389 op0 = copy_to_mode_reg (mode0, op0);
5391 pat = GEN_FCN (icode) (target, op0);
5392 if (! pat)
5393 return 0;
5394 emit_insn (pat);
5395 return target;
5398 /* Expand an expression EXP that calls a built-in function,
5399 with result going to TARGET if that's convenient
5400 (and in mode MODE if that's convenient).
5401 SUBTARGET may be used as the target for computing one of EXP's operands.
5402 IGNORE is nonzero if the value is to be ignored. */
5404 static rtx
5405 c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5406 rtx subtarget ATTRIBUTE_UNUSED,
5407 enum machine_mode mode ATTRIBUTE_UNUSED,
5408 int ignore ATTRIBUTE_UNUSED)
5410 size_t i;
5411 const struct builtin_description *d;
5412 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5413 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5415 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
5416 if (d->code == fcode)
5417 return c6x_expand_binop_builtin (d->icode, exp, target,
5418 fcode == C6X_BUILTIN_CLRR);
5420 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
5421 if (d->code == fcode)
5422 return c6x_expand_unop_builtin (d->icode, exp, target);
5424 gcc_unreachable ();
5427 /* Target Structure. */
5429 /* Initialize the GCC target structure. */
5430 #undef TARGET_FUNCTION_ARG
5431 #define TARGET_FUNCTION_ARG c6x_function_arg
5432 #undef TARGET_FUNCTION_ARG_ADVANCE
5433 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
5434 #undef TARGET_FUNCTION_ARG_BOUNDARY
5435 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
5436 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
5437 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
5438 c6x_function_arg_round_boundary
5439 #undef TARGET_FUNCTION_VALUE_REGNO_P
5440 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
5441 #undef TARGET_FUNCTION_VALUE
5442 #define TARGET_FUNCTION_VALUE c6x_function_value
5443 #undef TARGET_LIBCALL_VALUE
5444 #define TARGET_LIBCALL_VALUE c6x_libcall_value
5445 #undef TARGET_RETURN_IN_MEMORY
5446 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
5447 #undef TARGET_RETURN_IN_MSB
5448 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
5449 #undef TARGET_PASS_BY_REFERENCE
5450 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
5451 #undef TARGET_CALLEE_COPIES
5452 #define TARGET_CALLEE_COPIES c6x_callee_copies
5453 #undef TARGET_STRUCT_VALUE_RTX
5454 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
5455 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5456 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
5458 #undef TARGET_ASM_OUTPUT_MI_THUNK
5459 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
5460 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5461 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
5463 #undef TARGET_BUILD_BUILTIN_VA_LIST
5464 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
5466 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5467 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
5468 #undef TARGET_TRAMPOLINE_INIT
5469 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
5471 #undef TARGET_LEGITIMATE_CONSTANT_P
5472 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
5473 #undef TARGET_LEGITIMATE_ADDRESS_P
5474 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
5476 #undef TARGET_IN_SMALL_DATA_P
5477 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
5478 #undef TARGET_ASM_SELECT_RTX_SECTION
5479 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
5480 #undef TARGET_ASM_SELECT_SECTION
5481 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
5482 #undef TARGET_ASM_UNIQUE_SECTION
5483 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
5484 #undef TARGET_SECTION_TYPE_FLAGS
5485 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
5486 #undef TARGET_HAVE_SRODATA_SECTION
5487 #define TARGET_HAVE_SRODATA_SECTION true
5488 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
5489 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
5491 #undef TARGET_OPTION_OVERRIDE
5492 #define TARGET_OPTION_OVERRIDE c6x_option_override
5493 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5494 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
5496 #undef TARGET_INIT_LIBFUNCS
5497 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
5498 #undef TARGET_LIBFUNC_GNU_PREFIX
5499 #define TARGET_LIBFUNC_GNU_PREFIX true
5501 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5502 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
5503 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5504 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
5505 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
5506 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
5508 #undef TARGET_RTX_COSTS
5509 #define TARGET_RTX_COSTS c6x_rtx_costs
5511 #undef TARGET_SCHED_INIT
5512 #define TARGET_SCHED_INIT c6x_sched_init
5513 #undef TARGET_SCHED_SET_SCHED_FLAGS
5514 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
5515 #undef TARGET_SCHED_ADJUST_COST
5516 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
5517 #undef TARGET_SCHED_ISSUE_RATE
5518 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
5519 #undef TARGET_SCHED_VARIABLE_ISSUE
5520 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
5521 #undef TARGET_SCHED_REORDER
5522 #define TARGET_SCHED_REORDER c6x_sched_reorder
5523 #undef TARGET_SCHED_REORDER2
5524 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
5525 #undef TARGET_SCHED_EXPOSED_PIPELINE
5526 #define TARGET_SCHED_EXPOSED_PIPELINE true
5528 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
5529 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
5530 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
5531 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
5532 #undef TARGET_SCHED_SET_SCHED_CONTEXT
5533 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
5534 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
5535 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
5537 #undef TARGET_CAN_ELIMINATE
5538 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
5540 #undef TARGET_PREFERRED_RENAME_CLASS
5541 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
5543 #undef TARGET_MACHINE_DEPENDENT_REORG
5544 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
5546 #undef TARGET_ASM_FILE_START
5547 #define TARGET_ASM_FILE_START c6x_file_start
5549 #undef TARGET_PRINT_OPERAND
5550 #define TARGET_PRINT_OPERAND c6x_print_operand
5551 #undef TARGET_PRINT_OPERAND_ADDRESS
5552 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
5553 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
5554 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
5556 /* C6x unwinding tables use a different format for the typeinfo tables. */
5557 #undef TARGET_ASM_TTYPE
5558 #define TARGET_ASM_TTYPE c6x_output_ttype
5560 #undef TARGET_DWARF_REGISTER_SPAN
5561 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
5563 #undef TARGET_INIT_BUILTINS
5564 #define TARGET_INIT_BUILTINS c6x_init_builtins
5565 #undef TARGET_EXPAND_BUILTIN
5566 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
5567 #undef TARGET_BUILTIN_DECL
5568 #define TARGET_BUILTIN_DECL c6x_builtin_decl
5570 struct gcc_target targetm = TARGET_INITIALIZER;
5572 #include "gt-c6x.h"