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