]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/c6x/c6x.c
Update copyright years in gcc/
[thirdparty/gcc.git] / gcc / config / c6x / c6x.c
CommitLineData
bcead286 1/* Target Code for TI C6X
23a5b65a 2 Copyright (C) 2010-2014 Free Software Foundation, Inc.
bcead286
BS
3 Contributed by Andrew Jenner <andrew@codesourcery.com>
4 Contributed by Bernd Schmidt <bernds@codesourcery.com>
5
6 This file is part of GCC.
7
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.
12
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.
17
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/>. */
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "tm.h"
26#include "rtl.h"
27#include "tree.h"
d8a2d370
DN
28#include "stor-layout.h"
29#include "varasm.h"
30#include "calls.h"
31#include "stringpool.h"
bcead286
BS
32#include "insn-flags.h"
33#include "output.h"
34#include "insn-attr.h"
35#include "insn-codes.h"
36#include "expr.h"
37#include "regs.h"
38#include "optabs.h"
39#include "recog.h"
40#include "ggc.h"
41#include "sched-int.h"
42#include "timevar.h"
43#include "tm_p.h"
44#include "tm-preds.h"
45#include "tm-constrs.h"
46#include "df.h"
6399c0ab 47#include "function.h"
bcead286
BS
48#include "diagnostic-core.h"
49#include "cgraph.h"
bcead286
BS
50#include "langhooks.h"
51#include "target.h"
52#include "target-def.h"
53#include "sel-sched.h"
54#include "debug.h"
55#include "opts.h"
11e69edc 56#include "hw-doloop.h"
8076c3e3 57#include "regrename.h"
7ee2468b 58#include "dumpfile.h"
cb076acf 59#include "gimple-expr.h"
bcead286
BS
60
61/* Table of supported architecture variants. */
62typedef struct
63{
64 const char *arch;
65 enum c6x_cpu_type type;
66 unsigned short features;
67} c6x_arch_table;
68
69/* A list of all ISAs, mapping each one to a representative device.
70 Used for -march selection. */
71static const c6x_arch_table all_isas[] =
72{
73#define C6X_ISA(NAME,DEVICE,FLAGS) \
74 { NAME, DEVICE, FLAGS },
75#include "c6x-isas.def"
76#undef C6X_ISA
77 { NULL, C6X_CPU_C62X, 0 }
78};
79
80/* This is the parsed result of the "-march=" option, if given. */
81enum c6x_cpu_type c6x_arch = C6X_DEFAULT_ARCH;
82
83/* A mask of insn types that are allowed by the architecture selected by
84 the -march option. */
85unsigned long c6x_insn_mask = C6X_DEFAULT_INSN_MASK;
86
87/* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
88 */
89static rtx c6x_current_insn = NULL_RTX;
90
91/* A decl we build to access __c6xabi_DSBT_base. */
92static GTY(()) tree dsbt_decl;
93\f
94/* Determines whether we run our final scheduling pass or not. We always
95 avoid the normal second scheduling pass. */
96static int c6x_flag_schedule_insns2;
97
98/* Determines whether we run variable tracking in machine dependent
99 reorganization. */
100static int c6x_flag_var_tracking;
101
102/* Determines whether we use modulo scheduling. */
103static int c6x_flag_modulo_sched;
104
105/* Record the state of flag_pic before we set it to 1 for DSBT. */
106int c6x_initial_flag_pic;
107\f
108typedef struct
109{
110 /* We record the clock cycle for every insn during scheduling. */
111 int clock;
112 /* After scheduling, we run assign_reservations to choose unit
113 reservations for all insns. These are recorded here. */
114 int reservation;
115 /* Records the new condition for insns which must be made
116 conditional after scheduling. An entry of NULL_RTX means no such
117 change is necessary. */
118 rtx new_cond;
119 /* True for the first insn that was scheduled in an ebb. */
120 bool ebb_start;
6bd9bf42
BS
121 /* The scheduler state after the insn, transformed into a mask of UNIT_QID
122 bits rather than storing the state. Meaningful only for the last
123 insn in a cycle. */
124 unsigned int unit_mask;
bcead286
BS
125} c6x_sched_insn_info;
126
bcead286
BS
127
128/* Record a c6x_sched_insn_info structure for every insn in the function. */
9771b263 129static vec<c6x_sched_insn_info> insn_info;
bcead286 130
9771b263
DN
131#define INSN_INFO_LENGTH (insn_info).length ()
132#define INSN_INFO_ENTRY(N) (insn_info[(N)])
bcead286
BS
133
134static bool done_cfi_sections;
135
bcead286
BS
136#define RESERVATION_FLAG_D 1
137#define RESERVATION_FLAG_L 2
138#define RESERVATION_FLAG_S 4
139#define RESERVATION_FLAG_M 8
140#define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
141#define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
142#define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
143#define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
144
6bd9bf42
BS
145/* The DFA names of the units. */
146static const char *const c6x_unit_names[] =
147{
148 "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
149 "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
150};
151
152/* The DFA unit number for each unit in c6x_unit_names[]. */
153static int c6x_unit_codes[ARRAY_SIZE (c6x_unit_names)];
154
155/* Unit query IDs. */
156#define UNIT_QID_D1 0
157#define UNIT_QID_L1 1
158#define UNIT_QID_S1 2
159#define UNIT_QID_M1 3
160#define UNIT_QID_FPS1 4
161#define UNIT_QID_FPL1 5
162#define UNIT_QID_ADDDPS1 6
163#define UNIT_QID_ADDDPL1 7
164#define UNIT_QID_SIDE_OFFSET 8
165
bcead286 166#define RESERVATION_S1 2
6bd9bf42 167#define RESERVATION_S2 10
11e69edc
BS
168
169/* An enum for the unit requirements we count in the UNIT_REQS table. */
170enum unitreqs
171{
172 UNIT_REQ_D,
173 UNIT_REQ_L,
174 UNIT_REQ_S,
175 UNIT_REQ_M,
176 UNIT_REQ_DL,
177 UNIT_REQ_DS,
178 UNIT_REQ_LS,
179 UNIT_REQ_DLS,
180 UNIT_REQ_T,
181 UNIT_REQ_X,
182 UNIT_REQ_MAX
183};
184
185/* A table used to count unit requirements. Used when computing minimum
186 iteration intervals. */
187typedef int unit_req_table[2][UNIT_REQ_MAX];
188static unit_req_table unit_reqs;
bcead286
BS
189\f
190/* Register map for debugging. */
e13a0ccb 191unsigned const dbx_register_map[FIRST_PSEUDO_REGISTER] =
bcead286
BS
192{
193 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* A0 - A15. */
194 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, /* A16 - A32. */
195 50, 51, 52,
196 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, /* B0 - B15. */
197 29, 30, 31,
198 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, /* B16 - B32. */
199 66, 67, 68,
200 -1, -1, -1 /* FP, ARGP, ILC. */
201};
202\f
203/* Allocate a new, cleared machine_function structure. */
204
205static struct machine_function *
206c6x_init_machine_status (void)
207{
208 return ggc_alloc_cleared_machine_function ();
209}
210
211/* Implement TARGET_OPTION_OVERRIDE. */
212
213static void
214c6x_option_override (void)
215{
6bd9bf42
BS
216 unsigned i;
217
bcead286
BS
218 if (global_options_set.x_c6x_arch_option)
219 {
220 c6x_arch = all_isas[c6x_arch_option].type;
221 c6x_insn_mask &= ~C6X_INSNS_ALL_CPU_BITS;
222 c6x_insn_mask |= all_isas[c6x_arch_option].features;
223 }
224
225 c6x_flag_schedule_insns2 = flag_schedule_insns_after_reload;
226 flag_schedule_insns_after_reload = 0;
227
228 c6x_flag_modulo_sched = flag_modulo_sched;
229 flag_modulo_sched = 0;
230
231 init_machine_status = c6x_init_machine_status;
232
6bd9bf42
BS
233 for (i = 0; i < ARRAY_SIZE (c6x_unit_names); i++)
234 c6x_unit_codes[i] = get_cpu_unit_code (c6x_unit_names[i]);
235
bcead286
BS
236 if (flag_pic && !TARGET_DSBT)
237 {
238 error ("-fpic and -fPIC not supported without -mdsbt on this target");
239 flag_pic = 0;
240 }
241 c6x_initial_flag_pic = flag_pic;
242 if (TARGET_DSBT && !flag_pic)
243 flag_pic = 1;
244}
245
246
247/* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook. */
248
249static void
250c6x_conditional_register_usage (void)
251{
252 int i;
253 if (c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X)
254 for (i = 16; i < 32; i++)
255 {
256 fixed_regs[i] = 1;
257 fixed_regs[32 + i] = 1;
258 }
259 if (TARGET_INSNS_64)
260 {
261 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_A_REGS],
262 REG_A0);
263 SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_REGS],
264 REG_A0);
265 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_A_REGS],
266 REG_A0);
267 CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_REGS],
268 REG_A0);
269 }
270}
271\f
272static GTY(()) rtx eqdf_libfunc;
273static GTY(()) rtx nedf_libfunc;
274static GTY(()) rtx ledf_libfunc;
275static GTY(()) rtx ltdf_libfunc;
276static GTY(()) rtx gedf_libfunc;
277static GTY(()) rtx gtdf_libfunc;
278static GTY(()) rtx eqsf_libfunc;
279static GTY(()) rtx nesf_libfunc;
280static GTY(()) rtx lesf_libfunc;
281static GTY(()) rtx ltsf_libfunc;
282static GTY(()) rtx gesf_libfunc;
283static GTY(()) rtx gtsf_libfunc;
284static GTY(()) rtx strasgi_libfunc;
285static GTY(()) rtx strasgi64p_libfunc;
286
287/* Implement the TARGET_INIT_LIBFUNCS macro. We use this to rename library
288 functions to match the C6x ABI. */
289
290static void
291c6x_init_libfuncs (void)
292{
293 /* Double-precision floating-point arithmetic. */
294 set_optab_libfunc (add_optab, DFmode, "__c6xabi_addd");
295 set_optab_libfunc (sdiv_optab, DFmode, "__c6xabi_divd");
296 set_optab_libfunc (smul_optab, DFmode, "__c6xabi_mpyd");
297 set_optab_libfunc (neg_optab, DFmode, "__c6xabi_negd");
298 set_optab_libfunc (sub_optab, DFmode, "__c6xabi_subd");
299
300 /* Single-precision floating-point arithmetic. */
301 set_optab_libfunc (add_optab, SFmode, "__c6xabi_addf");
302 set_optab_libfunc (sdiv_optab, SFmode, "__c6xabi_divf");
303 set_optab_libfunc (smul_optab, SFmode, "__c6xabi_mpyf");
304 set_optab_libfunc (neg_optab, SFmode, "__c6xabi_negf");
305 set_optab_libfunc (sub_optab, SFmode, "__c6xabi_subf");
306
307 /* Floating-point comparisons. */
308 eqsf_libfunc = init_one_libfunc ("__c6xabi_eqf");
309 nesf_libfunc = init_one_libfunc ("__c6xabi_neqf");
310 lesf_libfunc = init_one_libfunc ("__c6xabi_lef");
311 ltsf_libfunc = init_one_libfunc ("__c6xabi_ltf");
312 gesf_libfunc = init_one_libfunc ("__c6xabi_gef");
313 gtsf_libfunc = init_one_libfunc ("__c6xabi_gtf");
314 eqdf_libfunc = init_one_libfunc ("__c6xabi_eqd");
315 nedf_libfunc = init_one_libfunc ("__c6xabi_neqd");
316 ledf_libfunc = init_one_libfunc ("__c6xabi_led");
317 ltdf_libfunc = init_one_libfunc ("__c6xabi_ltd");
318 gedf_libfunc = init_one_libfunc ("__c6xabi_ged");
319 gtdf_libfunc = init_one_libfunc ("__c6xabi_gtd");
320
321 set_optab_libfunc (eq_optab, SFmode, NULL);
322 set_optab_libfunc (ne_optab, SFmode, "__c6xabi_neqf");
323 set_optab_libfunc (gt_optab, SFmode, NULL);
324 set_optab_libfunc (ge_optab, SFmode, NULL);
325 set_optab_libfunc (lt_optab, SFmode, NULL);
326 set_optab_libfunc (le_optab, SFmode, NULL);
327 set_optab_libfunc (unord_optab, SFmode, "__c6xabi_unordf");
328 set_optab_libfunc (eq_optab, DFmode, NULL);
329 set_optab_libfunc (ne_optab, DFmode, "__c6xabi_neqd");
330 set_optab_libfunc (gt_optab, DFmode, NULL);
331 set_optab_libfunc (ge_optab, DFmode, NULL);
332 set_optab_libfunc (lt_optab, DFmode, NULL);
333 set_optab_libfunc (le_optab, DFmode, NULL);
334 set_optab_libfunc (unord_optab, DFmode, "__c6xabi_unordd");
335
336 /* Floating-point to integer conversions. */
337 set_conv_libfunc (sfix_optab, SImode, DFmode, "__c6xabi_fixdi");
338 set_conv_libfunc (ufix_optab, SImode, DFmode, "__c6xabi_fixdu");
339 set_conv_libfunc (sfix_optab, DImode, DFmode, "__c6xabi_fixdlli");
340 set_conv_libfunc (ufix_optab, DImode, DFmode, "__c6xabi_fixdull");
341 set_conv_libfunc (sfix_optab, SImode, SFmode, "__c6xabi_fixfi");
342 set_conv_libfunc (ufix_optab, SImode, SFmode, "__c6xabi_fixfu");
343 set_conv_libfunc (sfix_optab, DImode, SFmode, "__c6xabi_fixflli");
344 set_conv_libfunc (ufix_optab, DImode, SFmode, "__c6xabi_fixfull");
345
346 /* Conversions between floating types. */
347 set_conv_libfunc (trunc_optab, SFmode, DFmode, "__c6xabi_cvtdf");
348 set_conv_libfunc (sext_optab, DFmode, SFmode, "__c6xabi_cvtfd");
349
350 /* Integer to floating-point conversions. */
351 set_conv_libfunc (sfloat_optab, DFmode, SImode, "__c6xabi_fltid");
352 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__c6xabi_fltud");
353 set_conv_libfunc (sfloat_optab, DFmode, DImode, "__c6xabi_fltllid");
354 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__c6xabi_fltulld");
355 set_conv_libfunc (sfloat_optab, SFmode, SImode, "__c6xabi_fltif");
356 set_conv_libfunc (ufloat_optab, SFmode, SImode, "__c6xabi_fltuf");
357 set_conv_libfunc (sfloat_optab, SFmode, DImode, "__c6xabi_fltllif");
358 set_conv_libfunc (ufloat_optab, SFmode, DImode, "__c6xabi_fltullf");
359
360 /* Long long. */
361 set_optab_libfunc (smul_optab, DImode, "__c6xabi_mpyll");
362 set_optab_libfunc (ashl_optab, DImode, "__c6xabi_llshl");
363 set_optab_libfunc (lshr_optab, DImode, "__c6xabi_llshru");
364 set_optab_libfunc (ashr_optab, DImode, "__c6xabi_llshr");
365
366 set_optab_libfunc (sdiv_optab, SImode, "__c6xabi_divi");
367 set_optab_libfunc (udiv_optab, SImode, "__c6xabi_divu");
368 set_optab_libfunc (smod_optab, SImode, "__c6xabi_remi");
369 set_optab_libfunc (umod_optab, SImode, "__c6xabi_remu");
370 set_optab_libfunc (sdivmod_optab, SImode, "__c6xabi_divremi");
371 set_optab_libfunc (udivmod_optab, SImode, "__c6xabi_divremu");
372 set_optab_libfunc (sdiv_optab, DImode, "__c6xabi_divlli");
373 set_optab_libfunc (udiv_optab, DImode, "__c6xabi_divull");
374 set_optab_libfunc (smod_optab, DImode, "__c6xabi_remlli");
375 set_optab_libfunc (umod_optab, DImode, "__c6xabi_remull");
376 set_optab_libfunc (udivmod_optab, DImode, "__c6xabi_divremull");
377
378 /* Block move. */
379 strasgi_libfunc = init_one_libfunc ("__c6xabi_strasgi");
380 strasgi64p_libfunc = init_one_libfunc ("__c6xabi_strasgi_64plus");
381}
382
383/* Begin the assembly file. */
384
385static void
386c6x_file_start (void)
387{
388 /* Variable tracking should be run after all optimizations which change order
389 of insns. It also needs a valid CFG. This can't be done in
390 c6x_override_options, because flag_var_tracking is finalized after
391 that. */
392 c6x_flag_var_tracking = flag_var_tracking;
393 flag_var_tracking = 0;
394
395 done_cfi_sections = false;
396 default_file_start ();
397
398 /* Arrays are aligned to 8-byte boundaries. */
399 asm_fprintf (asm_out_file,
400 "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
401 asm_fprintf (asm_out_file,
402 "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
403
404 /* Stack alignment is 8 bytes. */
405 asm_fprintf (asm_out_file,
406 "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
407 asm_fprintf (asm_out_file,
408 "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
409
410#if 0 /* FIXME: Reenable when TI's tools are fixed. */
411 /* ??? Ideally we'd check flag_short_wchar somehow. */
412 asm_fprintf (asm_out_file, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
413#endif
414
415 /* We conform to version 1.0 of the ABI. */
416 asm_fprintf (asm_out_file,
417 "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
418
419}
420
421/* The LTO frontend only enables exceptions when it sees a function that
422 uses it. This changes the return value of dwarf2out_do_frame, so we
423 have to check before every function. */
424
425void
426c6x_output_file_unwind (FILE * f)
427{
428 if (done_cfi_sections)
429 return;
430
1e874273
PB
431 /* Output a .cfi_sections directive. */
432 if (dwarf2out_do_frame ())
bcead286 433 {
1e874273
PB
434 if (flag_unwind_tables || flag_exceptions)
435 {
436 if (write_symbols == DWARF2_DEBUG
437 || write_symbols == VMS_AND_DWARF2_DEBUG)
438 asm_fprintf (f, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
439 else
440 asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
441 }
442 else
443 asm_fprintf (f, "\t.cfi_sections .debug_frame\n");
bcead286
BS
444 done_cfi_sections = true;
445 }
446}
447
448/* Output unwind directives at the end of a function. */
449
450static void
451c6x_output_fn_unwind (FILE * f)
452{
453 /* Return immediately if we are not generating unwinding tables. */
454 if (! (flag_unwind_tables || flag_exceptions))
455 return;
456
457 /* If this function will never be unwound, then mark it as such. */
458 if (!(flag_unwind_tables || crtl->uses_eh_lsda)
459 && (TREE_NOTHROW (current_function_decl)
460 || crtl->all_throwers_are_sibcalls))
461 fputs("\t.cantunwind\n", f);
462
463 fputs ("\t.endp\n", f);
464}
465
466\f
467/* Stack and Calling. */
468
469int argument_registers[10] =
470{
471 REG_A4, REG_B4,
472 REG_A6, REG_B6,
473 REG_A8, REG_B8,
474 REG_A10, REG_B10,
475 REG_A12, REG_B12
476};
477
478/* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h. */
479
480void
481c6x_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, rtx libname,
482 int n_named_args ATTRIBUTE_UNUSED)
483{
484 cum->count = 0;
485 cum->nregs = 10;
486 if (!libname && fntype)
487 {
488 /* We need to find out the number of named arguments. Unfortunately,
489 for incoming arguments, N_NAMED_ARGS is set to -1. */
490 if (stdarg_p (fntype))
491 cum->nregs = type_num_arguments (fntype) - 1;
492 if (cum->nregs > 10)
493 cum->nregs = 10;
494 }
495}
496
497/* Implements the macro FUNCTION_ARG defined in c6x.h. */
498
499static rtx
500c6x_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
501 const_tree type, bool named ATTRIBUTE_UNUSED)
502{
503 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
504 if (cum->count >= cum->nregs)
505 return NULL_RTX;
506 if (type)
507 {
508 HOST_WIDE_INT size = int_size_in_bytes (type);
509 if (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (type))
510 {
511 if (size > 4)
512 {
513 rtx reg1 = gen_rtx_REG (SImode, argument_registers[cum->count] + 1);
514 rtx reg2 = gen_rtx_REG (SImode, argument_registers[cum->count]);
515 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
516 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
517 return gen_rtx_PARALLEL (mode, vec);
518 }
519 }
520 }
521 return gen_rtx_REG (mode, argument_registers[cum->count]);
522}
523
524static void
525c6x_function_arg_advance (cumulative_args_t cum_v,
526 enum machine_mode mode ATTRIBUTE_UNUSED,
527 const_tree type ATTRIBUTE_UNUSED,
528 bool named ATTRIBUTE_UNUSED)
529{
530 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
531 cum->count++;
532}
533
534
535/* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
536 upward rather than downward. */
537
538bool
539c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
540 const_tree type, bool first)
541{
542 HOST_WIDE_INT size;
543
544 if (!TARGET_BIG_ENDIAN)
545 return true;
546 if (!first)
547 return true;
548 if (!type)
549 return true;
550 size = int_size_in_bytes (type);
551 return size == 3;
552}
553
554/* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
555
556static unsigned int
557c6x_function_arg_boundary (enum machine_mode mode, const_tree type)
558{
559 unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
560
561 if (boundary > BITS_PER_WORD)
562 return 2 * BITS_PER_WORD;
563
564 if (mode == BLKmode)
565 {
566 HOST_WIDE_INT size = int_size_in_bytes (type);
567 if (size > 4)
568 return 2 * BITS_PER_WORD;
569 if (boundary < BITS_PER_WORD)
570 {
571 if (size >= 3)
572 return BITS_PER_WORD;
573 if (size >= 2)
574 return 2 * BITS_PER_UNIT;
575 }
576 }
577 return boundary;
578}
579
580/* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY. */
581static unsigned int
582c6x_function_arg_round_boundary (enum machine_mode mode, const_tree type)
583{
584 return c6x_function_arg_boundary (mode, type);
585}
586
587/* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
588 where function FUNC returns or receives a value of data type TYPE. */
589
590static rtx
591c6x_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
592 bool outgoing ATTRIBUTE_UNUSED)
593{
594 /* Functions return values in register A4. When returning aggregates, we may
595 have to adjust for endianness. */
596 if (TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P (type))
597 {
598 HOST_WIDE_INT size = int_size_in_bytes (type);
599 if (size > 4)
600 {
601
602 rtx reg1 = gen_rtx_REG (SImode, REG_A4 + 1);
603 rtx reg2 = gen_rtx_REG (SImode, REG_A4);
604 rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
605 gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
606 return gen_rtx_PARALLEL (TYPE_MODE (type), vec);
607 }
608 }
609 return gen_rtx_REG (TYPE_MODE (type), REG_A4);
610}
611
612/* Implement TARGET_LIBCALL_VALUE. */
613
614static rtx
615c6x_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
616{
617 return gen_rtx_REG (mode, REG_A4);
618}
619
620/* TARGET_STRUCT_VALUE_RTX implementation. */
621
622static rtx
623c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED)
624{
625 return gen_rtx_REG (Pmode, REG_A3);
626}
627
628/* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
629
630static bool
631c6x_function_value_regno_p (const unsigned int regno)
632{
633 return regno == REG_A4;
634}
635
636/* Types larger than 64 bit, and variable sized types, are passed by
637 reference. The callee must copy them; see c6x_callee_copies. */
638
639static bool
640c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
641 enum machine_mode mode, const_tree type,
642 bool named ATTRIBUTE_UNUSED)
643{
644 int size = -1;
645 if (type)
646 size = int_size_in_bytes (type);
647 else if (mode != VOIDmode)
648 size = GET_MODE_SIZE (mode);
649 return size > 2 * UNITS_PER_WORD || size == -1;
650}
651
652/* Decide whether a type should be returned in memory (true)
653 or in a register (false). This is called by the macro
654 TARGET_RETURN_IN_MEMORY. */
655
656static bool
657c6x_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
658{
659 int size = int_size_in_bytes (type);
660 return size > 2 * UNITS_PER_WORD || size == -1;
661}
662
663/* Values which must be returned in the most-significant end of the return
664 register. */
665
666static bool
667c6x_return_in_msb (const_tree valtype)
668{
669 HOST_WIDE_INT size = int_size_in_bytes (valtype);
670 return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && size == 3;
671}
672
673/* Implement TARGET_CALLEE_COPIES. */
674
675static bool
676c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
677 enum machine_mode mode ATTRIBUTE_UNUSED,
678 const_tree type ATTRIBUTE_UNUSED,
679 bool named ATTRIBUTE_UNUSED)
680{
681 return true;
682}
683
684/* Return the type to use as __builtin_va_list. */
685static tree
686c6x_build_builtin_va_list (void)
687{
688 return build_pointer_type (char_type_node);
689}
690\f
691static void
692c6x_asm_trampoline_template (FILE *f)
693{
694 fprintf (f, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
695 fprintf (f, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
696 fprintf (f, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
697 fprintf (f, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
698 fprintf (f, "\t.long\t0x00000362\n"); /* b .s2 B0 */
699 fprintf (f, "\t.long\t0x00008000\n"); /* nop 5 */
700 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
701 fprintf (f, "\t.long\t0x00000000\n"); /* nop */
702}
703
704/* Emit RTL insns to initialize the variable parts of a trampoline at
705 TRAMP. FNADDR is an RTX for the address of the function's pure
706 code. CXT is an RTX for the static chain value for the function. */
707
708static void
709c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt)
710{
711 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
712 rtx t1 = copy_to_reg (fnaddr);
713 rtx t2 = copy_to_reg (cxt);
714 rtx mask = gen_reg_rtx (SImode);
715 int i;
716
717 emit_block_move (tramp, assemble_trampoline_template (),
718 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
719
720 emit_move_insn (mask, GEN_INT (0xffff << 7));
721
722 for (i = 0; i < 4; i++)
723 {
724 rtx mem = adjust_address (tramp, SImode, i * 4);
725 rtx t = (i & 1) ? t2 : t1;
726 rtx v1 = gen_reg_rtx (SImode);
727 rtx v2 = gen_reg_rtx (SImode);
728 emit_move_insn (v1, mem);
729 if (i < 2)
730 emit_insn (gen_ashlsi3 (v2, t, GEN_INT (7)));
731 else
732 emit_insn (gen_lshrsi3 (v2, t, GEN_INT (9)));
733 emit_insn (gen_andsi3 (v2, v2, mask));
734 emit_insn (gen_iorsi3 (v2, v2, v1));
735 emit_move_insn (mem, v2);
736 }
737#ifdef CLEAR_INSN_CACHE
738 tramp = XEXP (tramp, 0);
739 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"),
740 LCT_NORMAL, VOIDmode, 2, tramp, Pmode,
0a81f074
RS
741 plus_constant (Pmode, tramp, TRAMPOLINE_SIZE),
742 Pmode);
bcead286
BS
743#endif
744}
745\f
746/* Determine whether c6x_output_mi_thunk can succeed. */
747
748static bool
749c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
750 HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
751 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
752 const_tree function ATTRIBUTE_UNUSED)
753{
754 return !TARGET_LONG_CALLS;
755}
756
757/* Output the assembler code for a thunk function. THUNK is the
758 declaration for the thunk function itself, FUNCTION is the decl for
759 the target function. DELTA is an immediate constant offset to be
760 added to THIS. If VCALL_OFFSET is nonzero, the word at
761 *(*this + vcall_offset) should be added to THIS. */
762
763static void
764c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
765 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
766 HOST_WIDE_INT vcall_offset, tree function)
767{
768 rtx xops[5];
769 /* The this parameter is passed as the first argument. */
770 rtx this_rtx = gen_rtx_REG (Pmode, REG_A4);
771
772 c6x_current_insn = NULL_RTX;
773
774 xops[4] = XEXP (DECL_RTL (function), 0);
775 if (!vcall_offset)
776 {
777 output_asm_insn ("b .s2 \t%4", xops);
778 if (!delta)
779 output_asm_insn ("nop 5", xops);
780 }
781
782 /* Adjust the this parameter by a fixed constant. */
783 if (delta)
784 {
785 xops[0] = GEN_INT (delta);
786 xops[1] = this_rtx;
787 if (delta >= -16 && delta <= 15)
788 {
789 output_asm_insn ("add .s1 %0, %1, %1", xops);
790 if (!vcall_offset)
791 output_asm_insn ("nop 4", xops);
792 }
793 else if (delta >= 16 && delta < 32)
794 {
795 output_asm_insn ("add .d1 %0, %1, %1", xops);
796 if (!vcall_offset)
797 output_asm_insn ("nop 4", xops);
798 }
799 else if (delta >= -32768 && delta < 32768)
800 {
801 output_asm_insn ("mvk .s1 %0, A0", xops);
802 output_asm_insn ("add .d1 %1, A0, %1", xops);
803 if (!vcall_offset)
804 output_asm_insn ("nop 3", xops);
805 }
806 else
807 {
808 output_asm_insn ("mvkl .s1 %0, A0", xops);
809 output_asm_insn ("mvkh .s1 %0, A0", xops);
810 output_asm_insn ("add .d1 %1, A0, %1", xops);
811 if (!vcall_offset)
812 output_asm_insn ("nop 3", xops);
813 }
814 }
815
816 /* Adjust the this parameter by a value stored in the vtable. */
817 if (vcall_offset)
818 {
819 rtx a0tmp = gen_rtx_REG (Pmode, REG_A0);
820 rtx a3tmp = gen_rtx_REG (Pmode, REG_A3);
821
822 xops[1] = a3tmp;
823 xops[2] = a0tmp;
824 xops[3] = gen_rtx_MEM (Pmode, a0tmp);
825 output_asm_insn ("mv .s1 a4, %2", xops);
826 output_asm_insn ("ldw .d1t1 %3, %2", xops);
827
828 /* Adjust the this parameter. */
0a81f074
RS
829 xops[0] = gen_rtx_MEM (Pmode, plus_constant (Pmode, a0tmp,
830 vcall_offset));
bcead286
BS
831 if (!memory_operand (xops[0], Pmode))
832 {
833 rtx tmp2 = gen_rtx_REG (Pmode, REG_A1);
834 xops[0] = GEN_INT (vcall_offset);
835 xops[1] = tmp2;
836 output_asm_insn ("mvkl .s1 %0, %1", xops);
837 output_asm_insn ("mvkh .s1 %0, %1", xops);
838 output_asm_insn ("nop 2", xops);
839 output_asm_insn ("add .d1 %2, %1, %2", xops);
840 xops[0] = gen_rtx_MEM (Pmode, a0tmp);
841 }
842 else
843 output_asm_insn ("nop 4", xops);
844 xops[2] = this_rtx;
845 output_asm_insn ("ldw .d1t1 %0, %1", xops);
846 output_asm_insn ("|| b .s2 \t%4", xops);
847 output_asm_insn ("nop 4", xops);
848 output_asm_insn ("add .d1 %2, %1, %2", xops);
849 }
850}
851\f
852/* Return true if EXP goes in small data/bss. */
853
854static bool
855c6x_in_small_data_p (const_tree exp)
856{
857 /* We want to merge strings, so we never consider them small data. */
858 if (TREE_CODE (exp) == STRING_CST)
859 return false;
860
861 /* Functions are never small data. */
862 if (TREE_CODE (exp) == FUNCTION_DECL)
863 return false;
864
865 if (TREE_CODE (exp) == VAR_DECL && DECL_WEAK (exp))
866 return false;
867
868 if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
869 {
870 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
871
872 if (strcmp (section, ".neardata") == 0
873 || strncmp (section, ".neardata.", 10) == 0
874 || strncmp (section, ".gnu.linkonce.s.", 16) == 0
875 || strcmp (section, ".bss") == 0
876 || strncmp (section, ".bss.", 5) == 0
877 || strncmp (section, ".gnu.linkonce.sb.", 17) == 0
878 || strcmp (section, ".rodata") == 0
879 || strncmp (section, ".rodata.", 8) == 0
880 || strncmp (section, ".gnu.linkonce.s2.", 17) == 0)
881 return true;
882 }
883 else
884 return PLACE_IN_SDATA_P (exp);
885
886 return false;
887}
888
889/* Return a section for X. The only special thing we do here is to
890 honor small data. We don't have a tree type, so we can't use the
891 PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
892 everything sized 8 bytes or smaller into small data. */
893
894static section *
895c6x_select_rtx_section (enum machine_mode mode, rtx x,
896 unsigned HOST_WIDE_INT align)
897{
898 if (c6x_sdata_mode == C6X_SDATA_ALL
899 || (c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE (mode) <= 8))
900 /* ??? Consider using mergeable sdata sections. */
901 return sdata_section;
902 else
903 return default_elf_select_rtx_section (mode, x, align);
904}
905
906static section *
907c6x_elf_select_section (tree decl, int reloc,
908 unsigned HOST_WIDE_INT align)
909{
910 const char *sname = NULL;
911 unsigned int flags = SECTION_WRITE;
912 if (c6x_in_small_data_p (decl))
913 {
914 switch (categorize_decl_for_section (decl, reloc))
915 {
916 case SECCAT_SRODATA:
917 sname = ".rodata";
918 flags = 0;
919 break;
920 case SECCAT_SDATA:
921 sname = ".neardata";
922 break;
923 case SECCAT_SBSS:
924 sname = ".bss";
925 flags |= SECTION_BSS;
926 default:
927 break;
928 }
929 }
930 else
931 {
932 switch (categorize_decl_for_section (decl, reloc))
933 {
934 case SECCAT_DATA:
935 sname = ".fardata";
936 break;
937 case SECCAT_DATA_REL:
938 sname = ".fardata.rel";
939 break;
940 case SECCAT_DATA_REL_LOCAL:
941 sname = ".fardata.rel.local";
942 break;
943 case SECCAT_DATA_REL_RO:
944 sname = ".fardata.rel.ro";
945 break;
946 case SECCAT_DATA_REL_RO_LOCAL:
947 sname = ".fardata.rel.ro.local";
948 break;
949 case SECCAT_BSS:
950 sname = ".far";
951 flags |= SECTION_BSS;
952 break;
953 case SECCAT_RODATA:
954 sname = ".const";
955 flags = 0;
956 break;
957 case SECCAT_SRODATA:
958 case SECCAT_SDATA:
959 case SECCAT_SBSS:
960 gcc_unreachable ();
961 default:
962 break;
963 }
964 }
965 if (sname)
966 {
967 /* We might get called with string constants, but get_named_section
968 doesn't like them as they are not DECLs. Also, we need to set
969 flags in that case. */
970 if (!DECL_P (decl))
971 return get_section (sname, flags, NULL);
972 return get_named_section (decl, sname, reloc);
973 }
974
975 return default_elf_select_section (decl, reloc, align);
976}
977
978/* Build up a unique section name, expressed as a
979 STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
980 RELOC indicates whether the initial value of EXP requires
981 link-time relocations. */
982
983static void ATTRIBUTE_UNUSED
984c6x_elf_unique_section (tree decl, int reloc)
985{
986 const char *prefix = NULL;
987 /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
988 bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
989
990 if (c6x_in_small_data_p (decl))
991 {
992 switch (categorize_decl_for_section (decl, reloc))
993 {
994 case SECCAT_SDATA:
995 prefix = one_only ? ".s" : ".neardata";
996 break;
997 case SECCAT_SBSS:
998 prefix = one_only ? ".sb" : ".bss";
999 break;
1000 case SECCAT_SRODATA:
1001 prefix = one_only ? ".s2" : ".rodata";
1002 break;
1003 case SECCAT_RODATA_MERGE_STR:
1004 case SECCAT_RODATA_MERGE_STR_INIT:
1005 case SECCAT_RODATA_MERGE_CONST:
1006 case SECCAT_RODATA:
1007 case SECCAT_DATA:
1008 case SECCAT_DATA_REL:
1009 case SECCAT_DATA_REL_LOCAL:
1010 case SECCAT_DATA_REL_RO:
1011 case SECCAT_DATA_REL_RO_LOCAL:
1012 gcc_unreachable ();
1013 default:
1014 /* Everything else we place into default sections and hope for the
1015 best. */
1016 break;
1017 }
1018 }
1019 else
1020 {
1021 switch (categorize_decl_for_section (decl, reloc))
1022 {
1023 case SECCAT_DATA:
1024 case SECCAT_DATA_REL:
1025 case SECCAT_DATA_REL_LOCAL:
1026 case SECCAT_DATA_REL_RO:
1027 case SECCAT_DATA_REL_RO_LOCAL:
1028 prefix = one_only ? ".fd" : ".fardata";
1029 break;
1030 case SECCAT_BSS:
1031 prefix = one_only ? ".fb" : ".far";
1032 break;
1033 case SECCAT_RODATA:
1034 case SECCAT_RODATA_MERGE_STR:
1035 case SECCAT_RODATA_MERGE_STR_INIT:
1036 case SECCAT_RODATA_MERGE_CONST:
1037 prefix = one_only ? ".fr" : ".const";
1038 break;
1039 case SECCAT_SRODATA:
1040 case SECCAT_SDATA:
1041 case SECCAT_SBSS:
1042 gcc_unreachable ();
1043 default:
1044 break;
1045 }
1046 }
1047
1048 if (prefix)
1049 {
1050 const char *name, *linkonce;
1051 char *string;
1052
1053 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1054 name = targetm.strip_name_encoding (name);
1055
1056 /* If we're using one_only, then there needs to be a .gnu.linkonce
1057 prefix to the section name. */
1058 linkonce = one_only ? ".gnu.linkonce" : "";
1059
1060 string = ACONCAT ((linkonce, prefix, ".", name, NULL));
1061
1062 DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
1063 return;
1064 }
1065 default_unique_section (decl, reloc);
1066}
1067
1068static unsigned int
1069c6x_section_type_flags (tree decl, const char *name, int reloc)
1070{
1071 unsigned int flags = 0;
1072
1073 if (strcmp (name, ".far") == 0
1074 || strncmp (name, ".far.", 5) == 0)
1075 flags |= SECTION_BSS;
1076
1077 flags |= default_section_type_flags (decl, name, reloc);
1078
1079 return flags;
1080}
1081\f
1082/* Checks whether the given CALL_EXPR would use a caller saved
1083 register. This is used to decide whether sibling call optimization
1084 could be performed on the respective function call. */
1085
1086static bool
1087c6x_call_saved_register_used (tree call_expr)
1088{
1089 CUMULATIVE_ARGS cum_v;
1090 cumulative_args_t cum;
1091 HARD_REG_SET call_saved_regset;
1092 tree parameter;
1093 enum machine_mode mode;
1094 tree type;
1095 rtx parm_rtx;
1096 int i;
1097
1098 INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0);
1099 cum = pack_cumulative_args (&cum_v);
1100
1101 COMPL_HARD_REG_SET (call_saved_regset, call_used_reg_set);
1102 for (i = 0; i < call_expr_nargs (call_expr); i++)
1103 {
1104 parameter = CALL_EXPR_ARG (call_expr, i);
1105 gcc_assert (parameter);
1106
1107 /* For an undeclared variable passed as parameter we will get
1108 an ERROR_MARK node here. */
1109 if (TREE_CODE (parameter) == ERROR_MARK)
1110 return true;
1111
1112 type = TREE_TYPE (parameter);
1113 gcc_assert (type);
1114
1115 mode = TYPE_MODE (type);
1116 gcc_assert (mode);
1117
1118 if (pass_by_reference (&cum_v, mode, type, true))
1119 {
1120 mode = Pmode;
1121 type = build_pointer_type (type);
1122 }
1123
1124 parm_rtx = c6x_function_arg (cum, mode, type, 0);
1125
1126 c6x_function_arg_advance (cum, mode, type, 0);
1127
1128 if (!parm_rtx)
1129 continue;
1130
1131 if (REG_P (parm_rtx)
1132 && overlaps_hard_reg_set_p (call_saved_regset, GET_MODE (parm_rtx),
1133 REGNO (parm_rtx)))
1134 return true;
1135 if (GET_CODE (parm_rtx) == PARALLEL)
1136 {
1137 int n = XVECLEN (parm_rtx, 0);
1138 while (n-- > 0)
1139 {
1140 rtx x = XEXP (XVECEXP (parm_rtx, 0, n), 0);
1141 if (REG_P (x)
1142 && overlaps_hard_reg_set_p (call_saved_regset,
1143 GET_MODE (x), REGNO (x)))
1144 return true;
1145 }
1146 }
1147 }
1148 return false;
1149}
1150
1151/* Decide whether we can make a sibling call to a function. DECL is the
1152 declaration of the function being targeted by the call and EXP is the
1153 CALL_EXPR representing the call. */
1154
1155static bool
1156c6x_function_ok_for_sibcall (tree decl, tree exp)
1157{
1158 /* Registers A10, A12, B10 and B12 are available as arguments
1159 register but unfortunately caller saved. This makes functions
1160 needing these registers for arguments not suitable for
1161 sibcalls. */
1162 if (c6x_call_saved_register_used (exp))
1163 return false;
1164
1165 if (!flag_pic)
1166 return true;
1167
1168 if (TARGET_DSBT)
1169 {
1170 /* When compiling for DSBT, the calling function must be local,
1171 so that when we reload B14 in the sibcall epilogue, it will
1172 not change its value. */
1173 struct cgraph_local_info *this_func;
1174
1175 if (!decl)
1176 /* Not enough information. */
1177 return false;
1178
1179 this_func = cgraph_local_info (current_function_decl);
1180 return this_func->local;
1181 }
1182
1183 return true;
1184}
1185
1186/* Return true if DECL is known to be linked into section SECTION. */
1187
1188static bool
1189c6x_function_in_section_p (tree decl, section *section)
1190{
1191 /* We can only be certain about functions defined in the same
1192 compilation unit. */
1193 if (!TREE_STATIC (decl))
1194 return false;
1195
1196 /* Make sure that SYMBOL always binds to the definition in this
1197 compilation unit. */
1198 if (!targetm.binds_local_p (decl))
1199 return false;
1200
1201 /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
1202 if (!DECL_SECTION_NAME (decl))
1203 {
1204 /* Make sure that we will not create a unique section for DECL. */
1205 if (flag_function_sections || DECL_ONE_ONLY (decl))
1206 return false;
1207 }
1208
1209 return function_section (decl) == section;
1210}
1211
1212/* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
1213 as a long call. */
1214bool
1215c6x_long_call_p (rtx op)
1216{
1217 tree decl;
1218
1219 if (!TARGET_LONG_CALLS)
1220 return false;
1221
1222 decl = SYMBOL_REF_DECL (op);
1223
1224 /* Try to determine whether the symbol is in the same section as the current
1225 function. Be conservative, and only cater for cases in which the
1226 whole of the current function is placed in the same section. */
1227 if (decl != NULL_TREE
1228 && !flag_reorder_blocks_and_partition
1229 && TREE_CODE (decl) == FUNCTION_DECL
1230 && c6x_function_in_section_p (decl, current_function_section ()))
1231 return false;
1232
1233 return true;
1234}
1235
1236/* Emit the sequence for a call. */
1237void
1238c6x_expand_call (rtx retval, rtx address, bool sibcall)
1239{
1240 rtx callee = XEXP (address, 0);
1241 rtx call_insn;
1242
1243 if (!c6x_call_operand (callee, Pmode))
1244 {
1245 callee = force_reg (Pmode, callee);
1246 address = change_address (address, Pmode, callee);
1247 }
1248 call_insn = gen_rtx_CALL (VOIDmode, address, const0_rtx);
1249 if (sibcall)
1250 {
1251 call_insn = emit_call_insn (call_insn);
1252 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
1253 gen_rtx_REG (Pmode, REG_B3));
1254 }
1255 else
1256 {
1257 if (retval == NULL_RTX)
1258 call_insn = emit_call_insn (call_insn);
1259 else
1260 call_insn = emit_call_insn (gen_rtx_SET (GET_MODE (retval), retval,
1261 call_insn));
1262 }
1263 if (flag_pic)
1264 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
1265}
1266
1267/* Legitimize PIC addresses. If the address is already position-independent,
1268 we return ORIG. Newly generated position-independent addresses go into a
1269 reg. This is REG if nonzero, otherwise we allocate register(s) as
1270 necessary. PICREG is the register holding the pointer to the PIC offset
1271 table. */
1272
1273static rtx
1274legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
1275{
1276 rtx addr = orig;
1277 rtx new_rtx = orig;
1278
1279 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
1280 {
1281 int unspec = UNSPEC_LOAD_GOT;
1282 rtx tmp;
1283
1284 if (reg == 0)
1285 {
1286 gcc_assert (can_create_pseudo_p ());
1287 reg = gen_reg_rtx (Pmode);
1288 }
1289 if (flag_pic == 2)
1290 {
1291 if (can_create_pseudo_p ())
1292 tmp = gen_reg_rtx (Pmode);
1293 else
1294 tmp = reg;
1295 emit_insn (gen_movsi_gotoff_high (tmp, addr));
1296 emit_insn (gen_movsi_gotoff_lo_sum (tmp, tmp, addr));
1297 emit_insn (gen_load_got_gotoff (reg, picreg, tmp));
1298 }
1299 else
1300 {
1301 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
1302 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
1303
1304 emit_move_insn (reg, new_rtx);
1305 }
1306 if (picreg == pic_offset_table_rtx)
1307 crtl->uses_pic_offset_table = 1;
1308 return reg;
1309 }
1310
1311 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1312 {
1313 rtx base;
1314
1315 if (GET_CODE (addr) == CONST)
1316 {
1317 addr = XEXP (addr, 0);
1318 gcc_assert (GET_CODE (addr) == PLUS);
1319 }
1320
1321 if (XEXP (addr, 0) == picreg)
1322 return orig;
1323
1324 if (reg == 0)
1325 {
1326 gcc_assert (can_create_pseudo_p ());
1327 reg = gen_reg_rtx (Pmode);
1328 }
1329
1330 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
1331 addr = legitimize_pic_address (XEXP (addr, 1),
1332 base == reg ? NULL_RTX : reg,
1333 picreg);
1334
1335 if (GET_CODE (addr) == CONST_INT)
1336 {
1337 gcc_assert (! reload_in_progress && ! reload_completed);
1338 addr = force_reg (Pmode, addr);
1339 }
1340
1341 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
1342 {
1343 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
1344 addr = XEXP (addr, 1);
1345 }
1346
1347 return gen_rtx_PLUS (Pmode, base, addr);
1348 }
1349
1350 return new_rtx;
1351}
1352
1353/* Expand a move operation in mode MODE. The operands are in OPERANDS.
1354 Returns true if no further code must be generated, false if the caller
1355 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1356
1357bool
1358expand_move (rtx *operands, enum machine_mode mode)
1359{
1360 rtx dest = operands[0];
1361 rtx op = operands[1];
1362
1363 if ((reload_in_progress | reload_completed) == 0
1364 && GET_CODE (dest) == MEM && GET_CODE (op) != REG)
1365 operands[1] = force_reg (mode, op);
1366 else if (mode == SImode && symbolic_operand (op, SImode))
1367 {
1368 if (flag_pic)
1369 {
1370 if (sdata_symbolic_operand (op, SImode))
1371 {
1372 emit_insn (gen_load_sdata_pic (dest, pic_offset_table_rtx, op));
1373 crtl->uses_pic_offset_table = 1;
1374 return true;
1375 }
1376 else
1377 {
1378 rtx temp = (reload_completed || reload_in_progress
1379 ? dest : gen_reg_rtx (Pmode));
1380
1381 operands[1] = legitimize_pic_address (op, temp,
1382 pic_offset_table_rtx);
1383 }
1384 }
1385 else if (reload_completed
1386 && !sdata_symbolic_operand (op, SImode))
1387 {
1388 emit_insn (gen_movsi_high (dest, op));
1389 emit_insn (gen_movsi_lo_sum (dest, dest, op));
1390 return true;
1391 }
1392 }
1393 return false;
1394}
1395
1396/* This function is called when we're about to expand an integer compare
1397 operation which performs COMPARISON. It examines the second operand,
1398 and if it is an integer constant that cannot be used directly on the
1399 current machine in a comparison insn, it returns true. */
1400bool
1401c6x_force_op_for_comparison_p (enum rtx_code code, rtx op)
1402{
1403 if (!CONST_INT_P (op) || satisfies_constraint_Iu4 (op))
1404 return false;
1405
1406 if ((code == EQ || code == LT || code == GT)
1407 && !satisfies_constraint_Is5 (op))
1408 return true;
1409 if ((code == GTU || code == LTU)
1410 && (!TARGET_INSNS_64 || !satisfies_constraint_Iu5 (op)))
1411 return true;
1412
1413 return false;
1414}
1415
1416/* Emit comparison instruction if necessary, returning the expression
1417 that holds the compare result in the proper mode. Return the comparison
1418 that should be used in the jump insn. */
1419
1420rtx
1421c6x_expand_compare (rtx comparison, enum machine_mode mode)
1422{
1423 enum rtx_code code = GET_CODE (comparison);
1424 rtx op0 = XEXP (comparison, 0);
1425 rtx op1 = XEXP (comparison, 1);
1426 rtx cmp;
1427 enum rtx_code jump_code = code;
1428 enum machine_mode op_mode = GET_MODE (op0);
1429
1430 if (op_mode == DImode && (code == NE || code == EQ) && op1 == const0_rtx)
1431 {
1432 rtx t = gen_reg_rtx (SImode);
1433 emit_insn (gen_iorsi3 (t, gen_lowpart (SImode, op0),
1434 gen_highpart (SImode, op0)));
1435 op_mode = SImode;
1436 cmp = t;
1437 }
1438 else if (op_mode == DImode)
1439 {
1440 rtx lo[2], high[2];
1441 rtx cmp1, cmp2;
1442
1443 if (code == NE || code == GEU || code == LEU || code == GE || code == LE)
1444 {
1445 code = reverse_condition (code);
1446 jump_code = EQ;
1447 }
1448 else
1449 jump_code = NE;
1450
1451 split_di (&op0, 1, lo, high);
1452 split_di (&op1, 1, lo + 1, high + 1);
1453
1454 if (c6x_force_op_for_comparison_p (code, high[1])
1455 || c6x_force_op_for_comparison_p (EQ, high[1]))
1456 high[1] = force_reg (SImode, high[1]);
1457
1458 cmp1 = gen_reg_rtx (SImode);
1459 cmp2 = gen_reg_rtx (SImode);
1460 emit_insn (gen_rtx_SET (VOIDmode, cmp1,
1461 gen_rtx_fmt_ee (code, SImode, high[0], high[1])));
1462 if (code == EQ)
1463 {
1464 if (c6x_force_op_for_comparison_p (code, lo[1]))
1465 lo[1] = force_reg (SImode, lo[1]);
1466 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1467 gen_rtx_fmt_ee (code, SImode, lo[0], lo[1])));
1468 emit_insn (gen_andsi3 (cmp1, cmp1, cmp2));
1469 }
1470 else
1471 {
1472 emit_insn (gen_rtx_SET (VOIDmode, cmp2,
1473 gen_rtx_EQ (SImode, high[0], high[1])));
1474 if (code == GT)
1475 code = GTU;
1476 else if (code == LT)
1477 code = LTU;
1478 if (c6x_force_op_for_comparison_p (code, lo[1]))
1479 lo[1] = force_reg (SImode, lo[1]);
1480 emit_insn (gen_cmpsi_and (cmp2, gen_rtx_fmt_ee (code, SImode,
1481 lo[0], lo[1]),
1482 lo[0], lo[1], cmp2));
1483 emit_insn (gen_iorsi3 (cmp1, cmp1, cmp2));
1484 }
1485 cmp = cmp1;
1486 }
1487 else if (TARGET_FP && !flag_finite_math_only
1488 && (op_mode == DFmode || op_mode == SFmode)
1489 && code != EQ && code != NE && code != LT && code != GT
1490 && code != UNLE && code != UNGE)
1491 {
1492 enum rtx_code code1, code2, code3;
1493 rtx (*fn) (rtx, rtx, rtx, rtx, rtx);
1494
1495 jump_code = NE;
1496 code3 = UNKNOWN;
1497 switch (code)
1498 {
1499 case UNLT:
1500 case UNGT:
1501 jump_code = EQ;
1502 /* fall through */
1503 case LE:
1504 case GE:
1505 code1 = code == LE || code == UNGT ? LT : GT;
1506 code2 = EQ;
1507 break;
1508
1509 case UNORDERED:
1510 jump_code = EQ;
1511 /* fall through */
1512 case ORDERED:
1513 code3 = EQ;
1514 /* fall through */
1515 case LTGT:
1516 code1 = LT;
1517 code2 = GT;
1518 break;
1519
1520 case UNEQ:
1521 code1 = LT;
1522 code2 = GT;
1523 jump_code = EQ;
1524 break;
1525
1526 default:
1527 gcc_unreachable ();
1528 }
1529
1530 cmp = gen_reg_rtx (SImode);
1531 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1532 gen_rtx_fmt_ee (code1, SImode, op0, op1)));
1533 fn = op_mode == DFmode ? gen_cmpdf_ior : gen_cmpsf_ior;
1534 emit_insn (fn (cmp, gen_rtx_fmt_ee (code2, SImode, op0, op1),
1535 op0, op1, cmp));
1536 if (code3 != UNKNOWN)
1537 emit_insn (fn (cmp, gen_rtx_fmt_ee (code3, SImode, op0, op1),
1538 op0, op1, cmp));
1539 }
1540 else if (op_mode == SImode && (code == NE || code == EQ) && op1 == const0_rtx)
1541 cmp = op0;
1542 else
1543 {
1544 bool is_fp_libfunc;
1545 is_fp_libfunc = !TARGET_FP && (op_mode == DFmode || op_mode == SFmode);
1546
1547 if ((code == NE || code == GEU || code == LEU || code == GE || code == LE)
1548 && !is_fp_libfunc)
1549 {
1550 code = reverse_condition (code);
1551 jump_code = EQ;
1552 }
1553 else if (code == UNGE)
1554 {
1555 code = LT;
1556 jump_code = EQ;
1557 }
1558 else if (code == UNLE)
1559 {
1560 code = GT;
1561 jump_code = EQ;
1562 }
1563 else
1564 jump_code = NE;
1565
1566 if (is_fp_libfunc)
1567 {
1568 rtx insns;
1569 rtx libfunc;
1570 switch (code)
1571 {
1572 case EQ:
1573 libfunc = op_mode == DFmode ? eqdf_libfunc : eqsf_libfunc;
1574 break;
1575 case NE:
1576 libfunc = op_mode == DFmode ? nedf_libfunc : nesf_libfunc;
1577 break;
1578 case GT:
1579 libfunc = op_mode == DFmode ? gtdf_libfunc : gtsf_libfunc;
1580 break;
1581 case GE:
1582 libfunc = op_mode == DFmode ? gedf_libfunc : gesf_libfunc;
1583 break;
1584 case LT:
1585 libfunc = op_mode == DFmode ? ltdf_libfunc : ltsf_libfunc;
1586 break;
1587 case LE:
1588 libfunc = op_mode == DFmode ? ledf_libfunc : lesf_libfunc;
1589 break;
1590 default:
1591 gcc_unreachable ();
1592 }
1593 start_sequence ();
1594
1595 cmp = emit_library_call_value (libfunc, 0, LCT_CONST, SImode, 2,
1596 op0, op_mode, op1, op_mode);
1597 insns = get_insns ();
1598 end_sequence ();
1599
1600 emit_libcall_block (insns, cmp, cmp,
1601 gen_rtx_fmt_ee (code, SImode, op0, op1));
1602 }
1603 else
1604 {
1605 cmp = gen_reg_rtx (SImode);
1606 if (c6x_force_op_for_comparison_p (code, op1))
1607 op1 = force_reg (SImode, op1);
1608 emit_insn (gen_rtx_SET (VOIDmode, cmp,
1609 gen_rtx_fmt_ee (code, SImode, op0, op1)));
1610 }
1611 }
1612
1613 return gen_rtx_fmt_ee (jump_code, mode, cmp, const0_rtx);
1614}
1615
1616/* Return one word of double-word value OP. HIGH_P is true to select the
1617 high part, false to select the low part. When encountering auto-increment
1618 addressing, we make the assumption that the low part is going to be accessed
1619 first. */
1620
1621rtx
1622c6x_subword (rtx op, bool high_p)
1623{
1624 unsigned int byte;
1625 enum machine_mode mode;
1626
1627 mode = GET_MODE (op);
1628 if (mode == VOIDmode)
1629 mode = DImode;
1630
1631 if (TARGET_BIG_ENDIAN ? !high_p : high_p)
1632 byte = UNITS_PER_WORD;
1633 else
1634 byte = 0;
1635
1636 if (MEM_P (op))
1637 {
1638 rtx addr = XEXP (op, 0);
1639 if (GET_CODE (addr) == PLUS || REG_P (addr))
1640 return adjust_address (op, word_mode, byte);
1641 /* FIXME: should really support autoincrement addressing for
1642 multi-word modes. */
1643 gcc_unreachable ();
1644 }
1645
1646 return simplify_gen_subreg (word_mode, op, mode, byte);
1647}
1648
1649/* Split one or more DImode RTL references into pairs of SImode
1650 references. The RTL can be REG, offsettable MEM, integer constant, or
1651 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1652 split and "num" is its length. lo_half and hi_half are output arrays
1653 that parallel "operands". */
1654
1655void
1656split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1657{
1658 while (num--)
1659 {
1660 rtx op = operands[num];
1661
1662 lo_half[num] = c6x_subword (op, false);
1663 hi_half[num] = c6x_subword (op, true);
1664 }
1665}
1666
1667/* Return true if VAL is a mask valid for a clr instruction. */
1668bool
1669c6x_valid_mask_p (HOST_WIDE_INT val)
1670{
1671 int i;
1672 for (i = 0; i < 32; i++)
1673 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1674 break;
1675 for (; i < 32; i++)
1676 if (val & ((unsigned HOST_WIDE_INT)1 << i))
1677 break;
1678 for (; i < 32; i++)
1679 if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
1680 return false;
1681 return true;
1682}
1683
1684/* Expand a block move for a movmemM pattern. */
1685
1686bool
1687c6x_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
1688 rtx expected_align_exp ATTRIBUTE_UNUSED,
1689 rtx expected_size_exp ATTRIBUTE_UNUSED)
1690{
1691 unsigned HOST_WIDE_INT align = 1;
1692 unsigned HOST_WIDE_INT src_mem_align, dst_mem_align, min_mem_align;
1693 unsigned HOST_WIDE_INT count = 0, offset = 0;
1694 unsigned int biggest_move = TARGET_STDW ? 8 : 4;
1695
1696 if (CONST_INT_P (align_exp))
1697 align = INTVAL (align_exp);
1698
1699 src_mem_align = MEM_ALIGN (src) / BITS_PER_UNIT;
1700 dst_mem_align = MEM_ALIGN (dst) / BITS_PER_UNIT;
1701 min_mem_align = MIN (src_mem_align, dst_mem_align);
1702
1703 if (min_mem_align > align)
1704 align = min_mem_align / BITS_PER_UNIT;
1705 if (src_mem_align < align)
1706 src_mem_align = align;
1707 if (dst_mem_align < align)
1708 dst_mem_align = align;
1709
1710 if (CONST_INT_P (count_exp))
1711 count = INTVAL (count_exp);
1712 else
1713 return false;
1714
1715 /* Make sure we don't need to care about overflow later on. */
1716 if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
1717 return false;
1718
1719 if (count >= 28 && (count & 3) == 0 && align >= 4)
1720 {
1721 tree dst_expr = MEM_EXPR (dst);
1722 tree src_expr = MEM_EXPR (src);
1723 rtx fn = TARGET_INSNS_64PLUS ? strasgi64p_libfunc : strasgi_libfunc;
1724 rtx srcreg = force_reg (Pmode, XEXP (src, 0));
1725 rtx dstreg = force_reg (Pmode, XEXP (dst, 0));
1726
1727 if (src_expr)
1728 mark_addressable (src_expr);
1729 if (dst_expr)
1730 mark_addressable (dst_expr);
1731 emit_library_call (fn, LCT_NORMAL, VOIDmode, 3,
1732 dstreg, Pmode, srcreg, Pmode, count_exp, SImode);
1733 return true;
1734 }
1735
1736 if (biggest_move > align && !TARGET_INSNS_64)
1737 biggest_move = align;
1738
1739 if (count / biggest_move > 7)
1740 return false;
1741
1742 while (count > 0)
1743 {
1744 rtx reg, reg_lowpart;
1745 enum machine_mode srcmode, dstmode;
1746 unsigned HOST_WIDE_INT src_size, dst_size, src_left;
1747 int shift;
1748 rtx srcmem, dstmem;
1749
1750 while (biggest_move > count)
1751 biggest_move /= 2;
1752
1753 src_size = dst_size = biggest_move;
1754 if (src_size > src_mem_align && src_size == 2)
1755 src_size = 1;
1756 if (dst_size > dst_mem_align && dst_size == 2)
1757 dst_size = 1;
1758
1759 if (dst_size > src_size)
1760 dst_size = src_size;
1761
1762 srcmode = mode_for_size (src_size * BITS_PER_UNIT, MODE_INT, 0);
1763 dstmode = mode_for_size (dst_size * BITS_PER_UNIT, MODE_INT, 0);
1764 if (src_size >= 4)
1765 reg_lowpart = reg = gen_reg_rtx (srcmode);
1766 else
1767 {
1768 reg = gen_reg_rtx (SImode);
1769 reg_lowpart = gen_lowpart (srcmode, reg);
1770 }
1771
1772 srcmem = adjust_address (copy_rtx (src), srcmode, offset);
1773
1774 if (src_size > src_mem_align)
1775 {
1776 enum insn_code icode = (srcmode == SImode ? CODE_FOR_movmisalignsi
1777 : CODE_FOR_movmisaligndi);
1778 emit_insn (GEN_FCN (icode) (reg_lowpart, srcmem));
1779 }
1780 else
1781 emit_move_insn (reg_lowpart, srcmem);
1782
1783 src_left = src_size;
1784 shift = TARGET_BIG_ENDIAN ? (src_size - dst_size) * BITS_PER_UNIT : 0;
1785 while (src_left > 0)
1786 {
1787 rtx dstreg = reg_lowpart;
1788
1789 if (src_size > dst_size)
1790 {
1791 rtx srcword = reg;
1792 int shift_amount = shift & (BITS_PER_WORD - 1);
1793 if (src_size > 4)
1794 srcword = operand_subword_force (srcword, src_left >= 4 ? 0 : 4,
1795 SImode);
1796 if (shift_amount > 0)
1797 {
1798 dstreg = gen_reg_rtx (SImode);
1799 emit_insn (gen_lshrsi3 (dstreg, srcword,
1800 GEN_INT (shift_amount)));
1801 }
1802 else
1803 dstreg = srcword;
1804 dstreg = gen_lowpart (dstmode, dstreg);
1805 }
1806
1807 dstmem = adjust_address (copy_rtx (dst), dstmode, offset);
1808 if (dst_size > dst_mem_align)
1809 {
1810 enum insn_code icode = (dstmode == SImode ? CODE_FOR_movmisalignsi
1811 : CODE_FOR_movmisaligndi);
1812 emit_insn (GEN_FCN (icode) (dstmem, dstreg));
1813 }
1814 else
1815 emit_move_insn (dstmem, dstreg);
1816
1817 if (TARGET_BIG_ENDIAN)
1818 shift -= dst_size * BITS_PER_UNIT;
1819 else
1820 shift += dst_size * BITS_PER_UNIT;
1821 offset += dst_size;
1822 src_left -= dst_size;
1823 }
1824 count -= src_size;
1825 }
1826 return true;
1827}
1828\f
1829/* Subroutine of print_address_operand, print a single address offset OFF for
1830 a memory access of mode MEM_MODE, choosing between normal form and scaled
1831 form depending on the type of the insn. Misaligned memory references must
1832 use the scaled form. */
1833
1834static void
1835print_address_offset (FILE *file, rtx off, enum machine_mode mem_mode)
1836{
1837 rtx pat;
1838
1839 if (c6x_current_insn != NULL_RTX)
1840 {
1841 pat = PATTERN (c6x_current_insn);
1842 if (GET_CODE (pat) == COND_EXEC)
1843 pat = COND_EXEC_CODE (pat);
1844 if (GET_CODE (pat) == PARALLEL)
1845 pat = XVECEXP (pat, 0, 0);
1846
1847 if (GET_CODE (pat) == SET
1848 && GET_CODE (SET_SRC (pat)) == UNSPEC
1849 && XINT (SET_SRC (pat), 1) == UNSPEC_MISALIGNED_ACCESS)
1850 {
1851 gcc_assert (CONST_INT_P (off)
1852 && (INTVAL (off) & (GET_MODE_SIZE (mem_mode) - 1)) == 0);
1853 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1854 INTVAL (off) / GET_MODE_SIZE (mem_mode));
1855 return;
1856 }
1857 }
1858 fputs ("(", file);
1859 output_address (off);
1860 fputs (")", file);
1861}
1862
1863static bool
1864c6x_print_operand_punct_valid_p (unsigned char c)
1865{
1866 return c == '$' || c == '.' || c == '|';
1867}
1868
1869static void c6x_print_operand (FILE *, rtx, int);
1870
1871/* Subroutine of c6x_print_operand; used to print a memory reference X to FILE. */
1872
1873static void
1874c6x_print_address_operand (FILE *file, rtx x, enum machine_mode mem_mode)
1875{
1876 rtx off;
1877 switch (GET_CODE (x))
1878 {
1879 case PRE_MODIFY:
1880 case POST_MODIFY:
1881 if (GET_CODE (x) == POST_MODIFY)
1882 output_address (XEXP (x, 0));
1883 off = XEXP (XEXP (x, 1), 1);
1884 if (XEXP (x, 0) == stack_pointer_rtx)
1885 {
1886 if (GET_CODE (x) == PRE_MODIFY)
1887 gcc_assert (INTVAL (off) > 0);
1888 else
1889 gcc_assert (INTVAL (off) < 0);
1890 }
1891 if (CONST_INT_P (off) && INTVAL (off) < 0)
1892 {
1893 fprintf (file, "--");
1894 off = GEN_INT (-INTVAL (off));
1895 }
1896 else
1897 fprintf (file, "++");
1898 if (GET_CODE (x) == PRE_MODIFY)
1899 output_address (XEXP (x, 0));
1900 print_address_offset (file, off, mem_mode);
1901 break;
1902
1903 case PLUS:
1904 off = XEXP (x, 1);
1905 if (CONST_INT_P (off) && INTVAL (off) < 0)
1906 {
1907 fprintf (file, "-");
1908 off = GEN_INT (-INTVAL (off));
1909 }
1910 else
1911 fprintf (file, "+");
1912 output_address (XEXP (x, 0));
1913 print_address_offset (file, off, mem_mode);
1914 break;
1915
1916 case PRE_DEC:
1917 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1918 fprintf (file, "--");
1919 output_address (XEXP (x, 0));
1920 fprintf (file, "[1]");
1921 break;
1922 case PRE_INC:
1923 fprintf (file, "++");
1924 output_address (XEXP (x, 0));
1925 fprintf (file, "[1]");
1926 break;
1927 case POST_INC:
1928 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
1929 output_address (XEXP (x, 0));
1930 fprintf (file, "++[1]");
1931 break;
1932 case POST_DEC:
1933 output_address (XEXP (x, 0));
1934 fprintf (file, "--[1]");
1935 break;
1936
1937 case SYMBOL_REF:
1938 case CONST:
1939 case LABEL_REF:
1940 gcc_assert (sdata_symbolic_operand (x, Pmode));
1941 fprintf (file, "+B14(");
1942 output_addr_const (file, x);
1943 fprintf (file, ")");
1944 break;
1945
1946 case UNSPEC:
1947 switch (XINT (x, 1))
1948 {
1949 case UNSPEC_LOAD_GOT:
1950 fputs ("$GOT(", file);
1951 output_addr_const (file, XVECEXP (x, 0, 0));
1952 fputs (")", file);
1953 break;
1954 case UNSPEC_LOAD_SDATA:
1955 output_addr_const (file, XVECEXP (x, 0, 0));
1956 break;
1957 default:
1958 gcc_unreachable ();
1959 }
1960 break;
1961
1962 default:
1963 gcc_assert (GET_CODE (x) != MEM);
1964 c6x_print_operand (file, x, 0);
1965 break;
1966 }
1967}
1968
1969/* Return a single character, which is either 'l', 's', 'd' or 'm', which
1970 specifies the functional unit used by INSN. */
1971
1972char
1973c6x_get_unit_specifier (rtx insn)
1974{
1975 enum attr_units units;
1976
9771b263 1977 if (insn_info.exists ())
bcead286
BS
1978 {
1979 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
1980 return c6x_unit_names[unit][0];
1981 }
1982
1983 units = get_attr_units (insn);
1984 switch (units)
1985 {
1986 case UNITS_D:
1987 case UNITS_DL:
1988 case UNITS_DS:
1989 case UNITS_DLS:
1990 case UNITS_D_ADDR:
1991 return 'd';
1992 break;
1993 case UNITS_L:
1994 case UNITS_LS:
1995 return 'l';
1996 break;
1997 case UNITS_S:
1998 return 's';
1999 break;
2000 case UNITS_M:
2001 return 'm';
2002 break;
2003 default:
2004 gcc_unreachable ();
2005 }
2006}
2007
2008/* Prints the unit specifier field. */
2009static void
2010c6x_print_unit_specifier_field (FILE *file, rtx insn)
2011{
2012 enum attr_units units = get_attr_units (insn);
2013 enum attr_cross cross = get_attr_cross (insn);
2014 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
2015 int half;
2016 char unitspec;
2017
2018 if (units == UNITS_D_ADDR)
2019 {
2020 enum attr_addr_regfile arf = get_attr_addr_regfile (insn);
2021 int t_half;
2022 gcc_assert (arf != ADDR_REGFILE_UNKNOWN);
2023 half = arf == ADDR_REGFILE_A ? 1 : 2;
2024 t_half = rf == DEST_REGFILE_A ? 1 : 2;
2025 fprintf (file, ".d%dt%d", half, t_half);
2026 return;
2027 }
2028
9771b263 2029 if (insn_info.exists ())
bcead286
BS
2030 {
2031 int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
2032 fputs (".", file);
2033 fputs (c6x_unit_names[unit], file);
2034 if (cross == CROSS_Y)
2035 fputs ("x", file);
2036 return;
2037 }
2038
2039 gcc_assert (rf != DEST_REGFILE_UNKNOWN);
2040 unitspec = c6x_get_unit_specifier (insn);
2041 half = rf == DEST_REGFILE_A ? 1 : 2;
2042 fprintf (file, ".%c%d%s", unitspec, half, cross == CROSS_Y ? "x" : "");
2043}
2044
2045/* Output assembly language output for the address ADDR to FILE. */
2046static void
2047c6x_print_operand_address (FILE *file, rtx addr)
2048{
2049 c6x_print_address_operand (file, addr, VOIDmode);
2050}
2051
2052/* Print an operand, X, to FILE, with an optional modifier in CODE.
2053
2054 Meaning of CODE:
2055 $ -- print the unit specifier field for the instruction.
2056 . -- print the predicate for the instruction or an emptry string for an
2057 unconditional one.
2058 | -- print "||" if the insn should be issued in parallel with the previous
2059 one.
2060
2061 C -- print an opcode suffix for a reversed condition
2062 d -- H, W or D as a suffix for ADDA, based on the factor given by the
2063 operand
2064 D -- print either B, H, W or D as a suffix for ADDA, based on the size of
2065 the operand
2066 J -- print a predicate
2067 j -- like J, but use reverse predicate
2068 k -- treat a CONST_INT as a register number and print it as a register
2069 k -- like k, but print out a doubleword register
2070 n -- print an integer operand, negated
2071 p -- print the low part of a DImode register
2072 P -- print the high part of a DImode register
2073 r -- print the absolute value of an integer operand, shifted right by 1
2074 R -- print the absolute value of an integer operand, shifted right by 2
2075 f -- the first clear bit in an integer operand assumed to be a mask for
2076 a clr instruction
2077 F -- the last clear bit in such a mask
2078 s -- the first set bit in an integer operand assumed to be a mask for
2079 a set instruction
2080 S -- the last set bit in such a mask
2081 U -- print either 1 or 2, depending on the side of the machine used by
2082 the operand */
2083
2084static void
2085c6x_print_operand (FILE *file, rtx x, int code)
2086{
2087 int i;
2088 HOST_WIDE_INT v;
2089 tree t;
2090 enum machine_mode mode;
2091
2092 if (code == '|')
2093 {
2094 if (GET_MODE (c6x_current_insn) != TImode)
2095 fputs ("||", file);
2096 return;
2097 }
2098 if (code == '$')
2099 {
2100 c6x_print_unit_specifier_field (file, c6x_current_insn);
2101 return;
2102 }
2103
2104 if (code == '.')
2105 {
2106 x = current_insn_predicate;
2107 if (x)
2108 {
2109 unsigned int regno = REGNO (XEXP (x, 0));
2110 fputs ("[", file);
2111 if (GET_CODE (x) == EQ)
2112 fputs ("!", file);
2113 fputs (reg_names [regno], file);
2114 fputs ("]", file);
2115 }
2116 return;
2117 }
2118
2119 mode = GET_MODE (x);
2120
2121 switch (code)
2122 {
2123 case 'C':
2124 case 'c':
2125 {
2126 enum rtx_code c = GET_CODE (x);
2127 if (code == 'C')
2128 c = swap_condition (c);
2129 fputs (GET_RTX_NAME (c), file);
2130 }
2131 return;
2132
2133 case 'J':
2134 case 'j':
2135 {
2136 unsigned int regno = REGNO (XEXP (x, 0));
2137 if ((GET_CODE (x) == EQ) == (code == 'J'))
2138 fputs ("!", file);
2139 fputs (reg_names [regno], file);
2140 }
2141 return;
2142
2143 case 'k':
2144 gcc_assert (GET_CODE (x) == CONST_INT);
2145 v = INTVAL (x);
2146 fprintf (file, "%s", reg_names[v]);
2147 return;
2148 case 'K':
2149 gcc_assert (GET_CODE (x) == CONST_INT);
2150 v = INTVAL (x);
2151 gcc_assert ((v & 1) == 0);
2152 fprintf (file, "%s:%s", reg_names[v + 1], reg_names[v]);
2153 return;
2154
2155 case 's':
2156 case 'S':
2157 case 'f':
2158 case 'F':
2159 gcc_assert (GET_CODE (x) == CONST_INT);
2160 v = INTVAL (x);
2161 for (i = 0; i < 32; i++)
2162 {
2163 HOST_WIDE_INT tst = v & 1;
2164 if (((code == 'f' || code == 'F') && !tst)
2165 || ((code == 's' || code == 'S') && tst))
2166 break;
2167 v >>= 1;
2168 }
2169 if (code == 'f' || code == 's')
2170 {
2171 fprintf (file, "%d", i);
2172 return;
2173 }
2174 for (;i < 32; i++)
2175 {
2176 HOST_WIDE_INT tst = v & 1;
2177 if ((code == 'F' && tst) || (code == 'S' && !tst))
2178 break;
2179 v >>= 1;
2180 }
2181 fprintf (file, "%d", i - 1);
2182 return;
2183
2184 case 'n':
2185 gcc_assert (GET_CODE (x) == CONST_INT);
2186 output_addr_const (file, GEN_INT (-INTVAL (x)));
2187 return;
2188
2189 case 'r':
2190 gcc_assert (GET_CODE (x) == CONST_INT);
2191 v = INTVAL (x);
2192 if (v < 0)
2193 v = -v;
2194 output_addr_const (file, GEN_INT (v >> 1));
2195 return;
2196
2197 case 'R':
2198 gcc_assert (GET_CODE (x) == CONST_INT);
2199 v = INTVAL (x);
2200 if (v < 0)
2201 v = -v;
2202 output_addr_const (file, GEN_INT (v >> 2));
2203 return;
2204
2205 case 'd':
2206 gcc_assert (GET_CODE (x) == CONST_INT);
2207 v = INTVAL (x);
2208 fputs (v == 2 ? "h" : v == 4 ? "w" : "d", file);
2209 return;
2210
2211 case 'p':
2212 case 'P':
2213 gcc_assert (GET_CODE (x) == REG);
2214 v = REGNO (x);
2215 if (code == 'P')
2216 v++;
2217 fputs (reg_names[v], file);
2218 return;
2219
2220 case 'D':
2221 v = 0;
2222 if (GET_CODE (x) == CONST)
2223 {
2224 x = XEXP (x, 0);
2225 gcc_assert (GET_CODE (x) == PLUS);
2226 gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
2227 v = INTVAL (XEXP (x, 1));
2228 x = XEXP (x, 0);
2229
2230 }
2231 gcc_assert (GET_CODE (x) == SYMBOL_REF);
2232
2233 t = SYMBOL_REF_DECL (x);
2234 if (DECL_P (t))
2235 v |= DECL_ALIGN_UNIT (t);
2236 else
2237 v |= TYPE_ALIGN_UNIT (TREE_TYPE (t));
2238 if (v & 1)
2239 fputs ("b", file);
2240 else if (v & 2)
2241 fputs ("h", file);
2242 else
2243 fputs ("w", file);
2244 return;
2245
2246 case 'U':
2247 if (MEM_P (x))
2248 {
2249 x = XEXP (x, 0);
2250 if (GET_CODE (x) == PLUS
2251 || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
2252 x = XEXP (x, 0);
2253 if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
2254 {
2255 gcc_assert (sdata_symbolic_operand (x, Pmode));
2256 fputs ("2", file);
2257 return;
2258 }
2259 }
2260 gcc_assert (REG_P (x));
2261 if (A_REGNO_P (REGNO (x)))
2262 fputs ("1", file);
2263 if (B_REGNO_P (REGNO (x)))
2264 fputs ("2", file);
2265 return;
2266
2267 default:
2268 switch (GET_CODE (x))
2269 {
2270 case REG:
2271 if (GET_MODE_SIZE (mode) == 8)
2272 fprintf (file, "%s:%s", reg_names[REGNO (x) + 1],
2273 reg_names[REGNO (x)]);
2274 else
2275 fprintf (file, "%s", reg_names[REGNO (x)]);
2276 break;
2277
2278 case MEM:
2279 fputc ('*', file);
2280 gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
2281 c6x_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
2282 break;
2283
2284 case SYMBOL_REF:
2285 fputc ('(', file);
2286 output_addr_const (file, x);
2287 fputc (')', file);
2288 break;
2289
2290 case CONST_INT:
2291 output_addr_const (file, x);
2292 break;
2293
2294 case CONST_DOUBLE:
2295 output_operand_lossage ("invalid const_double operand");
2296 break;
2297
2298 default:
2299 output_addr_const (file, x);
2300 }
2301 }
2302}
2303\f
2304/* Return TRUE if OP is a valid memory address with a base register of
2305 class C. If SMALL_OFFSET is true, we disallow memory references which would
2306 require a long offset with B14/B15. */
2307
2308bool
2309c6x_mem_operand (rtx op, enum reg_class c, bool small_offset)
2310{
2311 enum machine_mode mode = GET_MODE (op);
2312 rtx base = XEXP (op, 0);
2313 switch (GET_CODE (base))
2314 {
2315 case REG:
2316 break;
2317 case PLUS:
2318 if (small_offset
2319 && (XEXP (base, 0) == stack_pointer_rtx
2320 || XEXP (base, 0) == pic_offset_table_rtx))
2321 {
2322 if (!c6x_legitimate_address_p_1 (mode, base, true, true))
2323 return false;
2324 }
2325
2326 /* fall through */
2327 case PRE_INC:
2328 case PRE_DEC:
2329 case PRE_MODIFY:
2330 case POST_INC:
2331 case POST_DEC:
2332 case POST_MODIFY:
2333 base = XEXP (base, 0);
2334 break;
2335
2336 case CONST:
2337 case LABEL_REF:
2338 case SYMBOL_REF:
2339 gcc_assert (sdata_symbolic_operand (base, Pmode));
2340 return !small_offset && c == B_REGS;
2341
2342 default:
2343 return false;
2344 }
2345 return TEST_HARD_REG_BIT (reg_class_contents[ (int) (c)], REGNO (base));
2346}
2347
2348/* Returns true if X is a valid address for use in a memory reference
2349 of mode MODE. If STRICT is true, we do not allow pseudo registers
2350 in the address. NO_LARGE_OFFSET is true if we are examining an
2351 address for use in a load or store misaligned instruction, or
2352 recursively examining an operand inside a PRE/POST_MODIFY. */
2353
2354bool
2355c6x_legitimate_address_p_1 (enum machine_mode mode, rtx x, bool strict,
2356 bool no_large_offset)
2357{
2358 int size, size1;
2359 HOST_WIDE_INT off;
2360 enum rtx_code code = GET_CODE (x);
2361
2362 switch (code)
2363 {
2364 case PRE_MODIFY:
2365 case POST_MODIFY:
2366 /* We can't split these into word-sized pieces yet. */
2367 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2368 return false;
2369 if (GET_CODE (XEXP (x, 1)) != PLUS)
2370 return false;
2371 if (!c6x_legitimate_address_p_1 (mode, XEXP (x, 1), strict, true))
2372 return false;
2373 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
2374 return false;
2375
2376 /* fall through */
2377 case PRE_INC:
2378 case PRE_DEC:
2379 case POST_INC:
2380 case POST_DEC:
2381 /* We can't split these into word-sized pieces yet. */
2382 if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2383 return false;
2384 x = XEXP (x, 0);
2385 if (!REG_P (x))
2386 return false;
2387
2388 /* fall through */
2389 case REG:
2390 if (strict)
2391 return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x));
2392 else
2393 return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x));
2394
2395 case PLUS:
2396 if (!REG_P (XEXP (x, 0))
2397 || !c6x_legitimate_address_p_1 (mode, XEXP (x, 0), strict, false))
2398 return false;
2399 /* We cannot ensure currently that both registers end up in the
2400 same register file. */
2401 if (REG_P (XEXP (x, 1)))
2402 return false;
2403
2404 if (mode == BLKmode)
2405 size = 4;
2406 else if (mode == VOIDmode)
2407 /* ??? This can happen during ivopts. */
2408 size = 1;
2409 else
2410 size = GET_MODE_SIZE (mode);
2411
2412 if (flag_pic
2413 && GET_CODE (XEXP (x, 1)) == UNSPEC
2414 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_SDATA
2415 && XEXP (x, 0) == pic_offset_table_rtx
2416 && sdata_symbolic_operand (XVECEXP (XEXP (x, 1), 0, 0), SImode))
2417 return !no_large_offset && size <= 4;
2418 if (flag_pic == 1
2419 && mode == Pmode
2420 && GET_CODE (XEXP (x, 1)) == UNSPEC
2421 && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_GOT
2422 && XEXP (x, 0) == pic_offset_table_rtx
2423 && (GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == SYMBOL_REF
2424 || GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == LABEL_REF))
2425 return !no_large_offset;
2426 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2427 return false;
2428
2429 off = INTVAL (XEXP (x, 1));
2430
2431 /* If the machine does not have doubleword load/stores, we'll use
2432 word size accesses. */
2433 size1 = size;
2434 if (size == 2 * UNITS_PER_WORD && !TARGET_STDW)
2435 size = UNITS_PER_WORD;
2436
2437 if (((HOST_WIDE_INT)size1 - 1) & off)
2438 return false;
2439 off /= size;
2440 if (off > -32 && off < (size1 == size ? 32 : 28))
2441 return true;
2442 if (no_large_offset || code != PLUS || XEXP (x, 0) != stack_pointer_rtx
2443 || size1 > UNITS_PER_WORD)
2444 return false;
2445 return off >= 0 && off < 32768;
2446
2447 case CONST:
2448 case SYMBOL_REF:
2449 case LABEL_REF:
2450 return (!no_large_offset
2451 /* With -fpic, we must wrap it in an unspec to show the B14
2452 dependency. */
2453 && !flag_pic
2454 && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
2455 && sdata_symbolic_operand (x, Pmode));
2456
2457 default:
2458 return false;
2459 }
2460}
2461
2462static bool
2463c6x_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
2464{
2465 return c6x_legitimate_address_p_1 (mode, x, strict, false);
2466}
2467
2468static bool
2469c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
2470 rtx x ATTRIBUTE_UNUSED)
2471{
2472 return true;
2473}
2474\f
2475/* Implements TARGET_PREFERRED_RENAME_CLASS. */
2476static reg_class_t
2477c6x_preferred_rename_class (reg_class_t cl)
2478{
2479 if (cl == A_REGS)
2480 return NONPREDICATE_A_REGS;
2481 if (cl == B_REGS)
2482 return NONPREDICATE_B_REGS;
2483 if (cl == ALL_REGS || cl == GENERAL_REGS)
2484 return NONPREDICATE_REGS;
2485 return NO_REGS;
2486}
2487\f
2488/* Implements FINAL_PRESCAN_INSN. */
2489void
2490c6x_final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
2491 int noperands ATTRIBUTE_UNUSED)
2492{
2493 c6x_current_insn = insn;
2494}
2495\f
2496/* A structure to describe the stack layout of a function. The layout is
2497 as follows:
2498
2499 [saved frame pointer (or possibly padding0)]
2500 --> incoming stack pointer, new hard frame pointer
2501 [saved call-used regs]
2502 [optional padding1]
2503 --> soft frame pointer
2504 [frame]
2505 [outgoing arguments]
2506 [optional padding2]
2507
2508 The structure members are laid out in this order. */
2509
2510struct c6x_frame
2511{
2512 int padding0;
2513 /* Number of registers to save. */
2514 int nregs;
2515 int padding1;
2516 HOST_WIDE_INT frame;
2517 int outgoing_arguments_size;
2518 int padding2;
2519
2520 HOST_WIDE_INT to_allocate;
2521 /* The offsets relative to the incoming stack pointer (which
2522 becomes HARD_FRAME_POINTER). */
2523 HOST_WIDE_INT frame_pointer_offset;
2524 HOST_WIDE_INT b3_offset;
2525
2526 /* True if we should call push_rts/pop_rts to save and restore
2527 registers. */
2528 bool push_rts;
2529};
2530
2531/* Return true if we need to save and modify the PIC register in the
2532 prologue. */
2533
2534static bool
2535must_reload_pic_reg_p (void)
2536{
2537 struct cgraph_local_info *i = NULL;
2538
2539 if (!TARGET_DSBT)
2540 return false;
2541
2542 i = cgraph_local_info (current_function_decl);
2543
416ff32e 2544 if ((crtl->uses_pic_offset_table || !crtl->is_leaf) && !i->local)
bcead286
BS
2545 return true;
2546 return false;
2547}
2548
2549/* Return 1 if we need to save REGNO. */
2550static int
2551c6x_save_reg (unsigned int regno)
2552{
2553 return ((df_regs_ever_live_p (regno)
2554 && !call_used_regs[regno]
2555 && !fixed_regs[regno])
2556 || (regno == RETURN_ADDR_REGNO
2557 && (df_regs_ever_live_p (regno)
416ff32e 2558 || !crtl->is_leaf))
bcead286
BS
2559 || (regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ()));
2560}
2561
2562/* Examine the number of regs NREGS we've determined we must save.
2563 Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
2564 prologue and epilogue. */
2565
2566static bool
2567use_push_rts_p (int nregs)
2568{
2569 if (TARGET_INSNS_64PLUS && optimize_function_for_size_p (cfun)
2570 && !cfun->machine->contains_sibcall
2571 && !cfun->returns_struct
2572 && !TARGET_LONG_CALLS
2573 && nregs >= 6 && !frame_pointer_needed)
2574 return true;
2575 return false;
2576}
2577
2578/* Return number of saved general prupose registers. */
2579
2580int
2581c6x_nsaved_regs (void)
2582{
2583 int nregs = 0;
2584 int regno;
2585
2586 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
2587 if (c6x_save_reg (regno))
2588 nregs++;
2589 return nregs;
2590}
2591
2592/* The safe debug order mandated by the ABI. */
2593static unsigned reg_save_order[] =
2594{
2595 REG_A10, REG_A11, REG_A12, REG_A13,
2596 REG_A14, REG_B3,
2597 REG_B10, REG_B11, REG_B12, REG_B13,
2598 REG_B14, REG_A15
2599};
2600
2601#define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
2602
2603/* Compute the layout of the stack frame and store it in FRAME. */
2604
2605static void
2606c6x_compute_frame_layout (struct c6x_frame *frame)
2607{
2608 HOST_WIDE_INT size = get_frame_size ();
2609 HOST_WIDE_INT offset;
2610 int nregs;
2611
2612 /* We use the four bytes which are technically inside the caller's frame,
2613 usually to save the frame pointer. */
2614 offset = -4;
2615 frame->padding0 = 0;
2616 nregs = c6x_nsaved_regs ();
2617 frame->push_rts = false;
2618 frame->b3_offset = 0;
2619 if (use_push_rts_p (nregs))
2620 {
2621 frame->push_rts = true;
2622 frame->b3_offset = (TARGET_BIG_ENDIAN ? -12 : -13) * 4;
2623 nregs = 14;
2624 }
2625 else if (c6x_save_reg (REG_B3))
2626 {
2627 int idx;
2628 for (idx = N_SAVE_ORDER - 1; reg_save_order[idx] != REG_B3; idx--)
2629 {
2630 if (c6x_save_reg (reg_save_order[idx]))
2631 frame->b3_offset -= 4;
2632 }
2633 }
2634 frame->nregs = nregs;
2635
2636 if (size == 0 && nregs == 0)
2637 {
2638 frame->padding0 = 4;
2639 frame->padding1 = frame->padding2 = 0;
2640 frame->frame_pointer_offset = frame->to_allocate = 0;
2641 frame->outgoing_arguments_size = 0;
2642 return;
2643 }
2644
2645 if (!frame->push_rts)
2646 offset += frame->nregs * 4;
2647
2648 if (offset == 0 && size == 0 && crtl->outgoing_args_size == 0
416ff32e 2649 && !crtl->is_leaf)
bcead286
BS
2650 /* Don't use the bottom of the caller's frame if we have no
2651 allocation of our own and call other functions. */
2652 frame->padding0 = frame->padding1 = 4;
2653 else if (offset & 4)
2654 frame->padding1 = 4;
2655 else
2656 frame->padding1 = 0;
2657
2658 offset += frame->padding0 + frame->padding1;
2659 frame->frame_pointer_offset = offset;
2660 offset += size;
2661
2662 frame->outgoing_arguments_size = crtl->outgoing_args_size;
2663 offset += frame->outgoing_arguments_size;
2664
2665 if ((offset & 4) == 0)
2666 frame->padding2 = 8;
2667 else
2668 frame->padding2 = 4;
2669 frame->to_allocate = offset + frame->padding2;
2670}
2671
2672/* Return the offset between two registers, one to be eliminated, and the other
2673 its replacement, at the start of a routine. */
2674
2675HOST_WIDE_INT
2676c6x_initial_elimination_offset (int from, int to)
2677{
2678 struct c6x_frame frame;
2679 c6x_compute_frame_layout (&frame);
2680
2681 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
2682 return 0;
2683 else if (from == FRAME_POINTER_REGNUM
2684 && to == HARD_FRAME_POINTER_REGNUM)
2685 return -frame.frame_pointer_offset;
2686 else
2687 {
2688 gcc_assert (to == STACK_POINTER_REGNUM);
2689
2690 if (from == ARG_POINTER_REGNUM)
2691 return frame.to_allocate + (frame.push_rts ? 56 : 0);
2692
2693 gcc_assert (from == FRAME_POINTER_REGNUM);
2694 return frame.to_allocate - frame.frame_pointer_offset;
2695 }
2696}
2697
2698/* Given FROM and TO register numbers, say whether this elimination is
2699 allowed. Frame pointer elimination is automatically handled. */
2700
2701static bool
2702c6x_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
2703{
2704 if (to == STACK_POINTER_REGNUM)
2705 return !frame_pointer_needed;
2706 return true;
2707}
2708
2709/* Emit insns to increment the stack pointer by OFFSET. If
2710 FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
2711 Does nothing if the offset is zero. */
2712
2713static void
2714emit_add_sp_const (HOST_WIDE_INT offset, bool frame_related_p)
2715{
2716 rtx to_add = GEN_INT (offset);
2717 rtx orig_to_add = to_add;
2718 rtx insn;
2719
2720 if (offset == 0)
2721 return;
2722
2723 if (offset < -32768 || offset > 32767)
2724 {
2725 rtx reg = gen_rtx_REG (SImode, REG_A0);
2726 rtx low = GEN_INT (trunc_int_for_mode (offset, HImode));
2727
2728 insn = emit_insn (gen_movsi_high (reg, low));
2729 if (frame_related_p)
2730 RTX_FRAME_RELATED_P (insn) = 1;
2731 insn = emit_insn (gen_movsi_lo_sum (reg, reg, to_add));
2732 if (frame_related_p)
2733 RTX_FRAME_RELATED_P (insn) = 1;
2734 to_add = reg;
2735 }
2736 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2737 to_add));
2738 if (frame_related_p)
2739 {
2740 if (REG_P (to_add))
2741 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2742 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
2743 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2744 orig_to_add)));
2745
2746 RTX_FRAME_RELATED_P (insn) = 1;
2747 }
2748}
2749
2750/* Prologue and epilogue. */
2751void
2752c6x_expand_prologue (void)
2753{
2754 struct c6x_frame frame;
2755 rtx insn, mem;
2756 int nsaved = 0;
2757 HOST_WIDE_INT initial_offset, off, added_already;
2758
2759 c6x_compute_frame_layout (&frame);
2760
2761 if (flag_stack_usage_info)
2762 current_function_static_stack_size = frame.to_allocate;
2763
2764 initial_offset = -frame.to_allocate;
2765 if (frame.push_rts)
2766 {
2767 emit_insn (gen_push_rts ());
2768 nsaved = frame.nregs;
2769 }
2770
2771 /* If the offsets would be too large for the memory references we will
2772 create to save registers, do the stack allocation in two parts.
2773 Ensure by subtracting 8 that we don't store to the word pointed to
2774 by the stack pointer. */
2775 if (initial_offset < -32768)
2776 initial_offset = -frame.frame_pointer_offset - 8;
2777
2778 if (frame.to_allocate > 0)
2779 gcc_assert (initial_offset != 0);
2780
2781 off = -initial_offset + 4 - frame.padding0;
2782
2783 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2784
2785 added_already = 0;
2786 if (frame_pointer_needed)
2787 {
2788 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2789 /* We go through some contortions here to both follow the ABI's
2790 recommendation that FP == incoming SP, and to avoid writing or
2791 reading the word pointed to by the stack pointer. */
2792 rtx addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
2793 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2794 GEN_INT (-8)));
2795 insn = emit_move_insn (gen_frame_mem (Pmode, addr), fp_reg);
2796 RTX_FRAME_RELATED_P (insn) = 1;
2797 nsaved++;
2798 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, stack_pointer_rtx,
2799 GEN_INT (8)));
2800 RTX_FRAME_RELATED_P (insn) = 1;
2801 off -= 4;
2802 added_already = -8;
2803 }
2804
2805 emit_add_sp_const (initial_offset - added_already, true);
2806
2807 if (nsaved < frame.nregs)
2808 {
2809 unsigned i;
2810
2811 for (i = 0; i < N_SAVE_ORDER; i++)
2812 {
2813 int idx = N_SAVE_ORDER - i - 1;
2814 unsigned regno = reg_save_order[idx];
2815 rtx reg;
2816 enum machine_mode save_mode = SImode;
2817
2818 if (regno == REG_A15 && frame_pointer_needed)
2819 /* Already saved. */
2820 continue;
2821 if (!c6x_save_reg (regno))
2822 continue;
2823
2824 if (TARGET_STDW && (off & 4) == 0 && off <= 256
2825 && (regno & 1) == 1
2826 && i + 1 < N_SAVE_ORDER
2827 && reg_save_order[idx - 1] == regno - 1
2828 && c6x_save_reg (regno - 1))
2829 {
2830 save_mode = DImode;
2831 regno--;
2832 i++;
2833 }
2834 reg = gen_rtx_REG (save_mode, regno);
2835 off -= GET_MODE_SIZE (save_mode);
2836
2837 insn = emit_move_insn (adjust_address (mem, save_mode, off),
2838 reg);
2839 RTX_FRAME_RELATED_P (insn) = 1;
2840
2841 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2842 }
2843 }
2844 gcc_assert (nsaved == frame.nregs);
2845 emit_add_sp_const (-frame.to_allocate - initial_offset, true);
2846 if (must_reload_pic_reg_p ())
2847 {
2848 if (dsbt_decl == NULL)
2849 {
2850 tree t;
2851
2852 t = build_index_type (integer_one_node);
2853 t = build_array_type (integer_type_node, t);
2854 t = build_decl (BUILTINS_LOCATION, VAR_DECL,
2855 get_identifier ("__c6xabi_DSBT_BASE"), t);
2856 DECL_ARTIFICIAL (t) = 1;
2857 DECL_IGNORED_P (t) = 1;
2858 DECL_EXTERNAL (t) = 1;
2859 TREE_STATIC (t) = 1;
2860 TREE_PUBLIC (t) = 1;
2861 TREE_USED (t) = 1;
2862
2863 dsbt_decl = t;
2864 }
2865 emit_insn (gen_setup_dsbt (pic_offset_table_rtx,
2866 XEXP (DECL_RTL (dsbt_decl), 0)));
2867 }
2868}
2869
2870void
2871c6x_expand_epilogue (bool sibcall)
2872{
2873 unsigned i;
2874 struct c6x_frame frame;
2875 rtx mem;
2876 HOST_WIDE_INT off;
2877 int nsaved = 0;
2878
2879 c6x_compute_frame_layout (&frame);
2880
2881 mem = gen_frame_mem (Pmode, stack_pointer_rtx);
2882
2883 /* Insert a dummy set/use of the stack pointer. This creates a
2884 scheduler barrier between the prologue saves and epilogue restores. */
2885 emit_insn (gen_epilogue_barrier (stack_pointer_rtx, stack_pointer_rtx));
2886
2887 /* If the offsets would be too large for the memory references we will
2888 create to restore registers, do a preliminary stack adjustment here. */
2889 off = frame.to_allocate - frame.frame_pointer_offset + frame.padding1;
2890 if (frame.push_rts)
2891 {
2892 nsaved = frame.nregs;
2893 }
2894 else
2895 {
2896 if (frame.to_allocate > 32768)
2897 {
2898 /* Don't add the entire offset so that we leave an unused word
2899 above the stack pointer. */
2900 emit_add_sp_const ((off - 16) & ~7, false);
2901 off &= 7;
2902 off += 16;
2903 }
2904 for (i = 0; i < N_SAVE_ORDER; i++)
2905 {
2906 unsigned regno = reg_save_order[i];
2907 rtx reg;
2908 enum machine_mode save_mode = SImode;
2909
2910 if (!c6x_save_reg (regno))
2911 continue;
2912 if (regno == REG_A15 && frame_pointer_needed)
2913 continue;
2914
2915 if (TARGET_STDW && (off & 4) == 0 && off < 256
2916 && (regno & 1) == 0
2917 && i + 1 < N_SAVE_ORDER
2918 && reg_save_order[i + 1] == regno + 1
2919 && c6x_save_reg (regno + 1))
2920 {
2921 save_mode = DImode;
2922 i++;
2923 }
2924 reg = gen_rtx_REG (save_mode, regno);
2925
2926 emit_move_insn (reg, adjust_address (mem, save_mode, off));
2927
2928 off += GET_MODE_SIZE (save_mode);
2929 nsaved += HARD_REGNO_NREGS (regno, save_mode);
2930 }
2931 }
2932 if (!frame_pointer_needed)
2933 emit_add_sp_const (off + frame.padding0 - 4, false);
2934 else
2935 {
2936 rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
2937 rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
2938 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2939 GEN_INT (8)));
2940 emit_insn (gen_addsi3 (stack_pointer_rtx, hard_frame_pointer_rtx,
2941 GEN_INT (-8)));
2942 emit_move_insn (fp_reg, gen_frame_mem (Pmode, addr));
2943 nsaved++;
2944 }
2945 gcc_assert (nsaved == frame.nregs);
2946 if (!sibcall)
2947 {
2948 if (frame.push_rts)
2949 emit_jump_insn (gen_pop_rts ());
2950 else
2951 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
2952 RETURN_ADDR_REGNO)));
2953 }
2954}
2955
2956/* Return the value of the return address for the frame COUNT steps up
2957 from the current frame, after the prologue.
2958 We punt for everything but the current frame by returning const0_rtx. */
2959
2960rtx
2961c6x_return_addr_rtx (int count)
2962{
2963 if (count != 0)
2964 return const0_rtx;
2965
2966 return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNO);
2967}
2968\f
2969/* Return true iff TYPE is one of the shadow types. */
2970static bool
2971shadow_type_p (enum attr_type type)
2972{
2973 return (type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW
2974 || type == TYPE_MULT_SHADOW);
2975}
2976
2977/* Return true iff INSN is a shadow pattern. */
2978static bool
2979shadow_p (rtx insn)
2980{
2981 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2982 return false;
2983 return shadow_type_p (get_attr_type (insn));
2984}
2985
2986/* Return true iff INSN is a shadow or blockage pattern. */
2987static bool
2988shadow_or_blockage_p (rtx insn)
2989{
2990 enum attr_type type;
2991 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
2992 return false;
2993 type = get_attr_type (insn);
2994 return shadow_type_p (type) || type == TYPE_BLOCKAGE;
2995}
2996\f
2997/* Translate UNITS into a bitmask of units we can reserve for this
2998 insn. */
2999static int
3000get_reservation_flags (enum attr_units units)
3001{
3002 switch (units)
3003 {
3004 case UNITS_D:
3005 case UNITS_D_ADDR:
3006 return RESERVATION_FLAG_D;
3007 case UNITS_L:
3008 return RESERVATION_FLAG_L;
3009 case UNITS_S:
3010 return RESERVATION_FLAG_S;
3011 case UNITS_M:
3012 return RESERVATION_FLAG_M;
3013 case UNITS_LS:
3014 return RESERVATION_FLAG_LS;
3015 case UNITS_DL:
3016 return RESERVATION_FLAG_DL;
3017 case UNITS_DS:
3018 return RESERVATION_FLAG_DS;
3019 case UNITS_DLS:
3020 return RESERVATION_FLAG_DLS;
3021 default:
3022 return 0;
3023 }
3024}
3025
3026/* Compute the side of the machine used by INSN, which reserves UNITS.
3027 This must match the reservations in the scheduling description. */
3028static int
3029get_insn_side (rtx insn, enum attr_units units)
3030{
3031 if (units == UNITS_D_ADDR)
3032 return (get_attr_addr_regfile (insn) == ADDR_REGFILE_A ? 0 : 1);
3033 else
3034 {
3035 enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
3036 if (rf == DEST_REGFILE_ANY)
3037 return get_attr_type (insn) == TYPE_BRANCH ? 0 : 1;
3038 else
3039 return rf == DEST_REGFILE_A ? 0 : 1;
3040 }
3041}
3042
3043/* After scheduling, walk the insns between HEAD and END and assign unit
3044 reservations. */
3045static void
3046assign_reservations (rtx head, rtx end)
3047{
3048 rtx insn;
3049 for (insn = head; insn != NEXT_INSN (end); insn = NEXT_INSN (insn))
3050 {
6bd9bf42
BS
3051 unsigned int sched_mask, reserved;
3052 rtx within, last;
bcead286
BS
3053 int pass;
3054 int rsrv[2];
3055 int rsrv_count[2][4];
6bd9bf42 3056 int i;
bcead286
BS
3057
3058 if (GET_MODE (insn) != TImode)
3059 continue;
3060
6bd9bf42
BS
3061 reserved = 0;
3062 last = NULL_RTX;
3063 /* Find the last insn in the packet. It has a state recorded for it,
3064 which we can use to determine the units we should be using. */
3065 for (within = insn;
3066 (within != NEXT_INSN (end)
3067 && (within == insn || GET_MODE (within) != TImode));
3068 within = NEXT_INSN (within))
3069 {
3070 int icode;
3071 if (!NONDEBUG_INSN_P (within))
3072 continue;
3073 icode = recog_memoized (within);
3074 if (icode < 0)
3075 continue;
3076 if (shadow_p (within))
3077 continue;
3078 if (INSN_INFO_ENTRY (INSN_UID (within)).reservation != 0)
3079 reserved |= 1 << INSN_INFO_ENTRY (INSN_UID (within)).reservation;
3080 last = within;
3081 }
3082 if (last == NULL_RTX)
3083 continue;
3084
3085 sched_mask = INSN_INFO_ENTRY (INSN_UID (last)).unit_mask;
3086 sched_mask &= ~reserved;
3087
bcead286 3088 memset (rsrv_count, 0, sizeof rsrv_count);
6bd9bf42
BS
3089 rsrv[0] = rsrv[1] = ~0;
3090 for (i = 0; i < 8; i++)
3091 {
3092 int side = i / 4;
3093 int unit = i & 3;
3094 unsigned unit_bit = 1 << (unit + side * UNIT_QID_SIDE_OFFSET);
3095 /* Clear the bits which we expect to reserve in the following loop,
3096 leaving the ones set which aren't present in the scheduler's
3097 state and shouldn't be reserved. */
3098 if (sched_mask & unit_bit)
3099 rsrv[i / 4] &= ~(1 << unit);
3100 }
bcead286
BS
3101
3102 /* Walk through the insns that occur in the same cycle. We use multiple
3103 passes to assign units, assigning for insns with the most specific
3104 requirements first. */
3105 for (pass = 0; pass < 4; pass++)
3106 for (within = insn;
3107 (within != NEXT_INSN (end)
3108 && (within == insn || GET_MODE (within) != TImode));
3109 within = NEXT_INSN (within))
3110 {
6bd9bf42 3111 int uid = INSN_UID (within);
bcead286
BS
3112 int this_rsrv, side;
3113 int icode;
3114 enum attr_units units;
6bd9bf42 3115 enum attr_type type;
bcead286
BS
3116 int j;
3117
3118 if (!NONDEBUG_INSN_P (within))
3119 continue;
3120 icode = recog_memoized (within);
3121 if (icode < 0)
3122 continue;
6bd9bf42
BS
3123 if (INSN_INFO_ENTRY (uid).reservation != 0)
3124 continue;
bcead286 3125 units = get_attr_units (within);
6bd9bf42 3126 type = get_attr_type (within);
bcead286
BS
3127 this_rsrv = get_reservation_flags (units);
3128 if (this_rsrv == 0)
3129 continue;
3130 side = get_insn_side (within, units);
3131
6bd9bf42
BS
3132 /* Certain floating point instructions are treated specially. If
3133 an insn can choose between units it can reserve, and its
3134 reservation spans more than one cycle, the reservation contains
3135 special markers in the first cycle to help us reconstruct what
3136 the automaton chose. */
3137 if ((type == TYPE_ADDDP || type == TYPE_FP4)
3138 && units == UNITS_LS)
3139 {
3140 int test1_code = ((type == TYPE_FP4 ? UNIT_QID_FPL1 : UNIT_QID_ADDDPL1)
3141 + side * UNIT_QID_SIDE_OFFSET);
3142 int test2_code = ((type == TYPE_FP4 ? UNIT_QID_FPS1 : UNIT_QID_ADDDPS1)
3143 + side * UNIT_QID_SIDE_OFFSET);
3144 if ((sched_mask & (1 << test1_code)) != 0)
3145 {
3146 this_rsrv = RESERVATION_FLAG_L;
3147 sched_mask &= ~(1 << test1_code);
3148 }
3149 else if ((sched_mask & (1 << test2_code)) != 0)
3150 {
3151 this_rsrv = RESERVATION_FLAG_S;
3152 sched_mask &= ~(1 << test2_code);
3153 }
3154 }
3155
bcead286
BS
3156 if ((this_rsrv & (this_rsrv - 1)) == 0)
3157 {
6bd9bf42 3158 int t = exact_log2 (this_rsrv) + side * UNIT_QID_SIDE_OFFSET;
bcead286 3159 rsrv[side] |= this_rsrv;
6bd9bf42 3160 INSN_INFO_ENTRY (uid).reservation = t;
bcead286
BS
3161 continue;
3162 }
3163
3164 if (pass == 1)
3165 {
3166 for (j = 0; j < 4; j++)
3167 if (this_rsrv & (1 << j))
3168 rsrv_count[side][j]++;
3169 continue;
3170 }
3171 if ((pass == 2 && this_rsrv != RESERVATION_FLAG_DLS)
3172 || (pass == 3 && this_rsrv == RESERVATION_FLAG_DLS))
3173 {
3174 int best = -1, best_cost = INT_MAX;
3175 for (j = 0; j < 4; j++)
3176 if ((this_rsrv & (1 << j))
3177 && !(rsrv[side] & (1 << j))
3178 && rsrv_count[side][j] < best_cost)
3179 {
3180 best_cost = rsrv_count[side][j];
3181 best = j;
3182 }
3183 gcc_assert (best != -1);
3184 rsrv[side] |= 1 << best;
3185 for (j = 0; j < 4; j++)
3186 if ((this_rsrv & (1 << j)) && j != best)
3187 rsrv_count[side][j]--;
3188
6bd9bf42
BS
3189 INSN_INFO_ENTRY (uid).reservation
3190 = best + side * UNIT_QID_SIDE_OFFSET;
bcead286
BS
3191 }
3192 }
3193 }
3194}
11e69edc
BS
3195
3196/* Return a factor by which to weight unit imbalances for a reservation
3197 R. */
3198static int
3199unit_req_factor (enum unitreqs r)
3200{
3201 switch (r)
3202 {
3203 case UNIT_REQ_D:
3204 case UNIT_REQ_L:
3205 case UNIT_REQ_S:
3206 case UNIT_REQ_M:
3207 case UNIT_REQ_X:
3208 case UNIT_REQ_T:
3209 return 1;
3210 case UNIT_REQ_DL:
3211 case UNIT_REQ_LS:
3212 case UNIT_REQ_DS:
3213 return 2;
3214 case UNIT_REQ_DLS:
3215 return 3;
3216 default:
3217 gcc_unreachable ();
3218 }
3219}
3220
3221/* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
3222 requirements. Returns zero if INSN can't be handled, otherwise
3223 either one or two to show how many of the two pairs are in use.
3224 REQ1 is always used, it holds what is normally thought of as the
3225 instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
3226 describe a cross path, or for loads/stores, the T unit. */
3227static int
3228get_unit_reqs (rtx insn, int *req1, int *side1, int *req2, int *side2)
3229{
3230 enum attr_units units;
3231 enum attr_cross cross;
3232 int side, req;
3233
3234 if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
3235 return 0;
3236 units = get_attr_units (insn);
3237 if (units == UNITS_UNKNOWN)
3238 return 0;
3239 side = get_insn_side (insn, units);
3240 cross = get_attr_cross (insn);
3241
3242 req = (units == UNITS_D ? UNIT_REQ_D
3243 : units == UNITS_D_ADDR ? UNIT_REQ_D
3244 : units == UNITS_DL ? UNIT_REQ_DL
3245 : units == UNITS_DS ? UNIT_REQ_DS
3246 : units == UNITS_L ? UNIT_REQ_L
3247 : units == UNITS_LS ? UNIT_REQ_LS
3248 : units == UNITS_S ? UNIT_REQ_S
3249 : units == UNITS_M ? UNIT_REQ_M
3250 : units == UNITS_DLS ? UNIT_REQ_DLS
3251 : -1);
3252 gcc_assert (req != -1);
3253 *req1 = req;
3254 *side1 = side;
3255 if (units == UNITS_D_ADDR)
3256 {
3257 *req2 = UNIT_REQ_T;
3258 *side2 = side ^ (cross == CROSS_Y ? 1 : 0);
3259 return 2;
3260 }
3261 else if (cross == CROSS_Y)
3262 {
3263 *req2 = UNIT_REQ_X;
3264 *side2 = side;
3265 return 2;
3266 }
3267 return 1;
3268}
3269
3270/* Walk the insns between and including HEAD and TAIL, and mark the
3271 resource requirements in the unit_reqs table. */
3272static void
3273count_unit_reqs (unit_req_table reqs, rtx head, rtx tail)
3274{
3275 rtx insn;
3276
3277 memset (reqs, 0, sizeof (unit_req_table));
3278
3279 for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
3280 {
3281 int side1, side2, req1, req2;
3282
3283 switch (get_unit_reqs (insn, &req1, &side1, &req2, &side2))
3284 {
3285 case 2:
3286 reqs[side2][req2]++;
3287 /* fall through */
3288 case 1:
3289 reqs[side1][req1]++;
3290 break;
3291 }
3292 }
3293}
3294
3295/* Update the table REQS by merging more specific unit reservations into
3296 more general ones, i.e. counting (for example) UNIT_REQ_D also in
3297 UNIT_REQ_DL, DS, and DLS. */
3298static void
3299merge_unit_reqs (unit_req_table reqs)
3300{
3301 int side;
3302 for (side = 0; side < 2; side++)
3303 {
3304 int d = reqs[side][UNIT_REQ_D];
3305 int l = reqs[side][UNIT_REQ_L];
3306 int s = reqs[side][UNIT_REQ_S];
3307 int dl = reqs[side][UNIT_REQ_DL];
3308 int ls = reqs[side][UNIT_REQ_LS];
3309 int ds = reqs[side][UNIT_REQ_DS];
3310
3311 reqs[side][UNIT_REQ_DL] += d;
3312 reqs[side][UNIT_REQ_DL] += l;
3313 reqs[side][UNIT_REQ_DS] += d;
3314 reqs[side][UNIT_REQ_DS] += s;
3315 reqs[side][UNIT_REQ_LS] += l;
3316 reqs[side][UNIT_REQ_LS] += s;
3317 reqs[side][UNIT_REQ_DLS] += ds + dl + ls + d + l + s;
3318 }
3319}
3320
8076c3e3
BS
3321/* Examine the table REQS and return a measure of unit imbalance by comparing
3322 the two sides of the machine. If, for example, D1 is used twice and D2
3323 used not at all, the return value should be 1 in the absence of other
3324 imbalances. */
3325static int
3326unit_req_imbalance (unit_req_table reqs)
3327{
3328 int val = 0;
3329 int i;
3330
3331 for (i = 0; i < UNIT_REQ_MAX; i++)
3332 {
ed80f859 3333 int factor = unit_req_factor ((enum unitreqs) i);
8076c3e3
BS
3334 int diff = abs (reqs[0][i] - reqs[1][i]);
3335 val += (diff + factor - 1) / factor / 2;
3336 }
3337 return val;
3338}
3339
11e69edc
BS
3340/* Return the resource-constrained minimum iteration interval given the
3341 data in the REQS table. This must have been processed with
3342 merge_unit_reqs already. */
3343static int
3344res_mii (unit_req_table reqs)
3345{
3346 int side, req;
3347 int worst = 1;
3348 for (side = 0; side < 2; side++)
3349 for (req = 0; req < UNIT_REQ_MAX; req++)
3350 {
ed80f859 3351 int factor = unit_req_factor ((enum unitreqs) req);
11e69edc
BS
3352 worst = MAX ((reqs[side][UNIT_REQ_D] + factor - 1) / factor, worst);
3353 }
3354
3355 return worst;
3356}
8076c3e3
BS
3357
3358/* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
3359 the operands that are involved in the (up to) two reservations, as
3360 found by get_unit_reqs. Return true if we did this successfully, false
3361 if we couldn't identify what to do with INSN. */
3362static bool
3363get_unit_operand_masks (rtx insn, unsigned int *pmask1, unsigned int *pmask2)
3364{
8076c3e3
BS
3365 enum attr_op_pattern op_pat;
3366
3367 if (recog_memoized (insn) < 0)
3368 return 0;
3369 if (GET_CODE (PATTERN (insn)) == COND_EXEC)
3370 return false;
3371 extract_insn (insn);
3372 op_pat = get_attr_op_pattern (insn);
3373 if (op_pat == OP_PATTERN_DT)
3374 {
3375 gcc_assert (recog_data.n_operands == 2);
3376 *pmask1 = 1 << 0;
3377 *pmask2 = 1 << 1;
3378 return true;
3379 }
3380 else if (op_pat == OP_PATTERN_TD)
3381 {
3382 gcc_assert (recog_data.n_operands == 2);
3383 *pmask1 = 1 << 1;
3384 *pmask2 = 1 << 0;
3385 return true;
3386 }
3387 else if (op_pat == OP_PATTERN_SXS)
3388 {
3389 gcc_assert (recog_data.n_operands == 3);
3390 *pmask1 = (1 << 0) | (1 << 2);
3391 *pmask2 = 1 << 1;
3392 return true;
3393 }
3394 else if (op_pat == OP_PATTERN_SX)
3395 {
3396 gcc_assert (recog_data.n_operands == 2);
3397 *pmask1 = 1 << 0;
3398 *pmask2 = 1 << 1;
3399 return true;
3400 }
3401 else if (op_pat == OP_PATTERN_SSX)
3402 {
3403 gcc_assert (recog_data.n_operands == 3);
3404 *pmask1 = (1 << 0) | (1 << 1);
3405 *pmask2 = 1 << 2;
3406 return true;
3407 }
3408 return false;
3409}
3410
3411/* Try to replace a register in INSN, which has corresponding rename info
3412 from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
3413 about the operands that must be renamed and the side they are on.
3414 REQS is the table of unit reservations in the loop between HEAD and TAIL.
3415 We recompute this information locally after our transformation, and keep
3416 it only if we managed to improve the balance. */
3417static void
3418try_rename_operands (rtx head, rtx tail, unit_req_table reqs, rtx insn,
3419 insn_rr_info *info, unsigned int op_mask, int orig_side)
3420{
3421 enum reg_class super_class = orig_side == 0 ? B_REGS : A_REGS;
3422 HARD_REG_SET unavailable;
8076c3e3
BS
3423 du_head_p this_head;
3424 struct du_chain *chain;
3425 int i;
3426 unsigned tmp_mask;
3427 int best_reg, old_reg;
6e1aa848 3428 vec<du_head_p> involved_chains = vNULL;
8076c3e3
BS
3429 unit_req_table new_reqs;
3430
3431 for (i = 0, tmp_mask = op_mask; tmp_mask; i++)
3432 {
3433 du_head_p op_chain;
3434 if ((tmp_mask & (1 << i)) == 0)
3435 continue;
3436 if (info->op_info[i].n_chains != 1)
3437 goto out_fail;
3438 op_chain = regrename_chain_from_id (info->op_info[i].heads[0]->id);
9771b263 3439 involved_chains.safe_push (op_chain);
8076c3e3
BS
3440 tmp_mask &= ~(1 << i);
3441 }
3442
9771b263 3443 if (involved_chains.length () > 1)
8076c3e3
BS
3444 goto out_fail;
3445
9771b263 3446 this_head = involved_chains[0];
8076c3e3
BS
3447 if (this_head->cannot_rename)
3448 goto out_fail;
3449
3450 for (chain = this_head->first; chain; chain = chain->next_use)
3451 {
3452 unsigned int mask1, mask2, mask_changed;
3453 int count, side1, side2, req1, req2;
9771b263 3454 insn_rr_info *this_rr = &insn_rr[INSN_UID (chain->insn)];
8076c3e3
BS
3455
3456 count = get_unit_reqs (chain->insn, &req1, &side1, &req2, &side2);
3457
3458 if (count == 0)
3459 goto out_fail;
3460
3461 if (!get_unit_operand_masks (chain->insn, &mask1, &mask2))
3462 goto out_fail;
3463
3464 extract_insn (chain->insn);
3465
3466 mask_changed = 0;
3467 for (i = 0; i < recog_data.n_operands; i++)
3468 {
3469 int j;
3470 int n_this_op = this_rr->op_info[i].n_chains;
3471 for (j = 0; j < n_this_op; j++)
3472 {
3473 du_head_p other = this_rr->op_info[i].heads[j];
3474 if (regrename_chain_from_id (other->id) == this_head)
3475 break;
3476 }
3477 if (j == n_this_op)
3478 continue;
3479
3480 if (n_this_op != 1)
3481 goto out_fail;
3482 mask_changed |= 1 << i;
3483 }
3484 gcc_assert (mask_changed != 0);
3485 if (mask_changed != mask1 && mask_changed != mask2)
3486 goto out_fail;
3487 }
3488
3489 /* If we get here, we can do the renaming. */
3490 COMPL_HARD_REG_SET (unavailable, reg_class_contents[(int) super_class]);
3491
3492 old_reg = this_head->regno;
3493 best_reg = find_best_rename_reg (this_head, super_class, &unavailable, old_reg);
3494
3495 regrename_do_replace (this_head, best_reg);
3496
3497 count_unit_reqs (new_reqs, head, PREV_INSN (tail));
3498 merge_unit_reqs (new_reqs);
3499 if (dump_file)
3500 {
3501 fprintf (dump_file, "reshuffle for insn %d, op_mask %x, "
3502 "original side %d, new reg %d\n",
3503 INSN_UID (insn), op_mask, orig_side, best_reg);
3504 fprintf (dump_file, " imbalance %d -> %d\n",
3505 unit_req_imbalance (reqs), unit_req_imbalance (new_reqs));
3506 }
3507 if (unit_req_imbalance (new_reqs) > unit_req_imbalance (reqs))
3508 regrename_do_replace (this_head, old_reg);
3509 else
3510 memcpy (reqs, new_reqs, sizeof (unit_req_table));
3511
3512 out_fail:
9771b263 3513 involved_chains.release ();
8076c3e3
BS
3514}
3515
3516/* Find insns in LOOP which would, if shifted to the other side
3517 of the machine, reduce an imbalance in the unit reservations. */
3518static void
3519reshuffle_units (basic_block loop)
3520{
3521 rtx head = BB_HEAD (loop);
3522 rtx tail = BB_END (loop);
3523 rtx insn;
8076c3e3
BS
3524 unit_req_table reqs;
3525 edge e;
3526 edge_iterator ei;
8076c3e3
BS
3527 bitmap_head bbs;
3528
3529 count_unit_reqs (reqs, head, PREV_INSN (tail));
3530 merge_unit_reqs (reqs);
3531
3532 regrename_init (true);
3533
3534 bitmap_initialize (&bbs, &bitmap_default_obstack);
3535
3536 FOR_EACH_EDGE (e, ei, loop->preds)
ed80f859
BS
3537 bitmap_set_bit (&bbs, e->src->index);
3538
8076c3e3
BS
3539 bitmap_set_bit (&bbs, loop->index);
3540 regrename_analyze (&bbs);
3541
3542 for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
3543 {
3544 enum attr_units units;
8076c3e3
BS
3545 int count, side1, side2, req1, req2;
3546 unsigned int mask1, mask2;
3547 insn_rr_info *info;
3548
3549 if (!NONDEBUG_INSN_P (insn))
3550 continue;
3551
3552 count = get_unit_reqs (insn, &req1, &side1, &req2, &side2);
3553
3554 if (count == 0)
3555 continue;
3556
3557 if (!get_unit_operand_masks (insn, &mask1, &mask2))
3558 continue;
3559
9771b263 3560 info = &insn_rr[INSN_UID (insn)];
8076c3e3
BS
3561 if (info->op_info == NULL)
3562 continue;
3563
3564 if (reqs[side1][req1] > 1
3565 && reqs[side1][req1] > 2 * reqs[side1 ^ 1][req1])
3566 {
3567 try_rename_operands (head, tail, reqs, insn, info, mask1, side1);
3568 }
3569
3570 units = get_attr_units (insn);
3571 if (units == UNITS_D_ADDR)
3572 {
3573 gcc_assert (count == 2);
3574 if (reqs[side2][req2] > 1
3575 && reqs[side2][req2] > 2 * reqs[side2 ^ 1][req2])
3576 {
3577 try_rename_operands (head, tail, reqs, insn, info, mask2, side2);
3578 }
3579 }
3580 }
3581 regrename_finish ();
3582}
bcead286
BS
3583\f
3584/* Backend scheduling state. */
3585typedef struct c6x_sched_context
3586{
3587 /* The current scheduler clock, saved in the sched_reorder hook. */
3588 int curr_sched_clock;
3589
3590 /* Number of insns issued so far in this cycle. */
3591 int issued_this_cycle;
3592
3593 /* We record the time at which each jump occurs in JUMP_CYCLES. The
3594 theoretical maximum for number of jumps in flight is 12: 2 every
3595 cycle, with a latency of 6 cycles each. This is a circular
3596 buffer; JUMP_CYCLE_INDEX is the pointer to the start. Earlier
3597 jumps have a higher index. This array should be accessed through
3598 the jump_cycle function. */
3599 int jump_cycles[12];
3600 int jump_cycle_index;
3601
3602 /* In parallel with jump_cycles, this array records the opposite of
3603 the condition used in each pending jump. This is used to
3604 predicate insns that are scheduled in the jump's delay slots. If
3605 this is NULL_RTX no such predication happens. */
3606 rtx jump_cond[12];
3607
3608 /* Similar to the jump_cycles mechanism, but here we take into
3609 account all insns with delay slots, to avoid scheduling asms into
3610 the delay slots. */
3611 int delays_finished_at;
3612
3613 /* The following variable value is the last issued insn. */
3614 rtx last_scheduled_insn;
11e69edc
BS
3615 /* The last issued insn that isn't a shadow of another. */
3616 rtx last_scheduled_iter0;
bcead286 3617
6bd9bf42
BS
3618 /* The following variable value is DFA state before issuing the
3619 first insn in the current clock cycle. We do not use this member
3620 of the structure directly; we copy the data in and out of
3621 prev_cycle_state. */
3622 state_t prev_cycle_state_ctx;
11e69edc 3623
bcead286
BS
3624 int reg_n_accesses[FIRST_PSEUDO_REGISTER];
3625 int reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3626 int reg_set_in_cycle[FIRST_PSEUDO_REGISTER];
3627
3628 int tmp_reg_n_accesses[FIRST_PSEUDO_REGISTER];
3629 int tmp_reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
3630} *c6x_sched_context_t;
3631
3632/* The current scheduling state. */
3633static struct c6x_sched_context ss;
3634
073a8998 3635/* The following variable value is DFA state before issuing the first insn
6bd9bf42
BS
3636 in the current clock cycle. This is used in c6x_variable_issue for
3637 comparison with the state after issuing the last insn in a cycle. */
3638static state_t prev_cycle_state;
3639
bcead286
BS
3640/* Set when we discover while processing an insn that it would lead to too
3641 many accesses of the same register. */
3642static bool reg_access_stall;
3643
11e69edc
BS
3644/* The highest insn uid after delayed insns were split, but before loop bodies
3645 were copied by the modulo scheduling code. */
3646static int sploop_max_uid_iter0;
3647
bcead286
BS
3648/* Look up the jump cycle with index N. For an out-of-bounds N, we return 0,
3649 so the caller does not specifically have to test for it. */
3650static int
3651get_jump_cycle (int n)
3652{
3653 if (n >= 12)
3654 return 0;
3655 n += ss.jump_cycle_index;
3656 if (n >= 12)
3657 n -= 12;
3658 return ss.jump_cycles[n];
3659}
3660
3661/* Look up the jump condition with index N. */
3662static rtx
3663get_jump_cond (int n)
3664{
3665 if (n >= 12)
3666 return NULL_RTX;
3667 n += ss.jump_cycle_index;
3668 if (n >= 12)
3669 n -= 12;
3670 return ss.jump_cond[n];
3671}
3672
3673/* Return the index of the first jump that occurs after CLOCK_VAR. If no jump
3674 has delay slots beyond CLOCK_VAR, return -1. */
3675static int
3676first_jump_index (int clock_var)
3677{
3678 int retval = -1;
3679 int n = 0;
3680 for (;;)
3681 {
3682 int t = get_jump_cycle (n);
3683 if (t <= clock_var)
3684 break;
3685 retval = n;
3686 n++;
3687 }
3688 return retval;
3689}
3690
3691/* Add a new entry in our scheduling state for a jump that occurs in CYCLE
3692 and has the opposite condition of COND. */
3693static void
3694record_jump (int cycle, rtx cond)
3695{
3696 if (ss.jump_cycle_index == 0)
3697 ss.jump_cycle_index = 11;
3698 else
3699 ss.jump_cycle_index--;
3700 ss.jump_cycles[ss.jump_cycle_index] = cycle;
3701 ss.jump_cond[ss.jump_cycle_index] = cond;
3702}
3703
3704/* Set the clock cycle of INSN to CYCLE. Also clears the insn's entry in
3705 new_conditions. */
3706static void
3707insn_set_clock (rtx insn, int cycle)
3708{
3709 unsigned uid = INSN_UID (insn);
3710
3711 if (uid >= INSN_INFO_LENGTH)
9771b263 3712 insn_info.safe_grow (uid * 5 / 4 + 10);
bcead286
BS
3713
3714 INSN_INFO_ENTRY (uid).clock = cycle;
3715 INSN_INFO_ENTRY (uid).new_cond = NULL;
6bd9bf42 3716 INSN_INFO_ENTRY (uid).reservation = 0;
bcead286
BS
3717 INSN_INFO_ENTRY (uid).ebb_start = false;
3718}
3719
3720/* Return the clock cycle we set for the insn with uid UID. */
3721static int
3722insn_uid_get_clock (int uid)
3723{
3724 return INSN_INFO_ENTRY (uid).clock;
3725}
3726
3727/* Return the clock cycle we set for INSN. */
3728static int
3729insn_get_clock (rtx insn)
3730{
3731 return insn_uid_get_clock (INSN_UID (insn));
3732}
3733
3734/* Examine INSN, and if it is a conditional jump of any kind, return
3735 the opposite of the condition in which it branches. Otherwise,
3736 return NULL_RTX. */
3737static rtx
3738condjump_opposite_condition (rtx insn)
3739{
3740 rtx pat = PATTERN (insn);
3741 int icode = INSN_CODE (insn);
3742 rtx x = NULL;
3743
3744 if (icode == CODE_FOR_br_true || icode == CODE_FOR_br_false)
3745 {
3746 x = XEXP (SET_SRC (pat), 0);
3747 if (icode == CODE_FOR_br_false)
3748 return x;
3749 }
3750 if (GET_CODE (pat) == COND_EXEC)
3751 {
3752 rtx t = COND_EXEC_CODE (pat);
3753 if ((GET_CODE (t) == PARALLEL
3754 && GET_CODE (XVECEXP (t, 0, 0)) == RETURN)
3755 || (GET_CODE (t) == UNSPEC && XINT (t, 1) == UNSPEC_REAL_JUMP)
3756 || (GET_CODE (t) == SET && SET_DEST (t) == pc_rtx))
3757 x = COND_EXEC_TEST (pat);
3758 }
3759
3760 if (x != NULL_RTX)
3761 {
3762 enum rtx_code code = GET_CODE (x);
3763 x = gen_rtx_fmt_ee (code == EQ ? NE : EQ,
3764 GET_MODE (x), XEXP (x, 0),
3765 XEXP (x, 1));
3766 }
3767 return x;
3768}
3769
3770/* Return true iff COND1 and COND2 are exactly opposite conditions
3771 one of them NE and the other EQ. */
3772static bool
3773conditions_opposite_p (rtx cond1, rtx cond2)
3774{
3775 return (rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
3776 && rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1))
3777 && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)));
3778}
3779
3780/* Return true if we can add a predicate COND to INSN, or if INSN
3781 already has that predicate. If DOIT is true, also perform the
3782 modification. */
3783static bool
3784predicate_insn (rtx insn, rtx cond, bool doit)
3785{
3786 int icode;
3787 if (cond == NULL_RTX)
3788 {
3789 gcc_assert (!doit);
3790 return false;
3791 }
3792
3793 if (get_attr_predicable (insn) == PREDICABLE_YES
3794 && GET_CODE (PATTERN (insn)) != COND_EXEC)
3795 {
3796 if (doit)
3797 {
3798 rtx newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3799 PATTERN (insn) = newpat;
3800 INSN_CODE (insn) = -1;
3801 }
3802 return true;
3803 }
3804 if (GET_CODE (PATTERN (insn)) == COND_EXEC
3805 && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn)), cond))
3806 return true;
3807 icode = INSN_CODE (insn);
3808 if (icode == CODE_FOR_real_jump
3809 || icode == CODE_FOR_jump
3810 || icode == CODE_FOR_indirect_jump)
3811 {
3812 rtx pat = PATTERN (insn);
3813 rtx dest = (icode == CODE_FOR_real_jump ? XVECEXP (pat, 0, 0)
3814 : icode == CODE_FOR_jump ? XEXP (SET_SRC (pat), 0)
3815 : SET_SRC (pat));
3816 if (doit)
3817 {
3818 rtx newpat;
3819 if (REG_P (dest))
3820 newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
3821 else
3822 newpat = gen_br_true (cond, XEXP (cond, 0), dest);
3823 PATTERN (insn) = newpat;
3824 INSN_CODE (insn) = -1;
3825 }
3826 return true;
3827 }
3828 if (INSN_CODE (insn) == CODE_FOR_br_true)
3829 {
3830 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3831 return rtx_equal_p (br_cond, cond);
3832 }
3833 if (INSN_CODE (insn) == CODE_FOR_br_false)
3834 {
3835 rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
3836 return conditions_opposite_p (br_cond, cond);
3837 }
3838 return false;
3839}
3840
3841/* Initialize SC. Used by c6x_init_sched_context and c6x_sched_init. */
3842static void
3843init_sched_state (c6x_sched_context_t sc)
3844{
3845 sc->last_scheduled_insn = NULL_RTX;
11e69edc 3846 sc->last_scheduled_iter0 = NULL_RTX;
bcead286
BS
3847 sc->issued_this_cycle = 0;
3848 memset (sc->jump_cycles, 0, sizeof sc->jump_cycles);
3849 memset (sc->jump_cond, 0, sizeof sc->jump_cond);
3850 sc->jump_cycle_index = 0;
3851 sc->delays_finished_at = 0;
3852 sc->curr_sched_clock = 0;
3853
6bd9bf42
BS
3854 sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3855
bcead286
BS
3856 memset (sc->reg_n_accesses, 0, sizeof sc->reg_n_accesses);
3857 memset (sc->reg_n_xaccesses, 0, sizeof sc->reg_n_xaccesses);
3858 memset (sc->reg_set_in_cycle, 0, sizeof sc->reg_set_in_cycle);
6bd9bf42
BS
3859
3860 state_reset (sc->prev_cycle_state_ctx);
bcead286
BS
3861}
3862
3863/* Allocate store for new scheduling context. */
3864static void *
3865c6x_alloc_sched_context (void)
3866{
3867 return xmalloc (sizeof (struct c6x_sched_context));
3868}
3869
3870/* If CLEAN_P is true then initializes _SC with clean data,
3871 and from the global context otherwise. */
3872static void
3873c6x_init_sched_context (void *_sc, bool clean_p)
3874{
3875 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3876
3877 if (clean_p)
3878 {
3879 init_sched_state (sc);
3880 }
3881 else
6bd9bf42
BS
3882 {
3883 *sc = ss;
3884 sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
3885 memcpy (sc->prev_cycle_state_ctx, prev_cycle_state, dfa_state_size);
3886 }
bcead286
BS
3887}
3888
3889/* Sets the global scheduling context to the one pointed to by _SC. */
3890static void
3891c6x_set_sched_context (void *_sc)
3892{
3893 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3894
3895 gcc_assert (sc != NULL);
3896 ss = *sc;
6bd9bf42
BS
3897 memcpy (prev_cycle_state, sc->prev_cycle_state_ctx, dfa_state_size);
3898}
3899
3900/* Clear data in _SC. */
3901static void
3902c6x_clear_sched_context (void *_sc)
3903{
3904 c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
3905 gcc_assert (_sc != NULL);
3906
11e69edc 3907 free (sc->prev_cycle_state_ctx);
bcead286
BS
3908}
3909
3910/* Free _SC. */
3911static void
3912c6x_free_sched_context (void *_sc)
3913{
3914 free (_sc);
3915}
3916
1a83e602
BS
3917/* True if we are currently performing a preliminary scheduling
3918 pass before modulo scheduling; we can't allow the scheduler to
3919 modify instruction patterns using packetization assumptions,
3920 since there will be another scheduling pass later if modulo
3921 scheduling fails. */
3922static bool in_hwloop;
3923
bcead286
BS
3924/* Provide information about speculation capabilities, and set the
3925 DO_BACKTRACKING flag. */
3926static void
3927c6x_set_sched_flags (spec_info_t spec_info)
3928{
3929 unsigned int *flags = &(current_sched_info->flags);
3930
3931 if (*flags & SCHED_EBB)
3932 {
e2724e63 3933 *flags |= DO_BACKTRACKING | DO_PREDICATION;
bcead286 3934 }
1a83e602
BS
3935 if (in_hwloop)
3936 *flags |= DONT_BREAK_DEPENDENCIES;
bcead286
BS
3937
3938 spec_info->mask = 0;
3939}
3940
3941/* Implement the TARGET_SCHED_ISSUE_RATE hook. */
3942
3943static int
3944c6x_issue_rate (void)
3945{
3946 return 8;
3947}
3948
6bd9bf42
BS
3949/* Used together with the collapse_ndfa option, this ensures that we reach a
3950 deterministic automaton state before trying to advance a cycle.
3951 With collapse_ndfa, genautomata creates advance cycle arcs only for
3952 such deterministic states. */
3953
3954static rtx
3955c6x_sched_dfa_pre_cycle_insn (void)
3956{
3957 return const0_rtx;
3958}
3959
bcead286
BS
3960/* We're beginning a new block. Initialize data structures as necessary. */
3961
3962static void
3963c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED,
3964 int sched_verbose ATTRIBUTE_UNUSED,
3965 int max_ready ATTRIBUTE_UNUSED)
3966{
6bd9bf42
BS
3967 if (prev_cycle_state == NULL)
3968 {
3969 prev_cycle_state = xmalloc (dfa_state_size);
3970 }
bcead286 3971 init_sched_state (&ss);
6bd9bf42
BS
3972 state_reset (prev_cycle_state);
3973}
3974
3975/* We are about to being issuing INSN. Return nonzero if we cannot
3976 issue it on given cycle CLOCK and return zero if we should not sort
3977 the ready queue on the next clock start.
3978 For C6X, we use this function just to copy the previous DFA state
3979 for comparison purposes. */
3980
3981static int
3982c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
3983 rtx insn ATTRIBUTE_UNUSED, int last_clock ATTRIBUTE_UNUSED,
3984 int clock ATTRIBUTE_UNUSED, int *sort_p ATTRIBUTE_UNUSED)
3985{
3986 if (clock != last_clock)
3987 memcpy (prev_cycle_state, curr_state, dfa_state_size);
3988 return 0;
bcead286
BS
3989}
3990
3991static void
3992c6x_mark_regno_read (int regno, bool cross)
3993{
3994 int t = ++ss.tmp_reg_n_accesses[regno];
3995
3996 if (t > 4)
3997 reg_access_stall = true;
3998
3999 if (cross)
4000 {
4001 int set_cycle = ss.reg_set_in_cycle[regno];
4002 /* This must be done in this way rather than by tweaking things in
4003 adjust_cost, since the stall occurs even for insns with opposite
4004 predicates, and the scheduler may not even see a dependency. */
4005 if (set_cycle > 0 && set_cycle == ss.curr_sched_clock)
4006 reg_access_stall = true;
4007 /* This doesn't quite do anything yet as we're only modeling one
4008 x unit. */
4009 ++ss.tmp_reg_n_xaccesses[regno];
4010 }
4011}
4012
4013/* Note that REG is read in the insn being examined. If CROSS, it
4014 means the access is through a cross path. Update the temporary reg
4015 access arrays, and set REG_ACCESS_STALL if the insn can't be issued
4016 in the current cycle. */
4017
4018static void
4019c6x_mark_reg_read (rtx reg, bool cross)
4020{
4021 unsigned regno = REGNO (reg);
4022 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
4023
4024 while (nregs-- > 0)
4025 c6x_mark_regno_read (regno + nregs, cross);
4026}
4027
4028/* Note that register REG is written in cycle CYCLES. */
4029
4030static void
4031c6x_mark_reg_written (rtx reg, int cycles)
4032{
4033 unsigned regno = REGNO (reg);
4034 unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
4035
4036 while (nregs-- > 0)
4037 ss.reg_set_in_cycle[regno + nregs] = cycles;
4038}
4039
4040/* Update the register state information for an instruction whose
4041 body is X. Return true if the instruction has to be delayed until the
4042 next cycle. */
4043
4044static bool
4045c6x_registers_update (rtx insn)
4046{
4047 enum attr_cross cross;
4048 enum attr_dest_regfile destrf;
4049 int i, nops;
4050 rtx x;
4051
4052 if (!reload_completed || recog_memoized (insn) < 0)
4053 return false;
4054
4055 reg_access_stall = false;
4056 memcpy (ss.tmp_reg_n_accesses, ss.reg_n_accesses,
4057 sizeof ss.tmp_reg_n_accesses);
4058 memcpy (ss.tmp_reg_n_xaccesses, ss.reg_n_xaccesses,
4059 sizeof ss.tmp_reg_n_xaccesses);
4060
4061 extract_insn (insn);
4062
4063 cross = get_attr_cross (insn);
4064 destrf = get_attr_dest_regfile (insn);
4065
4066 nops = recog_data.n_operands;
4067 x = PATTERN (insn);
4068 if (GET_CODE (x) == COND_EXEC)
4069 {
4070 c6x_mark_reg_read (XEXP (XEXP (x, 0), 0), false);
4071 nops -= 2;
4072 }
4073
4074 for (i = 0; i < nops; i++)
4075 {
4076 rtx op = recog_data.operand[i];
4077 if (recog_data.operand_type[i] == OP_OUT)
4078 continue;
4079 if (REG_P (op))
4080 {
4081 bool this_cross = cross;
4082 if (destrf == DEST_REGFILE_A && A_REGNO_P (REGNO (op)))
4083 this_cross = false;
4084 if (destrf == DEST_REGFILE_B && B_REGNO_P (REGNO (op)))
4085 this_cross = false;
4086 c6x_mark_reg_read (op, this_cross);
4087 }
4088 else if (MEM_P (op))
4089 {
4090 op = XEXP (op, 0);
4091 switch (GET_CODE (op))
4092 {
4093 case POST_INC:
4094 case PRE_INC:
4095 case POST_DEC:
4096 case PRE_DEC:
4097 op = XEXP (op, 0);
4098 /* fall through */
4099 case REG:
4100 c6x_mark_reg_read (op, false);
4101 break;
4102 case POST_MODIFY:
4103 case PRE_MODIFY:
4104 op = XEXP (op, 1);
4105 gcc_assert (GET_CODE (op) == PLUS);
4106 /* fall through */
4107 case PLUS:
4108 c6x_mark_reg_read (XEXP (op, 0), false);
4109 if (REG_P (XEXP (op, 1)))
4110 c6x_mark_reg_read (XEXP (op, 1), false);
4111 break;
4112 case SYMBOL_REF:
4113 case LABEL_REF:
4114 case CONST:
4115 c6x_mark_regno_read (REG_B14, false);
4116 break;
4117 default:
4118 gcc_unreachable ();
4119 }
4120 }
4121 else if (!CONSTANT_P (op) && strlen (recog_data.constraints[i]) > 0)
4122 gcc_unreachable ();
4123 }
4124 return reg_access_stall;
4125}
4126
4127/* Helper function for the TARGET_SCHED_REORDER and
4128 TARGET_SCHED_REORDER2 hooks. If scheduling an insn would be unsafe
4129 in the current cycle, move it down in the ready list and return the
4130 number of non-unsafe insns. */
4131
4132static int
4133c6x_sched_reorder_1 (rtx *ready, int *pn_ready, int clock_var)
4134{
4135 int n_ready = *pn_ready;
4136 rtx *e_ready = ready + n_ready;
4137 rtx *insnp;
4138 int first_jump;
4139
4140 /* Keep track of conflicts due to a limit number of register accesses,
4141 and due to stalls incurred by too early accesses of registers using
4142 cross paths. */
4143
4144 for (insnp = ready; insnp < e_ready; insnp++)
4145 {
4146 rtx insn = *insnp;
4147 int icode = recog_memoized (insn);
4148 bool is_asm = (icode < 0
4149 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
4150 || asm_noperands (PATTERN (insn)) >= 0));
11e69edc 4151 bool no_parallel = (is_asm || icode == CODE_FOR_sploop
bcead286
BS
4152 || (icode >= 0
4153 && get_attr_type (insn) == TYPE_ATOMIC));
4154
4155 /* We delay asm insns until all delay slots are exhausted. We can't
4156 accurately tell how many cycles an asm takes, and the main scheduling
4157 code always assumes at least 1 cycle, which may be wrong. */
4158 if ((no_parallel
4159 && (ss.issued_this_cycle > 0 || clock_var < ss.delays_finished_at))
11e69edc
BS
4160 || c6x_registers_update (insn)
4161 || (ss.issued_this_cycle > 0 && icode == CODE_FOR_sploop))
bcead286
BS
4162 {
4163 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4164 *ready = insn;
4165 n_ready--;
4166 ready++;
4167 }
4168 else if (shadow_p (insn))
4169 {
4170 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4171 *ready = insn;
4172 }
4173 }
4174
4175 /* Ensure that no other jump is scheduled in jump delay slots, since
4176 it would put the machine into the wrong state. Also, we must
4177 avoid scheduling insns that have a latency longer than the
4178 remaining jump delay slots, as the code at the jump destination
4179 won't be prepared for it.
4180
4181 However, we can relax this condition somewhat. The rest of the
4182 scheduler will automatically avoid scheduling an insn on which
4183 the jump shadow depends so late that its side effect happens
4184 after the jump. This means that if we see an insn with a longer
4185 latency here, it can safely be scheduled if we can ensure that it
4186 has a predicate opposite of the previous jump: the side effect
4187 will happen in what we think of as the same basic block. In
4188 c6x_variable_issue, we will record the necessary predicate in
4189 new_conditions, and after scheduling is finished, we will modify
4190 the insn.
4191
4192 Special care must be taken whenever there is more than one jump
4193 in flight. */
4194
4195 first_jump = first_jump_index (clock_var);
4196 if (first_jump != -1)
4197 {
4198 int first_cycle = get_jump_cycle (first_jump);
4199 rtx first_cond = get_jump_cond (first_jump);
4200 int second_cycle = 0;
4201
4202 if (first_jump > 0)
4203 second_cycle = get_jump_cycle (first_jump - 1);
4204
4205 for (insnp = ready; insnp < e_ready; insnp++)
4206 {
4207 rtx insn = *insnp;
4208 int icode = recog_memoized (insn);
4209 bool is_asm = (icode < 0
4210 && (GET_CODE (PATTERN (insn)) == ASM_INPUT
4211 || asm_noperands (PATTERN (insn)) >= 0));
9e7fe10e 4212 int this_cycles, rsrv_cycles;
bcead286
BS
4213 enum attr_type type;
4214
4215 gcc_assert (!is_asm);
4216 if (icode < 0)
4217 continue;
4218 this_cycles = get_attr_cycles (insn);
9e7fe10e 4219 rsrv_cycles = get_attr_reserve_cycles (insn);
bcead286
BS
4220 type = get_attr_type (insn);
4221 /* Treat branches specially; there is also a hazard if two jumps
4222 end at the same cycle. */
4223 if (type == TYPE_BRANCH || type == TYPE_CALL)
4224 this_cycles++;
4225 if (clock_var + this_cycles <= first_cycle)
4226 continue;
4227 if ((first_jump > 0 && clock_var + this_cycles > second_cycle)
9e7fe10e 4228 || clock_var + rsrv_cycles > first_cycle
bcead286
BS
4229 || !predicate_insn (insn, first_cond, false))
4230 {
4231 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4232 *ready = insn;
4233 n_ready--;
4234 ready++;
4235 }
4236 }
4237 }
4238
4239 return n_ready;
4240}
4241
4242/* Implement the TARGET_SCHED_REORDER hook. We save the current clock
4243 for later and clear the register access information for the new
4244 cycle. We also move asm statements out of the way if they would be
4245 scheduled in a delay slot. */
4246
4247static int
4248c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
4249 int sched_verbose ATTRIBUTE_UNUSED,
4250 rtx *ready ATTRIBUTE_UNUSED,
4251 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
4252{
4253 ss.curr_sched_clock = clock_var;
4254 ss.issued_this_cycle = 0;
4255 memset (ss.reg_n_accesses, 0, sizeof ss.reg_n_accesses);
4256 memset (ss.reg_n_xaccesses, 0, sizeof ss.reg_n_xaccesses);
4257
4258 if (ready == NULL)
4259 return 0;
4260
4261 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
4262}
4263
4264/* Implement the TARGET_SCHED_REORDER2 hook. We use this to record the clock
4265 cycle for every insn. */
4266
4267static int
4268c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
4269 int sched_verbose ATTRIBUTE_UNUSED,
4270 rtx *ready ATTRIBUTE_UNUSED,
4271 int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
4272{
4273 /* FIXME: the assembler rejects labels inside an execute packet.
4274 This can occur if prologue insns are scheduled in parallel with
4275 others, so we avoid this here. Also make sure that nothing is
4276 scheduled in parallel with a TYPE_ATOMIC insn or after a jump. */
4277 if (RTX_FRAME_RELATED_P (ss.last_scheduled_insn)
4278 || JUMP_P (ss.last_scheduled_insn)
4279 || (recog_memoized (ss.last_scheduled_insn) >= 0
4280 && get_attr_type (ss.last_scheduled_insn) == TYPE_ATOMIC))
4281 {
4282 int n_ready = *pn_ready;
4283 rtx *e_ready = ready + n_ready;
4284 rtx *insnp;
4285
4286 for (insnp = ready; insnp < e_ready; insnp++)
4287 {
4288 rtx insn = *insnp;
4289 if (!shadow_p (insn))
4290 {
4291 memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
4292 *ready = insn;
4293 n_ready--;
4294 ready++;
4295 }
4296 }
4297 return n_ready;
4298 }
4299
4300 return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
4301}
4302
4303/* Subroutine of maybe_clobber_cond, called through note_stores. */
4304
4305static void
4306clobber_cond_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data1)
4307{
4308 rtx *cond = (rtx *)data1;
4309 if (*cond != NULL_RTX && reg_overlap_mentioned_p (x, *cond))
4310 *cond = NULL_RTX;
4311}
4312
4313/* Examine INSN, and if it destroys the conditions have recorded for
4314 any of the jumps in flight, clear that condition so that we don't
4315 predicate any more insns. CLOCK_VAR helps us limit the search to
4316 only those jumps which are still in flight. */
4317
4318static void
4319maybe_clobber_cond (rtx insn, int clock_var)
4320{
4321 int n, idx;
4322 idx = ss.jump_cycle_index;
4323 for (n = 0; n < 12; n++, idx++)
4324 {
4325 rtx cond, link;
4326 int cycle;
4327
4328 if (idx >= 12)
4329 idx -= 12;
4330 cycle = ss.jump_cycles[idx];
4331 if (cycle <= clock_var)
4332 return;
4333
4334 cond = ss.jump_cond[idx];
4335 if (cond == NULL_RTX)
4336 continue;
4337
4338 if (CALL_P (insn))
4339 {
4340 ss.jump_cond[idx] = NULL_RTX;
4341 continue;
4342 }
4343
4344 note_stores (PATTERN (insn), clobber_cond_1, ss.jump_cond + idx);
4345 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
4346 if (REG_NOTE_KIND (link) == REG_INC)
4347 clobber_cond_1 (XEXP (link, 0), NULL_RTX, ss.jump_cond + idx);
4348 }
4349}
4350
4351/* Implement the TARGET_SCHED_VARIABLE_ISSUE hook. We are about to
4352 issue INSN. Return the number of insns left on the ready queue
4353 that can be issued this cycle.
4354 We use this hook to record clock cycles and reservations for every insn. */
4355
4356static int
4357c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
4358 int sched_verbose ATTRIBUTE_UNUSED,
4359 rtx insn, int can_issue_more ATTRIBUTE_UNUSED)
4360{
4361 ss.last_scheduled_insn = insn;
11e69edc
BS
4362 if (INSN_UID (insn) < sploop_max_uid_iter0 && !JUMP_P (insn))
4363 ss.last_scheduled_iter0 = insn;
bcead286
BS
4364 if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
4365 ss.issued_this_cycle++;
9771b263 4366 if (insn_info.exists ())
bcead286 4367 {
6bd9bf42 4368 state_t st_after = alloca (dfa_state_size);
bcead286
BS
4369 int curr_clock = ss.curr_sched_clock;
4370 int uid = INSN_UID (insn);
4371 int icode = recog_memoized (insn);
4372 rtx first_cond;
4373 int first, first_cycle;
6bd9bf42
BS
4374 unsigned int mask;
4375 int i;
bcead286
BS
4376
4377 insn_set_clock (insn, curr_clock);
4378 INSN_INFO_ENTRY (uid).ebb_start
4379 = curr_clock == 0 && ss.issued_this_cycle == 1;
4380
4381 first = first_jump_index (ss.curr_sched_clock);
4382 if (first == -1)
4383 {
4384 first_cycle = 0;
4385 first_cond = NULL_RTX;
4386 }
4387 else
4388 {
4389 first_cycle = get_jump_cycle (first);
4390 first_cond = get_jump_cond (first);
4391 }
4392 if (icode >= 0
4393 && first_cycle > curr_clock
4394 && first_cond != NULL_RTX
4395 && (curr_clock + get_attr_cycles (insn) > first_cycle
4396 || get_attr_type (insn) == TYPE_BRANCH
4397 || get_attr_type (insn) == TYPE_CALL))
4398 INSN_INFO_ENTRY (uid).new_cond = first_cond;
4399
6bd9bf42
BS
4400 memcpy (st_after, curr_state, dfa_state_size);
4401 state_transition (st_after, const0_rtx);
4402
4403 mask = 0;
4404 for (i = 0; i < 2 * UNIT_QID_SIDE_OFFSET; i++)
4405 if (cpu_unit_reservation_p (st_after, c6x_unit_codes[i])
4406 && !cpu_unit_reservation_p (prev_cycle_state, c6x_unit_codes[i]))
4407 mask |= 1 << i;
4408 INSN_INFO_ENTRY (uid).unit_mask = mask;
4409
bcead286
BS
4410 maybe_clobber_cond (insn, curr_clock);
4411
4412 if (icode >= 0)
4413 {
4414 int i, cycles;
4415
4416 c6x_registers_update (insn);
4417 memcpy (ss.reg_n_accesses, ss.tmp_reg_n_accesses,
4418 sizeof ss.reg_n_accesses);
4419 memcpy (ss.reg_n_xaccesses, ss.tmp_reg_n_accesses,
4420 sizeof ss.reg_n_xaccesses);
4421
4422 cycles = get_attr_cycles (insn);
4423 if (ss.delays_finished_at < ss.curr_sched_clock + cycles)
4424 ss.delays_finished_at = ss.curr_sched_clock + cycles;
4425 if (get_attr_type (insn) == TYPE_BRANCH
4426 || get_attr_type (insn) == TYPE_CALL)
4427 {
4428 rtx opposite = condjump_opposite_condition (insn);
4429 record_jump (ss.curr_sched_clock + cycles, opposite);
4430 }
4431
4432 /* Mark the cycles in which the destination registers are written.
4433 This is used for calculating stalls when using cross units. */
4434 extract_insn (insn);
4435 /* Cross-path stalls don't apply to results of load insns. */
4436 if (get_attr_type (insn) == TYPE_LOAD
4437 || get_attr_type (insn) == TYPE_LOADN
4438 || get_attr_type (insn) == TYPE_LOAD_SHADOW)
4439 cycles--;
4440 for (i = 0; i < recog_data.n_operands; i++)
4441 {
4442 rtx op = recog_data.operand[i];
4443 if (MEM_P (op))
4444 {
4445 rtx addr = XEXP (op, 0);
4446 if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
4447 c6x_mark_reg_written (XEXP (addr, 0),
4448 insn_uid_get_clock (uid) + 1);
4449 }
4450 if (recog_data.operand_type[i] != OP_IN
4451 && REG_P (op))
4452 {
4453 c6x_mark_reg_written (op,
4454 insn_uid_get_clock (uid) + cycles);
4455 }
4456 }
4457 }
4458 }
4459 return can_issue_more;
4460}
4461
4462/* Implement the TARGET_SCHED_ADJUST_COST hook. We need special handling for
4463 anti- and output dependencies. */
4464
4465static int
4466c6x_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4467{
4468 enum attr_type insn_type = TYPE_UNKNOWN, dep_insn_type = TYPE_UNKNOWN;
4469 int dep_insn_code_number, insn_code_number;
4470 int shadow_bonus = 0;
4471 enum reg_note kind;
4472 dep_insn_code_number = recog_memoized (dep_insn);
4473 insn_code_number = recog_memoized (insn);
4474
4475 if (dep_insn_code_number >= 0)
4476 dep_insn_type = get_attr_type (dep_insn);
4477
4478 if (insn_code_number >= 0)
4479 insn_type = get_attr_type (insn);
4480
4481 kind = REG_NOTE_KIND (link);
4482 if (kind == 0)
4483 {
4484 /* If we have a dependency on a load, and it's not for the result of
4485 the load, it must be for an autoincrement. Reduce the cost in that
4486 case. */
4487 if (dep_insn_type == TYPE_LOAD)
4488 {
4489 rtx set = PATTERN (dep_insn);
4490 if (GET_CODE (set) == COND_EXEC)
4491 set = COND_EXEC_CODE (set);
4492 if (GET_CODE (set) == UNSPEC)
4493 cost = 1;
4494 else
4495 {
4496 gcc_assert (GET_CODE (set) == SET);
4497 if (!reg_overlap_mentioned_p (SET_DEST (set), PATTERN (insn)))
4498 cost = 1;
4499 }
4500 }
4501 }
4502
4503 /* A jump shadow needs to have its latency decreased by one. Conceptually,
4504 it occurs in between two cycles, but we schedule it at the end of the
4505 first cycle. */
4506 if (shadow_type_p (insn_type))
4507 shadow_bonus = 1;
4508
4509 /* Anti and output dependencies usually have zero cost, but we want
4510 to insert a stall after a jump, and after certain floating point
4511 insns that take more than one cycle to read their inputs. In the
4512 future, we should try to find a better algorithm for scheduling
4513 jumps. */
4514 if (kind != 0)
4515 {
4516 /* We can get anti-dependencies against shadow insns. Treat these
4517 like output dependencies, so that the insn is entirely finished
4518 before the branch takes place. */
4519 if (kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW)
4520 kind = REG_DEP_OUTPUT;
4521 switch (dep_insn_type)
4522 {
4523 case TYPE_CALLP:
4524 return 1;
4525 case TYPE_BRANCH:
4526 case TYPE_CALL:
4527 if (get_attr_has_shadow (dep_insn) == HAS_SHADOW_Y)
4528 /* This is a real_jump/real_call insn. These don't have
4529 outputs, and ensuring the validity of scheduling things
4530 in the delay slot is the job of
4531 c6x_sched_reorder_1. */
4532 return 0;
4533 /* Unsplit calls can happen - e.g. for divide insns. */
4534 return 6;
4535 case TYPE_LOAD:
4536 case TYPE_LOADN:
4537 case TYPE_INTDP:
4538 if (kind == REG_DEP_OUTPUT)
4539 return 5 - shadow_bonus;
4540 return 0;
4541 case TYPE_MPY4:
4542 case TYPE_FP4:
4543 if (kind == REG_DEP_OUTPUT)
4544 return 4 - shadow_bonus;
4545 return 0;
4546 case TYPE_MPY2:
4547 if (kind == REG_DEP_OUTPUT)
4548 return 2 - shadow_bonus;
4549 return 0;
4550 case TYPE_CMPDP:
4551 if (kind == REG_DEP_OUTPUT)
4552 return 2 - shadow_bonus;
4553 return 2;
4554 case TYPE_ADDDP:
4555 case TYPE_MPYSPDP:
4556 if (kind == REG_DEP_OUTPUT)
4557 return 7 - shadow_bonus;
4558 return 2;
4559 case TYPE_MPYSP2DP:
4560 if (kind == REG_DEP_OUTPUT)
4561 return 5 - shadow_bonus;
4562 return 2;
4563 case TYPE_MPYI:
4564 if (kind == REG_DEP_OUTPUT)
4565 return 9 - shadow_bonus;
4566 return 4;
4567 case TYPE_MPYID:
4568 case TYPE_MPYDP:
4569 if (kind == REG_DEP_OUTPUT)
4570 return 10 - shadow_bonus;
4571 return 4;
4572
4573 default:
4574 if (insn_type == TYPE_SPKERNEL)
4575 return 0;
4576 if (kind == REG_DEP_OUTPUT)
4577 return 1 - shadow_bonus;
4578
4579 return 0;
4580 }
4581 }
4582
4583 return cost - shadow_bonus;
4584}
4585\f
4586/* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
4587 are N_FILLED. REAL_FIRST identifies the slot if the insn that appears
4588 first in the original stream. */
4589
4590static void
4591gen_one_bundle (rtx *slot, int n_filled, int real_first)
4592{
4593 rtx bundle;
4594 rtx t;
4595 int i;
4596
4597 bundle = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec_v (n_filled, slot));
4598 bundle = make_insn_raw (bundle);
4599 BLOCK_FOR_INSN (bundle) = BLOCK_FOR_INSN (slot[0]);
9d12bc68 4600 INSN_LOCATION (bundle) = INSN_LOCATION (slot[0]);
bcead286
BS
4601 PREV_INSN (bundle) = PREV_INSN (slot[real_first]);
4602
4603 t = NULL_RTX;
4604
4605 for (i = 0; i < n_filled; i++)
4606 {
4607 rtx insn = slot[i];
4608 remove_insn (insn);
4609 PREV_INSN (insn) = t ? t : PREV_INSN (bundle);
4610 if (t != NULL_RTX)
4611 NEXT_INSN (t) = insn;
4612 t = insn;
4613 if (i > 0)
9d12bc68 4614 INSN_LOCATION (slot[i]) = INSN_LOCATION (bundle);
bcead286
BS
4615 }
4616
4617 NEXT_INSN (bundle) = NEXT_INSN (PREV_INSN (bundle));
4618 NEXT_INSN (t) = NEXT_INSN (bundle);
4619 NEXT_INSN (PREV_INSN (bundle)) = bundle;
4620 PREV_INSN (NEXT_INSN (bundle)) = bundle;
4621}
4622
4623/* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
4624 try to insert labels in the middle. */
4625
4626static void
4627c6x_gen_bundles (void)
4628{
4629 basic_block bb;
4630 rtx insn, next, last_call;
4631
11cd3bed 4632 FOR_EACH_BB_FN (bb, cfun)
bcead286
BS
4633 {
4634 rtx insn, next;
4635 /* The machine is eight insns wide. We can have up to six shadow
4636 insns, plus an extra slot for merging the jump shadow. */
4637 rtx slot[15];
4638 int n_filled = 0;
4639 int first_slot = 0;
4640
4641 for (insn = BB_HEAD (bb);; insn = next)
4642 {
4643 int at_end;
4644 rtx delete_this = NULL_RTX;
4645
4646 if (NONDEBUG_INSN_P (insn))
4647 {
4648 /* Put calls at the start of the sequence. */
4649 if (CALL_P (insn))
4650 {
4651 first_slot++;
4652 if (n_filled)
4653 {
4654 memmove (&slot[1], &slot[0],
4655 n_filled * sizeof (slot[0]));
4656 }
4657 if (!shadow_p (insn))
4658 {
4659 PUT_MODE (insn, TImode);
4660 if (n_filled)
4661 PUT_MODE (slot[1], VOIDmode);
4662 }
4663 n_filled++;
4664 slot[0] = insn;
4665 }
4666 else
4667 {
4668 slot[n_filled++] = insn;
4669 }
4670 }
4671
4672 next = NEXT_INSN (insn);
4673 while (next && insn != BB_END (bb)
4674 && !(NONDEBUG_INSN_P (next)
4675 && GET_CODE (PATTERN (next)) != USE
4676 && GET_CODE (PATTERN (next)) != CLOBBER))
4677 {
4678 insn = next;
4679 next = NEXT_INSN (insn);
4680 }
4681
4682 at_end = insn == BB_END (bb);
4683 if (delete_this == NULL_RTX
4684 && (at_end || (GET_MODE (next) == TImode
4685 && !(shadow_p (next) && CALL_P (next)))))
4686 {
4687 if (n_filled >= 2)
4688 gen_one_bundle (slot, n_filled, first_slot);
4689
4690 n_filled = 0;
4691 first_slot = 0;
4692 }
4693 if (at_end)
4694 break;
4695 }
4696 }
4697 /* Bundling, and emitting nops, can separate
4698 NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls. Fix
4699 that up here. */
4700 last_call = NULL_RTX;
4701 for (insn = get_insns (); insn; insn = next)
4702 {
4703 next = NEXT_INSN (insn);
4704 if (CALL_P (insn)
4705 || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE
4706 && CALL_P (XVECEXP (PATTERN (insn), 0, 0))))
4707 last_call = insn;
4708 if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION)
4709 continue;
4710 if (NEXT_INSN (last_call) == insn)
4711 continue;
4712 NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
4713 PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
4714 PREV_INSN (insn) = last_call;
4715 NEXT_INSN (insn) = NEXT_INSN (last_call);
4716 PREV_INSN (NEXT_INSN (insn)) = insn;
4717 NEXT_INSN (PREV_INSN (insn)) = insn;
4718 last_call = insn;
4719 }
4720}
4721
4722/* Emit a NOP instruction for CYCLES cycles after insn AFTER. Return it. */
4723
4724static rtx
4725emit_nop_after (int cycles, rtx after)
4726{
4727 rtx insn;
4728
4729 /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
4730 operation. We don't need the extra NOP since in this case, the hardware
4731 will automatically insert the required stall. */
4732 if (cycles == 10)
4733 cycles--;
4734
4735 gcc_assert (cycles < 10);
4736
4737 insn = emit_insn_after (gen_nop_count (GEN_INT (cycles)), after);
4738 PUT_MODE (insn, TImode);
4739
4740 return insn;
4741}
4742
4743/* Determine whether INSN is a call that needs to have a return label
4744 placed. */
4745
4746static bool
4747returning_call_p (rtx insn)
4748{
4749 if (CALL_P (insn))
4750 return (!SIBLING_CALL_P (insn)
4751 && get_attr_type (insn) != TYPE_CALLP
4752 && get_attr_type (insn) != TYPE_SHADOW);
4753 if (recog_memoized (insn) < 0)
4754 return false;
4755 if (get_attr_type (insn) == TYPE_CALL)
4756 return true;
4757 return false;
4758}
4759
4760/* Determine whether INSN's pattern can be converted to use callp. */
4761static bool
4762can_use_callp (rtx insn)
4763{
4764 int icode = recog_memoized (insn);
4765 if (!TARGET_INSNS_64PLUS
4766 || icode < 0
4767 || GET_CODE (PATTERN (insn)) == COND_EXEC)
4768 return false;
4769
4770 return ((icode == CODE_FOR_real_call
4771 || icode == CODE_FOR_call_internal
4772 || icode == CODE_FOR_call_value_internal)
4773 && get_attr_dest_regfile (insn) == DEST_REGFILE_ANY);
4774}
4775
4776/* Convert the pattern of INSN, which must be a CALL_INSN, into a callp. */
4777static void
4778convert_to_callp (rtx insn)
4779{
4780 rtx lab;
4781 extract_insn (insn);
4782 if (GET_CODE (PATTERN (insn)) == SET)
4783 {
4784 rtx dest = recog_data.operand[0];
4785 lab = recog_data.operand[1];
4786 PATTERN (insn) = gen_callp_value (dest, lab);
4787 INSN_CODE (insn) = CODE_FOR_callp_value;
4788 }
4789 else
4790 {
4791 lab = recog_data.operand[0];
4792 PATTERN (insn) = gen_callp (lab);
4793 INSN_CODE (insn) = CODE_FOR_callp;
4794 }
4795}
4796
4797/* Scan forwards from INSN until we find the next insn that has mode TImode
4798 (indicating it starts a new cycle), and occurs in cycle CLOCK.
4799 Return it if we find such an insn, NULL_RTX otherwise. */
4800static rtx
4801find_next_cycle_insn (rtx insn, int clock)
4802{
4803 rtx t = insn;
4804 if (GET_MODE (t) == TImode)
4805 t = next_real_insn (t);
4806 while (t && GET_MODE (t) != TImode)
4807 t = next_real_insn (t);
4808
4809 if (t && insn_get_clock (t) == clock)
4810 return t;
4811 return NULL_RTX;
4812}
4813
4814/* If COND_INSN has a COND_EXEC condition, wrap the same condition
4815 around PAT. Return PAT either unchanged or modified in this
4816 way. */
4817static rtx
4818duplicate_cond (rtx pat, rtx cond_insn)
4819{
4820 rtx cond_pat = PATTERN (cond_insn);
4821 if (GET_CODE (cond_pat) == COND_EXEC)
4822 pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (cond_pat)),
4823 pat);
4824 return pat;
4825}
4826
4827/* Walk forward from INSN to find the last insn that issues in the same clock
4828 cycle. */
4829static rtx
4830find_last_same_clock (rtx insn)
4831{
4832 rtx retval = insn;
4833 rtx t = next_real_insn (insn);
4834
4835 while (t && GET_MODE (t) != TImode)
4836 {
4837 if (!DEBUG_INSN_P (t) && recog_memoized (t) >= 0)
4838 retval = t;
4839 t = next_real_insn (t);
4840 }
4841 return retval;
4842}
4843
4844/* For every call insn in the function, emit code to load the return
4845 address. For each call we create a return label and store it in
4846 CALL_LABELS. If are not scheduling, we emit the labels here,
4847 otherwise the caller will do it later.
4848 This function is called after final insn scheduling, but before creating
4849 the SEQUENCEs that represent execute packets. */
4850
4851static void
4852reorg_split_calls (rtx *call_labels)
4853{
4854 unsigned int reservation_mask = 0;
4855 rtx insn = get_insns ();
b64925dc 4856 gcc_assert (NOTE_P (insn));
bcead286
BS
4857 insn = next_real_insn (insn);
4858 while (insn)
4859 {
4860 int uid;
4861 rtx next = next_real_insn (insn);
4862
4863 if (DEBUG_INSN_P (insn))
4864 goto done;
4865
4866 if (GET_MODE (insn) == TImode)
4867 reservation_mask = 0;
4868 uid = INSN_UID (insn);
4869 if (c6x_flag_schedule_insns2 && recog_memoized (insn) >= 0)
4870 reservation_mask |= 1 << INSN_INFO_ENTRY (uid).reservation;
4871
4872 if (returning_call_p (insn))
4873 {
4874 rtx label = gen_label_rtx ();
4875 rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
4876 rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
4877
4878 LABEL_NUSES (label) = 2;
4879 if (!c6x_flag_schedule_insns2)
4880 {
4881 if (can_use_callp (insn))
4882 convert_to_callp (insn);
4883 else
4884 {
4885 rtx t;
4886 rtx slot[4];
4887 emit_label_after (label, insn);
4888
4889 /* Bundle the call and its delay slots into a single
4890 SEQUENCE. While these do not issue in parallel
4891 we need to group them into a single EH region. */
4892 slot[0] = insn;
4893 PUT_MODE (insn, TImode);
4894 if (TARGET_INSNS_64)
4895 {
4896 t = gen_addkpc (reg, labelref, GEN_INT (4));
4897 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4898 insn);
4899 PUT_MODE (slot[1], TImode);
4900 gen_one_bundle (slot, 2, 0);
4901 }
4902 else
4903 {
4904 slot[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
4905 insn);
4906 PUT_MODE (slot[3], TImode);
4907 t = gen_movsi_lo_sum (reg, reg, labelref);
4908 slot[2] = emit_insn_after (duplicate_cond (t, insn),
4909 insn);
4910 PUT_MODE (slot[2], TImode);
4911 t = gen_movsi_high (reg, labelref);
4912 slot[1] = emit_insn_after (duplicate_cond (t, insn),
4913 insn);
4914 PUT_MODE (slot[1], TImode);
4915 gen_one_bundle (slot, 4, 0);
4916 }
4917 }
4918 }
4919 else
4920 {
4921 /* If we scheduled, we reserved the .S2 unit for one or two
4922 cycles after the call. Emit the insns in these slots,
4923 unless it's possible to create a CALLP insn.
4924 Note that this works because the dependencies ensure that
4925 no insn setting/using B3 is scheduled in the delay slots of
4926 a call. */
4927 int this_clock = insn_get_clock (insn);
4928 rtx last_same_clock;
4929 rtx after1;
4930
4931 call_labels[INSN_UID (insn)] = label;
4932
4933 last_same_clock = find_last_same_clock (insn);
4934
4935 if (can_use_callp (insn))
4936 {
4937 /* Find the first insn of the next execute packet. If it
6bd9bf42 4938 is the shadow insn corresponding to this call, we may
bcead286 4939 use a CALLP insn. */
6bd9bf42 4940 rtx shadow = next_nonnote_nondebug_insn (last_same_clock);
bcead286 4941
6bd9bf42
BS
4942 if (CALL_P (shadow)
4943 && insn_get_clock (shadow) == this_clock + 5)
bcead286 4944 {
6bd9bf42
BS
4945 convert_to_callp (shadow);
4946 insn_set_clock (shadow, this_clock);
4947 INSN_INFO_ENTRY (INSN_UID (shadow)).reservation
4948 = RESERVATION_S2;
4949 INSN_INFO_ENTRY (INSN_UID (shadow)).unit_mask
4950 = INSN_INFO_ENTRY (INSN_UID (last_same_clock)).unit_mask;
bcead286
BS
4951 if (GET_MODE (insn) == TImode)
4952 {
4953 rtx new_cycle_first = NEXT_INSN (insn);
4954 while (!NONDEBUG_INSN_P (new_cycle_first)
4955 || GET_CODE (PATTERN (new_cycle_first)) == USE
4956 || GET_CODE (PATTERN (new_cycle_first)) == CLOBBER)
4957 new_cycle_first = NEXT_INSN (new_cycle_first);
4958 PUT_MODE (new_cycle_first, TImode);
6bd9bf42
BS
4959 if (new_cycle_first != shadow)
4960 PUT_MODE (shadow, VOIDmode);
bcead286
BS
4961 INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
4962 = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
4963 }
4964 else
6bd9bf42 4965 PUT_MODE (shadow, VOIDmode);
bcead286
BS
4966 delete_insn (insn);
4967 goto done;
4968 }
4969 }
4970 after1 = find_next_cycle_insn (last_same_clock, this_clock + 1);
4971 if (after1 == NULL_RTX)
4972 after1 = last_same_clock;
4973 else
4974 after1 = find_last_same_clock (after1);
4975 if (TARGET_INSNS_64)
4976 {
4977 rtx x1 = gen_addkpc (reg, labelref, const0_rtx);
4978 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4979 insn_set_clock (x1, this_clock + 1);
4980 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
4981 if (after1 == last_same_clock)
4982 PUT_MODE (x1, TImode);
6bd9bf42
BS
4983 else
4984 INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
4985 = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
bcead286
BS
4986 }
4987 else
4988 {
4989 rtx x1, x2;
4990 rtx after2 = find_next_cycle_insn (after1, this_clock + 2);
4991 if (after2 == NULL_RTX)
4992 after2 = after1;
4993 x2 = gen_movsi_lo_sum (reg, reg, labelref);
4994 x2 = emit_insn_after (duplicate_cond (x2, insn), after2);
4995 x1 = gen_movsi_high (reg, labelref);
4996 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
4997 insn_set_clock (x1, this_clock + 1);
4998 insn_set_clock (x2, this_clock + 2);
4999 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
5000 INSN_INFO_ENTRY (INSN_UID (x2)).reservation = RESERVATION_S2;
5001 if (after1 == last_same_clock)
5002 PUT_MODE (x1, TImode);
6bd9bf42
BS
5003 else
5004 INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
5005 = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
bcead286
BS
5006 if (after1 == after2)
5007 PUT_MODE (x2, TImode);
6bd9bf42
BS
5008 else
5009 INSN_INFO_ENTRY (INSN_UID (x2)).unit_mask
5010 = INSN_INFO_ENTRY (INSN_UID (after2)).unit_mask;
bcead286
BS
5011 }
5012 }
5013 }
5014 done:
5015 insn = next;
5016 }
5017}
5018
5019/* Called as part of c6x_reorg. This function emits multi-cycle NOP
5020 insns as required for correctness. CALL_LABELS is the array that
5021 holds the return labels for call insns; we emit these here if
5022 scheduling was run earlier. */
5023
5024static void
5025reorg_emit_nops (rtx *call_labels)
5026{
5027 bool first;
5028 rtx prev, last_call;
5029 int prev_clock, earliest_bb_end;
5030 int prev_implicit_nops;
5031 rtx insn = get_insns ();
5032
5033 /* We look at one insn (or bundle inside a sequence) in each iteration, storing
5034 its issue time in PREV_CLOCK for the next iteration. If there is a gap in
5035 clocks, we must insert a NOP.
5036 EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
5037 current basic block will finish. We must not allow the next basic block to
5038 begin before this cycle.
5039 PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
5040 a multi-cycle nop. The code is scheduled such that subsequent insns will
5041 show the cycle gap, but we needn't insert a real NOP instruction. */
5042 insn = next_real_insn (insn);
5043 last_call = prev = NULL_RTX;
5044 prev_clock = -1;
5045 earliest_bb_end = 0;
5046 prev_implicit_nops = 0;
5047 first = true;
5048 while (insn)
5049 {
5050 int this_clock = -1;
5051 rtx next;
5052 int max_cycles = 0;
5053
5054 next = next_real_insn (insn);
5055
5056 if (DEBUG_INSN_P (insn)
5057 || GET_CODE (PATTERN (insn)) == USE
5058 || GET_CODE (PATTERN (insn)) == CLOBBER
5059 || shadow_or_blockage_p (insn)
34f0d87a 5060 || JUMP_TABLE_DATA_P (insn))
bcead286
BS
5061 goto next_insn;
5062
5063 if (!c6x_flag_schedule_insns2)
5064 /* No scheduling; ensure that no parallel issue happens. */
5065 PUT_MODE (insn, TImode);
5066 else
5067 {
5068 int cycles;
5069
5070 this_clock = insn_get_clock (insn);
5071 if (this_clock != prev_clock)
5072 {
5073 PUT_MODE (insn, TImode);
5074
5075 if (!first)
5076 {
5077 cycles = this_clock - prev_clock;
5078
5079 cycles -= prev_implicit_nops;
5080 if (cycles > 1)
5081 {
5082 rtx nop = emit_nop_after (cycles - 1, prev);
5083 insn_set_clock (nop, prev_clock + prev_implicit_nops + 1);
5084 }
5085 }
5086 prev_clock = this_clock;
5087
5088 if (last_call
5089 && insn_get_clock (last_call) + 6 <= this_clock)
5090 {
5091 emit_label_before (call_labels[INSN_UID (last_call)], insn);
5092 last_call = NULL_RTX;
5093 }
5094 prev_implicit_nops = 0;
5095 }
5096 }
5097
5098 /* Examine how many cycles the current insn takes, and adjust
5099 LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS. */
5100 if (recog_memoized (insn) >= 0
5101 /* If not scheduling, we've emitted NOPs after calls already. */
5102 && (c6x_flag_schedule_insns2 || !returning_call_p (insn)))
5103 {
5104 max_cycles = get_attr_cycles (insn);
5105 if (get_attr_type (insn) == TYPE_CALLP)
5106 prev_implicit_nops = 5;
5107 }
5108 else
5109 max_cycles = 1;
5110 if (returning_call_p (insn))
5111 last_call = insn;
5112
5113 if (c6x_flag_schedule_insns2)
5114 {
5115 gcc_assert (this_clock >= 0);
5116 if (earliest_bb_end < this_clock + max_cycles)
5117 earliest_bb_end = this_clock + max_cycles;
5118 }
5119 else if (max_cycles > 1)
5120 emit_nop_after (max_cycles - 1, insn);
5121
5122 prev = insn;
5123 first = false;
5124
5125 next_insn:
5126 if (c6x_flag_schedule_insns2
5127 && (next == NULL_RTX
5128 || (GET_MODE (next) == TImode
5129 && INSN_INFO_ENTRY (INSN_UID (next)).ebb_start))
5130 && earliest_bb_end > 0)
5131 {
5132 int cycles = earliest_bb_end - prev_clock;
5133 if (cycles > 1)
5134 {
5135 prev = emit_nop_after (cycles - 1, prev);
5136 insn_set_clock (prev, prev_clock + prev_implicit_nops + 1);
5137 }
5138 earliest_bb_end = 0;
5139 prev_clock = -1;
5140 first = true;
5141
5142 if (last_call)
5143 emit_label_after (call_labels[INSN_UID (last_call)], prev);
5144 last_call = NULL_RTX;
5145 }
5146 insn = next;
5147 }
5148}
5149
5150/* If possible, split INSN, which we know is either a jump or a call, into a real
5151 insn and its shadow. */
5152static void
5153split_delayed_branch (rtx insn)
5154{
5155 int code = recog_memoized (insn);
5156 rtx i1, newpat;
5157 rtx pat = PATTERN (insn);
5158
5159 if (GET_CODE (pat) == COND_EXEC)
5160 pat = COND_EXEC_CODE (pat);
5161
5162 if (CALL_P (insn))
5163 {
5164 rtx src = pat, dest = NULL_RTX;
5165 rtx callee;
5166 if (GET_CODE (pat) == SET)
5167 {
5168 dest = SET_DEST (pat);
5169 src = SET_SRC (pat);
5170 }
5171 callee = XEXP (XEXP (src, 0), 0);
5172 if (SIBLING_CALL_P (insn))
5173 {
5174 if (REG_P (callee))
5175 newpat = gen_indirect_sibcall_shadow ();
5176 else
5177 newpat = gen_sibcall_shadow (callee);
5178 pat = gen_real_jump (callee);
5179 }
5180 else if (dest != NULL_RTX)
5181 {
5182 if (REG_P (callee))
5183 newpat = gen_indirect_call_value_shadow (dest);
5184 else
5185 newpat = gen_call_value_shadow (dest, callee);
5186 pat = gen_real_call (callee);
5187 }
5188 else
5189 {
5190 if (REG_P (callee))
5191 newpat = gen_indirect_call_shadow ();
5192 else
5193 newpat = gen_call_shadow (callee);
5194 pat = gen_real_call (callee);
5195 }
5196 pat = duplicate_cond (pat, insn);
5197 newpat = duplicate_cond (newpat, insn);
5198 }
5199 else
5200 {
5201 rtx src, op;
5202 if (GET_CODE (pat) == PARALLEL
5203 && GET_CODE (XVECEXP (pat, 0, 0)) == RETURN)
5204 {
5205 newpat = gen_return_shadow ();
5206 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
5207 newpat = duplicate_cond (newpat, insn);
5208 }
5209 else
5210 switch (code)
5211 {
5212 case CODE_FOR_br_true:
5213 case CODE_FOR_br_false:
5214 src = SET_SRC (pat);
5215 op = XEXP (src, code == CODE_FOR_br_true ? 1 : 2);
5216 newpat = gen_condjump_shadow (op);
5217 pat = gen_real_jump (op);
5218 if (code == CODE_FOR_br_true)
5219 pat = gen_rtx_COND_EXEC (VOIDmode, XEXP (src, 0), pat);
5220 else
5221 pat = gen_rtx_COND_EXEC (VOIDmode,
5222 reversed_comparison (XEXP (src, 0),
5223 VOIDmode),
5224 pat);
5225 break;
5226
5227 case CODE_FOR_jump:
5228 op = SET_SRC (pat);
5229 newpat = gen_jump_shadow (op);
5230 break;
5231
5232 case CODE_FOR_indirect_jump:
5233 newpat = gen_indirect_jump_shadow ();
5234 break;
5235
5236 case CODE_FOR_return_internal:
5237 newpat = gen_return_shadow ();
5238 pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
5239 break;
5240
5241 default:
5242 return;
5243 }
5244 }
5245 i1 = emit_insn_before (pat, insn);
5246 PATTERN (insn) = newpat;
5247 INSN_CODE (insn) = -1;
06d7e8e7 5248 record_delay_slot_pair (i1, insn, 5, 0);
bcead286
BS
5249}
5250
11e69edc
BS
5251/* If INSN is a multi-cycle insn that should be handled properly in
5252 modulo-scheduling, split it into a real insn and a shadow.
5253 Return true if we made a change.
5254
5255 It is valid for us to fail to split an insn; the caller has to deal
5256 with the possibility. Currently we handle loads and most mpy2 and
5257 mpy4 insns. */
5258static bool
5259split_delayed_nonbranch (rtx insn)
5260{
5261 int code = recog_memoized (insn);
5262 enum attr_type type;
5263 rtx i1, newpat, src, dest;
5264 rtx pat = PATTERN (insn);
5265 rtvec rtv;
5266 int delay;
5267
5268 if (GET_CODE (pat) == COND_EXEC)
5269 pat = COND_EXEC_CODE (pat);
5270
5271 if (code < 0 || GET_CODE (pat) != SET)
5272 return false;
5273 src = SET_SRC (pat);
5274 dest = SET_DEST (pat);
5275 if (!REG_P (dest))
5276 return false;
5277
5278 type = get_attr_type (insn);
5279 if (code >= 0
5280 && (type == TYPE_LOAD
5281 || type == TYPE_LOADN))
5282 {
5283 if (!MEM_P (src)
5284 && (GET_CODE (src) != ZERO_EXTEND
5285 || !MEM_P (XEXP (src, 0))))
5286 return false;
5287
5288 if (GET_MODE_SIZE (GET_MODE (dest)) > 4
5289 && (GET_MODE_SIZE (GET_MODE (dest)) != 8 || !TARGET_LDDW))
5290 return false;
5291
5292 rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
5293 SET_SRC (pat));
5294 newpat = gen_load_shadow (SET_DEST (pat));
5295 pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_LOAD);
5296 delay = 4;
5297 }
5298 else if (code >= 0
5299 && (type == TYPE_MPY2
5300 || type == TYPE_MPY4))
5301 {
5302 /* We don't handle floating point multiplies yet. */
5303 if (GET_MODE (dest) == SFmode)
5304 return false;
5305
5306 rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
5307 SET_SRC (pat));
5308 newpat = gen_mult_shadow (SET_DEST (pat));
5309 pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_MULT);
5310 delay = type == TYPE_MPY2 ? 1 : 3;
5311 }
5312 else
5313 return false;
5314
5315 pat = duplicate_cond (pat, insn);
5316 newpat = duplicate_cond (newpat, insn);
5317 i1 = emit_insn_before (pat, insn);
5318 PATTERN (insn) = newpat;
5319 INSN_CODE (insn) = -1;
5320 recog_memoized (insn);
5321 recog_memoized (i1);
5322 record_delay_slot_pair (i1, insn, delay, 0);
5323 return true;
5324}
5325
5326/* Examine if INSN is the result of splitting a load into a real load and a
5327 shadow, and if so, undo the transformation. */
5328static void
5329undo_split_delayed_nonbranch (rtx insn)
5330{
5331 int icode = recog_memoized (insn);
5332 enum attr_type type;
5333 rtx prev_pat, insn_pat, prev;
5334
5335 if (icode < 0)
5336 return;
5337 type = get_attr_type (insn);
5338 if (type != TYPE_LOAD_SHADOW && type != TYPE_MULT_SHADOW)
5339 return;
5340 prev = PREV_INSN (insn);
5341 prev_pat = PATTERN (prev);
5342 insn_pat = PATTERN (insn);
5343 if (GET_CODE (prev_pat) == COND_EXEC)
5344 {
5345 prev_pat = COND_EXEC_CODE (prev_pat);
5346 insn_pat = COND_EXEC_CODE (insn_pat);
5347 }
5348
5349 gcc_assert (GET_CODE (prev_pat) == UNSPEC
5350 && ((XINT (prev_pat, 1) == UNSPEC_REAL_LOAD
5351 && type == TYPE_LOAD_SHADOW)
5352 || (XINT (prev_pat, 1) == UNSPEC_REAL_MULT
5353 && type == TYPE_MULT_SHADOW)));
5354 insn_pat = gen_rtx_SET (VOIDmode, SET_DEST (insn_pat),
5355 XVECEXP (prev_pat, 0, 1));
5356 insn_pat = duplicate_cond (insn_pat, prev);
5357 PATTERN (insn) = insn_pat;
5358 INSN_CODE (insn) = -1;
5359 delete_insn (prev);
5360}
5361
bcead286
BS
5362/* Split every insn (i.e. jumps and calls) which can have delay slots into
5363 two parts: the first one is scheduled normally and emits the instruction,
5364 while the second one is a shadow insn which shows the side effect taking
5365 place. The second one is placed in the right cycle by the scheduler, but
5366 not emitted as an assembly instruction. */
5367
5368static void
5369split_delayed_insns (void)
5370{
5371 rtx insn;
5372 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5373 {
5374 if (JUMP_P (insn) || CALL_P (insn))
5375 split_delayed_branch (insn);
5376 }
5377}
5378
5379/* For every insn that has an entry in the new_conditions vector, give it
5380 the appropriate predicate. */
5381static void
5382conditionalize_after_sched (void)
5383{
5384 basic_block bb;
5385 rtx insn;
11cd3bed 5386 FOR_EACH_BB_FN (bb, cfun)
bcead286
BS
5387 FOR_BB_INSNS (bb, insn)
5388 {
5389 unsigned uid = INSN_UID (insn);
5390 rtx cond;
5391 if (!NONDEBUG_INSN_P (insn) || uid >= INSN_INFO_LENGTH)
5392 continue;
5393 cond = INSN_INFO_ENTRY (uid).new_cond;
5394 if (cond == NULL_RTX)
5395 continue;
5396 if (dump_file)
5397 fprintf (dump_file, "Conditionalizing insn %d\n", uid);
5398 predicate_insn (insn, cond, true);
5399 }
5400}
5401
11e69edc
BS
5402/* A callback for the hw-doloop pass. This function examines INSN; if
5403 it is a loop_end pattern we recognize, return the reg rtx for the
5404 loop counter. Otherwise, return NULL_RTX. */
5405
5406static rtx
5407hwloop_pattern_reg (rtx insn)
5408{
5409 rtx pat, reg;
5410
5411 if (!JUMP_P (insn) || recog_memoized (insn) != CODE_FOR_loop_end)
5412 return NULL_RTX;
5413
5414 pat = PATTERN (insn);
5415 reg = SET_DEST (XVECEXP (pat, 0, 1));
5416 if (!REG_P (reg))
5417 return NULL_RTX;
5418 return reg;
5419}
5420
5421/* Return the number of cycles taken by BB, as computed by scheduling,
5422 including the latencies of all insns with delay slots. IGNORE is
5423 an insn we should ignore in the calculation, usually the final
5424 branch. */
5425static int
5426bb_earliest_end_cycle (basic_block bb, rtx ignore)
5427{
5428 int earliest = 0;
5429 rtx insn;
5430
5431 FOR_BB_INSNS (bb, insn)
5432 {
5433 int cycles, this_clock;
5434
5435 if (LABEL_P (insn) || NOTE_P (insn) || DEBUG_INSN_P (insn)
5436 || GET_CODE (PATTERN (insn)) == USE
5437 || GET_CODE (PATTERN (insn)) == CLOBBER
5438 || insn == ignore)
5439 continue;
5440
5441 this_clock = insn_get_clock (insn);
5442 cycles = get_attr_cycles (insn);
5443
5444 if (earliest < this_clock + cycles)
5445 earliest = this_clock + cycles;
5446 }
5447 return earliest;
5448}
5449
5450/* Examine the insns in BB and remove all which have a uid greater or
5451 equal to MAX_UID. */
5452static void
5453filter_insns_above (basic_block bb, int max_uid)
5454{
5455 rtx insn, next;
5456 bool prev_ti = false;
5457 int prev_cycle = -1;
5458
5459 FOR_BB_INSNS_SAFE (bb, insn, next)
5460 {
5461 int this_cycle;
5462 if (!NONDEBUG_INSN_P (insn))
5463 continue;
5464 if (insn == BB_END (bb))
5465 return;
5466 this_cycle = insn_get_clock (insn);
5467 if (prev_ti && this_cycle == prev_cycle)
5468 {
5469 gcc_assert (GET_MODE (insn) != TImode);
5470 PUT_MODE (insn, TImode);
5471 }
5472 prev_ti = false;
5473 if (INSN_UID (insn) >= max_uid)
5474 {
5475 if (GET_MODE (insn) == TImode)
5476 {
5477 prev_ti = true;
5478 prev_cycle = this_cycle;
5479 }
5480 delete_insn (insn);
5481 }
5482 }
5483}
5484
74b388c3
PB
5485/* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
5486
5487static void
5488c6x_asm_emit_except_personality (rtx personality)
5489{
5490 fputs ("\t.personality\t", asm_out_file);
5491 output_addr_const (asm_out_file, personality);
5492 fputc ('\n', asm_out_file);
5493}
5494
5495/* Use a special assembly directive rather than a regular setion for
5496 unwind table data. */
5497
5498static void
5499c6x_asm_init_sections (void)
5500{
5501 exception_section = get_unnamed_section (0, output_section_asm_op,
5502 "\t.handlerdata");
5503}
5504
11e69edc
BS
5505/* A callback for the hw-doloop pass. Called to optimize LOOP in a
5506 machine-specific fashion; returns true if successful and false if
5507 the hwloop_fail function should be called. */
5508
5509static bool
5510hwloop_optimize (hwloop_info loop)
5511{
5512 basic_block entry_bb, bb;
5513 rtx seq, insn, prev, entry_after, end_packet;
5514 rtx head_insn, tail_insn, new_insns, last_insn;
ed80f859 5515 int loop_earliest;
11e69edc
BS
5516 int n_execute_packets;
5517 edge entry_edge;
5518 unsigned ix;
5519 int max_uid_before, delayed_splits;
5520 int i, sp_ii, min_ii, max_ii, max_parallel, n_insns, n_real_insns, stages;
5521 rtx *orig_vec;
5522 rtx *copies;
5523 rtx **insn_copies;
5524
5525 if (!c6x_flag_modulo_sched || !c6x_flag_schedule_insns2
5526 || !TARGET_INSNS_64PLUS)
5527 return false;
5528
5529 if (loop->iter_reg_used || loop->depth > 1)
5530 return false;
5531 if (loop->has_call || loop->has_asm)
5532 return false;
5533
5534 if (loop->head != loop->tail)
5535 return false;
5536
5537 gcc_assert (loop->incoming_dest == loop->head);
5538
5539 entry_edge = NULL;
9771b263 5540 FOR_EACH_VEC_SAFE_ELT (loop->incoming, i, entry_edge)
11e69edc
BS
5541 if (entry_edge->flags & EDGE_FALLTHRU)
5542 break;
5543 if (entry_edge == NULL)
5544 return false;
5545
8076c3e3
BS
5546 reshuffle_units (loop->head);
5547
1a83e602 5548 in_hwloop = true;
11e69edc
BS
5549 schedule_ebbs_init ();
5550 schedule_ebb (BB_HEAD (loop->tail), loop->loop_end, true);
5551 schedule_ebbs_finish ();
1a83e602 5552 in_hwloop = false;
11e69edc
BS
5553
5554 bb = loop->head;
5555 loop_earliest = bb_earliest_end_cycle (bb, loop->loop_end) + 1;
5556
5557 max_uid_before = get_max_uid ();
5558
5559 /* Split all multi-cycle operations, such as loads. For normal
5560 scheduling, we only do this for branches, as the generated code
5561 would otherwise not be interrupt-safe. When using sploop, it is
5562 safe and beneficial to split them. If any multi-cycle operations
5563 remain after splitting (because we don't handle them yet), we
5564 cannot pipeline the loop. */
5565 delayed_splits = 0;
5566 FOR_BB_INSNS (bb, insn)
5567 {
5568 if (NONDEBUG_INSN_P (insn))
5569 {
5570 recog_memoized (insn);
5571 if (split_delayed_nonbranch (insn))
5572 delayed_splits++;
5573 else if (INSN_CODE (insn) >= 0
5574 && get_attr_cycles (insn) > 1)
5575 goto undo_splits;
5576 }
5577 }
5578
5579 /* Count the number of insns as well as the number real insns, and save
5580 the original sequence of insns in case we must restore it later. */
5581 n_insns = n_real_insns = 0;
5582 FOR_BB_INSNS (bb, insn)
5583 {
5584 n_insns++;
5585 if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
5586 n_real_insns++;
5587 }
5588 orig_vec = XNEWVEC (rtx, n_insns);
5589 n_insns = 0;
5590 FOR_BB_INSNS (bb, insn)
5591 orig_vec[n_insns++] = insn;
5592
5593 /* Count the unit reservations, and compute a minimum II from that
5594 table. */
5595 count_unit_reqs (unit_reqs, loop->start_label,
5596 PREV_INSN (loop->loop_end));
5597 merge_unit_reqs (unit_reqs);
5598
5599 min_ii = res_mii (unit_reqs);
5600 max_ii = loop_earliest < 15 ? loop_earliest : 14;
5601
5602 /* Make copies of the loop body, up to a maximum number of stages we want
5603 to handle. */
5604 max_parallel = loop_earliest / min_ii + 1;
5605
5606 copies = XCNEWVEC (rtx, (max_parallel + 1) * n_real_insns);
5607 insn_copies = XNEWVEC (rtx *, max_parallel + 1);
5608 for (i = 0; i < max_parallel + 1; i++)
5609 insn_copies[i] = copies + i * n_real_insns;
5610
5611 head_insn = next_nonnote_nondebug_insn (loop->start_label);
5612 tail_insn = prev_real_insn (BB_END (bb));
5613
5614 i = 0;
5615 FOR_BB_INSNS (bb, insn)
5616 if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
5617 insn_copies[0][i++] = insn;
5618
5619 sploop_max_uid_iter0 = get_max_uid ();
5620
5621 /* Generate the copies of the loop body, and save them in the
5622 INSN_COPIES array. */
5623 start_sequence ();
5624 for (i = 0; i < max_parallel; i++)
5625 {
5626 int j;
5627 rtx this_iter;
5628
5629 this_iter = duplicate_insn_chain (head_insn, tail_insn);
5630 j = 0;
5631 while (this_iter)
5632 {
5633 rtx prev_stage_insn = insn_copies[i][j];
5634 gcc_assert (INSN_CODE (this_iter) == INSN_CODE (prev_stage_insn));
5635
5636 if (INSN_CODE (this_iter) >= 0
5637 && (get_attr_type (this_iter) == TYPE_LOAD_SHADOW
5638 || get_attr_type (this_iter) == TYPE_MULT_SHADOW))
5639 {
5640 rtx prev = PREV_INSN (this_iter);
5641 record_delay_slot_pair (prev, this_iter,
5642 get_attr_cycles (prev) - 1, 0);
5643 }
5644 else
5645 record_delay_slot_pair (prev_stage_insn, this_iter, i, 1);
5646
5647 insn_copies[i + 1][j] = this_iter;
5648 j++;
5649 this_iter = next_nonnote_nondebug_insn (this_iter);
5650 }
5651 }
5652 new_insns = get_insns ();
5653 last_insn = insn_copies[max_parallel][n_real_insns - 1];
5654 end_sequence ();
5655 emit_insn_before (new_insns, BB_END (bb));
5656
5657 /* Try to schedule the loop using varying initiation intervals,
5658 starting with the smallest possible and incrementing it
5659 on failure. */
5660 for (sp_ii = min_ii; sp_ii <= max_ii; sp_ii++)
5661 {
5662 basic_block tmp_bb;
5663 if (dump_file)
5664 fprintf (dump_file, "Trying to schedule for II %d\n", sp_ii);
5665
5666 df_clear_flags (DF_LR_RUN_DCE);
5667
5668 schedule_ebbs_init ();
5669 set_modulo_params (sp_ii, max_parallel, n_real_insns,
5670 sploop_max_uid_iter0);
5671 tmp_bb = schedule_ebb (BB_HEAD (bb), last_insn, true);
5672 schedule_ebbs_finish ();
5673
5674 if (tmp_bb)
5675 {
5676 if (dump_file)
5677 fprintf (dump_file, "Found schedule with II %d\n", sp_ii);
5678 break;
5679 }
5680 }
5681
5682 discard_delay_pairs_above (max_uid_before);
5683
5684 if (sp_ii > max_ii)
5685 goto restore_loop;
5686
5687 stages = insn_get_clock (ss.last_scheduled_iter0) / sp_ii + 1;
5688
5689 if (stages == 1 && sp_ii > 5)
5690 goto restore_loop;
5691
5692 /* At this point, we know we've been successful, unless we find later that
5693 there are too many execute packets for the loop buffer to hold. */
5694
5695 /* Assign reservations to the instructions in the loop. We must find
5696 the stage that contains the full loop kernel, and transfer the
5697 reservations of the instructions contained in it to the corresponding
5698 instructions from iteration 0, which are the only ones we'll keep. */
5699 assign_reservations (BB_HEAD (bb), ss.last_scheduled_insn);
5700 PREV_INSN (BB_END (bb)) = ss.last_scheduled_iter0;
5701 NEXT_INSN (ss.last_scheduled_iter0) = BB_END (bb);
5702 filter_insns_above (bb, sploop_max_uid_iter0);
5703
5704 for (i = 0; i < n_real_insns; i++)
5705 {
5706 rtx insn = insn_copies[0][i];
5707 int uid = INSN_UID (insn);
5708 int stage = insn_uid_get_clock (uid) / sp_ii;
5709
5710 if (stage + 1 < stages)
5711 {
5712 int copy_uid;
5713 stage = stages - stage - 1;
5714 copy_uid = INSN_UID (insn_copies[stage][i]);
5715 INSN_INFO_ENTRY (uid).reservation
5716 = INSN_INFO_ENTRY (copy_uid).reservation;
5717 }
5718 }
5719 if (stages == 1)
5720 stages++;
5721
5722 /* Compute the number of execute packets the pipelined form of the loop will
5723 require. */
5724 prev = NULL_RTX;
5725 n_execute_packets = 0;
5726 for (insn = loop->start_label; insn != loop->loop_end; insn = NEXT_INSN (insn))
5727 {
5728 if (NONDEBUG_INSN_P (insn) && GET_MODE (insn) == TImode
5729 && !shadow_p (insn))
5730 {
5731 n_execute_packets++;
5732 if (prev && insn_get_clock (prev) + 1 != insn_get_clock (insn))
5733 /* We need an extra NOP instruction. */
5734 n_execute_packets++;
5735
5736 prev = insn;
5737 }
5738 }
5739
5740 end_packet = ss.last_scheduled_iter0;
5741 while (!NONDEBUG_INSN_P (end_packet) || GET_MODE (end_packet) != TImode)
5742 end_packet = PREV_INSN (end_packet);
5743
5744 /* The earliest cycle in which we can emit the SPKERNEL instruction. */
5745 loop_earliest = (stages - 1) * sp_ii;
5746 if (loop_earliest > insn_get_clock (end_packet))
5747 {
5748 n_execute_packets++;
5749 end_packet = loop->loop_end;
5750 }
5751 else
5752 loop_earliest = insn_get_clock (end_packet);
5753
5754 if (n_execute_packets > 14)
5755 goto restore_loop;
5756
5757 /* Generate the spkernel instruction, and place it at the appropriate
5758 spot. */
5759 PUT_MODE (end_packet, VOIDmode);
5760
5761 insn = gen_spkernel (GEN_INT (stages - 1),
5762 const0_rtx, JUMP_LABEL (loop->loop_end));
5763 insn = emit_jump_insn_before (insn, end_packet);
5764 JUMP_LABEL (insn) = JUMP_LABEL (loop->loop_end);
5765 insn_set_clock (insn, loop_earliest);
5766 PUT_MODE (insn, TImode);
5767 INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start = false;
5768 delete_insn (loop->loop_end);
5769
5770 /* Place the mvc and sploop instructions before the loop. */
5771 entry_bb = entry_edge->src;
5772
5773 start_sequence ();
5774
5775 insn = emit_insn (gen_mvilc (loop->iter_reg));
5776 insn = emit_insn (gen_sploop (GEN_INT (sp_ii)));
5777
5778 seq = get_insns ();
5779
9771b263 5780 if (!single_succ_p (entry_bb) || vec_safe_length (loop->incoming) > 1)
11e69edc
BS
5781 {
5782 basic_block new_bb;
5783 edge e;
5784 edge_iterator ei;
5785
5786 emit_insn_before (seq, BB_HEAD (loop->head));
5787 seq = emit_label_before (gen_label_rtx (), seq);
5788
5789 new_bb = create_basic_block (seq, insn, entry_bb);
5790 FOR_EACH_EDGE (e, ei, loop->incoming)
5791 {
5792 if (!(e->flags & EDGE_FALLTHRU))
5793 redirect_edge_and_branch_force (e, new_bb);
5794 else
5795 redirect_edge_succ (e, new_bb);
5796 }
5797 make_edge (new_bb, loop->head, 0);
5798 }
5799 else
5800 {
5801 entry_after = BB_END (entry_bb);
5802 while (DEBUG_INSN_P (entry_after)
5803 || (NOTE_P (entry_after)
5804 && NOTE_KIND (entry_after) != NOTE_INSN_BASIC_BLOCK))
5805 entry_after = PREV_INSN (entry_after);
5806 emit_insn_after (seq, entry_after);
5807 }
5808
5809 end_sequence ();
5810
5811 /* Make sure we don't try to schedule this loop again. */
9771b263 5812 for (ix = 0; loop->blocks.iterate (ix, &bb); ix++)
11e69edc
BS
5813 bb->flags |= BB_DISABLE_SCHEDULE;
5814
5815 return true;
5816
5817 restore_loop:
5818 if (dump_file)
5819 fprintf (dump_file, "Unable to pipeline loop.\n");
5820
5821 for (i = 1; i < n_insns; i++)
5822 {
5823 NEXT_INSN (orig_vec[i - 1]) = orig_vec[i];
5824 PREV_INSN (orig_vec[i]) = orig_vec[i - 1];
5825 }
5826 PREV_INSN (orig_vec[0]) = PREV_INSN (BB_HEAD (bb));
5827 NEXT_INSN (PREV_INSN (BB_HEAD (bb))) = orig_vec[0];
5828 NEXT_INSN (orig_vec[n_insns - 1]) = NEXT_INSN (BB_END (bb));
5829 PREV_INSN (NEXT_INSN (BB_END (bb))) = orig_vec[n_insns - 1];
5830 BB_HEAD (bb) = orig_vec[0];
5831 BB_END (bb) = orig_vec[n_insns - 1];
5832 undo_splits:
5833 free_delay_pairs ();
5834 FOR_BB_INSNS (bb, insn)
5835 if (NONDEBUG_INSN_P (insn))
5836 undo_split_delayed_nonbranch (insn);
5837 return false;
5838}
5839
5840/* A callback for the hw-doloop pass. Called when a loop we have discovered
5841 turns out not to be optimizable; we have to split the doloop_end pattern
5842 into a subtract and a test. */
5843static void
5844hwloop_fail (hwloop_info loop)
5845{
5846 rtx insn, test, testreg;
5847
5848 if (dump_file)
5849 fprintf (dump_file, "splitting doloop insn %d\n",
5850 INSN_UID (loop->loop_end));
5851 insn = gen_addsi3 (loop->iter_reg, loop->iter_reg, constm1_rtx);
5852 /* See if we can emit the add at the head of the loop rather than at the
5853 end. */
5854 if (loop->head == NULL
5855 || loop->iter_reg_used_outside
5856 || loop->iter_reg_used
5857 || TEST_HARD_REG_BIT (loop->regs_set_in_loop, REGNO (loop->iter_reg))
5858 || loop->incoming_dest != loop->head
5859 || EDGE_COUNT (loop->head->preds) != 2)
5860 emit_insn_before (insn, loop->loop_end);
5861 else
5862 {
5863 rtx t = loop->start_label;
5864 while (!NOTE_P (t) || NOTE_KIND (t) != NOTE_INSN_BASIC_BLOCK)
5865 t = NEXT_INSN (t);
5866 emit_insn_after (insn, t);
5867 }
5868
5869 testreg = SET_DEST (XVECEXP (PATTERN (loop->loop_end), 0, 2));
5870 if (GET_CODE (testreg) == SCRATCH)
5871 testreg = loop->iter_reg;
5872 else
5873 emit_insn_before (gen_movsi (testreg, loop->iter_reg), loop->loop_end);
5874
5875 test = gen_rtx_NE (VOIDmode, testreg, const0_rtx);
5876 insn = emit_jump_insn_before (gen_cbranchsi4 (test, testreg, const0_rtx,
5877 loop->start_label),
5878 loop->loop_end);
5879
5880 JUMP_LABEL (insn) = loop->start_label;
5881 LABEL_NUSES (loop->start_label)++;
5882 delete_insn (loop->loop_end);
5883}
5884
5885static struct hw_doloop_hooks c6x_doloop_hooks =
5886{
5887 hwloop_pattern_reg,
5888 hwloop_optimize,
5889 hwloop_fail
5890};
5891
5892/* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
5893 doloop_end patterns where such optimizations are impossible. */
5894static void
5895c6x_hwloops (void)
5896{
5897 if (optimize)
5898 reorg_loops (true, &c6x_doloop_hooks);
5899}
5900
bcead286
BS
5901/* Implement the TARGET_MACHINE_DEPENDENT_REORG pass. We split call insns here
5902 into a sequence that loads the return register and performs the call,
5903 and emit the return label.
5904 If scheduling after reload is requested, it happens here. */
5905
5906static void
5907c6x_reorg (void)
5908{
5909 basic_block bb;
5910 rtx *call_labels;
5911 bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
5912 && !maybe_skip_selective_scheduling ());
5913
5914 /* We are freeing block_for_insn in the toplev to keep compatibility
5915 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5916 compute_bb_for_insn ();
5917
5918 df_clear_flags (DF_LR_RUN_DCE);
8076c3e3 5919 df_note_add_problem ();
bcead286
BS
5920
5921 /* If optimizing, we'll have split before scheduling. */
5922 if (optimize == 0)
5923 split_all_insns ();
5924
8076c3e3
BS
5925 df_analyze ();
5926
bcead286
BS
5927 if (c6x_flag_schedule_insns2)
5928 {
5929 int sz = get_max_uid () * 3 / 2 + 1;
5930
9771b263 5931 insn_info.create (sz);
11e69edc
BS
5932 }
5933
5934 /* Make sure the real-jump insns we create are not deleted. When modulo-
5935 scheduling, situations where a reg is only stored in a loop can also
5936 cause dead code when doing the initial unrolling. */
5937 sched_no_dce = true;
bcead286 5938
11e69edc 5939 c6x_hwloops ();
bcead286 5940
11e69edc
BS
5941 if (c6x_flag_schedule_insns2)
5942 {
bcead286
BS
5943 split_delayed_insns ();
5944 timevar_push (TV_SCHED2);
5945 if (do_selsched)
5946 run_selective_scheduling ();
5947 else
5948 schedule_ebbs ();
5949 conditionalize_after_sched ();
5950 timevar_pop (TV_SCHED2);
5951
5952 free_delay_pairs ();
bcead286 5953 }
11e69edc 5954 sched_no_dce = false;
bcead286
BS
5955
5956 call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
5957
5958 reorg_split_calls (call_labels);
5959
5960 if (c6x_flag_schedule_insns2)
5961 {
11cd3bed 5962 FOR_EACH_BB_FN (bb, cfun)
bcead286
BS
5963 if ((bb->flags & BB_DISABLE_SCHEDULE) == 0)
5964 assign_reservations (BB_HEAD (bb), BB_END (bb));
5965 }
5966
5967 if (c6x_flag_var_tracking)
5968 {
5969 timevar_push (TV_VAR_TRACKING);
5970 variable_tracking_main ();
5971 timevar_pop (TV_VAR_TRACKING);
5972 }
5973
5974 reorg_emit_nops (call_labels);
5975
5976 /* Post-process the schedule to move parallel insns into SEQUENCEs. */
5977 if (c6x_flag_schedule_insns2)
5978 {
5979 free_delay_pairs ();
5980 c6x_gen_bundles ();
5981 }
5982
5983 df_finish_pass (false);
5984}
5985
5986/* Called when a function has been assembled. It should perform all the
5987 tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
5988 tasks.
5989 We free the reservation (and other scheduling) information here now that
5990 all insns have been output. */
5991void
5992c6x_function_end (FILE *file, const char *fname)
5993{
5994 c6x_output_fn_unwind (file);
5995
9771b263 5996 insn_info.release ();
bcead286
BS
5997
5998 if (!flag_inhibit_size_directive)
5999 ASM_OUTPUT_MEASURED_SIZE (file, fname);
6000}
6001\f
6002/* Determine whether X is a shift with code CODE and an integer amount
6003 AMOUNT. */
6004static bool
6005shift_p (rtx x, enum rtx_code code, int amount)
6006{
6007 return (GET_CODE (x) == code && GET_CODE (XEXP (x, 1)) == CONST_INT
6008 && INTVAL (XEXP (x, 1)) == amount);
6009}
6010
6011/* Compute a (partial) cost for rtx X. Return true if the complete
6012 cost has been computed, and false if subexpressions should be
6013 scanned. In either case, *TOTAL contains the cost result. */
6014
6015static bool
68f932c4
RS
6016c6x_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
6017 bool speed)
bcead286
BS
6018{
6019 int cost2 = COSTS_N_INSNS (1);
6020 rtx op0, op1;
6021
6022 switch (code)
6023 {
6024 case CONST_INT:
6025 if (outer_code == SET || outer_code == PLUS)
6026 *total = satisfies_constraint_IsB (x) ? 0 : cost2;
6027 else if (outer_code == AND || outer_code == IOR || outer_code == XOR
6028 || outer_code == MINUS)
6029 *total = satisfies_constraint_Is5 (x) ? 0 : cost2;
6030 else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
6031 || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
6032 *total = satisfies_constraint_Iu4 (x) ? 0 : cost2;
6033 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
6034 || outer_code == LSHIFTRT)
6035 *total = satisfies_constraint_Iu5 (x) ? 0 : cost2;
6036 else
6037 *total = cost2;
6038 return true;
6039
6040 case CONST:
6041 case LABEL_REF:
6042 case SYMBOL_REF:
6043 case CONST_DOUBLE:
6044 *total = COSTS_N_INSNS (2);
6045 return true;
6046
6047 case TRUNCATE:
6048 /* Recognize a mult_highpart operation. */
6049 if ((GET_MODE (x) == HImode || GET_MODE (x) == SImode)
6050 && GET_CODE (XEXP (x, 0)) == LSHIFTRT
6051 && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x))
6052 && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
6053 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
6054 && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x)))
6055 {
6056 rtx mul = XEXP (XEXP (x, 0), 0);
6057 rtx op0 = XEXP (mul, 0);
6058 rtx op1 = XEXP (mul, 1);
6059 enum rtx_code code0 = GET_CODE (op0);
6060 enum rtx_code code1 = GET_CODE (op1);
6061
6062 if ((code0 == code1
6063 && (code0 == SIGN_EXTEND || code0 == ZERO_EXTEND))
6064 || (GET_MODE (x) == HImode
6065 && code0 == ZERO_EXTEND && code1 == SIGN_EXTEND))
6066 {
6067 if (GET_MODE (x) == HImode)
6068 *total = COSTS_N_INSNS (2);
6069 else
6070 *total = COSTS_N_INSNS (12);
68f932c4
RS
6071 *total += rtx_cost (XEXP (op0, 0), code0, 0, speed);
6072 *total += rtx_cost (XEXP (op1, 0), code1, 0, speed);
bcead286
BS
6073 return true;
6074 }
6075 }
6076 return false;
6077
6078 case ASHIFT:
6079 case ASHIFTRT:
6080 case LSHIFTRT:
6081 if (GET_MODE (x) == DImode)
6082 *total = COSTS_N_INSNS (CONSTANT_P (XEXP (x, 1)) ? 4 : 15);
6083 else
6084 *total = COSTS_N_INSNS (1);
6085 return false;
6086
6087 case PLUS:
6088 case MINUS:
6089 *total = COSTS_N_INSNS (1);
6090 op0 = code == PLUS ? XEXP (x, 0) : XEXP (x, 1);
6091 op1 = code == PLUS ? XEXP (x, 1) : XEXP (x, 0);
6092 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
6093 && INTEGRAL_MODE_P (GET_MODE (x))
6094 && GET_CODE (op0) == MULT
6095 && GET_CODE (XEXP (op0, 1)) == CONST_INT
6096 && (INTVAL (XEXP (op0, 1)) == 2
6097 || INTVAL (XEXP (op0, 1)) == 4
6098 || (code == PLUS && INTVAL (XEXP (op0, 1)) == 8)))
6099 {
68f932c4
RS
6100 *total += rtx_cost (XEXP (op0, 0), ASHIFT, 0, speed);
6101 *total += rtx_cost (op1, (enum rtx_code) code, 1, speed);
bcead286
BS
6102 return true;
6103 }
6104 return false;
6105
6106 case MULT:
6107 op0 = XEXP (x, 0);
6108 op1 = XEXP (x, 1);
6109 if (GET_MODE (x) == DFmode)
6110 {
6111 if (TARGET_FP)
6112 *total = COSTS_N_INSNS (speed ? 10 : 1);
6113 else
6114 *total = COSTS_N_INSNS (speed ? 200 : 4);
6115 }
6116 else if (GET_MODE (x) == SFmode)
6117 {
6118 if (TARGET_FP)
6119 *total = COSTS_N_INSNS (speed ? 4 : 1);
6120 else
6121 *total = COSTS_N_INSNS (speed ? 100 : 4);
6122 }
6123 else if (GET_MODE (x) == DImode)
6124 {
6125 if (TARGET_MPY32
6126 && GET_CODE (op0) == GET_CODE (op1)
6127 && (GET_CODE (op0) == ZERO_EXTEND
6128 || GET_CODE (op0) == SIGN_EXTEND))
6129 {
6130 *total = COSTS_N_INSNS (speed ? 2 : 1);
6131 op0 = XEXP (op0, 0);
6132 op1 = XEXP (op1, 0);
6133 }
6134 else
6135 /* Maybe improve this laster. */
6136 *total = COSTS_N_INSNS (20);
6137 }
6138 else if (GET_MODE (x) == SImode)
6139 {
6140 if (((GET_CODE (op0) == ZERO_EXTEND
6141 || GET_CODE (op0) == SIGN_EXTEND
6142 || shift_p (op0, LSHIFTRT, 16))
6143 && (GET_CODE (op1) == SIGN_EXTEND
6144 || GET_CODE (op1) == ZERO_EXTEND
6145 || scst5_operand (op1, SImode)
6146 || shift_p (op1, ASHIFTRT, 16)
6147 || shift_p (op1, LSHIFTRT, 16)))
6148 || (shift_p (op0, ASHIFTRT, 16)
6149 && (GET_CODE (op1) == SIGN_EXTEND
6150 || shift_p (op1, ASHIFTRT, 16))))
6151 {
6152 *total = COSTS_N_INSNS (speed ? 2 : 1);
6153 op0 = XEXP (op0, 0);
6154 if (scst5_operand (op1, SImode))
6155 op1 = NULL_RTX;
6156 else
6157 op1 = XEXP (op1, 0);
6158 }
6159 else if (!speed)
6160 *total = COSTS_N_INSNS (1);
6161 else if (TARGET_MPY32)
6162 *total = COSTS_N_INSNS (4);
6163 else
6164 *total = COSTS_N_INSNS (6);
6165 }
6166 else if (GET_MODE (x) == HImode)
6167 *total = COSTS_N_INSNS (speed ? 2 : 1);
6168
6169 if (GET_CODE (op0) != REG
6170 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
68f932c4 6171 *total += rtx_cost (op0, MULT, 0, speed);
bcead286
BS
6172 if (op1 && GET_CODE (op1) != REG
6173 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
68f932c4 6174 *total += rtx_cost (op1, MULT, 1, speed);
bcead286
BS
6175 return true;
6176
6177 case UDIV:
6178 case DIV:
6179 /* This is a bit random; assuming on average there'll be 16 leading
6180 zeros. FIXME: estimate better for constant dividends. */
6181 *total = COSTS_N_INSNS (6 + 3 * 16);
6182 return false;
6183
6184 case IF_THEN_ELSE:
6185 /* Recognize the cmp_and/ior patterns. */
6186 op0 = XEXP (x, 0);
6187 if ((GET_CODE (op0) == EQ || GET_CODE (op0) == NE)
6188 && REG_P (XEXP (op0, 0))
6189 && XEXP (op0, 1) == const0_rtx
6190 && rtx_equal_p (XEXP (x, 1), XEXP (op0, 0)))
6191 {
68f932c4
RS
6192 *total = rtx_cost (XEXP (x, 1), (enum rtx_code) outer_code,
6193 opno, speed);
bcead286
BS
6194 return false;
6195 }
6196 return false;
6197
6198 default:
6199 return false;
6200 }
6201}
6202
6203/* Implements target hook vector_mode_supported_p. */
6204
6205static bool
6206c6x_vector_mode_supported_p (enum machine_mode mode)
6207{
6208 switch (mode)
6209 {
6210 case V2HImode:
6211 case V4QImode:
6212 case V2SImode:
6213 case V4HImode:
6214 case V8QImode:
6215 return true;
6216 default:
6217 return false;
6218 }
6219}
6220
6221/* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6222static enum machine_mode
6223c6x_preferred_simd_mode (enum machine_mode mode)
6224{
6225 switch (mode)
6226 {
6227 case HImode:
6228 return V2HImode;
6229 case QImode:
6230 return V4QImode;
6231
6232 default:
6233 return word_mode;
6234 }
6235}
6236
6237/* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6238
6239static bool
6240c6x_scalar_mode_supported_p (enum machine_mode mode)
6241{
6242 if (ALL_FIXED_POINT_MODE_P (mode)
6243 && GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
6244 return true;
6245
6246 return default_scalar_mode_supported_p (mode);
6247}
6248
6249/* Output a reference from a function exception table to the type_info
6250 object X. Output these via a special assembly directive. */
6251
6252static bool
6253c6x_output_ttype (rtx x)
6254{
6255 /* Use special relocations for symbol references. */
6256 if (GET_CODE (x) != CONST_INT)
6257 fputs ("\t.ehtype\t", asm_out_file);
6258 else
6259 fputs ("\t.word\t", asm_out_file);
6260 output_addr_const (asm_out_file, x);
6261 fputc ('\n', asm_out_file);
6262
6263 return TRUE;
6264}
6265
6266/* Modify the return address of the current function. */
6267
6268void
6269c6x_set_return_address (rtx source, rtx scratch)
6270{
6271 struct c6x_frame frame;
6272 rtx addr;
6273 HOST_WIDE_INT offset;
6274
6275 c6x_compute_frame_layout (&frame);
6276 if (! c6x_save_reg (RETURN_ADDR_REGNO))
6277 emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNO), source);
6278 else
6279 {
6280
6281 if (frame_pointer_needed)
6282 {
6283 addr = hard_frame_pointer_rtx;
6284 offset = frame.b3_offset;
6285 }
6286 else
6287 {
6288 addr = stack_pointer_rtx;
6289 offset = frame.to_allocate - frame.b3_offset;
6290 }
6291
6292 /* TODO: Use base+offset loads where possible. */
6293 if (offset)
6294 {
6295 HOST_WIDE_INT low = trunc_int_for_mode (offset, HImode);
6296
6297 emit_insn (gen_movsi_high (scratch, GEN_INT (low)));
6298 if (low != offset)
6299 emit_insn (gen_movsi_lo_sum (scratch, scratch, GEN_INT(offset)));
6300 emit_insn (gen_addsi3 (scratch, addr, scratch));
6301 addr = scratch;
6302 }
6303
6304 emit_move_insn (gen_frame_mem (Pmode, addr), source);
6305 }
6306}
6307
6308/* We save pairs of registers using a DImode store. Describe the component
6309 registers for DWARF generation code. */
6310
6311static rtx
6312c6x_dwarf_register_span (rtx rtl)
6313{
6314 unsigned regno;
6315 unsigned real_regno;
6316 int nregs;
6317 int i;
6318 rtx p;
6319
6320 regno = REGNO (rtl);
6321 nregs = HARD_REGNO_NREGS (regno, GET_MODE (rtl));
6322 if (nregs == 1)
6323 return NULL_RTX;
6324
6325 p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc(nregs));
6326 for (i = 0; i < nregs; i++)
6327 {
6328 if (TARGET_BIG_ENDIAN)
6329 real_regno = regno + nregs - (i + 1);
6330 else
6331 real_regno = regno + i;
6332
6333 XVECEXP (p, 0, i) = gen_rtx_REG (SImode, real_regno);
6334 }
6335
6336 return p;
6337}
6338\f
6339/* Codes for all the C6X builtins. */
6340enum c6x_builtins
6341{
6342 C6X_BUILTIN_SADD,
6343 C6X_BUILTIN_SSUB,
6344 C6X_BUILTIN_ADD2,
6345 C6X_BUILTIN_SUB2,
6346 C6X_BUILTIN_ADD4,
6347 C6X_BUILTIN_SUB4,
6348 C6X_BUILTIN_SADD2,
6349 C6X_BUILTIN_SSUB2,
6350 C6X_BUILTIN_SADDU4,
6351
6352 C6X_BUILTIN_SMPY,
6353 C6X_BUILTIN_SMPYH,
6354 C6X_BUILTIN_SMPYHL,
6355 C6X_BUILTIN_SMPYLH,
6356 C6X_BUILTIN_MPY2,
6357 C6X_BUILTIN_SMPY2,
6358
6359 C6X_BUILTIN_CLRR,
6360 C6X_BUILTIN_EXTR,
6361 C6X_BUILTIN_EXTRU,
6362
6363 C6X_BUILTIN_SSHL,
6364 C6X_BUILTIN_SUBC,
6365 C6X_BUILTIN_ABS,
6366 C6X_BUILTIN_ABS2,
6367 C6X_BUILTIN_AVG2,
6368 C6X_BUILTIN_AVGU4,
6369
6370 C6X_BUILTIN_MAX
6371};
6372
6373
6374static GTY(()) tree c6x_builtin_decls[C6X_BUILTIN_MAX];
6375
6376/* Return the C6X builtin for CODE. */
6377static tree
6378c6x_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
6379{
6380 if (code >= C6X_BUILTIN_MAX)
6381 return error_mark_node;
6382
6383 return c6x_builtin_decls[code];
6384}
6385
6386#define def_builtin(NAME, TYPE, CODE) \
6387do { \
6388 tree bdecl; \
6389 bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
6390 NULL, NULL_TREE); \
6391 c6x_builtin_decls[CODE] = bdecl; \
6392} while (0)
6393
6394/* Set up all builtin functions for this target. */
6395static void
6396c6x_init_builtins (void)
6397{
6398 tree V4QI_type_node = build_vector_type (unsigned_intQI_type_node, 4);
6399 tree V2HI_type_node = build_vector_type (intHI_type_node, 2);
6400 tree V2SI_type_node = build_vector_type (intSI_type_node, 2);
6401 tree int_ftype_int
6402 = build_function_type_list (integer_type_node, integer_type_node,
6403 NULL_TREE);
6404 tree int_ftype_int_int
6405 = build_function_type_list (integer_type_node, integer_type_node,
6406 integer_type_node, NULL_TREE);
6407 tree v2hi_ftype_v2hi
6408 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
6409 tree v4qi_ftype_v4qi_v4qi
6410 = build_function_type_list (V4QI_type_node, V4QI_type_node,
6411 V4QI_type_node, NULL_TREE);
6412 tree v2hi_ftype_v2hi_v2hi
6413 = build_function_type_list (V2HI_type_node, V2HI_type_node,
6414 V2HI_type_node, NULL_TREE);
6415 tree v2si_ftype_v2hi_v2hi
6416 = build_function_type_list (V2SI_type_node, V2HI_type_node,
6417 V2HI_type_node, NULL_TREE);
6418
6419 def_builtin ("__builtin_c6x_sadd", int_ftype_int_int,
6420 C6X_BUILTIN_SADD);
6421 def_builtin ("__builtin_c6x_ssub", int_ftype_int_int,
6422 C6X_BUILTIN_SSUB);
6423 def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi,
6424 C6X_BUILTIN_ADD2);
6425 def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi,
6426 C6X_BUILTIN_SUB2);
6427 def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi,
6428 C6X_BUILTIN_ADD4);
6429 def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi,
6430 C6X_BUILTIN_SUB4);
6431 def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi,
6432 C6X_BUILTIN_MPY2);
6433 def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi,
6434 C6X_BUILTIN_SADD2);
6435 def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi,
6436 C6X_BUILTIN_SSUB2);
6437 def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi,
6438 C6X_BUILTIN_SADDU4);
6439 def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi,
6440 C6X_BUILTIN_SMPY2);
6441
6442 def_builtin ("__builtin_c6x_smpy", int_ftype_int_int,
6443 C6X_BUILTIN_SMPY);
6444 def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int,
6445 C6X_BUILTIN_SMPYH);
6446 def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int,
6447 C6X_BUILTIN_SMPYHL);
6448 def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int,
6449 C6X_BUILTIN_SMPYLH);
6450
6451 def_builtin ("__builtin_c6x_sshl", int_ftype_int_int,
6452 C6X_BUILTIN_SSHL);
6453 def_builtin ("__builtin_c6x_subc", int_ftype_int_int,
6454 C6X_BUILTIN_SUBC);
6455
6456 def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi,
6457 C6X_BUILTIN_AVG2);
6458 def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi,
6459 C6X_BUILTIN_AVGU4);
6460
6461 def_builtin ("__builtin_c6x_clrr", int_ftype_int_int,
6462 C6X_BUILTIN_CLRR);
6463 def_builtin ("__builtin_c6x_extr", int_ftype_int_int,
6464 C6X_BUILTIN_EXTR);
6465 def_builtin ("__builtin_c6x_extru", int_ftype_int_int,
6466 C6X_BUILTIN_EXTRU);
6467
6468 def_builtin ("__builtin_c6x_abs", int_ftype_int, C6X_BUILTIN_ABS);
6469 def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi, C6X_BUILTIN_ABS2);
6470}
6471
6472
6473struct builtin_description
6474{
6475 const enum insn_code icode;
6476 const char *const name;
6477 const enum c6x_builtins code;
6478};
6479
6480static const struct builtin_description bdesc_2arg[] =
6481{
6482 { CODE_FOR_saddsi3, "__builtin_c6x_sadd", C6X_BUILTIN_SADD },
6483 { CODE_FOR_ssubsi3, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB },
6484 { CODE_FOR_addv2hi3, "__builtin_c6x_add2", C6X_BUILTIN_ADD2 },
6485 { CODE_FOR_subv2hi3, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2 },
6486 { CODE_FOR_addv4qi3, "__builtin_c6x_add4", C6X_BUILTIN_ADD4 },
6487 { CODE_FOR_subv4qi3, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4 },
6488 { CODE_FOR_ss_addv2hi3, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2 },
6489 { CODE_FOR_ss_subv2hi3, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2 },
6490 { CODE_FOR_us_addv4qi3, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4 },
6491
6492 { CODE_FOR_subcsi3, "__builtin_c6x_subc", C6X_BUILTIN_SUBC },
6493 { CODE_FOR_ss_ashlsi3, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL },
6494
6495 { CODE_FOR_avgv2hi3, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2 },
6496 { CODE_FOR_uavgv4qi3, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4 },
6497
6498 { CODE_FOR_mulhqsq3, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY },
6499 { CODE_FOR_mulhqsq3_hh, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH },
6500 { CODE_FOR_mulhqsq3_lh, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH },
6501 { CODE_FOR_mulhqsq3_hl, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL },
6502
6503 { CODE_FOR_mulv2hqv2sq3, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2 },
6504
6505 { CODE_FOR_clrr, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR },
6506 { CODE_FOR_extr, "__builtin_c6x_extr", C6X_BUILTIN_EXTR },
6507 { CODE_FOR_extru, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU }
6508};
6509
6510static const struct builtin_description bdesc_1arg[] =
6511{
6512 { CODE_FOR_ssabssi2, "__builtin_c6x_abs", C6X_BUILTIN_ABS },
6513 { CODE_FOR_ssabsv2hi2, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2 }
6514};
6515
6516/* Errors in the source file can cause expand_expr to return const0_rtx
6517 where we expect a vector. To avoid crashing, use one of the vector
6518 clear instructions. */
6519static rtx
6520safe_vector_operand (rtx x, enum machine_mode mode)
6521{
6522 if (x != const0_rtx)
6523 return x;
6524 x = gen_reg_rtx (SImode);
6525
6526 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
6527 return gen_lowpart (mode, x);
6528}
6529
6530/* Subroutine of c6x_expand_builtin to take care of binop insns. MACFLAG is -1
6531 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6532
6533static rtx
6534c6x_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
6535 bool match_op)
6536{
6537 int offs = match_op ? 1 : 0;
6538 rtx pat;
6539 tree arg0 = CALL_EXPR_ARG (exp, 0);
6540 tree arg1 = CALL_EXPR_ARG (exp, 1);
6541 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6542 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6543 enum machine_mode op0mode = GET_MODE (op0);
6544 enum machine_mode op1mode = GET_MODE (op1);
6545 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6546 enum machine_mode mode0 = insn_data[icode].operand[1 + offs].mode;
6547 enum machine_mode mode1 = insn_data[icode].operand[2 + offs].mode;
6548 rtx ret = target;
6549
6550 if (VECTOR_MODE_P (mode0))
6551 op0 = safe_vector_operand (op0, mode0);
6552 if (VECTOR_MODE_P (mode1))
6553 op1 = safe_vector_operand (op1, mode1);
6554
6555 if (! target
6556 || GET_MODE (target) != tmode
6557 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6558 {
6559 if (tmode == SQmode || tmode == V2SQmode)
6560 {
6561 ret = gen_reg_rtx (tmode == SQmode ? SImode : V2SImode);
6562 target = gen_lowpart (tmode, ret);
6563 }
6564 else
6565 target = gen_reg_rtx (tmode);
6566 }
6567
6568 if ((op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode)
6569 && (mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode))
6570 {
6571 op0mode = mode0;
6572 op0 = gen_lowpart (mode0, op0);
6573 }
6574 if ((op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode)
6575 && (mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode))
6576 {
6577 op1mode = mode1;
6578 op1 = gen_lowpart (mode1, op1);
6579 }
6580 /* In case the insn wants input operands in modes different from
6581 the result, abort. */
6582 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
6583 && (op1mode == mode1 || op1mode == VOIDmode));
6584
6585 if (! (*insn_data[icode].operand[1 + offs].predicate) (op0, mode0))
6586 op0 = copy_to_mode_reg (mode0, op0);
6587 if (! (*insn_data[icode].operand[2 + offs].predicate) (op1, mode1))
6588 op1 = copy_to_mode_reg (mode1, op1);
6589
6590 if (match_op)
6591 pat = GEN_FCN (icode) (target, target, op0, op1);
6592 else
6593 pat = GEN_FCN (icode) (target, op0, op1);
6594
6595 if (! pat)
6596 return 0;
6597
6598 emit_insn (pat);
6599
6600 return ret;
6601}
6602
6603/* Subroutine of c6x_expand_builtin to take care of unop insns. */
6604
6605static rtx
6606c6x_expand_unop_builtin (enum insn_code icode, tree exp,
6607 rtx target)
6608{
6609 rtx pat;
6610 tree arg0 = CALL_EXPR_ARG (exp, 0);
6611 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
6612 enum machine_mode op0mode = GET_MODE (op0);
6613 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6614 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6615
6616 if (! target
6617 || GET_MODE (target) != tmode
6618 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6619 target = gen_reg_rtx (tmode);
6620
6621 if (VECTOR_MODE_P (mode0))
6622 op0 = safe_vector_operand (op0, mode0);
6623
6624 if (op0mode == SImode && mode0 == HImode)
6625 {
6626 op0mode = HImode;
6627 op0 = gen_lowpart (HImode, op0);
6628 }
6629 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
6630
6631 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6632 op0 = copy_to_mode_reg (mode0, op0);
6633
6634 pat = GEN_FCN (icode) (target, op0);
6635 if (! pat)
6636 return 0;
6637 emit_insn (pat);
6638 return target;
6639}
6640
6641/* Expand an expression EXP that calls a built-in function,
6642 with result going to TARGET if that's convenient
6643 (and in mode MODE if that's convenient).
6644 SUBTARGET may be used as the target for computing one of EXP's operands.
6645 IGNORE is nonzero if the value is to be ignored. */
6646
6647static rtx
6648c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6649 rtx subtarget ATTRIBUTE_UNUSED,
6650 enum machine_mode mode ATTRIBUTE_UNUSED,
6651 int ignore ATTRIBUTE_UNUSED)
6652{
6653 size_t i;
6654 const struct builtin_description *d;
6655 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6656 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6657
6658 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6659 if (d->code == fcode)
6660 return c6x_expand_binop_builtin (d->icode, exp, target,
6661 fcode == C6X_BUILTIN_CLRR);
6662
6663 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6664 if (d->code == fcode)
6665 return c6x_expand_unop_builtin (d->icode, exp, target);
6666
6667 gcc_unreachable ();
6668}
1e874273
PB
6669
6670/* Target unwind frame info is generated from dwarf CFI directives, so
6671 always output dwarf2 unwind info. */
6672
6673static enum unwind_info_type
6674c6x_debug_unwind_info (void)
6675{
6676 if (flag_unwind_tables || flag_exceptions)
6677 return UI_DWARF2;
6678
6679 return default_debug_unwind_info ();
6680}
bcead286
BS
6681\f
6682/* Target Structure. */
6683
6684/* Initialize the GCC target structure. */
6685#undef TARGET_FUNCTION_ARG
6686#define TARGET_FUNCTION_ARG c6x_function_arg
6687#undef TARGET_FUNCTION_ARG_ADVANCE
6688#define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
6689#undef TARGET_FUNCTION_ARG_BOUNDARY
6690#define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
6691#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
6692#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
6693 c6x_function_arg_round_boundary
6694#undef TARGET_FUNCTION_VALUE_REGNO_P
6695#define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
6696#undef TARGET_FUNCTION_VALUE
6697#define TARGET_FUNCTION_VALUE c6x_function_value
6698#undef TARGET_LIBCALL_VALUE
6699#define TARGET_LIBCALL_VALUE c6x_libcall_value
6700#undef TARGET_RETURN_IN_MEMORY
6701#define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
6702#undef TARGET_RETURN_IN_MSB
6703#define TARGET_RETURN_IN_MSB c6x_return_in_msb
6704#undef TARGET_PASS_BY_REFERENCE
6705#define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
6706#undef TARGET_CALLEE_COPIES
6707#define TARGET_CALLEE_COPIES c6x_callee_copies
6708#undef TARGET_STRUCT_VALUE_RTX
6709#define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
6710#undef TARGET_FUNCTION_OK_FOR_SIBCALL
6711#define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
6712
6713#undef TARGET_ASM_OUTPUT_MI_THUNK
6714#define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
6715#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6716#define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
6717
6718#undef TARGET_BUILD_BUILTIN_VA_LIST
6719#define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
6720
6721#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6722#define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
6723#undef TARGET_TRAMPOLINE_INIT
6724#define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
6725
6726#undef TARGET_LEGITIMATE_CONSTANT_P
6727#define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
6728#undef TARGET_LEGITIMATE_ADDRESS_P
6729#define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
6730
6731#undef TARGET_IN_SMALL_DATA_P
6732#define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
6733#undef TARGET_ASM_SELECT_RTX_SECTION
6734#define TARGET_ASM_SELECT_RTX_SECTION c6x_select_rtx_section
6735#undef TARGET_ASM_SELECT_SECTION
6736#define TARGET_ASM_SELECT_SECTION c6x_elf_select_section
6737#undef TARGET_ASM_UNIQUE_SECTION
6738#define TARGET_ASM_UNIQUE_SECTION c6x_elf_unique_section
6739#undef TARGET_SECTION_TYPE_FLAGS
6740#define TARGET_SECTION_TYPE_FLAGS c6x_section_type_flags
6741#undef TARGET_HAVE_SRODATA_SECTION
6742#define TARGET_HAVE_SRODATA_SECTION true
6743#undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
6744#define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
6745
6746#undef TARGET_OPTION_OVERRIDE
6747#define TARGET_OPTION_OVERRIDE c6x_option_override
6748#undef TARGET_CONDITIONAL_REGISTER_USAGE
6749#define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
6750
6751#undef TARGET_INIT_LIBFUNCS
6752#define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
6753#undef TARGET_LIBFUNC_GNU_PREFIX
6754#define TARGET_LIBFUNC_GNU_PREFIX true
6755
6756#undef TARGET_SCALAR_MODE_SUPPORTED_P
6757#define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
6758#undef TARGET_VECTOR_MODE_SUPPORTED_P
6759#define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
6760#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
6761#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
6762
6763#undef TARGET_RTX_COSTS
6764#define TARGET_RTX_COSTS c6x_rtx_costs
6765
6766#undef TARGET_SCHED_INIT
6767#define TARGET_SCHED_INIT c6x_sched_init
6768#undef TARGET_SCHED_SET_SCHED_FLAGS
6769#define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
6770#undef TARGET_SCHED_ADJUST_COST
6771#define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
6772#undef TARGET_SCHED_ISSUE_RATE
6773#define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
6774#undef TARGET_SCHED_VARIABLE_ISSUE
6775#define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
6776#undef TARGET_SCHED_REORDER
6777#define TARGET_SCHED_REORDER c6x_sched_reorder
6778#undef TARGET_SCHED_REORDER2
6779#define TARGET_SCHED_REORDER2 c6x_sched_reorder2
6bd9bf42
BS
6780#undef TARGET_SCHED_DFA_NEW_CYCLE
6781#define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
6782#undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
6783#define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
bcead286
BS
6784#undef TARGET_SCHED_EXPOSED_PIPELINE
6785#define TARGET_SCHED_EXPOSED_PIPELINE true
6786
6787#undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
6788#define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
6789#undef TARGET_SCHED_INIT_SCHED_CONTEXT
6790#define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
6791#undef TARGET_SCHED_SET_SCHED_CONTEXT
6792#define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
6bd9bf42
BS
6793#undef TARGET_SCHED_CLEAR_SCHED_CONTEXT
6794#define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_sched_context
bcead286
BS
6795#undef TARGET_SCHED_FREE_SCHED_CONTEXT
6796#define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
6797
6798#undef TARGET_CAN_ELIMINATE
6799#define TARGET_CAN_ELIMINATE c6x_can_eliminate
6800
6801#undef TARGET_PREFERRED_RENAME_CLASS
6802#define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
6803
6804#undef TARGET_MACHINE_DEPENDENT_REORG
6805#define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
6806
6807#undef TARGET_ASM_FILE_START
6808#define TARGET_ASM_FILE_START c6x_file_start
6809
6810#undef TARGET_PRINT_OPERAND
6811#define TARGET_PRINT_OPERAND c6x_print_operand
6812#undef TARGET_PRINT_OPERAND_ADDRESS
6813#define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
6814#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
6815#define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
6816
6817/* C6x unwinding tables use a different format for the typeinfo tables. */
6818#undef TARGET_ASM_TTYPE
6819#define TARGET_ASM_TTYPE c6x_output_ttype
6820
1e874273
PB
6821/* The C6x ABI follows the ARM EABI exception handling rules. */
6822#undef TARGET_ARM_EABI_UNWINDER
6823#define TARGET_ARM_EABI_UNWINDER true
6824
74b388c3
PB
6825#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
6826#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
6827
6828#undef TARGET_ASM_INIT_SECTIONS
6829#define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
6830
1e874273
PB
6831#undef TARGET_DEBUG_UNWIND_INFO
6832#define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
6833
bcead286
BS
6834#undef TARGET_DWARF_REGISTER_SPAN
6835#define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
6836
6837#undef TARGET_INIT_BUILTINS
6838#define TARGET_INIT_BUILTINS c6x_init_builtins
6839#undef TARGET_EXPAND_BUILTIN
6840#define TARGET_EXPAND_BUILTIN c6x_expand_builtin
6841#undef TARGET_BUILTIN_DECL
6842#define TARGET_BUILTIN_DECL c6x_builtin_decl
6843
6844struct gcc_target targetm = TARGET_INITIALIZER;
6845
6846#include "gt-c6x.h"