1/* Output routines for Sunplus S+CORE processor 2 Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc. 3 Contributed by Sunnorth. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published 9 by the Free Software Foundation; either version 3, or (at your 10 option) any later version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21#include "config.h" 22#include "system.h" 23#include "coretypes.h" 24#include "tm.h" 25#include "rtl.h" 26#include "regs.h" 27#include "hard-reg-set.h" 28#include "real.h" 29#include "insn-config.h" 30#include "conditions.h" 31#include "insn-attr.h" 32#include "recog.h" 33#include "toplev.h" 34#include "output.h" 35#include "tree.h" 36#include "function.h" 37#include "expr.h" 38#include "optabs.h" 39#include "flags.h" 40#include "reload.h" 41#include "tm_p.h" 42#include "ggc.h" 43#include "gstab.h" 44#include "hashtab.h" 45#include "debug.h" 46#include "target.h" 47#include "target-def.h" 48#include "integrate.h" 49#include "langhooks.h" 50#include "score7.h" 51#include "score3.h" 52#include "df.h" 53 54#undef TARGET_ASM_FILE_START 55#define TARGET_ASM_FILE_START score_asm_file_start 56 57#undef TARGET_ASM_FILE_END 58#define TARGET_ASM_FILE_END score_asm_file_end 59 60#undef TARGET_ASM_FUNCTION_PROLOGUE 61#define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue 62 63#undef TARGET_ASM_FUNCTION_EPILOGUE 64#define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue 65 66#undef TARGET_DEFAULT_TARGET_FLAGS 67#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT 68#undef TARGET_HANDLE_OPTION 69#define TARGET_HANDLE_OPTION score_handle_option 70 71#undef TARGET_LEGITIMIZE_ADDRESS 72#define TARGET_LEGITIMIZE_ADDRESS score_legitimize_address 73 74#undef TARGET_SCHED_ISSUE_RATE 75#define TARGET_SCHED_ISSUE_RATE score_issue_rate 76 77#undef TARGET_ASM_SELECT_RTX_SECTION 78#define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section 79 80#undef TARGET_IN_SMALL_DATA_P 81#define TARGET_IN_SMALL_DATA_P score_in_small_data_p 82 83#undef TARGET_FUNCTION_OK_FOR_SIBCALL 84#define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall 85 86#undef TARGET_STRICT_ARGUMENT_NAMING 87#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true 88 89#undef TARGET_ASM_OUTPUT_MI_THUNK 90#define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk 91 92#undef TARGET_PROMOTE_FUNCTION_MODE 93#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote 94 95#undef TARGET_PROMOTE_PROTOTYPES 96#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true 97 98#undef TARGET_MUST_PASS_IN_STACK 99#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size 100 101#undef TARGET_ARG_PARTIAL_BYTES 102#define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes 103 104#undef TARGET_PASS_BY_REFERENCE 105#define TARGET_PASS_BY_REFERENCE score_pass_by_reference 106 107#undef TARGET_RETURN_IN_MEMORY 108#define TARGET_RETURN_IN_MEMORY score_return_in_memory 109 110#undef TARGET_RTX_COSTS 111#define TARGET_RTX_COSTS score_rtx_costs 112 113#undef TARGET_ADDRESS_COST 114#define TARGET_ADDRESS_COST score_address_cost 115 116#undef TARGET_LEGITIMATE_ADDRESS_P 117#define TARGET_LEGITIMATE_ADDRESS_P score_legitimate_address_p 118 119#undef TARGET_CAN_ELIMINATE 120#define TARGET_CAN_ELIMINATE score_can_eliminate 121 122#undef TARGET_ASM_TRAMPOLINE_TEMPLATE 123#define TARGET_ASM_TRAMPOLINE_TEMPLATE score_asm_trampoline_template 124#undef TARGET_TRAMPOLINE_INIT 125#define TARGET_TRAMPOLINE_INIT score_trampoline_init 126 127struct extern_list *extern_head = 0; 128 129/* default 0 = NO_REGS */ 130enum reg_class score_char_to_class[256]; 131 132/* Implement TARGET_RETURN_IN_MEMORY. In S+core, 133 small structures are returned in a register. 134 Objects with varying size must still be returned in memory. */ 135static bool 136score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED) 137{ 138 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 139 return score7_return_in_memory (type, fndecl); 140 else if (TARGET_SCORE3) 141 return score3_return_in_memory (type, fndecl); 142 143 gcc_unreachable (); 144} 145 146/* Return nonzero when an argument must be passed by reference. */ 147static bool 148score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, 149 enum machine_mode mode, tree type, 150 bool named ATTRIBUTE_UNUSED) 151{ 152 /* If we have a variable-sized parameter, we have no choice. */ 153 return targetm.calls.must_pass_in_stack (mode, type); 154} 155 156/* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text 157 in order to avoid duplicating too much logic from elsewhere. */ 158static void 159score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 160 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 161 tree function) 162{ 163 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 164 return score7_output_mi_thunk (file, thunk_fndecl, delta, 165 vcall_offset, function); 166 else if (TARGET_SCORE3) 167 return score3_output_mi_thunk (file, thunk_fndecl, delta, 168 vcall_offset, function); 169 gcc_unreachable (); 170} 171 172/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ 173static bool 174score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl, 175 ATTRIBUTE_UNUSED tree exp) 176{ 177 return true; 178} 179 180/* Set up the stack and frame (if desired) for the function. */ 181static void 182score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) 183{ 184 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 185 return score7_function_prologue (file, size); 186 else if (TARGET_SCORE3) 187 return score3_function_prologue (file, size); 188 189 gcc_unreachable (); 190} 191 192/* Do any necessary cleanup after a function to restore stack, frame, 193 and regs. */ 194static void 195score_function_epilogue (FILE *file, 196 HOST_WIDE_INT size ATTRIBUTE_UNUSED) 197{ 198 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 199 return score7_function_epilogue (file, size); 200 else if (TARGET_SCORE3) 201 return score3_function_epilogue (file, size); 202 203 gcc_unreachable (); 204} 205 206/* Implement TARGET_SCHED_ISSUE_RATE. */ 207static int 208score_issue_rate (void) 209{ 210 return 1; 211} 212 213/* Choose the section to use for the constant rtx expression X that has 214 mode MODE. */ 215static section * 216score_select_rtx_section (enum machine_mode mode, rtx x, 217 unsigned HOST_WIDE_INT align) 218{ 219 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 220 return score7_select_rtx_section (mode, x, align); 221 else if (TARGET_SCORE3) 222 return score3_select_rtx_section (mode, x, align); 223 224 gcc_unreachable (); 225} 226 227/* Implement TARGET_IN_SMALL_DATA_P. */ 228static bool 229score_in_small_data_p (tree decl) 230{ 231 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 232 return score7_in_small_data_p (decl); 233 else if (TARGET_SCORE3) 234 return score3_in_small_data_p (decl); 235 236 gcc_unreachable (); 237} 238 239/* Implement TARGET_ASM_FILE_START. */ 240static void 241score_asm_file_start (void) 242{ 243 if (TARGET_SCORE5) 244 fprintf (asm_out_file, "# Sunplus S+core5 %s rev=%s\n", 245 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 246 else if (TARGET_SCORE5U) 247 fprintf (asm_out_file, "# Sunplus S+core5u %s rev=%s\n", 248 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 249 else if (TARGET_SCORE7D) 250 fprintf (asm_out_file, "# Sunplus S+core7d %s rev=%s\n", 251 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 252 else if (TARGET_SCORE7) 253 fprintf (asm_out_file, "# Sunplus S+core7 %s rev=%s\n", 254 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 255 else if (TARGET_SCORE3D) 256 fprintf (asm_out_file, "# Sunplus S+core3d %s rev=%s\n", 257 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 258 else if (TARGET_SCORE3) 259 fprintf (asm_out_file, "# Sunplus S+core3 %s rev=%s\n", 260 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 261 else 262 fprintf (asm_out_file, "# Sunplus S+core unknown %s rev=%s\n", 263 TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); 264 265 default_file_start (); 266 267 if (flag_pic) 268 fprintf (asm_out_file, "\t.set pic\n"); 269} 270 271/* Implement TARGET_ASM_FILE_END. When using assembler macros, emit 272 .externs for any small-data variables that turned out to be external. */ 273static void 274score_asm_file_end (void) 275{ 276 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 277 return score7_asm_file_end (); 278 else if (TARGET_SCORE3) 279 return score3_asm_file_end (); 280 281 gcc_unreachable (); 282} 283 284#define MASK_ALL_CPU_BITS \ 285 (MASK_SCORE5 | MASK_SCORE5U | MASK_SCORE7 | MASK_SCORE7D \ 286 | MASK_SCORE3 | MASK_SCORE3D) 287 288/* Implement TARGET_HANDLE_OPTION. */ 289static bool 290score_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) 291{ 292 switch (code) 293 { 294 case OPT_mscore7d: 295 target_flags &= ~(MASK_ALL_CPU_BITS); 296 target_flags |= MASK_SCORE7 | MASK_SCORE7D; 297 return true; 298 299 case OPT_mscore3d: 300 target_flags &= ~(MASK_ALL_CPU_BITS); 301 target_flags |= MASK_SCORE3 | MASK_SCORE3D; 302 return true; 303 304 case OPT_march_: 305 if (strcmp (arg, "score5") == 0) 306 { 307 target_flags &= ~(MASK_ALL_CPU_BITS); 308 target_flags |= MASK_SCORE5; 309 return true; 310 } 311 else if (strcmp (arg, "score5u") == 0) 312 { 313 target_flags &= ~(MASK_ALL_CPU_BITS); 314 target_flags |= MASK_SCORE5U; 315 return true; 316 } 317 else if (strcmp (arg, "score7") == 0) 318 { 319 target_flags &= ~(MASK_ALL_CPU_BITS); 320 target_flags |= MASK_SCORE7; 321 return true; 322 } 323 else if (strcmp (arg, "score7d") == 0) 324 { 325 target_flags &= ~(MASK_ALL_CPU_BITS); 326 target_flags |= MASK_SCORE7 | MASK_SCORE7D; 327 return true; 328 } 329 else if (strcmp (arg, "score3") == 0) 330 { 331 target_flags &= ~(MASK_ALL_CPU_BITS); 332 target_flags |= MASK_SCORE3; 333 return true; 334 } 335 else if (strcmp (arg, "score3d") == 0) 336 { 337 target_flags &= ~(MASK_ALL_CPU_BITS); 338 target_flags |= MASK_SCORE3 | MASK_SCORE3D; 339 return true; 340 } 341 else 342 return false; 343 344 default: 345 return true; 346 } 347} 348 349/* Implement OVERRIDE_OPTIONS macro. */ 350void 351score_override_options (void) 352{ 353 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 354 return score7_override_options (); 355 else if (TARGET_SCORE3) 356 return score3_override_options (); 357 358 return score7_override_options (); 359} 360 361/* Implement REGNO_REG_CLASS macro. */ 362int 363score_reg_class (int regno) 364{ 365 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 366 return score7_reg_class (regno); 367 else if (TARGET_SCORE3) 368 return score3_reg_class (regno); 369 370 gcc_unreachable (); 371} 372 373/* Implement PREFERRED_RELOAD_CLASS macro. */ 374enum reg_class 375score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass) 376{ 377 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 378 return score7_preferred_reload_class (x, rclass); 379 else if (TARGET_SCORE3) 380 return score3_preferred_reload_class (x, rclass); 381 382 gcc_unreachable (); 383} 384 385/* Implement SECONDARY_INPUT_RELOAD_CLASS 386 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */ 387enum reg_class 388score_secondary_reload_class (enum reg_class rclass, 389 enum machine_mode mode ATTRIBUTE_UNUSED, 390 rtx x) 391{ 392 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 393 return score7_secondary_reload_class (rclass, mode, x); 394 else if (TARGET_SCORE3) 395 return score3_secondary_reload_class (rclass, mode, x); 396 397 gcc_unreachable (); 398} 399 400/* Implement CONST_OK_FOR_LETTER_P macro. */ 401int 402score_const_ok_for_letter_p (HOST_WIDE_INT value, char c) 403{ 404 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 405 return score7_const_ok_for_letter_p (value, c); 406 else if (TARGET_SCORE3) 407 return score3_const_ok_for_letter_p (value, c); 408 409 gcc_unreachable (); 410} 411 412/* Implement EXTRA_CONSTRAINT macro. */ 413int 414score_extra_constraint (rtx op, char c) 415{ 416 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 417 return score7_extra_constraint (op, c); 418 else if (TARGET_SCORE3) 419 return score3_extra_constraint (op, c); 420 421 gcc_unreachable (); 422} 423 424/* Return truth value on whether or not a given hard register 425 can support a given mode. */ 426int 427score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) 428{ 429 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 430 return score7_hard_regno_mode_ok (regno, mode); 431 else if (TARGET_SCORE3) 432 return score3_hard_regno_mode_ok (regno, mode); 433 434 gcc_unreachable (); 435} 436 437/* We can always eliminate to the hard frame pointer. We can eliminate 438 to the stack pointer unless a frame pointer is needed. */ 439 440static bool 441score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) 442{ 443 return (to == HARD_FRAME_POINTER_REGNUM 444 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed)); 445} 446 447/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame 448 pointer or argument pointer. TO is either the stack pointer or 449 hard frame pointer. */ 450HOST_WIDE_INT 451score_initial_elimination_offset (int from, 452 int to ATTRIBUTE_UNUSED) 453{ 454 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 455 return score7_initial_elimination_offset (from, to); 456 else if (TARGET_SCORE3) 457 return score3_initial_elimination_offset (from, to); 458 459 gcc_unreachable (); 460} 461 462/* Argument support functions. */ 463 464/* Initialize CUMULATIVE_ARGS for a function. */ 465void 466score_init_cumulative_args (CUMULATIVE_ARGS *cum, 467 tree fntype ATTRIBUTE_UNUSED, 468 rtx libname ATTRIBUTE_UNUSED) 469{ 470 memset (cum, 0, sizeof (CUMULATIVE_ARGS)); 471} 472 473/* Implement FUNCTION_ARG_ADVANCE macro. */ 474void 475score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, 476 tree type, int named) 477{ 478 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 479 return score7_function_arg_advance (cum, mode, type, named); 480 else if (TARGET_SCORE3) 481 return score3_function_arg_advance (cum, mode, type, named); 482 483 gcc_unreachable (); 484} 485 486/* Implement TARGET_ARG_PARTIAL_BYTES macro. */ 487int 488score_arg_partial_bytes (CUMULATIVE_ARGS *cum, 489 enum machine_mode mode, tree type, bool named) 490{ 491 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 492 return score7_arg_partial_bytes (cum, mode, type, named); 493 else if (TARGET_SCORE3) 494 return score3_arg_partial_bytes (cum, mode, type, named); 495 496 gcc_unreachable (); 497} 498 499/* Implement FUNCTION_ARG macro. */ 500rtx 501score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, 502 tree type, int named) 503{ 504 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 505 return score7_function_arg (cum, mode, type, named); 506 else if (TARGET_SCORE3) 507 return score3_function_arg (cum, mode, type, named); 508 509 gcc_unreachable (); 510} 511 512/* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls, 513 VALTYPE is the return type and MODE is VOIDmode. For libcalls, 514 VALTYPE is null and MODE is the mode of the return value. */ 515rtx 516score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED, 517 enum machine_mode mode) 518{ 519 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 520 return score7_function_value (valtype, func, mode); 521 else if (TARGET_SCORE3) 522 return score3_function_value (valtype, func, mode); 523 524 gcc_unreachable (); 525} 526 527/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 528static void 529score_asm_trampoline_template (FILE *f) 530{ 531 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 532 return score7_asm_trampoline_template (f); 533 else if (TARGET_SCORE3) 534 return score3_asm_trampoline_template (f); 535 536 gcc_unreachable (); 537} 538 539/* Implement TARGET_TRAMPOLINE_INIT. */ 540static void 541score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) 542{ 543 /* ??? These two routines are identical. */ 544 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 545 return score7_trampoline_init (m_tramp, fndecl, chain_value); 546 else if (TARGET_SCORE3) 547 return score3_trampoline_init (m_tramp, fndecl, chain_value); 548 549 gcc_unreachable (); 550} 551 552/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */ 553int 554score_regno_mode_ok_for_base_p (int regno, int strict) 555{ 556 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 557 return score7_regno_mode_ok_for_base_p (regno, strict); 558 else if (TARGET_SCORE3) 559 return score3_regno_mode_ok_for_base_p (regno, strict); 560 561 gcc_unreachable (); 562} 563 564/* Implement TARGET_LEGITIMIZE_ADDRESS_P. */ 565bool 566score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) 567{ 568 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 569 return score7_legitimate_address_p (mode, x, strict); 570 else if (TARGET_SCORE3) 571 return score3_legitimate_address_p (mode, x, strict); 572 573 gcc_unreachable (); 574} 575 576/* This function is used to implement LEGITIMIZE_ADDRESS. If X can 577 be legitimized in a way that the generic machinery might not expect, 578 return the new address, else return X. */ 579static rtx 580score_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 581 enum machine_mode mode ATTRIBUTE_UNUSED) 582{ 583 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 584 return score7_legitimize_address (x); 585 else if (TARGET_SCORE3) 586 return score3_legitimize_address (x); 587 588 gcc_unreachable (); 589} 590 591/* Return a number assessing the cost of moving a register in class 592 FROM to class TO. */ 593int 594score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, 595 enum reg_class from, enum reg_class to) 596{ 597 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 598 return score7_register_move_cost (mode, from, to); 599 else if (TARGET_SCORE3) 600 return score3_register_move_cost (mode, from, to); 601 602 gcc_unreachable (); 603} 604 605/* Implement TARGET_RTX_COSTS macro. */ 606bool 607score_rtx_costs (rtx x, int code, int outer_code, int *total, 608 bool speed ATTRIBUTE_UNUSED) 609{ 610 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 611 return score7_rtx_costs (x, code, outer_code, total, speed); 612 else if (TARGET_SCORE3) 613 return score3_rtx_costs (x, code, outer_code, total, speed); 614 615 gcc_unreachable (); 616} 617 618/* Implement TARGET_ADDRESS_COST macro. */ 619int 620score_address_cost (rtx addr, 621 bool speed ATTRIBUTE_UNUSED) 622{ 623 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 624 return score7_address_cost (addr); 625 else if (TARGET_SCORE3) 626 return score3_address_cost (addr); 627 628 gcc_unreachable (); 629} 630 631/* Implement ASM_OUTPUT_EXTERNAL macro. */ 632int 633score_output_external (FILE *file ATTRIBUTE_UNUSED, 634 tree decl, const char *name) 635{ 636 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 637 return score7_output_external (file, decl, name); 638 else if (TARGET_SCORE3) 639 return score3_output_external (file, decl, name); 640 641 gcc_unreachable (); 642} 643 644/* Implement RETURN_ADDR_RTX. Note, we do not support moving 645 back to a previous frame. */ 646rtx 647score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 648{ 649 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 650 return score7_return_addr (count, frame); 651 else if (TARGET_SCORE3) 652 return score3_return_addr (count, frame); 653 654 gcc_unreachable (); 655} 656 657/* Implement PRINT_OPERAND macro. */ 658void 659score_print_operand (FILE *file, rtx op, int c) 660{ 661 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 662 return score7_print_operand (file, op, c); 663 else if (TARGET_SCORE3) 664 return score3_print_operand (file, op, c); 665 666 gcc_unreachable (); 667} 668 669/* Implement PRINT_OPERAND_ADDRESS macro. */ 670void 671score_print_operand_address (FILE *file, rtx x) 672{ 673 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 674 return score7_print_operand_address (file, x); 675 else if (TARGET_SCORE3) 676 return score3_print_operand_address (file, x); 677 678 gcc_unreachable (); 679} 680 681/* Implement SELECT_CC_MODE macro. */ 682enum machine_mode 683score_select_cc_mode (enum rtx_code op, rtx x, rtx y) 684{ 685 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 686 return score7_select_cc_mode (op, x, y); 687 else if (TARGET_SCORE3) 688 return score3_select_cc_mode (op, x, y); 689 690 gcc_unreachable (); 691} 692 693/* Return true if X is a symbolic constant that can be calculated in 694 the same way as a bare symbol. If it is, store the type of the 695 symbol in *SYMBOL_TYPE. */ 696int 697score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) 698{ 699 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 700 return score7_symbolic_constant_p (x, symbol_type); 701 else if (TARGET_SCORE3) 702 return score3_symbolic_constant_p (x, symbol_type); 703 704 gcc_unreachable (); 705} 706 707/* Generate the prologue instructions for entry into a S+core function. */ 708void 709score_prologue (void) 710{ 711 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 712 return score7_prologue (); 713 else if (TARGET_SCORE3) 714 return score3_prologue (); 715 716 gcc_unreachable (); 717} 718 719/* Generate the epilogue instructions in a S+core function. */ 720void 721score_epilogue (int sibcall_p) 722{ 723 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 724 return score7_epilogue (sibcall_p); 725 else if (TARGET_SCORE3) 726 return score3_epilogue (sibcall_p); 727 728 gcc_unreachable (); 729} 730 731/* Call and sibcall pattern all need call this function. */ 732void 733score_call (rtx *ops, bool sib) 734{ 735 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 736 return score7_call (ops, sib); 737 else if (TARGET_SCORE3) 738 return score3_call (ops, sib); 739 740 gcc_unreachable (); 741} 742 743/* Call value and sibcall value pattern all need call this function. */ 744void 745score_call_value (rtx *ops, bool sib) 746{ 747 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 748 return score7_call_value (ops, sib); 749 else if (TARGET_SCORE3) 750 return score3_call_value (ops, sib); 751 752 gcc_unreachable (); 753} 754 755void 756score_movsicc (rtx *ops) 757{ 758 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 759 return score7_movsicc (ops); 760 else if (TARGET_SCORE3) 761 return score3_movsicc (ops); 762 763 gcc_unreachable (); 764} 765 766/* Machine Split */ 767void 768score_movdi (rtx *ops) 769{ 770 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 771 return score7_movdi (ops); 772 else if (TARGET_SCORE3) 773 return score3_movdi (ops); 774 775 gcc_unreachable (); 776} 777 778void 779score_zero_extract_andi (rtx *ops) 780{ 781 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 782 return score7_zero_extract_andi (ops); 783 else if (TARGET_SCORE3) 784 return score3_zero_extract_andi (ops); 785 786 gcc_unreachable (); 787} 788 789/* Output asm insn for move. */ 790const char * 791score_move (rtx *ops) 792{ 793 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 794 return score7_move (ops); 795 else if (TARGET_SCORE3) 796 return score3_move (ops); 797 798 gcc_unreachable (); 799} 800 801/* Output asm insn for load. */ 802const char * 803score_linsn (rtx *ops, enum score_mem_unit unit, bool sign) 804{ 805 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 806 return score7_linsn (ops, unit, sign); 807 else if (TARGET_SCORE3) 808 return score3_linsn (ops, unit, sign); 809 810 gcc_unreachable (); 811} 812 813/* Output asm insn for store. */ 814const char * 815score_sinsn (rtx *ops, enum score_mem_unit unit) 816{ 817 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 818 return score7_sinsn (ops, unit); 819 else if (TARGET_SCORE3) 820 return score3_sinsn (ops, unit); 821 822 gcc_unreachable (); 823} 824 825/* Output asm insn for load immediate. */ 826const char * 827score_limm (rtx *ops) 828{ 829 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 830 return score7_limm (ops); 831 else if (TARGET_SCORE3) 832 return score3_limm (ops); 833 834 gcc_unreachable (); 835} 836 837 838/* Generate add insn. */ 839const char * 840score_select_add_imm (rtx *ops, bool set_cc) 841{ 842 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 843 return score7_select_add_imm (ops, set_cc); 844 else if (TARGET_SCORE3) 845 return score3_select_add_imm (ops, set_cc); 846 847 gcc_unreachable (); 848} 849 850/* Output arith insn. */ 851const char * 852score_select (rtx *ops, const char *inst_pre, 853 bool commu, const char *letter, bool set_cc) 854{ 855 if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) 856 return score7_select (ops, inst_pre, commu, letter, set_cc); 857 else if (TARGET_SCORE3) 858 return score3_select (ops, inst_pre, commu, letter, set_cc); 859 860 gcc_unreachable (); 861} 862 863/* Output switch case insn, only supported in score3. */ 864const char * 865score_output_casesi (rtx *operands) 866{ 867 if (TARGET_SCORE3) 868 return score3_output_casesi (operands); 869 870 gcc_unreachable (); 871} 872 873/* Output rpush insn, only supported in score3. */ 874const char * 875score_rpush (rtx *operands) 876{ 877 if (TARGET_SCORE3) 878 return score3_rpush (operands); 879 880 gcc_unreachable (); 881} 882 883/* Output rpop insn, only supported in score3. */ 884const char * 885score_rpop (rtx *operands) 886{ 887 if (TARGET_SCORE3) 888 return score3_rpop (operands); 889 890 gcc_unreachable (); 891} 892 893/* Emit lcb/lce insns. */ 894bool 895score_unaligned_load (rtx *ops) 896{ 897 rtx dst = ops[0]; 898 rtx src = ops[1]; 899 rtx len = ops[2]; 900 rtx off = ops[3]; 901 rtx addr_reg; 902 903 if (INTVAL (len) != BITS_PER_WORD 904 || (INTVAL (off) % BITS_PER_UNIT) != 0) 905 return false; 906 907 gcc_assert (GET_MODE_SIZE (GET_MODE (dst)) == GET_MODE_SIZE (SImode)); 908 909 addr_reg = copy_addr_to_reg (XEXP (src, 0)); 910 emit_insn (gen_move_lcb (addr_reg, addr_reg)); 911 emit_insn (gen_move_lce (addr_reg, addr_reg, dst)); 912 913 return true; 914} 915 916/* Emit scb/sce insns. */ 917bool 918score_unaligned_store (rtx *ops) 919{ 920 rtx dst = ops[0]; 921 rtx len = ops[1]; 922 rtx off = ops[2]; 923 rtx src = ops[3]; 924 rtx addr_reg; 925 926 if (INTVAL(len) != BITS_PER_WORD 927 || (INTVAL(off) % BITS_PER_UNIT) != 0) 928 return false; 929 930 gcc_assert (GET_MODE_SIZE (GET_MODE (src)) == GET_MODE_SIZE (SImode)); 931 932 addr_reg = copy_addr_to_reg (XEXP (dst, 0)); 933 emit_insn (gen_move_scb (addr_reg, addr_reg, src)); 934 emit_insn (gen_move_sce (addr_reg, addr_reg)); 935 936 return true; 937} 938 939/* If length is short, generate move insns straight. */ 940static void 941score_block_move_straight (rtx dst, rtx src, HOST_WIDE_INT length) 942{ 943 HOST_WIDE_INT leftover; 944 int i, reg_count; 945 rtx *regs; 946 947 leftover = length % UNITS_PER_WORD; 948 length -= leftover; 949 reg_count = length / UNITS_PER_WORD; 950 951 regs = XALLOCAVEC (rtx, reg_count); 952 for (i = 0; i < reg_count; i++) 953 regs[i] = gen_reg_rtx (SImode); 954 955 /* Load from src to regs. */ 956 if (MEM_ALIGN (src) >= BITS_PER_WORD) 957 { 958 HOST_WIDE_INT offset = 0; 959 for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++) 960 emit_move_insn (regs[i], adjust_address (src, SImode, offset)); 961 } 962 else if (reg_count >= 1) 963 { 964 rtx src_reg = copy_addr_to_reg (XEXP (src, 0)); 965 966 emit_insn (gen_move_lcb (src_reg, src_reg)); 967 for (i = 0; i < (reg_count - 1); i++) 968 emit_insn (gen_move_lcw (src_reg, src_reg, regs[i])); 969 emit_insn (gen_move_lce (src_reg, src_reg, regs[i])); 970 } 971 972 /* Store regs to dest. */ 973 if (MEM_ALIGN (dst) >= BITS_PER_WORD) 974 { 975 HOST_WIDE_INT offset = 0; 976 for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++) 977 emit_move_insn (adjust_address (dst, SImode, offset), regs[i]); 978 } 979 else if (reg_count >= 1) 980 { 981 rtx dst_reg = copy_addr_to_reg (XEXP (dst, 0)); 982 983 emit_insn (gen_move_scb (dst_reg, dst_reg, regs[0])); 984 for (i = 1; i < reg_count; i++) 985 emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i])); 986 emit_insn (gen_move_sce (dst_reg, dst_reg)); 987 } 988 989 /* Mop up any left-over bytes. */ 990 if (leftover > 0) 991 { 992 src = adjust_address (src, BLKmode, length); 993 dst = adjust_address (dst, BLKmode, length); 994 move_by_pieces (dst, src, leftover, 995 MIN (MEM_ALIGN (src), MEM_ALIGN (dst)), 0); 996 } 997} 998 999/* Generate loop head when dst or src is unaligned. */ 1000static void 1001score_block_move_loop_head (rtx dst_reg, HOST_WIDE_INT dst_align, 1002 rtx src_reg, HOST_WIDE_INT src_align, 1003 HOST_WIDE_INT length) 1004{ 1005 bool src_unaligned = (src_align < BITS_PER_WORD); 1006 bool dst_unaligned = (dst_align < BITS_PER_WORD); 1007 1008 rtx temp = gen_reg_rtx (SImode); 1009 1010 gcc_assert (length == UNITS_PER_WORD); 1011 1012 if (src_unaligned) 1013 { 1014 emit_insn (gen_move_lcb (src_reg, src_reg)); 1015 emit_insn (gen_move_lcw (src_reg, src_reg, temp)); 1016 } 1017 else 1018 emit_insn (gen_move_lw_a (src_reg, 1019 src_reg, gen_int_mode (4, SImode), temp)); 1020 1021 if (dst_unaligned) 1022 emit_insn (gen_move_scb (dst_reg, dst_reg, temp)); 1023 else 1024 emit_insn (gen_move_sw_a (dst_reg, 1025 dst_reg, gen_int_mode (4, SImode), temp)); 1026} 1027 1028/* Generate loop body, copy length bytes per iteration. */ 1029static void 1030score_block_move_loop_body (rtx dst_reg, HOST_WIDE_INT dst_align, 1031 rtx src_reg, HOST_WIDE_INT src_align, 1032 HOST_WIDE_INT length) 1033{ 1034 int reg_count = length / UNITS_PER_WORD; 1035 rtx *regs = XALLOCAVEC (rtx, reg_count); 1036 int i; 1037 bool src_unaligned = (src_align < BITS_PER_WORD); 1038 bool dst_unaligned = (dst_align < BITS_PER_WORD); 1039 1040 for (i = 0; i < reg_count; i++) 1041 regs[i] = gen_reg_rtx (SImode); 1042 1043 if (src_unaligned) 1044 { 1045 for (i = 0; i < reg_count; i++) 1046 emit_insn (gen_move_lcw (src_reg, src_reg, regs[i])); 1047 } 1048 else 1049 { 1050 for (i = 0; i < reg_count; i++) 1051 emit_insn (gen_move_lw_a (src_reg, 1052 src_reg, gen_int_mode (4, SImode), regs[i])); 1053 } 1054 1055 if (dst_unaligned) 1056 { 1057 for (i = 0; i < reg_count; i++) 1058 emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i])); 1059 } 1060 else 1061 { 1062 for (i = 0; i < reg_count; i++) 1063 emit_insn (gen_move_sw_a (dst_reg, 1064 dst_reg, gen_int_mode (4, SImode), regs[i])); 1065 } 1066} 1067 1068/* Generate loop foot, copy the leftover bytes. */ 1069static void 1070score_block_move_loop_foot (rtx dst_reg, HOST_WIDE_INT dst_align, 1071 rtx src_reg, HOST_WIDE_INT src_align, 1072 HOST_WIDE_INT length) 1073{ 1074 bool src_unaligned = (src_align < BITS_PER_WORD); 1075 bool dst_unaligned = (dst_align < BITS_PER_WORD); 1076 1077 HOST_WIDE_INT leftover; 1078 1079 leftover = length % UNITS_PER_WORD; 1080 length -= leftover; 1081 1082 if (length > 0) 1083 score_block_move_loop_body (dst_reg, dst_align, 1084 src_reg, src_align, length); 1085 1086 if (dst_unaligned) 1087 emit_insn (gen_move_sce (dst_reg, dst_reg)); 1088 1089 if (leftover > 0) 1090 { 1091 HOST_WIDE_INT src_adj = src_unaligned ? -4 : 0; 1092 HOST_WIDE_INT dst_adj = dst_unaligned ? -4 : 0; 1093 rtx temp; 1094 1095 gcc_assert (leftover < UNITS_PER_WORD); 1096 1097 if (leftover >= UNITS_PER_WORD / 2 1098 && src_align >= BITS_PER_WORD / 2 1099 && dst_align >= BITS_PER_WORD / 2) 1100 { 1101 temp = gen_reg_rtx (HImode); 1102 emit_insn (gen_move_lhu_b (src_reg, src_reg, 1103 gen_int_mode (src_adj, SImode), temp)); 1104 emit_insn (gen_move_sh_b (dst_reg, dst_reg, 1105 gen_int_mode (dst_adj, SImode), temp)); 1106 leftover -= UNITS_PER_WORD / 2; 1107 src_adj = UNITS_PER_WORD / 2; 1108 dst_adj = UNITS_PER_WORD / 2; 1109 } 1110 1111 while (leftover > 0) 1112 { 1113 temp = gen_reg_rtx (QImode); 1114 emit_insn (gen_move_lbu_b (src_reg, src_reg, 1115 gen_int_mode (src_adj, SImode), temp)); 1116 emit_insn (gen_move_sb_b (dst_reg, dst_reg, 1117 gen_int_mode (dst_adj, SImode), temp)); 1118 leftover--; 1119 src_adj = 1; 1120 dst_adj = 1; 1121 } 1122 } 1123} 1124 1125#define MIN_MOVE_REGS 3 1126#define MIN_MOVE_BYTES (MIN_MOVE_REGS * UNITS_PER_WORD) 1127#define MAX_MOVE_REGS 4 1128#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD) 1129 1130/* The length is large, generate a loop if necessary. 1131 The loop is consisted by loop head/body/foot. */ 1132static void 1133score_block_move_loop (rtx dst, rtx src, HOST_WIDE_INT length) 1134{ 1135 HOST_WIDE_INT src_align = MEM_ALIGN (src); 1136 HOST_WIDE_INT dst_align = MEM_ALIGN (dst); 1137 HOST_WIDE_INT loop_mov_bytes; 1138 HOST_WIDE_INT iteration = 0; 1139 HOST_WIDE_INT head_length = 0, leftover; 1140 rtx label, src_reg, dst_reg, final_dst, test; 1141 1142 bool gen_loop_head = (src_align < BITS_PER_WORD 1143 || dst_align < BITS_PER_WORD); 1144 1145 if (gen_loop_head) 1146 head_length += UNITS_PER_WORD; 1147 1148 for (loop_mov_bytes = MAX_MOVE_BYTES; 1149 loop_mov_bytes >= MIN_MOVE_BYTES; 1150 loop_mov_bytes -= UNITS_PER_WORD) 1151 { 1152 iteration = (length - head_length) / loop_mov_bytes; 1153 if (iteration > 1) 1154 break; 1155 } 1156 if (iteration <= 1) 1157 { 1158 score_block_move_straight (dst, src, length); 1159 return; 1160 } 1161 1162 leftover = (length - head_length) % loop_mov_bytes; 1163 length -= leftover; 1164 1165 src_reg = copy_addr_to_reg (XEXP (src, 0)); 1166 dst_reg = copy_addr_to_reg (XEXP (dst, 0)); 1167 final_dst = expand_simple_binop (Pmode, PLUS, dst_reg, GEN_INT (length), 1168 0, 0, OPTAB_WIDEN); 1169 1170 if (gen_loop_head) 1171 score_block_move_loop_head (dst_reg, dst_align, 1172 src_reg, src_align, head_length); 1173 1174 label = gen_label_rtx (); 1175 emit_label (label); 1176 1177 score_block_move_loop_body (dst_reg, dst_align, 1178 src_reg, src_align, loop_mov_bytes); 1179 1180 test = gen_rtx_NE (VOIDmode, dst_reg, final_dst); 1181 emit_jump_insn (gen_cbranchsi4 (test, dst_reg, final_dst, label)); 1182 1183 score_block_move_loop_foot (dst_reg, dst_align, 1184 src_reg, src_align, leftover); 1185} 1186 1187/* Generate block move, for misc.md: "movmemsi". */ 1188bool 1189score_block_move (rtx *ops) 1190{ 1191 rtx dst = ops[0]; 1192 rtx src = ops[1]; 1193 rtx length = ops[2]; 1194 1195 if (TARGET_LITTLE_ENDIAN 1196 && (MEM_ALIGN (src) < BITS_PER_WORD || MEM_ALIGN (dst) < BITS_PER_WORD) 1197 && INTVAL (length) >= UNITS_PER_WORD) 1198 return false; 1199 1200 if (GET_CODE (length) == CONST_INT) 1201 { 1202 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES) 1203 { 1204 score_block_move_straight (dst, src, INTVAL (length)); 1205 return true; 1206 } 1207 else if (optimize && 1208 !(flag_unroll_loops || flag_unroll_all_loops)) 1209 { 1210 score_block_move_loop (dst, src, INTVAL (length)); 1211 return true; 1212 } 1213 } 1214 return false; 1215} 1216 1217struct gcc_target targetm = TARGET_INITIALIZER; 1218