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