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