1/* Subroutines used for code generation on the Tilera TILE-Gx. 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 "tm_p.h" 70#include "tm-constrs.h" 71#include "target.h" 72#include "target-def.h" 73#include "dwarf2.h" 74#include "timevar.h" 75#include "fold-const.h" 76#include "hash-table.h" 77#include "ggc.h" 78#include "tree-ssa-alias.h" 79#include "internal-fn.h" 80#include "gimple-fold.h" 81#include "tree-eh.h" 82#include "gimple-expr.h" 83#include "is-a.h" 84#include "gimple.h" 85#include "stringpool.h" 86#include "stor-layout.h" 87#include "gimplify.h" 88#include "cfgloop.h" 89#include "tilegx-builtins.h" 90#include "tilegx-multiply.h" 91#include "diagnostic.h" 92#include "builtins.h" 93 94/* SYMBOL_REF for GOT */ 95static GTY(()) rtx g_got_symbol = NULL; 96 97/* In case of a POST_INC or POST_DEC memory reference, we must report 98 the mode of the memory reference from TARGET_PRINT_OPERAND to 99 TARGET_PRINT_OPERAND_ADDRESS. */ 100static machine_mode output_memory_reference_mode; 101 102/* Report whether we're printing out the first address fragment of a 103 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to 104 TARGET_PRINT_OPERAND_ADDRESS. */ 105static bool output_memory_autoinc_first; 106 107 108 109/* Option handling */ 110 111/* Implement TARGET_OPTION_OVERRIDE. */ 112static void 113tilegx_option_override (void) 114{ 115 if (global_options_set.x_tilegx_cmodel) 116 { 117 switch (tilegx_cmodel) 118 { 119 case CM_SMALL: 120 case CM_SMALL_PIC: 121 if (flag_pic) 122 tilegx_cmodel = CM_SMALL_PIC; 123 break; 124 125 case CM_LARGE: 126 case CM_LARGE_PIC: 127 if (flag_pic) 128 tilegx_cmodel = CM_LARGE_PIC; 129 break; 130 131 default: 132 gcc_unreachable (); 133 } 134 } 135 else 136 tilegx_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; 137 138 /* When modulo scheduling is enabled, we still rely on regular 139 scheduler for bundling. */ 140 if (flag_modulo_sched) 141 flag_resched_modulo_sched = 1; 142} 143 144 145 146/* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */ 147static bool 148tilegx_scalar_mode_supported_p (machine_mode mode) 149{ 150 switch (mode) 151 { 152 case QImode: 153 case HImode: 154 case SImode: 155 case DImode: 156 case TImode: 157 return true; 158 159 case SFmode: 160 case DFmode: 161 return true; 162 163 default: 164 return false; 165 } 166} 167 168 169/* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */ 170static bool 171tilegx_vector_mode_supported_p (machine_mode mode) 172{ 173 return mode == V8QImode || mode == V4HImode || mode == V2SImode; 174} 175 176 177/* Implement TARGET_CANNOT_FORCE_CONST_MEM. */ 178static bool 179tilegx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, 180 rtx x ATTRIBUTE_UNUSED) 181{ 182 return true; 183} 184 185 186/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ 187static bool 188tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) 189{ 190 return (tilegx_cmodel != CM_LARGE && tilegx_cmodel != CM_LARGE_PIC 191 && (decl != NULL)); 192} 193 194 195/* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are 196 passed by reference. */ 197static bool 198tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, 199 machine_mode mode ATTRIBUTE_UNUSED, 200 const_tree type, bool named ATTRIBUTE_UNUSED) 201{ 202 return (type && TYPE_SIZE (type) 203 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST); 204} 205 206 207/* Implement TARGET_RETURN_IN_MSB. We return a value in the most 208 significant part of a register if: 209 - the target is big-endian; and 210 - the value has an aggregate type (e.g., structure or union). */ 211static bool 212tilegx_return_in_msb (const_tree valtype) 213{ 214 return (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype)); 215} 216 217 218/* Implement TARGET_RETURN_IN_MEMORY. */ 219static bool 220tilegx_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) 221{ 222 return !IN_RANGE (int_size_in_bytes (type), 223 0, TILEGX_NUM_RETURN_REGS * UNITS_PER_WORD); 224} 225 226 227/* Implement TARGET_MODE_REP_EXTENDED. */ 228static int 229tilegx_mode_rep_extended (machine_mode mode, machine_mode mode_rep) 230{ 231 /* SImode register values are sign-extended to DImode. */ 232 if (mode == SImode && mode_rep == DImode) 233 return SIGN_EXTEND; 234 235 return UNKNOWN; 236} 237 238 239/* Implement TARGET_FUNCTION_ARG_BOUNDARY. */ 240static unsigned int 241tilegx_function_arg_boundary (machine_mode mode, const_tree type) 242{ 243 unsigned int alignment; 244 245 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode); 246 if (alignment < PARM_BOUNDARY) 247 alignment = PARM_BOUNDARY; 248 if (alignment > STACK_BOUNDARY) 249 alignment = STACK_BOUNDARY; 250 return alignment; 251} 252 253 254/* Implement TARGET_FUNCTION_ARG. */ 255static rtx 256tilegx_function_arg (cumulative_args_t cum_v, 257 machine_mode mode, 258 const_tree type, bool named ATTRIBUTE_UNUSED) 259{ 260 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v); 261 int byte_size = ((mode == BLKmode) 262 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 263 bool doubleword_aligned_p; 264 265 if (cum >= TILEGX_NUM_ARG_REGS) 266 return NULL_RTX; 267 268 /* See whether the argument has doubleword alignment. */ 269 doubleword_aligned_p = 270 tilegx_function_arg_boundary (mode, type) > BITS_PER_WORD; 271 272 if (doubleword_aligned_p) 273 cum += cum & 1; 274 275 /* The ABI does not allow parameters to be passed partially in reg 276 and partially in stack. */ 277 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) 278 > TILEGX_NUM_ARG_REGS) 279 return NULL_RTX; 280 281 return gen_rtx_REG (mode, cum); 282} 283 284 285/* Implement TARGET_FUNCTION_ARG_ADVANCE. */ 286static void 287tilegx_function_arg_advance (cumulative_args_t cum_v, 288 machine_mode mode, 289 const_tree type, bool named ATTRIBUTE_UNUSED) 290{ 291 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 292 293 int byte_size = ((mode == BLKmode) 294 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 295 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 296 bool doubleword_aligned_p; 297 298 /* See whether the argument has doubleword alignment. */ 299 doubleword_aligned_p = 300 tilegx_function_arg_boundary (mode, type) > BITS_PER_WORD; 301 302 if (doubleword_aligned_p) 303 *cum += *cum & 1; 304 305 /* If the current argument does not fit in the pretend_args space, 306 skip over it. */ 307 if (*cum < TILEGX_NUM_ARG_REGS 308 && *cum + word_size > TILEGX_NUM_ARG_REGS) 309 *cum = TILEGX_NUM_ARG_REGS; 310 311 *cum += word_size; 312} 313 314 315/* Implement TARGET_FUNCTION_VALUE. */ 316static rtx 317tilegx_function_value (const_tree valtype, const_tree fn_decl_or_type, 318 bool outgoing ATTRIBUTE_UNUSED) 319{ 320 machine_mode mode; 321 int unsigned_p; 322 323 mode = TYPE_MODE (valtype); 324 unsigned_p = TYPE_UNSIGNED (valtype); 325 326 mode = promote_function_mode (valtype, mode, &unsigned_p, 327 fn_decl_or_type, 1); 328 329 return gen_rtx_REG (mode, 0); 330} 331 332 333/* Implement TARGET_LIBCALL_VALUE. */ 334static rtx 335tilegx_libcall_value (machine_mode mode, 336 const_rtx fun ATTRIBUTE_UNUSED) 337{ 338 return gen_rtx_REG (mode, 0); 339} 340 341 342/* Implement FUNCTION_VALUE_REGNO_P. */ 343static bool 344tilegx_function_value_regno_p (const unsigned int regno) 345{ 346 return regno < TILEGX_NUM_RETURN_REGS; 347} 348 349 350/* Implement TARGET_BUILD_BUILTIN_VA_LIST. */ 351static tree 352tilegx_build_builtin_va_list (void) 353{ 354 tree f_args, f_skip, record, type_decl; 355 bool owp; 356 357 record = lang_hooks.types.make_type (RECORD_TYPE); 358 359 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL, 360 get_identifier ("__va_list_tag"), record); 361 362 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL, 363 get_identifier ("__args"), ptr_type_node); 364 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL, 365 get_identifier ("__skip"), ptr_type_node); 366 367 DECL_FIELD_CONTEXT (f_args) = record; 368 369 DECL_FIELD_CONTEXT (f_skip) = record; 370 371 TREE_CHAIN (record) = type_decl; 372 TYPE_NAME (record) = type_decl; 373 TYPE_FIELDS (record) = f_args; 374 TREE_CHAIN (f_args) = f_skip; 375 376 /* We know this is being padded and we want it too. It is an 377 internal type so hide the warnings from the user. */ 378 owp = warn_padded; 379 warn_padded = false; 380 381 layout_type (record); 382 383 warn_padded = owp; 384 385 /* The correct type is an array type of one element. */ 386 return record; 387} 388 389 390/* Implement TARGET_EXPAND_BUILTIN_VA_START. */ 391static void 392tilegx_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) 393{ 394 tree f_args, f_skip; 395 tree args, skip, t; 396 397 f_args = TYPE_FIELDS (TREE_TYPE (valist)); 398 f_skip = TREE_CHAIN (f_args); 399 400 args = 401 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); 402 skip = 403 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); 404 405 /* Find the __args area. */ 406 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx); 407 t = fold_build_pointer_plus_hwi (t, 408 UNITS_PER_WORD * 409 (crtl->args.info - TILEGX_NUM_ARG_REGS)); 410 411 if (crtl->args.pretend_args_size > 0) 412 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); 413 414 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t); 415 TREE_SIDE_EFFECTS (t) = 1; 416 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 417 418 /* Find the __skip area. */ 419 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx); 420 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET); 421 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t); 422 TREE_SIDE_EFFECTS (t) = 1; 423 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); 424} 425 426 427/* Implement TARGET_SETUP_INCOMING_VARARGS. */ 428static void 429tilegx_setup_incoming_varargs (cumulative_args_t cum, 430 machine_mode mode, 431 tree type, int *pretend_args, int no_rtl) 432{ 433 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum); 434 int first_reg; 435 436 /* The caller has advanced CUM up to, but not beyond, the last named 437 argument. Advance a local copy of CUM past the last "real" named 438 argument, to find out how many registers are left over. */ 439 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum), 440 mode, type, true); 441 first_reg = local_cum; 442 443 if (local_cum < TILEGX_NUM_ARG_REGS) 444 { 445 *pretend_args = UNITS_PER_WORD * (TILEGX_NUM_ARG_REGS - first_reg); 446 447 if (!no_rtl) 448 { 449 alias_set_type set = get_varargs_alias_set (); 450 rtx tmp = 451 gen_rtx_MEM (BLKmode, plus_constant (Pmode, 452 virtual_incoming_args_rtx, 453 -STACK_POINTER_OFFSET - 454 UNITS_PER_WORD * 455 (TILEGX_NUM_ARG_REGS - 456 first_reg))); 457 MEM_NOTRAP_P (tmp) = 1; 458 set_mem_alias_set (tmp, set); 459 move_block_from_reg (first_reg, tmp, 460 TILEGX_NUM_ARG_REGS - first_reg); 461 } 462 } 463 else 464 *pretend_args = 0; 465} 466 467 468/* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating 469 the va_list structure VALIST as required to retrieve an argument of 470 type TYPE, and returning that argument. 471 472 ret = va_arg(VALIST, TYPE); 473 474 generates code equivalent to: 475 476 paddedsize = (sizeof(TYPE) + 7) & -8; 477 if ( (VALIST.__args + paddedsize > VALIST.__skip) 478 & (VALIST.__args <= VALIST.__skip)) 479 addr = VALIST.__skip + STACK_POINTER_OFFSET; 480 else 481 addr = VALIST.__args; 482 VALIST.__args = addr + paddedsize; 483 if (BYTES_BIG_ENDIAN) 484 ret = *(TYPE *)(addr + paddedsize - sizeof(TYPE)); 485 else 486 ret = *(TYPE *)addr; 487 */ 488static tree 489tilegx_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, 490 gimple_seq *post_p ATTRIBUTE_UNUSED) 491{ 492 tree f_args, f_skip; 493 tree args, skip; 494 HOST_WIDE_INT size, rsize; 495 tree addr, tmp; 496 bool pass_by_reference_p; 497 498 f_args = TYPE_FIELDS (va_list_type_node); 499 f_skip = TREE_CHAIN (f_args); 500 501 args = 502 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE); 503 skip = 504 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE); 505 506 addr = create_tmp_var (ptr_type_node, "va_arg"); 507 508 /* If an object is dynamically sized, a pointer to it is passed 509 instead of the object itself. */ 510 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type, 511 false); 512 513 if (pass_by_reference_p) 514 type = build_pointer_type (type); 515 516 size = int_size_in_bytes (type); 517 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD; 518 519 /* If the alignment of the type is greater than the default for a 520 parameter, align to the STACK_BOUNDARY. */ 521 if (TYPE_ALIGN (type) > PARM_BOUNDARY) 522 { 523 /* Assert the only case we generate code for: when 524 stack boundary = 2 * parm boundary. */ 525 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2); 526 527 tmp = build2 (BIT_AND_EXPR, sizetype, 528 fold_convert (sizetype, unshare_expr (args)), 529 size_int (PARM_BOUNDARY / 8)); 530 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, 531 unshare_expr (args), tmp); 532 533 gimplify_assign (unshare_expr (args), tmp, pre_p); 534 } 535 536 /* Build conditional expression to calculate addr. The expression 537 will be gimplified later. */ 538 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize); 539 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node, 540 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)), 541 build2 (LE_EXPR, boolean_type_node, unshare_expr (args), 542 unshare_expr (skip))); 543 544 tmp = build3 (COND_EXPR, ptr_type_node, tmp, 545 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip), 546 size_int (STACK_POINTER_OFFSET)), 547 unshare_expr (args)); 548 549 /* Adjust the address of va_arg if it is in big endian mode. */ 550 if (BYTES_BIG_ENDIAN && rsize > size) 551 tmp = fold_build_pointer_plus_hwi (tmp, rsize - size); 552 gimplify_assign (addr, tmp, pre_p); 553 554 /* Update VALIST.__args. */ 555 556 if (BYTES_BIG_ENDIAN && rsize > size) 557 tmp = fold_build_pointer_plus_hwi (addr, size); 558 else 559 tmp = fold_build_pointer_plus_hwi (addr, rsize); 560 gimplify_assign (unshare_expr (args), tmp, pre_p); 561 562 addr = fold_convert (build_pointer_type (type), addr); 563 564 if (pass_by_reference_p) 565 addr = build_va_arg_indirect_ref (addr); 566 567 return build_va_arg_indirect_ref (addr); 568} 569 570 571 572/* Implement TARGET_RTX_COSTS. */ 573static bool 574tilegx_rtx_costs (rtx x, int code, int outer_code, int opno, int *total, 575 bool speed) 576{ 577 switch (code) 578 { 579 case CONST_INT: 580 /* If this is an 8-bit constant, return zero since it can be 581 used nearly anywhere with no cost. If it is a valid operand 582 for an ADD or AND, likewise return 0 if we know it will be 583 used in that context. Otherwise, return 2 since it might be 584 used there later. All other constants take at least two 585 insns. */ 586 if (satisfies_constraint_I (x)) 587 { 588 *total = 0; 589 return true; 590 } 591 else if (outer_code == PLUS && add_operand (x, VOIDmode)) 592 { 593 /* Slightly penalize large constants even though we can add 594 them in one instruction, because it forces the use of 595 2-wide bundling mode. */ 596 *total = 1; 597 return true; 598 } 599 else if (move_operand (x, SImode)) 600 { 601 /* We can materialize in one move. */ 602 *total = COSTS_N_INSNS (1); 603 return true; 604 } 605 else 606 { 607 /* We can materialize in two moves. */ 608 *total = COSTS_N_INSNS (2); 609 return true; 610 } 611 612 return false; 613 614 case CONST: 615 case LABEL_REF: 616 case SYMBOL_REF: 617 *total = COSTS_N_INSNS (2); 618 return true; 619 620 case CONST_DOUBLE: 621 *total = COSTS_N_INSNS (4); 622 return true; 623 624 case HIGH: 625 *total = 0; 626 return true; 627 628 case MEM: 629 /* If outer-code was a sign or zero extension, a cost of 630 COSTS_N_INSNS (1) was already added in, so account for 631 that. */ 632 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND) 633 *total = COSTS_N_INSNS (1); 634 else 635 *total = COSTS_N_INSNS (2); 636 return true; 637 638 case PLUS: 639 /* Convey that shl[123]add are efficient. */ 640 if (GET_CODE (XEXP (x, 0)) == MULT 641 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode)) 642 { 643 *total = (rtx_cost (XEXP (XEXP (x, 0), 0), 644 (enum rtx_code) outer_code, opno, speed) 645 + rtx_cost (XEXP (x, 1), 646 (enum rtx_code) outer_code, opno, speed) 647 + COSTS_N_INSNS (1)); 648 return true; 649 } 650 return false; 651 652 case MULT: 653 *total = COSTS_N_INSNS (2); 654 return false; 655 656 case DIV: 657 case UDIV: 658 case MOD: 659 case UMOD: 660 /* These are handled by software and are very expensive. */ 661 *total = COSTS_N_INSNS (100); 662 return false; 663 664 case UNSPEC: 665 case UNSPEC_VOLATILE: 666 { 667 int num = XINT (x, 1); 668 669 if (num <= TILEGX_LAST_LATENCY_1_INSN) 670 *total = COSTS_N_INSNS (1); 671 else if (num <= TILEGX_LAST_LATENCY_2_INSN) 672 *total = COSTS_N_INSNS (2); 673 else if (num > TILEGX_LAST_LATENCY_INSN) 674 { 675 if (num == UNSPEC_NON_TEMPORAL) 676 { 677 /* These are basically loads. */ 678 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND) 679 *total = COSTS_N_INSNS (1); 680 else 681 *total = COSTS_N_INSNS (2); 682 } 683 else 684 { 685 if (outer_code == PLUS) 686 *total = 0; 687 else 688 *total = COSTS_N_INSNS (1); 689 } 690 } 691 else 692 { 693 switch (num) 694 { 695 case UNSPEC_BLOCKAGE: 696 case UNSPEC_NETWORK_BARRIER: 697 case UNSPEC_ATOMIC: 698 *total = 0; 699 break; 700 701 case UNSPEC_LNK_AND_LABEL: 702 case UNSPEC_MF: 703 case UNSPEC_MOV_PCREL_STEP3: 704 case UNSPEC_NETWORK_RECEIVE: 705 case UNSPEC_NETWORK_SEND: 706 case UNSPEC_SPR_MOVE: 707 case UNSPEC_TLS_GD_ADD: 708 *total = COSTS_N_INSNS (1); 709 break; 710 711 case UNSPEC_TLS_IE_LOAD: 712 case UNSPEC_XCHG: 713 *total = COSTS_N_INSNS (2); 714 break; 715 716 case UNSPEC_SP_SET: 717 *total = COSTS_N_INSNS (3); 718 break; 719 720 case UNSPEC_SP_TEST: 721 *total = COSTS_N_INSNS (4); 722 break; 723 724 case UNSPEC_CMPXCHG: 725 case UNSPEC_INSN_CMPEXCH: 726 case UNSPEC_LATENCY_L2: 727 *total = COSTS_N_INSNS (11); 728 break; 729 730 case UNSPEC_TLS_GD_CALL: 731 *total = COSTS_N_INSNS (30); 732 break; 733 734 case UNSPEC_LATENCY_MISS: 735 *total = COSTS_N_INSNS (80); 736 break; 737 738 default: 739 *total = COSTS_N_INSNS (1); 740 } 741 } 742 return true; 743 } 744 745 default: 746 return false; 747 } 748} 749 750 751 752/* Rtl lowering. */ 753 754/* Create a temporary variable to hold a partial result, to enable 755 CSE. */ 756static rtx 757create_temp_reg_if_possible (machine_mode mode, rtx default_reg) 758{ 759 return can_create_pseudo_p () ? gen_reg_rtx (mode) : default_reg; 760} 761 762 763/* Functions to save and restore machine-specific function data. */ 764static struct machine_function * 765tilegx_init_machine_status (void) 766{ 767 return ggc_cleared_alloc<machine_function> (); 768} 769 770 771/* Do anything needed before RTL is emitted for each function. */ 772void 773tilegx_init_expanders (void) 774{ 775 /* Arrange to initialize and mark the machine per-function 776 status. */ 777 init_machine_status = tilegx_init_machine_status; 778 779 if (cfun && cfun->machine && flag_pic) 780 { 781 static int label_num = 0; 782 783 char text_label_name[32]; 784 785 struct machine_function *machine = cfun->machine; 786 787 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++); 788 789 machine->text_label_symbol = 790 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name)); 791 792 machine->text_label_rtx = 793 gen_rtx_REG (Pmode, TILEGX_PIC_TEXT_LABEL_REGNUM); 794 795 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); 796 797 machine->calls_tls_get_addr = false; 798 } 799} 800 801 802/* Implement TARGET_EXPAND_TO_RTL_HOOK. */ 803static void 804tilegx_expand_to_rtl_hook (void) 805{ 806 /* Exclude earlier sets of crtl->uses_pic_offset_table, because we 807 only care about uses actually emitted. */ 808 crtl->uses_pic_offset_table = 0; 809} 810 811 812/* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode 813 matching insns and therefore guarantee that the shift count is 814 modulo 64. SImode shifts sometimes use the 64 bit version so do 815 not hold such guarantee. */ 816static unsigned HOST_WIDE_INT 817tilegx_shift_truncation_mask (machine_mode mode) 818{ 819 return mode == DImode ? 63 : 0; 820} 821 822 823/* Implement TARGET_INIT_LIBFUNCS. */ 824static void 825tilegx_init_libfuncs (void) 826{ 827 /* We need to explicitly generate these libfunc's to support 828 conversion of divide by constant to multiply (the divide stubs in 829 tilegx.md exist also for this reason). Normally we'd expect gcc 830 to lazily generate them when they are needed, but for some reason 831 it's set up to only generate them if the mode is the word 832 mode. */ 833 set_optab_libfunc (sdiv_optab, SImode, "__divsi3"); 834 set_optab_libfunc (udiv_optab, SImode, "__udivsi3"); 835 set_optab_libfunc (smod_optab, SImode, "__modsi3"); 836 set_optab_libfunc (umod_optab, SImode, "__umodsi3"); 837} 838 839 840/* Return true if X contains a thread-local symbol. */ 841static bool 842tilegx_tls_referenced_p (rtx x) 843{ 844 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) 845 x = XEXP (XEXP (x, 0), 0); 846 847 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x)) 848 return true; 849 850 /* That's all we handle in tilegx_legitimize_tls_address for 851 now. */ 852 return false; 853} 854 855 856/* Return true if X requires a scratch register. It is given that 857 flag_pic is on and that X satisfies CONSTANT_P. */ 858static int 859tilegx_pic_address_needs_scratch (rtx x) 860{ 861 if (GET_CODE (x) == CONST 862 && GET_CODE (XEXP (x, 0)) == PLUS 863 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 864 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF) 865 && (CONST_INT_P (XEXP (XEXP (x, 0), 1)))) 866 return true; 867 868 return false; 869} 870 871 872/* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for 873 which we are willing to load the value into a register via a move 874 pattern. TLS cannot be treated as a constant because it can 875 include a function call. */ 876static bool 877tilegx_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) 878{ 879 switch (GET_CODE (x)) 880 { 881 case CONST: 882 case SYMBOL_REF: 883 return !tilegx_tls_referenced_p (x); 884 885 default: 886 return true; 887 } 888} 889 890 891/* Return true if the constant value X is a legitimate general operand 892 when generating PIC code. It is given that flag_pic is on and that 893 X satisfies CONSTANT_P. */ 894bool 895tilegx_legitimate_pic_operand_p (rtx x) 896{ 897 if (tilegx_pic_address_needs_scratch (x)) 898 return false; 899 900 if (tilegx_tls_referenced_p (x)) 901 return false; 902 903 return true; 904} 905 906 907/* Return true if the rtx X can be used as an address operand. */ 908static bool 909tilegx_legitimate_address_p (machine_mode ARG_UNUSED (mode), rtx x, 910 bool strict) 911{ 912 if (GET_CODE (x) == SUBREG) 913 x = SUBREG_REG (x); 914 915 switch (GET_CODE (x)) 916 { 917 case POST_INC: 918 case POST_DEC: 919 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) 920 return false; 921 922 x = XEXP (x, 0); 923 break; 924 925 case POST_MODIFY: 926 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) 927 return false; 928 929 if (GET_CODE (XEXP (x, 1)) != PLUS) 930 return false; 931 932 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0))) 933 return false; 934 935 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1))) 936 return false; 937 938 x = XEXP (x, 0); 939 break; 940 941 case REG: 942 break; 943 944 default: 945 return false; 946 } 947 948 /* Check if x is a valid reg. */ 949 if (!REG_P (x)) 950 return false; 951 952 if (strict) 953 return REGNO_OK_FOR_BASE_P (REGNO (x)); 954 else 955 return true; 956} 957 958 959/* Return the rtx containing SYMBOL_REF to the text label. */ 960static rtx 961tilegx_text_label_symbol (void) 962{ 963 return cfun->machine->text_label_symbol; 964} 965 966 967/* Return the register storing the value of the text label. */ 968static rtx 969tilegx_text_label_rtx (void) 970{ 971 return cfun->machine->text_label_rtx; 972} 973 974 975/* Return the register storing the value of the global offset 976 table. */ 977static rtx 978tilegx_got_rtx (void) 979{ 980 return cfun->machine->got_rtx; 981} 982 983 984/* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */ 985static rtx 986tilegx_got_symbol (void) 987{ 988 if (g_got_symbol == NULL) 989 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 990 991 return g_got_symbol; 992} 993 994 995/* Return a reference to the got to be used by tls references. */ 996static rtx 997tilegx_tls_got (void) 998{ 999 rtx temp; 1000 if (flag_pic) 1001 { 1002 crtl->uses_pic_offset_table = 1; 1003 return tilegx_got_rtx (); 1004 } 1005 1006 temp = gen_reg_rtx (Pmode); 1007 emit_move_insn (temp, tilegx_got_symbol ()); 1008 1009 return temp; 1010} 1011 1012 1013/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute 1014 this (thread-local) address. */ 1015static rtx 1016tilegx_legitimize_tls_address (rtx addr) 1017{ 1018 rtx ret; 1019 1020 gcc_assert (can_create_pseudo_p ()); 1021 1022 if (GET_CODE (addr) == SYMBOL_REF) 1023 switch (SYMBOL_REF_TLS_MODEL (addr)) 1024 { 1025 case TLS_MODEL_GLOBAL_DYNAMIC: 1026 case TLS_MODEL_LOCAL_DYNAMIC: 1027 { 1028 rtx r0, temp, temp2, temp3, got, last; 1029 1030 ret = gen_reg_rtx (Pmode); 1031 r0 = gen_rtx_REG (Pmode, 0); 1032 temp = gen_reg_rtx (Pmode); 1033 temp2 = gen_reg_rtx (Pmode); 1034 temp3 = gen_reg_rtx (Pmode); 1035 1036 got = tilegx_tls_got (); 1037 if (TARGET_32BIT) 1038 { 1039 emit_insn (gen_mov_tls_gd_step1_32bit (temp, addr)); 1040 emit_insn (gen_mov_tls_gd_step2_32bit (temp2, temp, addr)); 1041 emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr)); 1042 } 1043 else 1044 { 1045 emit_insn (gen_mov_tls_gd_step1 (temp, addr)); 1046 emit_insn (gen_mov_tls_gd_step2 (temp2, temp, addr)); 1047 emit_insn (gen_tls_add (temp2, got, temp2, addr)); 1048 } 1049 1050 emit_move_insn (r0, temp2); 1051 1052 if (TARGET_32BIT) 1053 { 1054 emit_insn (gen_tls_gd_call_32bit (addr)); 1055 } 1056 else 1057 { 1058 emit_insn (gen_tls_gd_call (addr)); 1059 } 1060 1061 emit_move_insn (temp3, r0); 1062 1063 if (TARGET_32BIT) 1064 last = emit_insn (gen_tls_gd_add_32bit (ret, temp3, addr)); 1065 else 1066 last = emit_insn (gen_tls_gd_add (ret, temp3, addr)); 1067 1068 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 1069 break; 1070 } 1071 case TLS_MODEL_INITIAL_EXEC: 1072 { 1073 rtx temp, temp2, temp3, got; 1074 rtx_insn *last; 1075 1076 ret = gen_reg_rtx (Pmode); 1077 temp = gen_reg_rtx (Pmode); 1078 temp2 = gen_reg_rtx (Pmode); 1079 temp3 = gen_reg_rtx (Pmode); 1080 1081 got = tilegx_tls_got (); 1082 if (TARGET_32BIT) 1083 { 1084 emit_insn (gen_mov_tls_ie_step1_32bit (temp, addr)); 1085 emit_insn (gen_mov_tls_ie_step2_32bit (temp2, temp, addr)); 1086 emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr)); 1087 emit_insn (gen_tls_ie_load_32bit (temp3, temp2, addr)); 1088 } 1089 else 1090 { 1091 emit_insn (gen_mov_tls_ie_step1 (temp, addr)); 1092 emit_insn (gen_mov_tls_ie_step2 (temp2, temp, addr)); 1093 emit_insn (gen_tls_add (temp2, got, temp2, addr)); 1094 emit_insn (gen_tls_ie_load (temp3, temp2, addr)); 1095 } 1096 1097 last = 1098 emit_move_insn(ret, 1099 gen_rtx_PLUS (Pmode, 1100 gen_rtx_REG (Pmode, 1101 THREAD_POINTER_REGNUM), 1102 temp3)); 1103 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 1104 break; 1105 } 1106 case TLS_MODEL_LOCAL_EXEC: 1107 { 1108 rtx temp, temp2; 1109 rtx_insn *last; 1110 1111 ret = gen_reg_rtx (Pmode); 1112 temp = gen_reg_rtx (Pmode); 1113 temp2 = gen_reg_rtx (Pmode); 1114 1115 if (TARGET_32BIT) 1116 { 1117 emit_insn (gen_mov_tls_le_step1_32bit (temp, addr)); 1118 emit_insn (gen_mov_tls_le_step2_32bit (temp2, temp, addr)); 1119 } 1120 else 1121 { 1122 emit_insn (gen_mov_tls_le_step1 (temp, addr)); 1123 emit_insn (gen_mov_tls_le_step2 (temp2, temp, addr)); 1124 } 1125 1126 last = 1127 emit_move_insn (ret, 1128 gen_rtx_PLUS (Pmode, 1129 gen_rtx_REG (Pmode, 1130 THREAD_POINTER_REGNUM), 1131 temp2)); 1132 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr)); 1133 break; 1134 } 1135 default: 1136 gcc_unreachable (); 1137 } 1138 else if (GET_CODE (addr) == CONST) 1139 { 1140 rtx base, offset; 1141 1142 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS); 1143 1144 base = tilegx_legitimize_tls_address (XEXP (XEXP (addr, 0), 0)); 1145 offset = XEXP (XEXP (addr, 0), 1); 1146 1147 base = force_operand (base, NULL_RTX); 1148 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset)); 1149 } 1150 else 1151 gcc_unreachable (); 1152 1153 return ret; 1154} 1155 1156 1157/* Returns a register that points to ADDR, a symbolic address, by 1158 computing its address relative to tilegx_text_label_symbol. */ 1159void 1160tilegx_compute_pcrel_address (rtx result, rtx addr) 1161{ 1162 rtx text_label_symbol = tilegx_text_label_symbol (); 1163 rtx text_label_rtx = tilegx_text_label_rtx (); 1164 rtx temp, temp2, temp3; 1165 1166 temp = create_temp_reg_if_possible (Pmode, result); 1167 temp2 = create_temp_reg_if_possible (Pmode, result); 1168 1169 if (TARGET_32BIT) 1170 { 1171 emit_insn (gen_mov_pcrel_step1_32bit (temp, addr, text_label_symbol)); 1172 emit_insn (gen_mov_pcrel_step2_32bit (temp2, temp, addr, 1173 text_label_symbol)); 1174 emit_insn (gen_mov_pcrel_step3_32bit (result, temp2, 1175 text_label_rtx, 1176 addr, text_label_symbol)); 1177 } 1178 else if (tilegx_cmodel == CM_LARGE_PIC) 1179 { 1180 temp3 = create_temp_reg_if_possible (Pmode, result); 1181 emit_insn (gen_mov_large_pcrel_step1 (temp, addr, text_label_symbol)); 1182 emit_insn (gen_mov_large_pcrel_step2 (temp2, temp, addr, 1183 text_label_symbol)); 1184 emit_insn (gen_mov_large_pcrel_step3 (temp3, temp2, addr, 1185 text_label_symbol)); 1186 emit_insn (gen_mov_large_pcrel_step4 (result, temp3, 1187 text_label_rtx, 1188 addr, text_label_symbol)); 1189 } 1190 else 1191 { 1192 emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol)); 1193 emit_insn (gen_mov_pcrel_step2 (temp2, temp, addr, text_label_symbol)); 1194 emit_insn (gen_mov_pcrel_step3 (result, temp2, 1195 text_label_rtx, 1196 addr, text_label_symbol)); 1197 } 1198} 1199 1200 1201/* Returns a register that points to the plt entry of ADDR, a symbolic 1202 address, by computing its address relative to 1203 tilegx_text_label_symbol. */ 1204void 1205tilegx_compute_pcrel_plt_address (rtx result, rtx addr) 1206{ 1207 rtx text_label_symbol = tilegx_text_label_symbol (); 1208 rtx text_label_rtx = tilegx_text_label_rtx (); 1209 rtx temp, temp2, temp3; 1210 1211 temp = create_temp_reg_if_possible (Pmode, result); 1212 temp2 = create_temp_reg_if_possible (Pmode, result); 1213 1214 if (TARGET_32BIT) 1215 { 1216 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp, addr, 1217 text_label_symbol)); 1218 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2, temp, addr, 1219 text_label_symbol)); 1220 emit_move_insn (result, gen_rtx_PLUS (Pmode, temp2, text_label_rtx)); 1221 } 1222 else 1223 { 1224 temp3 = create_temp_reg_if_possible (Pmode, result); 1225 1226 emit_insn (gen_mov_plt_pcrel_step1 (temp, addr, text_label_symbol)); 1227 emit_insn (gen_mov_plt_pcrel_step2 (temp2, temp, addr, 1228 text_label_symbol)); 1229 emit_insn (gen_mov_plt_pcrel_step3 (temp3, temp2, addr, 1230 text_label_symbol)); 1231 emit_move_insn (result, gen_rtx_PLUS (Pmode, temp3, text_label_rtx)); 1232 } 1233} 1234 1235 1236/* Legitimize PIC addresses. If the address is already 1237 position-independent, we return ORIG. Newly generated 1238 position-independent addresses go into a reg. This is REG if 1239 nonzero, otherwise we allocate register(s) as necessary. */ 1240static rtx 1241tilegx_legitimize_pic_address (rtx orig, 1242 machine_mode mode ATTRIBUTE_UNUSED, 1243 rtx reg) 1244{ 1245 if (GET_CODE (orig) == SYMBOL_REF) 1246 { 1247 rtx address, pic_ref; 1248 1249 if (reg == 0) 1250 { 1251 gcc_assert (can_create_pseudo_p ()); 1252 reg = gen_reg_rtx (Pmode); 1253 } 1254 1255 if (SYMBOL_REF_LOCAL_P (orig)) 1256 { 1257 /* If not during reload, allocate another temp reg here for 1258 loading in the address, so that these instructions can be 1259 optimized properly. */ 1260 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg); 1261 tilegx_compute_pcrel_address (temp_reg, orig); 1262 1263 /* Note: this is conservative. We use the text_label but we 1264 don't use the pic_offset_table. However, in some cases 1265 we may need the pic_offset_table (see 1266 tilegx_fixup_pcrel_references). */ 1267 crtl->uses_pic_offset_table = 1; 1268 1269 address = temp_reg; 1270 1271 emit_move_insn (reg, address); 1272 return reg; 1273 } 1274 else 1275 { 1276 /* If not during reload, allocate another temp reg here for 1277 loading in the address, so that these instructions can be 1278 optimized properly. */ 1279 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg); 1280 1281 gcc_assert (flag_pic); 1282 if (flag_pic == 1) 1283 { 1284 if (TARGET_32BIT) 1285 { 1286 emit_insn (gen_add_got16_32bit (temp_reg, 1287 tilegx_got_rtx (), 1288 orig)); 1289 } 1290 else 1291 { 1292 emit_insn (gen_add_got16 (temp_reg, 1293 tilegx_got_rtx (), orig)); 1294 } 1295 } 1296 else 1297 { 1298 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg); 1299 rtx temp_reg3 = create_temp_reg_if_possible (Pmode, reg); 1300 if (TARGET_32BIT) 1301 { 1302 emit_insn (gen_mov_got32_step1_32bit (temp_reg3, orig)); 1303 emit_insn (gen_mov_got32_step2_32bit 1304 (temp_reg2, temp_reg3, orig)); 1305 } 1306 else 1307 { 1308 emit_insn (gen_mov_got32_step1 (temp_reg3, orig)); 1309 emit_insn (gen_mov_got32_step2 (temp_reg2, temp_reg3, 1310 orig)); 1311 } 1312 emit_move_insn (temp_reg, 1313 gen_rtx_PLUS (Pmode, 1314 tilegx_got_rtx (), temp_reg2)); 1315 } 1316 1317 address = temp_reg; 1318 1319 pic_ref = gen_const_mem (Pmode, address); 1320 crtl->uses_pic_offset_table = 1; 1321 emit_move_insn (reg, pic_ref); 1322 /* The following put a REG_EQUAL note on this insn, so that 1323 it can be optimized by loop. But it causes the label to 1324 be optimized away. */ 1325 /* set_unique_reg_note (insn, REG_EQUAL, orig); */ 1326 return reg; 1327 } 1328 } 1329 else if (GET_CODE (orig) == CONST) 1330 { 1331 rtx base, offset; 1332 1333 if (GET_CODE (XEXP (orig, 0)) == PLUS 1334 && XEXP (XEXP (orig, 0), 0) == tilegx_got_rtx ()) 1335 return orig; 1336 1337 if (reg == 0) 1338 { 1339 gcc_assert (can_create_pseudo_p ()); 1340 reg = gen_reg_rtx (Pmode); 1341 } 1342 1343 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); 1344 base = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), 1345 Pmode, reg); 1346 offset = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, 1347 base == reg ? 0 : reg); 1348 1349 if (CONST_INT_P (offset)) 1350 { 1351 if (can_create_pseudo_p ()) 1352 offset = force_reg (Pmode, offset); 1353 else 1354 /* If we reach here, then something is seriously wrong. */ 1355 gcc_unreachable (); 1356 } 1357 1358 if (can_create_pseudo_p ()) 1359 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset)); 1360 else 1361 gcc_unreachable (); 1362 } 1363 else if (GET_CODE (orig) == LABEL_REF) 1364 { 1365 rtx address; 1366 rtx temp_reg; 1367 1368 if (reg == 0) 1369 { 1370 gcc_assert (can_create_pseudo_p ()); 1371 reg = gen_reg_rtx (Pmode); 1372 } 1373 1374 /* If not during reload, allocate another temp reg here for 1375 loading in the address, so that these instructions can be 1376 optimized properly. */ 1377 temp_reg = create_temp_reg_if_possible (Pmode, reg); 1378 tilegx_compute_pcrel_address (temp_reg, orig); 1379 1380 /* Note: this is conservative. We use the text_label but we 1381 don't use the pic_offset_table. */ 1382 crtl->uses_pic_offset_table = 1; 1383 1384 address = temp_reg; 1385 1386 emit_move_insn (reg, address); 1387 1388 return reg; 1389 } 1390 1391 return orig; 1392} 1393 1394 1395/* Implement TARGET_LEGITIMIZE_ADDRESS. */ 1396static rtx 1397tilegx_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 1398 machine_mode mode) 1399{ 1400 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD 1401 && symbolic_operand (x, Pmode) && tilegx_tls_referenced_p (x)) 1402 { 1403 return tilegx_legitimize_tls_address (x); 1404 } 1405 else if (flag_pic) 1406 { 1407 return tilegx_legitimize_pic_address (x, mode, 0); 1408 } 1409 else 1410 return x; 1411} 1412 1413 1414/* Implement TARGET_DELEGITIMIZE_ADDRESS. */ 1415static rtx 1416tilegx_delegitimize_address (rtx x) 1417{ 1418 x = delegitimize_mem_from_attrs (x); 1419 1420 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC) 1421 { 1422 switch (XINT (XEXP (x, 0), 1)) 1423 { 1424 case UNSPEC_HW0: 1425 case UNSPEC_HW1: 1426 case UNSPEC_HW2: 1427 case UNSPEC_HW3: 1428 case UNSPEC_HW0_LAST: 1429 case UNSPEC_HW1_LAST: 1430 case UNSPEC_HW2_LAST: 1431 case UNSPEC_HW0_PCREL: 1432 case UNSPEC_HW1_PCREL: 1433 case UNSPEC_HW1_LAST_PCREL: 1434 case UNSPEC_HW2_LAST_PCREL: 1435 case UNSPEC_HW0_PLT_PCREL: 1436 case UNSPEC_HW1_PLT_PCREL: 1437 case UNSPEC_HW1_LAST_PLT_PCREL: 1438 case UNSPEC_HW2_LAST_PLT_PCREL: 1439 case UNSPEC_HW0_GOT: 1440 case UNSPEC_HW0_LAST_GOT: 1441 case UNSPEC_HW1_LAST_GOT: 1442 case UNSPEC_HW0_TLS_GD: 1443 case UNSPEC_HW1_LAST_TLS_GD: 1444 case UNSPEC_HW0_TLS_IE: 1445 case UNSPEC_HW1_LAST_TLS_IE: 1446 case UNSPEC_HW0_TLS_LE: 1447 case UNSPEC_HW1_LAST_TLS_LE: 1448 x = XVECEXP (XEXP (x, 0), 0, 0); 1449 break; 1450 } 1451 } 1452 1453 return x; 1454} 1455 1456 1457/* Emit code to load the PIC register. */ 1458static void 1459load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED) 1460{ 1461 int orig_flag_pic = flag_pic; 1462 1463 rtx got_symbol = tilegx_got_symbol (); 1464 rtx text_label_symbol = tilegx_text_label_symbol (); 1465 rtx text_label_rtx = tilegx_text_label_rtx (); 1466 flag_pic = 0; 1467 1468 if (TARGET_32BIT) 1469 { 1470 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx, 1471 text_label_symbol)); 1472 } 1473 else 1474 { 1475 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol)); 1476 } 1477 1478 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol); 1479 1480 flag_pic = orig_flag_pic; 1481 1482 /* Need to emit this whether or not we obey regdecls, since 1483 setjmp/longjmp can cause life info to screw up. ??? In the case 1484 where we don't obey regdecls, this is not sufficient since we may 1485 not fall out the bottom. */ 1486 emit_use (tilegx_got_rtx ()); 1487} 1488 1489 1490/* Return the simd variant of the constant NUM of mode MODE, by 1491 replicating it to fill an interger of mode DImode. NUM is first 1492 truncated to fit in MODE. */ 1493rtx 1494tilegx_simd_int (rtx num, machine_mode mode) 1495{ 1496 HOST_WIDE_INT n = 0; 1497 1498 gcc_assert (CONST_INT_P (num)); 1499 1500 n = INTVAL (num); 1501 1502 switch (mode) 1503 { 1504 case QImode: 1505 n = 0x0101010101010101LL * (n & 0x000000FF); 1506 break; 1507 case HImode: 1508 n = 0x0001000100010001LL * (n & 0x0000FFFF); 1509 break; 1510 case SImode: 1511 n = 0x0000000100000001LL * (n & 0xFFFFFFFF); 1512 break; 1513 case DImode: 1514 break; 1515 default: 1516 gcc_unreachable (); 1517 } 1518 1519 return GEN_INT (n); 1520} 1521 1522 1523/* Returns true iff VAL can be moved into a register in one 1524 instruction. And if it can, it emits the code to move the constant 1525 into DEST_REG. 1526 1527 If THREE_WIDE_ONLY is true, this insists on an instruction that 1528 works in a bundle containing three instructions. */ 1529static bool 1530expand_set_cint64_one_inst (rtx dest_reg, 1531 HOST_WIDE_INT val, bool three_wide_only) 1532{ 1533 if (val == trunc_int_for_mode (val, QImode)) 1534 { 1535 /* Success! */ 1536 emit_move_insn (dest_reg, GEN_INT (val)); 1537 return true; 1538 } 1539 else if (!three_wide_only) 1540 { 1541 /* Test for the following constraints: J, K, N, P. We avoid 1542 generating an rtx and using existing predicates because we 1543 can be testing and rejecting a lot of constants, and GEN_INT 1544 is O(N). */ 1545 if ((val >= -32768 && val <= 65535) 1546 || ((val == (val & 0xFF) * 0x0101010101010101LL)) 1547 || (val == ((trunc_int_for_mode (val, QImode) & 0xFFFF) 1548 * 0x0001000100010001LL))) 1549 { 1550 emit_move_insn (dest_reg, GEN_INT (val)); 1551 return true; 1552 } 1553 } 1554 1555 return false; 1556} 1557 1558 1559/* Implement DImode rotatert. */ 1560static HOST_WIDE_INT 1561rotate_right (HOST_WIDE_INT n, int count) 1562{ 1563 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFFFFFFFFFFULL; 1564 if (count == 0) 1565 return x; 1566 return ((x >> count) | (x << (64 - count))) & 0xFFFFFFFFFFFFFFFFULL; 1567} 1568 1569 1570/* Return true iff n contains exactly one contiguous sequence of 1 1571 bits, possibly wrapping around from high bits to low bits. */ 1572bool 1573tilegx_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit) 1574{ 1575 int i; 1576 1577 if (n == 0) 1578 return false; 1579 1580 for (i = 0; i < 64; i++) 1581 { 1582 unsigned HOST_WIDE_INT x = rotate_right (n, i); 1583 if (!(x & 1)) 1584 continue; 1585 1586 /* See if x is a power of two minus one, i.e. only consecutive 1 1587 bits starting from bit 0. */ 1588 if ((x & (x + 1)) == 0) 1589 { 1590 if (first_bit != NULL) 1591 *first_bit = i; 1592 if (last_bit != NULL) 1593 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 63; 1594 1595 return true; 1596 } 1597 } 1598 1599 return false; 1600} 1601 1602 1603/* Create code to move the CONST_INT value in src_val to dest_reg. */ 1604static void 1605expand_set_cint64 (rtx dest_reg, rtx src_val) 1606{ 1607 HOST_WIDE_INT val; 1608 int leading_zeroes, trailing_zeroes; 1609 int three_wide_only; 1610 int shift, ins_shift, zero_cluster_shift; 1611 rtx temp, subreg; 1612 1613 gcc_assert (CONST_INT_P (src_val)); 1614 val = trunc_int_for_mode (INTVAL (src_val), GET_MODE (dest_reg)); 1615 1616 /* See if we can generate the constant in one instruction. */ 1617 if (expand_set_cint64_one_inst (dest_reg, val, false)) 1618 return; 1619 1620 /* Force the destination to DImode so we can use DImode instructions 1621 to create it. This both allows instructions like rotl, and 1622 certain efficient 3-wide instructions. */ 1623 subreg = simplify_gen_subreg (DImode, dest_reg, GET_MODE (dest_reg), 0); 1624 gcc_assert (subreg != NULL); 1625 dest_reg = subreg; 1626 1627 temp = create_temp_reg_if_possible (DImode, dest_reg); 1628 1629 leading_zeroes = 63 - floor_log2 (val & 0xFFFFFFFFFFFFFFFFULL); 1630 trailing_zeroes = exact_log2 (val & -val); 1631 1632 /* First try all three-wide instructions that generate a constant 1633 (i.e. movei) followed by various shifts and rotates. If none of 1634 those work, try various two-wide ways of generating a constant 1635 followed by various shifts and rotates. */ 1636 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--) 1637 { 1638 int count; 1639 1640 if (expand_set_cint64_one_inst (temp, val >> trailing_zeroes, 1641 three_wide_only)) 1642 { 1643 /* 0xFFFFFFFFFFFFA500 becomes: 1644 movei temp, 0xFFFFFFFFFFFFFFA5 1645 shli dest, temp, 8 */ 1646 emit_move_insn (dest_reg, 1647 gen_rtx_ASHIFT (DImode, temp, 1648 GEN_INT (trailing_zeroes))); 1649 return; 1650 } 1651 1652 if (expand_set_cint64_one_inst (temp, val << leading_zeroes, 1653 three_wide_only)) 1654 { 1655 /* 0x7FFFFFFFFFFFFFFF becomes: 1656 movei temp, -2 1657 shrui dest, temp, 1 */ 1658 emit_move_insn (dest_reg, 1659 gen_rtx_LSHIFTRT (DImode, temp, 1660 GEN_INT (leading_zeroes))); 1661 return; 1662 } 1663 1664 /* Try rotating a one-instruction immediate. */ 1665 for (count = 1; count < 64; count++) 1666 { 1667 HOST_WIDE_INT r = rotate_right (val, count); 1668 if (expand_set_cint64_one_inst (temp, r, three_wide_only)) 1669 { 1670 /* 0xFFFFFFFFFFA5FFFF becomes: 1671 movei temp, 0xFFFFFFFFFFFFFFA5 1672 rotli dest, temp, 16 */ 1673 emit_move_insn (dest_reg, 1674 gen_rtx_ROTATE (DImode, temp, GEN_INT (count))); 1675 return; 1676 } 1677 } 1678 } 1679 1680 /* There are two cases here to produce a large constant. 1681 In the most general case, we do this: 1682 1683 moveli x, hw3(NUM) 1684 shl16insli x, x, hw2(NUM) 1685 shl16insli x, x, hw1(NUM) 1686 shl16insli x, x, hw0(NUM) 1687 1688 However, we can sometimes do better. shl16insli is a poor way to 1689 insert 16 zero bits, because simply shifting left by 16 has more 1690 bundling freedom. So if we see any contiguous aligned sequence 1691 of 16 or more zero bits (below the highest set bit), it is always 1692 more efficient to materialize the bits above the zero bits, then 1693 left shift to put in the zeroes, then insert whatever bits 1694 remain. For example, we might end up with: 1695 1696 movei x, NUM >> (37 + 16) 1697 shli x, x, 37 1698 shl16insli x, x, hw0(NUM) */ 1699 1700 zero_cluster_shift = -1; 1701 1702 for (shift = 0; shift < 48 - leading_zeroes; shift += 16) 1703 { 1704 HOST_WIDE_INT x = val >> shift; 1705 1706 /* Find the least significant group of 16 aligned zero bits. */ 1707 if ((x & 0xFFFF) == 0x0000) 1708 { 1709 /* Grab any following zero bits as well. */ 1710 zero_cluster_shift = exact_log2 (x & -x); 1711 shift += zero_cluster_shift; 1712 break; 1713 } 1714 } 1715 1716 if (zero_cluster_shift >= 0) 1717 { 1718 unsigned HOST_WIDE_INT leftover; 1719 1720 /* Recursively create the constant above the lowest 16 zero 1721 bits. */ 1722 expand_set_cint64 (temp, GEN_INT (val >> shift)); 1723 1724 /* See if we can easily insert the remaining bits, or if we need 1725 to fall through to the more general case. */ 1726 leftover = val - ((val >> shift) << shift); 1727 if (leftover == 0) 1728 { 1729 /* A simple left shift is enough. */ 1730 emit_move_insn (dest_reg, 1731 gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift))); 1732 return; 1733 } 1734 else if (leftover <= 32767) 1735 { 1736 /* Left shift into position then add in the leftover. */ 1737 rtx temp2 = create_temp_reg_if_possible (DImode, temp); 1738 emit_move_insn (temp2, 1739 gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift))); 1740 emit_move_insn (dest_reg, 1741 gen_rtx_PLUS (DImode, temp2, GEN_INT (leftover))); 1742 return; 1743 } 1744 else 1745 { 1746 /* Shift in the batch of >= 16 zeroes we detected earlier. 1747 After this, shift will be aligned mod 16 so the final 1748 loop can use shl16insli. */ 1749 rtx temp2 = create_temp_reg_if_possible (DImode, temp); 1750 rtx shift_count_rtx = GEN_INT (zero_cluster_shift); 1751 1752 emit_move_insn (temp2, 1753 gen_rtx_ASHIFT (DImode, temp, shift_count_rtx)); 1754 1755 shift -= zero_cluster_shift; 1756 temp = temp2; 1757 } 1758 } 1759 else 1760 { 1761 /* Set as many high 16-bit blocks as we can with a single 1762 instruction. We'll insert the remaining 16-bit blocks 1763 below. */ 1764 for (shift = 16;; shift += 16) 1765 { 1766 gcc_assert (shift < 64); 1767 if (expand_set_cint64_one_inst (temp, val >> shift, false)) 1768 break; 1769 } 1770 } 1771 1772 /* At this point, temp == val >> shift, shift % 16 == 0, and we 1773 still need to insert any bits of 'val' below 'shift'. Those bits 1774 are guaranteed to not have 16 contiguous zeroes. */ 1775 1776 gcc_assert ((shift & 15) == 0); 1777 1778 for (ins_shift = shift - 16; ins_shift >= 0; ins_shift -= 16) 1779 { 1780 rtx result; 1781 HOST_WIDE_INT bits = (val >> ins_shift) & 0xFFFF; 1782 gcc_assert (bits != 0); 1783 1784 /* On the last iteration we need to store into dest_reg. */ 1785 if (ins_shift == 0) 1786 result = dest_reg; 1787 else 1788 result = create_temp_reg_if_possible (DImode, dest_reg); 1789 1790 emit_insn (gen_insn_shl16insli (result, temp, GEN_INT (bits))); 1791 1792 temp = result; 1793 } 1794} 1795 1796 1797/* Load OP1, a 64-bit constant, into OP0, a register. We know it 1798 can't be done in one insn when we get here, the move expander 1799 guarantees this. */ 1800void 1801tilegx_expand_set_const64 (rtx op0, rtx op1) 1802{ 1803 if (CONST_INT_P (op1)) 1804 { 1805 /* TODO: I don't know if we want to split large constants 1806 now, or wait until later (with a define_split). 1807 1808 Does splitting early help CSE? Does it harm other 1809 optimizations that might fold loads? */ 1810 expand_set_cint64 (op0, op1); 1811 } 1812 else 1813 { 1814 rtx temp = create_temp_reg_if_possible (Pmode, op0); 1815 1816 if (TARGET_32BIT) 1817 { 1818 /* Generate the 2-insn sequence to materialize a symbolic 1819 address. */ 1820 emit_insn (gen_mov_address_32bit_step1 (temp, op1)); 1821 emit_insn (gen_mov_address_32bit_step2 (op0, temp, op1)); 1822 } 1823 else 1824 { 1825 /* Generate the 3-insn sequence to materialize a symbolic 1826 address. Note that this assumes that virtual addresses 1827 fit in 48 signed bits, which is currently true. */ 1828 rtx temp2 = create_temp_reg_if_possible (Pmode, op0); 1829 emit_insn (gen_mov_address_step1 (temp, op1)); 1830 emit_insn (gen_mov_address_step2 (temp2, temp, op1)); 1831 emit_insn (gen_mov_address_step3 (op0, temp2, op1)); 1832 } 1833 } 1834} 1835 1836 1837/* Expand a move instruction. Return true if all work is done. */ 1838bool 1839tilegx_expand_mov (machine_mode mode, rtx *operands) 1840{ 1841 /* Handle sets of MEM first. */ 1842 if (MEM_P (operands[0])) 1843 { 1844 if (can_create_pseudo_p ()) 1845 operands[0] = validize_mem (operands[0]); 1846 1847 if (reg_or_0_operand (operands[1], mode)) 1848 return false; 1849 1850 if (!reload_in_progress) 1851 operands[1] = force_reg (mode, operands[1]); 1852 } 1853 1854 /* Fixup TLS cases. */ 1855 if (CONSTANT_P (operands[1]) && tilegx_tls_referenced_p (operands[1])) 1856 { 1857 operands[1] = tilegx_legitimize_tls_address (operands[1]); 1858 return false; 1859 } 1860 1861 /* Fixup PIC cases. */ 1862 if (flag_pic && CONSTANT_P (operands[1])) 1863 { 1864 if (tilegx_pic_address_needs_scratch (operands[1])) 1865 operands[1] = tilegx_legitimize_pic_address (operands[1], mode, 0); 1866 1867 if (symbolic_operand (operands[1], mode)) 1868 { 1869 operands[1] = tilegx_legitimize_pic_address (operands[1], 1870 mode, 1871 (reload_in_progress ? 1872 operands[0] : 1873 NULL_RTX)); 1874 return false; 1875 } 1876 } 1877 1878 /* Accept non-constants and valid constants unmodified. */ 1879 if (!CONSTANT_P (operands[1]) || move_operand (operands[1], mode)) 1880 return false; 1881 1882 /* Split large integers. */ 1883 tilegx_expand_set_const64 (operands[0], operands[1]); 1884 return true; 1885} 1886 1887 1888/* Expand unaligned loads. */ 1889void 1890tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize, 1891 HOST_WIDE_INT bit_offset, bool sign) 1892{ 1893 machine_mode mode; 1894 rtx addr_lo, addr_hi; 1895 rtx mem_lo, mem_hi, hi; 1896 rtx mema, wide_result; 1897 int last_byte_offset; 1898 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT; 1899 1900 mode = GET_MODE (dest_reg); 1901 1902 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0) 1903 { 1904 rtx mem_left, mem_right; 1905 rtx left = gen_reg_rtx (mode); 1906 1907 /* When just loading a two byte value, we can load the two bytes 1908 individually and combine them efficiently. */ 1909 1910 mem_lo = adjust_address (mem, QImode, byte_offset); 1911 mem_hi = adjust_address (mem, QImode, byte_offset + 1); 1912 1913 if (BYTES_BIG_ENDIAN) 1914 { 1915 mem_left = mem_lo; 1916 mem_right = mem_hi; 1917 } 1918 else 1919 { 1920 mem_left = mem_hi; 1921 mem_right = mem_lo; 1922 } 1923 1924 if (sign) 1925 { 1926 /* Do a signed load of the second byte and use bfins to set 1927 the high bits of the result. */ 1928 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, dest_reg), 1929 mem_right)); 1930 emit_insn (gen_extendqidi2 (gen_lowpart (DImode, left), mem_left)); 1931 emit_insn (gen_insv (gen_lowpart (DImode, dest_reg), 1932 GEN_INT (64 - 8), GEN_INT (8), 1933 gen_lowpart (DImode, left))); 1934 } 1935 else 1936 { 1937 /* Do two unsigned loads and use v1int_l to interleave 1938 them. */ 1939 rtx right = gen_reg_rtx (mode); 1940 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, right), 1941 mem_right)); 1942 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, left), 1943 mem_left)); 1944 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode, dest_reg), 1945 gen_lowpart (DImode, left), 1946 gen_lowpart (DImode, right))); 1947 } 1948 1949 return; 1950 } 1951 1952 mema = XEXP (mem, 0); 1953 1954 /* AND addresses cannot be in any alias set, since they may 1955 implicitly alias surrounding code. Ideally we'd have some alias 1956 set that covered all types except those with alignment 8 or 1957 higher. */ 1958 addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset)); 1959 mem_lo = change_address (mem, mode, 1960 gen_rtx_AND (GET_MODE (mema), addr_lo, 1961 GEN_INT (-8))); 1962 set_mem_alias_set (mem_lo, 0); 1963 1964 /* Load the high word at an address that will not fault if the low 1965 address is aligned and at the very end of a page. */ 1966 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT; 1967 addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset)); 1968 mem_hi = change_address (mem, mode, 1969 gen_rtx_AND (GET_MODE (mema), addr_hi, 1970 GEN_INT (-8))); 1971 set_mem_alias_set (mem_hi, 0); 1972 1973 if (bitsize == 64) 1974 { 1975 addr_lo = make_safe_from (addr_lo, dest_reg); 1976 wide_result = dest_reg; 1977 } 1978 else 1979 { 1980 wide_result = gen_reg_rtx (mode); 1981 } 1982 1983 /* Load hi first in case dest_reg is used in mema. */ 1984 hi = gen_reg_rtx (mode); 1985 emit_move_insn (hi, mem_hi); 1986 emit_move_insn (wide_result, mem_lo); 1987 1988 emit_insn (gen_insn_dblalign (gen_lowpart (DImode, wide_result), 1989 gen_lowpart (DImode, wide_result), 1990 gen_lowpart (DImode, hi), addr_lo)); 1991 1992 if (bitsize != 64) 1993 { 1994 rtx extracted = 1995 extract_bit_field (gen_lowpart (DImode, wide_result), 1996 bitsize, bit_offset % BITS_PER_UNIT, 1997 !sign, gen_lowpart (DImode, dest_reg), 1998 DImode, DImode); 1999 2000 if (extracted != dest_reg) 2001 emit_move_insn (dest_reg, gen_lowpart (DImode, extracted)); 2002 } 2003} 2004 2005 2006/* Expand unaligned stores. */ 2007static void 2008tilegx_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize, 2009 HOST_WIDE_INT bit_offset) 2010{ 2011 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT; 2012 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT; 2013 HOST_WIDE_INT shift_init, shift_increment, shift_amt; 2014 HOST_WIDE_INT i; 2015 rtx mem_addr; 2016 rtx store_val; 2017 2018 shift_init = BYTES_BIG_ENDIAN ? (bitsize - BITS_PER_UNIT) : 0; 2019 shift_increment = BYTES_BIG_ENDIAN ? -BITS_PER_UNIT : BITS_PER_UNIT; 2020 2021 for (i = 0, shift_amt = shift_init; 2022 i < bytesize; 2023 i++, shift_amt += shift_increment) 2024 { 2025 mem_addr = adjust_address (mem, QImode, byte_offset + i); 2026 2027 if (shift_amt) 2028 { 2029 store_val = expand_simple_binop (DImode, LSHIFTRT, 2030 gen_lowpart (DImode, src), 2031 GEN_INT (shift_amt), NULL, 1, 2032 OPTAB_LIB_WIDEN); 2033 store_val = gen_lowpart (QImode, store_val); 2034 } 2035 else 2036 { 2037 store_val = gen_lowpart (QImode, src); 2038 } 2039 2040 emit_move_insn (mem_addr, store_val); 2041 } 2042} 2043 2044 2045/* Implement the movmisalign patterns. One of the operands is a 2046 memory that is not naturally aligned. Emit instructions to load 2047 it. */ 2048void 2049tilegx_expand_movmisalign (machine_mode mode, rtx *operands) 2050{ 2051 if (MEM_P (operands[1])) 2052 { 2053 rtx tmp; 2054 2055 if (register_operand (operands[0], mode)) 2056 tmp = operands[0]; 2057 else 2058 tmp = gen_reg_rtx (mode); 2059 2060 tilegx_expand_unaligned_load (tmp, operands[1], GET_MODE_BITSIZE (mode), 2061 0, true); 2062 2063 if (tmp != operands[0]) 2064 emit_move_insn (operands[0], tmp); 2065 } 2066 else if (MEM_P (operands[0])) 2067 { 2068 if (!reg_or_0_operand (operands[1], mode)) 2069 operands[1] = force_reg (mode, operands[1]); 2070 2071 tilegx_expand_unaligned_store (operands[0], operands[1], 2072 GET_MODE_BITSIZE (mode), 0); 2073 } 2074 else 2075 gcc_unreachable (); 2076 2077} 2078 2079 2080/* Implement the allocate_stack pattern (alloca). */ 2081void 2082tilegx_allocate_stack (rtx op0, rtx op1) 2083{ 2084 /* Technically the correct way to initialize chain_loc is with 2085 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem() 2086 * sets the alias_set to that of a frame reference. Some of our 2087 * tests rely on some unsafe assumption about when the chaining 2088 * update is done, we need to be conservative about reordering the 2089 * chaining instructions. 2090 */ 2091 rtx fp_addr = gen_reg_rtx (Pmode); 2092 rtx fp_value = gen_reg_rtx (Pmode); 2093 rtx fp_loc; 2094 2095 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx, 2096 GEN_INT (UNITS_PER_WORD))); 2097 2098 fp_loc = gen_frame_mem (Pmode, fp_addr); 2099 2100 emit_move_insn (fp_value, fp_loc); 2101 2102 op1 = force_reg (Pmode, op1); 2103 2104 emit_move_insn (stack_pointer_rtx, 2105 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1)); 2106 2107 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx, 2108 GEN_INT (UNITS_PER_WORD))); 2109 2110 fp_loc = gen_frame_mem (Pmode, fp_addr); 2111 2112 emit_move_insn (fp_loc, fp_value); 2113 2114 emit_move_insn (op0, virtual_stack_dynamic_rtx); 2115} 2116 2117 2118 2119/* Multiplies */ 2120 2121 2122/* Returns the insn_code in ENTRY. */ 2123static enum insn_code 2124tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry 2125 *entry) 2126{ 2127 return tilegx_multiply_insn_seq_decode_opcode[entry->compressed_opcode]; 2128} 2129 2130 2131/* Returns the length of the 'op' array. */ 2132static int 2133tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq *seq) 2134{ 2135 /* The array either uses all of its allocated slots or is terminated 2136 by a bogus opcode. Either way, the array size is the index of the 2137 last valid opcode plus one. */ 2138 int i; 2139 for (i = tilegx_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--) 2140 if (tilegx_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing) 2141 return i + 1; 2142 2143 /* An empty array is not allowed. */ 2144 gcc_unreachable (); 2145} 2146 2147 2148/* We precompute a number of expression trees for multiplying by 2149 constants. This generates code for such an expression tree by 2150 walking through the nodes in the tree (which are conveniently 2151 pre-linearized) and emitting an instruction for each one. */ 2152static void 2153tilegx_expand_constant_multiply_given_sequence (rtx result, rtx src, 2154 const struct 2155 tilegx_multiply_insn_seq *seq) 2156{ 2157 int i; 2158 int num_ops; 2159 2160 /* Keep track of the subexpressions computed so far, so later 2161 instructions can refer to them. We seed the array with zero and 2162 the value being multiplied. */ 2163 int num_subexprs = 2; 2164 rtx subexprs[tilegx_multiply_insn_seq_MAX_OPERATIONS + 2]; 2165 subexprs[0] = const0_rtx; 2166 subexprs[1] = src; 2167 2168 /* Determine how many instructions we are going to generate. */ 2169 num_ops = tilegx_multiply_get_num_ops (seq); 2170 gcc_assert (num_ops > 0 2171 && num_ops <= tilegx_multiply_insn_seq_MAX_OPERATIONS); 2172 2173 for (i = 0; i < num_ops; i++) 2174 { 2175 const struct tilegx_multiply_insn_seq_entry *entry = &seq->op[i]; 2176 2177 /* Figure out where to store the output of this instruction. */ 2178 const bool is_last_op = (i + 1 == num_ops); 2179 rtx out = is_last_op ? result : gen_reg_rtx (DImode); 2180 2181 enum insn_code opcode = tilegx_multiply_get_opcode (entry); 2182 if (opcode == CODE_FOR_ashldi3) 2183 { 2184 /* Handle shift by immediate. This is a special case because 2185 the meaning of the second operand is a constant shift 2186 count rather than an operand index. */ 2187 2188 /* Make sure the shift count is in range. Zero should not 2189 happen. */ 2190 const int shift_count = entry->rhs; 2191 gcc_assert (shift_count > 0 && shift_count < 64); 2192 2193 /* Emit the actual instruction. */ 2194 emit_insn (GEN_FCN (opcode) 2195 (out, subexprs[entry->lhs], 2196 gen_rtx_CONST_INT (DImode, shift_count))); 2197 } 2198 else 2199 { 2200 /* Handle a normal two-operand instruction, such as add or 2201 shl1add. */ 2202 2203 /* Make sure we are referring to a previously computed 2204 subexpression. */ 2205 gcc_assert (entry->rhs < num_subexprs); 2206 2207 /* Emit the actual instruction. */ 2208 emit_insn (GEN_FCN (opcode) 2209 (out, subexprs[entry->lhs], subexprs[entry->rhs])); 2210 } 2211 2212 /* Record this subexpression for use by later expressions. */ 2213 subexprs[num_subexprs++] = out; 2214 } 2215} 2216 2217 2218/* bsearch helper function. */ 2219static int 2220tilegx_compare_multipliers (const void *key, const void *t) 2221{ 2222 long long delta = 2223 (*(const long long *) key 2224 - ((const struct tilegx_multiply_insn_seq *) t)->multiplier); 2225 return (delta < 0) ? -1 : (delta > 0); 2226} 2227 2228 2229/* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none 2230 exists. */ 2231static const struct tilegx_multiply_insn_seq * 2232tilegx_find_multiply_insn_seq_for_constant (long long multiplier) 2233{ 2234 return ((const struct tilegx_multiply_insn_seq *) 2235 bsearch (&multiplier, tilegx_multiply_insn_seq_table, 2236 tilegx_multiply_insn_seq_table_size, 2237 sizeof tilegx_multiply_insn_seq_table[0], 2238 tilegx_compare_multipliers)); 2239} 2240 2241 2242/* Try to a expand constant multiply in DImode by looking it up in a 2243 precompiled table. OP0 is the result operand, OP1 is the source 2244 operand, and MULTIPLIER is the value of the constant. Return true 2245 if it succeeds. */ 2246static bool 2247tilegx_expand_const_muldi (rtx op0, rtx op1, long long multiplier) 2248{ 2249 /* See if we have precomputed an efficient way to multiply by this 2250 constant. */ 2251 const struct tilegx_multiply_insn_seq *seq = 2252 tilegx_find_multiply_insn_seq_for_constant (multiplier); 2253 if (seq != NULL) 2254 { 2255 tilegx_expand_constant_multiply_given_sequence (op0, op1, seq); 2256 return true; 2257 } 2258 else 2259 return false; 2260} 2261 2262 2263/* Expand the muldi pattern. */ 2264bool 2265tilegx_expand_muldi (rtx op0, rtx op1, rtx op2) 2266{ 2267 if (CONST_INT_P (op2)) 2268 { 2269 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), DImode); 2270 return tilegx_expand_const_muldi (op0, op1, n); 2271 } 2272 return false; 2273} 2274 2275 2276/* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the 2277 operands, and SIGN is true if it's a signed multiply, and false if 2278 it's an unsigned multiply. */ 2279static void 2280tilegx_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign) 2281{ 2282 rtx tmp0 = gen_reg_rtx (DImode); 2283 rtx tmp1 = gen_reg_rtx (DImode); 2284 rtx tmp2 = gen_reg_rtx (DImode); 2285 rtx tmp3 = gen_reg_rtx (DImode); 2286 rtx tmp4 = gen_reg_rtx (DImode); 2287 rtx tmp5 = gen_reg_rtx (DImode); 2288 rtx tmp6 = gen_reg_rtx (DImode); 2289 rtx tmp7 = gen_reg_rtx (DImode); 2290 rtx tmp8 = gen_reg_rtx (DImode); 2291 rtx tmp9 = gen_reg_rtx (DImode); 2292 rtx tmp10 = gen_reg_rtx (DImode); 2293 rtx tmp11 = gen_reg_rtx (DImode); 2294 rtx tmp12 = gen_reg_rtx (DImode); 2295 rtx tmp13 = gen_reg_rtx (DImode); 2296 rtx result_lo = gen_reg_rtx (DImode); 2297 2298 if (sign) 2299 { 2300 emit_insn (gen_insn_mul_hs_lu (tmp0, op1, op2)); 2301 emit_insn (gen_insn_mul_hs_lu (tmp1, op2, op1)); 2302 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2)); 2303 emit_insn (gen_insn_mul_hs_hs (tmp3, op1, op2)); 2304 } 2305 else 2306 { 2307 emit_insn (gen_insn_mul_hu_lu (tmp0, op1, op2)); 2308 emit_insn (gen_insn_mul_hu_lu (tmp1, op2, op1)); 2309 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2)); 2310 emit_insn (gen_insn_mul_hu_hu (tmp3, op1, op2)); 2311 } 2312 2313 emit_move_insn (tmp4, (gen_rtx_ASHIFT (DImode, tmp0, GEN_INT (32)))); 2314 2315 emit_move_insn (tmp5, (gen_rtx_ASHIFT (DImode, tmp1, GEN_INT (32)))); 2316 2317 emit_move_insn (tmp6, (gen_rtx_PLUS (DImode, tmp4, tmp5))); 2318 emit_move_insn (result_lo, (gen_rtx_PLUS (DImode, tmp2, tmp6))); 2319 2320 emit_move_insn (tmp7, gen_rtx_LTU (DImode, tmp6, tmp4)); 2321 emit_move_insn (tmp8, gen_rtx_LTU (DImode, result_lo, tmp2)); 2322 2323 if (sign) 2324 { 2325 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (DImode, tmp0, GEN_INT (32)))); 2326 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (DImode, tmp1, GEN_INT (32)))); 2327 } 2328 else 2329 { 2330 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (DImode, tmp0, GEN_INT (32)))); 2331 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (32)))); 2332 } 2333 2334 emit_move_insn (tmp11, (gen_rtx_PLUS (DImode, tmp3, tmp7))); 2335 emit_move_insn (tmp12, (gen_rtx_PLUS (DImode, tmp8, tmp9))); 2336 emit_move_insn (tmp13, (gen_rtx_PLUS (DImode, tmp11, tmp12))); 2337 emit_move_insn (result, (gen_rtx_PLUS (DImode, tmp13, tmp10))); 2338} 2339 2340 2341/* Implement smuldi3_highpart. */ 2342void 2343tilegx_expand_smuldi3_highpart (rtx op0, rtx op1, rtx op2) 2344{ 2345 tilegx_expand_high_multiply (op0, op1, op2, true); 2346} 2347 2348 2349/* Implement umuldi3_highpart. */ 2350void 2351tilegx_expand_umuldi3_highpart (rtx op0, rtx op1, rtx op2) 2352{ 2353 tilegx_expand_high_multiply (op0, op1, op2, false); 2354} 2355 2356 2357 2358/* Compare and branches */ 2359 2360/* Produce the rtx yielding a bool for a floating point 2361 comparison. */ 2362static bool 2363tilegx_emit_fp_setcc (rtx res, enum rtx_code code, machine_mode mode, 2364 rtx op0, rtx op1) 2365{ 2366 /* TODO: Certain compares again constants can be done using entirely 2367 integer operations. But you have to get the special cases right 2368 e.g. NaN, +0 == -0, etc. */ 2369 2370 rtx flags; 2371 int flag_index; 2372 rtx a = force_reg (DImode, gen_lowpart (DImode, op0)); 2373 rtx b = force_reg (DImode, gen_lowpart (DImode, op1)); 2374 2375 flags = gen_reg_rtx (DImode); 2376 2377 if (mode == SFmode) 2378 { 2379 emit_insn (gen_insn_fsingle_add1 (flags, a, b)); 2380 } 2381 else 2382 { 2383 gcc_assert (mode == DFmode); 2384 emit_insn (gen_insn_fdouble_add_flags (flags, a, b)); 2385 } 2386 2387 switch (code) 2388 { 2389 case EQ: flag_index = 30; break; 2390 case NE: flag_index = 31; break; 2391 case LE: flag_index = 27; break; 2392 case LT: flag_index = 26; break; 2393 case GE: flag_index = 29; break; 2394 case GT: flag_index = 28; break; 2395 default: gcc_unreachable (); 2396 } 2397 2398 gcc_assert (GET_MODE (res) == DImode); 2399 emit_move_insn (res, gen_rtx_ZERO_EXTRACT (DImode, flags, GEN_INT (1), 2400 GEN_INT (flag_index))); 2401 return true; 2402} 2403 2404 2405/* Certain simplifications can be done to make invalid setcc 2406 operations valid. Return the final comparison, or NULL if we can't 2407 work. */ 2408static bool 2409tilegx_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1, 2410 machine_mode cmp_mode) 2411{ 2412 rtx tmp; 2413 bool swap = false; 2414 2415 if (cmp_mode == SFmode || cmp_mode == DFmode) 2416 return tilegx_emit_fp_setcc (res, code, cmp_mode, op0, op1); 2417 2418 /* The general case: fold the comparison code to the types of 2419 compares that we have, choosing the branch as necessary. */ 2420 2421 switch (code) 2422 { 2423 case EQ: 2424 case NE: 2425 case LE: 2426 case LT: 2427 case LEU: 2428 case LTU: 2429 /* We have these compares. */ 2430 break; 2431 2432 case GE: 2433 case GT: 2434 case GEU: 2435 case GTU: 2436 /* We do not have these compares, so we reverse the 2437 operands. */ 2438 swap = true; 2439 break; 2440 2441 default: 2442 /* We should not have called this with any other code. */ 2443 gcc_unreachable (); 2444 } 2445 2446 if (swap) 2447 { 2448 code = swap_condition (code); 2449 tmp = op0, op0 = op1, op1 = tmp; 2450 } 2451 2452 if (!reg_or_0_operand (op0, cmp_mode)) 2453 op0 = force_reg (cmp_mode, op0); 2454 2455 if (!CONST_INT_P (op1) && !register_operand (op1, cmp_mode)) 2456 op1 = force_reg (cmp_mode, op1); 2457 2458 /* Return the setcc comparison. */ 2459 emit_insn (gen_rtx_SET (VOIDmode, res, 2460 gen_rtx_fmt_ee (code, DImode, op0, op1))); 2461 2462 return true; 2463} 2464 2465 2466/* Implement cstore patterns. */ 2467bool 2468tilegx_emit_setcc (rtx operands[], machine_mode cmp_mode) 2469{ 2470 return 2471 tilegx_emit_setcc_internal (operands[0], GET_CODE (operands[1]), 2472 operands[2], operands[3], cmp_mode); 2473} 2474 2475 2476/* Return whether CODE is a signed comparison. */ 2477static bool 2478signed_compare_p (enum rtx_code code) 2479{ 2480 return (code == EQ || code == NE || code == LT || code == LE 2481 || code == GT || code == GE); 2482} 2483 2484 2485/* Generate the comparison for a DImode conditional branch. */ 2486static rtx 2487tilegx_emit_cc_test (enum rtx_code code, rtx op0, rtx op1, 2488 machine_mode cmp_mode, bool eq_ne_only) 2489{ 2490 enum rtx_code branch_code; 2491 rtx temp; 2492 2493 if (cmp_mode == SFmode || cmp_mode == DFmode) 2494 { 2495 /* Compute a boolean saying whether the comparison is true. */ 2496 temp = gen_reg_rtx (DImode); 2497 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode); 2498 2499 /* Test that flag. */ 2500 return gen_rtx_fmt_ee (NE, VOIDmode, temp, const0_rtx); 2501 } 2502 2503 /* Check for a compare against zero using a comparison we can do 2504 directly. */ 2505 if (op1 == const0_rtx 2506 && (code == EQ || code == NE 2507 || (!eq_ne_only && signed_compare_p (code)))) 2508 { 2509 op0 = force_reg (cmp_mode, op0); 2510 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx); 2511 } 2512 2513 /* The general case: fold the comparison code to the types of 2514 compares that we have, choosing the branch as necessary. */ 2515 switch (code) 2516 { 2517 case EQ: 2518 case LE: 2519 case LT: 2520 case LEU: 2521 case LTU: 2522 /* We have these compares. */ 2523 branch_code = NE; 2524 break; 2525 2526 case NE: 2527 case GE: 2528 case GT: 2529 case GEU: 2530 case GTU: 2531 /* These must be reversed (except NE, but let's 2532 canonicalize). */ 2533 code = reverse_condition (code); 2534 branch_code = EQ; 2535 break; 2536 2537 default: 2538 gcc_unreachable (); 2539 } 2540 2541 if (CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU)) 2542 { 2543 HOST_WIDE_INT n = INTVAL (op1); 2544 2545 switch (code) 2546 { 2547 case EQ: 2548 /* Subtract off the value we want to compare against and see 2549 if we get zero. This is cheaper than creating a constant 2550 in a register. Except that subtracting -128 is more 2551 expensive than seqi to -128, so we leave that alone. */ 2552 /* ??? Don't do this when comparing against symbols, 2553 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 == 2554 0), which will be declared false out of hand (at least 2555 for non-weak). */ 2556 if (n != -128 2557 && add_operand (GEN_INT (-n), DImode) 2558 && !(symbolic_operand (op0, VOIDmode) 2559 || (REG_P (op0) && REG_POINTER (op0)))) 2560 { 2561 /* TODO: Use a SIMD add immediate to hit zero for tiled 2562 constants in a single instruction. */ 2563 if (GET_MODE (op0) != DImode) 2564 { 2565 /* Convert to DImode so we can use addli. Note that 2566 this will not actually generate any code because 2567 sign extension from SI -> DI is a no-op. I don't 2568 know if it's safe just to make a paradoxical 2569 subreg here though. */ 2570 rtx temp2 = gen_reg_rtx (DImode); 2571 emit_insn (gen_extendsidi2 (temp2, op0)); 2572 op0 = temp2; 2573 } 2574 else 2575 { 2576 op0 = force_reg (DImode, op0); 2577 } 2578 temp = gen_reg_rtx (DImode); 2579 emit_move_insn (temp, gen_rtx_PLUS (DImode, op0, GEN_INT (-n))); 2580 return gen_rtx_fmt_ee (reverse_condition (branch_code), 2581 VOIDmode, temp, const0_rtx); 2582 } 2583 break; 2584 2585 case LEU: 2586 if (n == -1) 2587 break; 2588 /* FALLTHRU */ 2589 2590 case LTU: 2591 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc. 2592 We use arithmetic shift right because it's a 3-wide op, 2593 while logical shift right is not. */ 2594 { 2595 int first = exact_log2 (code == LTU ? n : n + 1); 2596 if (first != -1) 2597 { 2598 op0 = force_reg (cmp_mode, op0); 2599 temp = gen_reg_rtx (cmp_mode); 2600 emit_move_insn (temp, 2601 gen_rtx_ASHIFTRT (cmp_mode, op0, 2602 GEN_INT (first))); 2603 return gen_rtx_fmt_ee (reverse_condition (branch_code), 2604 VOIDmode, temp, const0_rtx); 2605 } 2606 } 2607 break; 2608 2609 default: 2610 break; 2611 } 2612 } 2613 2614 /* Compute a flag saying whether we should branch. */ 2615 temp = gen_reg_rtx (DImode); 2616 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode); 2617 2618 /* Return the branch comparison. */ 2619 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx); 2620} 2621 2622 2623/* Generate the comparison for a conditional branch. */ 2624void 2625tilegx_emit_conditional_branch (rtx operands[], machine_mode cmp_mode) 2626{ 2627 rtx cmp_rtx = 2628 tilegx_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2], 2629 cmp_mode, false); 2630 rtx branch_rtx = gen_rtx_SET (VOIDmode, pc_rtx, 2631 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx, 2632 gen_rtx_LABEL_REF 2633 (VOIDmode, 2634 operands[3]), 2635 pc_rtx)); 2636 emit_jump_insn (branch_rtx); 2637} 2638 2639 2640/* Implement the mov<mode>cc pattern. */ 2641rtx 2642tilegx_emit_conditional_move (rtx cmp) 2643{ 2644 return 2645 tilegx_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1), 2646 GET_MODE (XEXP (cmp, 0)), true); 2647} 2648 2649 2650/* Return true if INSN is annotated with a REG_BR_PROB note that 2651 indicates it's a branch that's predicted taken. */ 2652static bool 2653cbranch_predicted_p (rtx_insn *insn) 2654{ 2655 rtx x = find_reg_note (insn, REG_BR_PROB, 0); 2656 2657 if (x) 2658 { 2659 int pred_val = XINT (x, 0); 2660 2661 return pred_val >= REG_BR_PROB_BASE / 2; 2662 } 2663 2664 return false; 2665} 2666 2667 2668/* Output assembly code for a specific branch instruction, appending 2669 the branch prediction flag to the opcode if appropriate. */ 2670static const char * 2671tilegx_output_simple_cbranch_with_opcode (rtx_insn *insn, const char *opcode, 2672 int regop, bool reverse_predicted) 2673{ 2674 static char buf[64]; 2675 sprintf (buf, "%s%s\t%%r%d, %%l0", opcode, 2676 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "", 2677 regop); 2678 return buf; 2679} 2680 2681 2682/* Output assembly code for a specific branch instruction, appending 2683 the branch prediction flag to the opcode if appropriate. */ 2684const char * 2685tilegx_output_cbranch_with_opcode (rtx_insn *insn, rtx *operands, 2686 const char *opcode, 2687 const char *rev_opcode, int regop) 2688{ 2689 const char *branch_if_false; 2690 rtx taken, not_taken; 2691 bool is_simple_branch; 2692 2693 gcc_assert (LABEL_P (operands[0])); 2694 2695 is_simple_branch = true; 2696 if (INSN_ADDRESSES_SET_P ()) 2697 { 2698 int from_addr = INSN_ADDRESSES (INSN_UID (insn)); 2699 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0])); 2700 int delta = to_addr - from_addr; 2701 is_simple_branch = IN_RANGE (delta, -524288, 524280); 2702 } 2703 2704 if (is_simple_branch) 2705 { 2706 /* Just a simple conditional branch. */ 2707 return 2708 tilegx_output_simple_cbranch_with_opcode (insn, opcode, regop, false); 2709 } 2710 2711 /* Generate a reversed branch around a direct jump. This fallback 2712 does not use branch-likely instructions. */ 2713 not_taken = gen_label_rtx (); 2714 taken = operands[0]; 2715 2716 /* Generate the reversed branch to NOT_TAKEN. */ 2717 operands[0] = not_taken; 2718 branch_if_false = 2719 tilegx_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, true); 2720 output_asm_insn (branch_if_false, operands); 2721 2722 output_asm_insn ("j\t%l0", &taken); 2723 2724 /* Output NOT_TAKEN. */ 2725 targetm.asm_out.internal_label (asm_out_file, "L", 2726 CODE_LABEL_NUMBER (not_taken)); 2727 return ""; 2728} 2729 2730 2731/* Output assembly code for a conditional branch instruction. */ 2732const char * 2733tilegx_output_cbranch (rtx_insn *insn, rtx *operands, bool reversed) 2734{ 2735 enum rtx_code code = GET_CODE (operands[1]); 2736 const char *opcode; 2737 const char *rev_opcode; 2738 2739 if (reversed) 2740 code = reverse_condition (code); 2741 2742 switch (code) 2743 { 2744 case NE: 2745 opcode = "bnez"; 2746 rev_opcode = "beqz"; 2747 break; 2748 case EQ: 2749 opcode = "beqz"; 2750 rev_opcode = "bnez"; 2751 break; 2752 case GE: 2753 opcode = "bgez"; 2754 rev_opcode = "bltz"; 2755 break; 2756 case GT: 2757 opcode = "bgtz"; 2758 rev_opcode = "blez"; 2759 break; 2760 case LE: 2761 opcode = "blez"; 2762 rev_opcode = "bgtz"; 2763 break; 2764 case LT: 2765 opcode = "bltz"; 2766 rev_opcode = "bgez"; 2767 break; 2768 default: 2769 gcc_unreachable (); 2770 } 2771 2772 return tilegx_output_cbranch_with_opcode (insn, operands, opcode, 2773 rev_opcode, 2); 2774} 2775 2776 2777/* Implement the tablejump pattern. */ 2778void 2779tilegx_expand_tablejump (rtx op0, rtx op1) 2780{ 2781 if (flag_pic) 2782 { 2783 rtx temp = gen_reg_rtx (Pmode); 2784 rtx temp2 = gen_reg_rtx (Pmode); 2785 2786 tilegx_compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1)); 2787 emit_move_insn (temp2, 2788 gen_rtx_PLUS (Pmode, 2789 convert_to_mode (Pmode, op0, false), 2790 temp)); 2791 op0 = temp2; 2792 } 2793 2794 emit_jump_insn (gen_tablejump_aux (op0, op1)); 2795} 2796 2797 2798/* Emit barrier before an atomic, as needed for the memory MODEL. */ 2799void 2800tilegx_pre_atomic_barrier (enum memmodel model) 2801{ 2802 if (need_atomic_barrier_p (model, true)) 2803 emit_insn (gen_memory_barrier ()); 2804} 2805 2806 2807/* Emit barrier after an atomic, as needed for the memory MODEL. */ 2808void 2809tilegx_post_atomic_barrier (enum memmodel model) 2810{ 2811 if (need_atomic_barrier_p (model, false)) 2812 emit_insn (gen_memory_barrier ()); 2813} 2814 2815 2816 2817/* Expand a builtin vector binary op, by calling gen function GEN with 2818 operands in the proper modes. DEST is converted to DEST_MODE, and 2819 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */ 2820void 2821tilegx_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), 2822 machine_mode dest_mode, 2823 rtx dest, 2824 machine_mode src_mode, 2825 rtx src0, rtx src1, bool do_src1) 2826{ 2827 dest = gen_lowpart (dest_mode, dest); 2828 2829 if (src0 == const0_rtx) 2830 src0 = CONST0_RTX (src_mode); 2831 else 2832 src0 = gen_lowpart (src_mode, src0); 2833 2834 if (do_src1) 2835 { 2836 if (src1 == const0_rtx) 2837 src1 = CONST0_RTX (src_mode); 2838 else 2839 src1 = gen_lowpart (src_mode, src1); 2840 } 2841 2842 emit_insn ((*gen) (dest, src0, src1)); 2843} 2844 2845 2846 2847/* Intrinsics */ 2848 2849 2850struct tile_builtin_info 2851{ 2852 enum insn_code icode; 2853 tree fndecl; 2854}; 2855 2856static struct tile_builtin_info tilegx_builtin_info[TILEGX_BUILTIN_max] = { 2857 { CODE_FOR_adddi3, NULL }, /* add */ 2858 { CODE_FOR_addsi3, NULL }, /* addx */ 2859 { CODE_FOR_ssaddsi3, NULL }, /* addxsc */ 2860 { CODE_FOR_anddi3, NULL }, /* and */ 2861 { CODE_FOR_insn_bfexts, NULL }, /* bfexts */ 2862 { CODE_FOR_insn_bfextu, NULL }, /* bfextu */ 2863 { CODE_FOR_insn_bfins, NULL }, /* bfins */ 2864 { CODE_FOR_clzdi2, NULL }, /* clz */ 2865 { CODE_FOR_insn_cmoveqz, NULL }, /* cmoveqz */ 2866 { CODE_FOR_insn_cmovnez, NULL }, /* cmovnez */ 2867 { CODE_FOR_insn_cmpeq_didi, NULL }, /* cmpeq */ 2868 { CODE_FOR_insn_cmpexch, NULL }, /* cmpexch */ 2869 { CODE_FOR_insn_cmpexch4, NULL }, /* cmpexch4 */ 2870 { CODE_FOR_insn_cmples_didi, NULL }, /* cmples */ 2871 { CODE_FOR_insn_cmpleu_didi, NULL }, /* cmpleu */ 2872 { CODE_FOR_insn_cmplts_didi, NULL }, /* cmplts */ 2873 { CODE_FOR_insn_cmpltu_didi, NULL }, /* cmpltu */ 2874 { CODE_FOR_insn_cmpne_didi, NULL }, /* cmpne */ 2875 { CODE_FOR_insn_cmul, NULL }, /* cmul */ 2876 { CODE_FOR_insn_cmula, NULL }, /* cmula */ 2877 { CODE_FOR_insn_cmulaf, NULL }, /* cmulaf */ 2878 { CODE_FOR_insn_cmulf, NULL }, /* cmulf */ 2879 { CODE_FOR_insn_cmulfr, NULL }, /* cmulfr */ 2880 { CODE_FOR_insn_cmulh, NULL }, /* cmulh */ 2881 { CODE_FOR_insn_cmulhr, NULL }, /* cmulhr */ 2882 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */ 2883 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */ 2884 { CODE_FOR_ctzdi2, NULL }, /* ctz */ 2885 { CODE_FOR_insn_dblalign, NULL }, /* dblalign */ 2886 { CODE_FOR_insn_dblalign2, NULL }, /* dblalign2 */ 2887 { CODE_FOR_insn_dblalign4, NULL }, /* dblalign4 */ 2888 { CODE_FOR_insn_dblalign6, NULL }, /* dblalign6 */ 2889 { CODE_FOR_insn_drain, NULL }, /* drain */ 2890 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */ 2891 { CODE_FOR_insn_exch, NULL }, /* exch */ 2892 { CODE_FOR_insn_exch4, NULL }, /* exch4 */ 2893 { CODE_FOR_insn_fdouble_add_flags, NULL }, /* fdouble_add_flags */ 2894 { CODE_FOR_insn_fdouble_addsub, NULL }, /* fdouble_addsub */ 2895 { CODE_FOR_insn_fdouble_mul_flags, NULL }, /* fdouble_mul_flags */ 2896 { CODE_FOR_insn_fdouble_pack1, NULL }, /* fdouble_pack1 */ 2897 { CODE_FOR_insn_fdouble_pack2, NULL }, /* fdouble_pack2 */ 2898 { CODE_FOR_insn_fdouble_sub_flags, NULL }, /* fdouble_sub_flags */ 2899 { CODE_FOR_insn_fdouble_unpack_max, NULL }, /* fdouble_unpack_max */ 2900 { CODE_FOR_insn_fdouble_unpack_min, NULL }, /* fdouble_unpack_min */ 2901 { CODE_FOR_insn_fetchadd, NULL }, /* fetchadd */ 2902 { CODE_FOR_insn_fetchadd4, NULL }, /* fetchadd4 */ 2903 { CODE_FOR_insn_fetchaddgez, NULL }, /* fetchaddgez */ 2904 { CODE_FOR_insn_fetchaddgez4, NULL }, /* fetchaddgez4 */ 2905 { CODE_FOR_insn_fetchand, NULL }, /* fetchand */ 2906 { CODE_FOR_insn_fetchand4, NULL }, /* fetchand4 */ 2907 { CODE_FOR_insn_fetchor, NULL }, /* fetchor */ 2908 { CODE_FOR_insn_fetchor4, NULL }, /* fetchor4 */ 2909 { CODE_FOR_insn_finv, NULL }, /* finv */ 2910 { CODE_FOR_insn_flush, NULL }, /* flush */ 2911 { CODE_FOR_insn_flushwb, NULL }, /* flushwb */ 2912 { CODE_FOR_insn_fnop, NULL }, /* fnop */ 2913 { CODE_FOR_insn_fsingle_add1, NULL }, /* fsingle_add1 */ 2914 { CODE_FOR_insn_fsingle_addsub2, NULL }, /* fsingle_addsub2 */ 2915 { CODE_FOR_insn_fsingle_mul1, NULL }, /* fsingle_mul1 */ 2916 { CODE_FOR_insn_fsingle_mul2, NULL }, /* fsingle_mul2 */ 2917 { CODE_FOR_insn_fsingle_pack1, NULL }, /* fsingle_pack1 */ 2918 { CODE_FOR_insn_fsingle_pack2, NULL }, /* fsingle_pack2 */ 2919 { CODE_FOR_insn_fsingle_sub1, NULL }, /* fsingle_sub1 */ 2920 { CODE_FOR_insn_icoh, NULL }, /* icoh */ 2921 { CODE_FOR_insn_ill, NULL }, /* ill */ 2922 { CODE_FOR_insn_info, NULL }, /* info */ 2923 { CODE_FOR_insn_infol, NULL }, /* infol */ 2924 { CODE_FOR_insn_inv, NULL }, /* inv */ 2925 { CODE_FOR_insn_ld, NULL }, /* ld */ 2926 { CODE_FOR_insn_ld1s, NULL }, /* ld1s */ 2927 { CODE_FOR_insn_ld1u, NULL }, /* ld1u */ 2928 { CODE_FOR_insn_ld2s, NULL }, /* ld2s */ 2929 { CODE_FOR_insn_ld2u, NULL }, /* ld2u */ 2930 { CODE_FOR_insn_ld4s, NULL }, /* ld4s */ 2931 { CODE_FOR_insn_ld4u, NULL }, /* ld4u */ 2932 { CODE_FOR_insn_ldna, NULL }, /* ldna */ 2933 { CODE_FOR_insn_ldnt, NULL }, /* ldnt */ 2934 { CODE_FOR_insn_ldnt1s, NULL }, /* ldnt1s */ 2935 { CODE_FOR_insn_ldnt1u, NULL }, /* ldnt1u */ 2936 { CODE_FOR_insn_ldnt2s, NULL }, /* ldnt2s */ 2937 { CODE_FOR_insn_ldnt2u, NULL }, /* ldnt2u */ 2938 { CODE_FOR_insn_ldnt4s, NULL }, /* ldnt4s */ 2939 { CODE_FOR_insn_ldnt4u, NULL }, /* ldnt4u */ 2940 { CODE_FOR_insn_ld_L2, NULL }, /* ld_L2 */ 2941 { CODE_FOR_insn_ld1s_L2, NULL }, /* ld1s_L2 */ 2942 { CODE_FOR_insn_ld1u_L2, NULL }, /* ld1u_L2 */ 2943 { CODE_FOR_insn_ld2s_L2, NULL }, /* ld2s_L2 */ 2944 { CODE_FOR_insn_ld2u_L2, NULL }, /* ld2u_L2 */ 2945 { CODE_FOR_insn_ld4s_L2, NULL }, /* ld4s_L2 */ 2946 { CODE_FOR_insn_ld4u_L2, NULL }, /* ld4u_L2 */ 2947 { CODE_FOR_insn_ldna_L2, NULL }, /* ldna_L2 */ 2948 { CODE_FOR_insn_ldnt_L2, NULL }, /* ldnt_L2 */ 2949 { CODE_FOR_insn_ldnt1s_L2, NULL }, /* ldnt1s_L2 */ 2950 { CODE_FOR_insn_ldnt1u_L2, NULL }, /* ldnt1u_L2 */ 2951 { CODE_FOR_insn_ldnt2s_L2, NULL }, /* ldnt2s_L2 */ 2952 { CODE_FOR_insn_ldnt2u_L2, NULL }, /* ldnt2u_L2 */ 2953 { CODE_FOR_insn_ldnt4s_L2, NULL }, /* ldnt4s_L2 */ 2954 { CODE_FOR_insn_ldnt4u_L2, NULL }, /* ldnt4u_L2 */ 2955 { CODE_FOR_insn_ld_miss, NULL }, /* ld_miss */ 2956 { CODE_FOR_insn_ld1s_miss, NULL }, /* ld1s_miss */ 2957 { CODE_FOR_insn_ld1u_miss, NULL }, /* ld1u_miss */ 2958 { CODE_FOR_insn_ld2s_miss, NULL }, /* ld2s_miss */ 2959 { CODE_FOR_insn_ld2u_miss, NULL }, /* ld2u_miss */ 2960 { CODE_FOR_insn_ld4s_miss, NULL }, /* ld4s_miss */ 2961 { CODE_FOR_insn_ld4u_miss, NULL }, /* ld4u_miss */ 2962 { CODE_FOR_insn_ldna_miss, NULL }, /* ldna_miss */ 2963 { CODE_FOR_insn_ldnt_miss, NULL }, /* ldnt_miss */ 2964 { CODE_FOR_insn_ldnt1s_miss, NULL }, /* ldnt1s_miss */ 2965 { CODE_FOR_insn_ldnt1u_miss, NULL }, /* ldnt1u_miss */ 2966 { CODE_FOR_insn_ldnt2s_miss, NULL }, /* ldnt2s_miss */ 2967 { CODE_FOR_insn_ldnt2u_miss, NULL }, /* ldnt2u_miss */ 2968 { CODE_FOR_insn_ldnt4s_miss, NULL }, /* ldnt4s_miss */ 2969 { CODE_FOR_insn_ldnt4u_miss, NULL }, /* ldnt4u_miss */ 2970 { CODE_FOR_insn_lnk, NULL }, /* lnk */ 2971 { CODE_FOR_memory_barrier, NULL }, /* mf */ 2972 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */ 2973 { CODE_FOR_insn_mm, NULL }, /* mm */ 2974 { CODE_FOR_insn_mnz, NULL }, /* mnz */ 2975 { CODE_FOR_movdi, NULL }, /* move */ 2976 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */ 2977 { CODE_FOR_insn_mul_hs_hs, NULL }, /* mul_hs_hs */ 2978 { CODE_FOR_insn_mul_hs_hu, NULL }, /* mul_hs_hu */ 2979 { CODE_FOR_insn_mul_hs_ls, NULL }, /* mul_hs_ls */ 2980 { CODE_FOR_insn_mul_hs_lu, NULL }, /* mul_hs_lu */ 2981 { CODE_FOR_insn_mul_hu_hu, NULL }, /* mul_hu_hu */ 2982 { CODE_FOR_insn_mul_hu_ls, NULL }, /* mul_hu_ls */ 2983 { CODE_FOR_insn_mul_hu_lu, NULL }, /* mul_hu_lu */ 2984 { CODE_FOR_insn_mul_ls_ls, NULL }, /* mul_ls_ls */ 2985 { CODE_FOR_insn_mul_ls_lu, NULL }, /* mul_ls_lu */ 2986 { CODE_FOR_insn_mul_lu_lu, NULL }, /* mul_lu_lu */ 2987 { CODE_FOR_insn_mula_hs_hs, NULL }, /* mula_hs_hs */ 2988 { CODE_FOR_insn_mula_hs_hu, NULL }, /* mula_hs_hu */ 2989 { CODE_FOR_insn_mula_hs_ls, NULL }, /* mula_hs_ls */ 2990 { CODE_FOR_insn_mula_hs_lu, NULL }, /* mula_hs_lu */ 2991 { CODE_FOR_insn_mula_hu_hu, NULL }, /* mula_hu_hu */ 2992 { CODE_FOR_insn_mula_hu_ls, NULL }, /* mula_hu_ls */ 2993 { CODE_FOR_insn_mula_hu_lu, NULL }, /* mula_hu_lu */ 2994 { CODE_FOR_insn_mula_ls_ls, NULL }, /* mula_ls_ls */ 2995 { CODE_FOR_insn_mula_ls_lu, NULL }, /* mula_ls_lu */ 2996 { CODE_FOR_insn_mula_lu_lu, NULL }, /* mula_lu_lu */ 2997 { CODE_FOR_insn_mulax, NULL }, /* mulax */ 2998 { CODE_FOR_mulsi3, NULL }, /* mulx */ 2999 { CODE_FOR_insn_mz, NULL }, /* mz */ 3000 { CODE_FOR_insn_nap, NULL }, /* nap */ 3001 { CODE_FOR_nop, NULL }, /* nop */ 3002 { CODE_FOR_insn_nor_di, NULL }, /* nor */ 3003 { CODE_FOR_iordi3, NULL }, /* or */ 3004 { CODE_FOR_popcountdi2, NULL }, /* pcnt */ 3005 { CODE_FOR_insn_prefetch_l1, NULL }, /* prefetch_l1 */ 3006 { CODE_FOR_insn_prefetch_l1_fault, NULL }, /* prefetch_l1_fault */ 3007 { CODE_FOR_insn_prefetch_l2, NULL }, /* prefetch_l2 */ 3008 { CODE_FOR_insn_prefetch_l2_fault, NULL }, /* prefetch_l2_fault */ 3009 { CODE_FOR_insn_prefetch_l3, NULL }, /* prefetch_l3 */ 3010 { CODE_FOR_insn_prefetch_l3_fault, NULL }, /* prefetch_l3_fault */ 3011 { CODE_FOR_insn_revbits, NULL }, /* revbits */ 3012 { CODE_FOR_bswapdi2, NULL }, /* revbytes */ 3013 { CODE_FOR_rotldi3, NULL }, /* rotl */ 3014 { CODE_FOR_ashldi3, NULL }, /* shl */ 3015 { CODE_FOR_insn_shl16insli, NULL }, /* shl16insli */ 3016 { CODE_FOR_insn_shl1add, NULL }, /* shl1add */ 3017 { CODE_FOR_insn_shl1addx, NULL }, /* shl1addx */ 3018 { CODE_FOR_insn_shl2add, NULL }, /* shl2add */ 3019 { CODE_FOR_insn_shl2addx, NULL }, /* shl2addx */ 3020 { CODE_FOR_insn_shl3add, NULL }, /* shl3add */ 3021 { CODE_FOR_insn_shl3addx, NULL }, /* shl3addx */ 3022 { CODE_FOR_ashlsi3, NULL }, /* shlx */ 3023 { CODE_FOR_ashrdi3, NULL }, /* shrs */ 3024 { CODE_FOR_lshrdi3, NULL }, /* shru */ 3025 { CODE_FOR_lshrsi3, NULL }, /* shrux */ 3026 { CODE_FOR_insn_shufflebytes, NULL }, /* shufflebytes */ 3027 { CODE_FOR_insn_shufflebytes1, NULL }, /* shufflebytes1 */ 3028 { CODE_FOR_insn_st, NULL }, /* st */ 3029 { CODE_FOR_insn_st1, NULL }, /* st1 */ 3030 { CODE_FOR_insn_st2, NULL }, /* st2 */ 3031 { CODE_FOR_insn_st4, NULL }, /* st4 */ 3032 { CODE_FOR_insn_stnt, NULL }, /* stnt */ 3033 { CODE_FOR_insn_stnt1, NULL }, /* stnt1 */ 3034 { CODE_FOR_insn_stnt2, NULL }, /* stnt2 */ 3035 { CODE_FOR_insn_stnt4, NULL }, /* stnt4 */ 3036 { CODE_FOR_subdi3, NULL }, /* sub */ 3037 { CODE_FOR_subsi3, NULL }, /* subx */ 3038 { CODE_FOR_sssubsi3, NULL }, /* subxsc */ 3039 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */ 3040 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */ 3041 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */ 3042 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */ 3043 { CODE_FOR_insn_v1add, NULL }, /* v1add */ 3044 { CODE_FOR_insn_v1addi, NULL }, /* v1addi */ 3045 { CODE_FOR_insn_v1adduc, NULL }, /* v1adduc */ 3046 { CODE_FOR_insn_v1adiffu, NULL }, /* v1adiffu */ 3047 { CODE_FOR_insn_v1avgu, NULL }, /* v1avgu */ 3048 { CODE_FOR_insn_v1cmpeq, NULL }, /* v1cmpeq */ 3049 { CODE_FOR_insn_v1cmpeqi, NULL }, /* v1cmpeqi */ 3050 { CODE_FOR_insn_v1cmples, NULL }, /* v1cmples */ 3051 { CODE_FOR_insn_v1cmpleu, NULL }, /* v1cmpleu */ 3052 { CODE_FOR_insn_v1cmplts, NULL }, /* v1cmplts */ 3053 { CODE_FOR_insn_v1cmpltsi, NULL }, /* v1cmpltsi */ 3054 { CODE_FOR_insn_v1cmpltu, NULL }, /* v1cmpltu */ 3055 { CODE_FOR_insn_v1cmpltui, NULL }, /* v1cmpltui */ 3056 { CODE_FOR_insn_v1cmpne, NULL }, /* v1cmpne */ 3057 { CODE_FOR_insn_v1ddotpu, NULL }, /* v1ddotpu */ 3058 { CODE_FOR_insn_v1ddotpua, NULL }, /* v1ddotpua */ 3059 { CODE_FOR_insn_v1ddotpus, NULL }, /* v1ddotpus */ 3060 { CODE_FOR_insn_v1ddotpusa, NULL }, /* v1ddotpusa */ 3061 { CODE_FOR_insn_v1dotp, NULL }, /* v1dotp */ 3062 { CODE_FOR_insn_v1dotpa, NULL }, /* v1dotpa */ 3063 { CODE_FOR_insn_v1dotpu, NULL }, /* v1dotpu */ 3064 { CODE_FOR_insn_v1dotpua, NULL }, /* v1dotpua */ 3065 { CODE_FOR_insn_v1dotpus, NULL }, /* v1dotpus */ 3066 { CODE_FOR_insn_v1dotpusa, NULL }, /* v1dotpusa */ 3067 { CODE_FOR_insn_v1int_h, NULL }, /* v1int_h */ 3068 { CODE_FOR_insn_v1int_l, NULL }, /* v1int_l */ 3069 { CODE_FOR_insn_v1maxu, NULL }, /* v1maxu */ 3070 { CODE_FOR_insn_v1maxui, NULL }, /* v1maxui */ 3071 { CODE_FOR_insn_v1minu, NULL }, /* v1minu */ 3072 { CODE_FOR_insn_v1minui, NULL }, /* v1minui */ 3073 { CODE_FOR_insn_v1mnz, NULL }, /* v1mnz */ 3074 { CODE_FOR_insn_v1multu, NULL }, /* v1multu */ 3075 { CODE_FOR_insn_v1mulu, NULL }, /* v1mulu */ 3076 { CODE_FOR_insn_v1mulus, NULL }, /* v1mulus */ 3077 { CODE_FOR_insn_v1mz, NULL }, /* v1mz */ 3078 { CODE_FOR_insn_v1sadau, NULL }, /* v1sadau */ 3079 { CODE_FOR_insn_v1sadu, NULL }, /* v1sadu */ 3080 { CODE_FOR_insn_v1shl, NULL }, /* v1shl */ 3081 { CODE_FOR_insn_v1shl, NULL }, /* v1shli */ 3082 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrs */ 3083 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrsi */ 3084 { CODE_FOR_insn_v1shru, NULL }, /* v1shru */ 3085 { CODE_FOR_insn_v1shru, NULL }, /* v1shrui */ 3086 { CODE_FOR_insn_v1sub, NULL }, /* v1sub */ 3087 { CODE_FOR_insn_v1subuc, NULL }, /* v1subuc */ 3088 { CODE_FOR_insn_v2add, NULL }, /* v2add */ 3089 { CODE_FOR_insn_v2addi, NULL }, /* v2addi */ 3090 { CODE_FOR_insn_v2addsc, NULL }, /* v2addsc */ 3091 { CODE_FOR_insn_v2adiffs, NULL }, /* v2adiffs */ 3092 { CODE_FOR_insn_v2avgs, NULL }, /* v2avgs */ 3093 { CODE_FOR_insn_v2cmpeq, NULL }, /* v2cmpeq */ 3094 { CODE_FOR_insn_v2cmpeqi, NULL }, /* v2cmpeqi */ 3095 { CODE_FOR_insn_v2cmples, NULL }, /* v2cmples */ 3096 { CODE_FOR_insn_v2cmpleu, NULL }, /* v2cmpleu */ 3097 { CODE_FOR_insn_v2cmplts, NULL }, /* v2cmplts */ 3098 { CODE_FOR_insn_v2cmpltsi, NULL }, /* v2cmpltsi */ 3099 { CODE_FOR_insn_v2cmpltu, NULL }, /* v2cmpltu */ 3100 { CODE_FOR_insn_v2cmpltui, NULL }, /* v2cmpltui */ 3101 { CODE_FOR_insn_v2cmpne, NULL }, /* v2cmpne */ 3102 { CODE_FOR_insn_v2dotp, NULL }, /* v2dotp */ 3103 { CODE_FOR_insn_v2dotpa, NULL }, /* v2dotpa */ 3104 { CODE_FOR_insn_v2int_h, NULL }, /* v2int_h */ 3105 { CODE_FOR_insn_v2int_l, NULL }, /* v2int_l */ 3106 { CODE_FOR_insn_v2maxs, NULL }, /* v2maxs */ 3107 { CODE_FOR_insn_v2maxsi, NULL }, /* v2maxsi */ 3108 { CODE_FOR_insn_v2mins, NULL }, /* v2mins */ 3109 { CODE_FOR_insn_v2minsi, NULL }, /* v2minsi */ 3110 { CODE_FOR_insn_v2mnz, NULL }, /* v2mnz */ 3111 { CODE_FOR_insn_v2mulfsc, NULL }, /* v2mulfsc */ 3112 { CODE_FOR_insn_v2muls, NULL }, /* v2muls */ 3113 { CODE_FOR_insn_v2mults, NULL }, /* v2mults */ 3114 { CODE_FOR_insn_v2mz, NULL }, /* v2mz */ 3115 { CODE_FOR_insn_v2packh, NULL }, /* v2packh */ 3116 { CODE_FOR_insn_v2packl, NULL }, /* v2packl */ 3117 { CODE_FOR_insn_v2packuc, NULL }, /* v2packuc */ 3118 { CODE_FOR_insn_v2sadas, NULL }, /* v2sadas */ 3119 { CODE_FOR_insn_v2sadau, NULL }, /* v2sadau */ 3120 { CODE_FOR_insn_v2sads, NULL }, /* v2sads */ 3121 { CODE_FOR_insn_v2sadu, NULL }, /* v2sadu */ 3122 { CODE_FOR_insn_v2shl, NULL }, /* v2shl */ 3123 { CODE_FOR_insn_v2shl, NULL }, /* v2shli */ 3124 { CODE_FOR_insn_v2shlsc, NULL }, /* v2shlsc */ 3125 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrs */ 3126 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrsi */ 3127 { CODE_FOR_insn_v2shru, NULL }, /* v2shru */ 3128 { CODE_FOR_insn_v2shru, NULL }, /* v2shrui */ 3129 { CODE_FOR_insn_v2sub, NULL }, /* v2sub */ 3130 { CODE_FOR_insn_v2subsc, NULL }, /* v2subsc */ 3131 { CODE_FOR_insn_v4add, NULL }, /* v4add */ 3132 { CODE_FOR_insn_v4addsc, NULL }, /* v4addsc */ 3133 { CODE_FOR_insn_v4int_h, NULL }, /* v4int_h */ 3134 { CODE_FOR_insn_v4int_l, NULL }, /* v4int_l */ 3135 { CODE_FOR_insn_v4packsc, NULL }, /* v4packsc */ 3136 { CODE_FOR_insn_v4shl, NULL }, /* v4shl */ 3137 { CODE_FOR_insn_v4shlsc, NULL }, /* v4shlsc */ 3138 { CODE_FOR_insn_v4shrs, NULL }, /* v4shrs */ 3139 { CODE_FOR_insn_v4shru, NULL }, /* v4shru */ 3140 { CODE_FOR_insn_v4sub, NULL }, /* v4sub */ 3141 { CODE_FOR_insn_v4subsc, NULL }, /* v4subsc */ 3142 { CODE_FOR_insn_wh64, NULL }, /* wh64 */ 3143 { CODE_FOR_xordi3, NULL }, /* xor */ 3144 { CODE_FOR_tilegx_network_barrier, NULL }, /* network_barrier */ 3145 { CODE_FOR_tilegx_idn0_receive, NULL }, /* idn0_receive */ 3146 { CODE_FOR_tilegx_idn1_receive, NULL }, /* idn1_receive */ 3147 { CODE_FOR_tilegx_idn_send, NULL }, /* idn_send */ 3148 { CODE_FOR_tilegx_udn0_receive, NULL }, /* udn0_receive */ 3149 { CODE_FOR_tilegx_udn1_receive, NULL }, /* udn1_receive */ 3150 { CODE_FOR_tilegx_udn2_receive, NULL }, /* udn2_receive */ 3151 { CODE_FOR_tilegx_udn3_receive, NULL }, /* udn3_receive */ 3152 { CODE_FOR_tilegx_udn_send, NULL }, /* udn_send */ 3153}; 3154 3155 3156struct tilegx_builtin_def 3157{ 3158 const char *name; 3159 enum tilegx_builtin code; 3160 bool is_const; 3161 /* The first character is the return type. Subsequent characters 3162 are the argument types. See char_to_type. */ 3163 const char *type; 3164}; 3165 3166 3167static const struct tilegx_builtin_def tilegx_builtins[] = { 3168 { "__insn_add", TILEGX_INSN_ADD, true, "lll" }, 3169 { "__insn_addi", TILEGX_INSN_ADD, true, "lll" }, 3170 { "__insn_addli", TILEGX_INSN_ADD, true, "lll" }, 3171 { "__insn_addx", TILEGX_INSN_ADDX, true, "iii" }, 3172 { "__insn_addxi", TILEGX_INSN_ADDX, true, "iii" }, 3173 { "__insn_addxli", TILEGX_INSN_ADDX, true, "iii" }, 3174 { "__insn_addxsc", TILEGX_INSN_ADDXSC, true, "iii" }, 3175 { "__insn_and", TILEGX_INSN_AND, true, "lll" }, 3176 { "__insn_andi", TILEGX_INSN_AND, true, "lll" }, 3177 { "__insn_bfexts", TILEGX_INSN_BFEXTS, true, "llll" }, 3178 { "__insn_bfextu", TILEGX_INSN_BFEXTU, true, "llll" }, 3179 { "__insn_bfins", TILEGX_INSN_BFINS, true, "lllll"}, 3180 { "__insn_clz", TILEGX_INSN_CLZ, true, "ll" }, 3181 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ, true, "llll" }, 3182 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ, true, "llll" }, 3183 { "__insn_cmpeq", TILEGX_INSN_CMPEQ, true, "lll" }, 3184 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ, true, "lll" }, 3185 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH, false, "lpl" }, 3186 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4, false, "ipi" }, 3187 { "__insn_cmples", TILEGX_INSN_CMPLES, true, "lll" }, 3188 { "__insn_cmpleu", TILEGX_INSN_CMPLEU, true, "lll" }, 3189 { "__insn_cmplts", TILEGX_INSN_CMPLTS, true, "lll" }, 3190 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS, true, "lll" }, 3191 { "__insn_cmpltu", TILEGX_INSN_CMPLTU, true, "lll" }, 3192 { "__insn_cmpltui", TILEGX_INSN_CMPLTU, true, "lll" }, 3193 { "__insn_cmpne", TILEGX_INSN_CMPNE, true, "lll" }, 3194 { "__insn_cmul", TILEGX_INSN_CMUL, true, "lll" }, 3195 { "__insn_cmula", TILEGX_INSN_CMULA, true, "llll" }, 3196 { "__insn_cmulaf", TILEGX_INSN_CMULAF, true, "llll" }, 3197 { "__insn_cmulf", TILEGX_INSN_CMULF, true, "lll" }, 3198 { "__insn_cmulfr", TILEGX_INSN_CMULFR, true, "lll" }, 3199 { "__insn_cmulh", TILEGX_INSN_CMULH, true, "lll" }, 3200 { "__insn_cmulhr", TILEGX_INSN_CMULHR, true, "lll" }, 3201 { "__insn_crc32_32", TILEGX_INSN_CRC32_32, true, "lll" }, 3202 { "__insn_crc32_8", TILEGX_INSN_CRC32_8, true, "lll" }, 3203 { "__insn_ctz", TILEGX_INSN_CTZ, true, "ll" }, 3204 { "__insn_dblalign", TILEGX_INSN_DBLALIGN, true, "lllk" }, 3205 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2, true, "lll" }, 3206 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4, true, "lll" }, 3207 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6, true, "lll" }, 3208 { "__insn_drain", TILEGX_INSN_DRAIN, false, "v" }, 3209 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR, false, "vl" }, 3210 { "__insn_exch", TILEGX_INSN_EXCH, false, "lpl" }, 3211 { "__insn_exch4", TILEGX_INSN_EXCH4, false, "ipi" }, 3212 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS, true, "lll" }, 3213 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB, true, "llll" }, 3214 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS, true, "lll" }, 3215 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1, true, "lll" }, 3216 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2, true, "llll" }, 3217 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS, true, "lll" }, 3218 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX, true, "lll" }, 3219 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN, true, "lll" }, 3220 { "__insn_fetchadd", TILEGX_INSN_FETCHADD, false, "lpl" }, 3221 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4, false, "ipi" }, 3222 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ, false, "lpl" }, 3223 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4, false, "ipi" }, 3224 { "__insn_fetchand", TILEGX_INSN_FETCHAND, false, "lpl" }, 3225 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4, false, "ipi" }, 3226 { "__insn_fetchor", TILEGX_INSN_FETCHOR, false, "lpl" }, 3227 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4, false, "ipi" }, 3228 { "__insn_finv", TILEGX_INSN_FINV, false, "vk" }, 3229 { "__insn_flush", TILEGX_INSN_FLUSH, false, "vk" }, 3230 { "__insn_flushwb", TILEGX_INSN_FLUSHWB, false, "v" }, 3231 { "__insn_fnop", TILEGX_INSN_FNOP, false, "v" }, 3232 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1, true, "lll" }, 3233 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2, true, "llll" }, 3234 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1, true, "lll" }, 3235 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2, true, "lll" }, 3236 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1, true, "ll" }, 3237 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2, true, "lll" }, 3238 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1, true, "lll" }, 3239 { "__insn_icoh", TILEGX_INSN_ICOH, false, "vk" }, 3240 { "__insn_ill", TILEGX_INSN_ILL, false, "v" }, 3241 { "__insn_info", TILEGX_INSN_INFO, false, "vl" }, 3242 { "__insn_infol", TILEGX_INSN_INFOL, false, "vl" }, 3243 { "__insn_inv", TILEGX_INSN_INV, false, "vp" }, 3244 { "__insn_ld", TILEGX_INSN_LD, false, "lk" }, 3245 { "__insn_ld1s", TILEGX_INSN_LD1S, false, "lk" }, 3246 { "__insn_ld1u", TILEGX_INSN_LD1U, false, "lk" }, 3247 { "__insn_ld2s", TILEGX_INSN_LD2S, false, "lk" }, 3248 { "__insn_ld2u", TILEGX_INSN_LD2U, false, "lk" }, 3249 { "__insn_ld4s", TILEGX_INSN_LD4S, false, "lk" }, 3250 { "__insn_ld4u", TILEGX_INSN_LD4U, false, "lk" }, 3251 { "__insn_ldna", TILEGX_INSN_LDNA, false, "lk" }, 3252 { "__insn_ldnt", TILEGX_INSN_LDNT, false, "lk" }, 3253 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S, false, "lk" }, 3254 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U, false, "lk" }, 3255 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S, false, "lk" }, 3256 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U, false, "lk" }, 3257 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S, false, "lk" }, 3258 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U, false, "lk" }, 3259 { "__insn_ld_L2", TILEGX_INSN_LD_L2, false, "lk" }, 3260 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2, false, "lk" }, 3261 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2, false, "lk" }, 3262 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2, false, "lk" }, 3263 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2, false, "lk" }, 3264 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2, false, "lk" }, 3265 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2, false, "lk" }, 3266 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2, false, "lk" }, 3267 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2, false, "lk" }, 3268 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2, false, "lk" }, 3269 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2, false, "lk" }, 3270 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2, false, "lk" }, 3271 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2, false, "lk" }, 3272 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2, false, "lk" }, 3273 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2, false, "lk" }, 3274 { "__insn_ld_miss", TILEGX_INSN_LD_MISS, false, "lk" }, 3275 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS, false, "lk" }, 3276 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS, false, "lk" }, 3277 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS, false, "lk" }, 3278 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS, false, "lk" }, 3279 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS, false, "lk" }, 3280 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS, false, "lk" }, 3281 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS, false, "lk" }, 3282 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS, false, "lk" }, 3283 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS, false, "lk" }, 3284 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS, false, "lk" }, 3285 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS, false, "lk" }, 3286 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS, false, "lk" }, 3287 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS, false, "lk" }, 3288 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS, false, "lk" }, 3289 { "__insn_lnk", TILEGX_INSN_LNK, true, "l" }, 3290 { "__insn_mf", TILEGX_INSN_MF, false, "v" }, 3291 { "__insn_mfspr", TILEGX_INSN_MFSPR, false, "ll" }, 3292 { "__insn_mm", TILEGX_INSN_MM, true, "lllll"}, 3293 { "__insn_mnz", TILEGX_INSN_MNZ, true, "lll" }, 3294 { "__insn_move", TILEGX_INSN_MOVE, true, "ll" }, 3295 { "__insn_movei", TILEGX_INSN_MOVE, true, "ll" }, 3296 { "__insn_moveli", TILEGX_INSN_MOVE, true, "ll" }, 3297 { "__insn_mtspr", TILEGX_INSN_MTSPR, false, "vll" }, 3298 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS, true, "lll" }, 3299 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU, true, "lll" }, 3300 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS, true, "lll" }, 3301 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU, true, "lll" }, 3302 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU, true, "lll" }, 3303 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS, true, "lll" }, 3304 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU, true, "lll" }, 3305 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS, true, "lll" }, 3306 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU, true, "lll" }, 3307 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU, true, "lll" }, 3308 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS, true, "llll" }, 3309 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU, true, "llll" }, 3310 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS, true, "llll" }, 3311 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU, true, "llll" }, 3312 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU, true, "llll" }, 3313 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS, true, "llll" }, 3314 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU, true, "llll" }, 3315 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS, true, "llll" }, 3316 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU, true, "llll" }, 3317 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU, true, "llll" }, 3318 { "__insn_mulax", TILEGX_INSN_MULAX, true, "iiii" }, 3319 { "__insn_mulx", TILEGX_INSN_MULX, true, "iii" }, 3320 { "__insn_mz", TILEGX_INSN_MZ, true, "lll" }, 3321 { "__insn_nap", TILEGX_INSN_NAP, false, "v" }, 3322 { "__insn_nop", TILEGX_INSN_NOP, true, "v" }, 3323 { "__insn_nor", TILEGX_INSN_NOR, true, "lll" }, 3324 { "__insn_or", TILEGX_INSN_OR, true, "lll" }, 3325 { "__insn_ori", TILEGX_INSN_OR, true, "lll" }, 3326 { "__insn_pcnt", TILEGX_INSN_PCNT, true, "ll" }, 3327 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1, false, "vk" }, 3328 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1, false, "vk" }, 3329 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT, false, "vk" }, 3330 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2, false, "vk" }, 3331 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT, false, "vk" }, 3332 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3, false, "vk" }, 3333 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT, false, "vk" }, 3334 { "__insn_revbits", TILEGX_INSN_REVBITS, true, "ll" }, 3335 { "__insn_revbytes", TILEGX_INSN_REVBYTES, true, "ll" }, 3336 { "__insn_rotl", TILEGX_INSN_ROTL, true, "lli" }, 3337 { "__insn_rotli", TILEGX_INSN_ROTL, true, "lli" }, 3338 { "__insn_shl", TILEGX_INSN_SHL, true, "lli" }, 3339 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI, true, "lll" }, 3340 { "__insn_shl1add", TILEGX_INSN_SHL1ADD, true, "lll" }, 3341 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX, true, "iii" }, 3342 { "__insn_shl2add", TILEGX_INSN_SHL2ADD, true, "lll" }, 3343 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX, true, "iii" }, 3344 { "__insn_shl3add", TILEGX_INSN_SHL3ADD, true, "lll" }, 3345 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX, true, "iii" }, 3346 { "__insn_shli", TILEGX_INSN_SHL, true, "lli" }, 3347 { "__insn_shlx", TILEGX_INSN_SHLX, true, "iii" }, 3348 { "__insn_shlxi", TILEGX_INSN_SHLX, true, "iii" }, 3349 { "__insn_shrs", TILEGX_INSN_SHRS, true, "lli" }, 3350 { "__insn_shrsi", TILEGX_INSN_SHRS, true, "lli" }, 3351 { "__insn_shru", TILEGX_INSN_SHRU, true, "lli" }, 3352 { "__insn_shrui", TILEGX_INSN_SHRU, true, "lli" }, 3353 { "__insn_shrux", TILEGX_INSN_SHRUX, true, "iii" }, 3354 { "__insn_shruxi", TILEGX_INSN_SHRUX, true, "iii" }, 3355 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES, true, "llll" }, 3356 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1, true, "lll" }, 3357 { "__insn_st", TILEGX_INSN_ST, false, "vpl" }, 3358 { "__insn_st1", TILEGX_INSN_ST1, false, "vpl" }, 3359 { "__insn_st2", TILEGX_INSN_ST2, false, "vpl" }, 3360 { "__insn_st4", TILEGX_INSN_ST4, false, "vpl" }, 3361 { "__insn_stnt", TILEGX_INSN_STNT, false, "vpl" }, 3362 { "__insn_stnt1", TILEGX_INSN_STNT1, false, "vpl" }, 3363 { "__insn_stnt2", TILEGX_INSN_STNT2, false, "vpl" }, 3364 { "__insn_stnt4", TILEGX_INSN_STNT4, false, "vpl" }, 3365 { "__insn_sub", TILEGX_INSN_SUB, true, "lll" }, 3366 { "__insn_subx", TILEGX_INSN_SUBX, true, "iii" }, 3367 { "__insn_subxsc", TILEGX_INSN_SUBXSC, true, "iii" }, 3368 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0, true, "lll" }, 3369 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1, true, "lll" }, 3370 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2, true, "lll" }, 3371 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3, true, "lll" }, 3372 { "__insn_v1add", TILEGX_INSN_V1ADD, true, "lll" }, 3373 { "__insn_v1addi", TILEGX_INSN_V1ADDI, true, "lll" }, 3374 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC, true, "lll" }, 3375 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU, true, "lll" }, 3376 { "__insn_v1avgu", TILEGX_INSN_V1AVGU, true, "lll" }, 3377 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ, true, "lll" }, 3378 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI, true, "lll" }, 3379 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES, true, "lll" }, 3380 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU, true, "lll" }, 3381 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS, true, "lll" }, 3382 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI, true, "lll" }, 3383 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU, true, "lll" }, 3384 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI, true, "lll" }, 3385 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE, true, "lll" }, 3386 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU, true, "lll" }, 3387 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA, true, "llll" }, 3388 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS, true, "lll" }, 3389 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA, true, "llll" }, 3390 { "__insn_v1dotp", TILEGX_INSN_V1DOTP, true, "lll" }, 3391 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA, true, "llll" }, 3392 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU, true, "lll" }, 3393 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA, true, "llll" }, 3394 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS, true, "lll" }, 3395 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA, true, "llll" }, 3396 { "__insn_v1int_h", TILEGX_INSN_V1INT_H, true, "lll" }, 3397 { "__insn_v1int_l", TILEGX_INSN_V1INT_L, true, "lll" }, 3398 { "__insn_v1maxu", TILEGX_INSN_V1MAXU, true, "lll" }, 3399 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI, true, "lll" }, 3400 { "__insn_v1minu", TILEGX_INSN_V1MINU, true, "lll" }, 3401 { "__insn_v1minui", TILEGX_INSN_V1MINUI, true, "lll" }, 3402 { "__insn_v1mnz", TILEGX_INSN_V1MNZ, true, "lll" }, 3403 { "__insn_v1multu", TILEGX_INSN_V1MULTU, true, "lll" }, 3404 { "__insn_v1mulu", TILEGX_INSN_V1MULU, true, "lll" }, 3405 { "__insn_v1mulus", TILEGX_INSN_V1MULUS, true, "lll" }, 3406 { "__insn_v1mz", TILEGX_INSN_V1MZ, true, "lll" }, 3407 { "__insn_v1sadau", TILEGX_INSN_V1SADAU, true, "llll" }, 3408 { "__insn_v1sadu", TILEGX_INSN_V1SADU, true, "lll" }, 3409 { "__insn_v1shl", TILEGX_INSN_V1SHL, true, "lll" }, 3410 { "__insn_v1shli", TILEGX_INSN_V1SHLI, true, "lll" }, 3411 { "__insn_v1shrs", TILEGX_INSN_V1SHRS, true, "lll" }, 3412 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI, true, "lll" }, 3413 { "__insn_v1shru", TILEGX_INSN_V1SHRU, true, "lll" }, 3414 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI, true, "lll" }, 3415 { "__insn_v1sub", TILEGX_INSN_V1SUB, true, "lll" }, 3416 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC, true, "lll" }, 3417 { "__insn_v2add", TILEGX_INSN_V2ADD, true, "lll" }, 3418 { "__insn_v2addi", TILEGX_INSN_V2ADDI, true, "lll" }, 3419 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC, true, "lll" }, 3420 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS, true, "lll" }, 3421 { "__insn_v2avgs", TILEGX_INSN_V2AVGS, true, "lll" }, 3422 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ, true, "lll" }, 3423 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI, true, "lll" }, 3424 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES, true, "lll" }, 3425 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU, true, "lll" }, 3426 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS, true, "lll" }, 3427 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI, true, "lll" }, 3428 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU, true, "lll" }, 3429 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI, true, "lll" }, 3430 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE, true, "lll" }, 3431 { "__insn_v2dotp", TILEGX_INSN_V2DOTP, true, "lll" }, 3432 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA, true, "llll" }, 3433 { "__insn_v2int_h", TILEGX_INSN_V2INT_H, true, "lll" }, 3434 { "__insn_v2int_l", TILEGX_INSN_V2INT_L, true, "lll" }, 3435 { "__insn_v2maxs", TILEGX_INSN_V2MAXS, true, "lll" }, 3436 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI, true, "lll" }, 3437 { "__insn_v2mins", TILEGX_INSN_V2MINS, true, "lll" }, 3438 { "__insn_v2minsi", TILEGX_INSN_V2MINSI, true, "lll" }, 3439 { "__insn_v2mnz", TILEGX_INSN_V2MNZ, true, "lll" }, 3440 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC, true, "lll" }, 3441 { "__insn_v2muls", TILEGX_INSN_V2MULS, true, "lll" }, 3442 { "__insn_v2mults", TILEGX_INSN_V2MULTS, true, "lll" }, 3443 { "__insn_v2mz", TILEGX_INSN_V2MZ, true, "lll" }, 3444 { "__insn_v2packh", TILEGX_INSN_V2PACKH, true, "lll" }, 3445 { "__insn_v2packl", TILEGX_INSN_V2PACKL, true, "lll" }, 3446 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC, true, "lll" }, 3447 { "__insn_v2sadas", TILEGX_INSN_V2SADAS, true, "llll" }, 3448 { "__insn_v2sadau", TILEGX_INSN_V2SADAU, true, "llll" }, 3449 { "__insn_v2sads", TILEGX_INSN_V2SADS, true, "lll" }, 3450 { "__insn_v2sadu", TILEGX_INSN_V2SADU, true, "lll" }, 3451 { "__insn_v2shl", TILEGX_INSN_V2SHL, true, "lll" }, 3452 { "__insn_v2shli", TILEGX_INSN_V2SHLI, true, "lll" }, 3453 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC, true, "lll" }, 3454 { "__insn_v2shrs", TILEGX_INSN_V2SHRS, true, "lll" }, 3455 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI, true, "lll" }, 3456 { "__insn_v2shru", TILEGX_INSN_V2SHRU, true, "lll" }, 3457 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI, true, "lll" }, 3458 { "__insn_v2sub", TILEGX_INSN_V2SUB, true, "lll" }, 3459 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC, true, "lll" }, 3460 { "__insn_v4add", TILEGX_INSN_V4ADD, true, "lll" }, 3461 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC, true, "lll" }, 3462 { "__insn_v4int_h", TILEGX_INSN_V4INT_H, true, "lll" }, 3463 { "__insn_v4int_l", TILEGX_INSN_V4INT_L, true, "lll" }, 3464 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC, true, "lll" }, 3465 { "__insn_v4shl", TILEGX_INSN_V4SHL, true, "lll" }, 3466 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC, true, "lll" }, 3467 { "__insn_v4shrs", TILEGX_INSN_V4SHRS, true, "lll" }, 3468 { "__insn_v4shru", TILEGX_INSN_V4SHRU, true, "lll" }, 3469 { "__insn_v4sub", TILEGX_INSN_V4SUB, true, "lll" }, 3470 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC, true, "lll" }, 3471 { "__insn_wh64", TILEGX_INSN_WH64, false, "vp" }, 3472 { "__insn_xor", TILEGX_INSN_XOR, true, "lll" }, 3473 { "__insn_xori", TILEGX_INSN_XOR, true, "lll" }, 3474 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER, false, "v" }, 3475 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE, false, "l" }, 3476 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE, false, "l" }, 3477 { "__tile_idn_send", TILEGX_IDN_SEND, false, "vl" }, 3478 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE, false, "l" }, 3479 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE, false, "l" }, 3480 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE, false, "l" }, 3481 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE, false, "l" }, 3482 { "__tile_udn_send", TILEGX_UDN_SEND, false, "vl" }, 3483}; 3484 3485 3486/* Convert a character in a builtin type string to a tree type. */ 3487static tree 3488char_to_type (char c) 3489{ 3490 static tree volatile_ptr_type_node = NULL; 3491 static tree volatile_const_ptr_type_node = NULL; 3492 3493 if (volatile_ptr_type_node == NULL) 3494 { 3495 volatile_ptr_type_node = 3496 build_pointer_type (build_qualified_type (void_type_node, 3497 TYPE_QUAL_VOLATILE)); 3498 volatile_const_ptr_type_node = 3499 build_pointer_type (build_qualified_type (void_type_node, 3500 TYPE_QUAL_CONST 3501 | TYPE_QUAL_VOLATILE)); 3502 } 3503 3504 switch (c) 3505 { 3506 case 'v': 3507 return void_type_node; 3508 case 'i': 3509 return unsigned_type_node; 3510 case 'l': 3511 return long_long_unsigned_type_node; 3512 case 'p': 3513 return volatile_ptr_type_node; 3514 case 'k': 3515 return volatile_const_ptr_type_node; 3516 default: 3517 gcc_unreachable (); 3518 } 3519} 3520 3521 3522/* Implement TARGET_INIT_BUILTINS. */ 3523static void 3524tilegx_init_builtins (void) 3525{ 3526 size_t i; 3527 3528 for (i = 0; i < ARRAY_SIZE (tilegx_builtins); i++) 3529 { 3530 const struct tilegx_builtin_def *p = &tilegx_builtins[i]; 3531 tree ftype, ret_type, arg_type_list = void_list_node; 3532 tree decl; 3533 int j; 3534 3535 for (j = strlen (p->type) - 1; j > 0; j--) 3536 { 3537 arg_type_list = 3538 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list); 3539 } 3540 3541 ret_type = char_to_type (p->type[0]); 3542 3543 ftype = build_function_type (ret_type, arg_type_list); 3544 3545 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD, 3546 NULL, NULL); 3547 3548 if (p->is_const) 3549 TREE_READONLY (decl) = 1; 3550 TREE_NOTHROW (decl) = 1; 3551 3552 if (tilegx_builtin_info[p->code].fndecl == NULL) 3553 tilegx_builtin_info[p->code].fndecl = decl; 3554 } 3555} 3556 3557 3558/* Implement TARGET_EXPAND_BUILTIN. */ 3559static rtx 3560tilegx_expand_builtin (tree exp, 3561 rtx target, 3562 rtx subtarget ATTRIBUTE_UNUSED, 3563 machine_mode mode ATTRIBUTE_UNUSED, 3564 int ignore ATTRIBUTE_UNUSED) 3565{ 3566#define MAX_BUILTIN_ARGS 4 3567 3568 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); 3569 unsigned int fcode = DECL_FUNCTION_CODE (fndecl); 3570 tree arg; 3571 call_expr_arg_iterator iter; 3572 enum insn_code icode; 3573 rtx op[MAX_BUILTIN_ARGS + 1], pat; 3574 int opnum; 3575 bool nonvoid; 3576 insn_gen_fn fn; 3577 3578 if (fcode >= TILEGX_BUILTIN_max) 3579 internal_error ("bad builtin fcode"); 3580 icode = tilegx_builtin_info[fcode].icode; 3581 if (icode == 0) 3582 internal_error ("bad builtin icode"); 3583 3584 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; 3585 3586 opnum = nonvoid; 3587 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) 3588 { 3589 const struct insn_operand_data *insn_op; 3590 3591 if (arg == error_mark_node) 3592 return NULL_RTX; 3593 if (opnum > MAX_BUILTIN_ARGS) 3594 return NULL_RTX; 3595 3596 insn_op = &insn_data[icode].operand[opnum]; 3597 3598 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL); 3599 3600 if (!(*insn_op->predicate) (op[opnum], insn_op->mode)) 3601 { 3602 machine_mode opmode = insn_op->mode; 3603 3604 /* pointer_operand and pmode_register_operand operands do 3605 not specify a mode, so use the operand's mode instead 3606 (which should always be right by the time we get here, 3607 except for constants, which are VOIDmode). */ 3608 if (opmode == VOIDmode) 3609 { 3610 machine_mode m = GET_MODE (op[opnum]); 3611 gcc_assert (m == Pmode || m == VOIDmode); 3612 opmode = Pmode; 3613 } 3614 3615 op[opnum] = copy_to_mode_reg (opmode, op[opnum]); 3616 } 3617 3618 if (!(*insn_op->predicate) (op[opnum], insn_op->mode)) 3619 { 3620 /* We still failed to meet the predicate even after moving 3621 into a register. Assume we needed an immediate. */ 3622 error_at (EXPR_LOCATION (exp), 3623 "operand must be an immediate of the right size"); 3624 return const0_rtx; 3625 } 3626 3627 opnum++; 3628 } 3629 3630 if (nonvoid) 3631 { 3632 machine_mode tmode = insn_data[icode].operand[0].mode; 3633 if (!target 3634 || GET_MODE (target) != tmode 3635 || !(*insn_data[icode].operand[0].predicate) (target, tmode)) 3636 { 3637 if (tmode == VOIDmode) 3638 { 3639 /* get the mode from the return type. */ 3640 tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))); 3641 } 3642 target = gen_reg_rtx (tmode); 3643 } 3644 op[0] = target; 3645 } 3646 3647 fn = GEN_FCN (icode); 3648 switch (opnum) 3649 { 3650 case 0: 3651 pat = fn (NULL_RTX); 3652 break; 3653 case 1: 3654 pat = fn (op[0]); 3655 break; 3656 case 2: 3657 pat = fn (op[0], op[1]); 3658 break; 3659 case 3: 3660 pat = fn (op[0], op[1], op[2]); 3661 break; 3662 case 4: 3663 pat = fn (op[0], op[1], op[2], op[3]); 3664 break; 3665 case 5: 3666 pat = fn (op[0], op[1], op[2], op[3], op[4]); 3667 break; 3668 default: 3669 gcc_unreachable (); 3670 } 3671 if (!pat) 3672 return NULL_RTX; 3673 3674 /* If we are generating a prefetch, tell the scheduler not to move 3675 it around. */ 3676 if (GET_CODE (pat) == PREFETCH) 3677 PREFETCH_SCHEDULE_BARRIER_P (pat) = true; 3678 3679 emit_insn (pat); 3680 3681 if (nonvoid) 3682 return target; 3683 else 3684 return const0_rtx; 3685} 3686 3687 3688/* Implement TARGET_BUILTIN_DECL. */ 3689static tree 3690tilegx_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) 3691{ 3692 if (code >= TILEGX_BUILTIN_max) 3693 return error_mark_node; 3694 3695 return tilegx_builtin_info[code].fndecl; 3696} 3697 3698 3699 3700/* Stack frames */ 3701 3702/* Return whether REGNO needs to be saved in the stack frame. */ 3703static bool 3704need_to_save_reg (unsigned int regno) 3705{ 3706 if (!fixed_regs[regno] && !call_used_regs[regno] 3707 && df_regs_ever_live_p (regno)) 3708 return true; 3709 3710 if (flag_pic 3711 && (regno == PIC_OFFSET_TABLE_REGNUM 3712 || regno == TILEGX_PIC_TEXT_LABEL_REGNUM) 3713 && (crtl->uses_pic_offset_table || crtl->saves_all_registers)) 3714 return true; 3715 3716 if (crtl->calls_eh_return) 3717 { 3718 unsigned i; 3719 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++) 3720 { 3721 if (regno == EH_RETURN_DATA_REGNO (i)) 3722 return true; 3723 } 3724 } 3725 3726 return false; 3727} 3728 3729 3730/* Return the size of the register savev area. This function is only 3731 correct starting with local register allocation */ 3732static int 3733tilegx_saved_regs_size (void) 3734{ 3735 int reg_save_size = 0; 3736 int regno; 3737 int offset_to_frame; 3738 int align_mask; 3739 3740 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 3741 if (need_to_save_reg (regno)) 3742 reg_save_size += UNITS_PER_WORD; 3743 3744 /* Pad out the register save area if necessary to make 3745 frame_pointer_rtx be as aligned as the stack pointer. */ 3746 offset_to_frame = crtl->args.pretend_args_size + reg_save_size; 3747 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1; 3748 reg_save_size += (-offset_to_frame) & align_mask; 3749 3750 return reg_save_size; 3751} 3752 3753 3754/* Round up frame size SIZE. */ 3755static int 3756round_frame_size (int size) 3757{ 3758 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1) 3759 & -STACK_BOUNDARY / BITS_PER_UNIT); 3760} 3761 3762 3763/* Emit a store in the stack frame to save REGNO at address ADDR, and 3764 emit the corresponding REG_CFA_OFFSET note described by CFA and 3765 CFA_OFFSET. Return the emitted insn. */ 3766static rtx 3767frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa, 3768 int cfa_offset) 3769{ 3770 rtx reg = gen_rtx_REG (DImode, regno); 3771 rtx mem = gen_frame_mem (DImode, addr); 3772 rtx mov = gen_movdi (mem, reg); 3773 3774 /* Describe what just happened in a way that dwarf understands. We 3775 use temporary registers to hold the address to make scheduling 3776 easier, and use the REG_CFA_OFFSET to describe the address as an 3777 offset from the CFA. */ 3778 rtx reg_note = gen_rtx_REG (DImode, regno_note); 3779 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, GEN_INT (cfa_offset)); 3780 rtx cfa_relative_mem = gen_frame_mem (DImode, cfa_relative_addr); 3781 rtx real = gen_rtx_SET (VOIDmode, cfa_relative_mem, reg_note); 3782 add_reg_note (mov, REG_CFA_OFFSET, real); 3783 3784 return emit_insn (mov); 3785} 3786 3787 3788/* Emit a load in the stack frame to load REGNO from address ADDR. 3789 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is 3790 non-null. Return the emitted insn. */ 3791static rtx_insn * 3792frame_emit_load (int regno, rtx addr, rtx *cfa_restores) 3793{ 3794 rtx reg = gen_rtx_REG (DImode, regno); 3795 rtx mem = gen_frame_mem (DImode, addr); 3796 if (cfa_restores) 3797 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores); 3798 return emit_insn (gen_movdi (reg, mem)); 3799} 3800 3801 3802/* Helper function to set RTX_FRAME_RELATED_P on instructions, 3803 including sequences. */ 3804static rtx 3805set_frame_related_p (void) 3806{ 3807 rtx_insn *seq = get_insns (); 3808 rtx_insn *insn; 3809 3810 end_sequence (); 3811 3812 if (!seq) 3813 return NULL_RTX; 3814 3815 if (INSN_P (seq)) 3816 { 3817 insn = seq; 3818 while (insn != NULL_RTX) 3819 { 3820 RTX_FRAME_RELATED_P (insn) = 1; 3821 insn = NEXT_INSN (insn); 3822 } 3823 seq = emit_insn (seq); 3824 } 3825 else 3826 { 3827 seq = emit_insn (seq); 3828 RTX_FRAME_RELATED_P (seq) = 1; 3829 } 3830 return seq; 3831} 3832 3833 3834#define FRP(exp) (start_sequence (), exp, set_frame_related_p ()) 3835 3836/* This emits code for 'sp += offset'. 3837 3838 The ABI only allows us to modify 'sp' in a single 'addi' or 3839 'addli', so the backtracer understands it. Larger amounts cannot 3840 use those instructions, so are added by placing the offset into a 3841 large register and using 'add'. 3842 3843 This happens after reload, so we need to expand it ourselves. */ 3844static rtx_insn * 3845emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related, 3846 rtx reg_notes) 3847{ 3848 rtx to_add; 3849 rtx imm_rtx = GEN_INT (offset); 3850 rtx pat; 3851 rtx_insn *insn; 3852 3853 if (satisfies_constraint_J (imm_rtx)) 3854 { 3855 /* We can add this using a single immediate add. */ 3856 to_add = imm_rtx; 3857 } 3858 else 3859 { 3860 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--); 3861 tilegx_expand_set_const64 (tmp, imm_rtx); 3862 to_add = tmp; 3863 } 3864 3865 /* Actually adjust the stack pointer. */ 3866 if (TARGET_32BIT) 3867 pat = gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, to_add); 3868 else 3869 pat = gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, to_add); 3870 3871 insn = emit_insn (pat); 3872 REG_NOTES (insn) = reg_notes; 3873 3874 /* Describe what just happened in a way that dwarf understands. */ 3875 if (frame_related) 3876 { 3877 rtx real = gen_rtx_SET (VOIDmode, stack_pointer_rtx, 3878 gen_rtx_PLUS (Pmode, stack_pointer_rtx, 3879 imm_rtx)); 3880 RTX_FRAME_RELATED_P (insn) = 1; 3881 add_reg_note (insn, REG_CFA_ADJUST_CFA, real); 3882 } 3883 3884 return insn; 3885} 3886 3887 3888/* Return whether the current function is leaf. This takes into 3889 account whether the function calls tls_get_addr. */ 3890static bool 3891tilegx_current_function_is_leaf (void) 3892{ 3893 return crtl->is_leaf && !cfun->machine->calls_tls_get_addr; 3894} 3895 3896 3897/* Return the frame size. */ 3898static int 3899compute_total_frame_size (void) 3900{ 3901 int total_size = (get_frame_size () + tilegx_saved_regs_size () 3902 + crtl->outgoing_args_size 3903 + crtl->args.pretend_args_size); 3904 3905 if (!tilegx_current_function_is_leaf () || cfun->calls_alloca) 3906 { 3907 /* Make room for save area in callee. */ 3908 total_size += STACK_POINTER_OFFSET; 3909 } 3910 3911 return round_frame_size (total_size); 3912} 3913 3914 3915/* Return nonzero if this function is known to have a null epilogue. 3916 This allows the optimizer to omit jumps to jumps if no stack was 3917 created. */ 3918bool 3919tilegx_can_use_return_insn_p (void) 3920{ 3921 return (reload_completed 3922 && cfun->static_chain_decl == 0 3923 && compute_total_frame_size () == 0 3924 && tilegx_current_function_is_leaf () 3925 && !crtl->profile && !df_regs_ever_live_p (TILEGX_LINK_REGNUM)); 3926} 3927 3928 3929/* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there 3930 is a frame pointer, it computes the value relative to 3931 that. Otherwise it uses the stack pointer. */ 3932static rtx 3933compute_frame_addr (int offset_from_fp, int *next_scratch_regno) 3934{ 3935 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx; 3936 int offset_from_base; 3937 3938 if (frame_pointer_needed) 3939 { 3940 base_reg_rtx = hard_frame_pointer_rtx; 3941 offset_from_base = offset_from_fp; 3942 } 3943 else 3944 { 3945 int offset_from_sp = compute_total_frame_size () + offset_from_fp; 3946 offset_from_base = offset_from_sp; 3947 base_reg_rtx = stack_pointer_rtx; 3948 } 3949 3950 if (offset_from_base == 0) 3951 return base_reg_rtx; 3952 3953 /* Compute the new value of the stack pointer. */ 3954 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--); 3955 offset_rtx = GEN_INT (offset_from_base); 3956 3957 if (!add_operand (offset_rtx, Pmode)) 3958 { 3959 expand_set_cint64 (tmp_reg_rtx, offset_rtx); 3960 offset_rtx = tmp_reg_rtx; 3961 } 3962 3963 emit_insn (gen_rtx_SET (VOIDmode, tmp_reg_rtx, 3964 gen_rtx_PLUS (Pmode, base_reg_rtx, offset_rtx))); 3965 3966 return tmp_reg_rtx; 3967} 3968 3969 3970/* The stack frame looks like this: 3971 +-------------+ 3972 | ... | 3973 | incoming | 3974 | stack args | 3975 AP -> +-------------+ 3976 | caller's HFP| 3977 +-------------+ 3978 | lr save | 3979 HFP -> +-------------+ 3980 | var args | 3981 | reg save | crtl->args.pretend_args_size bytes 3982 +-------------+ 3983 | ... | 3984 | saved regs | tilegx_saved_regs_size() bytes 3985 FP -> +-------------+ 3986 | ... | 3987 | vars | get_frame_size() bytes 3988 +-------------+ 3989 | ... | 3990 | outgoing | 3991 | stack args | crtl->outgoing_args_size bytes 3992 +-------------+ 3993 | HFP | ptr_size bytes (only here if nonleaf / alloca) 3994 +-------------+ 3995 | callee lr | ptr_size bytes (only here if nonleaf / alloca) 3996 | save | 3997 SP -> +-------------+ 3998 3999 HFP == incoming SP. 4000 4001 For functions with a frame larger than 32767 bytes, or which use 4002 alloca (), r52 is used as a frame pointer. Otherwise there is no 4003 frame pointer. 4004 4005 FP is saved at SP+ptr_size before calling a subroutine so the callee 4006 can chain. */ 4007void 4008tilegx_expand_prologue (void) 4009{ 4010#define ROUND_ROBIN_SIZE 4 4011 /* We round-robin through four scratch registers to hold temporary 4012 addresses for saving registers, to make instruction scheduling 4013 easier. */ 4014 rtx reg_save_addr[ROUND_ROBIN_SIZE] = { 4015 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX 4016 }; 4017 rtx insn, cfa; 4018 unsigned int which_scratch; 4019 int offset, start_offset, regno; 4020 4021 /* A register that holds a copy of the incoming fp. */ 4022 int fp_copy_regno = -1; 4023 4024 /* A register that holds a copy of the incoming sp. */ 4025 int sp_copy_regno = -1; 4026 4027 /* Next scratch register number to hand out (postdecrementing). */ 4028 int next_scratch_regno = 29; 4029 4030 int total_size = compute_total_frame_size (); 4031 4032 if (flag_stack_usage_info) 4033 current_function_static_stack_size = total_size; 4034 4035 /* Save lr first in its special location because code after this 4036 might use the link register as a scratch register. */ 4037 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM) || crtl->calls_eh_return) 4038 FRP (frame_emit_store (TILEGX_LINK_REGNUM, TILEGX_LINK_REGNUM, 4039 stack_pointer_rtx, stack_pointer_rtx, 0)); 4040 4041 if (total_size == 0) 4042 { 4043 /* Load the PIC register if needed. */ 4044 if (flag_pic && crtl->uses_pic_offset_table) 4045 load_pic_register (false); 4046 4047 return; 4048 } 4049 4050 cfa = stack_pointer_rtx; 4051 4052 if (frame_pointer_needed) 4053 { 4054 fp_copy_regno = next_scratch_regno--; 4055 4056 /* Copy the old frame pointer aside so we can save it later. */ 4057 insn = 4058 FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno), 4059 gen_lowpart (word_mode, hard_frame_pointer_rtx))); 4060 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); 4061 4062 /* Set up the frame pointer. */ 4063 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); 4064 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx); 4065 cfa = hard_frame_pointer_rtx; 4066 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY; 4067 4068 /* fp holds a copy of the incoming sp, in case we need to store 4069 it. */ 4070 sp_copy_regno = HARD_FRAME_POINTER_REGNUM; 4071 } 4072 else if (!tilegx_current_function_is_leaf ()) 4073 { 4074 /* Copy the old stack pointer aside so we can save it later. */ 4075 sp_copy_regno = next_scratch_regno--; 4076 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno), 4077 stack_pointer_rtx); 4078 } 4079 4080 if (tilegx_current_function_is_leaf ()) 4081 { 4082 /* No need to store chain pointer to caller's frame. */ 4083 emit_sp_adjust (-total_size, &next_scratch_regno, 4084 !frame_pointer_needed, NULL_RTX); 4085 } 4086 else 4087 { 4088 /* Save the frame pointer (incoming sp value) to support 4089 backtracing. First we need to create an rtx with the store 4090 address. */ 4091 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--); 4092 rtx size_rtx = GEN_INT (-(total_size - UNITS_PER_WORD)); 4093 4094 if (add_operand (size_rtx, Pmode)) 4095 { 4096 /* Expose more parallelism by computing this value from the 4097 original stack pointer, not the one after we have pushed 4098 the frame. */ 4099 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx); 4100 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p)); 4101 emit_sp_adjust (-total_size, &next_scratch_regno, 4102 !frame_pointer_needed, NULL_RTX); 4103 } 4104 else 4105 { 4106 /* The stack frame is large, so just store the incoming sp 4107 value at *(new_sp + UNITS_PER_WORD). */ 4108 rtx p; 4109 emit_sp_adjust (-total_size, &next_scratch_regno, 4110 !frame_pointer_needed, NULL_RTX); 4111 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 4112 GEN_INT (UNITS_PER_WORD)); 4113 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p)); 4114 } 4115 4116 /* Save our frame pointer for backtrace chaining. */ 4117 emit_insn (gen_movdi (gen_frame_mem (DImode, chain_addr), 4118 gen_rtx_REG (DImode, sp_copy_regno))); 4119 } 4120 4121 /* Compute where to start storing registers we need to save. */ 4122 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD; 4123 offset = start_offset; 4124 4125 /* Store all registers that need saving. */ 4126 which_scratch = 0; 4127 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) 4128 if (need_to_save_reg (regno)) 4129 { 4130 rtx r = reg_save_addr[which_scratch]; 4131 int from_regno; 4132 int cfa_offset = frame_pointer_needed ? offset : total_size + offset; 4133 4134 if (r == NULL_RTX) 4135 { 4136 int prev_scratch_regno = next_scratch_regno; 4137 r = compute_frame_addr (offset, &next_scratch_regno); 4138 if (prev_scratch_regno != next_scratch_regno) 4139 reg_save_addr[which_scratch] = r; 4140 } 4141 else 4142 { 4143 /* Advance to the next stack slot to store this 4144 register. */ 4145 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD; 4146 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride)); 4147 emit_insn (gen_rtx_SET (VOIDmode, r, p)); 4148 } 4149 4150 /* Save this register to the stack (but use the old fp value 4151 we copied aside if appropriate). */ 4152 from_regno = 4153 (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM) 4154 ? fp_copy_regno : regno; 4155 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset)); 4156 4157 offset -= UNITS_PER_WORD; 4158 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE; 4159 } 4160 4161 /* If profiling, force that to happen after the frame is set up. */ 4162 if (crtl->profile) 4163 emit_insn (gen_blockage ()); 4164 4165 /* Load the PIC register if needed. */ 4166 if (flag_pic && crtl->uses_pic_offset_table) 4167 load_pic_register (false); 4168} 4169 4170 4171/* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is 4172 true for a sibcall_epilogue pattern, and false for an epilogue 4173 pattern. */ 4174void 4175tilegx_expand_epilogue (bool sibcall_p) 4176{ 4177 /* We round-robin through four scratch registers to hold temporary 4178 addresses for saving registers, to make instruction scheduling 4179 easier. */ 4180 rtx reg_save_addr[ROUND_ROBIN_SIZE] = { 4181 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX 4182 }; 4183 rtx_insn *last_insn, *insn; 4184 unsigned int which_scratch; 4185 int offset, start_offset, regno; 4186 rtx cfa_restores = NULL_RTX; 4187 4188 /* A register that holds a copy of the incoming fp. */ 4189 int fp_copy_regno = -1; 4190 4191 /* Next scratch register number to hand out (postdecrementing). */ 4192 int next_scratch_regno = 29; 4193 4194 int total_size = compute_total_frame_size (); 4195 4196 last_insn = get_last_insn (); 4197 4198 /* Load lr first since we are going to need it first. */ 4199 insn = NULL; 4200 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM)) 4201 { 4202 insn = frame_emit_load (TILEGX_LINK_REGNUM, 4203 compute_frame_addr (0, &next_scratch_regno), 4204 &cfa_restores); 4205 } 4206 4207 if (total_size == 0) 4208 { 4209 if (insn) 4210 { 4211 RTX_FRAME_RELATED_P (insn) = 1; 4212 REG_NOTES (insn) = cfa_restores; 4213 } 4214 goto done; 4215 } 4216 4217 /* Compute where to start restoring registers. */ 4218 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD; 4219 offset = start_offset; 4220 4221 if (frame_pointer_needed) 4222 fp_copy_regno = next_scratch_regno--; 4223 4224 /* Restore all callee-saved registers. */ 4225 which_scratch = 0; 4226 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) 4227 if (need_to_save_reg (regno)) 4228 { 4229 rtx r = reg_save_addr[which_scratch]; 4230 if (r == NULL_RTX) 4231 { 4232 r = compute_frame_addr (offset, &next_scratch_regno); 4233 reg_save_addr[which_scratch] = r; 4234 } 4235 else 4236 { 4237 /* Advance to the next stack slot to store this register. */ 4238 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD; 4239 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride)); 4240 emit_insn (gen_rtx_SET (VOIDmode, r, p)); 4241 } 4242 4243 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM) 4244 frame_emit_load (fp_copy_regno, r, NULL); 4245 else 4246 frame_emit_load (regno, r, &cfa_restores); 4247 4248 offset -= UNITS_PER_WORD; 4249 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE; 4250 } 4251 4252 if (!tilegx_current_function_is_leaf ()) 4253 cfa_restores = 4254 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores); 4255 4256 emit_insn (gen_blockage ()); 4257 4258 if (frame_pointer_needed) 4259 { 4260 /* Restore the old stack pointer by copying from the frame 4261 pointer. */ 4262 if (TARGET_32BIT) 4263 { 4264 insn = emit_insn (gen_sp_restore_32bit (stack_pointer_rtx, 4265 hard_frame_pointer_rtx)); 4266 } 4267 else 4268 { 4269 insn = emit_insn (gen_sp_restore (stack_pointer_rtx, 4270 hard_frame_pointer_rtx)); 4271 } 4272 RTX_FRAME_RELATED_P (insn) = 1; 4273 REG_NOTES (insn) = cfa_restores; 4274 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); 4275 } 4276 else 4277 { 4278 insn = emit_sp_adjust (total_size, &next_scratch_regno, true, 4279 cfa_restores); 4280 } 4281 4282 if (crtl->calls_eh_return) 4283 { 4284 if (TARGET_32BIT) 4285 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, 4286 EH_RETURN_STACKADJ_RTX)); 4287 else 4288 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, 4289 EH_RETURN_STACKADJ_RTX)); 4290 } 4291 4292 /* Restore the old frame pointer. */ 4293 if (frame_pointer_needed) 4294 { 4295 insn = emit_move_insn (gen_lowpart (DImode, hard_frame_pointer_rtx), 4296 gen_rtx_REG (DImode, fp_copy_regno)); 4297 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx); 4298 } 4299 4300 /* Mark the pic registers as live outside of the function. */ 4301 if (flag_pic) 4302 { 4303 emit_use (cfun->machine->text_label_rtx); 4304 emit_use (cfun->machine->got_rtx); 4305 } 4306 4307done: 4308 if (!sibcall_p) 4309 { 4310 emit_jump_insn (gen__return ()); 4311 } 4312 else 4313 { 4314 emit_use (gen_rtx_REG (Pmode, TILEGX_LINK_REGNUM)); 4315 } 4316 4317 /* Mark all insns we just emitted as frame-related. */ 4318 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn)) 4319 RTX_FRAME_RELATED_P (last_insn) = 1; 4320} 4321 4322#undef ROUND_ROBIN_SIZE 4323 4324 4325/* Implement INITIAL_ELIMINATION_OFFSET. */ 4326int 4327tilegx_initial_elimination_offset (int from, int to) 4328{ 4329 int total_size = compute_total_frame_size (); 4330 4331 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 4332 { 4333 return (total_size - crtl->args.pretend_args_size 4334 - tilegx_saved_regs_size ()); 4335 } 4336 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 4337 { 4338 return -(crtl->args.pretend_args_size + tilegx_saved_regs_size ()); 4339 } 4340 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 4341 { 4342 return STACK_POINTER_OFFSET + total_size; 4343 } 4344 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 4345 { 4346 return STACK_POINTER_OFFSET; 4347 } 4348 else 4349 gcc_unreachable (); 4350} 4351 4352 4353/* Return an RTX indicating where the return address to the calling 4354 function can be found. */ 4355rtx 4356tilegx_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 4357{ 4358 if (count != 0) 4359 return const0_rtx; 4360 4361 return get_hard_reg_initial_val (Pmode, TILEGX_LINK_REGNUM); 4362} 4363 4364 4365/* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to 4366 prevent it from being deleted. */ 4367rtx 4368tilegx_eh_return_handler_rtx (void) 4369{ 4370 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx); 4371 MEM_VOLATILE_P (tmp) = true; 4372 return tmp; 4373} 4374 4375 4376 4377/* Registers */ 4378 4379/* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */ 4380static void 4381tilegx_conditional_register_usage (void) 4382{ 4383 global_regs[TILEGX_NETORDER_REGNUM] = 1; 4384 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a 4385 member of fixed_regs, and therefore must be member of 4386 call_used_regs, but it is not a member of call_really_used_regs[] 4387 because it is not clobbered by a call. */ 4388 if (TILEGX_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM) 4389 { 4390 fixed_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1; 4391 call_used_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1; 4392 } 4393 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) 4394 { 4395 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 4396 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 4397 } 4398} 4399 4400 4401/* Implement TARGET_FRAME_POINTER_REQUIRED. */ 4402static bool 4403tilegx_frame_pointer_required (void) 4404{ 4405 return crtl->calls_eh_return || cfun->calls_alloca; 4406} 4407 4408 4409 4410/* Scheduling and reorg */ 4411 4412/* Return the length of INSN. LENGTH is the initial length computed 4413 by attributes in the machine-description file. This is where we 4414 account for bundles. */ 4415int 4416tilegx_adjust_insn_length (rtx_insn *insn, int length) 4417{ 4418 machine_mode mode = GET_MODE (insn); 4419 4420 /* A non-termininating instruction in a bundle has length 0. */ 4421 if (mode == SImode) 4422 return 0; 4423 4424 /* By default, there is not length adjustment. */ 4425 return length; 4426} 4427 4428 4429/* Implement TARGET_SCHED_ISSUE_RATE. */ 4430static int 4431tilegx_issue_rate (void) 4432{ 4433 return 3; 4434} 4435 4436 4437/* Return the rtx for the jump target. */ 4438static rtx 4439get_jump_target (rtx branch) 4440{ 4441 if (CALL_P (branch)) 4442 { 4443 rtx call; 4444 call = PATTERN (branch); 4445 4446 if (GET_CODE (call) == PARALLEL) 4447 call = XVECEXP (call, 0, 0); 4448 4449 if (GET_CODE (call) == SET) 4450 call = SET_SRC (call); 4451 4452 if (GET_CODE (call) == CALL) 4453 return XEXP (XEXP (call, 0), 0); 4454 } 4455 return 0; 4456} 4457 4458 4459/* Implement TARGET_SCHED_ADJUST_COST. */ 4460static int 4461tilegx_sched_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, 4462 int cost) 4463{ 4464 /* If we have a true dependence, INSN is a call, and DEP_INSN 4465 defines a register that is needed by the call (argument or stack 4466 pointer) , set its latency to 0 so that it can be bundled with 4467 the call. Explicitly check for and exclude the case when 4468 DEP_INSN defines the target of the jump. */ 4469 if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE) 4470 { 4471 rtx target = get_jump_target (insn); 4472 if (!REG_P (target) || !set_of (target, dep_insn)) 4473 return 0; 4474 } 4475 4476 return cost; 4477} 4478 4479 4480/* Skip over irrelevant NOTEs and such and look for the next insn we 4481 would consider bundling. */ 4482static rtx_insn * 4483next_insn_to_bundle (rtx_insn *r, rtx_insn *end) 4484{ 4485 for (; r != end; r = NEXT_INSN (r)) 4486 { 4487 if (NONDEBUG_INSN_P (r) 4488 && GET_CODE (PATTERN (r)) != USE 4489 && GET_CODE (PATTERN (r)) != CLOBBER) 4490 return r; 4491 } 4492 4493 return NULL; 4494} 4495 4496 4497/* Go through all insns, and use the information generated during 4498 scheduling to generate SEQUENCEs to represent bundles of 4499 instructions issued simultaneously. */ 4500static void 4501tilegx_gen_bundles (void) 4502{ 4503 basic_block bb; 4504 FOR_EACH_BB_FN (bb, cfun) 4505 { 4506 rtx_insn *insn, *next, *prev; 4507 rtx_insn *end = NEXT_INSN (BB_END (bb)); 4508 4509 prev = NULL; 4510 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; 4511 prev = insn, insn = next) 4512 { 4513 next = next_insn_to_bundle (NEXT_INSN (insn), end); 4514 4515 /* Never wrap {} around inline asm. */ 4516 if (GET_CODE (PATTERN (insn)) != ASM_INPUT) 4517 { 4518 if (next == NULL_RTX || GET_MODE (next) == TImode 4519 /* NOTE: The scheduler incorrectly believes a call 4520 insn can execute in the same cycle as the insn 4521 after the call. This is of course impossible. 4522 Really we need to fix the scheduler somehow, so 4523 the code after the call gets scheduled 4524 optimally. */ 4525 || CALL_P (insn)) 4526 { 4527 /* Mark current insn as the end of a bundle. */ 4528 PUT_MODE (insn, QImode); 4529 } 4530 else 4531 { 4532 /* Mark it as part of a bundle. */ 4533 PUT_MODE (insn, SImode); 4534 } 4535 } 4536 4537 /* Delete barrier insns, because they can mess up the 4538 emitting of bundle braces. If it is end-of-bundle, then 4539 the previous insn must be marked end-of-bundle. */ 4540 if (get_attr_type (insn) == TYPE_NOTHING) { 4541 if (GET_MODE (insn) == QImode && prev != NULL 4542 && GET_MODE (prev) == SImode) 4543 { 4544 PUT_MODE (prev, QImode); 4545 } 4546 delete_insn (insn); 4547 } 4548 } 4549 } 4550} 4551 4552 4553/* Replace OLD_INSN with NEW_INSN. */ 4554static void 4555replace_insns (rtx_insn *old_insn, rtx_insn *new_insns) 4556{ 4557 if (new_insns) 4558 emit_insn_before (new_insns, old_insn); 4559 4560 delete_insn (old_insn); 4561} 4562 4563 4564/* Returns true if INSN is the first instruction of a pc-relative 4565 address compuatation. */ 4566static bool 4567match_pcrel_step1 (rtx insn) 4568{ 4569 rtx pattern = PATTERN (insn); 4570 rtx src; 4571 4572 if (GET_CODE (pattern) != SET) 4573 return false; 4574 4575 src = SET_SRC (pattern); 4576 4577 return (GET_CODE (src) == CONST 4578 && GET_CODE (XEXP (src, 0)) == UNSPEC 4579 && XINT (XEXP (src, 0), 1) == UNSPEC_HW1_LAST_PCREL); 4580} 4581 4582 4583/* Do the first replacement step in tilegx_fixup_pcrel_references. */ 4584static void 4585replace_mov_pcrel_step1 (rtx_insn *insn) 4586{ 4587 rtx pattern = PATTERN (insn); 4588 rtx unspec; 4589 rtx opnds[2]; 4590 rtx_insn *new_insns; 4591 4592 gcc_assert (GET_CODE (pattern) == SET); 4593 opnds[0] = SET_DEST (pattern); 4594 4595 gcc_assert (GET_CODE (SET_SRC (pattern)) == CONST); 4596 4597 unspec = XEXP (SET_SRC (pattern), 0); 4598 gcc_assert (GET_CODE (unspec) == UNSPEC); 4599 gcc_assert (XINT (unspec, 1) == UNSPEC_HW1_LAST_PCREL); 4600 opnds[1] = XVECEXP (unspec, 0, 0); 4601 4602 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4603 if (GET_CODE (opnds[1]) != SYMBOL_REF) 4604 return; 4605 4606 start_sequence (); 4607 4608 if (flag_pic != 1) 4609 { 4610 if (TARGET_32BIT) 4611 emit_insn (gen_mov_got32_step1_32bit (opnds[0], opnds[1])); 4612 else 4613 emit_insn (gen_mov_got32_step1 (opnds[0], opnds[1])); 4614 } 4615 4616 new_insns = get_insns (); 4617 end_sequence (); 4618 4619 replace_insns (insn, new_insns); 4620} 4621 4622 4623/* Returns true if INSN is the second instruction of a pc-relative 4624 address compuatation. */ 4625static bool 4626match_pcrel_step2 (rtx_insn *insn) 4627{ 4628 rtx unspec; 4629 rtx addr; 4630 4631 if (TARGET_32BIT) 4632 { 4633 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit) 4634 return false; 4635 } 4636 else 4637 { 4638 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli) 4639 return false; 4640 } 4641 4642 unspec = SET_SRC (PATTERN (insn)); 4643 addr = XVECEXP (unspec, 0, 1); 4644 4645 return (GET_CODE (addr) == CONST 4646 && GET_CODE (XEXP (addr, 0)) == UNSPEC 4647 && XINT (XEXP (addr, 0), 1) == UNSPEC_HW0_PCREL); 4648} 4649 4650 4651/* Do the second replacement step in tilegx_fixup_pcrel_references. */ 4652static void 4653replace_mov_pcrel_step2 (rtx_insn *insn) 4654{ 4655 rtx pattern = PATTERN (insn); 4656 rtx unspec; 4657 rtx addr; 4658 rtx opnds[3]; 4659 rtx_insn *new_insns; 4660 rtx got_rtx = tilegx_got_rtx (); 4661 4662 gcc_assert (GET_CODE (pattern) == SET); 4663 opnds[0] = SET_DEST (pattern); 4664 4665 unspec = SET_SRC (pattern); 4666 gcc_assert (GET_CODE (unspec) == UNSPEC); 4667 gcc_assert (XINT (unspec, 1) == UNSPEC_INSN_ADDR_SHL16INSLI); 4668 4669 opnds[1] = XVECEXP (unspec, 0, 0); 4670 4671 addr = XVECEXP (unspec, 0, 1); 4672 gcc_assert (GET_CODE (addr) == CONST); 4673 4674 unspec = XEXP (addr, 0); 4675 gcc_assert (GET_CODE (unspec) == UNSPEC); 4676 gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL); 4677 opnds[2] = XVECEXP (unspec, 0, 0); 4678 4679 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4680 if (GET_CODE (opnds[2]) != SYMBOL_REF) 4681 return; 4682 4683 start_sequence (); 4684 4685 if (flag_pic == 1) 4686 { 4687 if (TARGET_32BIT) 4688 emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2])); 4689 else 4690 emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2])); 4691 } 4692 else 4693 { 4694 if (TARGET_32BIT) 4695 emit_insn (gen_mov_got32_step2_32bit 4696 (opnds[0], opnds[1], opnds[2])); 4697 else 4698 emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2])); 4699 } 4700 4701 new_insns = get_insns (); 4702 end_sequence (); 4703 4704 replace_insns (insn, new_insns); 4705} 4706 4707 4708/* Do the third replacement step in tilegx_fixup_pcrel_references. */ 4709static void 4710replace_mov_pcrel_step3 (rtx_insn *insn) 4711{ 4712 rtx pattern = PATTERN (insn); 4713 rtx unspec; 4714 rtx opnds[4]; 4715 rtx_insn *new_insns; 4716 rtx got_rtx = tilegx_got_rtx (); 4717 rtx text_label_rtx = tilegx_text_label_rtx (); 4718 4719 gcc_assert (GET_CODE (pattern) == SET); 4720 opnds[0] = SET_DEST (pattern); 4721 4722 unspec = SET_SRC (pattern); 4723 gcc_assert (GET_CODE (unspec) == UNSPEC); 4724 gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3); 4725 4726 opnds[1] = got_rtx; 4727 4728 if (XVECEXP (unspec, 0, 0) == text_label_rtx) 4729 opnds[2] = XVECEXP (unspec, 0, 1); 4730 else 4731 { 4732 gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx); 4733 opnds[2] = XVECEXP (unspec, 0, 0); 4734 } 4735 4736 opnds[3] = XVECEXP (unspec, 0, 2); 4737 4738 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */ 4739 if (GET_CODE (opnds[3]) != SYMBOL_REF) 4740 return; 4741 4742 start_sequence (); 4743 4744 if (flag_pic == 1) 4745 { 4746 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2])); 4747 } 4748 else 4749 { 4750 emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2])); 4751 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0])); 4752 } 4753 4754 new_insns = get_insns (); 4755 end_sequence (); 4756 4757 replace_insns (insn, new_insns); 4758} 4759 4760 4761/* We generate PC relative SYMBOL_REFs as an optimization, to avoid 4762 going through the GOT when the symbol is local to the compilation 4763 unit. But such a symbol requires that the common text_label that 4764 we generate at the beginning of the function be in the same section 4765 as the reference to the SYMBOL_REF. This may not be true if we 4766 generate hot/cold sections. This function looks for such cases and 4767 replaces such references with the longer sequence going through the 4768 GOT. 4769 4770 We expect following instruction sequence: 4771 moveli tmp1, hw1_last(x-.L_PICLNK) [1] 4772 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2] 4773 add<x> tmp3, txt_label_reg, tmp2 [3] 4774 4775 If we're compiling -fpic, we replace with the following sequence 4776 (the numbers in brackets match the instructions they're replacing 4777 above). 4778 4779 add<x>li tmp2, got_reg, hw0_last_got(x) [2] 4780 ld<4> tmp3, tmp2 [3] 4781 4782 If we're compiling -fPIC, we replace the first instruction with: 4783 4784 moveli tmp1, hw1_last_got(x) [1] 4785 shl16insli tmp2, tmp1, hw0_got(x) [2] 4786 add<x> tmp3, got_reg, tmp2 [3] 4787 ld<4> tmp3, tmp3 [3] 4788 4789 Note that we're careful to disturb the instruction sequence as 4790 little as possible, since it's very late in the compilation 4791 process. */ 4792static void 4793tilegx_fixup_pcrel_references (void) 4794{ 4795 rtx_insn *insn, *next_insn; 4796 bool same_section_as_entry = true; 4797 4798 for (insn = get_insns (); insn; insn = next_insn) 4799 { 4800 next_insn = NEXT_INSN (insn); 4801 4802 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) 4803 { 4804 same_section_as_entry = !same_section_as_entry; 4805 continue; 4806 } 4807 4808 if (same_section_as_entry) 4809 continue; 4810 4811 if (!(INSN_P (insn) 4812 && GET_CODE (PATTERN (insn)) != USE 4813 && GET_CODE (PATTERN (insn)) != CLOBBER)) 4814 continue; 4815 4816 if (TARGET_32BIT) 4817 { 4818 if (match_pcrel_step1 (insn)) 4819 replace_mov_pcrel_step1 (insn); 4820 else if (match_pcrel_step2 (insn)) 4821 replace_mov_pcrel_step2 (insn); 4822 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit) 4823 replace_mov_pcrel_step3 (insn); 4824 } 4825 else 4826 { 4827 if (match_pcrel_step1 (insn)) 4828 replace_mov_pcrel_step1 (insn); 4829 else if (match_pcrel_step2 (insn)) 4830 replace_mov_pcrel_step2 (insn); 4831 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3) 4832 replace_mov_pcrel_step3 (insn); 4833 } 4834 } 4835} 4836 4837 4838/* Ensure that no var tracking notes are emitted in the middle of a 4839 three-instruction bundle. */ 4840static void 4841reorder_var_tracking_notes (void) 4842{ 4843 basic_block bb; 4844 FOR_EACH_BB_FN (bb, cfun) 4845 { 4846 rtx_insn *insn, *next; 4847 rtx_insn *queue = NULL; 4848 bool in_bundle = false; 4849 4850 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next) 4851 { 4852 next = NEXT_INSN (insn); 4853 4854 if (INSN_P (insn)) 4855 { 4856 /* Emit queued up notes at the last instruction of a 4857 bundle. */ 4858 if (GET_MODE (insn) == QImode) 4859 { 4860 while (queue) 4861 { 4862 rtx_insn *next_queue = PREV_INSN (queue); 4863 SET_PREV_INSN (NEXT_INSN (insn)) = queue; 4864 SET_NEXT_INSN (queue) = NEXT_INSN (insn); 4865 SET_NEXT_INSN (insn) = queue; 4866 SET_PREV_INSN (queue) = insn; 4867 queue = next_queue; 4868 } 4869 in_bundle = false; 4870 } 4871 else if (GET_MODE (insn) == SImode) 4872 in_bundle = true; 4873 } 4874 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION) 4875 { 4876 if (in_bundle) 4877 { 4878 rtx_insn *prev = PREV_INSN (insn); 4879 SET_PREV_INSN (next) = prev; 4880 SET_NEXT_INSN (prev) = next; 4881 4882 SET_PREV_INSN (insn) = queue; 4883 queue = insn; 4884 } 4885 } 4886 } 4887 } 4888} 4889 4890 4891/* Perform machine dependent operations on the rtl chain INSNS. */ 4892static void 4893tilegx_reorg (void) 4894{ 4895 /* We are freeing block_for_insn in the toplev to keep compatibility 4896 with old MDEP_REORGS that are not CFG based. Recompute it 4897 now. */ 4898 compute_bb_for_insn (); 4899 4900 if (flag_reorder_blocks_and_partition) 4901 { 4902 tilegx_fixup_pcrel_references (); 4903 } 4904 4905 if (flag_schedule_insns_after_reload) 4906 { 4907 split_all_insns (); 4908 4909 timevar_push (TV_SCHED2); 4910 schedule_insns (); 4911 timevar_pop (TV_SCHED2); 4912 4913 /* Examine the schedule to group into bundles. */ 4914 tilegx_gen_bundles (); 4915 } 4916 4917 df_analyze (); 4918 4919 if (flag_var_tracking) 4920 { 4921 timevar_push (TV_VAR_TRACKING); 4922 variable_tracking_main (); 4923 reorder_var_tracking_notes (); 4924 timevar_pop (TV_VAR_TRACKING); 4925 } 4926 4927 df_finish_pass (false); 4928} 4929 4930 4931 4932/* Assembly */ 4933 4934/* Select a format to encode pointers in exception handling data. 4935 CODE is 0 for data, 1 for code labels, 2 for function pointers. 4936 GLOBAL is true if the symbol may be affected by dynamic 4937 relocations. */ 4938int 4939tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global) 4940{ 4941 int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8; 4942 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type; 4943} 4944 4945 4946/* Implement TARGET_ASM_OUTPUT_MI_THUNK. */ 4947static void 4948tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 4949 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 4950 tree function) 4951{ 4952 rtx this_rtx, funexp, addend; 4953 rtx_insn *insn; 4954 4955 /* Pretend to be a post-reload pass while generating rtl. */ 4956 reload_completed = 1; 4957 4958 /* Mark the end of the (empty) prologue. */ 4959 emit_note (NOTE_INSN_PROLOGUE_END); 4960 4961 /* Find the "this" pointer. If the function returns a structure, 4962 the structure return pointer is in $1. */ 4963 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 4964 this_rtx = gen_rtx_REG (Pmode, 1); 4965 else 4966 this_rtx = gen_rtx_REG (Pmode, 0); 4967 4968 /* Add DELTA to THIS_RTX. */ 4969 if (!(delta >= -32868 && delta <= 32767)) 4970 { 4971 addend = gen_rtx_REG (Pmode, 29); 4972 emit_move_insn (addend, GEN_INT (delta)); 4973 } 4974 else 4975 addend = GEN_INT (delta); 4976 4977 if (TARGET_32BIT) 4978 emit_insn (gen_addsi3 (this_rtx, this_rtx, addend)); 4979 else 4980 emit_insn (gen_adddi3 (this_rtx, this_rtx, addend)); 4981 4982 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ 4983 if (vcall_offset) 4984 { 4985 rtx tmp; 4986 4987 tmp = gen_rtx_REG (Pmode, 29); 4988 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx)); 4989 4990 if (!(vcall_offset >= -32868 && vcall_offset <= 32767)) 4991 { 4992 addend = gen_rtx_REG (Pmode, 28); 4993 emit_move_insn (addend, GEN_INT (vcall_offset)); 4994 } 4995 else 4996 addend = GEN_INT (vcall_offset); 4997 4998 if (TARGET_32BIT) 4999 emit_insn (gen_addsi3 (tmp, tmp, addend)); 5000 else 5001 emit_insn (gen_adddi3 (tmp, tmp, addend)); 5002 5003 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp)); 5004 5005 if (TARGET_32BIT) 5006 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp)); 5007 else 5008 emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp)); 5009 } 5010 5011 /* Generate a tail call to the target function. */ 5012 if (!TREE_USED (function)) 5013 { 5014 assemble_external (function); 5015 TREE_USED (function) = 1; 5016 } 5017 funexp = XEXP (DECL_RTL (function), 0); 5018 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); 5019 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); 5020 SIBLING_CALL_P (insn) = 1; 5021 5022 /* Run just enough of rest_of_compilation to get the insns emitted. 5023 There's not really enough bulk here to make other passes such as 5024 instruction scheduling worth while. Note that use_thunk calls 5025 assemble_start_function and assemble_end_function. 5026 5027 We don't currently bundle, but the instruciton sequence is all 5028 serial except for the tail call, so we're only wasting one cycle. 5029 */ 5030 insn = get_insns (); 5031 shorten_branches (insn); 5032 final_start_function (insn, file, 1); 5033 final (insn, file, 1); 5034 final_end_function (); 5035 5036 /* Stop pretending to be a post-reload pass. */ 5037 reload_completed = 0; 5038} 5039 5040 5041/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 5042static void 5043tilegx_asm_trampoline_template (FILE *file) 5044{ 5045 int ptr_mode_size = GET_MODE_SIZE (ptr_mode); 5046 if (TARGET_32BIT) 5047 { 5048 fprintf (file, "\tlnk r10\n"); 5049 fprintf (file, "\taddxi r10, r10, 32\n"); 5050 fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size); 5051 fprintf (file, "\tld4s r10, r10\n"); 5052 fprintf (file, "\tjr r11\n"); 5053 fprintf (file, "\t.word 0 # <function address>\n"); 5054 fprintf (file, "\t.word 0 # <static chain value>\n"); 5055 } 5056 else 5057 { 5058 fprintf (file, "\tlnk r10\n"); 5059 fprintf (file, "\taddi r10, r10, 32\n"); 5060 fprintf (file, "\tld_add r11, r10, %d\n", ptr_mode_size); 5061 fprintf (file, "\tld r10, r10\n"); 5062 fprintf (file, "\tjr r11\n"); 5063 fprintf (file, "\t.quad 0 # <function address>\n"); 5064 fprintf (file, "\t.quad 0 # <static chain value>\n"); 5065 } 5066} 5067 5068 5069/* Implement TARGET_TRAMPOLINE_INIT. */ 5070static void 5071tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) 5072{ 5073 rtx fnaddr, chaddr; 5074 rtx mem; 5075 rtx begin_addr, end_addr; 5076 int ptr_mode_size = GET_MODE_SIZE (ptr_mode); 5077 5078 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0)); 5079 chaddr = copy_to_reg (static_chain); 5080 5081 emit_block_move (m_tramp, assemble_trampoline_template (), 5082 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); 5083 5084 mem = adjust_address (m_tramp, ptr_mode, 5085 TRAMPOLINE_SIZE - 2 * ptr_mode_size); 5086 emit_move_insn (mem, fnaddr); 5087 mem = adjust_address (m_tramp, ptr_mode, 5088 TRAMPOLINE_SIZE - ptr_mode_size); 5089 emit_move_insn (mem, chaddr); 5090 5091 /* Get pointers to the beginning and end of the code block. */ 5092 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0)); 5093 end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0), 5094 TRAMPOLINE_SIZE)); 5095 5096 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), 5097 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode, 5098 end_addr, Pmode); 5099} 5100 5101 5102/* Implement TARGET_PRINT_OPERAND. */ 5103static void 5104tilegx_print_operand (FILE *file, rtx x, int code) 5105{ 5106 switch (code) 5107 { 5108 case 'c': 5109 /* Print the compare operator opcode for conditional moves. */ 5110 switch (GET_CODE (x)) 5111 { 5112 case EQ: 5113 fputs ("z", file); 5114 break; 5115 case NE: 5116 fputs ("nz", file); 5117 break; 5118 default: 5119 output_operand_lossage ("invalid %%c operand"); 5120 } 5121 return; 5122 5123 case 'C': 5124 /* Print the compare operator opcode for conditional moves. */ 5125 switch (GET_CODE (x)) 5126 { 5127 case EQ: 5128 fputs ("nz", file); 5129 break; 5130 case NE: 5131 fputs ("z", file); 5132 break; 5133 default: 5134 output_operand_lossage ("invalid %%C operand"); 5135 } 5136 return; 5137 5138 case 'd': 5139 { 5140 /* Print the compare operator opcode for conditional moves. */ 5141 switch (GET_CODE (x)) 5142 { 5143 case EQ: 5144 fputs ("eq", file); 5145 break; 5146 case NE: 5147 fputs ("ne", file); 5148 break; 5149 default: 5150 output_operand_lossage ("invalid %%d operand"); 5151 } 5152 return; 5153 } 5154 5155 case 'D': 5156 { 5157 /* Print the compare operator opcode for conditional moves. */ 5158 switch (GET_CODE (x)) 5159 { 5160 case EQ: 5161 fputs ("ne", file); 5162 break; 5163 case NE: 5164 fputs ("eq", file); 5165 break; 5166 default: 5167 output_operand_lossage ("invalid %%D operand"); 5168 } 5169 return; 5170 } 5171 5172 case 'H': 5173 { 5174 if (GET_CODE (x) == CONST 5175 && GET_CODE (XEXP (x, 0)) == UNSPEC) 5176 { 5177 rtx addr = XVECEXP (XEXP (x, 0), 0, 0); 5178 int unspec = XINT (XEXP (x, 0), 1); 5179 const char *opstr = NULL; 5180 switch (unspec) 5181 { 5182 case UNSPEC_HW0: 5183 case UNSPEC_HW0_PCREL: 5184 opstr = "hw0"; 5185 break; 5186 case UNSPEC_HW1: 5187 case UNSPEC_HW1_PCREL: 5188 opstr = "hw1"; 5189 break; 5190 case UNSPEC_HW2: 5191 opstr = "hw2"; 5192 break; 5193 case UNSPEC_HW3: 5194 opstr = "hw3"; 5195 break; 5196 case UNSPEC_HW0_LAST: 5197 opstr = "hw0_last"; 5198 break; 5199 case UNSPEC_HW1_LAST: 5200 case UNSPEC_HW1_LAST_PCREL: 5201 opstr = "hw1_last"; 5202 break; 5203 case UNSPEC_HW2_LAST: 5204 case UNSPEC_HW2_LAST_PCREL: 5205 opstr = "hw2_last"; 5206 break; 5207 case UNSPEC_HW0_GOT: 5208 opstr = "hw0_got"; 5209 break; 5210 case UNSPEC_HW0_LAST_GOT: 5211 opstr = "hw0_last_got"; 5212 break; 5213 case UNSPEC_HW1_LAST_GOT: 5214 opstr = "hw1_last_got"; 5215 break; 5216 case UNSPEC_HW0_TLS_GD: 5217 opstr = "hw0_tls_gd"; 5218 break; 5219 case UNSPEC_HW1_LAST_TLS_GD: 5220 opstr = "hw1_last_tls_gd"; 5221 break; 5222 case UNSPEC_HW0_TLS_IE: 5223 opstr = "hw0_tls_ie"; 5224 break; 5225 case UNSPEC_HW1_LAST_TLS_IE: 5226 opstr = "hw1_last_tls_ie"; 5227 break; 5228 case UNSPEC_HW0_TLS_LE: 5229 opstr = "hw0_tls_le"; 5230 break; 5231 case UNSPEC_HW1_LAST_TLS_LE: 5232 opstr = "hw1_last_tls_le"; 5233 break; 5234 case UNSPEC_HW0_PLT_PCREL: 5235 opstr = "hw0_plt"; 5236 break; 5237 case UNSPEC_HW1_PLT_PCREL: 5238 opstr = "hw1_plt"; 5239 break; 5240 case UNSPEC_HW1_LAST_PLT_PCREL: 5241 opstr = "hw1_last_plt"; 5242 break; 5243 case UNSPEC_HW2_LAST_PLT_PCREL: 5244 opstr = "hw2_last_plt"; 5245 break; 5246 default: 5247 output_operand_lossage ("invalid %%H specifier"); 5248 } 5249 5250 fputs (opstr, file); 5251 fputc ('(', file); 5252 output_addr_const (file, addr); 5253 5254 if (unspec == UNSPEC_HW0_PCREL 5255 || unspec == UNSPEC_HW1_PCREL 5256 || unspec == UNSPEC_HW1_LAST_PCREL 5257 || unspec == UNSPEC_HW2_LAST_PCREL 5258 || unspec == UNSPEC_HW0_PLT_PCREL 5259 || unspec == UNSPEC_HW1_PLT_PCREL 5260 || unspec == UNSPEC_HW1_LAST_PLT_PCREL 5261 || unspec == UNSPEC_HW2_LAST_PLT_PCREL) 5262 { 5263 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1); 5264 fputs (" - " , file); 5265 output_addr_const (file, addr2); 5266 } 5267 5268 fputc (')', file); 5269 return; 5270 } 5271 else if (symbolic_operand (x, VOIDmode)) 5272 { 5273 output_addr_const (file, x); 5274 return; 5275 } 5276 } 5277 /* FALLTHRU */ 5278 5279 case 'h': 5280 { 5281 /* Print the low 16 bits of a constant. */ 5282 HOST_WIDE_INT i; 5283 if (CONST_INT_P (x)) 5284 i = INTVAL (x); 5285 else if (GET_CODE (x) == CONST_DOUBLE) 5286 i = CONST_DOUBLE_LOW (x); 5287 else 5288 { 5289 output_operand_lossage ("invalid %%h operand"); 5290 return; 5291 } 5292 i = trunc_int_for_mode (i, HImode); 5293 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 5294 return; 5295 } 5296 5297 case 'I': 5298 /* Print an auto-inc memory operand. */ 5299 if (!MEM_P (x)) 5300 { 5301 output_operand_lossage ("invalid %%I operand"); 5302 return; 5303 } 5304 5305 output_memory_reference_mode = GET_MODE (x); 5306 output_memory_autoinc_first = true; 5307 output_address (XEXP (x, 0)); 5308 output_memory_reference_mode = VOIDmode; 5309 return; 5310 5311 case 'i': 5312 /* Print an auto-inc memory operand. */ 5313 if (!MEM_P (x)) 5314 { 5315 output_operand_lossage ("invalid %%i operand"); 5316 return; 5317 } 5318 5319 output_memory_reference_mode = GET_MODE (x); 5320 output_memory_autoinc_first = false; 5321 output_address (XEXP (x, 0)); 5322 output_memory_reference_mode = VOIDmode; 5323 return; 5324 5325 case 'j': 5326 { 5327 /* Print the low 8 bits of a constant. */ 5328 HOST_WIDE_INT i; 5329 if (CONST_INT_P (x)) 5330 i = INTVAL (x); 5331 else if (GET_CODE (x) == CONST_DOUBLE) 5332 i = CONST_DOUBLE_LOW (x); 5333 else if (GET_CODE (x) == CONST_VECTOR 5334 && CONST_INT_P (CONST_VECTOR_ELT (x, 0))) 5335 i = INTVAL (CONST_VECTOR_ELT (x, 0)); 5336 else 5337 { 5338 output_operand_lossage ("invalid %%j operand"); 5339 return; 5340 } 5341 i = trunc_int_for_mode (i, QImode); 5342 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 5343 return; 5344 } 5345 5346 case 'P': 5347 { 5348 /* Print a constant plus one. */ 5349 if (!CONST_INT_P (x)) 5350 { 5351 output_operand_lossage ("invalid %%P operand"); 5352 return; 5353 } 5354 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1); 5355 return; 5356 } 5357 5358 case 'm': 5359 case 'M': 5360 { 5361 /* Print a bfextu-style bit range. */ 5362 int first_bit, last_bit; 5363 HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0; 5364 5365 if (!CONST_INT_P (x) 5366 || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip, 5367 &first_bit, &last_bit)) 5368 { 5369 output_operand_lossage ("invalid %%%c operand", code); 5370 return; 5371 } 5372 5373 fprintf (file, "%d, %d", first_bit, last_bit); 5374 return; 5375 } 5376 5377 case 'N': 5378 { 5379 const char *reg = NULL; 5380 5381 /* Print a network register. */ 5382 if (!CONST_INT_P (x)) 5383 { 5384 output_operand_lossage ("invalid %%N operand"); 5385 return; 5386 } 5387 5388 switch (INTVAL (x)) 5389 { 5390 case TILEGX_NETREG_IDN0: reg = "idn0"; break; 5391 case TILEGX_NETREG_IDN1: reg = "idn1"; break; 5392 case TILEGX_NETREG_UDN0: reg = "udn0"; break; 5393 case TILEGX_NETREG_UDN1: reg = "udn1"; break; 5394 case TILEGX_NETREG_UDN2: reg = "udn2"; break; 5395 case TILEGX_NETREG_UDN3: reg = "udn3"; break; 5396 default: 5397 gcc_unreachable (); 5398 } 5399 5400 fprintf (file, reg); 5401 return; 5402 } 5403 5404 case 'p': 5405 if (GET_CODE (x) == SYMBOL_REF) 5406 { 5407 if (flag_pic && !SYMBOL_REF_LOCAL_P (x)) 5408 fprintf (file, "plt("); 5409 output_addr_const (file, x); 5410 if (flag_pic && !SYMBOL_REF_LOCAL_P (x)) 5411 fprintf (file, ")"); 5412 } 5413 else 5414 output_addr_const (file, x); 5415 return; 5416 5417 case 'r': 5418 /* In this case we need a register. Use 'zero' if the operand 5419 is const0_rtx. */ 5420 if (x == const0_rtx 5421 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x)))) 5422 { 5423 fputs ("zero", file); 5424 return; 5425 } 5426 else if (!REG_P (x)) 5427 { 5428 output_operand_lossage ("invalid operand for 'r' specifier"); 5429 return; 5430 } 5431 /* FALLTHRU */ 5432 5433 case 0: 5434 if (REG_P (x)) 5435 { 5436 fprintf (file, "%s", reg_names[REGNO (x)]); 5437 return; 5438 } 5439 else if (MEM_P (x)) 5440 { 5441 output_memory_reference_mode = VOIDmode; 5442 output_address (XEXP (x, 0)); 5443 return; 5444 } 5445 else 5446 { 5447 output_addr_const (file, x); 5448 return; 5449 } 5450 } 5451 5452 debug_rtx (x); 5453 output_operand_lossage ("unable to print out operand yet; code == %d (%c)", 5454 code, code); 5455} 5456 5457 5458/* Implement TARGET_PRINT_OPERAND_ADDRESS. */ 5459static void 5460tilegx_print_operand_address (FILE *file, rtx addr) 5461{ 5462 if (GET_CODE (addr) == POST_DEC 5463 || GET_CODE (addr) == POST_INC) 5464 { 5465 int offset = GET_MODE_SIZE (output_memory_reference_mode); 5466 5467 gcc_assert (output_memory_reference_mode != VOIDmode); 5468 5469 if (output_memory_autoinc_first) 5470 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]); 5471 else 5472 fprintf (file, "%d", 5473 GET_CODE (addr) == POST_DEC ? -offset : offset); 5474 } 5475 else if (GET_CODE (addr) == POST_MODIFY) 5476 { 5477 gcc_assert (output_memory_reference_mode != VOIDmode); 5478 5479 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS); 5480 5481 if (output_memory_autoinc_first) 5482 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]); 5483 else 5484 fprintf (file, HOST_WIDE_INT_PRINT_DEC, 5485 INTVAL (XEXP (XEXP (addr, 1), 1))); 5486 } 5487 else 5488 tilegx_print_operand (file, addr, 'r'); 5489} 5490 5491 5492/* Machine mode of current insn, for determining curly brace 5493 placement. */ 5494static machine_mode insn_mode; 5495 5496 5497/* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */ 5498void 5499tilegx_final_prescan_insn (rtx_insn *insn) 5500{ 5501 /* Record this for tilegx_asm_output_opcode to examine. */ 5502 insn_mode = GET_MODE (insn); 5503} 5504 5505 5506/* While emitting asm, are we currently inside '{' for a bundle? */ 5507static bool tilegx_in_bundle = false; 5508 5509/* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as 5510 appropriate given the bundling information recorded by 5511 tilegx_gen_bundles. */ 5512const char * 5513tilegx_asm_output_opcode (FILE *stream, const char *code) 5514{ 5515 bool pseudo = !strcmp (code, "pseudo"); 5516 5517 if (!tilegx_in_bundle && insn_mode == SImode) 5518 { 5519 /* Start a new bundle. */ 5520 fprintf (stream, "{\n\t"); 5521 tilegx_in_bundle = true; 5522 } 5523 5524 if (tilegx_in_bundle && insn_mode == QImode) 5525 { 5526 /* Close an existing bundle. */ 5527 static char buf[100]; 5528 5529 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf)); 5530 5531 strcpy (buf, pseudo ? "" : code); 5532 strcat (buf, "\n\t}"); 5533 tilegx_in_bundle = false; 5534 5535 return buf; 5536 } 5537 else 5538 { 5539 return pseudo ? "" : code; 5540 } 5541} 5542 5543 5544/* Output assembler code to FILE to increment profiler label # LABELNO 5545 for profiling a function entry. */ 5546void 5547tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) 5548{ 5549 if (tilegx_in_bundle) 5550 { 5551 fprintf (file, "\t}\n"); 5552 } 5553 5554 if (flag_pic) 5555 { 5556 fprintf (file, 5557 "\t{\n" 5558 "\tmove\tr10, lr\n" 5559 "\tjal\tplt(%s)\n" 5560 "\t}\n", MCOUNT_NAME); 5561 } 5562 else 5563 { 5564 fprintf (file, 5565 "\t{\n" 5566 "\tmove\tr10, lr\n" 5567 "\tjal\t%s\n" 5568 "\t}\n", MCOUNT_NAME); 5569 } 5570 5571 tilegx_in_bundle = false; 5572} 5573 5574 5575/* Implement TARGET_ASM_FILE_END. */ 5576static void 5577tilegx_file_end (void) 5578{ 5579 if (NEED_INDICATE_EXEC_STACK) 5580 file_end_indicate_exec_stack (); 5581} 5582 5583 5584 5585#undef TARGET_HAVE_TLS 5586#define TARGET_HAVE_TLS HAVE_AS_TLS 5587 5588#undef TARGET_OPTION_OVERRIDE 5589#define TARGET_OPTION_OVERRIDE tilegx_option_override 5590 5591#undef TARGET_SCALAR_MODE_SUPPORTED_P 5592#define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p 5593 5594#undef TARGET_VECTOR_MODE_SUPPORTED_P 5595#define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p 5596 5597#undef TARGET_CANNOT_FORCE_CONST_MEM 5598#define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem 5599 5600#undef TARGET_FUNCTION_OK_FOR_SIBCALL 5601#define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall 5602 5603#undef TARGET_PASS_BY_REFERENCE 5604#define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference 5605 5606#undef TARGET_RETURN_IN_MSB 5607#define TARGET_RETURN_IN_MSB tilegx_return_in_msb 5608 5609#undef TARGET_RETURN_IN_MEMORY 5610#define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory 5611 5612#undef TARGET_MODE_REP_EXTENDED 5613#define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended 5614 5615#undef TARGET_FUNCTION_ARG_BOUNDARY 5616#define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary 5617 5618#undef TARGET_FUNCTION_ARG 5619#define TARGET_FUNCTION_ARG tilegx_function_arg 5620 5621#undef TARGET_FUNCTION_ARG_ADVANCE 5622#define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance 5623 5624#undef TARGET_FUNCTION_VALUE 5625#define TARGET_FUNCTION_VALUE tilegx_function_value 5626 5627#undef TARGET_LIBCALL_VALUE 5628#define TARGET_LIBCALL_VALUE tilegx_libcall_value 5629 5630#undef TARGET_FUNCTION_VALUE_REGNO_P 5631#define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p 5632 5633#undef TARGET_PROMOTE_FUNCTION_MODE 5634#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote 5635 5636#undef TARGET_PROMOTE_PROTOTYPES 5637#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false 5638 5639#undef TARGET_BUILD_BUILTIN_VA_LIST 5640#define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list 5641 5642#undef TARGET_EXPAND_BUILTIN_VA_START 5643#define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start 5644 5645#undef TARGET_SETUP_INCOMING_VARARGS 5646#define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs 5647 5648#undef TARGET_GIMPLIFY_VA_ARG_EXPR 5649#define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr 5650 5651#undef TARGET_RTX_COSTS 5652#define TARGET_RTX_COSTS tilegx_rtx_costs 5653 5654#undef TARGET_EXPAND_TO_RTL_HOOK 5655#define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook 5656 5657#undef TARGET_SHIFT_TRUNCATION_MASK 5658#define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask 5659 5660#undef TARGET_INIT_LIBFUNCS 5661#define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs 5662 5663/* Limit to what we can reach in one addli. */ 5664#undef TARGET_MIN_ANCHOR_OFFSET 5665#define TARGET_MIN_ANCHOR_OFFSET -32768 5666#undef TARGET_MAX_ANCHOR_OFFSET 5667#define TARGET_MAX_ANCHOR_OFFSET 32767 5668 5669#undef TARGET_LEGITIMATE_CONSTANT_P 5670#define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p 5671 5672#undef TARGET_LEGITIMATE_ADDRESS_P 5673#define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p 5674 5675#undef TARGET_LEGITIMIZE_ADDRESS 5676#define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address 5677 5678#undef TARGET_DELEGITIMIZE_ADDRESS 5679#define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address 5680 5681#undef TARGET_INIT_BUILTINS 5682#define TARGET_INIT_BUILTINS tilegx_init_builtins 5683 5684#undef TARGET_BUILTIN_DECL 5685#define TARGET_BUILTIN_DECL tilegx_builtin_decl 5686 5687#undef TARGET_EXPAND_BUILTIN 5688#define TARGET_EXPAND_BUILTIN tilegx_expand_builtin 5689 5690#undef TARGET_CONDITIONAL_REGISTER_USAGE 5691#define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage 5692 5693#undef TARGET_FRAME_POINTER_REQUIRED 5694#define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required 5695 5696#undef TARGET_DELAY_SCHED2 5697#define TARGET_DELAY_SCHED2 true 5698 5699#undef TARGET_DELAY_VARTRACK 5700#define TARGET_DELAY_VARTRACK true 5701 5702#undef TARGET_SCHED_ISSUE_RATE 5703#define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate 5704 5705#undef TARGET_SCHED_ADJUST_COST 5706#define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost 5707 5708#undef TARGET_MACHINE_DEPENDENT_REORG 5709#define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg 5710 5711#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 5712#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ 5713 hook_bool_const_tree_hwi_hwi_const_tree_true 5714 5715#undef TARGET_ASM_OUTPUT_MI_THUNK 5716#define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk 5717 5718#undef TARGET_ASM_TRAMPOLINE_TEMPLATE 5719#define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template 5720 5721#undef TARGET_TRAMPOLINE_INIT 5722#define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init 5723 5724#undef TARGET_PRINT_OPERAND 5725#define TARGET_PRINT_OPERAND tilegx_print_operand 5726 5727#undef TARGET_PRINT_OPERAND_ADDRESS 5728#define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address 5729 5730#undef TARGET_ASM_FILE_END 5731#define TARGET_ASM_FILE_END tilegx_file_end 5732 5733#undef TARGET_ASM_ALIGNED_DI_OP 5734#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" 5735 5736#undef TARGET_CAN_USE_DOLOOP_P 5737#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost 5738 5739struct gcc_target targetm = TARGET_INITIALIZER; 5740 5741#include "gt-tilegx.h" 5742