1 /* Subroutines used for code generation on the Tilera TILEPro. 2 Copyright (C) 2011-2017 Free Software Foundation, Inc. 3 Contributed by Walter Lee (walt@tilera.com) 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published 9 by the Free Software Foundation; either version 3, or (at your 10 option) any later version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "backend.h" 25 #include "target.h" 26 #include "rtl.h" 27 #include "tree.h" 28 #include "gimple.h" 29 #include "df.h" 30 #include "memmodel.h" 31 #include "tm_p.h" 32 #include "stringpool.h" 33 #include "expmed.h" 34 #include "optabs.h" 35 #include "regs.h" 36 #include "emit-rtl.h" 37 #include "recog.h" 38 #include "diagnostic.h" 39 #include "output.h" 40 #include "insn-attr.h" 41 #include "alias.h" 42 #include "explow.h" 43 #include "calls.h" 44 #include "varasm.h" 45 #include "expr.h" 46 #include "langhooks.h" 47 #include "cfgrtl.h" 48 #include "tm-constrs.h" 49 #include "dwarf2.h" 50 #include "fold-const.h" 51 #include "stor-layout.h" 52 #include "gimplify.h" 53 #include "tilepro-builtins.h" 54 #include "tilepro-multiply.h" 55 #include "builtins.h" 56 57 /* This file should be included last. */ 58 #include "target-def.h" 59 60 /* SYMBOL_REF for GOT */ 61 static GTY(()) rtx g_got_symbol = NULL; 62 63 /* Report whether we're printing out the first address fragment of a 64 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to 65 TARGET_PRINT_OPERAND_ADDRESS. */ 66 static bool output_memory_autoinc_first; 67 68 69 70 /* Option handling */ 71 72 /* Implement TARGET_OPTION_OVERRIDE. */ 73 static void 74 tilepro_option_override (void) 75 { 76 /* When modulo scheduling is enabled, we still rely on regular 77 scheduler for bundling. */ 78 if (flag_modulo_sched) 79 flag_resched_modulo_sched = 1; 80 } 81 82 83 84 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */ 85 static bool 86 tilepro_scalar_mode_supported_p (machine_mode mode) 87 { 88 switch (mode) 89 { 90 case QImode: 91 case HImode: 92 case SImode: 93 case DImode: 94 return true; 95 96 case SFmode: 97 case DFmode: 98 return true; 99 100 default: 101 return false; 102 } 103 } 104 105 106 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */ 107 static bool 108 tile_vector_mode_supported_p (machine_mode mode) 109 { 110 return mode == V4QImode || mode == V2HImode; 111 } 112 113 114 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */ 115 static bool 116 tilepro_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, 117 rtx x ATTRIBUTE_UNUSED) 118 { 119 return true; 120 } 121 122 123 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ 124 static bool 125 tilepro_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) 126 { 127 return decl != NULL; 128 } 129 130 131 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are 132 passed by reference. */ 133 static bool 134 tilepro_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, 135 machine_mode mode ATTRIBUTE_UNUSED, 136 const_tree type, bool named ATTRIBUTE_UNUSED) 137 { 138 return (type && TYPE_SIZE (type) 139 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST); 140 } 141 142 143 /* Implement TARGET_RETURN_IN_MEMORY. */ 144 static bool 145 tilepro_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) 146 { 147 return !IN_RANGE (int_size_in_bytes (type), 148 0, TILEPRO_NUM_RETURN_REGS * UNITS_PER_WORD); 149 } 150 151 152 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */ 153 static unsigned int 154 tilepro_function_arg_boundary (machine_mode mode, const_tree type) 155 { 156 unsigned int alignment; 157 158 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode); 159 if (alignment < PARM_BOUNDARY) 160 alignment = PARM_BOUNDARY; 161 if (alignment > STACK_BOUNDARY) 162 alignment = STACK_BOUNDARY; 163 return alignment; 164 } 165 166 167 /* Implement TARGET_FUNCTION_ARG. */ 168 static rtx 169 tilepro_function_arg (cumulative_args_t cum_v, 170 machine_mode mode, 171 const_tree type, bool named ATTRIBUTE_UNUSED) 172 { 173 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v); 174 int byte_size = ((mode == BLKmode) 175 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 176 bool doubleword_aligned_p; 177 178 if (cum >= TILEPRO_NUM_ARG_REGS) 179 return NULL_RTX; 180 181 /* See whether the argument has doubleword alignment. */ 182 doubleword_aligned_p = 183 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD; 184 185 if (doubleword_aligned_p) 186 cum += cum & 1; 187 188 /* The ABI does not allow parameters to be passed partially in reg 189 and partially in stack. */ 190 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) 191 > TILEPRO_NUM_ARG_REGS) 192 return NULL_RTX; 193 194 return gen_rtx_REG (mode, cum); 195 } 196 197 198 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */ 199 static void 200 tilepro_function_arg_advance (cumulative_args_t cum_v, 201 machine_mode mode, 202 const_tree type, bool named ATTRIBUTE_UNUSED) 203 { 204 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 205 206 int byte_size = ((mode == BLKmode) 207 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 208 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 209 bool doubleword_aligned_p; 210 211 /* See whether the argument has doubleword alignment. */ 212 doubleword_aligned_p = 213 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD; 214 215 if (doubleword_aligned_p) 216 *cum += *cum & 1; 217 218 /* If the current argument does not fit in the pretend_args space, 219 skip over it. */ 220 if (*cum < TILEPRO_NUM_ARG_REGS 221 && *cum + word_size > TILEPRO_NUM_ARG_REGS) 222 *cum = TILEPRO_NUM_ARG_REGS; 223 224 *cum += word_size; 225 } 226 227 228 /* Implement TARGET_FUNCTION_VALUE. */ 229 static rtx 230 tilepro_function_value (const_tree valtype, const_tree fn_decl_or_type, 231 bool outgoing ATTRIBUTE_UNUSED) 232 { 233 machine_mode mode; 234 int unsigned_p; 235 236 mode = TYPE_MODE (valtype); 237 unsigned_p = TYPE_UNSIGNED (valtype); 238 239 mode = promote_function_mode (valtype, mode, &unsigned_p, 240 fn_decl_or_type, 1); 241 242 return gen_rtx_REG (mode, 0); 243 } 244 245 246 /* Implement TARGET_LIBCALL_VALUE. */ 247 static rtx 248 tilepro_libcall_value (machine_mode mode, 249 const_rtx fun ATTRIBUTE_UNUSED) 250 { 251 return gen_rtx_REG (mode, 0); 252 } 253 254 255 /* Implement FUNCTION_VALUE_REGNO_P. */ 256 static bool 257 tilepro_function_value_regno_p (const unsigned int regno) 258 { 259 return regno < TILEPRO_NUM_RETURN_REGS; 260 } 261 262 263 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */ 264 static tree 265 tilepro_build_builtin_va_list (void) 266 { 267 tree f_args, f_skip, record, type_decl; 268 bool owp; 269 270 record = lang_hooks.types.make_type (RECORD_TYPE); 271 272 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL, 273 get_identifier ("__va_list_tag"), record); 274 275 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL, 276 get_identifier ("__args"), ptr_type_node); 277 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL, 278 get_identifier ("__skip"), ptr_type_node); 279 280 DECL_FIELD_CONTEXT (f_args) = record; 281 282 DECL_FIELD_CONTEXT (f_skip) = record; 283 284 TREE_CHAIN (record) = type_decl; 285 TYPE_NAME (record) = type_decl; 286 TYPE_FIELDS (record) = f_args; 287 TREE_CHAIN (f_args) = f_skip; 288 289 /* We know this is being padded and we want it too. It is an 290 internal type so hide the warnings from the user. */ 291 owp = warn_padded; 292 warn_padded = false; 293 294 layout_type (record); 295 296 warn_padded = owp; 297 298 /* The correct type is an array type of one element. */ 299 return record; 300 } 301 302 303 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */ 304 static void 305 tilepro_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) 306 { 307 tree f_args, f_skip; 308 tree args, skip, t; 309 310 f_args = TYPE_FIELDS (TREE_TYPE (valist)); 311 f_skip = TREE_CHAIN (f_args); 312 313 args = 314 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); 315 skip = 316 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); 317 318 /* Find the __args area. */ 319 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx); 320 t = fold_build_pointer_plus_hwi (t, 321 UNITS_PER_WORD * 322 (crtl->args.info - TILEPRO_NUM_ARG_REGS)); 323 324 if (crtl->args.pretend_args_size > 0) 325 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); 326 327 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t); 328 TREE_SIDE_EFFECTS (t) = 1; 329 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 330 331 /* Find the __skip area. */ 332 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx); 333 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); 334 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t); 335 TREE_SIDE_EFFECTS (t) = 1; 336 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 337 } 338 339 340 /* Implement TARGET_SETUP_INCOMING_VARARGS. */ 341 static void 342 tilepro_setup_incoming_varargs (cumulative_args_t cum, 343 machine_mode mode, 344 tree type, int *pretend_args, int no_rtl) 345 { 346 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum); 347 int first_reg; 348 349 /* The caller has advanced CUM up to, but not beyond, the last named 350 argument. Advance a local copy of CUM past the last "real" named 351 argument, to find out how many registers are left over. */ 352 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum), 353 mode, type, true); 354 first_reg = local_cum; 355 356 if (local_cum < TILEPRO_NUM_ARG_REGS) 357 { 358 *pretend_args = UNITS_PER_WORD * (TILEPRO_NUM_ARG_REGS - first_reg); 359 360 if (!no_rtl) 361 { 362 alias_set_type set = get_varargs_alias_set (); 363 rtx tmp = 364 gen_rtx_MEM (BLKmode, plus_constant (Pmode, \ 365 virtual_incoming_args_rtx, 366 -STACK_POINTER_OFFSET - 367 UNITS_PER_WORD * 368 (TILEPRO_NUM_ARG_REGS - 369 first_reg))); 370 MEM_NOTRAP_P (tmp) = 1; 371 set_mem_alias_set (tmp, set); 372 move_block_from_reg (first_reg, tmp, 373 TILEPRO_NUM_ARG_REGS - first_reg); 374 } 375 } 376 else 377 *pretend_args = 0; 378 } 379 380 381 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating 382 the va_list structure VALIST as required to retrieve an argument of 383 type TYPE, and returning that argument. 384 385 ret = va_arg(VALIST, TYPE); 386 387 generates code equivalent to: 388 389 paddedsize = (sizeof(TYPE) + 3) & -4; 390 if ((VALIST.__args + paddedsize > VALIST.__skip) 391 & (VALIST.__args <= VALIST.__skip)) 392 addr = VALIST.__skip + STACK_POINTER_OFFSET; 393 else 394 addr = VALIST.__args; 395 VALIST.__args = addr + paddedsize; 396 ret = *(TYPE *)addr; */ 397 static tree 398 tilepro_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p, 399 gimple_seq * post_p ATTRIBUTE_UNUSED) 400 { 401 tree f_args, f_skip; 402 tree args, skip; 403 HOST_WIDE_INT size, rsize; 404 tree addr, tmp; 405 bool pass_by_reference_p; 406 407 f_args = TYPE_FIELDS (va_list_type_node); 408 f_skip = TREE_CHAIN (f_args); 409 410 args = 411 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); 412 skip = 413 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); 414 415 addr = create_tmp_var (ptr_type_node, "va_arg"); 416 417 /* if an object is dynamically sized, a pointer to it is passed 418 instead of the object itself. */ 419 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type, 420 false); 421 422 if (pass_by_reference_p) 423 type = build_pointer_type (type); 424 425 size = int_size_in_bytes (type); 426 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD; 427 428 /* If the alignment of the type is greater than the default for a 429 parameter, align to STACK_BOUNDARY. */ 430 if (TYPE_ALIGN (type) > PARM_BOUNDARY) 431 { 432 /* Assert the only case we generate code for: when 433 stack boundary = 2 * parm boundary. */ 434 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2); 435 436 tmp = build2 (BIT_AND_EXPR, sizetype, 437 fold_convert (sizetype, unshare_expr (args)), 438 size_int (PARM_BOUNDARY / 8)); 439 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, 440 unshare_expr (args), tmp); 441 442 gimplify_assign (unshare_expr (args), tmp, pre_p); 443 } 444 445 /* Build conditional expression to calculate addr. The expression 446 will be gimplified later. */ 447 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize); 448 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node, 449 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)), 450 build2 (LE_EXPR, boolean_type_node, unshare_expr (args), 451 unshare_expr (skip))); 452 453 tmp = build3 (COND_EXPR, ptr_type_node, tmp, 454 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip), 455 size_int (STACK_POINTER_OFFSET)), 456 unshare_expr (args)); 457 458 gimplify_assign (addr, tmp, pre_p); 459 460 /* Update VALIST.__args. */ 461 tmp = fold_build_pointer_plus_hwi (addr, rsize); 462 gimplify_assign (unshare_expr (args), tmp, pre_p); 463 464 addr = fold_convert (build_pointer_type (type), addr); 465 466 if (pass_by_reference_p) 467 addr = build_va_arg_indirect_ref (addr); 468 469 return build_va_arg_indirect_ref (addr); 470 } 471 472 473 474 /* Implement TARGET_RTX_COSTS. */ 475 static bool 476 tilepro_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno, 477 int *total, bool speed) 478 { 479 int code = GET_CODE (x); 480 481 switch (code) 482 { 483 case CONST_INT: 484 /* If this is an 8-bit constant, return zero since it can be 485 used nearly anywhere with no cost. If it is a valid operand 486 for an ADD or AND, likewise return 0 if we know it will be 487 used in that context. Otherwise, return 2 since it might be 488 used there later. All other constants take at least two 489 insns. */ 490 if (satisfies_constraint_I (x)) 491 { 492 *total = 0; 493 return true; 494 } 495 else if (outer_code == PLUS && add_operand (x, VOIDmode)) 496 { 497 /* Slightly penalize large constants even though we can add 498 them in one instruction, because it forces the use of 499 2-wide bundling mode. */ 500 *total = 1; 501 return true; 502 } 503 else if (move_operand (x, SImode)) 504 { 505 /* We can materialize in one move. */ 506 *total = COSTS_N_INSNS (1); 507 return true; 508 } 509 else 510 { 511 /* We can materialize in two moves. */ 512 *total = COSTS_N_INSNS (2); 513 return true; 514 } 515 516 return false; 517 518 case CONST: 519 case LABEL_REF: 520 case SYMBOL_REF: 521 *total = COSTS_N_INSNS (2); 522 return true; 523 524 case CONST_DOUBLE: 525 *total = COSTS_N_INSNS (4); 526 return true; 527 528 case HIGH: 529 *total = 0; 530 return true; 531 532 case MEM: 533 /* If outer-code was a sign or zero extension, a cost of 534 COSTS_N_INSNS (1) was already added in, so account for 535 that. */ 536 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND) 537 *total = COSTS_N_INSNS (1); 538 else 539 *total = COSTS_N_INSNS (2); 540 return true; 541 542 case PLUS: 543 /* Convey that s[123]a are efficient. */ 544 if (GET_CODE (XEXP (x, 0)) == MULT 545 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode)) 546 { 547 *total = (rtx_cost (XEXP (XEXP (x, 0), 0), mode, 548 (enum rtx_code) outer_code, opno, speed) 549 + rtx_cost (XEXP (x, 1), mode, 550 (enum rtx_code) outer_code, opno, speed) 551 + COSTS_N_INSNS (1)); 552 return true; 553 } 554 return false; 555 556 case MULT: 557 *total = COSTS_N_INSNS (2); 558 return false; 559 560 case SIGN_EXTEND: 561 case ZERO_EXTEND: 562 if (outer_code == MULT) 563 *total = 0; 564 else 565 *total = COSTS_N_INSNS (1); 566 return false; 567 568 case DIV: 569 case UDIV: 570 case MOD: 571 case UMOD: 572 /* These are handled by software and are very expensive. */ 573 *total = COSTS_N_INSNS (100); 574 return false; 575 576 case UNSPEC: 577 case UNSPEC_VOLATILE: 578 { 579 int num = XINT (x, 1); 580 581 if (num <= TILEPRO_LAST_LATENCY_1_INSN) 582 *total = COSTS_N_INSNS (1); 583 else if (num <= TILEPRO_LAST_LATENCY_2_INSN) 584 *total = COSTS_N_INSNS (2); 585 else if (num > TILEPRO_LAST_LATENCY_INSN) 586 { 587 if (outer_code == PLUS) 588 *total = 0; 589 else 590 *total = COSTS_N_INSNS (1); 591 } 592 else 593 { 594 switch (num) 595 { 596 case UNSPEC_BLOCKAGE: 597 case UNSPEC_NETWORK_BARRIER: 598 *total = 0; 599 break; 600 601 case UNSPEC_LNK_AND_LABEL: 602 case UNSPEC_MF: 603 case UNSPEC_NETWORK_RECEIVE: 604 case UNSPEC_NETWORK_SEND: 605 case UNSPEC_TLS_GD_ADD: 606 *total = COSTS_N_INSNS (1); 607 break; 608 609 case UNSPEC_TLS_IE_LOAD: 610 *total = COSTS_N_INSNS (2); 611 break; 612 613 case UNSPEC_SP_SET: 614 *total = COSTS_N_INSNS (3); 615 break; 616 617 case UNSPEC_SP_TEST: 618 *total = COSTS_N_INSNS (4); 619 break; 620 621 case UNSPEC_LATENCY_L2: 622 *total = COSTS_N_INSNS (8); 623 break; 624 625 case UNSPEC_TLS_GD_CALL: 626 *total = COSTS_N_INSNS (30); 627 break; 628 629 case UNSPEC_LATENCY_MISS: 630 *total = COSTS_N_INSNS (80); 631 break; 632 633 default: 634 *total = COSTS_N_INSNS (1); 635 } 636 } 637 return true; 638 } 639 640 default: 641 return false; 642 } 643 } 644 645 646 647 /* Returns an SImode integer rtx with value VAL. */ 648 static rtx 649 gen_int_si (HOST_WIDE_INT val) 650 { 651 return gen_int_mode (val, SImode); 652 } 653 654 655 /* Create a temporary variable to hold a partial result, to enable 656 CSE. */ 657 static rtx 658 create_temp_reg_if_possible (machine_mode mode, rtx default_reg) 659 { 660 return can_create_pseudo_p ()? gen_reg_rtx (mode) : default_reg; 661 } 662 663 664 /* Functions to save and restore machine-specific function data. */ 665 static struct machine_function * 666 tilepro_init_machine_status (void) 667 { 668 return ggc_cleared_alloc<machine_function> (); 669 } 670 671 672 /* Do anything needed before RTL is emitted for each function. */ 673 void 674 tilepro_init_expanders (void) 675 { 676 /* Arrange to initialize and mark the machine per-function 677 status. */ 678 init_machine_status = tilepro_init_machine_status; 679 680 if (cfun && cfun->machine && flag_pic) 681 { 682 static int label_num = 0; 683 684 char text_label_name[32]; 685 686 struct machine_function *machine = cfun->machine; 687 688 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++); 689 690 machine->text_label_symbol = 691 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name)); 692 693 machine->text_label_rtx = 694 gen_rtx_REG (Pmode, TILEPRO_PIC_TEXT_LABEL_REGNUM); 695 696 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); 697 698 machine->calls_tls_get_addr = false; 699 } 700 } 701 702 703 /* Return true if X contains a thread-local symbol. */ 704 static bool 705 tilepro_tls_referenced_p (rtx x) 706 { 707 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) 708 x = XEXP (XEXP (x, 0), 0); 709 710 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x)) 711 return true; 712 713 /* That's all we handle in tilepro_legitimize_tls_address for 714 now. */ 715 return false; 716 } 717 718 719 /* Return true if X requires a scratch register. It is given that 720 flag_pic is on and that X satisfies CONSTANT_P. */ 721 static int 722 tilepro_pic_address_needs_scratch (rtx x) 723 { 724 if (GET_CODE (x) == CONST 725 && GET_CODE (XEXP (x, 0)) == PLUS 726 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 727 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF) 728 && CONST_INT_P (XEXP (XEXP (x, 0), 1))) 729 return true; 730 731 return false; 732 } 733 734 735 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for 736 which we are willing to load the value into a register via a move 737 pattern. TLS cannot be treated as a constant because it can 738 include a function call. */ 739 static bool 740 tilepro_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) 741 { 742 switch (GET_CODE (x)) 743 { 744 case CONST: 745 case SYMBOL_REF: 746 return !tilepro_tls_referenced_p (x); 747 748 default: 749 return true; 750 } 751 } 752 753 754 /* Return true if the constant value X is a legitimate general operand 755 when generating PIC code. It is given that flag_pic is on and that 756 X satisfies CONSTANT_P. */ 757 bool 758 tilepro_legitimate_pic_operand_p (rtx x) 759 { 760 if (tilepro_pic_address_needs_scratch (x)) 761 return false; 762 763 if (tilepro_tls_referenced_p (x)) 764 return false; 765 766 return true; 767 } 768 769 770 /* Return true if the rtx X can be used as an address operand. */ 771 static bool 772 tilepro_legitimate_address_p (machine_mode ARG_UNUSED (mode), rtx x, 773 bool strict) 774 { 775 if (GET_CODE (x) == SUBREG) 776 x = SUBREG_REG (x); 777 778 switch (GET_CODE (x)) 779 { 780 case POST_INC: 781 case POST_DEC: 782 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) 783 return false; 784 785 x = XEXP (x, 0); 786 break; 787 788 case POST_MODIFY: 789 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) 790 return false; 791 792 if (GET_CODE (XEXP (x, 1)) != PLUS) 793 return false; 794 795 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0))) 796 return false; 797 798 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1))) 799 return false; 800 801 x = XEXP (x, 0); 802 break; 803 804 case REG: 805 break; 806 807 default: 808 return false; 809 } 810 811 /* Check if x is a valid reg. */ 812 if (!REG_P (x)) 813 return false; 814 815 if (strict) 816 return REGNO_OK_FOR_BASE_P (REGNO (x)); 817 else 818 return true; 819 } 820 821 822 /* Return the rtx containing SYMBOL_REF to the text label. */ 823 static rtx 824 tilepro_text_label_symbol (void) 825 { 826 return cfun->machine->text_label_symbol; 827 } 828 829 830 /* Return the register storing the value of the text label. */ 831 static rtx 832 tilepro_text_label_rtx (void) 833 { 834 return cfun->machine->text_label_rtx; 835 } 836 837 838 /* Return the register storing the value of the global offset 839 table. */ 840 static rtx 841 tilepro_got_rtx (void) 842 { 843 return cfun->machine->got_rtx; 844 } 845 846 847 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */ 848 static rtx 849 tilepro_got_symbol (void) 850 { 851 if (g_got_symbol == NULL) 852 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 853 854 return g_got_symbol; 855 } 856 857 858 /* Return a reference to the got to be used by tls references. */ 859 static rtx 860 tilepro_tls_got (void) 861 { 862 rtx temp; 863 if (flag_pic) 864 { 865 crtl->uses_pic_offset_table = 1; 866 return tilepro_got_rtx (); 867 } 868 869 temp = gen_reg_rtx (Pmode); 870 emit_move_insn (temp, tilepro_got_symbol ()); 871 872 return temp; 873 } 874 875 876 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute 877 this (thread-local) address. */ 878 static rtx 879 tilepro_legitimize_tls_address (rtx addr) 880 { 881 rtx ret; 882 883 gcc_assert (can_create_pseudo_p ()); 884 885 if (GET_CODE (addr) == SYMBOL_REF) 886 switch (SYMBOL_REF_TLS_MODEL (addr)) 887 { 888 case TLS_MODEL_GLOBAL_DYNAMIC: 889 case TLS_MODEL_LOCAL_DYNAMIC: 890 { 891 rtx r0, temp1, temp2, temp3, got; 892 rtx_insn *last; 893 894 ret = gen_reg_rtx (Pmode); 895 r0 = gen_rtx_REG (Pmode, 0); 896 temp1 = gen_reg_rtx (Pmode); 897 temp2 = gen_reg_rtx (Pmode); 898 temp3 = gen_reg_rtx (Pmode); 899 900 got = tilepro_tls_got (); 901 emit_insn (gen_tls_gd_addhi (temp1, got, addr)); 902 emit_insn (gen_tls_gd_addlo (temp2, temp1, addr)); 903 emit_move_insn (r0, temp2); 904 emit_insn (gen_tls_gd_call (addr)); 905 emit_move_insn (temp3, r0); 906 last = emit_insn (gen_tls_gd_add (ret, temp3, addr)); 907 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 908 break; 909 } 910 case TLS_MODEL_INITIAL_EXEC: 911 { 912 rtx temp1, temp2, temp3, got; 913 rtx_insn *last; 914 915 ret = gen_reg_rtx (Pmode); 916 temp1 = gen_reg_rtx (Pmode); 917 temp2 = gen_reg_rtx (Pmode); 918 temp3 = gen_reg_rtx (Pmode); 919 920 got = tilepro_tls_got (); 921 emit_insn (gen_tls_ie_addhi (temp1, got, addr)); 922 emit_insn (gen_tls_ie_addlo (temp2, temp1, addr)); 923 emit_insn (gen_tls_ie_load (temp3, temp2, addr)); 924 last = 925 emit_move_insn(ret, 926 gen_rtx_PLUS (Pmode, 927 gen_rtx_REG (Pmode, 928 THREAD_POINTER_REGNUM), 929 temp3)); 930 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 931 break; 932 } 933 case TLS_MODEL_LOCAL_EXEC: 934 { 935 rtx temp1; 936 rtx_insn *last; 937 938 ret = gen_reg_rtx (Pmode); 939 temp1 = gen_reg_rtx (Pmode); 940 941 emit_insn (gen_tls_le_addhi (temp1, 942 gen_rtx_REG (Pmode, 943 THREAD_POINTER_REGNUM), 944 addr)); 945 last = emit_insn (gen_tls_le_addlo (ret, temp1, addr)); 946 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 947 break; 948 } 949 default: 950 gcc_unreachable (); 951 } 952 else if (GET_CODE (addr) == CONST) 953 { 954 rtx base, offset; 955 956 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS); 957 958 base = tilepro_legitimize_tls_address (XEXP (XEXP (addr, 0), 0)); 959 offset = XEXP (XEXP (addr, 0), 1); 960 961 base = force_operand (base, NULL_RTX); 962 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset)); 963 } 964 else 965 gcc_unreachable (); 966 967 return ret; 968 } 969 970 971 /* Legitimize PIC addresses. If the address is already 972 position-independent, we return ORIG. Newly generated 973 position-independent addresses go into a reg. This is REG if 974 nonzero, otherwise we allocate register(s) as necessary. */ 975 static rtx 976 tilepro_legitimize_pic_address (rtx orig, 977 machine_mode mode ATTRIBUTE_UNUSED, 978 rtx reg) 979 { 980 if (GET_CODE (orig) == SYMBOL_REF) 981 { 982 rtx address, pic_ref; 983 984 if (reg == 0) 985 { 986 gcc_assert (can_create_pseudo_p ()); 987 reg = gen_reg_rtx (Pmode); 988 } 989 990 if (SYMBOL_REF_LOCAL_P (orig)) 991 { 992 /* If not during reload, allocate another temp reg here for 993 loading in the address, so that these instructions can be 994 optimized properly. */ 995 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg); 996 rtx text_label_symbol = tilepro_text_label_symbol (); 997 rtx text_label_rtx = tilepro_text_label_rtx (); 998 999 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig, 1000 text_label_symbol)); 1001 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig, 1002 text_label_symbol)); 1003 1004 /* Note: this is conservative. We use the text_label but we 1005 don't use the pic_offset_table. However, in some cases 1006 we may need the pic_offset_table (see 1007 tilepro_fixup_pcrel_references). */ 1008 crtl->uses_pic_offset_table = 1; 1009 1010 address = temp_reg; 1011 1012 emit_move_insn (reg, address); 1013 return reg; 1014 } 1015 else 1016 { 1017 /* If not during reload, allocate another temp reg here for 1018 loading in the address, so that these instructions can be 1019 optimized properly. */ 1020 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg); 1021 1022 gcc_assert (flag_pic); 1023 if (flag_pic == 1) 1024 { 1025 emit_insn (gen_add_got16 (temp_reg, 1026 tilepro_got_rtx (), orig)); 1027 } 1028 else 1029 { 1030 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg); 1031 emit_insn (gen_addhi_got32 (temp_reg2, 1032 tilepro_got_rtx (), orig)); 1033 emit_insn (gen_addlo_got32 (temp_reg, temp_reg2, orig)); 1034 } 1035 1036 address = temp_reg; 1037 1038 pic_ref = gen_const_mem (Pmode, address); 1039 crtl->uses_pic_offset_table = 1; 1040 emit_move_insn (reg, pic_ref); 1041 /* The following put a REG_EQUAL note on this insn, so that 1042 it can be optimized by loop. But it causes the label to 1043 be optimized away. */ 1044 /* set_unique_reg_note (insn, REG_EQUAL, orig); */ 1045 return reg; 1046 } 1047 } 1048 else if (GET_CODE (orig) == CONST) 1049 { 1050 rtx base, offset; 1051 1052 if (GET_CODE (XEXP (orig, 0)) == PLUS 1053 && XEXP (XEXP (orig, 0), 0) == tilepro_got_rtx ()) 1054 return orig; 1055 1056 if (reg == 0) 1057 { 1058 gcc_assert (can_create_pseudo_p ()); 1059 reg = gen_reg_rtx (Pmode); 1060 } 1061 1062 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); 1063 base = tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, 1064 reg); 1065 offset = 1066 tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, 1067 base == reg ? 0 : reg); 1068 1069 if (CONST_INT_P (offset)) 1070 { 1071 if (can_create_pseudo_p ()) 1072 offset = force_reg (Pmode, offset); 1073 else 1074 /* If we reach here, then something is seriously 1075 wrong. */ 1076 gcc_unreachable (); 1077 } 1078 1079 if (can_create_pseudo_p ()) 1080 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset)); 1081 else 1082 gcc_unreachable (); 1083 } 1084 else if (GET_CODE (orig) == LABEL_REF) 1085 { 1086 rtx address, temp_reg; 1087 rtx text_label_symbol; 1088 rtx text_label_rtx; 1089 1090 if (reg == 0) 1091 { 1092 gcc_assert (can_create_pseudo_p ()); 1093 reg = gen_reg_rtx (Pmode); 1094 } 1095 1096 /* If not during reload, allocate another temp reg here for 1097 loading in the address, so that these instructions can be 1098 optimized properly. */ 1099 temp_reg = create_temp_reg_if_possible (Pmode, reg); 1100 text_label_symbol = tilepro_text_label_symbol (); 1101 text_label_rtx = tilepro_text_label_rtx (); 1102 1103 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig, 1104 text_label_symbol)); 1105 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig, 1106 text_label_symbol)); 1107 1108 /* Note: this is conservative. We use the text_label but we 1109 don't use the pic_offset_table. */ 1110 crtl->uses_pic_offset_table = 1; 1111 1112 address = temp_reg; 1113 1114 emit_move_insn (reg, address); 1115 1116 return reg; 1117 } 1118 1119 return orig; 1120 } 1121 1122 1123 /* Implement TARGET_LEGITIMIZE_ADDRESS. */ 1124 static rtx 1125 tilepro_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 1126 machine_mode mode) 1127 { 1128 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD 1129 && symbolic_operand (x, Pmode) && tilepro_tls_referenced_p (x)) 1130 { 1131 return tilepro_legitimize_tls_address (x); 1132 } 1133 else if (flag_pic) 1134 { 1135 return tilepro_legitimize_pic_address (x, mode, 0); 1136 } 1137 else 1138 return x; 1139 } 1140 1141 1142 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */ 1143 static rtx 1144 tilepro_delegitimize_address (rtx x) 1145 { 1146 x = delegitimize_mem_from_attrs (x); 1147 1148 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC) 1149 { 1150 switch (XINT (XEXP (x, 0), 1)) 1151 { 1152 case UNSPEC_PCREL_SYM: 1153 case UNSPEC_GOT16_SYM: 1154 case UNSPEC_GOT32_SYM: 1155 case UNSPEC_TLS_GD: 1156 case UNSPEC_TLS_IE: 1157 x = XVECEXP (XEXP (x, 0), 0, 0); 1158 break; 1159 } 1160 } 1161 1162 return x; 1163 } 1164 1165 1166 /* Emit code to load the PIC register. */ 1167 static void 1168 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED) 1169 { 1170 int orig_flag_pic = flag_pic; 1171 1172 rtx got_symbol = tilepro_got_symbol (); 1173 rtx text_label_symbol = tilepro_text_label_symbol (); 1174 rtx text_label_rtx = tilepro_text_label_rtx (); 1175 flag_pic = 0; 1176 1177 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol)); 1178 1179 emit_insn (gen_addli_pcrel (tilepro_got_rtx (), 1180 text_label_rtx, got_symbol, text_label_symbol)); 1181 1182 emit_insn (gen_auli_pcrel (tilepro_got_rtx (), 1183 tilepro_got_rtx (), 1184 got_symbol, text_label_symbol)); 1185 1186 flag_pic = orig_flag_pic; 1187 1188 /* Need to emit this whether or not we obey regdecls, since 1189 setjmp/longjmp can cause life info to screw up. ??? In the case 1190 where we don't obey regdecls, this is not sufficient since we may 1191 not fall out the bottom. */ 1192 emit_use (tilepro_got_rtx ()); 1193 } 1194 1195 1196 /* Return the simd variant of the constant NUM of mode MODE, by 1197 replicating it to fill an interger of mode SImode. NUM is first 1198 truncated to fit in MODE. */ 1199 rtx 1200 tilepro_simd_int (rtx num, machine_mode mode) 1201 { 1202 HOST_WIDE_INT n = 0; 1203 1204 gcc_assert (CONST_INT_P (num)); 1205 1206 n = INTVAL (num); 1207 1208 switch (mode) 1209 { 1210 case QImode: 1211 n = 0x01010101 * (n & 0x000000FF); 1212 break; 1213 case HImode: 1214 n = 0x00010001 * (n & 0x0000FFFF); 1215 break; 1216 case SImode: 1217 break; 1218 case DImode: 1219 break; 1220 default: 1221 gcc_unreachable (); 1222 } 1223 1224 return gen_int_si (n); 1225 } 1226 1227 1228 /* Split one or more DImode RTL references into pairs of SImode 1229 references. The RTL can be REG, offsettable MEM, integer constant, 1230 or CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL 1231 to split and "num" is its length. lo_half and hi_half are output 1232 arrays that parallel "operands". */ 1233 void 1234 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[]) 1235 { 1236 while (num--) 1237 { 1238 rtx op = operands[num]; 1239 1240 /* simplify_subreg refuse to split volatile memory addresses, 1241 but we still have to handle it. */ 1242 if (MEM_P (op)) 1243 { 1244 lo_half[num] = adjust_address (op, SImode, 0); 1245 hi_half[num] = adjust_address (op, SImode, 4); 1246 } 1247 else 1248 { 1249 lo_half[num] = simplify_gen_subreg (SImode, op, 1250 GET_MODE (op) == VOIDmode 1251 ? DImode : GET_MODE (op), 0); 1252 hi_half[num] = simplify_gen_subreg (SImode, op, 1253 GET_MODE (op) == VOIDmode 1254 ? DImode : GET_MODE (op), 4); 1255 } 1256 } 1257 } 1258 1259 1260 /* Returns true iff val can be moved into a register in one 1261 instruction. And if it can, it emits the code to move the 1262 constant. 1263 1264 If three_wide_only is true, this insists on an instruction that 1265 works in a bundle containing three instructions. */ 1266 static bool 1267 expand_set_cint32_one_inst (rtx dest_reg, 1268 HOST_WIDE_INT val, bool three_wide_only) 1269 { 1270 val = trunc_int_for_mode (val, SImode); 1271 1272 if (val == trunc_int_for_mode (val, QImode)) 1273 { 1274 /* Success! */ 1275 emit_move_insn (dest_reg, GEN_INT (val)); 1276 return true; 1277 } 1278 else if (!three_wide_only) 1279 { 1280 rtx imm_op = GEN_INT (val); 1281 1282 if (satisfies_constraint_J (imm_op) 1283 || satisfies_constraint_K (imm_op) 1284 || satisfies_constraint_N (imm_op) 1285 || satisfies_constraint_P (imm_op)) 1286 { 1287 emit_move_insn (dest_reg, imm_op); 1288 return true; 1289 } 1290 } 1291 1292 return false; 1293 } 1294 1295 1296 /* Implement SImode rotatert. */ 1297 static HOST_WIDE_INT 1298 rotate_right (HOST_WIDE_INT n, int count) 1299 { 1300 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFF; 1301 if (count == 0) 1302 return x; 1303 return ((x >> count) | (x << (32 - count))) & 0xFFFFFFFF; 1304 } 1305 1306 1307 /* Return true iff n contains exactly one contiguous sequence of 1 1308 bits, possibly wrapping around from high bits to low bits. */ 1309 bool 1310 tilepro_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit) 1311 { 1312 int i; 1313 1314 if (n == 0) 1315 return false; 1316 1317 for (i = 0; i < 32; i++) 1318 { 1319 unsigned HOST_WIDE_INT x = rotate_right (n, i); 1320 if (!(x & 1)) 1321 continue; 1322 1323 /* See if x is a power of two minus one, i.e. only consecutive 1 1324 bits starting from bit 0. */ 1325 if ((x & (x + 1)) == 0) 1326 { 1327 if (first_bit != NULL) 1328 *first_bit = i; 1329 if (last_bit != NULL) 1330 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 31; 1331 1332 return true; 1333 } 1334 } 1335 1336 return false; 1337 } 1338 1339 1340 /* Create code to move the CONST_INT value in src_val to dest_reg. */ 1341 static void 1342 expand_set_cint32 (rtx dest_reg, rtx src_val) 1343 { 1344 HOST_WIDE_INT val; 1345 int leading_zeroes, trailing_zeroes; 1346 int lower, upper; 1347 int three_wide_only; 1348 rtx temp; 1349 1350 gcc_assert (CONST_INT_P (src_val)); 1351 val = trunc_int_for_mode (INTVAL (src_val), SImode); 1352 1353 /* See if we can generate the constant in one instruction. */ 1354 if (expand_set_cint32_one_inst (dest_reg, val, false)) 1355 return; 1356 1357 /* Create a temporary variable to hold a partial result, to enable 1358 CSE. */ 1359 temp = create_temp_reg_if_possible (SImode, dest_reg); 1360 1361 leading_zeroes = 31 - floor_log2 (val & 0xFFFFFFFF); 1362 trailing_zeroes = exact_log2 (val & -val); 1363 1364 lower = trunc_int_for_mode (val, HImode); 1365 upper = trunc_int_for_mode ((val - lower) >> 16, HImode); 1366 1367 /* First try all three-wide instructions that generate a constant 1368 (i.e. movei) followed by various shifts and rotates. If none of 1369 those work, try various two-wide ways of generating a constant 1370 followed by various shifts and rotates. */ 1371 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--) 1372 { 1373 int count; 1374 1375 if (expand_set_cint32_one_inst (temp, val >> trailing_zeroes, 1376 three_wide_only)) 1377 { 1378 /* 0xFFFFA500 becomes: 1379 movei temp, 0xFFFFFFA5 1380 shli dest, temp, 8 */ 1381 emit_move_insn (dest_reg, 1382 gen_rtx_ASHIFT (SImode, temp, 1383 GEN_INT (trailing_zeroes))); 1384 return; 1385 } 1386 1387 if (expand_set_cint32_one_inst (temp, val << leading_zeroes, 1388 three_wide_only)) 1389 { 1390 /* 0x7FFFFFFF becomes: 1391 movei temp, -2 1392 shri dest, temp, 1 */ 1393 emit_move_insn (dest_reg, 1394 gen_rtx_LSHIFTRT (SImode, temp, 1395 GEN_INT (leading_zeroes))); 1396 return; 1397 } 1398 1399 /* Try rotating a one-instruction immediate, since rotate is 1400 3-wide. */ 1401 for (count = 1; count < 32; count++) 1402 { 1403 HOST_WIDE_INT r = rotate_right (val, count); 1404 if (expand_set_cint32_one_inst (temp, r, three_wide_only)) 1405 { 1406 /* 0xFFA5FFFF becomes: 1407 movei temp, 0xFFFFFFA5 1408 rli dest, temp, 16 */ 1409 emit_move_insn (dest_reg, 1410 gen_rtx_ROTATE (SImode, temp, GEN_INT (count))); 1411 return; 1412 } 1413 } 1414 1415 if (lower == trunc_int_for_mode (lower, QImode)) 1416 { 1417 /* We failed to use two 3-wide instructions, but the low 16 1418 bits are a small number so just use a 2-wide + 3-wide 1419 auli + addi pair rather than anything more exotic. 1420 1421 0x12340056 becomes: 1422 auli temp, zero, 0x1234 1423 addi dest, temp, 0x56 */ 1424 break; 1425 } 1426 } 1427 1428 /* Fallback case: use a auli + addli/addi pair. */ 1429 emit_move_insn (temp, GEN_INT (upper << 16)); 1430 emit_move_insn (dest_reg, (gen_rtx_PLUS (SImode, temp, GEN_INT (lower)))); 1431 } 1432 1433 1434 /* Load OP1, a 32-bit constant, into OP0, a register. We know it 1435 can't be done in one insn when we get here, the move expander 1436 guarantees this. */ 1437 void 1438 tilepro_expand_set_const32 (rtx op0, rtx op1) 1439 { 1440 machine_mode mode = GET_MODE (op0); 1441 rtx temp; 1442 1443 if (CONST_INT_P (op1)) 1444 { 1445 /* TODO: I don't know if we want to split large constants now, 1446 or wait until later (with a define_split). 1447 1448 Does splitting early help CSE? Does it harm other 1449 optimizations that might fold loads? */ 1450 expand_set_cint32 (op0, op1); 1451 } 1452 else 1453 { 1454 temp = create_temp_reg_if_possible (mode, op0); 1455 1456 /* A symbol, emit in the traditional way. */ 1457 emit_move_insn (temp, gen_rtx_HIGH (mode, op1)); 1458 emit_move_insn (op0, gen_rtx_LO_SUM (mode, temp, op1)); 1459 } 1460 } 1461 1462 1463 /* Expand a move instruction. Return true if all work is done. */ 1464 bool 1465 tilepro_expand_mov (machine_mode mode, rtx *operands) 1466 { 1467 /* Handle sets of MEM first. */ 1468 if (MEM_P (operands[0])) 1469 { 1470 if (can_create_pseudo_p ()) 1471 operands[0] = validize_mem (operands[0]); 1472 1473 if (reg_or_0_operand (operands[1], mode)) 1474 return false; 1475 1476 if (!reload_in_progress) 1477 operands[1] = force_reg (mode, operands[1]); 1478 } 1479 1480 /* Fixup TLS cases. */ 1481 if (CONSTANT_P (operands[1]) && tilepro_tls_referenced_p (operands[1])) 1482 { 1483 operands[1] = tilepro_legitimize_tls_address (operands[1]); 1484 return false; 1485 } 1486 1487 /* Fixup PIC cases. */ 1488 if (flag_pic && CONSTANT_P (operands[1])) 1489 { 1490 if (tilepro_pic_address_needs_scratch (operands[1])) 1491 operands[1] = tilepro_legitimize_pic_address (operands[1], mode, 0); 1492 1493 if (symbolic_operand (operands[1], mode)) 1494 { 1495 operands[1] = tilepro_legitimize_pic_address (operands[1], 1496 mode, 1497 (reload_in_progress ? 1498 operands[0] : 1499 NULL_RTX)); 1500 return false; 1501 } 1502 } 1503 1504 /* Fixup for UNSPEC addresses. */ 1505 if (flag_pic 1506 && GET_CODE (operands[1]) == HIGH 1507 && GET_CODE (XEXP (operands[1], 0)) == CONST 1508 && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == UNSPEC) 1509 { 1510 rtx unspec = XEXP (XEXP (operands[1], 0), 0); 1511 int unspec_num = XINT (unspec, 1); 1512 if (unspec_num == UNSPEC_PCREL_SYM) 1513 { 1514 emit_insn (gen_auli_pcrel (operands[0], const0_rtx, 1515 XVECEXP (unspec, 0, 0), 1516 XVECEXP (unspec, 0, 1))); 1517 return true; 1518 } 1519 else if (flag_pic == 2 && unspec_num == UNSPEC_GOT32_SYM) 1520 { 1521 emit_insn (gen_addhi_got32 (operands[0], const0_rtx, 1522 XVECEXP (unspec, 0, 0))); 1523 return true; 1524 } 1525 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_GD) 1526 { 1527 emit_insn (gen_tls_gd_addhi (operands[0], const0_rtx, 1528 XVECEXP (unspec, 0, 0))); 1529 return true; 1530 } 1531 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_IE) 1532 { 1533 emit_insn (gen_tls_ie_addhi (operands[0], const0_rtx, 1534 XVECEXP (unspec, 0, 0))); 1535 return true; 1536 } 1537 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_LE) 1538 { 1539 emit_insn (gen_tls_le_addhi (operands[0], const0_rtx, 1540 XVECEXP (unspec, 0, 0))); 1541 return true; 1542 } 1543 } 1544 1545 /* Accept non-constants and valid constants unmodified. */ 1546 if (!CONSTANT_P (operands[1]) 1547 || GET_CODE (operands[1]) == HIGH || move_operand (operands[1], mode)) 1548 return false; 1549 1550 /* Split large integers. */ 1551 if (GET_MODE_SIZE (mode) <= 4) 1552 { 1553 tilepro_expand_set_const32 (operands[0], operands[1]); 1554 return true; 1555 } 1556 1557 return false; 1558 } 1559 1560 1561 /* Expand the "insv" pattern. */ 1562 void 1563 tilepro_expand_insv (rtx operands[4]) 1564 { 1565 rtx first_rtx = operands[2]; 1566 HOST_WIDE_INT first = INTVAL (first_rtx); 1567 HOST_WIDE_INT width = INTVAL (operands[1]); 1568 rtx v = operands[3]; 1569 1570 /* Shift the inserted bits into position. */ 1571 if (first != 0) 1572 { 1573 if (CONST_INT_P (v)) 1574 { 1575 /* Shift the constant into mm position. */ 1576 v = gen_int_si (INTVAL (v) << first); 1577 } 1578 else 1579 { 1580 /* Shift over the value to be inserted. */ 1581 rtx tmp = gen_reg_rtx (SImode); 1582 emit_insn (gen_ashlsi3 (tmp, v, first_rtx)); 1583 v = tmp; 1584 } 1585 } 1586 1587 /* Insert the shifted bits using an 'mm' insn. */ 1588 emit_insn (gen_insn_mm (operands[0], v, operands[0], first_rtx, 1589 GEN_INT (first + width - 1))); 1590 } 1591 1592 1593 /* Expand unaligned loads. */ 1594 void 1595 tilepro_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize, 1596 HOST_WIDE_INT bit_offset, bool sign) 1597 { 1598 machine_mode mode; 1599 rtx addr_lo, addr_hi; 1600 rtx mem_lo, mem_hi, hi; 1601 rtx mema, wide_result; 1602 int last_byte_offset; 1603 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT; 1604 1605 mode = GET_MODE (dest_reg); 1606 1607 hi = gen_reg_rtx (mode); 1608 1609 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0) 1610 { 1611 rtx lo; 1612 1613 /* When just loading a two byte value, we can load the two bytes 1614 individually and combine them efficiently. */ 1615 1616 mem_lo = adjust_address (mem, QImode, byte_offset); 1617 mem_hi = adjust_address (mem, QImode, byte_offset + 1); 1618 1619 lo = gen_reg_rtx (mode); 1620 emit_insn (gen_zero_extendqisi2 (lo, mem_lo)); 1621 1622 if (sign) 1623 { 1624 rtx tmp = gen_reg_rtx (mode); 1625 1626 /* Do a signed load of the second byte then shift and OR it 1627 in. */ 1628 emit_insn (gen_extendqisi2 (gen_lowpart (SImode, hi), mem_hi)); 1629 emit_insn (gen_ashlsi3 (gen_lowpart (SImode, tmp), 1630 gen_lowpart (SImode, hi), GEN_INT (8))); 1631 emit_insn (gen_iorsi3 (gen_lowpart (SImode, dest_reg), 1632 gen_lowpart (SImode, lo), 1633 gen_lowpart (SImode, tmp))); 1634 } 1635 else 1636 { 1637 /* Do two unsigned loads and use intlb to interleave 1638 them. */ 1639 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, hi), mem_hi)); 1640 emit_insn (gen_insn_intlb (gen_lowpart (SImode, dest_reg), 1641 gen_lowpart (SImode, hi), 1642 gen_lowpart (SImode, lo))); 1643 } 1644 1645 return; 1646 } 1647 1648 mema = XEXP (mem, 0); 1649 1650 /* AND addresses cannot be in any alias set, since they may 1651 implicitly alias surrounding code. Ideally we'd have some alias 1652 set that covered all types except those with alignment 8 or 1653 higher. */ 1654 addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset)); 1655 mem_lo = change_address (mem, mode, 1656 gen_rtx_AND (Pmode, addr_lo, GEN_INT (-4))); 1657 set_mem_alias_set (mem_lo, 0); 1658 1659 /* Load the high word at an address that will not fault if the low 1660 address is aligned and at the very end of a page. */ 1661 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT; 1662 addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset)); 1663 mem_hi = change_address (mem, mode, 1664 gen_rtx_AND (Pmode, addr_hi, GEN_INT (-4))); 1665 set_mem_alias_set (mem_hi, 0); 1666 1667 if (bitsize == 32) 1668 { 1669 addr_lo = make_safe_from (addr_lo, dest_reg); 1670 wide_result = dest_reg; 1671 } 1672 else 1673 { 1674 wide_result = gen_reg_rtx (mode); 1675 } 1676 1677 /* Load hi first in case dest_reg is used in mema. */ 1678 emit_move_insn (hi, mem_hi); 1679 emit_move_insn (wide_result, mem_lo); 1680 1681 emit_insn (gen_insn_dword_align (gen_lowpart (SImode, wide_result), 1682 gen_lowpart (SImode, wide_result), 1683 gen_lowpart (SImode, hi), addr_lo)); 1684 1685 if (bitsize != 32) 1686 { 1687 rtx extracted = 1688 extract_bit_field (gen_lowpart (SImode, wide_result), 1689 bitsize, bit_offset % BITS_PER_UNIT, 1690 !sign, gen_lowpart (SImode, dest_reg), 1691 SImode, SImode, false); 1692 1693 if (extracted != dest_reg) 1694 emit_move_insn (dest_reg, gen_lowpart (SImode, extracted)); 1695 } 1696 } 1697 1698 1699 /* Expand unaligned stores. */ 1700 static void 1701 tilepro_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize, 1702 HOST_WIDE_INT bit_offset) 1703 { 1704 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT; 1705 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT; 1706 HOST_WIDE_INT shift_amt; 1707 HOST_WIDE_INT i; 1708 rtx mem_addr; 1709 rtx store_val; 1710 1711 for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT) 1712 { 1713 mem_addr = adjust_address (mem, QImode, byte_offset + i); 1714 1715 if (shift_amt) 1716 { 1717 store_val = expand_simple_binop (SImode, LSHIFTRT, 1718 gen_lowpart (SImode, src), 1719 GEN_INT (shift_amt), NULL, 1, 1720 OPTAB_LIB_WIDEN); 1721 store_val = gen_lowpart (QImode, store_val); 1722 } 1723 else 1724 { 1725 store_val = gen_lowpart (QImode, src); 1726 } 1727 1728 emit_move_insn (mem_addr, store_val); 1729 } 1730 } 1731 1732 1733 /* Implement the movmisalign patterns. One of the operands is a 1734 memory that is not naturally aligned. Emit instructions to load 1735 it. */ 1736 void 1737 tilepro_expand_movmisalign (machine_mode mode, rtx *operands) 1738 { 1739 if (MEM_P (operands[1])) 1740 { 1741 rtx tmp; 1742 1743 if (register_operand (operands[0], mode)) 1744 tmp = operands[0]; 1745 else 1746 tmp = gen_reg_rtx (mode); 1747 1748 tilepro_expand_unaligned_load (tmp, operands[1], 1749 GET_MODE_BITSIZE (mode), 0, true); 1750 1751 if (tmp != operands[0]) 1752 emit_move_insn (operands[0], tmp); 1753 } 1754 else if (MEM_P (operands[0])) 1755 { 1756 if (!reg_or_0_operand (operands[1], mode)) 1757 operands[1] = force_reg (mode, operands[1]); 1758 1759 tilepro_expand_unaligned_store (operands[0], operands[1], 1760 GET_MODE_BITSIZE (mode), 0); 1761 } 1762 else 1763 gcc_unreachable (); 1764 } 1765 1766 1767 /* Implement the addsi3 pattern. */ 1768 bool 1769 tilepro_expand_addsi (rtx op0, rtx op1, rtx op2) 1770 { 1771 rtx temp; 1772 HOST_WIDE_INT n; 1773 HOST_WIDE_INT high; 1774 1775 /* Skip anything that only takes one instruction. */ 1776 if (add_operand (op2, SImode)) 1777 return false; 1778 1779 /* We can only optimize ints here (it should be impossible to get 1780 here with any other type, but it is harmless to check. */ 1781 if (!CONST_INT_P (op2)) 1782 return false; 1783 1784 temp = create_temp_reg_if_possible (SImode, op0); 1785 n = INTVAL (op2); 1786 high = (n + (n & 0x8000)) & ~0xffff; 1787 1788 emit_move_insn (temp, gen_rtx_PLUS (SImode, op1, gen_int_si (high))); 1789 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, gen_int_si (n - high))); 1790 1791 return true; 1792 } 1793 1794 1795 /* Implement the allocate_stack pattern (alloca). */ 1796 void 1797 tilepro_allocate_stack (rtx op0, rtx op1) 1798 { 1799 /* Technically the correct way to initialize chain_loc is with 1800 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem() 1801 * sets the alias_set to that of a frame reference. Some of our 1802 * tests rely on some unsafe assumption about when the chaining 1803 * update is done, we need to be conservative about reordering the 1804 * chaining instructions. 1805 */ 1806 rtx fp_addr = gen_reg_rtx (Pmode); 1807 rtx fp_value = gen_reg_rtx (Pmode); 1808 rtx fp_loc; 1809 1810 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx, 1811 GEN_INT (UNITS_PER_WORD))); 1812 1813 fp_loc = gen_frame_mem (Pmode, fp_addr); 1814 1815 emit_move_insn (fp_value, fp_loc); 1816 1817 op1 = force_reg (Pmode, op1); 1818 1819 emit_move_insn (stack_pointer_rtx, 1820 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1)); 1821 1822 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx, 1823 GEN_INT (UNITS_PER_WORD))); 1824 1825 fp_loc = gen_frame_mem (Pmode, fp_addr); 1826 1827 emit_move_insn (fp_loc, fp_value); 1828 1829 emit_move_insn (op0, virtual_stack_dynamic_rtx); 1830 } 1831 1832 1833 1834 /* Multiplies */ 1835 1836 /* Returns the insn_code in ENTRY. */ 1837 static enum insn_code 1838 tilepro_multiply_get_opcode (const struct tilepro_multiply_insn_seq_entry 1839 *entry) 1840 { 1841 return tilepro_multiply_insn_seq_decode_opcode[entry->compressed_opcode]; 1842 } 1843 1844 1845 /* Returns the length of the 'op' array. */ 1846 static int 1847 tilepro_multiply_get_num_ops (const struct tilepro_multiply_insn_seq *seq) 1848 { 1849 /* The array either uses all of its allocated slots or is terminated 1850 by a bogus opcode. Either way, the array size is the index of the 1851 last valid opcode plus one. */ 1852 int i; 1853 for (i = tilepro_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--) 1854 if (tilepro_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing) 1855 return i + 1; 1856 1857 /* An empty array is not allowed. */ 1858 gcc_unreachable (); 1859 } 1860 1861 1862 /* We precompute a number of expression trees for multiplying by 1863 constants. This generates code for such an expression tree by 1864 walking through the nodes in the tree (which are conveniently 1865 pre-linearized) and emitting an instruction for each one. */ 1866 static void 1867 tilepro_expand_constant_multiply_given_sequence (rtx result, rtx src, 1868 const struct 1869 tilepro_multiply_insn_seq 1870 *seq) 1871 { 1872 int i; 1873 int num_ops; 1874 1875 /* Keep track of the subexpressions computed so far, so later 1876 instructions can refer to them. We seed the array with zero and 1877 the value being multiplied. */ 1878 int num_subexprs = 2; 1879 rtx subexprs[tilepro_multiply_insn_seq_MAX_OPERATIONS + 2]; 1880 subexprs[0] = const0_rtx; 1881 subexprs[1] = src; 1882 1883 /* Determine how many instructions we are going to generate. */ 1884 num_ops = tilepro_multiply_get_num_ops (seq); 1885 gcc_assert (num_ops > 0 1886 && num_ops <= tilepro_multiply_insn_seq_MAX_OPERATIONS); 1887 1888 for (i = 0; i < num_ops; i++) 1889 { 1890 const struct tilepro_multiply_insn_seq_entry *entry = &seq->op[i]; 1891 1892 /* Figure out where to store the output of this instruction. */ 1893 const bool is_last_op = (i + 1 == num_ops); 1894 rtx out = is_last_op ? result : gen_reg_rtx (SImode); 1895 1896 enum insn_code opcode = tilepro_multiply_get_opcode (entry); 1897 if (opcode == CODE_FOR_ashlsi3) 1898 { 1899 /* Handle shift by immediate. This is a special case because 1900 the meaning of the second operand is a constant shift 1901 count rather than an operand index. */ 1902 1903 /* Make sure the shift count is in range. Zero should not 1904 happen. */ 1905 const int shift_count = entry->rhs; 1906 gcc_assert (shift_count > 0 && shift_count < 32); 1907 1908 /* Emit the actual instruction. */ 1909 emit_insn (GEN_FCN (opcode) 1910 (out, subexprs[entry->lhs], 1911 gen_rtx_CONST_INT (SImode, shift_count))); 1912 } 1913 else 1914 { 1915 /* Handle a normal two-operand instruction, such as add or 1916 s1a. */ 1917 1918 /* Make sure we are referring to a previously computed 1919 subexpression. */ 1920 gcc_assert (entry->rhs < num_subexprs); 1921 1922 /* Emit the actual instruction. */ 1923 emit_insn (GEN_FCN (opcode) 1924 (out, subexprs[entry->lhs], subexprs[entry->rhs])); 1925 } 1926 1927 /* Record this subexpression for use by later expressions. */ 1928 subexprs[num_subexprs++] = out; 1929 } 1930 } 1931 1932 1933 /* bsearch helper function. */ 1934 static int 1935 tilepro_compare_multipliers (const void *key, const void *t) 1936 { 1937 return *(const int *) key - 1938 ((const struct tilepro_multiply_insn_seq *) t)->multiplier; 1939 } 1940 1941 1942 /* Returns the tilepro_multiply_insn_seq for multiplier, or NULL if 1943 none exists. */ 1944 static const struct tilepro_multiply_insn_seq * 1945 tilepro_find_multiply_insn_seq_for_constant (int multiplier) 1946 { 1947 return ((const struct tilepro_multiply_insn_seq *) 1948 bsearch (&multiplier, tilepro_multiply_insn_seq_table, 1949 tilepro_multiply_insn_seq_table_size, 1950 sizeof tilepro_multiply_insn_seq_table[0], 1951 tilepro_compare_multipliers)); 1952 } 1953 1954 1955 /* Try to a expand constant multiply in SImode by looking it up in a 1956 precompiled table. OP0 is the result operand, OP1 is the source 1957 operand, and MULTIPLIER is the value of the constant. Return true 1958 if it succeeds. */ 1959 static bool 1960 tilepro_expand_const_mulsi (rtx op0, rtx op1, int multiplier) 1961 { 1962 /* See if we have precomputed an efficient way to multiply by this 1963 constant. */ 1964 const struct tilepro_multiply_insn_seq *seq = 1965 tilepro_find_multiply_insn_seq_for_constant (multiplier); 1966 if (seq != NULL) 1967 { 1968 tilepro_expand_constant_multiply_given_sequence (op0, op1, seq); 1969 return true; 1970 } 1971 else 1972 return false; 1973 } 1974 1975 1976 /* Expand the mulsi pattern. */ 1977 bool 1978 tilepro_expand_mulsi (rtx op0, rtx op1, rtx op2) 1979 { 1980 if (CONST_INT_P (op2)) 1981 { 1982 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), SImode); 1983 return tilepro_expand_const_mulsi (op0, op1, n); 1984 } 1985 return false; 1986 } 1987 1988 1989 /* Expand a high multiply pattern in SImode. RESULT, OP1, OP2 are the 1990 operands, and SIGN is true if it's a signed multiply, and false if 1991 it's an unsigned multiply. */ 1992 static void 1993 tilepro_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign) 1994 { 1995 rtx tmp0 = gen_reg_rtx (SImode); 1996 rtx tmp1 = gen_reg_rtx (SImode); 1997 rtx tmp2 = gen_reg_rtx (SImode); 1998 rtx tmp3 = gen_reg_rtx (SImode); 1999 rtx tmp4 = gen_reg_rtx (SImode); 2000 rtx tmp5 = gen_reg_rtx (SImode); 2001 rtx tmp6 = gen_reg_rtx (SImode); 2002 rtx tmp7 = gen_reg_rtx (SImode); 2003 rtx tmp8 = gen_reg_rtx (SImode); 2004 rtx tmp9 = gen_reg_rtx (SImode); 2005 rtx tmp10 = gen_reg_rtx (SImode); 2006 rtx tmp11 = gen_reg_rtx (SImode); 2007 rtx tmp12 = gen_reg_rtx (SImode); 2008 rtx tmp13 = gen_reg_rtx (SImode); 2009 rtx result_lo = gen_reg_rtx (SImode); 2010 2011 if (sign) 2012 { 2013 emit_insn (gen_insn_mulhl_su (tmp0, op1, op2)); 2014 emit_insn (gen_insn_mulhl_su (tmp1, op2, op1)); 2015 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2)); 2016 emit_insn (gen_insn_mulhh_ss (tmp3, op1, op2)); 2017 } 2018 else 2019 { 2020 emit_insn (gen_insn_mulhl_uu (tmp0, op1, op2)); 2021 emit_insn (gen_insn_mulhl_uu (tmp1, op2, op1)); 2022 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2)); 2023 emit_insn (gen_insn_mulhh_uu (tmp3, op1, op2)); 2024 } 2025 2026 emit_move_insn (tmp4, (gen_rtx_ASHIFT (SImode, tmp0, GEN_INT (16)))); 2027 2028 emit_move_insn (tmp5, (gen_rtx_ASHIFT (SImode, tmp1, GEN_INT (16)))); 2029 2030 emit_move_insn (tmp6, (gen_rtx_PLUS (SImode, tmp4, tmp5))); 2031 emit_move_insn (result_lo, (gen_rtx_PLUS (SImode, tmp2, tmp6))); 2032 2033 emit_move_insn (tmp7, gen_rtx_LTU (SImode, tmp6, tmp4)); 2034 emit_move_insn (tmp8, gen_rtx_LTU (SImode, result_lo, tmp2)); 2035 2036 if (sign) 2037 { 2038 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (SImode, tmp0, GEN_INT (16)))); 2039 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (SImode, tmp1, GEN_INT (16)))); 2040 } 2041 else 2042 { 2043 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (SImode, tmp0, GEN_INT (16)))); 2044 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (SImode, tmp1, GEN_INT (16)))); 2045 } 2046 2047 emit_move_insn (tmp11, (gen_rtx_PLUS (SImode, tmp3, tmp7))); 2048 emit_move_insn (tmp12, (gen_rtx_PLUS (SImode, tmp8, tmp9))); 2049 emit_move_insn (tmp13, (gen_rtx_PLUS (SImode, tmp11, tmp12))); 2050 emit_move_insn (result, (gen_rtx_PLUS (SImode, tmp13, tmp10))); 2051 } 2052 2053 2054 /* Implement smulsi3_highpart. */ 2055 void 2056 tilepro_expand_smulsi3_highpart (rtx op0, rtx op1, rtx op2) 2057 { 2058 tilepro_expand_high_multiply (op0, op1, op2, true); 2059 } 2060 2061 2062 /* Implement umulsi3_highpart. */ 2063 void 2064 tilepro_expand_umulsi3_highpart (rtx op0, rtx op1, rtx op2) 2065 { 2066 tilepro_expand_high_multiply (op0, op1, op2, false); 2067 } 2068 2069 2070 2071 /* Compare and branches */ 2072 2073 /* Helper function to handle DImode for tilepro_emit_setcc_internal. */ 2074 static bool 2075 tilepro_emit_setcc_internal_di (rtx res, enum rtx_code code, rtx op0, rtx op1) 2076 { 2077 rtx operands[2], lo_half[2], hi_half[2]; 2078 rtx tmp, tmp0, tmp1, tmp2; 2079 bool swap = false; 2080 2081 /* Reduce the number of cases we need to handle by reversing the 2082 operands. */ 2083 switch (code) 2084 { 2085 case EQ: 2086 case NE: 2087 case LE: 2088 case LT: 2089 case LEU: 2090 case LTU: 2091 /* We handle these compares directly. */ 2092 break; 2093 2094 case GE: 2095 case GT: 2096 case GEU: 2097 case GTU: 2098 /* Reverse the operands. */ 2099 swap = true; 2100 break; 2101 2102 default: 2103 /* We should not have called this with any other code. */ 2104 gcc_unreachable (); 2105 } 2106 2107 if (swap) 2108 { 2109 code = swap_condition (code); 2110 tmp = op0, op0 = op1, op1 = tmp; 2111 } 2112 2113 operands[0] = op0; 2114 operands[1] = op1; 2115 2116 split_di (operands, 2, lo_half, hi_half); 2117 2118 if (!reg_or_0_operand (lo_half[0], SImode)) 2119 lo_half[0] = force_reg (SImode, lo_half[0]); 2120 2121 if (!reg_or_0_operand (hi_half[0], SImode)) 2122 hi_half[0] = force_reg (SImode, hi_half[0]); 2123 2124 if (!CONST_INT_P (lo_half[1]) && !register_operand (lo_half[1], SImode)) 2125 lo_half[1] = force_reg (SImode, lo_half[1]); 2126 2127 if (!CONST_INT_P (hi_half[1]) && !register_operand (hi_half[1], SImode)) 2128 hi_half[1] = force_reg (SImode, hi_half[1]); 2129 2130 tmp0 = gen_reg_rtx (SImode); 2131 tmp1 = gen_reg_rtx (SImode); 2132 tmp2 = gen_reg_rtx (SImode); 2133 2134 switch (code) 2135 { 2136 case EQ: 2137 emit_insn (gen_insn_seq (tmp0, lo_half[0], lo_half[1])); 2138 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1])); 2139 emit_insn (gen_andsi3 (res, tmp0, tmp1)); 2140 return true; 2141 case NE: 2142 emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1])); 2143 emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1])); 2144 emit_insn (gen_iorsi3 (res, tmp0, tmp1)); 2145 return true; 2146 case LE: 2147 emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1])); 2148 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1])); 2149 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1])); 2150 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2)); 2151 return true; 2152 case LT: 2153 if (operands[1] == const0_rtx) 2154 { 2155 emit_insn (gen_lshrsi3 (res, hi_half[0], GEN_INT (31))); 2156 return true; 2157 } 2158 else 2159 { 2160 emit_insn (gen_insn_slt (tmp0, hi_half[0], hi_half[1])); 2161 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1])); 2162 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1])); 2163 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2)); 2164 } 2165 return true; 2166 case LEU: 2167 emit_insn (gen_insn_slte_u (tmp0, hi_half[0], hi_half[1])); 2168 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1])); 2169 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1])); 2170 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2)); 2171 return true; 2172 case LTU: 2173 emit_insn (gen_insn_slt_u (tmp0, hi_half[0], hi_half[1])); 2174 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1])); 2175 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1])); 2176 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2)); 2177 return true; 2178 default: 2179 gcc_unreachable (); 2180 } 2181 2182 return false; 2183 } 2184 2185 2186 /* Certain simplifications can be done to make invalid setcc 2187 operations valid. Return the final comparison, or NULL if we can't 2188 work. */ 2189 static bool 2190 tilepro_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1, 2191 machine_mode cmp_mode) 2192 { 2193 rtx tmp; 2194 bool swap = false; 2195 2196 if (cmp_mode == DImode) 2197 { 2198 return tilepro_emit_setcc_internal_di (res, code, op0, op1); 2199 } 2200 2201 /* The general case: fold the comparison code to the types of 2202 compares that we have, choosing the branch as necessary. */ 2203 2204 switch (code) 2205 { 2206 case EQ: 2207 case NE: 2208 case LE: 2209 case LT: 2210 case LEU: 2211 case LTU: 2212 /* We have these compares. */ 2213 break; 2214 2215 case GE: 2216 case GT: 2217 case GEU: 2218 case GTU: 2219 /* We do not have these compares, so we reverse the 2220 operands. */ 2221 swap = true; 2222 break; 2223 2224 default: 2225 /* We should not have called this with any other code. */ 2226 gcc_unreachable (); 2227 } 2228 2229 if (swap) 2230 { 2231 code = swap_condition (code); 2232 tmp = op0, op0 = op1, op1 = tmp; 2233 } 2234 2235 if (!reg_or_0_operand (op0, SImode)) 2236 op0 = force_reg (SImode, op0); 2237 2238 if (!CONST_INT_P (op1) && !register_operand (op1, SImode)) 2239 op1 = force_reg (SImode, op1); 2240 2241 /* Return the setcc comparison. */ 2242 emit_insn (gen_rtx_SET (res, gen_rtx_fmt_ee (code, SImode, op0, op1))); 2243 2244 return true; 2245 } 2246 2247 2248 /* Implement cstore patterns. */ 2249 bool 2250 tilepro_emit_setcc (rtx operands[], machine_mode cmp_mode) 2251 { 2252 return 2253 tilepro_emit_setcc_internal (operands[0], GET_CODE (operands[1]), 2254 operands[2], operands[3], cmp_mode); 2255 } 2256 2257 2258 /* Return whether CODE is a signed comparison. */ 2259 static bool 2260 signed_compare_p (enum rtx_code code) 2261 { 2262 return (code == EQ || code == NE || code == LT || code == LE 2263 || code == GT || code == GE); 2264 } 2265 2266 2267 /* Generate the comparison for an SImode conditional branch. */ 2268 static rtx 2269 tilepro_emit_cc_test (enum rtx_code code, rtx op0, rtx op1, 2270 machine_mode cmp_mode, bool eq_ne_only) 2271 { 2272 enum rtx_code branch_code; 2273 rtx temp; 2274 2275 /* Check for a compare against zero using a comparison we can do 2276 directly. */ 2277 if (cmp_mode != DImode 2278 && op1 == const0_rtx 2279 && (code == EQ || code == NE 2280 || (!eq_ne_only && signed_compare_p (code)))) 2281 { 2282 op0 = force_reg (SImode, op0); 2283 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx); 2284 } 2285 2286 /* The general case: fold the comparison code to the types of 2287 compares that we have, choosing the branch as necessary. */ 2288 switch (code) 2289 { 2290 case EQ: 2291 case LE: 2292 case LT: 2293 case LEU: 2294 case LTU: 2295 /* We have these compares. */ 2296 branch_code = NE; 2297 break; 2298 2299 case NE: 2300 case GE: 2301 case GT: 2302 case GEU: 2303 case GTU: 2304 /* These must be reversed (except NE, but let's 2305 canonicalize). */ 2306 code = reverse_condition (code); 2307 branch_code = EQ; 2308 break; 2309 2310 default: 2311 gcc_unreachable (); 2312 } 2313 2314 if (cmp_mode != DImode 2315 && CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU)) 2316 { 2317 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op1), SImode); 2318 2319 switch (code) 2320 { 2321 case EQ: 2322 /* Subtract off the value we want to compare against and see 2323 if we get zero. This is cheaper than creating a constant 2324 in a register. Except that subtracting -128 is more 2325 expensive than seqi to -128, so we leave that alone. */ 2326 /* ??? Don't do this when comparing against symbols, 2327 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 == 2328 0), which will be declared false out of hand (at least 2329 for non-weak). */ 2330 if (!(symbolic_operand (op0, VOIDmode) 2331 || (REG_P (op0) && REG_POINTER (op0)))) 2332 { 2333 /* To compare against MIN_INT, we add MIN_INT and check 2334 for 0. */ 2335 HOST_WIDE_INT add; 2336 if (n != -2147483647 - 1) 2337 add = -n; 2338 else 2339 add = n; 2340 2341 op0 = force_reg (SImode, op0); 2342 temp = gen_reg_rtx (SImode); 2343 emit_insn (gen_addsi3 (temp, op0, gen_int_si (add))); 2344 return gen_rtx_fmt_ee (reverse_condition (branch_code), 2345 VOIDmode, temp, const0_rtx); 2346 } 2347 break; 2348 2349 case LEU: 2350 if (n == -1) 2351 break; 2352 /* FALLTHRU */ 2353 2354 case LTU: 2355 /* Change ((unsigned)x < 0x1000) into !((unsigned)x >> 12), 2356 etc. */ 2357 { 2358 int first = exact_log2 (code == LTU ? n : n + 1); 2359 if (first != -1) 2360 { 2361 op0 = force_reg (SImode, op0); 2362 temp = gen_reg_rtx (SImode); 2363 emit_move_insn (temp, 2364 gen_rtx_LSHIFTRT (SImode, op0, 2365 gen_int_si (first))); 2366 return gen_rtx_fmt_ee (reverse_condition (branch_code), 2367 VOIDmode, temp, const0_rtx); 2368 } 2369 } 2370 break; 2371 2372 default: 2373 break; 2374 } 2375 } 2376 2377 /* Compute a flag saying whether we should branch. */ 2378 temp = gen_reg_rtx (SImode); 2379 tilepro_emit_setcc_internal (temp, code, op0, op1, cmp_mode); 2380 2381 /* Return the branch comparison. */ 2382 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx); 2383 } 2384 2385 2386 /* Generate the comparison for a conditional branch. */ 2387 void 2388 tilepro_emit_conditional_branch (rtx operands[], machine_mode cmp_mode) 2389 { 2390 rtx cmp_rtx = 2391 tilepro_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2], 2392 cmp_mode, false); 2393 rtx branch_rtx = gen_rtx_SET (pc_rtx, 2394 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx, 2395 gen_rtx_LABEL_REF 2396 (VOIDmode, 2397 operands[3]), 2398 pc_rtx)); 2399 emit_jump_insn (branch_rtx); 2400 } 2401 2402 2403 /* Implement the movsicc pattern. */ 2404 rtx 2405 tilepro_emit_conditional_move (rtx cmp) 2406 { 2407 return 2408 tilepro_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1), 2409 GET_MODE (XEXP (cmp, 0)), true); 2410 } 2411 2412 2413 /* Return true if INSN is annotated with a REG_BR_PROB note that 2414 indicates it's a branch that's predicted taken. */ 2415 static bool 2416 cbranch_predicted_p (rtx_insn *insn) 2417 { 2418 rtx x = find_reg_note (insn, REG_BR_PROB, 0); 2419 2420 if (x) 2421 { 2422 int pred_val = XINT (x, 0); 2423 2424 return pred_val >= REG_BR_PROB_BASE / 2; 2425 } 2426 2427 return false; 2428 } 2429 2430 2431 /* Output assembly code for a specific branch instruction, appending 2432 the branch prediction flag to the opcode if appropriate. */ 2433 static const char * 2434 tilepro_output_simple_cbranch_with_opcode (rtx_insn *insn, const char *opcode, 2435 int regop, bool netreg_p, 2436 bool reverse_predicted) 2437 { 2438 static char buf[64]; 2439 sprintf (buf, "%s%s\t%%%c%d, %%l0", opcode, 2440 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "", 2441 netreg_p ? 'N' : 'r', regop); 2442 return buf; 2443 } 2444 2445 2446 /* Output assembly code for a specific branch instruction, appending 2447 the branch prediction flag to the opcode if appropriate. */ 2448 const char * 2449 tilepro_output_cbranch_with_opcode (rtx_insn *insn, rtx *operands, 2450 const char *opcode, 2451 const char *rev_opcode, 2452 int regop, bool netreg_p) 2453 { 2454 const char *branch_if_false; 2455 rtx taken, not_taken; 2456 bool is_simple_branch; 2457 2458 gcc_assert (LABEL_P (operands[0])); 2459 2460 is_simple_branch = true; 2461 if (INSN_ADDRESSES_SET_P ()) 2462 { 2463 int from_addr = INSN_ADDRESSES (INSN_UID (insn)); 2464 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0])); 2465 int delta = to_addr - from_addr; 2466 is_simple_branch = IN_RANGE (delta, -524288, 524280); 2467 } 2468 2469 if (is_simple_branch) 2470 { 2471 /* Just a simple conditional branch. */ 2472 return 2473 tilepro_output_simple_cbranch_with_opcode (insn, opcode, regop, 2474 netreg_p, false); 2475 } 2476 2477 /* Generate a reversed branch around a direct jump. This fallback 2478 does not use branch-likely instructions. */ 2479 not_taken = gen_label_rtx (); 2480 taken = operands[0]; 2481 2482 /* Generate the reversed branch to NOT_TAKEN. */ 2483 operands[0] = not_taken; 2484 branch_if_false = 2485 tilepro_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, 2486 netreg_p, true); 2487 output_asm_insn (branch_if_false, operands); 2488 2489 output_asm_insn ("j\t%l0", &taken); 2490 2491 /* Output NOT_TAKEN. */ 2492 targetm.asm_out.internal_label (asm_out_file, "L", 2493 CODE_LABEL_NUMBER (not_taken)); 2494 return ""; 2495 } 2496 2497 2498 /* Output assembly code for a conditional branch instruction. */ 2499 const char * 2500 tilepro_output_cbranch (rtx_insn *insn, rtx *operands, bool reversed) 2501 { 2502 enum rtx_code code = GET_CODE (operands[1]); 2503 const char *opcode; 2504 const char *rev_opcode; 2505 2506 if (reversed) 2507 code = reverse_condition (code); 2508 2509 switch (code) 2510 { 2511 case NE: 2512 opcode = "bnz"; 2513 rev_opcode = "bz"; 2514 break; 2515 case EQ: 2516 opcode = "bz"; 2517 rev_opcode = "bnz"; 2518 break; 2519 case GE: 2520 opcode = "bgez"; 2521 rev_opcode = "blz"; 2522 break; 2523 case GT: 2524 opcode = "bgz"; 2525 rev_opcode = "blez"; 2526 break; 2527 case LE: 2528 opcode = "blez"; 2529 rev_opcode = "bgz"; 2530 break; 2531 case LT: 2532 opcode = "blz"; 2533 rev_opcode = "bgez"; 2534 break; 2535 default: 2536 gcc_unreachable (); 2537 } 2538 2539 return 2540 tilepro_output_cbranch_with_opcode (insn, operands, opcode, rev_opcode, 2541 2, false); 2542 } 2543 2544 2545 /* Implement the tablejump pattern. */ 2546 void 2547 tilepro_expand_tablejump (rtx op0, rtx op1) 2548 { 2549 if (flag_pic) 2550 { 2551 rtx table = gen_rtx_LABEL_REF (Pmode, op1); 2552 rtx temp = gen_reg_rtx (Pmode); 2553 rtx text_label_symbol = tilepro_text_label_symbol (); 2554 rtx text_label_rtx = tilepro_text_label_rtx (); 2555 2556 emit_insn (gen_addli_pcrel (temp, text_label_rtx, 2557 table, text_label_symbol)); 2558 emit_insn (gen_auli_pcrel (temp, temp, table, text_label_symbol)); 2559 emit_move_insn (temp, 2560 gen_rtx_PLUS (Pmode, 2561 convert_to_mode (Pmode, op0, false), 2562 temp)); 2563 op0 = temp; 2564 } 2565 2566 emit_jump_insn (gen_tablejump_aux (op0, op1)); 2567 } 2568 2569 2570 /* Expand a builtin vector binary op, by calling gen function GEN with 2571 operands in the proper modes. DEST is converted to DEST_MODE, and 2572 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */ 2573 void 2574 tilepro_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), 2575 machine_mode dest_mode, 2576 rtx dest, 2577 machine_mode src_mode, 2578 rtx src0, rtx src1, bool do_src1) 2579 { 2580 dest = gen_lowpart (dest_mode, dest); 2581 2582 if (src0 == const0_rtx) 2583 src0 = CONST0_RTX (src_mode); 2584 else 2585 src0 = gen_lowpart (src_mode, src0); 2586 2587 if (do_src1) 2588 { 2589 if (src1 == const0_rtx) 2590 src1 = CONST0_RTX (src_mode); 2591 else 2592 src1 = gen_lowpart (src_mode, src1); 2593 } 2594 2595 emit_insn ((*gen) (dest, src0, src1)); 2596 } 2597 2598 2599 2600 /* Intrinsics */ 2601 2602 struct tile_builtin_info 2603 { 2604 enum insn_code icode; 2605 tree fndecl; 2606 }; 2607 2608 static struct tile_builtin_info tilepro_builtin_info[TILEPRO_BUILTIN_max] = { 2609 { CODE_FOR_addsi3, NULL }, /* add */ 2610 { CODE_FOR_insn_addb, NULL }, /* addb */ 2611 { CODE_FOR_insn_addbs_u, NULL }, /* addbs_u */ 2612 { CODE_FOR_insn_addh, NULL }, /* addh */ 2613 { CODE_FOR_insn_addhs, NULL }, /* addhs */ 2614 { CODE_FOR_insn_addib, NULL }, /* addib */ 2615 { CODE_FOR_insn_addih, NULL }, /* addih */ 2616 { CODE_FOR_insn_addlis, NULL }, /* addlis */ 2617 { CODE_FOR_ssaddsi3, NULL }, /* adds */ 2618 { CODE_FOR_insn_adiffb_u, NULL }, /* adiffb_u */ 2619 { CODE_FOR_insn_adiffh, NULL }, /* adiffh */ 2620 { CODE_FOR_andsi3, NULL }, /* and */ 2621 { CODE_FOR_insn_auli, NULL }, /* auli */ 2622 { CODE_FOR_insn_avgb_u, NULL }, /* avgb_u */ 2623 { CODE_FOR_insn_avgh, NULL }, /* avgh */ 2624 { CODE_FOR_insn_bitx, NULL }, /* bitx */ 2625 { CODE_FOR_bswapsi2, NULL }, /* bytex */ 2626 { CODE_FOR_clzsi2, NULL }, /* clz */ 2627 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */ 2628 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */ 2629 { CODE_FOR_ctzsi2, NULL }, /* ctz */ 2630 { CODE_FOR_insn_drain, NULL }, /* drain */ 2631 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */ 2632 { CODE_FOR_insn_dword_align, NULL }, /* dword_align */ 2633 { CODE_FOR_insn_finv, NULL }, /* finv */ 2634 { CODE_FOR_insn_flush, NULL }, /* flush */ 2635 { CODE_FOR_insn_fnop, NULL }, /* fnop */ 2636 { CODE_FOR_insn_icoh, NULL }, /* icoh */ 2637 { CODE_FOR_insn_ill, NULL }, /* ill */ 2638 { CODE_FOR_insn_info, NULL }, /* info */ 2639 { CODE_FOR_insn_infol, NULL }, /* infol */ 2640 { CODE_FOR_insn_inthb, NULL }, /* inthb */ 2641 { CODE_FOR_insn_inthh, NULL }, /* inthh */ 2642 { CODE_FOR_insn_intlb, NULL }, /* intlb */ 2643 { CODE_FOR_insn_intlh, NULL }, /* intlh */ 2644 { CODE_FOR_insn_inv, NULL }, /* inv */ 2645 { CODE_FOR_insn_lb, NULL }, /* lb */ 2646 { CODE_FOR_insn_lb_u, NULL }, /* lb_u */ 2647 { CODE_FOR_insn_lh, NULL }, /* lh */ 2648 { CODE_FOR_insn_lh_u, NULL }, /* lh_u */ 2649 { CODE_FOR_insn_lnk, NULL }, /* lnk */ 2650 { CODE_FOR_insn_lw, NULL }, /* lw */ 2651 { CODE_FOR_insn_lw_na, NULL }, /* lw_na */ 2652 { CODE_FOR_insn_lb_L2, NULL }, /* lb_L2 */ 2653 { CODE_FOR_insn_lb_u_L2, NULL }, /* lb_u_L2 */ 2654 { CODE_FOR_insn_lh_L2, NULL }, /* lh_L2 */ 2655 { CODE_FOR_insn_lh_u_L2, NULL }, /* lh_u_L2 */ 2656 { CODE_FOR_insn_lw_L2, NULL }, /* lw_L2 */ 2657 { CODE_FOR_insn_lw_na_L2, NULL }, /* lw_na_L2 */ 2658 { CODE_FOR_insn_lb_miss, NULL }, /* lb_miss */ 2659 { CODE_FOR_insn_lb_u_miss, NULL }, /* lb_u_miss */ 2660 { CODE_FOR_insn_lh_miss, NULL }, /* lh_miss */ 2661 { CODE_FOR_insn_lh_u_miss, NULL }, /* lh_u_miss */ 2662 { CODE_FOR_insn_lw_miss, NULL }, /* lw_miss */ 2663 { CODE_FOR_insn_lw_na_miss, NULL }, /* lw_na_miss */ 2664 { CODE_FOR_insn_maxb_u, NULL }, /* maxb_u */ 2665 { CODE_FOR_insn_maxh, NULL }, /* maxh */ 2666 { CODE_FOR_insn_maxib_u, NULL }, /* maxib_u */ 2667 { CODE_FOR_insn_maxih, NULL }, /* maxih */ 2668 { CODE_FOR_memory_barrier, NULL }, /* mf */ 2669 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */ 2670 { CODE_FOR_insn_minb_u, NULL }, /* minb_u */ 2671 { CODE_FOR_insn_minh, NULL }, /* minh */ 2672 { CODE_FOR_insn_minib_u, NULL }, /* minib_u */ 2673 { CODE_FOR_insn_minih, NULL }, /* minih */ 2674 { CODE_FOR_insn_mm, NULL }, /* mm */ 2675 { CODE_FOR_insn_mnz, NULL }, /* mnz */ 2676 { CODE_FOR_insn_mnzb, NULL }, /* mnzb */ 2677 { CODE_FOR_insn_mnzh, NULL }, /* mnzh */ 2678 { CODE_FOR_movsi, NULL }, /* move */ 2679 { CODE_FOR_insn_movelis, NULL }, /* movelis */ 2680 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */ 2681 { CODE_FOR_insn_mulhh_ss, NULL }, /* mulhh_ss */ 2682 { CODE_FOR_insn_mulhh_su, NULL }, /* mulhh_su */ 2683 { CODE_FOR_insn_mulhh_uu, NULL }, /* mulhh_uu */ 2684 { CODE_FOR_insn_mulhha_ss, NULL }, /* mulhha_ss */ 2685 { CODE_FOR_insn_mulhha_su, NULL }, /* mulhha_su */ 2686 { CODE_FOR_insn_mulhha_uu, NULL }, /* mulhha_uu */ 2687 { CODE_FOR_insn_mulhhsa_uu, NULL }, /* mulhhsa_uu */ 2688 { CODE_FOR_insn_mulhl_ss, NULL }, /* mulhl_ss */ 2689 { CODE_FOR_insn_mulhl_su, NULL }, /* mulhl_su */ 2690 { CODE_FOR_insn_mulhl_us, NULL }, /* mulhl_us */ 2691 { CODE_FOR_insn_mulhl_uu, NULL }, /* mulhl_uu */ 2692 { CODE_FOR_insn_mulhla_ss, NULL }, /* mulhla_ss */ 2693 { CODE_FOR_insn_mulhla_su, NULL }, /* mulhla_su */ 2694 { CODE_FOR_insn_mulhla_us, NULL }, /* mulhla_us */ 2695 { CODE_FOR_insn_mulhla_uu, NULL }, /* mulhla_uu */ 2696 { CODE_FOR_insn_mulhlsa_uu, NULL }, /* mulhlsa_uu */ 2697 { CODE_FOR_insn_mulll_ss, NULL }, /* mulll_ss */ 2698 { CODE_FOR_insn_mulll_su, NULL }, /* mulll_su */ 2699 { CODE_FOR_insn_mulll_uu, NULL }, /* mulll_uu */ 2700 { CODE_FOR_insn_mullla_ss, NULL }, /* mullla_ss */ 2701 { CODE_FOR_insn_mullla_su, NULL }, /* mullla_su */ 2702 { CODE_FOR_insn_mullla_uu, NULL }, /* mullla_uu */ 2703 { CODE_FOR_insn_mulllsa_uu, NULL }, /* mulllsa_uu */ 2704 { CODE_FOR_insn_mvnz, NULL }, /* mvnz */ 2705 { CODE_FOR_insn_mvz, NULL }, /* mvz */ 2706 { CODE_FOR_insn_mz, NULL }, /* mz */ 2707 { CODE_FOR_insn_mzb, NULL }, /* mzb */ 2708 { CODE_FOR_insn_mzh, NULL }, /* mzh */ 2709 { CODE_FOR_insn_nap, NULL }, /* nap */ 2710 { CODE_FOR_nop, NULL }, /* nop */ 2711 { CODE_FOR_insn_nor, NULL }, /* nor */ 2712 { CODE_FOR_iorsi3, NULL }, /* or */ 2713 { CODE_FOR_insn_packbs_u, NULL }, /* packbs_u */ 2714 { CODE_FOR_insn_packhb, NULL }, /* packhb */ 2715 { CODE_FOR_insn_packhs, NULL }, /* packhs */ 2716 { CODE_FOR_insn_packlb, NULL }, /* packlb */ 2717 { CODE_FOR_popcountsi2, NULL }, /* pcnt */ 2718 { CODE_FOR_insn_prefetch, NULL }, /* prefetch */ 2719 { CODE_FOR_insn_prefetch_L1, NULL }, /* prefetch_L1 */ 2720 { CODE_FOR_rotlsi3, NULL }, /* rl */ 2721 { CODE_FOR_insn_s1a, NULL }, /* s1a */ 2722 { CODE_FOR_insn_s2a, NULL }, /* s2a */ 2723 { CODE_FOR_insn_s3a, NULL }, /* s3a */ 2724 { CODE_FOR_insn_sadab_u, NULL }, /* sadab_u */ 2725 { CODE_FOR_insn_sadah, NULL }, /* sadah */ 2726 { CODE_FOR_insn_sadah_u, NULL }, /* sadah_u */ 2727 { CODE_FOR_insn_sadb_u, NULL }, /* sadb_u */ 2728 { CODE_FOR_insn_sadh, NULL }, /* sadh */ 2729 { CODE_FOR_insn_sadh_u, NULL }, /* sadh_u */ 2730 { CODE_FOR_insn_sb, NULL }, /* sb */ 2731 { CODE_FOR_insn_seq, NULL }, /* seq */ 2732 { CODE_FOR_insn_seqb, NULL }, /* seqb */ 2733 { CODE_FOR_insn_seqh, NULL }, /* seqh */ 2734 { CODE_FOR_insn_seqib, NULL }, /* seqib */ 2735 { CODE_FOR_insn_seqih, NULL }, /* seqih */ 2736 { CODE_FOR_insn_sh, NULL }, /* sh */ 2737 { CODE_FOR_ashlsi3, NULL }, /* shl */ 2738 { CODE_FOR_insn_shlb, NULL }, /* shlb */ 2739 { CODE_FOR_insn_shlh, NULL }, /* shlh */ 2740 { CODE_FOR_insn_shlb, NULL }, /* shlib */ 2741 { CODE_FOR_insn_shlh, NULL }, /* shlih */ 2742 { CODE_FOR_lshrsi3, NULL }, /* shr */ 2743 { CODE_FOR_insn_shrb, NULL }, /* shrb */ 2744 { CODE_FOR_insn_shrh, NULL }, /* shrh */ 2745 { CODE_FOR_insn_shrb, NULL }, /* shrib */ 2746 { CODE_FOR_insn_shrh, NULL }, /* shrih */ 2747 { CODE_FOR_insn_slt, NULL }, /* slt */ 2748 { CODE_FOR_insn_slt_u, NULL }, /* slt_u */ 2749 { CODE_FOR_insn_sltb, NULL }, /* sltb */ 2750 { CODE_FOR_insn_sltb_u, NULL }, /* sltb_u */ 2751 { CODE_FOR_insn_slte, NULL }, /* slte */ 2752 { CODE_FOR_insn_slte_u, NULL }, /* slte_u */ 2753 { CODE_FOR_insn_slteb, NULL }, /* slteb */ 2754 { CODE_FOR_insn_slteb_u, NULL }, /* slteb_u */ 2755 { CODE_FOR_insn_slteh, NULL }, /* slteh */ 2756 { CODE_FOR_insn_slteh_u, NULL }, /* slteh_u */ 2757 { CODE_FOR_insn_slth, NULL }, /* slth */ 2758 { CODE_FOR_insn_slth_u, NULL }, /* slth_u */ 2759 { CODE_FOR_insn_sltib, NULL }, /* sltib */ 2760 { CODE_FOR_insn_sltib_u, NULL }, /* sltib_u */ 2761 { CODE_FOR_insn_sltih, NULL }, /* sltih */ 2762 { CODE_FOR_insn_sltih_u, NULL }, /* sltih_u */ 2763 { CODE_FOR_insn_sne, NULL }, /* sne */ 2764 { CODE_FOR_insn_sneb, NULL }, /* sneb */ 2765 { CODE_FOR_insn_sneh, NULL }, /* sneh */ 2766 { CODE_FOR_ashrsi3, NULL }, /* sra */ 2767 { CODE_FOR_insn_srab, NULL }, /* srab */ 2768 { CODE_FOR_insn_srah, NULL }, /* srah */ 2769 { CODE_FOR_insn_srab, NULL }, /* sraib */ 2770 { CODE_FOR_insn_srah, NULL }, /* sraih */ 2771 { CODE_FOR_subsi3, NULL }, /* sub */ 2772 { CODE_FOR_insn_subb, NULL }, /* subb */ 2773 { CODE_FOR_insn_subbs_u, NULL }, /* subbs_u */ 2774 { CODE_FOR_insn_subh, NULL }, /* subh */ 2775 { CODE_FOR_insn_subhs, NULL }, /* subhs */ 2776 { CODE_FOR_sssubsi3, NULL }, /* subs */ 2777 { CODE_FOR_insn_sw, NULL }, /* sw */ 2778 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */ 2779 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */ 2780 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */ 2781 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */ 2782 { CODE_FOR_insn_tns, NULL }, /* tns */ 2783 { CODE_FOR_insn_wh64, NULL }, /* wh64 */ 2784 { CODE_FOR_xorsi3, NULL }, /* xor */ 2785 { CODE_FOR_tilepro_network_barrier, NULL }, /* network_barrier */ 2786 { CODE_FOR_tilepro_idn0_receive, NULL }, /* idn0_receive */ 2787 { CODE_FOR_tilepro_idn1_receive, NULL }, /* idn1_receive */ 2788 { CODE_FOR_tilepro_idn_send, NULL }, /* idn_send */ 2789 { CODE_FOR_tilepro_sn_receive, NULL }, /* sn_receive */ 2790 { CODE_FOR_tilepro_sn_send, NULL }, /* sn_send */ 2791 { CODE_FOR_tilepro_udn0_receive, NULL }, /* udn0_receive */ 2792 { CODE_FOR_tilepro_udn1_receive, NULL }, /* udn1_receive */ 2793 { CODE_FOR_tilepro_udn2_receive, NULL }, /* udn2_receive */ 2794 { CODE_FOR_tilepro_udn3_receive, NULL }, /* udn3_receive */ 2795 { CODE_FOR_tilepro_udn_send, NULL }, /* udn_send */ 2796 }; 2797 2798 2799 struct tilepro_builtin_def 2800 { 2801 const char *name; 2802 enum tilepro_builtin code; 2803 bool is_const; 2804 /* The first character is the return type. Subsequent characters 2805 are the argument types. See char_to_type. */ 2806 const char *type; 2807 }; 2808 2809 2810 static const struct tilepro_builtin_def tilepro_builtins[] = { 2811 { "__insn_add", TILEPRO_INSN_ADD, true, "lll" }, 2812 { "__insn_addb", TILEPRO_INSN_ADDB, true, "lll" }, 2813 { "__insn_addbs_u", TILEPRO_INSN_ADDBS_U, false, "lll" }, 2814 { "__insn_addh", TILEPRO_INSN_ADDH, true, "lll" }, 2815 { "__insn_addhs", TILEPRO_INSN_ADDHS, false, "lll" }, 2816 { "__insn_addi", TILEPRO_INSN_ADD, true, "lll" }, 2817 { "__insn_addib", TILEPRO_INSN_ADDIB, true, "lll" }, 2818 { "__insn_addih", TILEPRO_INSN_ADDIH, true, "lll" }, 2819 { "__insn_addli", TILEPRO_INSN_ADD, true, "lll" }, 2820 { "__insn_addlis", TILEPRO_INSN_ADDLIS, false, "lll" }, 2821 { "__insn_adds", TILEPRO_INSN_ADDS, false, "lll" }, 2822 { "__insn_adiffb_u", TILEPRO_INSN_ADIFFB_U, true, "lll" }, 2823 { "__insn_adiffh", TILEPRO_INSN_ADIFFH, true, "lll" }, 2824 { "__insn_and", TILEPRO_INSN_AND, true, "lll" }, 2825 { "__insn_andi", TILEPRO_INSN_AND, true, "lll" }, 2826 { "__insn_auli", TILEPRO_INSN_AULI, true, "lll" }, 2827 { "__insn_avgb_u", TILEPRO_INSN_AVGB_U, true, "lll" }, 2828 { "__insn_avgh", TILEPRO_INSN_AVGH, true, "lll" }, 2829 { "__insn_bitx", TILEPRO_INSN_BITX, true, "ll" }, 2830 { "__insn_bytex", TILEPRO_INSN_BYTEX, true, "ll" }, 2831 { "__insn_clz", TILEPRO_INSN_CLZ, true, "ll" }, 2832 { "__insn_crc32_32", TILEPRO_INSN_CRC32_32, true, "lll" }, 2833 { "__insn_crc32_8", TILEPRO_INSN_CRC32_8, true, "lll" }, 2834 { "__insn_ctz", TILEPRO_INSN_CTZ, true, "ll" }, 2835 { "__insn_drain", TILEPRO_INSN_DRAIN, false, "v" }, 2836 { "__insn_dtlbpr", TILEPRO_INSN_DTLBPR, false, "vl" }, 2837 { "__insn_dword_align", TILEPRO_INSN_DWORD_ALIGN, true, "lllk" }, 2838 { "__insn_finv", TILEPRO_INSN_FINV, false, "vk" }, 2839 { "__insn_flush", TILEPRO_INSN_FLUSH, false, "vk" }, 2840 { "__insn_fnop", TILEPRO_INSN_FNOP, false, "v" }, 2841 { "__insn_icoh", TILEPRO_INSN_ICOH, false, "vk" }, 2842 { "__insn_ill", TILEPRO_INSN_ILL, false, "v" }, 2843 { "__insn_info", TILEPRO_INSN_INFO, false, "vl" }, 2844 { "__insn_infol", TILEPRO_INSN_INFOL, false, "vl" }, 2845 { "__insn_inthb", TILEPRO_INSN_INTHB, true, "lll" }, 2846 { "__insn_inthh", TILEPRO_INSN_INTHH, true, "lll" }, 2847 { "__insn_intlb", TILEPRO_INSN_INTLB, true, "lll" }, 2848 { "__insn_intlh", TILEPRO_INSN_INTLH, true, "lll" }, 2849 { "__insn_inv", TILEPRO_INSN_INV, false, "vp" }, 2850 { "__insn_lb", TILEPRO_INSN_LB, false, "lk" }, 2851 { "__insn_lb_u", TILEPRO_INSN_LB_U, false, "lk" }, 2852 { "__insn_lh", TILEPRO_INSN_LH, false, "lk" }, 2853 { "__insn_lh_u", TILEPRO_INSN_LH_U, false, "lk" }, 2854 { "__insn_lnk", TILEPRO_INSN_LNK, true, "l" }, 2855 { "__insn_lw", TILEPRO_INSN_LW, false, "lk" }, 2856 { "__insn_lw_na", TILEPRO_INSN_LW_NA, false, "lk" }, 2857 { "__insn_lb_L2", TILEPRO_INSN_LB_L2, false, "lk" }, 2858 { "__insn_lb_u_L2", TILEPRO_INSN_LB_U_L2, false, "lk" }, 2859 { "__insn_lh_L2", TILEPRO_INSN_LH_L2, false, "lk" }, 2860 { "__insn_lh_u_L2", TILEPRO_INSN_LH_U_L2, false, "lk" }, 2861 { "__insn_lw_L2", TILEPRO_INSN_LW_L2, false, "lk" }, 2862 { "__insn_lw_na_L2", TILEPRO_INSN_LW_NA_L2, false, "lk" }, 2863 { "__insn_lb_miss", TILEPRO_INSN_LB_MISS, false, "lk" }, 2864 { "__insn_lb_u_miss", TILEPRO_INSN_LB_U_MISS, false, "lk" }, 2865 { "__insn_lh_miss", TILEPRO_INSN_LH_MISS, false, "lk" }, 2866 { "__insn_lh_u_miss", TILEPRO_INSN_LH_U_MISS, false, "lk" }, 2867 { "__insn_lw_miss", TILEPRO_INSN_LW_MISS, false, "lk" }, 2868 { "__insn_lw_na_miss", TILEPRO_INSN_LW_NA_MISS, false, "lk" }, 2869 { "__insn_maxb_u", TILEPRO_INSN_MAXB_U, true, "lll" }, 2870 { "__insn_maxh", TILEPRO_INSN_MAXH, true, "lll" }, 2871 { "__insn_maxib_u", TILEPRO_INSN_MAXIB_U, true, "lll" }, 2872 { "__insn_maxih", TILEPRO_INSN_MAXIH, true, "lll" }, 2873 { "__insn_mf", TILEPRO_INSN_MF, false, "v" }, 2874 { "__insn_mfspr", TILEPRO_INSN_MFSPR, false, "ll" }, 2875 { "__insn_minb_u", TILEPRO_INSN_MINB_U, true, "lll" }, 2876 { "__insn_minh", TILEPRO_INSN_MINH, true, "lll" }, 2877 { "__insn_minib_u", TILEPRO_INSN_MINIB_U, true, "lll" }, 2878 { "__insn_minih", TILEPRO_INSN_MINIH, true, "lll" }, 2879 { "__insn_mm", TILEPRO_INSN_MM, true, "lllll" }, 2880 { "__insn_mnz", TILEPRO_INSN_MNZ, true, "lll" }, 2881 { "__insn_mnzb", TILEPRO_INSN_MNZB, true, "lll" }, 2882 { "__insn_mnzh", TILEPRO_INSN_MNZH, true, "lll" }, 2883 { "__insn_move", TILEPRO_INSN_MOVE, true, "ll" }, 2884 { "__insn_movei", TILEPRO_INSN_MOVE, true, "ll" }, 2885 { "__insn_moveli", TILEPRO_INSN_MOVE, true, "ll" }, 2886 { "__insn_movelis", TILEPRO_INSN_MOVELIS, false, "ll" }, 2887 { "__insn_mtspr", TILEPRO_INSN_MTSPR, false, "vll" }, 2888 { "__insn_mulhh_ss", TILEPRO_INSN_MULHH_SS, true, "lll" }, 2889 { "__insn_mulhh_su", TILEPRO_INSN_MULHH_SU, true, "lll" }, 2890 { "__insn_mulhh_uu", TILEPRO_INSN_MULHH_UU, true, "lll" }, 2891 { "__insn_mulhha_ss", TILEPRO_INSN_MULHHA_SS, true, "llll" }, 2892 { "__insn_mulhha_su", TILEPRO_INSN_MULHHA_SU, true, "llll" }, 2893 { "__insn_mulhha_uu", TILEPRO_INSN_MULHHA_UU, true, "llll" }, 2894 { "__insn_mulhhsa_uu", TILEPRO_INSN_MULHHSA_UU, true, "llll" }, 2895 { "__insn_mulhl_ss", TILEPRO_INSN_MULHL_SS, true, "lll" }, 2896 { "__insn_mulhl_su", TILEPRO_INSN_MULHL_SU, true, "lll" }, 2897 { "__insn_mulhl_us", TILEPRO_INSN_MULHL_US, true, "lll" }, 2898 { "__insn_mulhl_uu", TILEPRO_INSN_MULHL_UU, true, "lll" }, 2899 { "__insn_mulhla_ss", TILEPRO_INSN_MULHLA_SS, true, "llll" }, 2900 { "__insn_mulhla_su", TILEPRO_INSN_MULHLA_SU, true, "llll" }, 2901 { "__insn_mulhla_us", TILEPRO_INSN_MULHLA_US, true, "llll" }, 2902 { "__insn_mulhla_uu", TILEPRO_INSN_MULHLA_UU, true, "llll" }, 2903 { "__insn_mulhlsa_uu", TILEPRO_INSN_MULHLSA_UU, true, "llll" }, 2904 { "__insn_mulll_ss", TILEPRO_INSN_MULLL_SS, true, "lll" }, 2905 { "__insn_mulll_su", TILEPRO_INSN_MULLL_SU, true, "lll" }, 2906 { "__insn_mulll_uu", TILEPRO_INSN_MULLL_UU, true, "lll" }, 2907 { "__insn_mullla_ss", TILEPRO_INSN_MULLLA_SS, true, "llll" }, 2908 { "__insn_mullla_su", TILEPRO_INSN_MULLLA_SU, true, "llll" }, 2909 { "__insn_mullla_uu", TILEPRO_INSN_MULLLA_UU, true, "llll" }, 2910 { "__insn_mulllsa_uu", TILEPRO_INSN_MULLLSA_UU, true, "llll" }, 2911 { "__insn_mvnz", TILEPRO_INSN_MVNZ, true, "llll" }, 2912 { "__insn_mvz", TILEPRO_INSN_MVZ, true, "llll" }, 2913 { "__insn_mz", TILEPRO_INSN_MZ, true, "lll" }, 2914 { "__insn_mzb", TILEPRO_INSN_MZB, true, "lll" }, 2915 { "__insn_mzh", TILEPRO_INSN_MZH, true, "lll" }, 2916 { "__insn_nap", TILEPRO_INSN_NAP, false, "v" }, 2917 { "__insn_nop", TILEPRO_INSN_NOP, true, "v" }, 2918 { "__insn_nor", TILEPRO_INSN_NOR, true, "lll" }, 2919 { "__insn_or", TILEPRO_INSN_OR, true, "lll" }, 2920 { "__insn_ori", TILEPRO_INSN_OR, true, "lll" }, 2921 { "__insn_packbs_u", TILEPRO_INSN_PACKBS_U, false, "lll" }, 2922 { "__insn_packhb", TILEPRO_INSN_PACKHB, true, "lll" }, 2923 { "__insn_packhs", TILEPRO_INSN_PACKHS, false, "lll" }, 2924 { "__insn_packlb", TILEPRO_INSN_PACKLB, true, "lll" }, 2925 { "__insn_pcnt", TILEPRO_INSN_PCNT, true, "ll" }, 2926 { "__insn_prefetch", TILEPRO_INSN_PREFETCH, false, "vk" }, 2927 { "__insn_prefetch_L1", TILEPRO_INSN_PREFETCH_L1, false, "vk" }, 2928 { "__insn_rl", TILEPRO_INSN_RL, true, "lll" }, 2929 { "__insn_rli", TILEPRO_INSN_RL, true, "lll" }, 2930 { "__insn_s1a", TILEPRO_INSN_S1A, true, "lll" }, 2931 { "__insn_s2a", TILEPRO_INSN_S2A, true, "lll" }, 2932 { "__insn_s3a", TILEPRO_INSN_S3A, true, "lll" }, 2933 { "__insn_sadab_u", TILEPRO_INSN_SADAB_U, true, "llll" }, 2934 { "__insn_sadah", TILEPRO_INSN_SADAH, true, "llll" }, 2935 { "__insn_sadah_u", TILEPRO_INSN_SADAH_U, true, "llll" }, 2936 { "__insn_sadb_u", TILEPRO_INSN_SADB_U, true, "lll" }, 2937 { "__insn_sadh", TILEPRO_INSN_SADH, true, "lll" }, 2938 { "__insn_sadh_u", TILEPRO_INSN_SADH_U, true, "lll" }, 2939 { "__insn_sb", TILEPRO_INSN_SB, false, "vpl" }, 2940 { "__insn_seq", TILEPRO_INSN_SEQ, true, "lll" }, 2941 { "__insn_seqb", TILEPRO_INSN_SEQB, true, "lll" }, 2942 { "__insn_seqh", TILEPRO_INSN_SEQH, true, "lll" }, 2943 { "__insn_seqi", TILEPRO_INSN_SEQ, true, "lll" }, 2944 { "__insn_seqib", TILEPRO_INSN_SEQIB, true, "lll" }, 2945 { "__insn_seqih", TILEPRO_INSN_SEQIH, true, "lll" }, 2946 { "__insn_sh", TILEPRO_INSN_SH, false, "vpl" }, 2947 { "__insn_shl", TILEPRO_INSN_SHL, true, "lll" }, 2948 { "__insn_shlb", TILEPRO_INSN_SHLB, true, "lll" }, 2949 { "__insn_shlh", TILEPRO_INSN_SHLH, true, "lll" }, 2950 { "__insn_shli", TILEPRO_INSN_SHL, true, "lll" }, 2951 { "__insn_shlib", TILEPRO_INSN_SHLIB, true, "lll" }, 2952 { "__insn_shlih", TILEPRO_INSN_SHLIH, true, "lll" }, 2953 { "__insn_shr", TILEPRO_INSN_SHR, true, "lll" }, 2954 { "__insn_shrb", TILEPRO_INSN_SHRB, true, "lll" }, 2955 { "__insn_shrh", TILEPRO_INSN_SHRH, true, "lll" }, 2956 { "__insn_shri", TILEPRO_INSN_SHR, true, "lll" }, 2957 { "__insn_shrib", TILEPRO_INSN_SHRIB, true, "lll" }, 2958 { "__insn_shrih", TILEPRO_INSN_SHRIH, true, "lll" }, 2959 { "__insn_slt", TILEPRO_INSN_SLT, true, "lll" }, 2960 { "__insn_slt_u", TILEPRO_INSN_SLT_U, true, "lll" }, 2961 { "__insn_sltb", TILEPRO_INSN_SLTB, true, "lll" }, 2962 { "__insn_sltb_u", TILEPRO_INSN_SLTB_U, true, "lll" }, 2963 { "__insn_slte", TILEPRO_INSN_SLTE, true, "lll" }, 2964 { "__insn_slte_u", TILEPRO_INSN_SLTE_U, true, "lll" }, 2965 { "__insn_slteb", TILEPRO_INSN_SLTEB, true, "lll" }, 2966 { "__insn_slteb_u", TILEPRO_INSN_SLTEB_U, true, "lll" }, 2967 { "__insn_slteh", TILEPRO_INSN_SLTEH, true, "lll" }, 2968 { "__insn_slteh_u", TILEPRO_INSN_SLTEH_U, true, "lll" }, 2969 { "__insn_slth", TILEPRO_INSN_SLTH, true, "lll" }, 2970 { "__insn_slth_u", TILEPRO_INSN_SLTH_U, true, "lll" }, 2971 { "__insn_slti", TILEPRO_INSN_SLT, true, "lll" }, 2972 { "__insn_slti_u", TILEPRO_INSN_SLT_U, true, "lll" }, 2973 { "__insn_sltib", TILEPRO_INSN_SLTIB, true, "lll" }, 2974 { "__insn_sltib_u", TILEPRO_INSN_SLTIB_U, true, "lll" }, 2975 { "__insn_sltih", TILEPRO_INSN_SLTIH, true, "lll" }, 2976 { "__insn_sltih_u", TILEPRO_INSN_SLTIH_U, true, "lll" }, 2977 { "__insn_sne", TILEPRO_INSN_SNE, true, "lll" }, 2978 { "__insn_sneb", TILEPRO_INSN_SNEB, true, "lll" }, 2979 { "__insn_sneh", TILEPRO_INSN_SNEH, true, "lll" }, 2980 { "__insn_sra", TILEPRO_INSN_SRA, true, "lll" }, 2981 { "__insn_srab", TILEPRO_INSN_SRAB, true, "lll" }, 2982 { "__insn_srah", TILEPRO_INSN_SRAH, true, "lll" }, 2983 { "__insn_srai", TILEPRO_INSN_SRA, true, "lll" }, 2984 { "__insn_sraib", TILEPRO_INSN_SRAIB, true, "lll" }, 2985 { "__insn_sraih", TILEPRO_INSN_SRAIH, true, "lll" }, 2986 { "__insn_sub", TILEPRO_INSN_SUB, true, "lll" }, 2987 { "__insn_subb", TILEPRO_INSN_SUBB, true, "lll" }, 2988 { "__insn_subbs_u", TILEPRO_INSN_SUBBS_U, false, "lll" }, 2989 { "__insn_subh", TILEPRO_INSN_SUBH, true, "lll" }, 2990 { "__insn_subhs", TILEPRO_INSN_SUBHS, false, "lll" }, 2991 { "__insn_subs", TILEPRO_INSN_SUBS, false, "lll" }, 2992 { "__insn_sw", TILEPRO_INSN_SW, false, "vpl" }, 2993 { "__insn_tblidxb0", TILEPRO_INSN_TBLIDXB0, true, "lll" }, 2994 { "__insn_tblidxb1", TILEPRO_INSN_TBLIDXB1, true, "lll" }, 2995 { "__insn_tblidxb2", TILEPRO_INSN_TBLIDXB2, true, "lll" }, 2996 { "__insn_tblidxb3", TILEPRO_INSN_TBLIDXB3, true, "lll" }, 2997 { "__insn_tns", TILEPRO_INSN_TNS, false, "lp" }, 2998 { "__insn_wh64", TILEPRO_INSN_WH64, false, "vp" }, 2999 { "__insn_xor", TILEPRO_INSN_XOR, true, "lll" }, 3000 { "__insn_xori", TILEPRO_INSN_XOR, true, "lll" }, 3001 { "__tile_network_barrier", TILEPRO_NETWORK_BARRIER, false, "v" }, 3002 { "__tile_idn0_receive", TILEPRO_IDN0_RECEIVE, false, "l" }, 3003 { "__tile_idn1_receive", TILEPRO_IDN1_RECEIVE, false, "l" }, 3004 { "__tile_idn_send", TILEPRO_IDN_SEND, false, "vl" }, 3005 { "__tile_sn_receive", TILEPRO_SN_RECEIVE, false, "l" }, 3006 { "__tile_sn_send", TILEPRO_SN_SEND, false, "vl" }, 3007 { "__tile_udn0_receive", TILEPRO_UDN0_RECEIVE, false, "l" }, 3008 { "__tile_udn1_receive", TILEPRO_UDN1_RECEIVE, false, "l" }, 3009 { "__tile_udn2_receive", TILEPRO_UDN2_RECEIVE, false, "l" }, 3010 { "__tile_udn3_receive", TILEPRO_UDN3_RECEIVE, false, "l" }, 3011 { "__tile_udn_send", TILEPRO_UDN_SEND, false, "vl" }, 3012 }; 3013 3014 3015 /* Convert a character in a builtin type string to a tree type. */ 3016 static tree 3017 char_to_type (char c) 3018 { 3019 static tree volatile_ptr_type_node = NULL; 3020 static tree volatile_const_ptr_type_node = NULL; 3021 3022 if (volatile_ptr_type_node == NULL) 3023 { 3024 volatile_ptr_type_node = 3025 build_pointer_type (build_qualified_type (void_type_node, 3026 TYPE_QUAL_VOLATILE)); 3027 volatile_const_ptr_type_node = 3028 build_pointer_type (build_qualified_type (void_type_node, 3029 TYPE_QUAL_CONST 3030 | TYPE_QUAL_VOLATILE)); 3031 } 3032 3033 switch (c) 3034 { 3035 case 'v': 3036 return void_type_node; 3037 case 'l': 3038 return long_unsigned_type_node; 3039 case 'p': 3040 return volatile_ptr_type_node; 3041 case 'k': 3042 return volatile_const_ptr_type_node; 3043 default: 3044 gcc_unreachable (); 3045 } 3046 } 3047 3048 3049 /* Implement TARGET_INIT_BUILTINS. */ 3050 static void 3051 tilepro_init_builtins (void) 3052 { 3053 size_t i; 3054 3055 for (i = 0; i < ARRAY_SIZE (tilepro_builtins); i++) 3056 { 3057 const struct tilepro_builtin_def *p = &tilepro_builtins[i]; 3058 tree ftype, ret_type, arg_type_list = void_list_node; 3059 tree decl; 3060 int j; 3061 3062 for (j = strlen (p->type) - 1; j > 0; j--) 3063 { 3064 arg_type_list = 3065 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list); 3066 } 3067 3068 ret_type = char_to_type (p->type[0]); 3069 3070 ftype = build_function_type (ret_type, arg_type_list); 3071 3072 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD, 3073 NULL, NULL); 3074 3075 if (p->is_const) 3076 TREE_READONLY (decl) = 1; 3077 TREE_NOTHROW (decl) = 1; 3078 3079 if (tilepro_builtin_info[p->code].fndecl == NULL) 3080 tilepro_builtin_info[p->code].fndecl = decl; 3081 } 3082 } 3083 3084 3085 /* Implement TARGET_EXPAND_BUILTIN. */ 3086 static rtx 3087 tilepro_expand_builtin (tree exp, 3088 rtx target, 3089 rtx subtarget ATTRIBUTE_UNUSED, 3090 machine_mode mode ATTRIBUTE_UNUSED, 3091 int ignore ATTRIBUTE_UNUSED) 3092 { 3093 #define MAX_BUILTIN_ARGS 4 3094 3095 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); 3096 unsigned int fcode = DECL_FUNCTION_CODE (fndecl); 3097 tree arg; 3098 call_expr_arg_iterator iter; 3099 enum insn_code icode; 3100 rtx op[MAX_BUILTIN_ARGS + 1], pat; 3101 int opnum; 3102 bool nonvoid; 3103 insn_gen_fn fn; 3104 3105 if (fcode >= TILEPRO_BUILTIN_max) 3106 internal_error ("bad builtin fcode"); 3107 icode = tilepro_builtin_info[fcode].icode; 3108 if (icode == 0) 3109 internal_error ("bad builtin icode"); 3110 3111 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; 3112 3113 opnum = nonvoid; 3114 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) 3115 { 3116 const struct insn_operand_data *insn_op; 3117 3118 if (arg == error_mark_node) 3119 return NULL_RTX; 3120 if (opnum > MAX_BUILTIN_ARGS) 3121 return NULL_RTX; 3122 3123 insn_op = &insn_data[icode].operand[opnum]; 3124 3125 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL); 3126 3127 if (!(*insn_op->predicate) (op[opnum], insn_op->mode)) 3128 op[opnum] = copy_to_mode_reg (insn_op->mode, op[opnum]); 3129 3130 if (!(*insn_op->predicate) (op[opnum], insn_op->mode)) 3131 { 3132 /* We still failed to meet the predicate even after moving 3133 into a register. Assume we needed an immediate. */ 3134 error_at (EXPR_LOCATION (exp), 3135 "operand must be an immediate of the right size"); 3136 return const0_rtx; 3137 } 3138 3139 opnum++; 3140 } 3141 3142 if (nonvoid) 3143 { 3144 machine_mode tmode = insn_data[icode].operand[0].mode; 3145 if (!target 3146 || GET_MODE (target) != tmode 3147 || !(*insn_data[icode].operand[0].predicate) (target, tmode)) 3148 target = gen_reg_rtx (tmode); 3149 op[0] = target; 3150 } 3151 3152 fn = GEN_FCN (icode); 3153 switch (opnum) 3154 { 3155 case 0: 3156 pat = fn (NULL_RTX); 3157 break; 3158 case 1: 3159 pat = fn (op[0]); 3160 break; 3161 case 2: 3162 pat = fn (op[0], op[1]); 3163 break; 3164 case 3: 3165 pat = fn (op[0], op[1], op[2]); 3166 break; 3167 case 4: 3168 pat = fn (op[0], op[1], op[2], op[3]); 3169 break; 3170 case 5: 3171 pat = fn (op[0], op[1], op[2], op[3], op[4]); 3172 break; 3173 default: 3174 gcc_unreachable (); 3175 } 3176 if (!pat) 3177 return NULL_RTX; 3178 3179 /* If we are generating a prefetch, tell the scheduler not to move 3180 it around. */ 3181 if (GET_CODE (pat) == PREFETCH) 3182 PREFETCH_SCHEDULE_BARRIER_P (pat) = true; 3183 3184 emit_insn (pat); 3185 3186 if (nonvoid) 3187 return target; 3188 else 3189 return const0_rtx; 3190 } 3191 3192 3193 /* Implement TARGET_BUILTIN_DECL. */ 3194 static tree 3195 tilepro_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) 3196 { 3197 if (code >= TILEPRO_BUILTIN_max) 3198 return error_mark_node; 3199 3200 return tilepro_builtin_info[code].fndecl; 3201 } 3202 3203 3204 3205 /* Stack frames */ 3206 3207 /* Return whether REGNO needs to be saved in the stack frame. */ 3208 static bool 3209 need_to_save_reg (unsigned int regno) 3210 { 3211 if (!fixed_regs[regno] && !call_used_regs[regno] 3212 && df_regs_ever_live_p (regno)) 3213 return true; 3214 3215 if (flag_pic 3216 && (regno == PIC_OFFSET_TABLE_REGNUM 3217 || regno == TILEPRO_PIC_TEXT_LABEL_REGNUM) 3218 && (crtl->uses_pic_offset_table || crtl->saves_all_registers)) 3219 return true; 3220 3221 if (crtl->calls_eh_return) 3222 { 3223 unsigned i; 3224 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++) 3225 { 3226 if (regno == EH_RETURN_DATA_REGNO (i)) 3227 return true; 3228 } 3229 } 3230 3231 return false; 3232 } 3233 3234 3235 /* Return the size of the register savev area. This function is only 3236 correct starting with local register allocation */ 3237 static int 3238 tilepro_saved_regs_size (void) 3239 { 3240 int reg_save_size = 0; 3241 int regno; 3242 int offset_to_frame; 3243 int align_mask; 3244 3245 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 3246 if (need_to_save_reg (regno)) 3247 reg_save_size += UNITS_PER_WORD; 3248 3249 /* Pad out the register save area if necessary to make 3250 frame_pointer_rtx be as aligned as the stack pointer. */ 3251 offset_to_frame = crtl->args.pretend_args_size + reg_save_size; 3252 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1; 3253 reg_save_size += (-offset_to_frame) & align_mask; 3254 3255 return reg_save_size; 3256 } 3257 3258 3259 /* Round up frame size SIZE. */ 3260 static int 3261 round_frame_size (int size) 3262 { 3263 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1) 3264 & -STACK_BOUNDARY / BITS_PER_UNIT); 3265 } 3266 3267 3268 /* Emit a store in the stack frame to save REGNO at address ADDR, and 3269 emit the corresponding REG_CFA_OFFSET note described by CFA and 3270 CFA_OFFSET. Return the emitted insn. */ 3271 static rtx 3272 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa, 3273 int cfa_offset) 3274 { 3275 rtx reg = gen_rtx_REG (Pmode, regno); 3276 rtx mem = gen_frame_mem (Pmode, addr); 3277 rtx mov = gen_movsi (mem, reg); 3278 3279 /* Describe what just happened in a way that dwarf understands. We 3280 use temporary registers to hold the address to make scheduling 3281 easier, and use the REG_CFA_OFFSET to describe the address as an 3282 offset from the CFA. */ 3283 rtx reg_note = gen_rtx_REG (Pmode, regno_note); 3284 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, gen_int_si (cfa_offset)); 3285 rtx cfa_relative_mem = gen_frame_mem (Pmode, cfa_relative_addr); 3286 rtx real = gen_rtx_SET (cfa_relative_mem, reg_note); 3287 add_reg_note (mov, REG_CFA_OFFSET, real); 3288 3289 return emit_insn (mov); 3290 } 3291 3292 3293 /* Emit a load in the stack frame to load REGNO from address ADDR. 3294 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is 3295 non-null. Return the emitted insn. */ 3296 static rtx_insn * 3297 frame_emit_load (int regno, rtx addr, rtx *cfa_restores) 3298 { 3299 rtx reg = gen_rtx_REG (Pmode, regno); 3300 rtx mem = gen_frame_mem (Pmode, addr); 3301 if (cfa_restores) 3302 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores); 3303 return emit_insn (gen_movsi (reg, mem)); 3304 } 3305 3306 3307 /* Helper function to set RTX_FRAME_RELATED_P on instructions, 3308 including sequences. */ 3309 static rtx_insn * 3310 set_frame_related_p (void) 3311 { 3312 rtx_insn *seq = get_insns (); 3313 rtx_insn *insn; 3314 3315 end_sequence (); 3316 3317 if (!seq) 3318 return NULL; 3319 3320 if (INSN_P (seq)) 3321 { 3322 insn = seq; 3323 while (insn != NULL_RTX) 3324 { 3325 RTX_FRAME_RELATED_P (insn) = 1; 3326 insn = NEXT_INSN (insn); 3327 } 3328 seq = emit_insn (seq); 3329 } 3330 else 3331 { 3332 seq = emit_insn (seq); 3333 RTX_FRAME_RELATED_P (seq) = 1; 3334 } 3335 return seq; 3336 } 3337 3338 3339 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ()) 3340 3341 /* This emits code for 'sp += offset'. 3342 3343 The ABI only allows us to modify 'sp' in a single 'addi' or 3344 'addli', so the backtracer understands it. Larger amounts cannot 3345 use those instructions, so are added by placing the offset into a 3346 large register and using 'add'. 3347 3348 This happens after reload, so we need to expand it ourselves. */ 3349 static rtx_insn * 3350 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related, 3351 rtx reg_notes) 3352 { 3353 rtx to_add; 3354 rtx imm_rtx = gen_int_si (offset); 3355 3356 rtx_insn *insn; 3357 if (satisfies_constraint_J (imm_rtx)) 3358 { 3359 /* We can add this using a single addi or addli. */ 3360 to_add = imm_rtx; 3361 } 3362 else 3363 { 3364 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--); 3365 tilepro_expand_set_const32 (tmp, imm_rtx); 3366 to_add = tmp; 3367 } 3368 3369 /* Actually adjust the stack pointer. */ 3370 insn = emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, 3371 to_add)); 3372 REG_NOTES (insn) = reg_notes; 3373 3374 /* Describe what just happened in a way that dwarf understands. */ 3375 if (frame_related) 3376 { 3377 rtx real = gen_rtx_SET (stack_pointer_rtx, 3378 gen_rtx_PLUS (Pmode, stack_pointer_rtx, 3379 imm_rtx)); 3380 RTX_FRAME_RELATED_P (insn) = 1; 3381 add_reg_note (insn, REG_CFA_ADJUST_CFA, real); 3382 } 3383 3384 return insn; 3385 } 3386 3387 3388 /* Return whether the current function is leaf. This takes into 3389 account whether the function calls tls_get_addr. */ 3390 static bool 3391 tilepro_current_function_is_leaf (void) 3392 { 3393 return crtl->is_leaf && !cfun->machine->calls_tls_get_addr; 3394 } 3395 3396 3397 /* Return the frame size. */ 3398 static int 3399 compute_total_frame_size (void) 3400 { 3401 int total_size = (get_frame_size () + tilepro_saved_regs_size () 3402 + crtl->outgoing_args_size 3403 + crtl->args.pretend_args_size); 3404 3405 if (!tilepro_current_function_is_leaf () || cfun->calls_alloca) 3406 { 3407 /* Make room for save area in callee. */ 3408 total_size += STACK_POINTER_OFFSET; 3409 } 3410 3411 return round_frame_size (total_size); 3412 } 3413 3414 3415 /* Return nonzero if this function is known to have a null epilogue. 3416 This allows the optimizer to omit jumps to jumps if no stack was 3417 created. */ 3418 bool 3419 tilepro_can_use_return_insn_p (void) 3420 { 3421 return (reload_completed 3422 && cfun->static_chain_decl == 0 3423 && compute_total_frame_size () == 0 3424 && tilepro_current_function_is_leaf () 3425 && !crtl->profile && !df_regs_ever_live_p (TILEPRO_LINK_REGNUM)); 3426 } 3427 3428 3429 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there 3430 is a frame pointer, it computes the value relative to 3431 that. Otherwise it uses the stack pointer. */ 3432 static rtx 3433 compute_frame_addr (int offset_from_fp, int *next_scratch_regno) 3434 { 3435 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx; 3436 int offset_from_base; 3437 3438 if (frame_pointer_needed) 3439 { 3440 base_reg_rtx = hard_frame_pointer_rtx; 3441 offset_from_base = offset_from_fp; 3442 } 3443 else 3444 { 3445 int offset_from_sp = compute_total_frame_size () + offset_from_fp; 3446 base_reg_rtx = stack_pointer_rtx; 3447 offset_from_base = offset_from_sp; 3448 } 3449 3450 if (offset_from_base == 0) 3451 return base_reg_rtx; 3452 3453 /* Compute the new value of the stack pointer. */ 3454 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--); 3455 offset_rtx = gen_int_si (offset_from_base); 3456 3457 if (!tilepro_expand_addsi (tmp_reg_rtx, base_reg_rtx, offset_rtx)) 3458 { 3459 emit_insn (gen_rtx_SET (tmp_reg_rtx, 3460 gen_rtx_PLUS (Pmode, base_reg_rtx, 3461 offset_rtx))); 3462 } 3463 3464 return tmp_reg_rtx; 3465 } 3466 3467 3468 /* The stack frame looks like this: 3469 +-------------+ 3470 | ... | 3471 | incoming | 3472 | stack args | 3473 AP -> +-------------+ 3474 | caller's HFP| 3475 +-------------+ 3476 | lr save | 3477 HFP -> +-------------+ 3478 | var args | 3479 | reg save | crtl->args.pretend_args_size bytes 3480 +-------------+ 3481 | ... | 3482 | saved regs | tilepro_saved_regs_size() bytes 3483 FP -> +-------------+ 3484 | ... | 3485 | vars | get_frame_size() bytes 3486 +-------------+ 3487 | ... | 3488 | outgoing | 3489 | stack args | crtl->outgoing_args_size bytes 3490 +-------------+ 3491 | HFP | 4 bytes (only here if nonleaf / alloca) 3492 +-------------+ 3493 | callee lr | 4 bytes (only here if nonleaf / alloca) 3494 | save | 3495 SP -> +-------------+ 3496 3497 HFP == incoming SP. 3498 3499 For functions with a frame larger than 32767 bytes, or which use 3500 alloca (), r52 is used as a frame pointer. Otherwise there is no 3501 frame pointer. 3502 3503 FP is saved at SP+4 before calling a subroutine so the 3504 callee can chain. */ 3505 void 3506 tilepro_expand_prologue (void) 3507 { 3508 #define ROUND_ROBIN_SIZE 4 3509 /* We round-robin through four scratch registers to hold temporary 3510 addresses for saving registers, to make instruction scheduling 3511 easier. */ 3512 rtx reg_save_addr[ROUND_ROBIN_SIZE] = { 3513 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX 3514 }; 3515 rtx insn, cfa; 3516 unsigned int which_scratch; 3517 int offset, start_offset, regno; 3518 3519 /* A register that holds a copy of the incoming fp. */ 3520 int fp_copy_regno = -1; 3521 3522 /* A register that holds a copy of the incoming sp. */ 3523 int sp_copy_regno = -1; 3524 3525 /* Next scratch register number to hand out (postdecrementing). */ 3526 int next_scratch_regno = 29; 3527 3528 int total_size = compute_total_frame_size (); 3529 3530 if (flag_stack_usage_info) 3531 current_function_static_stack_size = total_size; 3532 3533 /* Save lr first in its special location because code after this 3534 might use the link register as a scratch register. */ 3535 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM) || crtl->calls_eh_return) 3536 { 3537 FRP (frame_emit_store (TILEPRO_LINK_REGNUM, TILEPRO_LINK_REGNUM, 3538 stack_pointer_rtx, stack_pointer_rtx, 0)); 3539 emit_insn (gen_blockage ()); 3540 } 3541 3542 if (total_size == 0) 3543 { 3544 /* Load the PIC register if needed. */ 3545 if (flag_pic && crtl->uses_pic_offset_table) 3546 load_pic_register (false); 3547 3548 return; 3549 } 3550 3551 cfa = stack_pointer_rtx; 3552 3553 if (frame_pointer_needed) 3554 { 3555 fp_copy_regno = next_scratch_regno--; 3556 3557 /* Copy the old frame pointer aside so we can save it later. */ 3558 insn = FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno), 3559 hard_frame_pointer_rtx)); 3560 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); 3561 3562 /* Set up the frame pointer. */ 3563 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); 3564 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx); 3565 cfa = hard_frame_pointer_rtx; 3566 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY; 3567 3568 /* fp holds a copy of the incoming sp, in case we need to store 3569 it. */ 3570 sp_copy_regno = HARD_FRAME_POINTER_REGNUM; 3571 } 3572 else if (!tilepro_current_function_is_leaf ()) 3573 { 3574 /* Copy the old stack pointer aside so we can save it later. */ 3575 sp_copy_regno = next_scratch_regno--; 3576 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno), 3577 stack_pointer_rtx); 3578 } 3579 3580 if (tilepro_current_function_is_leaf ()) 3581 { 3582 /* No need to store chain pointer to caller's frame. */ 3583 emit_sp_adjust (-total_size, &next_scratch_regno, 3584 !frame_pointer_needed, NULL_RTX); 3585 } 3586 else 3587 { 3588 /* Save the frame pointer (incoming sp value) to support 3589 backtracing. First we need to create an rtx with the store 3590 address. */ 3591 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--); 3592 rtx size_rtx = gen_int_si (-(total_size - UNITS_PER_WORD)); 3593 3594 if (add_operand (size_rtx, Pmode)) 3595 { 3596 /* Expose more parallelism by computing this value from the 3597 original stack pointer, not the one after we have pushed 3598 the frame. */ 3599 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx); 3600 emit_insn (gen_rtx_SET (chain_addr, p)); 3601 emit_sp_adjust (-total_size, &next_scratch_regno, 3602 !frame_pointer_needed, NULL_RTX); 3603 } 3604 else 3605 { 3606 /* The stack frame is large, so just store the incoming sp 3607 value at *(new_sp + UNITS_PER_WORD). */ 3608 rtx p; 3609 emit_sp_adjust (-total_size, &next_scratch_regno, 3610 !frame_pointer_needed, NULL_RTX); 3611 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 3612 GEN_INT (UNITS_PER_WORD)); 3613 emit_insn (gen_rtx_SET (chain_addr, p)); 3614 } 3615 3616 /* Save our frame pointer for backtrace chaining. */ 3617 emit_insn (gen_movsi (gen_frame_mem (SImode, chain_addr), 3618 gen_rtx_REG (SImode, sp_copy_regno))); 3619 } 3620 3621 /* Compute where to start storing registers we need to save. */ 3622 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD; 3623 offset = start_offset; 3624 3625 /* Store all registers that need saving. */ 3626 which_scratch = 0; 3627 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) 3628 if (need_to_save_reg (regno)) 3629 { 3630 rtx r = reg_save_addr[which_scratch]; 3631 int from_regno; 3632 int cfa_offset = frame_pointer_needed ? offset : total_size + offset; 3633 3634 if (r == NULL_RTX) 3635 { 3636 rtx p = compute_frame_addr (offset, &next_scratch_regno); 3637 r = gen_rtx_REG (word_mode, next_scratch_regno--); 3638 reg_save_addr[which_scratch] = r; 3639 3640 emit_insn (gen_rtx_SET (r, p)); 3641 } 3642 else 3643 { 3644 /* Advance to the next stack slot to store this register. */ 3645 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD; 3646 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride)); 3647 emit_insn (gen_rtx_SET (r, p)); 3648 } 3649 3650 /* Save this register to the stack (but use the old fp value 3651 we copied aside if appropriate). */ 3652 from_regno = (fp_copy_regno >= 0 3653 && regno == 3654 HARD_FRAME_POINTER_REGNUM) ? fp_copy_regno : regno; 3655 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset)); 3656 3657 offset -= UNITS_PER_WORD; 3658 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE; 3659 } 3660 3661 /* If profiling, force that to happen after the frame is set up. */ 3662 if (crtl->profile) 3663 emit_insn (gen_blockage ()); 3664 3665 /* Load the PIC register if needed. */ 3666 if (flag_pic && crtl->uses_pic_offset_table) 3667 load_pic_register (false); 3668 } 3669 3670 3671 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is 3672 true for a sibcall_epilogue pattern, and false for an epilogue 3673 pattern. */ 3674 void 3675 tilepro_expand_epilogue (bool sibcall_p) 3676 { 3677 /* We round-robin through four scratch registers to hold temporary 3678 addresses for saving registers, to make instruction scheduling 3679 easier. */ 3680 rtx reg_save_addr[ROUND_ROBIN_SIZE] = { 3681 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX 3682 }; 3683 rtx_insn *last_insn, *insn; 3684 unsigned int which_scratch; 3685 int offset, start_offset, regno; 3686 rtx cfa_restores = NULL_RTX; 3687 3688 /* A register that holds a copy of the incoming fp. */ 3689 int fp_copy_regno = -1; 3690 3691 /* Next scratch register number to hand out (postdecrementing). */ 3692 int next_scratch_regno = 29; 3693 3694 int total_size = compute_total_frame_size (); 3695 3696 last_insn = get_last_insn (); 3697 3698 /* Load lr first since we are going to need it first. */ 3699 insn = NULL; 3700 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM)) 3701 { 3702 insn = frame_emit_load (TILEPRO_LINK_REGNUM, 3703 compute_frame_addr (0, &next_scratch_regno), 3704 &cfa_restores); 3705 } 3706 3707 if (total_size == 0) 3708 { 3709 if (insn) 3710 { 3711 RTX_FRAME_RELATED_P (insn) = 1; 3712 REG_NOTES (insn) = cfa_restores; 3713 } 3714 goto done; 3715 } 3716 3717 /* Compute where to start restoring registers. */ 3718 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD; 3719 offset = start_offset; 3720 3721 if (frame_pointer_needed) 3722 fp_copy_regno = next_scratch_regno--; 3723 3724 /* Restore all callee-saved registers. */ 3725 which_scratch = 0; 3726 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) 3727 if (need_to_save_reg (regno)) 3728 { 3729 rtx r = reg_save_addr[which_scratch]; 3730 if (r == NULL_RTX) 3731 { 3732 r = compute_frame_addr (offset, &next_scratch_regno); 3733 reg_save_addr[which_scratch] = r; 3734 } 3735 else 3736 { 3737 /* Advance to the next stack slot to store this 3738 register. */ 3739 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD; 3740 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride)); 3741 emit_insn (gen_rtx_SET (r, p)); 3742 } 3743 3744 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM) 3745 frame_emit_load (fp_copy_regno, r, NULL); 3746 else 3747 frame_emit_load (regno, r, &cfa_restores); 3748 3749 offset -= UNITS_PER_WORD; 3750 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE; 3751 } 3752 3753 if (!tilepro_current_function_is_leaf ()) 3754 cfa_restores = 3755 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores); 3756 3757 emit_insn (gen_blockage ()); 3758 3759 if (frame_pointer_needed) 3760 { 3761 /* Restore the old stack pointer by copying from the frame 3762 pointer. */ 3763 insn = emit_insn (gen_sp_restore (stack_pointer_rtx, 3764 hard_frame_pointer_rtx)); 3765 RTX_FRAME_RELATED_P (insn) = 1; 3766 REG_NOTES (insn) = cfa_restores; 3767 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); 3768 } 3769 else 3770 { 3771 insn = emit_sp_adjust (total_size, &next_scratch_regno, true, 3772 cfa_restores); 3773 } 3774 3775 if (crtl->calls_eh_return) 3776 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, 3777 EH_RETURN_STACKADJ_RTX)); 3778 3779 /* Restore the old frame pointer. */ 3780 if (frame_pointer_needed) 3781 { 3782 insn = emit_move_insn (hard_frame_pointer_rtx, 3783 gen_rtx_REG (Pmode, fp_copy_regno)); 3784 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx); 3785 } 3786 3787 /* Mark the pic registers as live outside of the function. */ 3788 if (flag_pic) 3789 { 3790 emit_use (cfun->machine->text_label_rtx); 3791 emit_use (cfun->machine->got_rtx); 3792 } 3793 3794 done: 3795 if (!sibcall_p) 3796 { 3797 /* Emit the actual 'return' instruction. */ 3798 emit_jump_insn (gen__return ()); 3799 } 3800 else 3801 { 3802 emit_use (gen_rtx_REG (Pmode, TILEPRO_LINK_REGNUM)); 3803 } 3804 3805 /* Mark all insns we just emitted as frame-related. */ 3806 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn)) 3807 RTX_FRAME_RELATED_P (last_insn) = 1; 3808 } 3809 3810 #undef ROUND_ROBIN_SIZE 3811 3812 3813 /* Implement INITIAL_ELIMINATION_OFFSET. */ 3814 int 3815 tilepro_initial_elimination_offset (int from, int to) 3816 { 3817 int total_size = compute_total_frame_size (); 3818 3819 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 3820 { 3821 return (total_size - crtl->args.pretend_args_size 3822 - tilepro_saved_regs_size ()); 3823 } 3824 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 3825 { 3826 return -(crtl->args.pretend_args_size + tilepro_saved_regs_size ()); 3827 } 3828 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 3829 { 3830 return STACK_POINTER_OFFSET + total_size; 3831 } 3832 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 3833 { 3834 return STACK_POINTER_OFFSET; 3835 } 3836 else 3837 gcc_unreachable (); 3838 } 3839 3840 3841 /* Return an RTX indicating where the return address to the 3842 calling function can be found. */ 3843 rtx 3844 tilepro_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 3845 { 3846 if (count != 0) 3847 return const0_rtx; 3848 3849 return get_hard_reg_initial_val (Pmode, TILEPRO_LINK_REGNUM); 3850 } 3851 3852 3853 /* Implement EH_RETURN_HANDLER_RTX. */ 3854 rtx 3855 tilepro_eh_return_handler_rtx (void) 3856 { 3857 /* The MEM needs to be volatile to prevent it from being 3858 deleted. */ 3859 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx); 3860 MEM_VOLATILE_P (tmp) = true; 3861 return tmp; 3862 } 3863 3864 3865 3866 /* Registers */ 3867 3868 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */ 3869 static void 3870 tilepro_conditional_register_usage (void) 3871 { 3872 global_regs[TILEPRO_NETORDER_REGNUM] = 1; 3873 /* TILEPRO_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a 3874 member of fixed_regs, and therefore must be member of 3875 call_used_regs, but it is not a member of call_really_used_regs[] 3876 because it is not clobbered by a call. */ 3877 if (TILEPRO_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM) 3878 { 3879 fixed_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1; 3880 call_used_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1; 3881 } 3882 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) 3883 { 3884 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 3885 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 3886 } 3887 } 3888 3889 3890 /* Implement TARGET_FRAME_POINTER_REQUIRED. */ 3891 static bool 3892 tilepro_frame_pointer_required (void) 3893 { 3894 return crtl->calls_eh_return || cfun->calls_alloca; 3895 } 3896 3897 3898 3899 /* Scheduling and reorg */ 3900 3901 /* Return the length of INSN. LENGTH is the initial length computed 3902 by attributes in the machine-description file. This is where we 3903 account for bundles. */ 3904 int 3905 tilepro_adjust_insn_length (rtx_insn *insn, int length) 3906 { 3907 machine_mode mode = GET_MODE (insn); 3908 3909 /* A non-termininating instruction in a bundle has length 0. */ 3910 if (mode == SImode) 3911 return 0; 3912 3913 /* By default, there is not length adjustment. */ 3914 return length; 3915 } 3916 3917 3918 /* Implement TARGET_SCHED_ISSUE_RATE. */ 3919 static int 3920 tilepro_issue_rate (void) 3921 { 3922 return 3; 3923 } 3924 3925 3926 /* Return the rtx for the jump target. */ 3927 static rtx 3928 get_jump_target (rtx branch) 3929 { 3930 if (CALL_P (branch)) 3931 { 3932 rtx call; 3933 call = PATTERN (branch); 3934 3935 if (GET_CODE (call) == PARALLEL) 3936 call = XVECEXP (call, 0, 0); 3937 3938 if (GET_CODE (call) == SET) 3939 call = SET_SRC (call); 3940 3941 if (GET_CODE (call) == CALL) 3942 return XEXP (XEXP (call, 0), 0); 3943 } 3944 return 0; 3945 } 3946 3947 /* Implement TARGET_SCHED_ADJUST_COST. */ 3948 static int 3949 tilepro_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, 3950 int cost, unsigned int) 3951 { 3952 /* If we have a true dependence, INSN is a call, and DEP_INSN 3953 defines a register that is needed by the call (argument or stack 3954 pointer), set its latency to 0 so that it can be bundled with 3955 the call. Explicitly check for and exclude the case when 3956 DEP_INSN defines the target of the jump. */ 3957 if (CALL_P (insn) && dep_type == REG_DEP_TRUE) 3958 { 3959 rtx target = get_jump_target (insn); 3960 if (!REG_P (target) || !set_of (target, dep_insn)) 3961 return 0; 3962 } 3963 3964 return cost; 3965 } 3966 3967 3968 /* Skip over irrelevant NOTEs and such and look for the next insn we 3969 would consider bundling. */ 3970 static rtx_insn * 3971 next_insn_to_bundle (rtx_insn *r, rtx_insn *end) 3972 { 3973 for (; r != end; r = NEXT_INSN (r)) 3974 { 3975 if (NONDEBUG_INSN_P (r) 3976 && GET_CODE (PATTERN (r)) != USE 3977 && GET_CODE (PATTERN (r)) != CLOBBER) 3978 return r; 3979 } 3980 3981 return NULL; 3982 } 3983 3984 3985 /* Go through all insns, and use the information generated during 3986 scheduling to generate SEQUENCEs to represent bundles of 3987 instructions issued simultaneously. */ 3988 static void 3989 tilepro_gen_bundles (void) 3990 { 3991 basic_block bb; 3992 FOR_EACH_BB_FN (bb, cfun) 3993 { 3994 rtx_insn *insn, *next; 3995 rtx_insn *end = NEXT_INSN (BB_END (bb)); 3996 3997 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next) 3998 { 3999 next = next_insn_to_bundle (NEXT_INSN (insn), end); 4000 4001 /* Never wrap {} around inline asm. */ 4002 if (GET_CODE (PATTERN (insn)) != ASM_INPUT) 4003 { 4004 if (next == NULL_RTX || GET_MODE (next) == TImode 4005 /* NOTE: The scheduler incorrectly believes a call 4006 insn can execute in the same cycle as the insn 4007 after the call. This is of course impossible. 4008 Really we need to fix the scheduler somehow, so 4009 the code after the call gets scheduled 4010 optimally. */ 4011 || CALL_P (insn)) 4012 { 4013 /* Mark current insn as the end of a bundle. */ 4014 PUT_MODE (insn, QImode); 4015 } 4016 else 4017 { 4018 /* Mark it as part of a bundle. */ 4019 PUT_MODE (insn, SImode); 4020 } 4021 } 4022 } 4023 } 4024 } 4025 4026 4027 /* Helper function for tilepro_fixup_pcrel_references. */ 4028 static void 4029 replace_pc_relative_symbol_ref (rtx_insn *insn, rtx opnds[4], bool first_insn_p) 4030 { 4031 rtx_insn *new_insns; 4032 4033 start_sequence (); 4034 4035 if (flag_pic == 1) 4036 { 4037 if (!first_insn_p) 4038 { 4039 emit_insn (gen_add_got16 (opnds[0], tilepro_got_rtx (), 4040 opnds[2])); 4041 emit_insn (gen_insn_lw (opnds[0], opnds[0])); 4042 } 4043 } 4044 else 4045 { 4046 if (first_insn_p) 4047 { 4048 emit_insn (gen_addhi_got32 (opnds[0], tilepro_got_rtx (), 4049 opnds[2])); 4050 } 4051 else 4052 { 4053 emit_insn (gen_addlo_got32 (opnds[0], opnds[1], opnds[2])); 4054 emit_insn (gen_insn_lw (opnds[0], opnds[0])); 4055 } 4056 } 4057 4058 new_insns = get_insns (); 4059 end_sequence (); 4060 4061 if (new_insns) 4062 emit_insn_before (new_insns, insn); 4063 4064 delete_insn (insn); 4065 } 4066 4067 4068 /* Returns whether INSN is a pc-relative addli insn. */ 4069 static bool 4070 match_addli_pcrel (rtx_insn *insn) 4071 { 4072 rtx pattern = PATTERN (insn); 4073 rtx unspec; 4074 4075 if (GET_CODE (pattern) != SET) 4076 return false; 4077 4078 if (GET_CODE (SET_SRC (pattern)) != LO_SUM) 4079 return false; 4080 4081 if (GET_CODE (XEXP (SET_SRC (pattern), 1)) != CONST) 4082 return false; 4083 4084 unspec = XEXP (XEXP (SET_SRC (pattern), 1), 0); 4085 4086 return (GET_CODE (unspec) == UNSPEC 4087 && XINT (unspec, 1) == UNSPEC_PCREL_SYM); 4088 } 4089 4090 4091 /* Helper function for tilepro_fixup_pcrel_references. */ 4092 static void 4093 replace_addli_pcrel (rtx_insn *insn) 4094 { 4095 rtx pattern = PATTERN (insn); 4096 rtx set_src; 4097 rtx unspec; 4098 rtx opnds[4]; 4099 bool first_insn_p; 4100 4101 gcc_assert (GET_CODE (pattern) == SET); 4102 opnds[0] = SET_DEST (pattern); 4103 4104 set_src = SET_SRC (pattern); 4105 gcc_assert (GET_CODE (set_src) == LO_SUM); 4106 gcc_assert (GET_CODE (XEXP (set_src, 1)) == CONST); 4107 opnds[1] = XEXP (set_src, 0); 4108 4109 unspec = XEXP (XEXP (set_src, 1), 0); 4110 gcc_assert (GET_CODE (unspec) == UNSPEC); 4111 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM); 4112 opnds[2] = XVECEXP (unspec, 0, 0); 4113 opnds[3] = XVECEXP (unspec, 0, 1); 4114 4115 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4116 if (GET_CODE (opnds[2]) != SYMBOL_REF) 4117 return; 4118 4119 first_insn_p = (opnds[1] == tilepro_text_label_rtx ()); 4120 4121 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p); 4122 } 4123 4124 4125 /* Returns whether INSN is a pc-relative auli insn. */ 4126 static bool 4127 match_auli_pcrel (rtx_insn *insn) 4128 { 4129 rtx pattern = PATTERN (insn); 4130 rtx high; 4131 rtx unspec; 4132 4133 if (GET_CODE (pattern) != SET) 4134 return false; 4135 4136 if (GET_CODE (SET_SRC (pattern)) != PLUS) 4137 return false; 4138 4139 high = XEXP (SET_SRC (pattern), 1); 4140 4141 if (GET_CODE (high) != HIGH 4142 || GET_CODE (XEXP (high, 0)) != CONST) 4143 return false; 4144 4145 unspec = XEXP (XEXP (high, 0), 0); 4146 4147 return (GET_CODE (unspec) == UNSPEC 4148 && XINT (unspec, 1) == UNSPEC_PCREL_SYM); 4149 } 4150 4151 4152 /* Helper function for tilepro_fixup_pcrel_references. */ 4153 static void 4154 replace_auli_pcrel (rtx_insn *insn) 4155 { 4156 rtx pattern = PATTERN (insn); 4157 rtx set_src; 4158 rtx high; 4159 rtx unspec; 4160 rtx opnds[4]; 4161 bool first_insn_p; 4162 4163 gcc_assert (GET_CODE (pattern) == SET); 4164 opnds[0] = SET_DEST (pattern); 4165 4166 set_src = SET_SRC (pattern); 4167 gcc_assert (GET_CODE (set_src) == PLUS); 4168 opnds[1] = XEXP (set_src, 0); 4169 4170 high = XEXP (set_src, 1); 4171 gcc_assert (GET_CODE (high) == HIGH); 4172 gcc_assert (GET_CODE (XEXP (high, 0)) == CONST); 4173 4174 unspec = XEXP (XEXP (high, 0), 0); 4175 gcc_assert (GET_CODE (unspec) == UNSPEC); 4176 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM); 4177 opnds[2] = XVECEXP (unspec, 0, 0); 4178 opnds[3] = XVECEXP (unspec, 0, 1); 4179 4180 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4181 if (GET_CODE (opnds[2]) != SYMBOL_REF) 4182 return; 4183 4184 first_insn_p = (opnds[1] == tilepro_text_label_rtx ()); 4185 4186 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p); 4187 } 4188 4189 4190 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid 4191 going through the GOT when the symbol is local to the compilation 4192 unit. But such a symbol requires that the common text_label that 4193 we generate at the beginning of the function be in the same section 4194 as the reference to the SYMBOL_REF. This may not be true if we 4195 generate hot/cold sections. This function looks for such cases and 4196 replaces such references with the longer sequence going through the 4197 GOT. 4198 4199 We expect one of the following two instruction sequences: 4200 addli tmp1, txt_label_reg, lo16(sym - txt_label) 4201 auli tmp2, tmp1, ha16(sym - txt_label) 4202 4203 auli tmp1, txt_label_reg, ha16(sym - txt_label) 4204 addli tmp2, tmp1, lo16(sym - txt_label) 4205 4206 If we're compiling -fpic, we replace the first instruction with 4207 nothing, and the second instruction with: 4208 4209 addli tmp2, got_rtx, got(sym) 4210 lw tmp2, tmp2 4211 4212 If we're compiling -fPIC, we replace the first instruction with: 4213 4214 auli tmp1, got_rtx, got_ha16(sym) 4215 4216 and the second instruction with: 4217 4218 addli tmp2, tmp1, got_lo16(sym) 4219 lw tmp2, tmp2 4220 4221 Note that we're careful to disturb the instruction sequence as 4222 little as possible, since it's very late in the compilation 4223 process. 4224 */ 4225 static void 4226 tilepro_fixup_pcrel_references (void) 4227 { 4228 rtx_insn *insn, *next_insn; 4229 bool same_section_as_entry = true; 4230 4231 for (insn = get_insns (); insn; insn = next_insn) 4232 { 4233 next_insn = NEXT_INSN (insn); 4234 4235 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) 4236 { 4237 same_section_as_entry = !same_section_as_entry; 4238 continue; 4239 } 4240 4241 if (same_section_as_entry) 4242 continue; 4243 4244 if (!(INSN_P (insn) 4245 && GET_CODE (PATTERN (insn)) != USE 4246 && GET_CODE (PATTERN (insn)) != CLOBBER)) 4247 continue; 4248 4249 if (match_addli_pcrel (insn)) 4250 replace_addli_pcrel (insn); 4251 else if (match_auli_pcrel (insn)) 4252 replace_auli_pcrel (insn); 4253 } 4254 } 4255 4256 4257 /* Ensure that no var tracking notes are emitted in the middle of a 4258 three-instruction bundle. */ 4259 static void 4260 reorder_var_tracking_notes (void) 4261 { 4262 basic_block bb; 4263 FOR_EACH_BB_FN (bb, cfun) 4264 { 4265 rtx_insn *insn, *next; 4266 rtx_insn *queue = NULL; 4267 bool in_bundle = false; 4268 4269 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next) 4270 { 4271 next = NEXT_INSN (insn); 4272 4273 if (INSN_P (insn)) 4274 { 4275 /* Emit queued up notes at the last instruction of a bundle. */ 4276 if (GET_MODE (insn) == QImode) 4277 { 4278 while (queue) 4279 { 4280 rtx_insn *next_queue = PREV_INSN (queue); 4281 SET_PREV_INSN (NEXT_INSN (insn)) = queue; 4282 SET_NEXT_INSN (queue) = NEXT_INSN (insn); 4283 SET_NEXT_INSN (insn) = queue; 4284 SET_PREV_INSN (queue) = insn; 4285 queue = next_queue; 4286 } 4287 in_bundle = false; 4288 } 4289 else if (GET_MODE (insn) == SImode) 4290 in_bundle = true; 4291 } 4292 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION) 4293 { 4294 if (in_bundle) 4295 { 4296 rtx_insn *prev = PREV_INSN (insn); 4297 SET_PREV_INSN (next) = prev; 4298 SET_NEXT_INSN (prev) = next; 4299 4300 SET_PREV_INSN (insn) = queue; 4301 queue = insn; 4302 } 4303 } 4304 } 4305 } 4306 } 4307 4308 4309 /* Perform machine dependent operations on the rtl chain INSNS. */ 4310 static void 4311 tilepro_reorg (void) 4312 { 4313 /* We are freeing block_for_insn in the toplev to keep compatibility 4314 with old MDEP_REORGS that are not CFG based. Recompute it 4315 now. */ 4316 compute_bb_for_insn (); 4317 4318 if (flag_reorder_blocks_and_partition) 4319 { 4320 tilepro_fixup_pcrel_references (); 4321 } 4322 4323 if (flag_schedule_insns_after_reload) 4324 { 4325 split_all_insns (); 4326 4327 timevar_push (TV_SCHED2); 4328 schedule_insns (); 4329 timevar_pop (TV_SCHED2); 4330 4331 /* Examine the schedule to group into bundles. */ 4332 tilepro_gen_bundles (); 4333 } 4334 4335 df_analyze (); 4336 4337 if (flag_var_tracking) 4338 { 4339 timevar_push (TV_VAR_TRACKING); 4340 variable_tracking_main (); 4341 reorder_var_tracking_notes (); 4342 timevar_pop (TV_VAR_TRACKING); 4343 } 4344 4345 df_finish_pass (false); 4346 } 4347 4348 4349 4350 /* Assembly */ 4351 4352 /* Select a format to encode pointers in exception handling data. 4353 CODE is 0 for data, 1 for code labels, 2 for function pointers. 4354 GLOBAL is true if the symbol may be affected by dynamic 4355 relocations. */ 4356 int 4357 tilepro_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global) 4358 { 4359 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4; 4360 } 4361 4362 4363 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */ 4364 static void 4365 tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 4366 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 4367 tree function) 4368 { 4369 rtx this_rtx, funexp; 4370 rtx_insn *insn; 4371 4372 /* Pretend to be a post-reload pass while generating rtl. */ 4373 reload_completed = 1; 4374 4375 /* Mark the end of the (empty) prologue. */ 4376 emit_note (NOTE_INSN_PROLOGUE_END); 4377 4378 /* Find the "this" pointer. If the function returns a structure, 4379 the structure return pointer is in $1. */ 4380 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 4381 this_rtx = gen_rtx_REG (Pmode, 1); 4382 else 4383 this_rtx = gen_rtx_REG (Pmode, 0); 4384 4385 /* Add DELTA to THIS_RTX. */ 4386 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta))); 4387 4388 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ 4389 if (vcall_offset) 4390 { 4391 rtx tmp; 4392 4393 tmp = gen_rtx_REG (Pmode, 29); 4394 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx)); 4395 4396 emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (vcall_offset))); 4397 4398 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp)); 4399 4400 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp)); 4401 } 4402 4403 /* Generate a tail call to the target function. */ 4404 if (!TREE_USED (function)) 4405 { 4406 assemble_external (function); 4407 TREE_USED (function) = 1; 4408 } 4409 funexp = XEXP (DECL_RTL (function), 0); 4410 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); 4411 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); 4412 SIBLING_CALL_P (insn) = 1; 4413 4414 /* Run just enough of rest_of_compilation to get the insns emitted. 4415 There's not really enough bulk here to make other passes such as 4416 instruction scheduling worth while. Note that use_thunk calls 4417 assemble_start_function and assemble_end_function. 4418 4419 We don't currently bundle, but the instruciton sequence is all 4420 serial except for the tail call, so we're only wasting one cycle. 4421 */ 4422 insn = get_insns (); 4423 shorten_branches (insn); 4424 final_start_function (insn, file, 1); 4425 final (insn, file, 1); 4426 final_end_function (); 4427 4428 /* Stop pretending to be a post-reload pass. */ 4429 reload_completed = 0; 4430 } 4431 4432 4433 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 4434 static void 4435 tilepro_asm_trampoline_template (FILE *file) 4436 { 4437 fprintf (file, "\tlnk r10\n"); 4438 fprintf (file, "\taddi r10, r10, 32\n"); 4439 fprintf (file, "\tlwadd r11, r10, %d\n", GET_MODE_SIZE (ptr_mode)); 4440 fprintf (file, "\tlw r10, r10\n"); 4441 fprintf (file, "\tjr r11\n"); 4442 fprintf (file, "\t.word 0 # <function address>\n"); 4443 fprintf (file, "\t.word 0 # <static chain value>\n"); 4444 } 4445 4446 4447 /* Implement TARGET_TRAMPOLINE_INIT. */ 4448 static void 4449 tilepro_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) 4450 { 4451 rtx fnaddr, chaddr; 4452 rtx mem; 4453 rtx begin_addr, end_addr; 4454 int ptr_mode_size = GET_MODE_SIZE (ptr_mode); 4455 4456 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0)); 4457 chaddr = copy_to_reg (static_chain); 4458 4459 emit_block_move (m_tramp, assemble_trampoline_template (), 4460 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); 4461 4462 mem = adjust_address (m_tramp, ptr_mode, 4463 TRAMPOLINE_SIZE - 2 * ptr_mode_size); 4464 emit_move_insn (mem, fnaddr); 4465 mem = adjust_address (m_tramp, ptr_mode, 4466 TRAMPOLINE_SIZE - ptr_mode_size); 4467 emit_move_insn (mem, chaddr); 4468 4469 /* Get pointers to the beginning and end of the code block. */ 4470 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0)); 4471 end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0), 4472 TRAMPOLINE_SIZE)); 4473 4474 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), 4475 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode, 4476 end_addr, Pmode); 4477 } 4478 4479 4480 /* Implement TARGET_PRINT_OPERAND. */ 4481 static void 4482 tilepro_print_operand (FILE *file, rtx x, int code) 4483 { 4484 switch (code) 4485 { 4486 case 'c': 4487 /* Print the compare operator opcode for conditional moves. */ 4488 switch (GET_CODE (x)) 4489 { 4490 case EQ: 4491 fputs ("z", file); 4492 break; 4493 case NE: 4494 fputs ("nz", file); 4495 break; 4496 default: 4497 output_operand_lossage ("invalid %%c operand"); 4498 } 4499 return; 4500 4501 case 'C': 4502 /* Print the compare operator opcode for conditional moves. */ 4503 switch (GET_CODE (x)) 4504 { 4505 case EQ: 4506 fputs ("nz", file); 4507 break; 4508 case NE: 4509 fputs ("z", file); 4510 break; 4511 default: 4512 output_operand_lossage ("invalid %%C operand"); 4513 } 4514 return; 4515 4516 case 'h': 4517 { 4518 /* Print the high 16 bits of a 32-bit constant. */ 4519 HOST_WIDE_INT i; 4520 if (CONST_INT_P (x)) 4521 i = INTVAL (x); 4522 else if (GET_CODE (x) == CONST_DOUBLE) 4523 i = CONST_DOUBLE_LOW (x); 4524 else 4525 { 4526 output_operand_lossage ("invalid %%h operand"); 4527 return; 4528 } 4529 i = trunc_int_for_mode (i >> 16, HImode); 4530 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 4531 return; 4532 } 4533 4534 case 'H': 4535 { 4536 rtx addr = NULL; 4537 const char *opstr = NULL; 4538 bool pcrel = false; 4539 if (GET_CODE (x) == CONST 4540 && GET_CODE (XEXP (x, 0)) == UNSPEC) 4541 { 4542 addr = XVECEXP (XEXP (x, 0), 0, 0); 4543 switch (XINT (XEXP (x, 0), 1)) 4544 { 4545 case UNSPEC_GOT32_SYM: 4546 opstr = "got_ha16"; 4547 break; 4548 case UNSPEC_PCREL_SYM: 4549 opstr = "ha16"; 4550 pcrel = true; 4551 break; 4552 case UNSPEC_TLS_GD: 4553 opstr = "tls_gd_ha16"; 4554 break; 4555 case UNSPEC_TLS_IE: 4556 opstr = "tls_ie_ha16"; 4557 break; 4558 case UNSPEC_TLS_LE: 4559 opstr = "tls_le_ha16"; 4560 break; 4561 default: 4562 output_operand_lossage ("invalid %%H operand"); 4563 } 4564 } 4565 else 4566 { 4567 addr = x; 4568 opstr = "ha16"; 4569 } 4570 4571 fputs (opstr, file); 4572 fputc ('(', file); 4573 output_addr_const (file, addr); 4574 4575 if (pcrel) 4576 { 4577 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1); 4578 fputs (" - " , file); 4579 output_addr_const (file, addr2); 4580 } 4581 4582 fputc (')', file); 4583 return; 4584 } 4585 4586 case 'I': 4587 /* Print an auto-inc memory operand. */ 4588 if (!MEM_P (x)) 4589 { 4590 output_operand_lossage ("invalid %%I operand"); 4591 return; 4592 } 4593 4594 output_memory_autoinc_first = true; 4595 output_address (GET_MODE (x), XEXP (x, 0)); 4596 return; 4597 4598 case 'i': 4599 /* Print an auto-inc memory operand. */ 4600 if (!MEM_P (x)) 4601 { 4602 output_operand_lossage ("invalid %%i operand"); 4603 return; 4604 } 4605 4606 output_memory_autoinc_first = false; 4607 output_address (GET_MODE (x), XEXP (x, 0)); 4608 return; 4609 4610 case 'j': 4611 { 4612 /* Print the low 8 bits of a constant. */ 4613 HOST_WIDE_INT i; 4614 if (CONST_INT_P (x)) 4615 i = INTVAL (x); 4616 else if (GET_CODE (x) == CONST_DOUBLE) 4617 i = CONST_DOUBLE_LOW (x); 4618 else if (GET_CODE (x) == CONST_VECTOR 4619 && CONST_INT_P (CONST_VECTOR_ELT (x, 0))) 4620 i = INTVAL (CONST_VECTOR_ELT (x, 0)); 4621 else 4622 { 4623 output_operand_lossage ("invalid %%j operand"); 4624 return; 4625 } 4626 i = trunc_int_for_mode (i, QImode); 4627 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 4628 return; 4629 } 4630 4631 case 'L': 4632 { 4633 rtx addr = NULL; 4634 const char *opstr = NULL; 4635 bool pcrel = false; 4636 if (GET_CODE (x) == CONST 4637 && GET_CODE (XEXP (x, 0)) == UNSPEC) 4638 { 4639 addr = XVECEXP (XEXP (x, 0), 0, 0); 4640 switch (XINT (XEXP (x, 0), 1)) 4641 { 4642 case UNSPEC_GOT16_SYM: 4643 opstr = "got"; 4644 break; 4645 case UNSPEC_GOT32_SYM: 4646 opstr = "got_lo16"; 4647 break; 4648 case UNSPEC_PCREL_SYM: 4649 opstr = "lo16"; 4650 pcrel = true; 4651 break; 4652 case UNSPEC_TLS_GD: 4653 opstr = "tls_gd_lo16"; 4654 break; 4655 case UNSPEC_TLS_IE: 4656 opstr = "tls_ie_lo16"; 4657 break; 4658 case UNSPEC_TLS_LE: 4659 opstr = "tls_le_lo16"; 4660 break; 4661 default: 4662 output_operand_lossage ("invalid %%L operand"); 4663 } 4664 } 4665 else 4666 { 4667 addr = x; 4668 opstr = "lo16"; 4669 } 4670 4671 fputs (opstr, file); 4672 fputc ('(', file); 4673 output_addr_const (file, addr); 4674 4675 if (pcrel) 4676 { 4677 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1); 4678 fputs (" - " , file); 4679 output_addr_const (file, addr2); 4680 } 4681 4682 fputc (')', file); 4683 return; 4684 } 4685 4686 case 'p': 4687 if (GET_CODE (x) == SYMBOL_REF) 4688 { 4689 if (flag_pic && !SYMBOL_REF_LOCAL_P (x)) 4690 fprintf (file, "plt("); 4691 output_addr_const (file, x); 4692 if (flag_pic && !SYMBOL_REF_LOCAL_P (x)) 4693 fprintf (file, ")"); 4694 } 4695 else 4696 output_addr_const (file, x); 4697 return; 4698 4699 case 'P': 4700 { 4701 /* Print a 32-bit constant plus one. */ 4702 HOST_WIDE_INT i; 4703 if (!CONST_INT_P (x)) 4704 { 4705 output_operand_lossage ("invalid %%P operand"); 4706 return; 4707 } 4708 i = trunc_int_for_mode (INTVAL (x) + 1, SImode); 4709 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 4710 return; 4711 } 4712 4713 case 'M': 4714 { 4715 /* Print an mm-style bit range. */ 4716 int first_bit, last_bit; 4717 4718 if (!CONST_INT_P (x) 4719 || !tilepro_bitfield_operand_p (INTVAL (x), &first_bit, 4720 &last_bit)) 4721 { 4722 output_operand_lossage ("invalid %%M operand"); 4723 return; 4724 } 4725 4726 fprintf (file, "%d, %d", first_bit, last_bit); 4727 return; 4728 } 4729 4730 case 'N': 4731 { 4732 const char *reg = NULL; 4733 4734 /* Print a network register. */ 4735 if (!CONST_INT_P (x)) 4736 { 4737 output_operand_lossage ("invalid %%N operand"); 4738 return; 4739 } 4740 4741 switch (INTVAL (x)) 4742 { 4743 case TILEPRO_NETREG_IDN0: reg = "idn0"; break; 4744 case TILEPRO_NETREG_IDN1: reg = "idn1"; break; 4745 case TILEPRO_NETREG_SN: reg = "sn"; break; 4746 case TILEPRO_NETREG_UDN0: reg = "udn0"; break; 4747 case TILEPRO_NETREG_UDN1: reg = "udn1"; break; 4748 case TILEPRO_NETREG_UDN2: reg = "udn2"; break; 4749 case TILEPRO_NETREG_UDN3: reg = "udn3"; break; 4750 default: gcc_unreachable (); 4751 } 4752 4753 fprintf (file, reg); 4754 return; 4755 } 4756 4757 case 't': 4758 { 4759 /* Log base 2 of a power of two. */ 4760 HOST_WIDE_INT i; 4761 HOST_WIDE_INT n; 4762 4763 if (!CONST_INT_P (x)) 4764 { 4765 output_operand_lossage ("invalid %%t operand"); 4766 return; 4767 } 4768 n = trunc_int_for_mode (INTVAL (x), SImode); 4769 i = exact_log2 (n); 4770 if (i < 0) 4771 { 4772 output_operand_lossage ("invalid %%t operand '" 4773 HOST_WIDE_INT_PRINT_DEC "'", n); 4774 return; 4775 } 4776 4777 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 4778 return; 4779 } 4780 break; 4781 4782 case 'r': 4783 /* In this case we need a register. Use 'zero' if the 4784 operand is const0_rtx. */ 4785 if (x == const0_rtx 4786 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x)))) 4787 { 4788 fputs ("zero", file); 4789 return; 4790 } 4791 else if (!REG_P (x)) 4792 { 4793 output_operand_lossage ("invalid %%r operand"); 4794 return; 4795 } 4796 /* FALLTHRU */ 4797 4798 case 0: 4799 if (REG_P (x)) 4800 { 4801 fprintf (file, "%s", reg_names[REGNO (x)]); 4802 return; 4803 } 4804 else if (MEM_P (x)) 4805 { 4806 output_address (VOIDmode, XEXP (x, 0)); 4807 return; 4808 } 4809 else 4810 { 4811 output_addr_const (file, x); 4812 return; 4813 } 4814 break; 4815 } 4816 4817 debug_rtx (x); 4818 output_operand_lossage ("unable to print out operand yet; code == %d (%c)", 4819 code, code); 4820 } 4821 4822 4823 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */ 4824 static void 4825 tilepro_print_operand_address (FILE *file, machine_mode mode, rtx addr) 4826 { 4827 if (GET_CODE (addr) == POST_DEC 4828 || GET_CODE (addr) == POST_INC) 4829 { 4830 int offset = GET_MODE_SIZE (mode); 4831 4832 gcc_assert (mode != VOIDmode); 4833 4834 if (output_memory_autoinc_first) 4835 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]); 4836 else 4837 fprintf (file, "%d", 4838 GET_CODE (addr) == POST_DEC ? -offset : offset); 4839 } 4840 else if (GET_CODE (addr) == POST_MODIFY) 4841 { 4842 gcc_assert (mode != VOIDmode); 4843 4844 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS); 4845 4846 if (output_memory_autoinc_first) 4847 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]); 4848 else 4849 fprintf (file, HOST_WIDE_INT_PRINT_DEC, 4850 INTVAL (XEXP (XEXP (addr, 1), 1))); 4851 } 4852 else 4853 tilepro_print_operand (file, addr, 'r'); 4854 } 4855 4856 4857 /* Machine mode of current insn, for determining curly brace 4858 placement. */ 4859 static machine_mode insn_mode; 4860 4861 4862 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */ 4863 void 4864 tilepro_final_prescan_insn (rtx_insn *insn) 4865 { 4866 /* Record this for tilepro_asm_output_opcode to examine. */ 4867 insn_mode = GET_MODE (insn); 4868 } 4869 4870 4871 /* While emitting asm, are we currently inside '{' for a bundle? */ 4872 static bool tilepro_in_bundle = false; 4873 4874 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as 4875 appropriate given the bundling information recorded by 4876 tilepro_gen_bundles. */ 4877 const char * 4878 tilepro_asm_output_opcode (FILE *stream, const char *code) 4879 { 4880 bool pseudo = !strcmp (code, "pseudo"); 4881 4882 if (!tilepro_in_bundle && insn_mode == SImode) 4883 { 4884 /* Start a new bundle. */ 4885 fprintf (stream, "{\n\t"); 4886 tilepro_in_bundle = true; 4887 } 4888 4889 if (tilepro_in_bundle && insn_mode == QImode) 4890 { 4891 /* Close an existing bundle. */ 4892 static char buf[100]; 4893 4894 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf)); 4895 4896 strcpy (buf, pseudo ? "" : code); 4897 strcat (buf, "\n\t}"); 4898 tilepro_in_bundle = false; 4899 4900 return buf; 4901 } 4902 else 4903 { 4904 return pseudo ? "" : code; 4905 } 4906 } 4907 4908 4909 /* Output assembler code to FILE to increment profiler label # LABELNO 4910 for profiling a function entry. */ 4911 void 4912 tilepro_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) 4913 { 4914 if (tilepro_in_bundle) 4915 { 4916 fprintf (file, "\t}\n"); 4917 } 4918 4919 if (flag_pic) 4920 { 4921 fprintf (file, 4922 "\t{\n" 4923 "\tmove\tr10, lr\n" 4924 "\tjal\tplt(%s)\n" 4925 "\t}\n", MCOUNT_NAME); 4926 } 4927 else 4928 { 4929 fprintf (file, 4930 "\t{\n" 4931 "\tmove\tr10, lr\n" 4932 "\tjal\t%s\n" 4933 "\t}\n", MCOUNT_NAME); 4934 } 4935 4936 tilepro_in_bundle = false; 4937 } 4938 4939 4940 /* Implement TARGET_ASM_FILE_END. */ 4941 static void 4942 tilepro_file_end (void) 4943 { 4944 if (NEED_INDICATE_EXEC_STACK) 4945 file_end_indicate_exec_stack (); 4946 } 4947 4948 4949 #undef TARGET_HAVE_TLS 4950 #define TARGET_HAVE_TLS HAVE_AS_TLS 4951 4952 #undef TARGET_OPTION_OVERRIDE 4953 #define TARGET_OPTION_OVERRIDE tilepro_option_override 4954 4955 #ifdef TARGET_THREAD_SSP_OFFSET 4956 #undef TARGET_STACK_PROTECT_GUARD 4957 #define TARGET_STACK_PROTECT_GUARD hook_tree_void_null 4958 #endif 4959 4960 #undef TARGET_SCALAR_MODE_SUPPORTED_P 4961 #define TARGET_SCALAR_MODE_SUPPORTED_P tilepro_scalar_mode_supported_p 4962 4963 #undef TARGET_VECTOR_MODE_SUPPORTED_P 4964 #define TARGET_VECTOR_MODE_SUPPORTED_P tile_vector_mode_supported_p 4965 4966 #undef TARGET_CANNOT_FORCE_CONST_MEM 4967 #define TARGET_CANNOT_FORCE_CONST_MEM tilepro_cannot_force_const_mem 4968 4969 #undef TARGET_FUNCTION_OK_FOR_SIBCALL 4970 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilepro_function_ok_for_sibcall 4971 4972 #undef TARGET_PASS_BY_REFERENCE 4973 #define TARGET_PASS_BY_REFERENCE tilepro_pass_by_reference 4974 4975 #undef TARGET_RETURN_IN_MEMORY 4976 #define TARGET_RETURN_IN_MEMORY tilepro_return_in_memory 4977 4978 #undef TARGET_FUNCTION_ARG_BOUNDARY 4979 #define TARGET_FUNCTION_ARG_BOUNDARY tilepro_function_arg_boundary 4980 4981 #undef TARGET_FUNCTION_ARG 4982 #define TARGET_FUNCTION_ARG tilepro_function_arg 4983 4984 #undef TARGET_FUNCTION_ARG_ADVANCE 4985 #define TARGET_FUNCTION_ARG_ADVANCE tilepro_function_arg_advance 4986 4987 #undef TARGET_FUNCTION_VALUE 4988 #define TARGET_FUNCTION_VALUE tilepro_function_value 4989 4990 #undef TARGET_LIBCALL_VALUE 4991 #define TARGET_LIBCALL_VALUE tilepro_libcall_value 4992 4993 #undef TARGET_FUNCTION_VALUE_REGNO_P 4994 #define TARGET_FUNCTION_VALUE_REGNO_P tilepro_function_value_regno_p 4995 4996 #undef TARGET_PROMOTE_FUNCTION_MODE 4997 #define TARGET_PROMOTE_FUNCTION_MODE \ 4998 default_promote_function_mode_always_promote 4999 5000 #undef TARGET_PROMOTE_PROTOTYPES 5001 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false 5002 5003 #undef TARGET_BUILD_BUILTIN_VA_LIST 5004 #define TARGET_BUILD_BUILTIN_VA_LIST tilepro_build_builtin_va_list 5005 5006 #undef TARGET_EXPAND_BUILTIN_VA_START 5007 #define TARGET_EXPAND_BUILTIN_VA_START tilepro_va_start 5008 5009 #undef TARGET_SETUP_INCOMING_VARARGS 5010 #define TARGET_SETUP_INCOMING_VARARGS tilepro_setup_incoming_varargs 5011 5012 #undef TARGET_GIMPLIFY_VA_ARG_EXPR 5013 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilepro_gimplify_va_arg_expr 5014 5015 #undef TARGET_RTX_COSTS 5016 #define TARGET_RTX_COSTS tilepro_rtx_costs 5017 5018 /* Limit to what we can reach in one addli. */ 5019 #undef TARGET_MIN_ANCHOR_OFFSET 5020 #define TARGET_MIN_ANCHOR_OFFSET -32768 5021 #undef TARGET_MAX_ANCHOR_OFFSET 5022 #define TARGET_MAX_ANCHOR_OFFSET 32767 5023 5024 #undef TARGET_LEGITIMATE_CONSTANT_P 5025 #define TARGET_LEGITIMATE_CONSTANT_P tilepro_legitimate_constant_p 5026 5027 #undef TARGET_LRA_P 5028 #define TARGET_LRA_P hook_bool_void_false 5029 5030 #undef TARGET_LEGITIMATE_ADDRESS_P 5031 #define TARGET_LEGITIMATE_ADDRESS_P tilepro_legitimate_address_p 5032 5033 #undef TARGET_LEGITIMIZE_ADDRESS 5034 #define TARGET_LEGITIMIZE_ADDRESS tilepro_legitimize_address 5035 5036 #undef TARGET_DELEGITIMIZE_ADDRESS 5037 #define TARGET_DELEGITIMIZE_ADDRESS tilepro_delegitimize_address 5038 5039 #undef TARGET_INIT_BUILTINS 5040 #define TARGET_INIT_BUILTINS tilepro_init_builtins 5041 5042 #undef TARGET_BUILTIN_DECL 5043 #define TARGET_BUILTIN_DECL tilepro_builtin_decl 5044 5045 #undef TARGET_EXPAND_BUILTIN 5046 #define TARGET_EXPAND_BUILTIN tilepro_expand_builtin 5047 5048 #undef TARGET_CONDITIONAL_REGISTER_USAGE 5049 #define TARGET_CONDITIONAL_REGISTER_USAGE tilepro_conditional_register_usage 5050 5051 #undef TARGET_FRAME_POINTER_REQUIRED 5052 #define TARGET_FRAME_POINTER_REQUIRED tilepro_frame_pointer_required 5053 5054 #undef TARGET_DELAY_SCHED2 5055 #define TARGET_DELAY_SCHED2 true 5056 5057 #undef TARGET_DELAY_VARTRACK 5058 #define TARGET_DELAY_VARTRACK true 5059 5060 #undef TARGET_SCHED_ISSUE_RATE 5061 #define TARGET_SCHED_ISSUE_RATE tilepro_issue_rate 5062 5063 #undef TARGET_SCHED_ADJUST_COST 5064 #define TARGET_SCHED_ADJUST_COST tilepro_sched_adjust_cost 5065 5066 #undef TARGET_MACHINE_DEPENDENT_REORG 5067 #define TARGET_MACHINE_DEPENDENT_REORG tilepro_reorg 5068 5069 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 5070 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ 5071 hook_bool_const_tree_hwi_hwi_const_tree_true 5072 5073 #undef TARGET_ASM_OUTPUT_MI_THUNK 5074 #define TARGET_ASM_OUTPUT_MI_THUNK tilepro_asm_output_mi_thunk 5075 5076 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE 5077 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilepro_asm_trampoline_template 5078 5079 #undef TARGET_TRAMPOLINE_INIT 5080 #define TARGET_TRAMPOLINE_INIT tilepro_trampoline_init 5081 5082 #undef TARGET_PRINT_OPERAND 5083 #define TARGET_PRINT_OPERAND tilepro_print_operand 5084 5085 #undef TARGET_PRINT_OPERAND_ADDRESS 5086 #define TARGET_PRINT_OPERAND_ADDRESS tilepro_print_operand_address 5087 5088 #undef TARGET_ASM_FILE_END 5089 #define TARGET_ASM_FILE_END tilepro_file_end 5090 5091 #undef TARGET_CAN_USE_DOLOOP_P 5092 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost 5093 5094 struct gcc_target targetm = TARGET_INITIALIZER; 5095 5096 #include "gt-tilepro.h" 5097