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