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