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