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