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