arm.h (ASM_PREFERRED_EH_DATA_FORMAT): Define.
[official-gcc.git] / gcc / config / c6x / c6x.c
blobf2ab0b88aa9f9d341f9be50c84c3d1d73f6b19e3
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 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
115 bits rather than storing the state. Meaningful only for the last
116 insn in a cycle. */
117 unsigned int unit_mask;
118 } c6x_sched_insn_info;
120 DEF_VEC_O(c6x_sched_insn_info);
121 DEF_VEC_ALLOC_O(c6x_sched_insn_info, heap);
123 /* Record a c6x_sched_insn_info structure for every insn in the function. */
124 static VEC(c6x_sched_insn_info, heap) *insn_info;
126 #define INSN_INFO_LENGTH (VEC_length (c6x_sched_insn_info, insn_info))
127 #define INSN_INFO_ENTRY(N) (*VEC_index (c6x_sched_insn_info, insn_info, (N)))
129 static bool done_cfi_sections;
131 #define RESERVATION_FLAG_D 1
132 #define RESERVATION_FLAG_L 2
133 #define RESERVATION_FLAG_S 4
134 #define RESERVATION_FLAG_M 8
135 #define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
136 #define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
137 #define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
138 #define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
140 /* The DFA names of the units. */
141 static const char *const c6x_unit_names[] =
143 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
144 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
147 /* The DFA unit number for each unit in c6x_unit_names[]. */
148 static int c6x_unit_codes[ARRAY_SIZE (c6x_unit_names)];
150 /* Unit query IDs. */
151 #define UNIT_QID_D1 0
152 #define UNIT_QID_L1 1
153 #define UNIT_QID_S1 2
154 #define UNIT_QID_M1 3
155 #define UNIT_QID_FPS1 4
156 #define UNIT_QID_FPL1 5
157 #define UNIT_QID_ADDDPS1 6
158 #define UNIT_QID_ADDDPL1 7
159 #define UNIT_QID_SIDE_OFFSET 8
161 #define RESERVATION_S1 2
162 #define RESERVATION_S2 10
164 /* Register map for debugging. */
165 int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
167 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
168 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
169 50, 51, 52,
170 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
171 29, 30, 31,
172 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
173 66, 67, 68,
174 -1, -1, -1 /* FP, ARGP, ILC. */
177 /* Allocate a new, cleared machine_function structure. */
179 static struct machine_function *
180 c6x_init_machine_status (void)
182 return ggc_alloc_cleared_machine_function ();
185 /* Implement TARGET_OPTION_OVERRIDE. */
187 static void
188 c6x_option_override (void)
190 unsigned i;
192 if (global_options_set.x_c6x_arch_option)
194 c6x_arch = all_isas[c6x_arch_option].type;
195 c6x_insn_mask &= ~C6X_INSNS_ALL_CPU_BITS;
196 c6x_insn_mask |= all_isas[c6x_arch_option].features;
199 c6x_flag_schedule_insns2 = flag_schedule_insns_after_reload;
200 flag_schedule_insns_after_reload = 0;
202 c6x_flag_modulo_sched = flag_modulo_sched;
203 flag_modulo_sched = 0;
205 init_machine_status = c6x_init_machine_status;
207 for (i = 0; i < ARRAY_SIZE (c6x_unit_names); i++)
208 c6x_unit_codes[i] = get_cpu_unit_code (c6x_unit_names[i]);
210 if (flag_pic && !TARGET_DSBT)
212 error ("-fpic and -fPIC not supported without -mdsbt on this target");
213 flag_pic = 0;
215 c6x_initial_flag_pic = flag_pic;
216 if (TARGET_DSBT && !flag_pic)
217 flag_pic = 1;
221 /* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
223 static void
224 c6x_conditional_register_usage (void)
226 int i;
227 if (c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X)
228 for (i = 16; i < 32; i++)
230 fixed_regs[i] = 1;
231 fixed_regs[32 + i] = 1;
233 if (TARGET_INSNS_64)
235 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_A_REGS],
236 REG_A0);
237 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_REGS],
238 REG_A0);
239 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_A_REGS],
240 REG_A0);
241 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_REGS],
242 REG_A0);
246 static GTY(()) rtx eqdf_libfunc;
247 static GTY(()) rtx nedf_libfunc;
248 static GTY(()) rtx ledf_libfunc;
249 static GTY(()) rtx ltdf_libfunc;
250 static GTY(()) rtx gedf_libfunc;
251 static GTY(()) rtx gtdf_libfunc;
252 static GTY(()) rtx eqsf_libfunc;
253 static GTY(()) rtx nesf_libfunc;
254 static GTY(()) rtx lesf_libfunc;
255 static GTY(()) rtx ltsf_libfunc;
256 static GTY(()) rtx gesf_libfunc;
257 static GTY(()) rtx gtsf_libfunc;
258 static GTY(()) rtx strasgi_libfunc;
259 static GTY(()) rtx strasgi64p_libfunc;
261 /* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
262 functions to match the C6x ABI. */
264 static void
265 c6x_init_libfuncs (void)
267 /* Double-precision floating-point arithmetic. */
268 set_optab_libfunc (add_optab, DFmode, "__c6xabi_addd");
269 set_optab_libfunc (sdiv_optab, DFmode, "__c6xabi_divd");
270 set_optab_libfunc (smul_optab, DFmode, "__c6xabi_mpyd");
271 set_optab_libfunc (neg_optab, DFmode, "__c6xabi_negd");
272 set_optab_libfunc (sub_optab, DFmode, "__c6xabi_subd");
274 /* Single-precision floating-point arithmetic. */
275 set_optab_libfunc (add_optab, SFmode, "__c6xabi_addf");
276 set_optab_libfunc (sdiv_optab, SFmode, "__c6xabi_divf");
277 set_optab_libfunc (smul_optab, SFmode, "__c6xabi_mpyf");
278 set_optab_libfunc (neg_optab, SFmode, "__c6xabi_negf");
279 set_optab_libfunc (sub_optab, SFmode, "__c6xabi_subf");
281 /* Floating-point comparisons. */
282 eqsf_libfunc = init_one_libfunc ("__c6xabi_eqf");
283 nesf_libfunc = init_one_libfunc ("__c6xabi_neqf");
284 lesf_libfunc = init_one_libfunc ("__c6xabi_lef");
285 ltsf_libfunc = init_one_libfunc ("__c6xabi_ltf");
286 gesf_libfunc = init_one_libfunc ("__c6xabi_gef");
287 gtsf_libfunc = init_one_libfunc ("__c6xabi_gtf");
288 eqdf_libfunc = init_one_libfunc ("__c6xabi_eqd");
289 nedf_libfunc = init_one_libfunc ("__c6xabi_neqd");
290 ledf_libfunc = init_one_libfunc ("__c6xabi_led");
291 ltdf_libfunc = init_one_libfunc ("__c6xabi_ltd");
292 gedf_libfunc = init_one_libfunc ("__c6xabi_ged");
293 gtdf_libfunc = init_one_libfunc ("__c6xabi_gtd");
295 set_optab_libfunc (eq_optab, SFmode, NULL);
296 set_optab_libfunc (ne_optab, SFmode, "__c6xabi_neqf");
297 set_optab_libfunc (gt_optab, SFmode, NULL);
298 set_optab_libfunc (ge_optab, SFmode, NULL);
299 set_optab_libfunc (lt_optab, SFmode, NULL);
300 set_optab_libfunc (le_optab, SFmode, NULL);
301 set_optab_libfunc (unord_optab, SFmode, "__c6xabi_unordf");
302 set_optab_libfunc (eq_optab, DFmode, NULL);
303 set_optab_libfunc (ne_optab, DFmode, "__c6xabi_neqd");
304 set_optab_libfunc (gt_optab, DFmode, NULL);
305 set_optab_libfunc (ge_optab, DFmode, NULL);
306 set_optab_libfunc (lt_optab, DFmode, NULL);
307 set_optab_libfunc (le_optab, DFmode, NULL);
308 set_optab_libfunc (unord_optab, DFmode, "__c6xabi_unordd");
310 /* Floating-point to integer conversions. */
311 set_conv_libfunc (sfix_optab, SImode, DFmode, "__c6xabi_fixdi");
312 set_conv_libfunc (ufix_optab, SImode, DFmode, "__c6xabi_fixdu");
313 set_conv_libfunc (sfix_optab, DImode, DFmode, "__c6xabi_fixdlli");
314 set_conv_libfunc (ufix_optab, DImode, DFmode, "__c6xabi_fixdull");
315 set_conv_libfunc (sfix_optab, SImode, SFmode, "__c6xabi_fixfi");
316 set_conv_libfunc (ufix_optab, SImode, SFmode, "__c6xabi_fixfu");
317 set_conv_libfunc (sfix_optab, DImode, SFmode, "__c6xabi_fixflli");
318 set_conv_libfunc (ufix_optab, DImode, SFmode, "__c6xabi_fixfull");
320 /* Conversions between floating types. */
321 set_conv_libfunc (trunc_optab, SFmode, DFmode, "__c6xabi_cvtdf");
322 set_conv_libfunc (sext_optab, DFmode, SFmode, "__c6xabi_cvtfd");
324 /* Integer to floating-point conversions. */
325 set_conv_libfunc (sfloat_optab, DFmode, SImode, "__c6xabi_fltid");
326 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__c6xabi_fltud");
327 set_conv_libfunc (sfloat_optab, DFmode, DImode, "__c6xabi_fltllid");
328 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__c6xabi_fltulld");
329 set_conv_libfunc (sfloat_optab, SFmode, SImode, "__c6xabi_fltif");
330 set_conv_libfunc (ufloat_optab, SFmode, SImode, "__c6xabi_fltuf");
331 set_conv_libfunc (sfloat_optab, SFmode, DImode, "__c6xabi_fltllif");
332 set_conv_libfunc (ufloat_optab, SFmode, DImode, "__c6xabi_fltullf");
334 /* Long long. */
335 set_optab_libfunc (smul_optab, DImode, "__c6xabi_mpyll");
336 set_optab_libfunc (ashl_optab, DImode, "__c6xabi_llshl");
337 set_optab_libfunc (lshr_optab, DImode, "__c6xabi_llshru");
338 set_optab_libfunc (ashr_optab, DImode, "__c6xabi_llshr");
340 set_optab_libfunc (sdiv_optab, SImode, "__c6xabi_divi");
341 set_optab_libfunc (udiv_optab, SImode, "__c6xabi_divu");
342 set_optab_libfunc (smod_optab, SImode, "__c6xabi_remi");
343 set_optab_libfunc (umod_optab, SImode, "__c6xabi_remu");
344 set_optab_libfunc (sdivmod_optab, SImode, "__c6xabi_divremi");
345 set_optab_libfunc (udivmod_optab, SImode, "__c6xabi_divremu");
346 set_optab_libfunc (sdiv_optab, DImode, "__c6xabi_divlli");
347 set_optab_libfunc (udiv_optab, DImode, "__c6xabi_divull");
348 set_optab_libfunc (smod_optab, DImode, "__c6xabi_remlli");
349 set_optab_libfunc (umod_optab, DImode, "__c6xabi_remull");
350 set_optab_libfunc (udivmod_optab, DImode, "__c6xabi_divremull");
352 /* Block move. */
353 strasgi_libfunc = init_one_libfunc ("__c6xabi_strasgi");
354 strasgi64p_libfunc = init_one_libfunc ("__c6xabi_strasgi_64plus");
357 /* Begin the assembly file. */
359 static void
360 c6x_file_start (void)
362 /* Variable tracking should be run after all optimizations which change order
363 of insns. It also needs a valid CFG. This can't be done in
364 c6x_override_options, because flag_var_tracking is finalized after
365 that. */
366 c6x_flag_var_tracking = flag_var_tracking;
367 flag_var_tracking = 0;
369 done_cfi_sections = false;
370 default_file_start ();
372 /* Arrays are aligned to 8-byte boundaries. */
373 asm_fprintf (asm_out_file,
374 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
375 asm_fprintf (asm_out_file,
376 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
378 /* Stack alignment is 8 bytes. */
379 asm_fprintf (asm_out_file,
380 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
381 asm_fprintf (asm_out_file,
382 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
384 #if 0 /* FIXME: Reenable when TI's tools are fixed. */
385 /* ??? Ideally we'd check flag_short_wchar somehow. */
386 asm_fprintf (asm_out_file, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
387 #endif
389 /* We conform to version 1.0 of the ABI. */
390 asm_fprintf (asm_out_file,
391 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
395 /* The LTO frontend only enables exceptions when it sees a function that
396 uses it. This changes the return value of dwarf2out_do_frame, so we
397 have to check before every function. */
399 void
400 c6x_output_file_unwind (FILE * f)
402 if (done_cfi_sections)
403 return;
405 /* Output a .cfi_sections directive. */
406 if (dwarf2out_do_frame ())
408 if (flag_unwind_tables || flag_exceptions)
410 if (write_symbols == DWARF2_DEBUG
411 || write_symbols == VMS_AND_DWARF2_DEBUG)
412 asm_fprintf (f, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
413 else
414 asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
416 else
417 asm_fprintf (f, "\t.cfi_sections .debug_frame\n");
418 done_cfi_sections = true;
422 /* Output unwind directives at the end of a function. */
424 static void
425 c6x_output_fn_unwind (FILE * f)
427 /* Return immediately if we are not generating unwinding tables. */
428 if (! (flag_unwind_tables || flag_exceptions))
429 return;
431 /* If this function will never be unwound, then mark it as such. */
432 if (!(flag_unwind_tables || crtl->uses_eh_lsda)
433 && (TREE_NOTHROW (current_function_decl)
434 || crtl->all_throwers_are_sibcalls))
435 fputs("\t.cantunwind\n", f);
437 fputs ("\t.endp\n", f);
441 /* Stack and Calling. */
443 int argument_registers[10] =
445 REG_A4, REG_B4,
446 REG_A6, REG_B6,
447 REG_A8, REG_B8,
448 REG_A10, REG_B10,
449 REG_A12, REG_B12
452 /* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
454 void
455 c6x_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, rtx libname,
456 int n_named_args ATTRIBUTE_UNUSED)
458 cum->count = 0;
459 cum->nregs = 10;
460 if (!libname && fntype)
462 /* We need to find out the number of named arguments. Unfortunately,
463 for incoming arguments, N_NAMED_ARGS is set to -1. */
464 if (stdarg_p (fntype))
465 cum->nregs = type_num_arguments (fntype) - 1;
466 if (cum->nregs > 10)
467 cum->nregs = 10;
471 /* Implements the macro FUNCTION_ARG defined in c6x.h. */
473 static rtx
474 c6x_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
475 const_tree type, bool named ATTRIBUTE_UNUSED)
477 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
478 if (cum->count >= cum->nregs)
479 return NULL_RTX;
480 if (type)
482 HOST_WIDE_INT size = int_size_in_bytes (type);
483 if (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (type))
485 if (size > 4)
487 rtx reg1 = gen_rtx_REG (SImode, argument_registers[cum->count] + 1);
488 rtx reg2 = gen_rtx_REG (SImode, argument_registers[cum->count]);
489 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
490 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
491 return gen_rtx_PARALLEL (mode, vec);
495 return gen_rtx_REG (mode, argument_registers[cum->count]);
498 static void
499 c6x_function_arg_advance (cumulative_args_t cum_v,
500 enum machine_mode mode ATTRIBUTE_UNUSED,
501 const_tree type ATTRIBUTE_UNUSED,
502 bool named ATTRIBUTE_UNUSED)
504 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
505 cum->count++;
509 /* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
510 upward rather than downward. */
512 bool
513 c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
514 const_tree type, bool first)
516 HOST_WIDE_INT size;
518 if (!TARGET_BIG_ENDIAN)
519 return true;
520 if (!first)
521 return true;
522 if (!type)
523 return true;
524 size = int_size_in_bytes (type);
525 return size == 3;
528 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
530 static unsigned int
531 c6x_function_arg_boundary (enum machine_mode mode, const_tree type)
533 unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
535 if (boundary > BITS_PER_WORD)
536 return 2 * BITS_PER_WORD;
538 if (mode == BLKmode)
540 HOST_WIDE_INT size = int_size_in_bytes (type);
541 if (size > 4)
542 return 2 * BITS_PER_WORD;
543 if (boundary < BITS_PER_WORD)
545 if (size >= 3)
546 return BITS_PER_WORD;
547 if (size >= 2)
548 return 2 * BITS_PER_UNIT;
551 return boundary;
554 /* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
555 static unsigned int
556 c6x_function_arg_round_boundary (enum machine_mode mode, const_tree type)
558 return c6x_function_arg_boundary (mode, type);
561 /* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
562 where function FUNC returns or receives a value of data type TYPE. */
564 static rtx
565 c6x_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
566 bool outgoing ATTRIBUTE_UNUSED)
568 /* Functions return values in register A4. When returning aggregates, we may
569 have to adjust for endianness. */
570 if (TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P (type))
572 HOST_WIDE_INT size = int_size_in_bytes (type);
573 if (size > 4)
576 rtx reg1 = gen_rtx_REG (SImode, REG_A4 + 1);
577 rtx reg2 = gen_rtx_REG (SImode, REG_A4);
578 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
579 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
580 return gen_rtx_PARALLEL (TYPE_MODE (type), vec);
583 return gen_rtx_REG (TYPE_MODE (type), REG_A4);
586 /* Implement TARGET_LIBCALL_VALUE. */
588 static rtx
589 c6x_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
591 return gen_rtx_REG (mode, REG_A4);
594 /* TARGET_STRUCT_VALUE_RTX implementation. */
596 static rtx
597 c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED)
599 return gen_rtx_REG (Pmode, REG_A3);
602 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
604 static bool
605 c6x_function_value_regno_p (const unsigned int regno)
607 return regno == REG_A4;
610 /* Types larger than 64 bit, and variable sized types, are passed by
611 reference. The callee must copy them; see c6x_callee_copies. */
613 static bool
614 c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
615 enum machine_mode mode, const_tree type,
616 bool named ATTRIBUTE_UNUSED)
618 int size = -1;
619 if (type)
620 size = int_size_in_bytes (type);
621 else if (mode != VOIDmode)
622 size = GET_MODE_SIZE (mode);
623 return size > 2 * UNITS_PER_WORD || size == -1;
626 /* Decide whether a type should be returned in memory (true)
627 or in a register (false). This is called by the macro
628 TARGET_RETURN_IN_MEMORY. */
630 static bool
631 c6x_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
633 int size = int_size_in_bytes (type);
634 return size > 2 * UNITS_PER_WORD || size == -1;
637 /* Values which must be returned in the most-significant end of the return
638 register. */
640 static bool
641 c6x_return_in_msb (const_tree valtype)
643 HOST_WIDE_INT size = int_size_in_bytes (valtype);
644 return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && size == 3;
647 /* Implement TARGET_CALLEE_COPIES. */
649 static bool
650 c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
651 enum machine_mode mode ATTRIBUTE_UNUSED,
652 const_tree type ATTRIBUTE_UNUSED,
653 bool named ATTRIBUTE_UNUSED)
655 return true;
658 /* Return the type to use as __builtin_va_list. */
659 static tree
660 c6x_build_builtin_va_list (void)
662 return build_pointer_type (char_type_node);
665 static void
666 c6x_asm_trampoline_template (FILE *f)
668 fprintf (f, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
669 fprintf (f, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
670 fprintf (f, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
671 fprintf (f, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
672 fprintf (f, "\t.long\t0x00000362\n"); /* b .s2 B0 */
673 fprintf (f, "\t.long\t0x00008000\n"); /* nop 5 */
674 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
675 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
678 /* Emit RTL insns to initialize the variable parts of a trampoline at
679 TRAMP. FNADDR is an RTX for the address of the function's pure
680 code. CXT is an RTX for the static chain value for the function. */
682 static void
683 c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt)
685 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
686 rtx t1 = copy_to_reg (fnaddr);
687 rtx t2 = copy_to_reg (cxt);
688 rtx mask = gen_reg_rtx (SImode);
689 int i;
691 emit_block_move (tramp, assemble_trampoline_template (),
692 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
694 emit_move_insn (mask, GEN_INT (0xffff << 7));
696 for (i = 0; i < 4; i++)
698 rtx mem = adjust_address (tramp, SImode, i * 4);
699 rtx t = (i & 1) ? t2 : t1;
700 rtx v1 = gen_reg_rtx (SImode);
701 rtx v2 = gen_reg_rtx (SImode);
702 emit_move_insn (v1, mem);
703 if (i < 2)
704 emit_insn (gen_ashlsi3 (v2, t, GEN_INT (7)));
705 else
706 emit_insn (gen_lshrsi3 (v2, t, GEN_INT (9)));
707 emit_insn (gen_andsi3 (v2, v2, mask));
708 emit_insn (gen_iorsi3 (v2, v2, v1));
709 emit_move_insn (mem, v2);
711 #ifdef CLEAR_INSN_CACHE
712 tramp = XEXP (tramp, 0);
713 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"),
714 LCT_NORMAL, VOIDmode, 2, tramp, Pmode,
715 plus_constant (tramp, TRAMPOLINE_SIZE), Pmode);
716 #endif
719 /* Determine whether c6x_output_mi_thunk can succeed. */
721 static bool
722 c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
723 HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
724 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
725 const_tree function ATTRIBUTE_UNUSED)
727 return !TARGET_LONG_CALLS;
730 /* Output the assembler code for a thunk function. THUNK is the
731 declaration for the thunk function itself, FUNCTION is the decl for
732 the target function. DELTA is an immediate constant offset to be
733 added to THIS. If VCALL_OFFSET is nonzero, the word at
734 *(*this + vcall_offset) should be added to THIS. */
736 static void
737 c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
738 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
739 HOST_WIDE_INT vcall_offset, tree function)
741 rtx xops[5];
742 /* The this parameter is passed as the first argument. */
743 rtx this_rtx = gen_rtx_REG (Pmode, REG_A4);
745 c6x_current_insn = NULL_RTX;
747 xops[4] = XEXP (DECL_RTL (function), 0);
748 if (!vcall_offset)
750 output_asm_insn ("b .s2 \t%4", xops);
751 if (!delta)
752 output_asm_insn ("nop 5", xops);
755 /* Adjust the this parameter by a fixed constant. */
756 if (delta)
758 xops[0] = GEN_INT (delta);
759 xops[1] = this_rtx;
760 if (delta >= -16 && delta <= 15)
762 output_asm_insn ("add .s1 %0, %1, %1", xops);
763 if (!vcall_offset)
764 output_asm_insn ("nop 4", xops);
766 else if (delta >= 16 && delta < 32)
768 output_asm_insn ("add .d1 %0, %1, %1", xops);
769 if (!vcall_offset)
770 output_asm_insn ("nop 4", xops);
772 else if (delta >= -32768 && delta < 32768)
774 output_asm_insn ("mvk .s1 %0, A0", xops);
775 output_asm_insn ("add .d1 %1, A0, %1", xops);
776 if (!vcall_offset)
777 output_asm_insn ("nop 3", xops);
779 else
781 output_asm_insn ("mvkl .s1 %0, A0", xops);
782 output_asm_insn ("mvkh .s1 %0, A0", xops);
783 output_asm_insn ("add .d1 %1, A0, %1", xops);
784 if (!vcall_offset)
785 output_asm_insn ("nop 3", xops);
789 /* Adjust the this parameter by a value stored in the vtable. */
790 if (vcall_offset)
792 rtx a0tmp = gen_rtx_REG (Pmode, REG_A0);
793 rtx a3tmp = gen_rtx_REG (Pmode, REG_A3);
795 xops[1] = a3tmp;
796 xops[2] = a0tmp;
797 xops[3] = gen_rtx_MEM (Pmode, a0tmp);
798 output_asm_insn ("mv .s1 a4, %2", xops);
799 output_asm_insn ("ldw .d1t1 %3, %2", xops);
801 /* Adjust the this parameter. */
802 xops[0] = gen_rtx_MEM (Pmode, plus_constant (a0tmp, vcall_offset));
803 if (!memory_operand (xops[0], Pmode))
805 rtx tmp2 = gen_rtx_REG (Pmode, REG_A1);
806 xops[0] = GEN_INT (vcall_offset);
807 xops[1] = tmp2;
808 output_asm_insn ("mvkl .s1 %0, %1", xops);
809 output_asm_insn ("mvkh .s1 %0, %1", xops);
810 output_asm_insn ("nop 2", xops);
811 output_asm_insn ("add .d1 %2, %1, %2", xops);
812 xops[0] = gen_rtx_MEM (Pmode, a0tmp);
814 else
815 output_asm_insn ("nop 4", xops);
816 xops[2] = this_rtx;
817 output_asm_insn ("ldw .d1t1 %0, %1", xops);
818 output_asm_insn ("|| b .s2 \t%4", xops);
819 output_asm_insn ("nop 4", xops);
820 output_asm_insn ("add .d1 %2, %1, %2", xops);
824 /* Return true if EXP goes in small data/bss. */
826 static bool
827 c6x_in_small_data_p (const_tree exp)
829 /* We want to merge strings, so we never consider them small data. */
830 if (TREE_CODE (exp) == STRING_CST)
831 return false;
833 /* Functions are never small data. */
834 if (TREE_CODE (exp) == FUNCTION_DECL)
835 return false;
837 if (TREE_CODE (exp) == VAR_DECL && DECL_WEAK (exp))
838 return false;
840 if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
842 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
844 if (strcmp (section, ".neardata") == 0
845 || strncmp (section, ".neardata.", 10) == 0
846 || strncmp (section, ".gnu.linkonce.s.", 16) == 0
847 || strcmp (section, ".bss") == 0
848 || strncmp (section, ".bss.", 5) == 0
849 || strncmp (section, ".gnu.linkonce.sb.", 17) == 0
850 || strcmp (section, ".rodata") == 0
851 || strncmp (section, ".rodata.", 8) == 0
852 || strncmp (section, ".gnu.linkonce.s2.", 17) == 0)
853 return true;
855 else
856 return PLACE_IN_SDATA_P (exp);
858 return false;
861 /* Return a section for X. The only special thing we do here is to
862 honor small data. We don't have a tree type, so we can't use the
863 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
864 everything sized 8 bytes or smaller into small data. */
866 static section *
867 c6x_select_rtx_section (enum machine_mode mode, rtx x,
868 unsigned HOST_WIDE_INT align)
870 if (c6x_sdata_mode == C6X_SDATA_ALL
871 || (c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE (mode) <= 8))
872 /* ??? Consider using mergeable sdata sections. */
873 return sdata_section;
874 else
875 return default_elf_select_rtx_section (mode, x, align);
878 static section *
879 c6x_elf_select_section (tree decl, int reloc,
880 unsigned HOST_WIDE_INT align)
882 const char *sname = NULL;
883 unsigned int flags = SECTION_WRITE;
884 if (c6x_in_small_data_p (decl))
886 switch (categorize_decl_for_section (decl, reloc))
888 case SECCAT_SRODATA:
889 sname = ".rodata";
890 flags = 0;
891 break;
892 case SECCAT_SDATA:
893 sname = ".neardata";
894 break;
895 case SECCAT_SBSS:
896 sname = ".bss";
897 flags |= SECTION_BSS;
898 default:
899 break;
902 else
904 switch (categorize_decl_for_section (decl, reloc))
906 case SECCAT_DATA:
907 sname = ".fardata";
908 break;
909 case SECCAT_DATA_REL:
910 sname = ".fardata.rel";
911 break;
912 case SECCAT_DATA_REL_LOCAL:
913 sname = ".fardata.rel.local";
914 break;
915 case SECCAT_DATA_REL_RO:
916 sname = ".fardata.rel.ro";
917 break;
918 case SECCAT_DATA_REL_RO_LOCAL:
919 sname = ".fardata.rel.ro.local";
920 break;
921 case SECCAT_BSS:
922 sname = ".far";
923 flags |= SECTION_BSS;
924 break;
925 case SECCAT_RODATA:
926 sname = ".const";
927 flags = 0;
928 break;
929 case SECCAT_SRODATA:
930 case SECCAT_SDATA:
931 case SECCAT_SBSS:
932 gcc_unreachable ();
933 default:
934 break;
937 if (sname)
939 /* We might get called with string constants, but get_named_section
940 doesn't like them as they are not DECLs. Also, we need to set
941 flags in that case. */
942 if (!DECL_P (decl))
943 return get_section (sname, flags, NULL);
944 return get_named_section (decl, sname, reloc);
947 return default_elf_select_section (decl, reloc, align);
950 /* Build up a unique section name, expressed as a
951 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
952 RELOC indicates whether the initial value of EXP requires
953 link-time relocations. */
955 static void ATTRIBUTE_UNUSED
956 c6x_elf_unique_section (tree decl, int reloc)
958 const char *prefix = NULL;
959 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
960 bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
962 if (c6x_in_small_data_p (decl))
964 switch (categorize_decl_for_section (decl, reloc))
966 case SECCAT_SDATA:
967 prefix = one_only ? ".s" : ".neardata";
968 break;
969 case SECCAT_SBSS:
970 prefix = one_only ? ".sb" : ".bss";
971 break;
972 case SECCAT_SRODATA:
973 prefix = one_only ? ".s2" : ".rodata";
974 break;
975 case SECCAT_RODATA_MERGE_STR:
976 case SECCAT_RODATA_MERGE_STR_INIT:
977 case SECCAT_RODATA_MERGE_CONST:
978 case SECCAT_RODATA:
979 case SECCAT_DATA:
980 case SECCAT_DATA_REL:
981 case SECCAT_DATA_REL_LOCAL:
982 case SECCAT_DATA_REL_RO:
983 case SECCAT_DATA_REL_RO_LOCAL:
984 gcc_unreachable ();
985 default:
986 /* Everything else we place into default sections and hope for the
987 best. */
988 break;
991 else
993 switch (categorize_decl_for_section (decl, reloc))
995 case SECCAT_DATA:
996 case SECCAT_DATA_REL:
997 case SECCAT_DATA_REL_LOCAL:
998 case SECCAT_DATA_REL_RO:
999 case SECCAT_DATA_REL_RO_LOCAL:
1000 prefix = one_only ? ".fd" : ".fardata";
1001 break;
1002 case SECCAT_BSS:
1003 prefix = one_only ? ".fb" : ".far";
1004 break;
1005 case SECCAT_RODATA:
1006 case SECCAT_RODATA_MERGE_STR:
1007 case SECCAT_RODATA_MERGE_STR_INIT:
1008 case SECCAT_RODATA_MERGE_CONST:
1009 prefix = one_only ? ".fr" : ".const";
1010 break;
1011 case SECCAT_SRODATA:
1012 case SECCAT_SDATA:
1013 case SECCAT_SBSS:
1014 gcc_unreachable ();
1015 default:
1016 break;
1020 if (prefix)
1022 const char *name, *linkonce;
1023 char *string;
1025 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1026 name = targetm.strip_name_encoding (name);
1028 /* If we're using one_only, then there needs to be a .gnu.linkonce
1029 prefix to the section name. */
1030 linkonce = one_only ? ".gnu.linkonce" : "";
1032 string = ACONCAT ((linkonce, prefix, ".", name, NULL));
1034 DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
1035 return;
1037 default_unique_section (decl, reloc);
1040 static unsigned int
1041 c6x_section_type_flags (tree decl, const char *name, int reloc)
1043 unsigned int flags = 0;
1045 if (strcmp (name, ".far") == 0
1046 || strncmp (name, ".far.", 5) == 0)
1047 flags |= SECTION_BSS;
1049 flags |= default_section_type_flags (decl, name, reloc);
1051 return flags;
1054 /* Checks whether the given CALL_EXPR would use a caller saved
1055 register. This is used to decide whether sibling call optimization
1056 could be performed on the respective function call. */
1058 static bool
1059 c6x_call_saved_register_used (tree call_expr)
1061 CUMULATIVE_ARGS cum_v;
1062 cumulative_args_t cum;
1063 HARD_REG_SET call_saved_regset;
1064 tree parameter;
1065 enum machine_mode mode;
1066 tree type;
1067 rtx parm_rtx;
1068 int i;
1070 INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0);
1071 cum = pack_cumulative_args (&cum_v);
1073 COMPL_HARD_REG_SET (call_saved_regset, call_used_reg_set);
1074 for (i = 0; i < call_expr_nargs (call_expr); i++)
1076 parameter = CALL_EXPR_ARG (call_expr, i);
1077 gcc_assert (parameter);
1079 /* For an undeclared variable passed as parameter we will get
1080 an ERROR_MARK node here. */
1081 if (TREE_CODE (parameter) == ERROR_MARK)
1082 return true;
1084 type = TREE_TYPE (parameter);
1085 gcc_assert (type);
1087 mode = TYPE_MODE (type);
1088 gcc_assert (mode);
1090 if (pass_by_reference (&cum_v, mode, type, true))
1092 mode = Pmode;
1093 type = build_pointer_type (type);
1096 parm_rtx = c6x_function_arg (cum, mode, type, 0);
1098 c6x_function_arg_advance (cum, mode, type, 0);
1100 if (!parm_rtx)
1101 continue;
1103 if (REG_P (parm_rtx)
1104 && overlaps_hard_reg_set_p (call_saved_regset, GET_MODE (parm_rtx),
1105 REGNO (parm_rtx)))
1106 return true;
1107 if (GET_CODE (parm_rtx) == PARALLEL)
1109 int n = XVECLEN (parm_rtx, 0);
1110 while (n-- > 0)
1112 rtx x = XEXP (XVECEXP (parm_rtx, 0, n), 0);
1113 if (REG_P (x)
1114 && overlaps_hard_reg_set_p (call_saved_regset,
1115 GET_MODE (x), REGNO (x)))
1116 return true;
1120 return false;
1123 /* Decide whether we can make a sibling call to a function. DECL is the
1124 declaration of the function being targeted by the call and EXP is the
1125 CALL_EXPR representing the call. */
1127 static bool
1128 c6x_function_ok_for_sibcall (tree decl, tree exp)
1130 /* Registers A10, A12, B10 and B12 are available as arguments
1131 register but unfortunately caller saved. This makes functions
1132 needing these registers for arguments not suitable for
1133 sibcalls. */
1134 if (c6x_call_saved_register_used (exp))
1135 return false;
1137 if (!flag_pic)
1138 return true;
1140 if (TARGET_DSBT)
1142 /* When compiling for DSBT, the calling function must be local,
1143 so that when we reload B14 in the sibcall epilogue, it will
1144 not change its value. */
1145 struct cgraph_local_info *this_func;
1147 if (!decl)
1148 /* Not enough information. */
1149 return false;
1151 this_func = cgraph_local_info (current_function_decl);
1152 return this_func->local;
1155 return true;
1158 /* Return true if DECL is known to be linked into section SECTION. */
1160 static bool
1161 c6x_function_in_section_p (tree decl, section *section)
1163 /* We can only be certain about functions defined in the same
1164 compilation unit. */
1165 if (!TREE_STATIC (decl))
1166 return false;
1168 /* Make sure that SYMBOL always binds to the definition in this
1169 compilation unit. */
1170 if (!targetm.binds_local_p (decl))
1171 return false;
1173 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1174 if (!DECL_SECTION_NAME (decl))
1176 /* Make sure that we will not create a unique section for DECL. */
1177 if (flag_function_sections || DECL_ONE_ONLY (decl))
1178 return false;
1181 return function_section (decl) == section;
1184 /* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1185 as a long call. */
1186 bool
1187 c6x_long_call_p (rtx op)
1189 tree decl;
1191 if (!TARGET_LONG_CALLS)
1192 return false;
1194 decl = SYMBOL_REF_DECL (op);
1196 /* Try to determine whether the symbol is in the same section as the current
1197 function. Be conservative, and only cater for cases in which the
1198 whole of the current function is placed in the same section. */
1199 if (decl != NULL_TREE
1200 && !flag_reorder_blocks_and_partition
1201 && TREE_CODE (decl) == FUNCTION_DECL
1202 && c6x_function_in_section_p (decl, current_function_section ()))
1203 return false;
1205 return true;
1208 /* Emit the sequence for a call. */
1209 void
1210 c6x_expand_call (rtx retval, rtx address, bool sibcall)
1212 rtx callee = XEXP (address, 0);
1213 rtx call_insn;
1215 if (!c6x_call_operand (callee, Pmode))
1217 callee = force_reg (Pmode, callee);
1218 address = change_address (address, Pmode, callee);
1220 call_insn = gen_rtx_CALL (VOIDmode, address, const0_rtx);
1221 if (sibcall)
1223 call_insn = emit_call_insn (call_insn);
1224 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
1225 gen_rtx_REG (Pmode, REG_B3));
1227 else
1229 if (retval == NULL_RTX)
1230 call_insn = emit_call_insn (call_insn);
1231 else
1232 call_insn = emit_call_insn (gen_rtx_SET (GET_MODE (retval), retval,
1233 call_insn));
1235 if (flag_pic)
1236 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
1239 /* Legitimize PIC addresses. If the address is already position-independent,
1240 we return ORIG. Newly generated position-independent addresses go into a
1241 reg. This is REG if nonzero, otherwise we allocate register(s) as
1242 necessary. PICREG is the register holding the pointer to the PIC offset
1243 table. */
1245 static rtx
1246 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
1248 rtx addr = orig;
1249 rtx new_rtx = orig;
1251 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
1253 int unspec = UNSPEC_LOAD_GOT;
1254 rtx tmp;
1256 if (reg == 0)
1258 gcc_assert (can_create_pseudo_p ());
1259 reg = gen_reg_rtx (Pmode);
1261 if (flag_pic == 2)
1263 if (can_create_pseudo_p ())
1264 tmp = gen_reg_rtx (Pmode);
1265 else
1266 tmp = reg;
1267 emit_insn (gen_movsi_gotoff_high (tmp, addr));
1268 emit_insn (gen_movsi_gotoff_lo_sum (tmp, tmp, addr));
1269 emit_insn (gen_load_got_gotoff (reg, picreg, tmp));
1271 else
1273 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
1274 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
1276 emit_move_insn (reg, new_rtx);
1278 if (picreg == pic_offset_table_rtx)
1279 crtl->uses_pic_offset_table = 1;
1280 return reg;
1283 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1285 rtx base;
1287 if (GET_CODE (addr) == CONST)
1289 addr = XEXP (addr, 0);
1290 gcc_assert (GET_CODE (addr) == PLUS);
1293 if (XEXP (addr, 0) == picreg)
1294 return orig;
1296 if (reg == 0)
1298 gcc_assert (can_create_pseudo_p ());
1299 reg = gen_reg_rtx (Pmode);
1302 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
1303 addr = legitimize_pic_address (XEXP (addr, 1),
1304 base == reg ? NULL_RTX : reg,
1305 picreg);
1307 if (GET_CODE (addr) == CONST_INT)
1309 gcc_assert (! reload_in_progress && ! reload_completed);
1310 addr = force_reg (Pmode, addr);
1313 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
1315 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
1316 addr = XEXP (addr, 1);
1319 return gen_rtx_PLUS (Pmode, base, addr);
1322 return new_rtx;
1325 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1326 Returns true if no further code must be generated, false if the caller
1327 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1329 bool
1330 expand_move (rtx *operands, enum machine_mode mode)
1332 rtx dest = operands[0];
1333 rtx op = operands[1];
1335 if ((reload_in_progress | reload_completed) == 0
1336 && GET_CODE (dest) == MEM && GET_CODE (op) != REG)
1337 operands[1] = force_reg (mode, op);
1338 else if (mode == SImode && symbolic_operand (op, SImode))
1340 if (flag_pic)
1342 if (sdata_symbolic_operand (op, SImode))
1344 emit_insn (gen_load_sdata_pic (dest, pic_offset_table_rtx, op));
1345 crtl->uses_pic_offset_table = 1;
1346 return true;
1348 else
1350 rtx temp = (reload_completed || reload_in_progress
1351 ? dest : gen_reg_rtx (Pmode));
1353 operands[1] = legitimize_pic_address (op, temp,
1354 pic_offset_table_rtx);
1357 else if (reload_completed
1358 && !sdata_symbolic_operand (op, SImode))
1360 emit_insn (gen_movsi_high (dest, op));
1361 emit_insn (gen_movsi_lo_sum (dest, dest, op));
1362 return true;
1365 return false;
1368 /* This function is called when we're about to expand an integer compare
1369 operation which performs COMPARISON. It examines the second operand,
1370 and if it is an integer constant that cannot be used directly on the
1371 current machine in a comparison insn, it returns true. */
1372 bool
1373 c6x_force_op_for_comparison_p (enum rtx_code code, rtx op)
1375 if (!CONST_INT_P (op) || satisfies_constraint_Iu4 (op))
1376 return false;
1378 if ((code == EQ || code == LT || code == GT)
1379 && !satisfies_constraint_Is5 (op))
1380 return true;
1381 if ((code == GTU || code == LTU)
1382 && (!TARGET_INSNS_64 || !satisfies_constraint_Iu5 (op)))
1383 return true;
1385 return false;
1388 /* Emit comparison instruction if necessary, returning the expression
1389 that holds the compare result in the proper mode. Return the comparison
1390 that should be used in the jump insn. */
1393 c6x_expand_compare (rtx comparison, enum machine_mode mode)
1395 enum rtx_code code = GET_CODE (comparison);
1396 rtx op0 = XEXP (comparison, 0);
1397 rtx op1 = XEXP (comparison, 1);
1398 rtx cmp;
1399 enum rtx_code jump_code = code;
1400 enum machine_mode op_mode = GET_MODE (op0);
1402 if (op_mode == DImode && (code == NE || code == EQ) && op1 == const0_rtx)
1404 rtx t = gen_reg_rtx (SImode);
1405 emit_insn (gen_iorsi3 (t, gen_lowpart (SImode, op0),
1406 gen_highpart (SImode, op0)));
1407 op_mode = SImode;
1408 cmp = t;
1410 else if (op_mode == DImode)
1412 rtx lo[2], high[2];
1413 rtx cmp1, cmp2;
1415 if (code == NE || code == GEU || code == LEU || code == GE || code == LE)
1417 code = reverse_condition (code);
1418 jump_code = EQ;
1420 else
1421 jump_code = NE;
1423 split_di (&op0, 1, lo, high);
1424 split_di (&op1, 1, lo + 1, high + 1);
1426 if (c6x_force_op_for_comparison_p (code, high[1])
1427 || c6x_force_op_for_comparison_p (EQ, high[1]))
1428 high[1] = force_reg (SImode, high[1]);
1430 cmp1 = gen_reg_rtx (SImode);
1431 cmp2 = gen_reg_rtx (SImode);
1432 emit_insn (gen_rtx_SET (VOIDmode, cmp1,
1433 gen_rtx_fmt_ee (code, SImode, high[0], high[1])));
1434 if (code == EQ)
1436 if (c6x_force_op_for_comparison_p (code, lo[1]))
1437 lo[1] = force_reg (SImode, lo[1]);
1438 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1439 gen_rtx_fmt_ee (code, SImode, lo[0], lo[1])));
1440 emit_insn (gen_andsi3 (cmp1, cmp1, cmp2));
1442 else
1444 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1445 gen_rtx_EQ (SImode, high[0], high[1])));
1446 if (code == GT)
1447 code = GTU;
1448 else if (code == LT)
1449 code = LTU;
1450 if (c6x_force_op_for_comparison_p (code, lo[1]))
1451 lo[1] = force_reg (SImode, lo[1]);
1452 emit_insn (gen_cmpsi_and (cmp2, gen_rtx_fmt_ee (code, SImode,
1453 lo[0], lo[1]),
1454 lo[0], lo[1], cmp2));
1455 emit_insn (gen_iorsi3 (cmp1, cmp1, cmp2));
1457 cmp = cmp1;
1459 else if (TARGET_FP && !flag_finite_math_only
1460 && (op_mode == DFmode || op_mode == SFmode)
1461 && code != EQ && code != NE && code != LT && code != GT
1462 && code != UNLE && code != UNGE)
1464 enum rtx_code code1, code2, code3;
1465 rtx (*fn) (rtx, rtx, rtx, rtx, rtx);
1467 jump_code = NE;
1468 code3 = UNKNOWN;
1469 switch (code)
1471 case UNLT:
1472 case UNGT:
1473 jump_code = EQ;
1474 /* fall through */
1475 case LE:
1476 case GE:
1477 code1 = code == LE || code == UNGT ? LT : GT;
1478 code2 = EQ;
1479 break;
1481 case UNORDERED:
1482 jump_code = EQ;
1483 /* fall through */
1484 case ORDERED:
1485 code3 = EQ;
1486 /* fall through */
1487 case LTGT:
1488 code1 = LT;
1489 code2 = GT;
1490 break;
1492 case UNEQ:
1493 code1 = LT;
1494 code2 = GT;
1495 jump_code = EQ;
1496 break;
1498 default:
1499 gcc_unreachable ();
1502 cmp = gen_reg_rtx (SImode);
1503 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1504 gen_rtx_fmt_ee (code1, SImode, op0, op1)));
1505 fn = op_mode == DFmode ? gen_cmpdf_ior : gen_cmpsf_ior;
1506 emit_insn (fn (cmp, gen_rtx_fmt_ee (code2, SImode, op0, op1),
1507 op0, op1, cmp));
1508 if (code3 != UNKNOWN)
1509 emit_insn (fn (cmp, gen_rtx_fmt_ee (code3, SImode, op0, op1),
1510 op0, op1, cmp));
1512 else if (op_mode == SImode && (code == NE || code == EQ) && op1 == const0_rtx)
1513 cmp = op0;
1514 else
1516 bool is_fp_libfunc;
1517 is_fp_libfunc = !TARGET_FP && (op_mode == DFmode || op_mode == SFmode);
1519 if ((code == NE || code == GEU || code == LEU || code == GE || code == LE)
1520 && !is_fp_libfunc)
1522 code = reverse_condition (code);
1523 jump_code = EQ;
1525 else if (code == UNGE)
1527 code = LT;
1528 jump_code = EQ;
1530 else if (code == UNLE)
1532 code = GT;
1533 jump_code = EQ;
1535 else
1536 jump_code = NE;
1538 if (is_fp_libfunc)
1540 rtx insns;
1541 rtx libfunc;
1542 switch (code)
1544 case EQ:
1545 libfunc = op_mode == DFmode ? eqdf_libfunc : eqsf_libfunc;
1546 break;
1547 case NE:
1548 libfunc = op_mode == DFmode ? nedf_libfunc : nesf_libfunc;
1549 break;
1550 case GT:
1551 libfunc = op_mode == DFmode ? gtdf_libfunc : gtsf_libfunc;
1552 break;
1553 case GE:
1554 libfunc = op_mode == DFmode ? gedf_libfunc : gesf_libfunc;
1555 break;
1556 case LT:
1557 libfunc = op_mode == DFmode ? ltdf_libfunc : ltsf_libfunc;
1558 break;
1559 case LE:
1560 libfunc = op_mode == DFmode ? ledf_libfunc : lesf_libfunc;
1561 break;
1562 default:
1563 gcc_unreachable ();
1565 start_sequence ();
1567 cmp = emit_library_call_value (libfunc, 0, LCT_CONST, SImode, 2,
1568 op0, op_mode, op1, op_mode);
1569 insns = get_insns ();
1570 end_sequence ();
1572 emit_libcall_block (insns, cmp, cmp,
1573 gen_rtx_fmt_ee (code, SImode, op0, op1));
1575 else
1577 cmp = gen_reg_rtx (SImode);
1578 if (c6x_force_op_for_comparison_p (code, op1))
1579 op1 = force_reg (SImode, op1);
1580 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1581 gen_rtx_fmt_ee (code, SImode, op0, op1)));
1585 return gen_rtx_fmt_ee (jump_code, mode, cmp, const0_rtx);
1588 /* Return one word of double-word value OP. HIGH_P is true to select the
1589 high part, false to select the low part. When encountering auto-increment
1590 addressing, we make the assumption that the low part is going to be accessed
1591 first. */
1594 c6x_subword (rtx op, bool high_p)
1596 unsigned int byte;
1597 enum machine_mode mode;
1599 mode = GET_MODE (op);
1600 if (mode == VOIDmode)
1601 mode = DImode;
1603 if (TARGET_BIG_ENDIAN ? !high_p : high_p)
1604 byte = UNITS_PER_WORD;
1605 else
1606 byte = 0;
1608 if (MEM_P (op))
1610 rtx addr = XEXP (op, 0);
1611 if (GET_CODE (addr) == PLUS || REG_P (addr))
1612 return adjust_address (op, word_mode, byte);
1613 /* FIXME: should really support autoincrement addressing for
1614 multi-word modes. */
1615 gcc_unreachable ();
1618 return simplify_gen_subreg (word_mode, op, mode, byte);
1621 /* Split one or more DImode RTL references into pairs of SImode
1622 references. The RTL can be REG, offsettable MEM, integer constant, or
1623 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1624 split and "num" is its length. lo_half and hi_half are output arrays
1625 that parallel "operands". */
1627 void
1628 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1630 while (num--)
1632 rtx op = operands[num];
1634 lo_half[num] = c6x_subword (op, false);
1635 hi_half[num] = c6x_subword (op, true);
1639 /* Return true if VAL is a mask valid for a clr instruction. */
1640 bool
1641 c6x_valid_mask_p (HOST_WIDE_INT val)
1643 int i;
1644 for (i = 0; i < 32; i++)
1645 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1646 break;
1647 for (; i < 32; i++)
1648 if (val & ((unsigned HOST_WIDE_INT)1 << i))
1649 break;
1650 for (; i < 32; i++)
1651 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1652 return false;
1653 return true;
1656 /* Expand a block move for a movmemM pattern. */
1658 bool
1659 c6x_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
1660 rtx expected_align_exp ATTRIBUTE_UNUSED,
1661 rtx expected_size_exp ATTRIBUTE_UNUSED)
1663 unsigned HOST_WIDE_INT align = 1;
1664 unsigned HOST_WIDE_INT src_mem_align, dst_mem_align, min_mem_align;
1665 unsigned HOST_WIDE_INT count = 0, offset = 0;
1666 unsigned int biggest_move = TARGET_STDW ? 8 : 4;
1668 if (CONST_INT_P (align_exp))
1669 align = INTVAL (align_exp);
1671 src_mem_align = MEM_ALIGN (src) / BITS_PER_UNIT;
1672 dst_mem_align = MEM_ALIGN (dst) / BITS_PER_UNIT;
1673 min_mem_align = MIN (src_mem_align, dst_mem_align);
1675 if (min_mem_align > align)
1676 align = min_mem_align / BITS_PER_UNIT;
1677 if (src_mem_align < align)
1678 src_mem_align = align;
1679 if (dst_mem_align < align)
1680 dst_mem_align = align;
1682 if (CONST_INT_P (count_exp))
1683 count = INTVAL (count_exp);
1684 else
1685 return false;
1687 /* Make sure we don't need to care about overflow later on. */
1688 if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
1689 return false;
1691 if (count >= 28 && (count & 3) == 0 && align >= 4)
1693 tree dst_expr = MEM_EXPR (dst);
1694 tree src_expr = MEM_EXPR (src);
1695 rtx fn = TARGET_INSNS_64PLUS ? strasgi64p_libfunc : strasgi_libfunc;
1696 rtx srcreg = force_reg (Pmode, XEXP (src, 0));
1697 rtx dstreg = force_reg (Pmode, XEXP (dst, 0));
1699 if (src_expr)
1700 mark_addressable (src_expr);
1701 if (dst_expr)
1702 mark_addressable (dst_expr);
1703 emit_library_call (fn, LCT_NORMAL, VOIDmode, 3,
1704 dstreg, Pmode, srcreg, Pmode, count_exp, SImode);
1705 return true;
1708 if (biggest_move > align && !TARGET_INSNS_64)
1709 biggest_move = align;
1711 if (count / biggest_move > 7)
1712 return false;
1714 while (count > 0)
1716 rtx reg, reg_lowpart;
1717 enum machine_mode srcmode, dstmode;
1718 unsigned HOST_WIDE_INT src_size, dst_size, src_left;
1719 int shift;
1720 rtx srcmem, dstmem;
1722 while (biggest_move > count)
1723 biggest_move /= 2;
1725 src_size = dst_size = biggest_move;
1726 if (src_size > src_mem_align && src_size == 2)
1727 src_size = 1;
1728 if (dst_size > dst_mem_align && dst_size == 2)
1729 dst_size = 1;
1731 if (dst_size > src_size)
1732 dst_size = src_size;
1734 srcmode = mode_for_size (src_size * BITS_PER_UNIT, MODE_INT, 0);
1735 dstmode = mode_for_size (dst_size * BITS_PER_UNIT, MODE_INT, 0);
1736 if (src_size >= 4)
1737 reg_lowpart = reg = gen_reg_rtx (srcmode);
1738 else
1740 reg = gen_reg_rtx (SImode);
1741 reg_lowpart = gen_lowpart (srcmode, reg);
1744 srcmem = adjust_address (copy_rtx (src), srcmode, offset);
1746 if (src_size > src_mem_align)
1748 enum insn_code icode = (srcmode == SImode ? CODE_FOR_movmisalignsi
1749 : CODE_FOR_movmisaligndi);
1750 emit_insn (GEN_FCN (icode) (reg_lowpart, srcmem));
1752 else
1753 emit_move_insn (reg_lowpart, srcmem);
1755 src_left = src_size;
1756 shift = TARGET_BIG_ENDIAN ? (src_size - dst_size) * BITS_PER_UNIT : 0;
1757 while (src_left > 0)
1759 rtx dstreg = reg_lowpart;
1761 if (src_size > dst_size)
1763 rtx srcword = reg;
1764 int shift_amount = shift & (BITS_PER_WORD - 1);
1765 if (src_size > 4)
1766 srcword = operand_subword_force (srcword, src_left >= 4 ? 0 : 4,
1767 SImode);
1768 if (shift_amount > 0)
1770 dstreg = gen_reg_rtx (SImode);
1771 emit_insn (gen_lshrsi3 (dstreg, srcword,
1772 GEN_INT (shift_amount)));
1774 else
1775 dstreg = srcword;
1776 dstreg = gen_lowpart (dstmode, dstreg);
1779 dstmem = adjust_address (copy_rtx (dst), dstmode, offset);
1780 if (dst_size > dst_mem_align)
1782 enum insn_code icode = (dstmode == SImode ? CODE_FOR_movmisalignsi
1783 : CODE_FOR_movmisaligndi);
1784 emit_insn (GEN_FCN (icode) (dstmem, dstreg));
1786 else
1787 emit_move_insn (dstmem, dstreg);
1789 if (TARGET_BIG_ENDIAN)
1790 shift -= dst_size * BITS_PER_UNIT;
1791 else
1792 shift += dst_size * BITS_PER_UNIT;
1793 offset += dst_size;
1794 src_left -= dst_size;
1796 count -= src_size;
1798 return true;
1801 /* Subroutine of print_address_operand, print a single address offset OFF for
1802 a memory access of mode MEM_MODE, choosing between normal form and scaled
1803 form depending on the type of the insn. Misaligned memory references must
1804 use the scaled form. */
1806 static void
1807 print_address_offset (FILE *file, rtx off, enum machine_mode mem_mode)
1809 rtx pat;
1811 if (c6x_current_insn != NULL_RTX)
1813 pat = PATTERN (c6x_current_insn);
1814 if (GET_CODE (pat) == COND_EXEC)
1815 pat = COND_EXEC_CODE (pat);
1816 if (GET_CODE (pat) == PARALLEL)
1817 pat = XVECEXP (pat, 0, 0);
1819 if (GET_CODE (pat) == SET
1820 && GET_CODE (SET_SRC (pat)) == UNSPEC
1821 && XINT (SET_SRC (pat), 1) == UNSPEC_MISALIGNED_ACCESS)
1823 gcc_assert (CONST_INT_P (off)
1824 && (INTVAL (off) & (GET_MODE_SIZE (mem_mode) - 1)) == 0);
1825 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1826 INTVAL (off) / GET_MODE_SIZE (mem_mode));
1827 return;
1830 fputs ("(", file);
1831 output_address (off);
1832 fputs (")", file);
1835 static bool
1836 c6x_print_operand_punct_valid_p (unsigned char c)
1838 return c == '$' || c == '.' || c == '|';
1841 static void c6x_print_operand (FILE *, rtx, int);
1843 /* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1845 static void
1846 c6x_print_address_operand (FILE *file, rtx x, enum machine_mode mem_mode)
1848 rtx off;
1849 switch (GET_CODE (x))
1851 case PRE_MODIFY:
1852 case POST_MODIFY:
1853 if (GET_CODE (x) == POST_MODIFY)
1854 output_address (XEXP (x, 0));
1855 off = XEXP (XEXP (x, 1), 1);
1856 if (XEXP (x, 0) == stack_pointer_rtx)
1858 if (GET_CODE (x) == PRE_MODIFY)
1859 gcc_assert (INTVAL (off) > 0);
1860 else
1861 gcc_assert (INTVAL (off) < 0);
1863 if (CONST_INT_P (off) && INTVAL (off) < 0)
1865 fprintf (file, "--");
1866 off = GEN_INT (-INTVAL (off));
1868 else
1869 fprintf (file, "++");
1870 if (GET_CODE (x) == PRE_MODIFY)
1871 output_address (XEXP (x, 0));
1872 print_address_offset (file, off, mem_mode);
1873 break;
1875 case PLUS:
1876 off = XEXP (x, 1);
1877 if (CONST_INT_P (off) && INTVAL (off) < 0)
1879 fprintf (file, "-");
1880 off = GEN_INT (-INTVAL (off));
1882 else
1883 fprintf (file, "+");
1884 output_address (XEXP (x, 0));
1885 print_address_offset (file, off, mem_mode);
1886 break;
1888 case PRE_DEC:
1889 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1890 fprintf (file, "--");
1891 output_address (XEXP (x, 0));
1892 fprintf (file, "[1]");
1893 break;
1894 case PRE_INC:
1895 fprintf (file, "++");
1896 output_address (XEXP (x, 0));
1897 fprintf (file, "[1]");
1898 break;
1899 case POST_INC:
1900 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1901 output_address (XEXP (x, 0));
1902 fprintf (file, "++[1]");
1903 break;
1904 case POST_DEC:
1905 output_address (XEXP (x, 0));
1906 fprintf (file, "--[1]");
1907 break;
1909 case SYMBOL_REF:
1910 case CONST:
1911 case LABEL_REF:
1912 gcc_assert (sdata_symbolic_operand (x, Pmode));
1913 fprintf (file, "+B14(");
1914 output_addr_const (file, x);
1915 fprintf (file, ")");
1916 break;
1918 case UNSPEC:
1919 switch (XINT (x, 1))
1921 case UNSPEC_LOAD_GOT:
1922 fputs ("$GOT(", file);
1923 output_addr_const (file, XVECEXP (x, 0, 0));
1924 fputs (")", file);
1925 break;
1926 case UNSPEC_LOAD_SDATA:
1927 output_addr_const (file, XVECEXP (x, 0, 0));
1928 break;
1929 default:
1930 gcc_unreachable ();
1932 break;
1934 default:
1935 gcc_assert (GET_CODE (x) != MEM);
1936 c6x_print_operand (file, x, 0);
1937 break;
1941 /* Return a single character, which is either 'l', 's', 'd' or 'm', which
1942 specifies the functional unit used by INSN. */
1944 char
1945 c6x_get_unit_specifier (rtx insn)
1947 enum attr_units units;
1949 if (insn_info)
1951 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
1952 return c6x_unit_names[unit][0];
1955 units = get_attr_units (insn);
1956 switch (units)
1958 case UNITS_D:
1959 case UNITS_DL:
1960 case UNITS_DS:
1961 case UNITS_DLS:
1962 case UNITS_D_ADDR:
1963 return 'd';
1964 break;
1965 case UNITS_L:
1966 case UNITS_LS:
1967 return 'l';
1968 break;
1969 case UNITS_S:
1970 return 's';
1971 break;
1972 case UNITS_M:
1973 return 'm';
1974 break;
1975 default:
1976 gcc_unreachable ();
1980 /* Prints the unit specifier field. */
1981 static void
1982 c6x_print_unit_specifier_field (FILE *file, rtx insn)
1984 enum attr_units units = get_attr_units (insn);
1985 enum attr_cross cross = get_attr_cross (insn);
1986 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
1987 int half;
1988 char unitspec;
1990 if (units == UNITS_D_ADDR)
1992 enum attr_addr_regfile arf = get_attr_addr_regfile (insn);
1993 int t_half;
1994 gcc_assert (arf != ADDR_REGFILE_UNKNOWN);
1995 half = arf == ADDR_REGFILE_A ? 1 : 2;
1996 t_half = rf == DEST_REGFILE_A ? 1 : 2;
1997 fprintf (file, ".d%dt%d", half, t_half);
1998 return;
2001 if (insn_info)
2003 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
2004 fputs (".", file);
2005 fputs (c6x_unit_names[unit], file);
2006 if (cross == CROSS_Y)
2007 fputs ("x", file);
2008 return;
2011 gcc_assert (rf != DEST_REGFILE_UNKNOWN);
2012 unitspec = c6x_get_unit_specifier (insn);
2013 half = rf == DEST_REGFILE_A ? 1 : 2;
2014 fprintf (file, ".%c%d%s", unitspec, half, cross == CROSS_Y ? "x" : "");
2017 /* Output assembly language output for the address ADDR to FILE. */
2018 static void
2019 c6x_print_operand_address (FILE *file, rtx addr)
2021 c6x_print_address_operand (file, addr, VOIDmode);
2024 /* Print an operand, X, to FILE, with an optional modifier in CODE.
2026 Meaning of CODE:
2027 $ -- print the unit specifier field for the instruction.
2028 . -- print the predicate for the instruction or an emptry string for an
2029 unconditional one.
2030 | -- print "||" if the insn should be issued in parallel with the previous
2031 one.
2033 C -- print an opcode suffix for a reversed condition
2034 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2035 operand
2036 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2037 the operand
2038 J -- print a predicate
2039 j -- like J, but use reverse predicate
2040 k -- treat a CONST_INT as a register number and print it as a register
2041 k -- like k, but print out a doubleword register
2042 n -- print an integer operand, negated
2043 p -- print the low part of a DImode register
2044 P -- print the high part of a DImode register
2045 r -- print the absolute value of an integer operand, shifted right by 1
2046 R -- print the absolute value of an integer operand, shifted right by 2
2047 f -- the first clear bit in an integer operand assumed to be a mask for
2048 a clr instruction
2049 F -- the last clear bit in such a mask
2050 s -- the first set bit in an integer operand assumed to be a mask for
2051 a set instruction
2052 S -- the last set bit in such a mask
2053 U -- print either 1 or 2, depending on the side of the machine used by
2054 the operand */
2056 static void
2057 c6x_print_operand (FILE *file, rtx x, int code)
2059 int i;
2060 HOST_WIDE_INT v;
2061 tree t;
2062 enum machine_mode mode;
2064 if (code == '|')
2066 if (GET_MODE (c6x_current_insn) != TImode)
2067 fputs ("||", file);
2068 return;
2070 if (code == '$')
2072 c6x_print_unit_specifier_field (file, c6x_current_insn);
2073 return;
2076 if (code == '.')
2078 x = current_insn_predicate;
2079 if (x)
2081 unsigned int regno = REGNO (XEXP (x, 0));
2082 fputs ("[", file);
2083 if (GET_CODE (x) == EQ)
2084 fputs ("!", file);
2085 fputs (reg_names [regno], file);
2086 fputs ("]", file);
2088 return;
2091 mode = GET_MODE (x);
2093 switch (code)
2095 case 'C':
2096 case 'c':
2098 enum rtx_code c = GET_CODE (x);
2099 if (code == 'C')
2100 c = swap_condition (c);
2101 fputs (GET_RTX_NAME (c), file);
2103 return;
2105 case 'J':
2106 case 'j':
2108 unsigned int regno = REGNO (XEXP (x, 0));
2109 if ((GET_CODE (x) == EQ) == (code == 'J'))
2110 fputs ("!", file);
2111 fputs (reg_names [regno], file);
2113 return;
2115 case 'k':
2116 gcc_assert (GET_CODE (x) == CONST_INT);
2117 v = INTVAL (x);
2118 fprintf (file, "%s", reg_names[v]);
2119 return;
2120 case 'K':
2121 gcc_assert (GET_CODE (x) == CONST_INT);
2122 v = INTVAL (x);
2123 gcc_assert ((v & 1) == 0);
2124 fprintf (file, "%s:%s", reg_names[v + 1], reg_names[v]);
2125 return;
2127 case 's':
2128 case 'S':
2129 case 'f':
2130 case 'F':
2131 gcc_assert (GET_CODE (x) == CONST_INT);
2132 v = INTVAL (x);
2133 for (i = 0; i < 32; i++)
2135 HOST_WIDE_INT tst = v & 1;
2136 if (((code == 'f' || code == 'F') && !tst)
2137 || ((code == 's' || code == 'S') && tst))
2138 break;
2139 v >>= 1;
2141 if (code == 'f' || code == 's')
2143 fprintf (file, "%d", i);
2144 return;
2146 for (;i < 32; i++)
2148 HOST_WIDE_INT tst = v & 1;
2149 if ((code == 'F' && tst) || (code == 'S' && !tst))
2150 break;
2151 v >>= 1;
2153 fprintf (file, "%d", i - 1);
2154 return;
2156 case 'n':
2157 gcc_assert (GET_CODE (x) == CONST_INT);
2158 output_addr_const (file, GEN_INT (-INTVAL (x)));
2159 return;
2161 case 'r':
2162 gcc_assert (GET_CODE (x) == CONST_INT);
2163 v = INTVAL (x);
2164 if (v < 0)
2165 v = -v;
2166 output_addr_const (file, GEN_INT (v >> 1));
2167 return;
2169 case 'R':
2170 gcc_assert (GET_CODE (x) == CONST_INT);
2171 v = INTVAL (x);
2172 if (v < 0)
2173 v = -v;
2174 output_addr_const (file, GEN_INT (v >> 2));
2175 return;
2177 case 'd':
2178 gcc_assert (GET_CODE (x) == CONST_INT);
2179 v = INTVAL (x);
2180 fputs (v == 2 ? "h" : v == 4 ? "w" : "d", file);
2181 return;
2183 case 'p':
2184 case 'P':
2185 gcc_assert (GET_CODE (x) == REG);
2186 v = REGNO (x);
2187 if (code == 'P')
2188 v++;
2189 fputs (reg_names[v], file);
2190 return;
2192 case 'D':
2193 v = 0;
2194 if (GET_CODE (x) == CONST)
2196 x = XEXP (x, 0);
2197 gcc_assert (GET_CODE (x) == PLUS);
2198 gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
2199 v = INTVAL (XEXP (x, 1));
2200 x = XEXP (x, 0);
2203 gcc_assert (GET_CODE (x) == SYMBOL_REF);
2205 t = SYMBOL_REF_DECL (x);
2206 if (DECL_P (t))
2207 v |= DECL_ALIGN_UNIT (t);
2208 else
2209 v |= TYPE_ALIGN_UNIT (TREE_TYPE (t));
2210 if (v & 1)
2211 fputs ("b", file);
2212 else if (v & 2)
2213 fputs ("h", file);
2214 else
2215 fputs ("w", file);
2216 return;
2218 case 'U':
2219 if (MEM_P (x))
2221 x = XEXP (x, 0);
2222 if (GET_CODE (x) == PLUS
2223 || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
2224 x = XEXP (x, 0);
2225 if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
2227 gcc_assert (sdata_symbolic_operand (x, Pmode));
2228 fputs ("2", file);
2229 return;
2232 gcc_assert (REG_P (x));
2233 if (A_REGNO_P (REGNO (x)))
2234 fputs ("1", file);
2235 if (B_REGNO_P (REGNO (x)))
2236 fputs ("2", file);
2237 return;
2239 default:
2240 switch (GET_CODE (x))
2242 case REG:
2243 if (GET_MODE_SIZE (mode) == 8)
2244 fprintf (file, "%s:%s", reg_names[REGNO (x) + 1],
2245 reg_names[REGNO (x)]);
2246 else
2247 fprintf (file, "%s", reg_names[REGNO (x)]);
2248 break;
2250 case MEM:
2251 fputc ('*', file);
2252 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
2253 c6x_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
2254 break;
2256 case SYMBOL_REF:
2257 fputc ('(', file);
2258 output_addr_const (file, x);
2259 fputc (')', file);
2260 break;
2262 case CONST_INT:
2263 output_addr_const (file, x);
2264 break;
2266 case CONST_DOUBLE:
2267 output_operand_lossage ("invalid const_double operand");
2268 break;
2270 default:
2271 output_addr_const (file, x);
2276 /* Return TRUE if OP is a valid memory address with a base register of
2277 class C. If SMALL_OFFSET is true, we disallow memory references which would
2278 require a long offset with B14/B15. */
2280 bool
2281 c6x_mem_operand (rtx op, enum reg_class c, bool small_offset)
2283 enum machine_mode mode = GET_MODE (op);
2284 rtx base = XEXP (op, 0);
2285 switch (GET_CODE (base))
2287 case REG:
2288 break;
2289 case PLUS:
2290 if (small_offset
2291 && (XEXP (base, 0) == stack_pointer_rtx
2292 || XEXP (base, 0) == pic_offset_table_rtx))
2294 if (!c6x_legitimate_address_p_1 (mode, base, true, true))
2295 return false;
2298 /* fall through */
2299 case PRE_INC:
2300 case PRE_DEC:
2301 case PRE_MODIFY:
2302 case POST_INC:
2303 case POST_DEC:
2304 case POST_MODIFY:
2305 base = XEXP (base, 0);
2306 break;
2308 case CONST:
2309 case LABEL_REF:
2310 case SYMBOL_REF:
2311 gcc_assert (sdata_symbolic_operand (base, Pmode));
2312 return !small_offset && c == B_REGS;
2314 default:
2315 return false;
2317 return TEST_HARD_REG_BIT (reg_class_contents[ (int) (c)], REGNO (base));
2320 /* Returns true if X is a valid address for use in a memory reference
2321 of mode MODE. If STRICT is true, we do not allow pseudo registers
2322 in the address. NO_LARGE_OFFSET is true if we are examining an
2323 address for use in a load or store misaligned instruction, or
2324 recursively examining an operand inside a PRE/POST_MODIFY. */
2326 bool
2327 c6x_legitimate_address_p_1 (enum machine_mode mode, rtx x, bool strict,
2328 bool no_large_offset)
2330 int size, size1;
2331 HOST_WIDE_INT off;
2332 enum rtx_code code = GET_CODE (x);
2334 switch (code)
2336 case PRE_MODIFY:
2337 case POST_MODIFY:
2338 /* We can't split these into word-sized pieces yet. */
2339 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2340 return false;
2341 if (GET_CODE (XEXP (x, 1)) != PLUS)
2342 return false;
2343 if (!c6x_legitimate_address_p_1 (mode, XEXP (x, 1), strict, true))
2344 return false;
2345 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
2346 return false;
2348 /* fall through */
2349 case PRE_INC:
2350 case PRE_DEC:
2351 case POST_INC:
2352 case POST_DEC:
2353 /* We can't split these into word-sized pieces yet. */
2354 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2355 return false;
2356 x = XEXP (x, 0);
2357 if (!REG_P (x))
2358 return false;
2360 /* fall through */
2361 case REG:
2362 if (strict)
2363 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x));
2364 else
2365 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x));
2367 case PLUS:
2368 if (!REG_P (XEXP (x, 0))
2369 || !c6x_legitimate_address_p_1 (mode, XEXP (x, 0), strict, false))
2370 return false;
2371 /* We cannot ensure currently that both registers end up in the
2372 same register file. */
2373 if (REG_P (XEXP (x, 1)))
2374 return false;
2376 if (mode == BLKmode)
2377 size = 4;
2378 else if (mode == VOIDmode)
2379 /* ??? This can happen during ivopts. */
2380 size = 1;
2381 else
2382 size = GET_MODE_SIZE (mode);
2384 if (flag_pic
2385 && GET_CODE (XEXP (x, 1)) == UNSPEC
2386 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_SDATA
2387 && XEXP (x, 0) == pic_offset_table_rtx
2388 && sdata_symbolic_operand (XVECEXP (XEXP (x, 1), 0, 0), SImode))
2389 return !no_large_offset && size <= 4;
2390 if (flag_pic == 1
2391 && mode == Pmode
2392 && GET_CODE (XEXP (x, 1)) == UNSPEC
2393 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_GOT
2394 && XEXP (x, 0) == pic_offset_table_rtx
2395 && (GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == SYMBOL_REF
2396 || GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == LABEL_REF))
2397 return !no_large_offset;
2398 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2399 return false;
2401 off = INTVAL (XEXP (x, 1));
2403 /* If the machine does not have doubleword load/stores, we'll use
2404 word size accesses. */
2405 size1 = size;
2406 if (size == 2 * UNITS_PER_WORD && !TARGET_STDW)
2407 size = UNITS_PER_WORD;
2409 if (((HOST_WIDE_INT)size1 - 1) & off)
2410 return false;
2411 off /= size;
2412 if (off > -32 && off < (size1 == size ? 32 : 28))
2413 return true;
2414 if (no_large_offset || code != PLUS || XEXP (x, 0) != stack_pointer_rtx
2415 || size1 > UNITS_PER_WORD)
2416 return false;
2417 return off >= 0 && off < 32768;
2419 case CONST:
2420 case SYMBOL_REF:
2421 case LABEL_REF:
2422 return (!no_large_offset
2423 /* With -fpic, we must wrap it in an unspec to show the B14
2424 dependency. */
2425 && !flag_pic
2426 && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
2427 && sdata_symbolic_operand (x, Pmode));
2429 default:
2430 return false;
2434 static bool
2435 c6x_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
2437 return c6x_legitimate_address_p_1 (mode, x, strict, false);
2440 static bool
2441 c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
2442 rtx x ATTRIBUTE_UNUSED)
2444 return true;
2447 /* Implements TARGET_PREFERRED_RENAME_CLASS. */
2448 static reg_class_t
2449 c6x_preferred_rename_class (reg_class_t cl)
2451 if (cl == A_REGS)
2452 return NONPREDICATE_A_REGS;
2453 if (cl == B_REGS)
2454 return NONPREDICATE_B_REGS;
2455 if (cl == ALL_REGS || cl == GENERAL_REGS)
2456 return NONPREDICATE_REGS;
2457 return NO_REGS;
2460 /* Implements FINAL_PRESCAN_INSN. */
2461 void
2462 c6x_final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
2463 int noperands ATTRIBUTE_UNUSED)
2465 c6x_current_insn = insn;
2468 /* A structure to describe the stack layout of a function. The layout is
2469 as follows:
2471 [saved frame pointer (or possibly padding0)]
2472 --> incoming stack pointer, new hard frame pointer
2473 [saved call-used regs]
2474 [optional padding1]
2475 --> soft frame pointer
2476 [frame]
2477 [outgoing arguments]
2478 [optional padding2]
2480 The structure members are laid out in this order. */
2482 struct c6x_frame
2484 int padding0;
2485 /* Number of registers to save. */
2486 int nregs;
2487 int padding1;
2488 HOST_WIDE_INT frame;
2489 int outgoing_arguments_size;
2490 int padding2;
2492 HOST_WIDE_INT to_allocate;
2493 /* The offsets relative to the incoming stack pointer (which
2494 becomes HARD_FRAME_POINTER). */
2495 HOST_WIDE_INT frame_pointer_offset;
2496 HOST_WIDE_INT b3_offset;
2498 /* True if we should call push_rts/pop_rts to save and restore
2499 registers. */
2500 bool push_rts;
2503 /* Return true if we need to save and modify the PIC register in the
2504 prologue. */
2506 static bool
2507 must_reload_pic_reg_p (void)
2509 struct cgraph_local_info *i = NULL;
2511 if (!TARGET_DSBT)
2512 return false;
2514 i = cgraph_local_info (current_function_decl);
2516 if ((crtl->uses_pic_offset_table || !current_function_is_leaf) && !i->local)
2517 return true;
2518 return false;
2521 /* Return 1 if we need to save REGNO. */
2522 static int
2523 c6x_save_reg (unsigned int regno)
2525 return ((df_regs_ever_live_p (regno)
2526 && !call_used_regs[regno]
2527 && !fixed_regs[regno])
2528 || (regno == RETURN_ADDR_REGNO
2529 && (df_regs_ever_live_p (regno)
2530 || !current_function_is_leaf))
2531 || (regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ()));
2534 /* Examine the number of regs NREGS we've determined we must save.
2535 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2536 prologue and epilogue. */
2538 static bool
2539 use_push_rts_p (int nregs)
2541 if (TARGET_INSNS_64PLUS && optimize_function_for_size_p (cfun)
2542 && !cfun->machine->contains_sibcall
2543 && !cfun->returns_struct
2544 && !TARGET_LONG_CALLS
2545 && nregs >= 6 && !frame_pointer_needed)
2546 return true;
2547 return false;
2550 /* Return number of saved general prupose registers. */
2553 c6x_nsaved_regs (void)
2555 int nregs = 0;
2556 int regno;
2558 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
2559 if (c6x_save_reg (regno))
2560 nregs++;
2561 return nregs;
2564 /* The safe debug order mandated by the ABI. */
2565 static unsigned reg_save_order[] =
2567 REG_A10, REG_A11, REG_A12, REG_A13,
2568 REG_A14, REG_B3,
2569 REG_B10, REG_B11, REG_B12, REG_B13,
2570 REG_B14, REG_A15
2573 #define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2575 /* Compute the layout of the stack frame and store it in FRAME. */
2577 static void
2578 c6x_compute_frame_layout (struct c6x_frame *frame)
2580 HOST_WIDE_INT size = get_frame_size ();
2581 HOST_WIDE_INT offset;
2582 int nregs;
2584 /* We use the four bytes which are technically inside the caller's frame,
2585 usually to save the frame pointer. */
2586 offset = -4;
2587 frame->padding0 = 0;
2588 nregs = c6x_nsaved_regs ();
2589 frame->push_rts = false;
2590 frame->b3_offset = 0;
2591 if (use_push_rts_p (nregs))
2593 frame->push_rts = true;
2594 frame->b3_offset = (TARGET_BIG_ENDIAN ? -12 : -13) * 4;
2595 nregs = 14;
2597 else if (c6x_save_reg (REG_B3))
2599 int idx;
2600 for (idx = N_SAVE_ORDER - 1; reg_save_order[idx] != REG_B3; idx--)
2602 if (c6x_save_reg (reg_save_order[idx]))
2603 frame->b3_offset -= 4;
2606 frame->nregs = nregs;
2608 if (size == 0 && nregs == 0)
2610 frame->padding0 = 4;
2611 frame->padding1 = frame->padding2 = 0;
2612 frame->frame_pointer_offset = frame->to_allocate = 0;
2613 frame->outgoing_arguments_size = 0;
2614 return;
2617 if (!frame->push_rts)
2618 offset += frame->nregs * 4;
2620 if (offset == 0 && size == 0 && crtl->outgoing_args_size == 0
2621 && !current_function_is_leaf)
2622 /* Don't use the bottom of the caller's frame if we have no
2623 allocation of our own and call other functions. */
2624 frame->padding0 = frame->padding1 = 4;
2625 else if (offset & 4)
2626 frame->padding1 = 4;
2627 else
2628 frame->padding1 = 0;
2630 offset += frame->padding0 + frame->padding1;
2631 frame->frame_pointer_offset = offset;
2632 offset += size;
2634 frame->outgoing_arguments_size = crtl->outgoing_args_size;
2635 offset += frame->outgoing_arguments_size;
2637 if ((offset & 4) == 0)
2638 frame->padding2 = 8;
2639 else
2640 frame->padding2 = 4;
2641 frame->to_allocate = offset + frame->padding2;
2644 /* Return the offset between two registers, one to be eliminated, and the other
2645 its replacement, at the start of a routine. */
2647 HOST_WIDE_INT
2648 c6x_initial_elimination_offset (int from, int to)
2650 struct c6x_frame frame;
2651 c6x_compute_frame_layout (&frame);
2653 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
2654 return 0;
2655 else if (from == FRAME_POINTER_REGNUM
2656 && to == HARD_FRAME_POINTER_REGNUM)
2657 return -frame.frame_pointer_offset;
2658 else
2660 gcc_assert (to == STACK_POINTER_REGNUM);
2662 if (from == ARG_POINTER_REGNUM)
2663 return frame.to_allocate + (frame.push_rts ? 56 : 0);
2665 gcc_assert (from == FRAME_POINTER_REGNUM);
2666 return frame.to_allocate - frame.frame_pointer_offset;
2670 /* Given FROM and TO register numbers, say whether this elimination is
2671 allowed. Frame pointer elimination is automatically handled. */
2673 static bool
2674 c6x_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
2676 if (to == STACK_POINTER_REGNUM)
2677 return !frame_pointer_needed;
2678 return true;
2681 /* Emit insns to increment the stack pointer by OFFSET. If
2682 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2683 Does nothing if the offset is zero. */
2685 static void
2686 emit_add_sp_const (HOST_WIDE_INT offset, bool frame_related_p)
2688 rtx to_add = GEN_INT (offset);
2689 rtx orig_to_add = to_add;
2690 rtx insn;
2692 if (offset == 0)
2693 return;
2695 if (offset < -32768 || offset > 32767)
2697 rtx reg = gen_rtx_REG (SImode, REG_A0);
2698 rtx low = GEN_INT (trunc_int_for_mode (offset, HImode));
2700 insn = emit_insn (gen_movsi_high (reg, low));
2701 if (frame_related_p)
2702 RTX_FRAME_RELATED_P (insn) = 1;
2703 insn = emit_insn (gen_movsi_lo_sum (reg, reg, to_add));
2704 if (frame_related_p)
2705 RTX_FRAME_RELATED_P (insn) = 1;
2706 to_add = reg;
2708 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2709 to_add));
2710 if (frame_related_p)
2712 if (REG_P (to_add))
2713 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2714 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
2715 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2716 orig_to_add)));
2718 RTX_FRAME_RELATED_P (insn) = 1;
2722 /* Prologue and epilogue. */
2723 void
2724 c6x_expand_prologue (void)
2726 struct c6x_frame frame;
2727 rtx insn, mem;
2728 int nsaved = 0;
2729 HOST_WIDE_INT initial_offset, off, added_already;
2731 c6x_compute_frame_layout (&frame);
2733 if (flag_stack_usage_info)
2734 current_function_static_stack_size = frame.to_allocate;
2736 initial_offset = -frame.to_allocate;
2737 if (frame.push_rts)
2739 emit_insn (gen_push_rts ());
2740 nsaved = frame.nregs;
2743 /* If the offsets would be too large for the memory references we will
2744 create to save registers, do the stack allocation in two parts.
2745 Ensure by subtracting 8 that we don't store to the word pointed to
2746 by the stack pointer. */
2747 if (initial_offset < -32768)
2748 initial_offset = -frame.frame_pointer_offset - 8;
2750 if (frame.to_allocate > 0)
2751 gcc_assert (initial_offset != 0);
2753 off = -initial_offset + 4 - frame.padding0;
2755 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2757 added_already = 0;
2758 if (frame_pointer_needed)
2760 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2761 /* We go through some contortions here to both follow the ABI's
2762 recommendation that FP == incoming SP, and to avoid writing or
2763 reading the word pointed to by the stack pointer. */
2764 rtx addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
2765 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2766 GEN_INT (-8)));
2767 insn = emit_move_insn (gen_frame_mem (Pmode, addr), fp_reg);
2768 RTX_FRAME_RELATED_P (insn) = 1;
2769 nsaved++;
2770 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, stack_pointer_rtx,
2771 GEN_INT (8)));
2772 RTX_FRAME_RELATED_P (insn) = 1;
2773 off -= 4;
2774 added_already = -8;
2777 emit_add_sp_const (initial_offset - added_already, true);
2779 if (nsaved < frame.nregs)
2781 unsigned i;
2783 for (i = 0; i < N_SAVE_ORDER; i++)
2785 int idx = N_SAVE_ORDER - i - 1;
2786 unsigned regno = reg_save_order[idx];
2787 rtx reg;
2788 enum machine_mode save_mode = SImode;
2790 if (regno == REG_A15 && frame_pointer_needed)
2791 /* Already saved. */
2792 continue;
2793 if (!c6x_save_reg (regno))
2794 continue;
2796 if (TARGET_STDW && (off & 4) == 0 && off <= 256
2797 && (regno & 1) == 1
2798 && i + 1 < N_SAVE_ORDER
2799 && reg_save_order[idx - 1] == regno - 1
2800 && c6x_save_reg (regno - 1))
2802 save_mode = DImode;
2803 regno--;
2804 i++;
2806 reg = gen_rtx_REG (save_mode, regno);
2807 off -= GET_MODE_SIZE (save_mode);
2809 insn = emit_move_insn (adjust_address (mem, save_mode, off),
2810 reg);
2811 RTX_FRAME_RELATED_P (insn) = 1;
2813 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2816 gcc_assert (nsaved == frame.nregs);
2817 emit_add_sp_const (-frame.to_allocate - initial_offset, true);
2818 if (must_reload_pic_reg_p ())
2820 if (dsbt_decl == NULL)
2822 tree t;
2824 t = build_index_type (integer_one_node);
2825 t = build_array_type (integer_type_node, t);
2826 t = build_decl (BUILTINS_LOCATION, VAR_DECL,
2827 get_identifier ("__c6xabi_DSBT_BASE"), t);
2828 DECL_ARTIFICIAL (t) = 1;
2829 DECL_IGNORED_P (t) = 1;
2830 DECL_EXTERNAL (t) = 1;
2831 TREE_STATIC (t) = 1;
2832 TREE_PUBLIC (t) = 1;
2833 TREE_USED (t) = 1;
2835 dsbt_decl = t;
2837 emit_insn (gen_setup_dsbt (pic_offset_table_rtx,
2838 XEXP (DECL_RTL (dsbt_decl), 0)));
2842 void
2843 c6x_expand_epilogue (bool sibcall)
2845 unsigned i;
2846 struct c6x_frame frame;
2847 rtx mem;
2848 HOST_WIDE_INT off;
2849 int nsaved = 0;
2851 c6x_compute_frame_layout (&frame);
2853 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2855 /* Insert a dummy set/use of the stack pointer. This creates a
2856 scheduler barrier between the prologue saves and epilogue restores. */
2857 emit_insn (gen_epilogue_barrier (stack_pointer_rtx, stack_pointer_rtx));
2859 /* If the offsets would be too large for the memory references we will
2860 create to restore registers, do a preliminary stack adjustment here. */
2861 off = frame.to_allocate - frame.frame_pointer_offset + frame.padding1;
2862 if (frame.push_rts)
2864 nsaved = frame.nregs;
2866 else
2868 if (frame.to_allocate > 32768)
2870 /* Don't add the entire offset so that we leave an unused word
2871 above the stack pointer. */
2872 emit_add_sp_const ((off - 16) & ~7, false);
2873 off &= 7;
2874 off += 16;
2876 for (i = 0; i < N_SAVE_ORDER; i++)
2878 unsigned regno = reg_save_order[i];
2879 rtx reg;
2880 enum machine_mode save_mode = SImode;
2882 if (!c6x_save_reg (regno))
2883 continue;
2884 if (regno == REG_A15 && frame_pointer_needed)
2885 continue;
2887 if (TARGET_STDW && (off & 4) == 0 && off < 256
2888 && (regno & 1) == 0
2889 && i + 1 < N_SAVE_ORDER
2890 && reg_save_order[i + 1] == regno + 1
2891 && c6x_save_reg (regno + 1))
2893 save_mode = DImode;
2894 i++;
2896 reg = gen_rtx_REG (save_mode, regno);
2898 emit_move_insn (reg, adjust_address (mem, save_mode, off));
2900 off += GET_MODE_SIZE (save_mode);
2901 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2904 if (!frame_pointer_needed)
2905 emit_add_sp_const (off + frame.padding0 - 4, false);
2906 else
2908 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2909 rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
2910 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2911 GEN_INT (8)));
2912 emit_insn (gen_addsi3 (stack_pointer_rtx, hard_frame_pointer_rtx,
2913 GEN_INT (-8)));
2914 emit_move_insn (fp_reg, gen_frame_mem (Pmode, addr));
2915 nsaved++;
2917 gcc_assert (nsaved == frame.nregs);
2918 if (!sibcall)
2920 if (frame.push_rts)
2921 emit_jump_insn (gen_pop_rts ());
2922 else
2923 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
2924 RETURN_ADDR_REGNO)));
2928 /* Return the value of the return address for the frame COUNT steps up
2929 from the current frame, after the prologue.
2930 We punt for everything but the current frame by returning const0_rtx. */
2933 c6x_return_addr_rtx (int count)
2935 if (count != 0)
2936 return const0_rtx;
2938 return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNO);
2941 /* Return true iff TYPE is one of the shadow types. */
2942 static bool
2943 shadow_type_p (enum attr_type type)
2945 return (type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW
2946 || type == TYPE_MULT_SHADOW);
2949 /* Return true iff INSN is a shadow pattern. */
2950 static bool
2951 shadow_p (rtx insn)
2953 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2954 return false;
2955 return shadow_type_p (get_attr_type (insn));
2958 /* Return true iff INSN is a shadow or blockage pattern. */
2959 static bool
2960 shadow_or_blockage_p (rtx insn)
2962 enum attr_type type;
2963 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2964 return false;
2965 type = get_attr_type (insn);
2966 return shadow_type_p (type) || type == TYPE_BLOCKAGE;
2969 /* Translate UNITS into a bitmask of units we can reserve for this
2970 insn. */
2971 static int
2972 get_reservation_flags (enum attr_units units)
2974 switch (units)
2976 case UNITS_D:
2977 case UNITS_D_ADDR:
2978 return RESERVATION_FLAG_D;
2979 case UNITS_L:
2980 return RESERVATION_FLAG_L;
2981 case UNITS_S:
2982 return RESERVATION_FLAG_S;
2983 case UNITS_M:
2984 return RESERVATION_FLAG_M;
2985 case UNITS_LS:
2986 return RESERVATION_FLAG_LS;
2987 case UNITS_DL:
2988 return RESERVATION_FLAG_DL;
2989 case UNITS_DS:
2990 return RESERVATION_FLAG_DS;
2991 case UNITS_DLS:
2992 return RESERVATION_FLAG_DLS;
2993 default:
2994 return 0;
2998 /* Compute the side of the machine used by INSN, which reserves UNITS.
2999 This must match the reservations in the scheduling description. */
3000 static int
3001 get_insn_side (rtx insn, enum attr_units units)
3003 if (units == UNITS_D_ADDR)
3004 return (get_attr_addr_regfile (insn) == ADDR_REGFILE_A ? 0 : 1);
3005 else
3007 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
3008 if (rf == DEST_REGFILE_ANY)
3009 return get_attr_type (insn) == TYPE_BRANCH ? 0 : 1;
3010 else
3011 return rf == DEST_REGFILE_A ? 0 : 1;
3015 /* After scheduling, walk the insns between HEAD and END and assign unit
3016 reservations. */
3017 static void
3018 assign_reservations (rtx head, rtx end)
3020 rtx insn;
3021 for (insn = head; insn != NEXT_INSN (end); insn = NEXT_INSN (insn))
3023 unsigned int sched_mask, reserved;
3024 rtx within, last;
3025 int pass;
3026 int rsrv[2];
3027 int rsrv_count[2][4];
3028 int i;
3030 if (GET_MODE (insn) != TImode)
3031 continue;
3033 reserved = 0;
3034 last = NULL_RTX;
3035 /* Find the last insn in the packet. It has a state recorded for it,
3036 which we can use to determine the units we should be using. */
3037 for (within = insn;
3038 (within != NEXT_INSN (end)
3039 && (within == insn || GET_MODE (within) != TImode));
3040 within = NEXT_INSN (within))
3042 int icode;
3043 if (!NONDEBUG_INSN_P (within))
3044 continue;
3045 icode = recog_memoized (within);
3046 if (icode < 0)
3047 continue;
3048 if (shadow_p (within))
3049 continue;
3050 if (INSN_INFO_ENTRY (INSN_UID (within)).reservation != 0)
3051 reserved |= 1 << INSN_INFO_ENTRY (INSN_UID (within)).reservation;
3052 last = within;
3054 if (last == NULL_RTX)
3055 continue;
3057 sched_mask = INSN_INFO_ENTRY (INSN_UID (last)).unit_mask;
3058 sched_mask &= ~reserved;
3060 memset (rsrv_count, 0, sizeof rsrv_count);
3061 rsrv[0] = rsrv[1] = ~0;
3062 for (i = 0; i < 8; i++)
3064 int side = i / 4;
3065 int unit = i & 3;
3066 unsigned unit_bit = 1 << (unit + side * UNIT_QID_SIDE_OFFSET);
3067 /* Clear the bits which we expect to reserve in the following loop,
3068 leaving the ones set which aren't present in the scheduler's
3069 state and shouldn't be reserved. */
3070 if (sched_mask & unit_bit)
3071 rsrv[i / 4] &= ~(1 << unit);
3074 /* Walk through the insns that occur in the same cycle. We use multiple
3075 passes to assign units, assigning for insns with the most specific
3076 requirements first. */
3077 for (pass = 0; pass < 4; pass++)
3078 for (within = insn;
3079 (within != NEXT_INSN (end)
3080 && (within == insn || GET_MODE (within) != TImode));
3081 within = NEXT_INSN (within))
3083 int uid = INSN_UID (within);
3084 int this_rsrv, side;
3085 int icode;
3086 enum attr_units units;
3087 enum attr_type type;
3088 int j;
3090 if (!NONDEBUG_INSN_P (within))
3091 continue;
3092 icode = recog_memoized (within);
3093 if (icode < 0)
3094 continue;
3095 if (INSN_INFO_ENTRY (uid).reservation != 0)
3096 continue;
3097 units = get_attr_units (within);
3098 type = get_attr_type (within);
3099 this_rsrv = get_reservation_flags (units);
3100 if (this_rsrv == 0)
3101 continue;
3102 side = get_insn_side (within, units);
3104 /* Certain floating point instructions are treated specially. If
3105 an insn can choose between units it can reserve, and its
3106 reservation spans more than one cycle, the reservation contains
3107 special markers in the first cycle to help us reconstruct what
3108 the automaton chose. */
3109 if ((type == TYPE_ADDDP || type == TYPE_FP4)
3110 && units == UNITS_LS)
3112 int test1_code = ((type == TYPE_FP4 ? UNIT_QID_FPL1 : UNIT_QID_ADDDPL1)
3113 + side * UNIT_QID_SIDE_OFFSET);
3114 int test2_code = ((type == TYPE_FP4 ? UNIT_QID_FPS1 : UNIT_QID_ADDDPS1)
3115 + side * UNIT_QID_SIDE_OFFSET);
3116 if ((sched_mask & (1 << test1_code)) != 0)
3118 this_rsrv = RESERVATION_FLAG_L;
3119 sched_mask &= ~(1 << test1_code);
3121 else if ((sched_mask & (1 << test2_code)) != 0)
3123 this_rsrv = RESERVATION_FLAG_S;
3124 sched_mask &= ~(1 << test2_code);
3128 if ((this_rsrv & (this_rsrv - 1)) == 0)
3130 int t = exact_log2 (this_rsrv) + side * UNIT_QID_SIDE_OFFSET;
3131 rsrv[side] |= this_rsrv;
3132 INSN_INFO_ENTRY (uid).reservation = t;
3133 continue;
3136 if (pass == 1)
3138 for (j = 0; j < 4; j++)
3139 if (this_rsrv & (1 << j))
3140 rsrv_count[side][j]++;
3141 continue;
3143 if ((pass == 2 && this_rsrv != RESERVATION_FLAG_DLS)
3144 || (pass == 3 && this_rsrv == RESERVATION_FLAG_DLS))
3146 int best = -1, best_cost = INT_MAX;
3147 for (j = 0; j < 4; j++)
3148 if ((this_rsrv & (1 << j))
3149 && !(rsrv[side] & (1 << j))
3150 && rsrv_count[side][j] < best_cost)
3152 best_cost = rsrv_count[side][j];
3153 best = j;
3155 gcc_assert (best != -1);
3156 rsrv[side] |= 1 << best;
3157 for (j = 0; j < 4; j++)
3158 if ((this_rsrv & (1 << j)) && j != best)
3159 rsrv_count[side][j]--;
3161 INSN_INFO_ENTRY (uid).reservation
3162 = best + side * UNIT_QID_SIDE_OFFSET;
3168 /* Backend scheduling state. */
3169 typedef struct c6x_sched_context
3171 /* The current scheduler clock, saved in the sched_reorder hook. */
3172 int curr_sched_clock;
3174 /* Number of insns issued so far in this cycle. */
3175 int issued_this_cycle;
3177 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3178 theoretical maximum for number of jumps in flight is 12: 2 every
3179 cycle, with a latency of 6 cycles each. This is a circular
3180 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3181 jumps have a higher index. This array should be accessed through
3182 the jump_cycle function. */
3183 int jump_cycles[12];
3184 int jump_cycle_index;
3186 /* In parallel with jump_cycles, this array records the opposite of
3187 the condition used in each pending jump. This is used to
3188 predicate insns that are scheduled in the jump's delay slots. If
3189 this is NULL_RTX no such predication happens. */
3190 rtx jump_cond[12];
3192 /* Similar to the jump_cycles mechanism, but here we take into
3193 account all insns with delay slots, to avoid scheduling asms into
3194 the delay slots. */
3195 int delays_finished_at;
3197 /* The following variable value is the last issued insn. */
3198 rtx last_scheduled_insn;
3200 /* The following variable value is DFA state before issuing the
3201 first insn in the current clock cycle. We do not use this member
3202 of the structure directly; we copy the data in and out of
3203 prev_cycle_state. */
3204 state_t prev_cycle_state_ctx;
3206 int reg_n_accesses[FIRST_PSEUDO_REGISTER];
3207 int reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3208 int reg_set_in_cycle[FIRST_PSEUDO_REGISTER];
3210 int tmp_reg_n_accesses[FIRST_PSEUDO_REGISTER];
3211 int tmp_reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3212 } *c6x_sched_context_t;
3214 /* The current scheduling state. */
3215 static struct c6x_sched_context ss;
3217 /* The following variable value is DFA state before issueing the first insn
3218 in the current clock cycle. This is used in c6x_variable_issue for
3219 comparison with the state after issuing the last insn in a cycle. */
3220 static state_t prev_cycle_state;
3222 /* Set when we discover while processing an insn that it would lead to too
3223 many accesses of the same register. */
3224 static bool reg_access_stall;
3226 /* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3227 so the caller does not specifically have to test for it. */
3228 static int
3229 get_jump_cycle (int n)
3231 if (n >= 12)
3232 return 0;
3233 n += ss.jump_cycle_index;
3234 if (n >= 12)
3235 n -= 12;
3236 return ss.jump_cycles[n];
3239 /* Look up the jump condition with index N. */
3240 static rtx
3241 get_jump_cond (int n)
3243 if (n >= 12)
3244 return NULL_RTX;
3245 n += ss.jump_cycle_index;
3246 if (n >= 12)
3247 n -= 12;
3248 return ss.jump_cond[n];
3251 /* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3252 has delay slots beyond CLOCK_VAR, return -1. */
3253 static int
3254 first_jump_index (int clock_var)
3256 int retval = -1;
3257 int n = 0;
3258 for (;;)
3260 int t = get_jump_cycle (n);
3261 if (t <= clock_var)
3262 break;
3263 retval = n;
3264 n++;
3266 return retval;
3269 /* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3270 and has the opposite condition of COND. */
3271 static void
3272 record_jump (int cycle, rtx cond)
3274 if (ss.jump_cycle_index == 0)
3275 ss.jump_cycle_index = 11;
3276 else
3277 ss.jump_cycle_index--;
3278 ss.jump_cycles[ss.jump_cycle_index] = cycle;
3279 ss.jump_cond[ss.jump_cycle_index] = cond;
3282 /* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3283 new_conditions. */
3284 static void
3285 insn_set_clock (rtx insn, int cycle)
3287 unsigned uid = INSN_UID (insn);
3289 if (uid >= INSN_INFO_LENGTH)
3290 VEC_safe_grow (c6x_sched_insn_info, heap, insn_info, uid * 5 / 4 + 10);
3292 INSN_INFO_ENTRY (uid).clock = cycle;
3293 INSN_INFO_ENTRY (uid).new_cond = NULL;
3294 INSN_INFO_ENTRY (uid).reservation = 0;
3295 INSN_INFO_ENTRY (uid).ebb_start = false;
3298 /* Return the clock cycle we set for the insn with uid UID. */
3299 static int
3300 insn_uid_get_clock (int uid)
3302 return INSN_INFO_ENTRY (uid).clock;
3305 /* Return the clock cycle we set for INSN. */
3306 static int
3307 insn_get_clock (rtx insn)
3309 return insn_uid_get_clock (INSN_UID (insn));
3312 /* Examine INSN, and if it is a conditional jump of any kind, return
3313 the opposite of the condition in which it branches. Otherwise,
3314 return NULL_RTX. */
3315 static rtx
3316 condjump_opposite_condition (rtx insn)
3318 rtx pat = PATTERN (insn);
3319 int icode = INSN_CODE (insn);
3320 rtx x = NULL;
3322 if (icode == CODE_FOR_br_true || icode == CODE_FOR_br_false)
3324 x = XEXP (SET_SRC (pat), 0);
3325 if (icode == CODE_FOR_br_false)
3326 return x;
3328 if (GET_CODE (pat) == COND_EXEC)
3330 rtx t = COND_EXEC_CODE (pat);
3331 if ((GET_CODE (t) == PARALLEL
3332 && GET_CODE (XVECEXP (t, 0, 0)) == RETURN)
3333 || (GET_CODE (t) == UNSPEC && XINT (t, 1) == UNSPEC_REAL_JUMP)
3334 || (GET_CODE (t) == SET && SET_DEST (t) == pc_rtx))
3335 x = COND_EXEC_TEST (pat);
3338 if (x != NULL_RTX)
3340 enum rtx_code code = GET_CODE (x);
3341 x = gen_rtx_fmt_ee (code == EQ ? NE : EQ,
3342 GET_MODE (x), XEXP (x, 0),
3343 XEXP (x, 1));
3345 return x;
3348 /* Return true iff COND1 and COND2 are exactly opposite conditions
3349 one of them NE and the other EQ. */
3350 static bool
3351 conditions_opposite_p (rtx cond1, rtx cond2)
3353 return (rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
3354 && rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1))
3355 && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)));
3358 /* Return true if we can add a predicate COND to INSN, or if INSN
3359 already has that predicate. If DOIT is true, also perform the
3360 modification. */
3361 static bool
3362 predicate_insn (rtx insn, rtx cond, bool doit)
3364 int icode;
3365 if (cond == NULL_RTX)
3367 gcc_assert (!doit);
3368 return false;
3371 if (get_attr_predicable (insn) == PREDICABLE_YES
3372 && GET_CODE (PATTERN (insn)) != COND_EXEC)
3374 if (doit)
3376 rtx newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3377 PATTERN (insn) = newpat;
3378 INSN_CODE (insn) = -1;
3380 return true;
3382 if (GET_CODE (PATTERN (insn)) == COND_EXEC
3383 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn)), cond))
3384 return true;
3385 icode = INSN_CODE (insn);
3386 if (icode == CODE_FOR_real_jump
3387 || icode == CODE_FOR_jump
3388 || icode == CODE_FOR_indirect_jump)
3390 rtx pat = PATTERN (insn);
3391 rtx dest = (icode == CODE_FOR_real_jump ? XVECEXP (pat, 0, 0)
3392 : icode == CODE_FOR_jump ? XEXP (SET_SRC (pat), 0)
3393 : SET_SRC (pat));
3394 if (doit)
3396 rtx newpat;
3397 if (REG_P (dest))
3398 newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3399 else
3400 newpat = gen_br_true (cond, XEXP (cond, 0), dest);
3401 PATTERN (insn) = newpat;
3402 INSN_CODE (insn) = -1;
3404 return true;
3406 if (INSN_CODE (insn) == CODE_FOR_br_true)
3408 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3409 return rtx_equal_p (br_cond, cond);
3411 if (INSN_CODE (insn) == CODE_FOR_br_false)
3413 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3414 return conditions_opposite_p (br_cond, cond);
3416 return false;
3419 /* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3420 static void
3421 init_sched_state (c6x_sched_context_t sc)
3423 sc->last_scheduled_insn = NULL_RTX;
3424 sc->issued_this_cycle = 0;
3425 memset (sc->jump_cycles, 0, sizeof sc->jump_cycles);
3426 memset (sc->jump_cond, 0, sizeof sc->jump_cond);
3427 sc->jump_cycle_index = 0;
3428 sc->delays_finished_at = 0;
3429 sc->curr_sched_clock = 0;
3431 sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3433 memset (sc->reg_n_accesses, 0, sizeof sc->reg_n_accesses);
3434 memset (sc->reg_n_xaccesses, 0, sizeof sc->reg_n_xaccesses);
3435 memset (sc->reg_set_in_cycle, 0, sizeof sc->reg_set_in_cycle);
3437 state_reset (sc->prev_cycle_state_ctx);
3440 /* Allocate store for new scheduling context. */
3441 static void *
3442 c6x_alloc_sched_context (void)
3444 return xmalloc (sizeof (struct c6x_sched_context));
3447 /* If CLEAN_P is true then initializes _SC with clean data,
3448 and from the global context otherwise. */
3449 static void
3450 c6x_init_sched_context (void *_sc, bool clean_p)
3452 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3454 if (clean_p)
3456 init_sched_state (sc);
3458 else
3460 *sc = ss;
3461 sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3462 memcpy (sc->prev_cycle_state_ctx, prev_cycle_state, dfa_state_size);
3466 /* Sets the global scheduling context to the one pointed to by _SC. */
3467 static void
3468 c6x_set_sched_context (void *_sc)
3470 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3472 gcc_assert (sc != NULL);
3473 ss = *sc;
3474 memcpy (prev_cycle_state, sc->prev_cycle_state_ctx, dfa_state_size);
3477 /* Clear data in _SC. */
3478 static void
3479 c6x_clear_sched_context (void *_sc)
3481 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3482 gcc_assert (_sc != NULL);
3484 free (sc->prev_cycle_state_ctx);
3487 /* Free _SC. */
3488 static void
3489 c6x_free_sched_context (void *_sc)
3491 free (_sc);
3494 /* Provide information about speculation capabilities, and set the
3495 DO_BACKTRACKING flag. */
3496 static void
3497 c6x_set_sched_flags (spec_info_t spec_info)
3499 unsigned int *flags = &(current_sched_info->flags);
3501 if (*flags & SCHED_EBB)
3503 *flags |= DO_BACKTRACKING;
3506 spec_info->mask = 0;
3509 /* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3511 static int
3512 c6x_issue_rate (void)
3514 return 8;
3517 /* Used together with the collapse_ndfa option, this ensures that we reach a
3518 deterministic automaton state before trying to advance a cycle.
3519 With collapse_ndfa, genautomata creates advance cycle arcs only for
3520 such deterministic states. */
3522 static rtx
3523 c6x_sched_dfa_pre_cycle_insn (void)
3525 return const0_rtx;
3528 /* We're beginning a new block. Initialize data structures as necessary. */
3530 static void
3531 c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED,
3532 int sched_verbose ATTRIBUTE_UNUSED,
3533 int max_ready ATTRIBUTE_UNUSED)
3535 if (prev_cycle_state == NULL)
3537 prev_cycle_state = xmalloc (dfa_state_size);
3539 init_sched_state (&ss);
3540 state_reset (prev_cycle_state);
3543 /* We are about to being issuing INSN. Return nonzero if we cannot
3544 issue it on given cycle CLOCK and return zero if we should not sort
3545 the ready queue on the next clock start.
3546 For C6X, we use this function just to copy the previous DFA state
3547 for comparison purposes. */
3549 static int
3550 c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
3551 rtx insn ATTRIBUTE_UNUSED, int last_clock ATTRIBUTE_UNUSED,
3552 int clock ATTRIBUTE_UNUSED, int *sort_p ATTRIBUTE_UNUSED)
3554 if (clock != last_clock)
3555 memcpy (prev_cycle_state, curr_state, dfa_state_size);
3556 return 0;
3559 static void
3560 c6x_mark_regno_read (int regno, bool cross)
3562 int t = ++ss.tmp_reg_n_accesses[regno];
3564 if (t > 4)
3565 reg_access_stall = true;
3567 if (cross)
3569 int set_cycle = ss.reg_set_in_cycle[regno];
3570 /* This must be done in this way rather than by tweaking things in
3571 adjust_cost, since the stall occurs even for insns with opposite
3572 predicates, and the scheduler may not even see a dependency. */
3573 if (set_cycle > 0 && set_cycle == ss.curr_sched_clock)
3574 reg_access_stall = true;
3575 /* This doesn't quite do anything yet as we're only modeling one
3576 x unit. */
3577 ++ss.tmp_reg_n_xaccesses[regno];
3581 /* Note that REG is read in the insn being examined. If CROSS, it
3582 means the access is through a cross path. Update the temporary reg
3583 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
3584 in the current cycle. */
3586 static void
3587 c6x_mark_reg_read (rtx reg, bool cross)
3589 unsigned regno = REGNO (reg);
3590 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
3592 while (nregs-- > 0)
3593 c6x_mark_regno_read (regno + nregs, cross);
3596 /* Note that register REG is written in cycle CYCLES. */
3598 static void
3599 c6x_mark_reg_written (rtx reg, int cycles)
3601 unsigned regno = REGNO (reg);
3602 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
3604 while (nregs-- > 0)
3605 ss.reg_set_in_cycle[regno + nregs] = cycles;
3608 /* Update the register state information for an instruction whose
3609 body is X. Return true if the instruction has to be delayed until the
3610 next cycle. */
3612 static bool
3613 c6x_registers_update (rtx insn)
3615 enum attr_cross cross;
3616 enum attr_dest_regfile destrf;
3617 int i, nops;
3618 rtx x;
3620 if (!reload_completed || recog_memoized (insn) < 0)
3621 return false;
3623 reg_access_stall = false;
3624 memcpy (ss.tmp_reg_n_accesses, ss.reg_n_accesses,
3625 sizeof ss.tmp_reg_n_accesses);
3626 memcpy (ss.tmp_reg_n_xaccesses, ss.reg_n_xaccesses,
3627 sizeof ss.tmp_reg_n_xaccesses);
3629 extract_insn (insn);
3631 cross = get_attr_cross (insn);
3632 destrf = get_attr_dest_regfile (insn);
3634 nops = recog_data.n_operands;
3635 x = PATTERN (insn);
3636 if (GET_CODE (x) == COND_EXEC)
3638 c6x_mark_reg_read (XEXP (XEXP (x, 0), 0), false);
3639 nops -= 2;
3642 for (i = 0; i < nops; i++)
3644 rtx op = recog_data.operand[i];
3645 if (recog_data.operand_type[i] == OP_OUT)
3646 continue;
3647 if (REG_P (op))
3649 bool this_cross = cross;
3650 if (destrf == DEST_REGFILE_A && A_REGNO_P (REGNO (op)))
3651 this_cross = false;
3652 if (destrf == DEST_REGFILE_B && B_REGNO_P (REGNO (op)))
3653 this_cross = false;
3654 c6x_mark_reg_read (op, this_cross);
3656 else if (MEM_P (op))
3658 op = XEXP (op, 0);
3659 switch (GET_CODE (op))
3661 case POST_INC:
3662 case PRE_INC:
3663 case POST_DEC:
3664 case PRE_DEC:
3665 op = XEXP (op, 0);
3666 /* fall through */
3667 case REG:
3668 c6x_mark_reg_read (op, false);
3669 break;
3670 case POST_MODIFY:
3671 case PRE_MODIFY:
3672 op = XEXP (op, 1);
3673 gcc_assert (GET_CODE (op) == PLUS);
3674 /* fall through */
3675 case PLUS:
3676 c6x_mark_reg_read (XEXP (op, 0), false);
3677 if (REG_P (XEXP (op, 1)))
3678 c6x_mark_reg_read (XEXP (op, 1), false);
3679 break;
3680 case SYMBOL_REF:
3681 case LABEL_REF:
3682 case CONST:
3683 c6x_mark_regno_read (REG_B14, false);
3684 break;
3685 default:
3686 gcc_unreachable ();
3689 else if (!CONSTANT_P (op) && strlen (recog_data.constraints[i]) > 0)
3690 gcc_unreachable ();
3692 return reg_access_stall;
3695 /* Helper function for the TARGET_SCHED_REORDER and
3696 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
3697 in the current cycle, move it down in the ready list and return the
3698 number of non-unsafe insns. */
3700 static int
3701 c6x_sched_reorder_1 (rtx *ready, int *pn_ready, int clock_var)
3703 int n_ready = *pn_ready;
3704 rtx *e_ready = ready + n_ready;
3705 rtx *insnp;
3706 int first_jump;
3708 /* Keep track of conflicts due to a limit number of register accesses,
3709 and due to stalls incurred by too early accesses of registers using
3710 cross paths. */
3712 for (insnp = ready; insnp < e_ready; insnp++)
3714 rtx insn = *insnp;
3715 int icode = recog_memoized (insn);
3716 bool is_asm = (icode < 0
3717 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
3718 || asm_noperands (PATTERN (insn)) >= 0));
3719 bool no_parallel = (is_asm
3720 || (icode >= 0
3721 && get_attr_type (insn) == TYPE_ATOMIC));
3723 /* We delay asm insns until all delay slots are exhausted. We can't
3724 accurately tell how many cycles an asm takes, and the main scheduling
3725 code always assumes at least 1 cycle, which may be wrong. */
3726 if ((no_parallel
3727 && (ss.issued_this_cycle > 0 || clock_var < ss.delays_finished_at))
3728 || c6x_registers_update (insn))
3730 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3731 *ready = insn;
3732 n_ready--;
3733 ready++;
3735 else if (shadow_p (insn))
3737 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3738 *ready = insn;
3742 /* Ensure that no other jump is scheduled in jump delay slots, since
3743 it would put the machine into the wrong state. Also, we must
3744 avoid scheduling insns that have a latency longer than the
3745 remaining jump delay slots, as the code at the jump destination
3746 won't be prepared for it.
3748 However, we can relax this condition somewhat. The rest of the
3749 scheduler will automatically avoid scheduling an insn on which
3750 the jump shadow depends so late that its side effect happens
3751 after the jump. This means that if we see an insn with a longer
3752 latency here, it can safely be scheduled if we can ensure that it
3753 has a predicate opposite of the previous jump: the side effect
3754 will happen in what we think of as the same basic block. In
3755 c6x_variable_issue, we will record the necessary predicate in
3756 new_conditions, and after scheduling is finished, we will modify
3757 the insn.
3759 Special care must be taken whenever there is more than one jump
3760 in flight. */
3762 first_jump = first_jump_index (clock_var);
3763 if (first_jump != -1)
3765 int first_cycle = get_jump_cycle (first_jump);
3766 rtx first_cond = get_jump_cond (first_jump);
3767 int second_cycle = 0;
3769 if (first_jump > 0)
3770 second_cycle = get_jump_cycle (first_jump - 1);
3772 for (insnp = ready; insnp < e_ready; insnp++)
3774 rtx insn = *insnp;
3775 int icode = recog_memoized (insn);
3776 bool is_asm = (icode < 0
3777 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
3778 || asm_noperands (PATTERN (insn)) >= 0));
3779 int this_cycles;
3780 enum attr_type type;
3782 gcc_assert (!is_asm);
3783 if (icode < 0)
3784 continue;
3785 this_cycles = get_attr_cycles (insn);
3786 type = get_attr_type (insn);
3787 /* Treat branches specially; there is also a hazard if two jumps
3788 end at the same cycle. */
3789 if (type == TYPE_BRANCH || type == TYPE_CALL)
3790 this_cycles++;
3791 if (clock_var + this_cycles <= first_cycle)
3792 continue;
3793 if ((first_jump > 0 && clock_var + this_cycles > second_cycle)
3794 || !predicate_insn (insn, first_cond, false))
3796 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3797 *ready = insn;
3798 n_ready--;
3799 ready++;
3804 return n_ready;
3807 /* Implement the TARGET_SCHED_REORDER hook. We save the current clock
3808 for later and clear the register access information for the new
3809 cycle. We also move asm statements out of the way if they would be
3810 scheduled in a delay slot. */
3812 static int
3813 c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
3814 int sched_verbose ATTRIBUTE_UNUSED,
3815 rtx *ready ATTRIBUTE_UNUSED,
3816 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
3818 ss.curr_sched_clock = clock_var;
3819 ss.issued_this_cycle = 0;
3820 memset (ss.reg_n_accesses, 0, sizeof ss.reg_n_accesses);
3821 memset (ss.reg_n_xaccesses, 0, sizeof ss.reg_n_xaccesses);
3823 if (ready == NULL)
3824 return 0;
3826 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
3829 /* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
3830 cycle for every insn. */
3832 static int
3833 c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
3834 int sched_verbose ATTRIBUTE_UNUSED,
3835 rtx *ready ATTRIBUTE_UNUSED,
3836 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
3838 /* FIXME: the assembler rejects labels inside an execute packet.
3839 This can occur if prologue insns are scheduled in parallel with
3840 others, so we avoid this here. Also make sure that nothing is
3841 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
3842 if (RTX_FRAME_RELATED_P (ss.last_scheduled_insn)
3843 || JUMP_P (ss.last_scheduled_insn)
3844 || (recog_memoized (ss.last_scheduled_insn) >= 0
3845 && get_attr_type (ss.last_scheduled_insn) == TYPE_ATOMIC))
3847 int n_ready = *pn_ready;
3848 rtx *e_ready = ready + n_ready;
3849 rtx *insnp;
3851 for (insnp = ready; insnp < e_ready; insnp++)
3853 rtx insn = *insnp;
3854 if (!shadow_p (insn))
3856 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
3857 *ready = insn;
3858 n_ready--;
3859 ready++;
3862 return n_ready;
3865 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
3868 /* Subroutine of maybe_clobber_cond, called through note_stores. */
3870 static void
3871 clobber_cond_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data1)
3873 rtx *cond = (rtx *)data1;
3874 if (*cond != NULL_RTX && reg_overlap_mentioned_p (x, *cond))
3875 *cond = NULL_RTX;
3878 /* Examine INSN, and if it destroys the conditions have recorded for
3879 any of the jumps in flight, clear that condition so that we don't
3880 predicate any more insns. CLOCK_VAR helps us limit the search to
3881 only those jumps which are still in flight. */
3883 static void
3884 maybe_clobber_cond (rtx insn, int clock_var)
3886 int n, idx;
3887 idx = ss.jump_cycle_index;
3888 for (n = 0; n < 12; n++, idx++)
3890 rtx cond, link;
3891 int cycle;
3893 if (idx >= 12)
3894 idx -= 12;
3895 cycle = ss.jump_cycles[idx];
3896 if (cycle <= clock_var)
3897 return;
3899 cond = ss.jump_cond[idx];
3900 if (cond == NULL_RTX)
3901 continue;
3903 if (CALL_P (insn))
3905 ss.jump_cond[idx] = NULL_RTX;
3906 continue;
3909 note_stores (PATTERN (insn), clobber_cond_1, ss.jump_cond + idx);
3910 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
3911 if (REG_NOTE_KIND (link) == REG_INC)
3912 clobber_cond_1 (XEXP (link, 0), NULL_RTX, ss.jump_cond + idx);
3916 /* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
3917 issue INSN. Return the number of insns left on the ready queue
3918 that can be issued this cycle.
3919 We use this hook to record clock cycles and reservations for every insn. */
3921 static int
3922 c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
3923 int sched_verbose ATTRIBUTE_UNUSED,
3924 rtx insn, int can_issue_more ATTRIBUTE_UNUSED)
3926 ss.last_scheduled_insn = insn;
3927 if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
3928 ss.issued_this_cycle++;
3929 if (insn_info)
3931 state_t st_after = alloca (dfa_state_size);
3932 int curr_clock = ss.curr_sched_clock;
3933 int uid = INSN_UID (insn);
3934 int icode = recog_memoized (insn);
3935 rtx first_cond;
3936 int first, first_cycle;
3937 unsigned int mask;
3938 int i;
3940 insn_set_clock (insn, curr_clock);
3941 INSN_INFO_ENTRY (uid).ebb_start
3942 = curr_clock == 0 && ss.issued_this_cycle == 1;
3944 first = first_jump_index (ss.curr_sched_clock);
3945 if (first == -1)
3947 first_cycle = 0;
3948 first_cond = NULL_RTX;
3950 else
3952 first_cycle = get_jump_cycle (first);
3953 first_cond = get_jump_cond (first);
3955 if (icode >= 0
3956 && first_cycle > curr_clock
3957 && first_cond != NULL_RTX
3958 && (curr_clock + get_attr_cycles (insn) > first_cycle
3959 || get_attr_type (insn) == TYPE_BRANCH
3960 || get_attr_type (insn) == TYPE_CALL))
3961 INSN_INFO_ENTRY (uid).new_cond = first_cond;
3963 memcpy (st_after, curr_state, dfa_state_size);
3964 state_transition (st_after, const0_rtx);
3966 mask = 0;
3967 for (i = 0; i < 2 * UNIT_QID_SIDE_OFFSET; i++)
3968 if (cpu_unit_reservation_p (st_after, c6x_unit_codes[i])
3969 && !cpu_unit_reservation_p (prev_cycle_state, c6x_unit_codes[i]))
3970 mask |= 1 << i;
3971 INSN_INFO_ENTRY (uid).unit_mask = mask;
3973 maybe_clobber_cond (insn, curr_clock);
3975 if (icode >= 0)
3977 int i, cycles;
3979 c6x_registers_update (insn);
3980 memcpy (ss.reg_n_accesses, ss.tmp_reg_n_accesses,
3981 sizeof ss.reg_n_accesses);
3982 memcpy (ss.reg_n_xaccesses, ss.tmp_reg_n_accesses,
3983 sizeof ss.reg_n_xaccesses);
3985 cycles = get_attr_cycles (insn);
3986 if (ss.delays_finished_at < ss.curr_sched_clock + cycles)
3987 ss.delays_finished_at = ss.curr_sched_clock + cycles;
3988 if (get_attr_type (insn) == TYPE_BRANCH
3989 || get_attr_type (insn) == TYPE_CALL)
3991 rtx opposite = condjump_opposite_condition (insn);
3992 record_jump (ss.curr_sched_clock + cycles, opposite);
3995 /* Mark the cycles in which the destination registers are written.
3996 This is used for calculating stalls when using cross units. */
3997 extract_insn (insn);
3998 /* Cross-path stalls don't apply to results of load insns. */
3999 if (get_attr_type (insn) == TYPE_LOAD
4000 || get_attr_type (insn) == TYPE_LOADN
4001 || get_attr_type (insn) == TYPE_LOAD_SHADOW)
4002 cycles--;
4003 for (i = 0; i < recog_data.n_operands; i++)
4005 rtx op = recog_data.operand[i];
4006 if (MEM_P (op))
4008 rtx addr = XEXP (op, 0);
4009 if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
4010 c6x_mark_reg_written (XEXP (addr, 0),
4011 insn_uid_get_clock (uid) + 1);
4013 if (recog_data.operand_type[i] != OP_IN
4014 && REG_P (op))
4016 c6x_mark_reg_written (op,
4017 insn_uid_get_clock (uid) + cycles);
4022 return can_issue_more;
4025 /* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4026 anti- and output dependencies. */
4028 static int
4029 c6x_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4031 enum attr_type insn_type = TYPE_UNKNOWN, dep_insn_type = TYPE_UNKNOWN;
4032 int dep_insn_code_number, insn_code_number;
4033 int shadow_bonus = 0;
4034 enum reg_note kind;
4035 dep_insn_code_number = recog_memoized (dep_insn);
4036 insn_code_number = recog_memoized (insn);
4038 if (dep_insn_code_number >= 0)
4039 dep_insn_type = get_attr_type (dep_insn);
4041 if (insn_code_number >= 0)
4042 insn_type = get_attr_type (insn);
4044 kind = REG_NOTE_KIND (link);
4045 if (kind == 0)
4047 /* If we have a dependency on a load, and it's not for the result of
4048 the load, it must be for an autoincrement. Reduce the cost in that
4049 case. */
4050 if (dep_insn_type == TYPE_LOAD)
4052 rtx set = PATTERN (dep_insn);
4053 if (GET_CODE (set) == COND_EXEC)
4054 set = COND_EXEC_CODE (set);
4055 if (GET_CODE (set) == UNSPEC)
4056 cost = 1;
4057 else
4059 gcc_assert (GET_CODE (set) == SET);
4060 if (!reg_overlap_mentioned_p (SET_DEST (set), PATTERN (insn)))
4061 cost = 1;
4066 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4067 it occurs in between two cycles, but we schedule it at the end of the
4068 first cycle. */
4069 if (shadow_type_p (insn_type))
4070 shadow_bonus = 1;
4072 /* Anti and output dependencies usually have zero cost, but we want
4073 to insert a stall after a jump, and after certain floating point
4074 insns that take more than one cycle to read their inputs. In the
4075 future, we should try to find a better algorithm for scheduling
4076 jumps. */
4077 if (kind != 0)
4079 /* We can get anti-dependencies against shadow insns. Treat these
4080 like output dependencies, so that the insn is entirely finished
4081 before the branch takes place. */
4082 if (kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW)
4083 kind = REG_DEP_OUTPUT;
4084 switch (dep_insn_type)
4086 case TYPE_CALLP:
4087 return 1;
4088 case TYPE_BRANCH:
4089 case TYPE_CALL:
4090 if (get_attr_has_shadow (dep_insn) == HAS_SHADOW_Y)
4091 /* This is a real_jump/real_call insn. These don't have
4092 outputs, and ensuring the validity of scheduling things
4093 in the delay slot is the job of
4094 c6x_sched_reorder_1. */
4095 return 0;
4096 /* Unsplit calls can happen - e.g. for divide insns. */
4097 return 6;
4098 case TYPE_LOAD:
4099 case TYPE_LOADN:
4100 case TYPE_INTDP:
4101 if (kind == REG_DEP_OUTPUT)
4102 return 5 - shadow_bonus;
4103 return 0;
4104 case TYPE_MPY4:
4105 case TYPE_FP4:
4106 if (kind == REG_DEP_OUTPUT)
4107 return 4 - shadow_bonus;
4108 return 0;
4109 case TYPE_MPY2:
4110 if (kind == REG_DEP_OUTPUT)
4111 return 2 - shadow_bonus;
4112 return 0;
4113 case TYPE_CMPDP:
4114 if (kind == REG_DEP_OUTPUT)
4115 return 2 - shadow_bonus;
4116 return 2;
4117 case TYPE_ADDDP:
4118 case TYPE_MPYSPDP:
4119 if (kind == REG_DEP_OUTPUT)
4120 return 7 - shadow_bonus;
4121 return 2;
4122 case TYPE_MPYSP2DP:
4123 if (kind == REG_DEP_OUTPUT)
4124 return 5 - shadow_bonus;
4125 return 2;
4126 case TYPE_MPYI:
4127 if (kind == REG_DEP_OUTPUT)
4128 return 9 - shadow_bonus;
4129 return 4;
4130 case TYPE_MPYID:
4131 case TYPE_MPYDP:
4132 if (kind == REG_DEP_OUTPUT)
4133 return 10 - shadow_bonus;
4134 return 4;
4136 default:
4137 if (insn_type == TYPE_SPKERNEL)
4138 return 0;
4139 if (kind == REG_DEP_OUTPUT)
4140 return 1 - shadow_bonus;
4142 return 0;
4146 return cost - shadow_bonus;
4149 /* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4150 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4151 first in the original stream. */
4153 static void
4154 gen_one_bundle (rtx *slot, int n_filled, int real_first)
4156 rtx bundle;
4157 rtx t;
4158 int i;
4160 bundle = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec_v (n_filled, slot));
4161 bundle = make_insn_raw (bundle);
4162 BLOCK_FOR_INSN (bundle) = BLOCK_FOR_INSN (slot[0]);
4163 INSN_LOCATOR (bundle) = INSN_LOCATOR (slot[0]);
4164 PREV_INSN (bundle) = PREV_INSN (slot[real_first]);
4166 t = NULL_RTX;
4168 for (i = 0; i < n_filled; i++)
4170 rtx insn = slot[i];
4171 remove_insn (insn);
4172 PREV_INSN (insn) = t ? t : PREV_INSN (bundle);
4173 if (t != NULL_RTX)
4174 NEXT_INSN (t) = insn;
4175 t = insn;
4176 if (i > 0)
4177 INSN_LOCATOR (slot[i]) = INSN_LOCATOR (bundle);
4180 NEXT_INSN (bundle) = NEXT_INSN (PREV_INSN (bundle));
4181 NEXT_INSN (t) = NEXT_INSN (bundle);
4182 NEXT_INSN (PREV_INSN (bundle)) = bundle;
4183 PREV_INSN (NEXT_INSN (bundle)) = bundle;
4186 /* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4187 try to insert labels in the middle. */
4189 static void
4190 c6x_gen_bundles (void)
4192 basic_block bb;
4193 rtx insn, next, last_call;
4195 FOR_EACH_BB (bb)
4197 rtx insn, next;
4198 /* The machine is eight insns wide. We can have up to six shadow
4199 insns, plus an extra slot for merging the jump shadow. */
4200 rtx slot[15];
4201 int n_filled = 0;
4202 int first_slot = 0;
4204 for (insn = BB_HEAD (bb);; insn = next)
4206 int at_end;
4207 rtx delete_this = NULL_RTX;
4209 if (NONDEBUG_INSN_P (insn))
4211 /* Put calls at the start of the sequence. */
4212 if (CALL_P (insn))
4214 first_slot++;
4215 if (n_filled)
4217 memmove (&slot[1], &slot[0],
4218 n_filled * sizeof (slot[0]));
4220 if (!shadow_p (insn))
4222 PUT_MODE (insn, TImode);
4223 if (n_filled)
4224 PUT_MODE (slot[1], VOIDmode);
4226 n_filled++;
4227 slot[0] = insn;
4229 else
4231 slot[n_filled++] = insn;
4235 next = NEXT_INSN (insn);
4236 while (next && insn != BB_END (bb)
4237 && !(NONDEBUG_INSN_P (next)
4238 && GET_CODE (PATTERN (next)) != USE
4239 && GET_CODE (PATTERN (next)) != CLOBBER))
4241 insn = next;
4242 next = NEXT_INSN (insn);
4245 at_end = insn == BB_END (bb);
4246 if (delete_this == NULL_RTX
4247 && (at_end || (GET_MODE (next) == TImode
4248 && !(shadow_p (next) && CALL_P (next)))))
4250 if (n_filled >= 2)
4251 gen_one_bundle (slot, n_filled, first_slot);
4253 n_filled = 0;
4254 first_slot = 0;
4256 if (at_end)
4257 break;
4260 /* Bundling, and emitting nops, can separate
4261 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4262 that up here. */
4263 last_call = NULL_RTX;
4264 for (insn = get_insns (); insn; insn = next)
4266 next = NEXT_INSN (insn);
4267 if (CALL_P (insn)
4268 || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE
4269 && CALL_P (XVECEXP (PATTERN (insn), 0, 0))))
4270 last_call = insn;
4271 if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION)
4272 continue;
4273 if (NEXT_INSN (last_call) == insn)
4274 continue;
4275 NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
4276 PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
4277 PREV_INSN (insn) = last_call;
4278 NEXT_INSN (insn) = NEXT_INSN (last_call);
4279 PREV_INSN (NEXT_INSN (insn)) = insn;
4280 NEXT_INSN (PREV_INSN (insn)) = insn;
4281 last_call = insn;
4285 /* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4287 static rtx
4288 emit_nop_after (int cycles, rtx after)
4290 rtx insn;
4292 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4293 operation. We don't need the extra NOP since in this case, the hardware
4294 will automatically insert the required stall. */
4295 if (cycles == 10)
4296 cycles--;
4298 gcc_assert (cycles < 10);
4300 insn = emit_insn_after (gen_nop_count (GEN_INT (cycles)), after);
4301 PUT_MODE (insn, TImode);
4303 return insn;
4306 /* Determine whether INSN is a call that needs to have a return label
4307 placed. */
4309 static bool
4310 returning_call_p (rtx insn)
4312 if (CALL_P (insn))
4313 return (!SIBLING_CALL_P (insn)
4314 && get_attr_type (insn) != TYPE_CALLP
4315 && get_attr_type (insn) != TYPE_SHADOW);
4316 if (recog_memoized (insn) < 0)
4317 return false;
4318 if (get_attr_type (insn) == TYPE_CALL)
4319 return true;
4320 return false;
4323 /* Determine whether INSN's pattern can be converted to use callp. */
4324 static bool
4325 can_use_callp (rtx insn)
4327 int icode = recog_memoized (insn);
4328 if (!TARGET_INSNS_64PLUS
4329 || icode < 0
4330 || GET_CODE (PATTERN (insn)) == COND_EXEC)
4331 return false;
4333 return ((icode == CODE_FOR_real_call
4334 || icode == CODE_FOR_call_internal
4335 || icode == CODE_FOR_call_value_internal)
4336 && get_attr_dest_regfile (insn) == DEST_REGFILE_ANY);
4339 /* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4340 static void
4341 convert_to_callp (rtx insn)
4343 rtx lab;
4344 extract_insn (insn);
4345 if (GET_CODE (PATTERN (insn)) == SET)
4347 rtx dest = recog_data.operand[0];
4348 lab = recog_data.operand[1];
4349 PATTERN (insn) = gen_callp_value (dest, lab);
4350 INSN_CODE (insn) = CODE_FOR_callp_value;
4352 else
4354 lab = recog_data.operand[0];
4355 PATTERN (insn) = gen_callp (lab);
4356 INSN_CODE (insn) = CODE_FOR_callp;
4360 /* Scan forwards from INSN until we find the next insn that has mode TImode
4361 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4362 Return it if we find such an insn, NULL_RTX otherwise. */
4363 static rtx
4364 find_next_cycle_insn (rtx insn, int clock)
4366 rtx t = insn;
4367 if (GET_MODE (t) == TImode)
4368 t = next_real_insn (t);
4369 while (t && GET_MODE (t) != TImode)
4370 t = next_real_insn (t);
4372 if (t && insn_get_clock (t) == clock)
4373 return t;
4374 return NULL_RTX;
4377 /* If COND_INSN has a COND_EXEC condition, wrap the same condition
4378 around PAT. Return PAT either unchanged or modified in this
4379 way. */
4380 static rtx
4381 duplicate_cond (rtx pat, rtx cond_insn)
4383 rtx cond_pat = PATTERN (cond_insn);
4384 if (GET_CODE (cond_pat) == COND_EXEC)
4385 pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (cond_pat)),
4386 pat);
4387 return pat;
4390 /* Walk forward from INSN to find the last insn that issues in the same clock
4391 cycle. */
4392 static rtx
4393 find_last_same_clock (rtx insn)
4395 rtx retval = insn;
4396 rtx t = next_real_insn (insn);
4398 while (t && GET_MODE (t) != TImode)
4400 if (!DEBUG_INSN_P (t) && recog_memoized (t) >= 0)
4401 retval = t;
4402 t = next_real_insn (t);
4404 return retval;
4407 /* For every call insn in the function, emit code to load the return
4408 address. For each call we create a return label and store it in
4409 CALL_LABELS. If are not scheduling, we emit the labels here,
4410 otherwise the caller will do it later.
4411 This function is called after final insn scheduling, but before creating
4412 the SEQUENCEs that represent execute packets. */
4414 static void
4415 reorg_split_calls (rtx *call_labels)
4417 unsigned int reservation_mask = 0;
4418 rtx insn = get_insns ();
4419 gcc_assert (GET_CODE (insn) == NOTE);
4420 insn = next_real_insn (insn);
4421 while (insn)
4423 int uid;
4424 rtx next = next_real_insn (insn);
4426 if (DEBUG_INSN_P (insn))
4427 goto done;
4429 if (GET_MODE (insn) == TImode)
4430 reservation_mask = 0;
4431 uid = INSN_UID (insn);
4432 if (c6x_flag_schedule_insns2 && recog_memoized (insn) >= 0)
4433 reservation_mask |= 1 << INSN_INFO_ENTRY (uid).reservation;
4435 if (returning_call_p (insn))
4437 rtx label = gen_label_rtx ();
4438 rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
4439 rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
4441 LABEL_NUSES (label) = 2;
4442 if (!c6x_flag_schedule_insns2)
4444 if (can_use_callp (insn))
4445 convert_to_callp (insn);
4446 else
4448 rtx t;
4449 rtx slot[4];
4450 emit_label_after (label, insn);
4452 /* Bundle the call and its delay slots into a single
4453 SEQUENCE. While these do not issue in parallel
4454 we need to group them into a single EH region. */
4455 slot[0] = insn;
4456 PUT_MODE (insn, TImode);
4457 if (TARGET_INSNS_64)
4459 t = gen_addkpc (reg, labelref, GEN_INT (4));
4460 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4461 insn);
4462 PUT_MODE (slot[1], TImode);
4463 gen_one_bundle (slot, 2, 0);
4465 else
4467 slot[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4468 insn);
4469 PUT_MODE (slot[3], TImode);
4470 t = gen_movsi_lo_sum (reg, reg, labelref);
4471 slot[2] = emit_insn_after (duplicate_cond (t, insn),
4472 insn);
4473 PUT_MODE (slot[2], TImode);
4474 t = gen_movsi_high (reg, labelref);
4475 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4476 insn);
4477 PUT_MODE (slot[1], TImode);
4478 gen_one_bundle (slot, 4, 0);
4482 else
4484 /* If we scheduled, we reserved the .S2 unit for one or two
4485 cycles after the call. Emit the insns in these slots,
4486 unless it's possible to create a CALLP insn.
4487 Note that this works because the dependencies ensure that
4488 no insn setting/using B3 is scheduled in the delay slots of
4489 a call. */
4490 int this_clock = insn_get_clock (insn);
4491 rtx last_same_clock;
4492 rtx after1;
4494 call_labels[INSN_UID (insn)] = label;
4496 last_same_clock = find_last_same_clock (insn);
4498 if (can_use_callp (insn))
4500 /* Find the first insn of the next execute packet. If it
4501 is the shadow insn corresponding to this call, we may
4502 use a CALLP insn. */
4503 rtx shadow = next_nonnote_nondebug_insn (last_same_clock);
4505 if (CALL_P (shadow)
4506 && insn_get_clock (shadow) == this_clock + 5)
4508 convert_to_callp (shadow);
4509 insn_set_clock (shadow, this_clock);
4510 INSN_INFO_ENTRY (INSN_UID (shadow)).reservation
4511 = RESERVATION_S2;
4512 INSN_INFO_ENTRY (INSN_UID (shadow)).unit_mask
4513 = INSN_INFO_ENTRY (INSN_UID (last_same_clock)).unit_mask;
4514 if (GET_MODE (insn) == TImode)
4516 rtx new_cycle_first = NEXT_INSN (insn);
4517 while (!NONDEBUG_INSN_P (new_cycle_first)
4518 || GET_CODE (PATTERN (new_cycle_first)) == USE
4519 || GET_CODE (PATTERN (new_cycle_first)) == CLOBBER)
4520 new_cycle_first = NEXT_INSN (new_cycle_first);
4521 PUT_MODE (new_cycle_first, TImode);
4522 if (new_cycle_first != shadow)
4523 PUT_MODE (shadow, VOIDmode);
4524 INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
4525 = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
4527 else
4528 PUT_MODE (shadow, VOIDmode);
4529 delete_insn (insn);
4530 goto done;
4533 after1 = find_next_cycle_insn (last_same_clock, this_clock + 1);
4534 if (after1 == NULL_RTX)
4535 after1 = last_same_clock;
4536 else
4537 after1 = find_last_same_clock (after1);
4538 if (TARGET_INSNS_64)
4540 rtx x1 = gen_addkpc (reg, labelref, const0_rtx);
4541 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4542 insn_set_clock (x1, this_clock + 1);
4543 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4544 if (after1 == last_same_clock)
4545 PUT_MODE (x1, TImode);
4546 else
4547 INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
4548 = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
4550 else
4552 rtx x1, x2;
4553 rtx after2 = find_next_cycle_insn (after1, this_clock + 2);
4554 if (after2 == NULL_RTX)
4555 after2 = after1;
4556 x2 = gen_movsi_lo_sum (reg, reg, labelref);
4557 x2 = emit_insn_after (duplicate_cond (x2, insn), after2);
4558 x1 = gen_movsi_high (reg, labelref);
4559 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4560 insn_set_clock (x1, this_clock + 1);
4561 insn_set_clock (x2, this_clock + 2);
4562 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4563 INSN_INFO_ENTRY (INSN_UID (x2)).reservation = RESERVATION_S2;
4564 if (after1 == last_same_clock)
4565 PUT_MODE (x1, TImode);
4566 else
4567 INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
4568 = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
4569 if (after1 == after2)
4570 PUT_MODE (x2, TImode);
4571 else
4572 INSN_INFO_ENTRY (INSN_UID (x2)).unit_mask
4573 = INSN_INFO_ENTRY (INSN_UID (after2)).unit_mask;
4577 done:
4578 insn = next;
4582 /* Called as part of c6x_reorg. This function emits multi-cycle NOP
4583 insns as required for correctness. CALL_LABELS is the array that
4584 holds the return labels for call insns; we emit these here if
4585 scheduling was run earlier. */
4587 static void
4588 reorg_emit_nops (rtx *call_labels)
4590 bool first;
4591 rtx prev, last_call;
4592 int prev_clock, earliest_bb_end;
4593 int prev_implicit_nops;
4594 rtx insn = get_insns ();
4596 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
4597 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
4598 clocks, we must insert a NOP.
4599 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
4600 current basic block will finish. We must not allow the next basic block to
4601 begin before this cycle.
4602 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
4603 a multi-cycle nop. The code is scheduled such that subsequent insns will
4604 show the cycle gap, but we needn't insert a real NOP instruction. */
4605 insn = next_real_insn (insn);
4606 last_call = prev = NULL_RTX;
4607 prev_clock = -1;
4608 earliest_bb_end = 0;
4609 prev_implicit_nops = 0;
4610 first = true;
4611 while (insn)
4613 int this_clock = -1;
4614 rtx next;
4615 int max_cycles = 0;
4617 next = next_real_insn (insn);
4619 if (DEBUG_INSN_P (insn)
4620 || GET_CODE (PATTERN (insn)) == USE
4621 || GET_CODE (PATTERN (insn)) == CLOBBER
4622 || shadow_or_blockage_p (insn)
4623 || (JUMP_P (insn)
4624 && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
4625 || GET_CODE (PATTERN (insn)) == ADDR_VEC)))
4626 goto next_insn;
4628 if (!c6x_flag_schedule_insns2)
4629 /* No scheduling; ensure that no parallel issue happens. */
4630 PUT_MODE (insn, TImode);
4631 else
4633 int cycles;
4635 this_clock = insn_get_clock (insn);
4636 if (this_clock != prev_clock)
4638 PUT_MODE (insn, TImode);
4640 if (!first)
4642 cycles = this_clock - prev_clock;
4644 cycles -= prev_implicit_nops;
4645 if (cycles > 1)
4647 rtx nop = emit_nop_after (cycles - 1, prev);
4648 insn_set_clock (nop, prev_clock + prev_implicit_nops + 1);
4651 prev_clock = this_clock;
4653 if (last_call
4654 && insn_get_clock (last_call) + 6 <= this_clock)
4656 emit_label_before (call_labels[INSN_UID (last_call)], insn);
4657 last_call = NULL_RTX;
4659 prev_implicit_nops = 0;
4663 /* Examine how many cycles the current insn takes, and adjust
4664 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
4665 if (recog_memoized (insn) >= 0
4666 /* If not scheduling, we've emitted NOPs after calls already. */
4667 && (c6x_flag_schedule_insns2 || !returning_call_p (insn)))
4669 max_cycles = get_attr_cycles (insn);
4670 if (get_attr_type (insn) == TYPE_CALLP)
4671 prev_implicit_nops = 5;
4673 else
4674 max_cycles = 1;
4675 if (returning_call_p (insn))
4676 last_call = insn;
4678 if (c6x_flag_schedule_insns2)
4680 gcc_assert (this_clock >= 0);
4681 if (earliest_bb_end < this_clock + max_cycles)
4682 earliest_bb_end = this_clock + max_cycles;
4684 else if (max_cycles > 1)
4685 emit_nop_after (max_cycles - 1, insn);
4687 prev = insn;
4688 first = false;
4690 next_insn:
4691 if (c6x_flag_schedule_insns2
4692 && (next == NULL_RTX
4693 || (GET_MODE (next) == TImode
4694 && INSN_INFO_ENTRY (INSN_UID (next)).ebb_start))
4695 && earliest_bb_end > 0)
4697 int cycles = earliest_bb_end - prev_clock;
4698 if (cycles > 1)
4700 prev = emit_nop_after (cycles - 1, prev);
4701 insn_set_clock (prev, prev_clock + prev_implicit_nops + 1);
4703 earliest_bb_end = 0;
4704 prev_clock = -1;
4705 first = true;
4707 if (last_call)
4708 emit_label_after (call_labels[INSN_UID (last_call)], prev);
4709 last_call = NULL_RTX;
4711 insn = next;
4715 /* If possible, split INSN, which we know is either a jump or a call, into a real
4716 insn and its shadow. */
4717 static void
4718 split_delayed_branch (rtx insn)
4720 int code = recog_memoized (insn);
4721 rtx i1, newpat;
4722 rtx pat = PATTERN (insn);
4724 if (GET_CODE (pat) == COND_EXEC)
4725 pat = COND_EXEC_CODE (pat);
4727 if (CALL_P (insn))
4729 rtx src = pat, dest = NULL_RTX;
4730 rtx callee;
4731 if (GET_CODE (pat) == SET)
4733 dest = SET_DEST (pat);
4734 src = SET_SRC (pat);
4736 callee = XEXP (XEXP (src, 0), 0);
4737 if (SIBLING_CALL_P (insn))
4739 if (REG_P (callee))
4740 newpat = gen_indirect_sibcall_shadow ();
4741 else
4742 newpat = gen_sibcall_shadow (callee);
4743 pat = gen_real_jump (callee);
4745 else if (dest != NULL_RTX)
4747 if (REG_P (callee))
4748 newpat = gen_indirect_call_value_shadow (dest);
4749 else
4750 newpat = gen_call_value_shadow (dest, callee);
4751 pat = gen_real_call (callee);
4753 else
4755 if (REG_P (callee))
4756 newpat = gen_indirect_call_shadow ();
4757 else
4758 newpat = gen_call_shadow (callee);
4759 pat = gen_real_call (callee);
4761 pat = duplicate_cond (pat, insn);
4762 newpat = duplicate_cond (newpat, insn);
4764 else
4766 rtx src, op;
4767 if (GET_CODE (pat) == PARALLEL
4768 && GET_CODE (XVECEXP (pat, 0, 0)) == RETURN)
4770 newpat = gen_return_shadow ();
4771 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
4772 newpat = duplicate_cond (newpat, insn);
4774 else
4775 switch (code)
4777 case CODE_FOR_br_true:
4778 case CODE_FOR_br_false:
4779 src = SET_SRC (pat);
4780 op = XEXP (src, code == CODE_FOR_br_true ? 1 : 2);
4781 newpat = gen_condjump_shadow (op);
4782 pat = gen_real_jump (op);
4783 if (code == CODE_FOR_br_true)
4784 pat = gen_rtx_COND_EXEC (VOIDmode, XEXP (src, 0), pat);
4785 else
4786 pat = gen_rtx_COND_EXEC (VOIDmode,
4787 reversed_comparison (XEXP (src, 0),
4788 VOIDmode),
4789 pat);
4790 break;
4792 case CODE_FOR_jump:
4793 op = SET_SRC (pat);
4794 newpat = gen_jump_shadow (op);
4795 break;
4797 case CODE_FOR_indirect_jump:
4798 newpat = gen_indirect_jump_shadow ();
4799 break;
4801 case CODE_FOR_return_internal:
4802 newpat = gen_return_shadow ();
4803 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
4804 break;
4806 default:
4807 return;
4810 i1 = emit_insn_before (pat, insn);
4811 PATTERN (insn) = newpat;
4812 INSN_CODE (insn) = -1;
4813 record_delay_slot_pair (i1, insn, 5);
4816 /* Split every insn (i.e. jumps and calls) which can have delay slots into
4817 two parts: the first one is scheduled normally and emits the instruction,
4818 while the second one is a shadow insn which shows the side effect taking
4819 place. The second one is placed in the right cycle by the scheduler, but
4820 not emitted as an assembly instruction. */
4822 static void
4823 split_delayed_insns (void)
4825 rtx insn;
4826 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4828 if (JUMP_P (insn) || CALL_P (insn))
4829 split_delayed_branch (insn);
4833 /* For every insn that has an entry in the new_conditions vector, give it
4834 the appropriate predicate. */
4835 static void
4836 conditionalize_after_sched (void)
4838 basic_block bb;
4839 rtx insn;
4840 FOR_EACH_BB (bb)
4841 FOR_BB_INSNS (bb, insn)
4843 unsigned uid = INSN_UID (insn);
4844 rtx cond;
4845 if (!NONDEBUG_INSN_P (insn) || uid >= INSN_INFO_LENGTH)
4846 continue;
4847 cond = INSN_INFO_ENTRY (uid).new_cond;
4848 if (cond == NULL_RTX)
4849 continue;
4850 if (dump_file)
4851 fprintf (dump_file, "Conditionalizing insn %d\n", uid);
4852 predicate_insn (insn, cond, true);
4856 /* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
4857 into a sequence that loads the return register and performs the call,
4858 and emit the return label.
4859 If scheduling after reload is requested, it happens here. */
4861 static void
4862 c6x_reorg (void)
4864 basic_block bb;
4865 rtx *call_labels;
4866 bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
4867 && !maybe_skip_selective_scheduling ());
4869 /* We are freeing block_for_insn in the toplev to keep compatibility
4870 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4871 compute_bb_for_insn ();
4873 df_clear_flags (DF_LR_RUN_DCE);
4875 /* If optimizing, we'll have split before scheduling. */
4876 if (optimize == 0)
4877 split_all_insns ();
4879 if (c6x_flag_schedule_insns2)
4881 int sz = get_max_uid () * 3 / 2 + 1;
4883 insn_info = VEC_alloc (c6x_sched_insn_info, heap, sz);
4885 /* Make sure the real-jump insns we create are not deleted. */
4886 sched_no_dce = true;
4888 split_delayed_insns ();
4889 timevar_push (TV_SCHED2);
4890 if (do_selsched)
4891 run_selective_scheduling ();
4892 else
4893 schedule_ebbs ();
4894 conditionalize_after_sched ();
4895 timevar_pop (TV_SCHED2);
4897 free_delay_pairs ();
4898 sched_no_dce = false;
4901 call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
4903 reorg_split_calls (call_labels);
4905 if (c6x_flag_schedule_insns2)
4907 FOR_EACH_BB (bb)
4908 if ((bb->flags & BB_DISABLE_SCHEDULE) == 0)
4909 assign_reservations (BB_HEAD (bb), BB_END (bb));
4912 if (c6x_flag_var_tracking)
4914 timevar_push (TV_VAR_TRACKING);
4915 variable_tracking_main ();
4916 timevar_pop (TV_VAR_TRACKING);
4919 reorg_emit_nops (call_labels);
4921 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
4922 if (c6x_flag_schedule_insns2)
4924 free_delay_pairs ();
4925 c6x_gen_bundles ();
4928 df_finish_pass (false);
4931 /* Called when a function has been assembled. It should perform all the
4932 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
4933 tasks.
4934 We free the reservation (and other scheduling) information here now that
4935 all insns have been output. */
4936 void
4937 c6x_function_end (FILE *file, const char *fname)
4939 c6x_output_fn_unwind (file);
4941 if (insn_info)
4942 VEC_free (c6x_sched_insn_info, heap, insn_info);
4943 insn_info = NULL;
4945 if (!flag_inhibit_size_directive)
4946 ASM_OUTPUT_MEASURED_SIZE (file, fname);
4949 /* Determine whether X is a shift with code CODE and an integer amount
4950 AMOUNT. */
4951 static bool
4952 shift_p (rtx x, enum rtx_code code, int amount)
4954 return (GET_CODE (x) == code && GET_CODE (XEXP (x, 1)) == CONST_INT
4955 && INTVAL (XEXP (x, 1)) == amount);
4958 /* Compute a (partial) cost for rtx X. Return true if the complete
4959 cost has been computed, and false if subexpressions should be
4960 scanned. In either case, *TOTAL contains the cost result. */
4962 static bool
4963 c6x_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
4964 bool speed)
4966 int cost2 = COSTS_N_INSNS (1);
4967 rtx op0, op1;
4969 switch (code)
4971 case CONST_INT:
4972 if (outer_code == SET || outer_code == PLUS)
4973 *total = satisfies_constraint_IsB (x) ? 0 : cost2;
4974 else if (outer_code == AND || outer_code == IOR || outer_code == XOR
4975 || outer_code == MINUS)
4976 *total = satisfies_constraint_Is5 (x) ? 0 : cost2;
4977 else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
4978 || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
4979 *total = satisfies_constraint_Iu4 (x) ? 0 : cost2;
4980 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
4981 || outer_code == LSHIFTRT)
4982 *total = satisfies_constraint_Iu5 (x) ? 0 : cost2;
4983 else
4984 *total = cost2;
4985 return true;
4987 case CONST:
4988 case LABEL_REF:
4989 case SYMBOL_REF:
4990 case CONST_DOUBLE:
4991 *total = COSTS_N_INSNS (2);
4992 return true;
4994 case TRUNCATE:
4995 /* Recognize a mult_highpart operation. */
4996 if ((GET_MODE (x) == HImode || GET_MODE (x) == SImode)
4997 && GET_CODE (XEXP (x, 0)) == LSHIFTRT
4998 && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x))
4999 && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
5000 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
5001 && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x)))
5003 rtx mul = XEXP (XEXP (x, 0), 0);
5004 rtx op0 = XEXP (mul, 0);
5005 rtx op1 = XEXP (mul, 1);
5006 enum rtx_code code0 = GET_CODE (op0);
5007 enum rtx_code code1 = GET_CODE (op1);
5009 if ((code0 == code1
5010 && (code0 == SIGN_EXTEND || code0 == ZERO_EXTEND))
5011 || (GET_MODE (x) == HImode
5012 && code0 == ZERO_EXTEND && code1 == SIGN_EXTEND))
5014 if (GET_MODE (x) == HImode)
5015 *total = COSTS_N_INSNS (2);
5016 else
5017 *total = COSTS_N_INSNS (12);
5018 *total += rtx_cost (XEXP (op0, 0), code0, 0, speed);
5019 *total += rtx_cost (XEXP (op1, 0), code1, 0, speed);
5020 return true;
5023 return false;
5025 case ASHIFT:
5026 case ASHIFTRT:
5027 case LSHIFTRT:
5028 if (GET_MODE (x) == DImode)
5029 *total = COSTS_N_INSNS (CONSTANT_P (XEXP (x, 1)) ? 4 : 15);
5030 else
5031 *total = COSTS_N_INSNS (1);
5032 return false;
5034 case PLUS:
5035 case MINUS:
5036 *total = COSTS_N_INSNS (1);
5037 op0 = code == PLUS ? XEXP (x, 0) : XEXP (x, 1);
5038 op1 = code == PLUS ? XEXP (x, 1) : XEXP (x, 0);
5039 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
5040 && INTEGRAL_MODE_P (GET_MODE (x))
5041 && GET_CODE (op0) == MULT
5042 && GET_CODE (XEXP (op0, 1)) == CONST_INT
5043 && (INTVAL (XEXP (op0, 1)) == 2
5044 || INTVAL (XEXP (op0, 1)) == 4
5045 || (code == PLUS && INTVAL (XEXP (op0, 1)) == 8)))
5047 *total += rtx_cost (XEXP (op0, 0), ASHIFT, 0, speed);
5048 *total += rtx_cost (op1, (enum rtx_code) code, 1, speed);
5049 return true;
5051 return false;
5053 case MULT:
5054 op0 = XEXP (x, 0);
5055 op1 = XEXP (x, 1);
5056 if (GET_MODE (x) == DFmode)
5058 if (TARGET_FP)
5059 *total = COSTS_N_INSNS (speed ? 10 : 1);
5060 else
5061 *total = COSTS_N_INSNS (speed ? 200 : 4);
5063 else if (GET_MODE (x) == SFmode)
5065 if (TARGET_FP)
5066 *total = COSTS_N_INSNS (speed ? 4 : 1);
5067 else
5068 *total = COSTS_N_INSNS (speed ? 100 : 4);
5070 else if (GET_MODE (x) == DImode)
5072 if (TARGET_MPY32
5073 && GET_CODE (op0) == GET_CODE (op1)
5074 && (GET_CODE (op0) == ZERO_EXTEND
5075 || GET_CODE (op0) == SIGN_EXTEND))
5077 *total = COSTS_N_INSNS (speed ? 2 : 1);
5078 op0 = XEXP (op0, 0);
5079 op1 = XEXP (op1, 0);
5081 else
5082 /* Maybe improve this laster. */
5083 *total = COSTS_N_INSNS (20);
5085 else if (GET_MODE (x) == SImode)
5087 if (((GET_CODE (op0) == ZERO_EXTEND
5088 || GET_CODE (op0) == SIGN_EXTEND
5089 || shift_p (op0, LSHIFTRT, 16))
5090 && (GET_CODE (op1) == SIGN_EXTEND
5091 || GET_CODE (op1) == ZERO_EXTEND
5092 || scst5_operand (op1, SImode)
5093 || shift_p (op1, ASHIFTRT, 16)
5094 || shift_p (op1, LSHIFTRT, 16)))
5095 || (shift_p (op0, ASHIFTRT, 16)
5096 && (GET_CODE (op1) == SIGN_EXTEND
5097 || shift_p (op1, ASHIFTRT, 16))))
5099 *total = COSTS_N_INSNS (speed ? 2 : 1);
5100 op0 = XEXP (op0, 0);
5101 if (scst5_operand (op1, SImode))
5102 op1 = NULL_RTX;
5103 else
5104 op1 = XEXP (op1, 0);
5106 else if (!speed)
5107 *total = COSTS_N_INSNS (1);
5108 else if (TARGET_MPY32)
5109 *total = COSTS_N_INSNS (4);
5110 else
5111 *total = COSTS_N_INSNS (6);
5113 else if (GET_MODE (x) == HImode)
5114 *total = COSTS_N_INSNS (speed ? 2 : 1);
5116 if (GET_CODE (op0) != REG
5117 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
5118 *total += rtx_cost (op0, MULT, 0, speed);
5119 if (op1 && GET_CODE (op1) != REG
5120 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
5121 *total += rtx_cost (op1, MULT, 1, speed);
5122 return true;
5124 case UDIV:
5125 case DIV:
5126 /* This is a bit random; assuming on average there'll be 16 leading
5127 zeros. FIXME: estimate better for constant dividends. */
5128 *total = COSTS_N_INSNS (6 + 3 * 16);
5129 return false;
5131 case IF_THEN_ELSE:
5132 /* Recognize the cmp_and/ior patterns. */
5133 op0 = XEXP (x, 0);
5134 if ((GET_CODE (op0) == EQ || GET_CODE (op0) == NE)
5135 && REG_P (XEXP (op0, 0))
5136 && XEXP (op0, 1) == const0_rtx
5137 && rtx_equal_p (XEXP (x, 1), XEXP (op0, 0)))
5139 *total = rtx_cost (XEXP (x, 1), (enum rtx_code) outer_code,
5140 opno, speed);
5141 return false;
5143 return false;
5145 default:
5146 return false;
5150 /* Implements target hook vector_mode_supported_p. */
5152 static bool
5153 c6x_vector_mode_supported_p (enum machine_mode mode)
5155 switch (mode)
5157 case V2HImode:
5158 case V4QImode:
5159 case V2SImode:
5160 case V4HImode:
5161 case V8QImode:
5162 return true;
5163 default:
5164 return false;
5168 /* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
5169 static enum machine_mode
5170 c6x_preferred_simd_mode (enum machine_mode mode)
5172 switch (mode)
5174 case HImode:
5175 return V2HImode;
5176 case QImode:
5177 return V4QImode;
5179 default:
5180 return word_mode;
5184 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
5186 static bool
5187 c6x_scalar_mode_supported_p (enum machine_mode mode)
5189 if (ALL_FIXED_POINT_MODE_P (mode)
5190 && GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
5191 return true;
5193 return default_scalar_mode_supported_p (mode);
5196 /* Output a reference from a function exception table to the type_info
5197 object X. Output these via a special assembly directive. */
5199 static bool
5200 c6x_output_ttype (rtx x)
5202 /* Use special relocations for symbol references. */
5203 if (GET_CODE (x) != CONST_INT)
5204 fputs ("\t.ehtype\t", asm_out_file);
5205 else
5206 fputs ("\t.word\t", asm_out_file);
5207 output_addr_const (asm_out_file, x);
5208 fputc ('\n', asm_out_file);
5210 return TRUE;
5213 /* Modify the return address of the current function. */
5215 void
5216 c6x_set_return_address (rtx source, rtx scratch)
5218 struct c6x_frame frame;
5219 rtx addr;
5220 HOST_WIDE_INT offset;
5222 c6x_compute_frame_layout (&frame);
5223 if (! c6x_save_reg (RETURN_ADDR_REGNO))
5224 emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNO), source);
5225 else
5228 if (frame_pointer_needed)
5230 addr = hard_frame_pointer_rtx;
5231 offset = frame.b3_offset;
5233 else
5235 addr = stack_pointer_rtx;
5236 offset = frame.to_allocate - frame.b3_offset;
5239 /* TODO: Use base+offset loads where possible. */
5240 if (offset)
5242 HOST_WIDE_INT low = trunc_int_for_mode (offset, HImode);
5244 emit_insn (gen_movsi_high (scratch, GEN_INT (low)));
5245 if (low != offset)
5246 emit_insn (gen_movsi_lo_sum (scratch, scratch, GEN_INT(offset)));
5247 emit_insn (gen_addsi3 (scratch, addr, scratch));
5248 addr = scratch;
5251 emit_move_insn (gen_frame_mem (Pmode, addr), source);
5255 /* We save pairs of registers using a DImode store. Describe the component
5256 registers for DWARF generation code. */
5258 static rtx
5259 c6x_dwarf_register_span (rtx rtl)
5261 unsigned regno;
5262 unsigned real_regno;
5263 int nregs;
5264 int i;
5265 rtx p;
5267 regno = REGNO (rtl);
5268 nregs = HARD_REGNO_NREGS (regno, GET_MODE (rtl));
5269 if (nregs == 1)
5270 return NULL_RTX;
5272 p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc(nregs));
5273 for (i = 0; i < nregs; i++)
5275 if (TARGET_BIG_ENDIAN)
5276 real_regno = regno + nregs - (i + 1);
5277 else
5278 real_regno = regno + i;
5280 XVECEXP (p, 0, i) = gen_rtx_REG (SImode, real_regno);
5283 return p;
5286 /* Codes for all the C6X builtins. */
5287 enum c6x_builtins
5289 C6X_BUILTIN_SADD,
5290 C6X_BUILTIN_SSUB,
5291 C6X_BUILTIN_ADD2,
5292 C6X_BUILTIN_SUB2,
5293 C6X_BUILTIN_ADD4,
5294 C6X_BUILTIN_SUB4,
5295 C6X_BUILTIN_SADD2,
5296 C6X_BUILTIN_SSUB2,
5297 C6X_BUILTIN_SADDU4,
5299 C6X_BUILTIN_SMPY,
5300 C6X_BUILTIN_SMPYH,
5301 C6X_BUILTIN_SMPYHL,
5302 C6X_BUILTIN_SMPYLH,
5303 C6X_BUILTIN_MPY2,
5304 C6X_BUILTIN_SMPY2,
5306 C6X_BUILTIN_CLRR,
5307 C6X_BUILTIN_EXTR,
5308 C6X_BUILTIN_EXTRU,
5310 C6X_BUILTIN_SSHL,
5311 C6X_BUILTIN_SUBC,
5312 C6X_BUILTIN_ABS,
5313 C6X_BUILTIN_ABS2,
5314 C6X_BUILTIN_AVG2,
5315 C6X_BUILTIN_AVGU4,
5317 C6X_BUILTIN_MAX
5321 static GTY(()) tree c6x_builtin_decls[C6X_BUILTIN_MAX];
5323 /* Return the C6X builtin for CODE. */
5324 static tree
5325 c6x_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
5327 if (code >= C6X_BUILTIN_MAX)
5328 return error_mark_node;
5330 return c6x_builtin_decls[code];
5333 #define def_builtin(NAME, TYPE, CODE) \
5334 do { \
5335 tree bdecl; \
5336 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5337 NULL, NULL_TREE); \
5338 c6x_builtin_decls[CODE] = bdecl; \
5339 } while (0)
5341 /* Set up all builtin functions for this target. */
5342 static void
5343 c6x_init_builtins (void)
5345 tree V4QI_type_node = build_vector_type (unsigned_intQI_type_node, 4);
5346 tree V2HI_type_node = build_vector_type (intHI_type_node, 2);
5347 tree V2SI_type_node = build_vector_type (intSI_type_node, 2);
5348 tree int_ftype_int
5349 = build_function_type_list (integer_type_node, integer_type_node,
5350 NULL_TREE);
5351 tree int_ftype_int_int
5352 = build_function_type_list (integer_type_node, integer_type_node,
5353 integer_type_node, NULL_TREE);
5354 tree v2hi_ftype_v2hi
5355 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5356 tree v4qi_ftype_v4qi_v4qi
5357 = build_function_type_list (V4QI_type_node, V4QI_type_node,
5358 V4QI_type_node, NULL_TREE);
5359 tree v2hi_ftype_v2hi_v2hi
5360 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5361 V2HI_type_node, NULL_TREE);
5362 tree v2si_ftype_v2hi_v2hi
5363 = build_function_type_list (V2SI_type_node, V2HI_type_node,
5364 V2HI_type_node, NULL_TREE);
5366 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int,
5367 C6X_BUILTIN_SADD);
5368 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int,
5369 C6X_BUILTIN_SSUB);
5370 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi,
5371 C6X_BUILTIN_ADD2);
5372 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi,
5373 C6X_BUILTIN_SUB2);
5374 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi,
5375 C6X_BUILTIN_ADD4);
5376 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi,
5377 C6X_BUILTIN_SUB4);
5378 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi,
5379 C6X_BUILTIN_MPY2);
5380 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi,
5381 C6X_BUILTIN_SADD2);
5382 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi,
5383 C6X_BUILTIN_SSUB2);
5384 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi,
5385 C6X_BUILTIN_SADDU4);
5386 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi,
5387 C6X_BUILTIN_SMPY2);
5389 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int,
5390 C6X_BUILTIN_SMPY);
5391 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int,
5392 C6X_BUILTIN_SMPYH);
5393 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int,
5394 C6X_BUILTIN_SMPYHL);
5395 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int,
5396 C6X_BUILTIN_SMPYLH);
5398 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int,
5399 C6X_BUILTIN_SSHL);
5400 def_builtin ("__builtin_c6x_subc", int_ftype_int_int,
5401 C6X_BUILTIN_SUBC);
5403 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi,
5404 C6X_BUILTIN_AVG2);
5405 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi,
5406 C6X_BUILTIN_AVGU4);
5408 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int,
5409 C6X_BUILTIN_CLRR);
5410 def_builtin ("__builtin_c6x_extr", int_ftype_int_int,
5411 C6X_BUILTIN_EXTR);
5412 def_builtin ("__builtin_c6x_extru", int_ftype_int_int,
5413 C6X_BUILTIN_EXTRU);
5415 def_builtin ("__builtin_c6x_abs", int_ftype_int, C6X_BUILTIN_ABS);
5416 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi, C6X_BUILTIN_ABS2);
5420 struct builtin_description
5422 const enum insn_code icode;
5423 const char *const name;
5424 const enum c6x_builtins code;
5427 static const struct builtin_description bdesc_2arg[] =
5429 { CODE_FOR_saddsi3, "__builtin_c6x_sadd", C6X_BUILTIN_SADD },
5430 { CODE_FOR_ssubsi3, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB },
5431 { CODE_FOR_addv2hi3, "__builtin_c6x_add2", C6X_BUILTIN_ADD2 },
5432 { CODE_FOR_subv2hi3, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2 },
5433 { CODE_FOR_addv4qi3, "__builtin_c6x_add4", C6X_BUILTIN_ADD4 },
5434 { CODE_FOR_subv4qi3, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4 },
5435 { CODE_FOR_ss_addv2hi3, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2 },
5436 { CODE_FOR_ss_subv2hi3, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2 },
5437 { CODE_FOR_us_addv4qi3, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4 },
5439 { CODE_FOR_subcsi3, "__builtin_c6x_subc", C6X_BUILTIN_SUBC },
5440 { CODE_FOR_ss_ashlsi3, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL },
5442 { CODE_FOR_avgv2hi3, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2 },
5443 { CODE_FOR_uavgv4qi3, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4 },
5445 { CODE_FOR_mulhqsq3, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY },
5446 { CODE_FOR_mulhqsq3_hh, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH },
5447 { CODE_FOR_mulhqsq3_lh, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH },
5448 { CODE_FOR_mulhqsq3_hl, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL },
5450 { CODE_FOR_mulv2hqv2sq3, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2 },
5452 { CODE_FOR_clrr, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR },
5453 { CODE_FOR_extr, "__builtin_c6x_extr", C6X_BUILTIN_EXTR },
5454 { CODE_FOR_extru, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU }
5457 static const struct builtin_description bdesc_1arg[] =
5459 { CODE_FOR_ssabssi2, "__builtin_c6x_abs", C6X_BUILTIN_ABS },
5460 { CODE_FOR_ssabsv2hi2, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2 }
5463 /* Errors in the source file can cause expand_expr to return const0_rtx
5464 where we expect a vector. To avoid crashing, use one of the vector
5465 clear instructions. */
5466 static rtx
5467 safe_vector_operand (rtx x, enum machine_mode mode)
5469 if (x != const0_rtx)
5470 return x;
5471 x = gen_reg_rtx (SImode);
5473 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5474 return gen_lowpart (mode, x);
5477 /* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
5478 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5480 static rtx
5481 c6x_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5482 bool match_op)
5484 int offs = match_op ? 1 : 0;
5485 rtx pat;
5486 tree arg0 = CALL_EXPR_ARG (exp, 0);
5487 tree arg1 = CALL_EXPR_ARG (exp, 1);
5488 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
5489 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
5490 enum machine_mode op0mode = GET_MODE (op0);
5491 enum machine_mode op1mode = GET_MODE (op1);
5492 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5493 enum machine_mode mode0 = insn_data[icode].operand[1 + offs].mode;
5494 enum machine_mode mode1 = insn_data[icode].operand[2 + offs].mode;
5495 rtx ret = target;
5497 if (VECTOR_MODE_P (mode0))
5498 op0 = safe_vector_operand (op0, mode0);
5499 if (VECTOR_MODE_P (mode1))
5500 op1 = safe_vector_operand (op1, mode1);
5502 if (! target
5503 || GET_MODE (target) != tmode
5504 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5506 if (tmode == SQmode || tmode == V2SQmode)
5508 ret = gen_reg_rtx (tmode == SQmode ? SImode : V2SImode);
5509 target = gen_lowpart (tmode, ret);
5511 else
5512 target = gen_reg_rtx (tmode);
5515 if ((op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode)
5516 && (mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode))
5518 op0mode = mode0;
5519 op0 = gen_lowpart (mode0, op0);
5521 if ((op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode)
5522 && (mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode))
5524 op1mode = mode1;
5525 op1 = gen_lowpart (mode1, op1);
5527 /* In case the insn wants input operands in modes different from
5528 the result, abort. */
5529 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5530 && (op1mode == mode1 || op1mode == VOIDmode));
5532 if (! (*insn_data[icode].operand[1 + offs].predicate) (op0, mode0))
5533 op0 = copy_to_mode_reg (mode0, op0);
5534 if (! (*insn_data[icode].operand[2 + offs].predicate) (op1, mode1))
5535 op1 = copy_to_mode_reg (mode1, op1);
5537 if (match_op)
5538 pat = GEN_FCN (icode) (target, target, op0, op1);
5539 else
5540 pat = GEN_FCN (icode) (target, op0, op1);
5542 if (! pat)
5543 return 0;
5545 emit_insn (pat);
5547 return ret;
5550 /* Subroutine of c6x_expand_builtin to take care of unop insns. */
5552 static rtx
5553 c6x_expand_unop_builtin (enum insn_code icode, tree exp,
5554 rtx target)
5556 rtx pat;
5557 tree arg0 = CALL_EXPR_ARG (exp, 0);
5558 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
5559 enum machine_mode op0mode = GET_MODE (op0);
5560 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5561 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5563 if (! target
5564 || GET_MODE (target) != tmode
5565 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5566 target = gen_reg_rtx (tmode);
5568 if (VECTOR_MODE_P (mode0))
5569 op0 = safe_vector_operand (op0, mode0);
5571 if (op0mode == SImode && mode0 == HImode)
5573 op0mode = HImode;
5574 op0 = gen_lowpart (HImode, op0);
5576 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5578 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5579 op0 = copy_to_mode_reg (mode0, op0);
5581 pat = GEN_FCN (icode) (target, op0);
5582 if (! pat)
5583 return 0;
5584 emit_insn (pat);
5585 return target;
5588 /* Expand an expression EXP that calls a built-in function,
5589 with result going to TARGET if that's convenient
5590 (and in mode MODE if that's convenient).
5591 SUBTARGET may be used as the target for computing one of EXP's operands.
5592 IGNORE is nonzero if the value is to be ignored. */
5594 static rtx
5595 c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5596 rtx subtarget ATTRIBUTE_UNUSED,
5597 enum machine_mode mode ATTRIBUTE_UNUSED,
5598 int ignore ATTRIBUTE_UNUSED)
5600 size_t i;
5601 const struct builtin_description *d;
5602 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5603 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5605 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
5606 if (d->code == fcode)
5607 return c6x_expand_binop_builtin (d->icode, exp, target,
5608 fcode == C6X_BUILTIN_CLRR);
5610 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
5611 if (d->code == fcode)
5612 return c6x_expand_unop_builtin (d->icode, exp, target);
5614 gcc_unreachable ();
5617 /* Target unwind frame info is generated from dwarf CFI directives, so
5618 always output dwarf2 unwind info. */
5620 static enum unwind_info_type
5621 c6x_debug_unwind_info (void)
5623 if (flag_unwind_tables || flag_exceptions)
5624 return UI_DWARF2;
5626 return default_debug_unwind_info ();
5629 /* Target Structure. */
5631 /* Initialize the GCC target structure. */
5632 #undef TARGET_FUNCTION_ARG
5633 #define TARGET_FUNCTION_ARG c6x_function_arg
5634 #undef TARGET_FUNCTION_ARG_ADVANCE
5635 #define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
5636 #undef TARGET_FUNCTION_ARG_BOUNDARY
5637 #define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
5638 #undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
5639 #define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
5640 c6x_function_arg_round_boundary
5641 #undef TARGET_FUNCTION_VALUE_REGNO_P
5642 #define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
5643 #undef TARGET_FUNCTION_VALUE
5644 #define TARGET_FUNCTION_VALUE c6x_function_value
5645 #undef TARGET_LIBCALL_VALUE
5646 #define TARGET_LIBCALL_VALUE c6x_libcall_value
5647 #undef TARGET_RETURN_IN_MEMORY
5648 #define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
5649 #undef TARGET_RETURN_IN_MSB
5650 #define TARGET_RETURN_IN_MSB c6x_return_in_msb
5651 #undef TARGET_PASS_BY_REFERENCE
5652 #define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
5653 #undef TARGET_CALLEE_COPIES
5654 #define TARGET_CALLEE_COPIES c6x_callee_copies
5655 #undef TARGET_STRUCT_VALUE_RTX
5656 #define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
5657 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5658 #define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
5660 #undef TARGET_ASM_OUTPUT_MI_THUNK
5661 #define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
5662 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5663 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
5665 #undef TARGET_BUILD_BUILTIN_VA_LIST
5666 #define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
5668 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5669 #define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
5670 #undef TARGET_TRAMPOLINE_INIT
5671 #define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
5673 #undef TARGET_LEGITIMATE_CONSTANT_P
5674 #define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
5675 #undef TARGET_LEGITIMATE_ADDRESS_P
5676 #define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
5678 #undef TARGET_IN_SMALL_DATA_P
5679 #define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
5680 #undef TARGET_ASM_SELECT_RTX_SECTION
5681 #define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
5682 #undef TARGET_ASM_SELECT_SECTION
5683 #define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
5684 #undef TARGET_ASM_UNIQUE_SECTION
5685 #define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
5686 #undef TARGET_SECTION_TYPE_FLAGS
5687 #define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
5688 #undef TARGET_HAVE_SRODATA_SECTION
5689 #define TARGET_HAVE_SRODATA_SECTION true
5690 #undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
5691 #define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
5693 #undef TARGET_OPTION_OVERRIDE
5694 #define TARGET_OPTION_OVERRIDE c6x_option_override
5695 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5696 #define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
5698 #undef TARGET_INIT_LIBFUNCS
5699 #define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
5700 #undef TARGET_LIBFUNC_GNU_PREFIX
5701 #define TARGET_LIBFUNC_GNU_PREFIX true
5703 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5704 #define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
5705 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5706 #define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
5707 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
5708 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
5710 #undef TARGET_RTX_COSTS
5711 #define TARGET_RTX_COSTS c6x_rtx_costs
5713 #undef TARGET_SCHED_INIT
5714 #define TARGET_SCHED_INIT c6x_sched_init
5715 #undef TARGET_SCHED_SET_SCHED_FLAGS
5716 #define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
5717 #undef TARGET_SCHED_ADJUST_COST
5718 #define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
5719 #undef TARGET_SCHED_ISSUE_RATE
5720 #define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
5721 #undef TARGET_SCHED_VARIABLE_ISSUE
5722 #define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
5723 #undef TARGET_SCHED_REORDER
5724 #define TARGET_SCHED_REORDER c6x_sched_reorder
5725 #undef TARGET_SCHED_REORDER2
5726 #define TARGET_SCHED_REORDER2 c6x_sched_reorder2
5727 #undef TARGET_SCHED_DFA_NEW_CYCLE
5728 #define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
5729 #undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
5730 #define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
5731 #undef TARGET_SCHED_EXPOSED_PIPELINE
5732 #define TARGET_SCHED_EXPOSED_PIPELINE true
5734 #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
5735 #define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
5736 #undef TARGET_SCHED_INIT_SCHED_CONTEXT
5737 #define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
5738 #undef TARGET_SCHED_SET_SCHED_CONTEXT
5739 #define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
5740 #undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
5741 #define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
5742 #undef TARGET_SCHED_FREE_SCHED_CONTEXT
5743 #define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
5745 #undef TARGET_CAN_ELIMINATE
5746 #define TARGET_CAN_ELIMINATE c6x_can_eliminate
5748 #undef TARGET_PREFERRED_RENAME_CLASS
5749 #define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
5751 #undef TARGET_MACHINE_DEPENDENT_REORG
5752 #define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
5754 #undef TARGET_ASM_FILE_START
5755 #define TARGET_ASM_FILE_START c6x_file_start
5757 #undef TARGET_PRINT_OPERAND
5758 #define TARGET_PRINT_OPERAND c6x_print_operand
5759 #undef TARGET_PRINT_OPERAND_ADDRESS
5760 #define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
5761 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
5762 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
5764 /* C6x unwinding tables use a different format for the typeinfo tables. */
5765 #undef TARGET_ASM_TTYPE
5766 #define TARGET_ASM_TTYPE c6x_output_ttype
5768 /* The C6x ABI follows the ARM EABI exception handling rules. */
5769 #undef TARGET_ARM_EABI_UNWINDER
5770 #define TARGET_ARM_EABI_UNWINDER true
5772 #undef TARGET_DEBUG_UNWIND_INFO
5773 #define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
5775 #undef TARGET_DWARF_REGISTER_SPAN
5776 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
5778 #undef TARGET_INIT_BUILTINS
5779 #define TARGET_INIT_BUILTINS c6x_init_builtins
5780 #undef TARGET_EXPAND_BUILTIN
5781 #define TARGET_EXPAND_BUILTIN c6x_expand_builtin
5782 #undef TARGET_BUILTIN_DECL
5783 #define TARGET_BUILTIN_DECL c6x_builtin_decl
5785 struct gcc_target targetm = TARGET_INITIALIZER;
5787 #include "gt-c6x.h"