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