1/* score7.c for Sunplus S+CORE processor 2 Copyright (C) 2005, 2007, 2008 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 "cfglayout.h" 51#include "score7.h" 52#include "df.h" 53 54#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0) 55#define INS_BUF_SZ 128 56 57extern enum reg_class score_char_to_class[256]; 58 59static int score7_sdata_max; 60static char score7_ins[INS_BUF_SZ + 8]; 61 62/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points 63 to the same object as SYMBOL. */ 64static int 65score7_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset) 66{ 67 if (GET_CODE (symbol) != SYMBOL_REF) 68 return 0; 69 70 if (CONSTANT_POOL_ADDRESS_P (symbol) 71 && offset >= 0 72 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol))) 73 return 1; 74 75 if (SYMBOL_REF_DECL (symbol) != 0 76 && offset >= 0 77 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol)))) 78 return 1; 79 80 return 0; 81} 82 83/* Split X into a base and a constant offset, storing them in *BASE 84 and *OFFSET respectively. */ 85static void 86score7_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset) 87{ 88 *offset = 0; 89 90 if (GET_CODE (x) == CONST) 91 x = XEXP (x, 0); 92 93 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) 94 { 95 *offset += INTVAL (XEXP (x, 1)); 96 x = XEXP (x, 0); 97 } 98 99 *base = x; 100} 101 102/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */ 103static enum score_symbol_type 104score7_classify_symbol (rtx x) 105{ 106 if (GET_CODE (x) == LABEL_REF) 107 return SYMBOL_GENERAL; 108 109 gcc_assert (GET_CODE (x) == SYMBOL_REF); 110 111 if (CONSTANT_POOL_ADDRESS_P (x)) 112 { 113 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE7_SDATA_MAX) 114 return SYMBOL_SMALL_DATA; 115 return SYMBOL_GENERAL; 116 } 117 if (SYMBOL_REF_SMALL_P (x)) 118 return SYMBOL_SMALL_DATA; 119 return SYMBOL_GENERAL; 120} 121 122/* Return true if the current function must save REGNO. */ 123static int 124score7_save_reg_p (unsigned int regno) 125{ 126 /* Check call-saved registers. */ 127 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) 128 return 1; 129 130 /* We need to save the old frame pointer before setting up a new one. */ 131 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) 132 return 1; 133 134 /* We need to save the incoming return address if it is ever clobbered 135 within the function. */ 136 if (regno == RA_REGNUM && df_regs_ever_live_p (regno)) 137 return 1; 138 139 return 0; 140} 141 142/* Return one word of double-word value OP, taking into account the fixed 143 endianness of certain registers. HIGH_P is true to select the high part, 144 false to select the low part. */ 145static rtx 146score7_subw (rtx op, int high_p) 147{ 148 unsigned int byte; 149 enum machine_mode mode = GET_MODE (op); 150 151 if (mode == VOIDmode) 152 mode = DImode; 153 154 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0; 155 156 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM) 157 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM); 158 159 if (GET_CODE (op) == MEM) 160 return adjust_address (op, SImode, byte); 161 162 return simplify_gen_subreg (SImode, op, mode, byte); 163} 164 165static struct score7_frame_info * 166score7_cached_frame (void) 167{ 168 static struct score7_frame_info _frame_info; 169 return &_frame_info; 170} 171 172/* Return the bytes needed to compute the frame pointer from the current 173 stack pointer. SIZE is the size (in bytes) of the local variables. */ 174static struct score7_frame_info * 175score7_compute_frame_size (HOST_WIDE_INT size) 176{ 177 unsigned int regno; 178 struct score7_frame_info *f = score7_cached_frame (); 179 180 memset (f, 0, sizeof (struct score7_frame_info)); 181 f->gp_reg_size = 0; 182 f->mask = 0; 183 f->var_size = SCORE7_STACK_ALIGN (size); 184 f->args_size = crtl->outgoing_args_size; 185 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0; 186 if (f->var_size == 0 && current_function_is_leaf) 187 f->args_size = f->cprestore_size = 0; 188 189 if (f->args_size == 0 && cfun->calls_alloca) 190 f->args_size = UNITS_PER_WORD; 191 192 f->total_size = f->var_size + f->args_size + f->cprestore_size; 193 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) 194 { 195 if (score7_save_reg_p (regno)) 196 { 197 f->gp_reg_size += GET_MODE_SIZE (SImode); 198 f->mask |= 1 << (regno - GP_REG_FIRST); 199 } 200 } 201 202 if (crtl->calls_eh_return) 203 { 204 unsigned int i; 205 for (i = 0;; ++i) 206 { 207 regno = EH_RETURN_DATA_REGNO (i); 208 if (regno == INVALID_REGNUM) 209 break; 210 f->gp_reg_size += GET_MODE_SIZE (SImode); 211 f->mask |= 1 << (regno - GP_REG_FIRST); 212 } 213 } 214 215 f->total_size += f->gp_reg_size; 216 f->num_gp = f->gp_reg_size / UNITS_PER_WORD; 217 218 if (f->mask) 219 { 220 HOST_WIDE_INT offset; 221 offset = (f->args_size + f->cprestore_size + f->var_size 222 + f->gp_reg_size - GET_MODE_SIZE (SImode)); 223 f->gp_sp_offset = offset; 224 } 225 else 226 f->gp_sp_offset = 0; 227 228 return f; 229} 230 231/* Return true if X is a valid base register for the given mode. 232 Allow only hard registers if STRICT. */ 233static int 234score7_valid_base_register_p (rtx x, int strict) 235{ 236 if (!strict && GET_CODE (x) == SUBREG) 237 x = SUBREG_REG (x); 238 239 return (GET_CODE (x) == REG 240 && score7_regno_mode_ok_for_base_p (REGNO (x), strict)); 241} 242 243/* Return true if X is a valid address for machine mode MODE. If it is, 244 fill in INFO appropriately. STRICT is true if we should only accept 245 hard base registers. */ 246static int 247score7_classify_address (struct score7_address_info *info, 248 enum machine_mode mode, rtx x, int strict) 249{ 250 info->code = GET_CODE (x); 251 252 switch (info->code) 253 { 254 case REG: 255 case SUBREG: 256 info->type = SCORE7_ADD_REG; 257 info->reg = x; 258 info->offset = const0_rtx; 259 return score7_valid_base_register_p (info->reg, strict); 260 case PLUS: 261 info->type = SCORE7_ADD_REG; 262 info->reg = XEXP (x, 0); 263 info->offset = XEXP (x, 1); 264 return (score7_valid_base_register_p (info->reg, strict) 265 && GET_CODE (info->offset) == CONST_INT 266 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1)); 267 case PRE_DEC: 268 case POST_DEC: 269 case PRE_INC: 270 case POST_INC: 271 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode)) 272 return false; 273 info->type = SCORE7_ADD_REG; 274 info->reg = XEXP (x, 0); 275 info->offset = GEN_INT (GET_MODE_SIZE (mode)); 276 return score7_valid_base_register_p (info->reg, strict); 277 case CONST_INT: 278 info->type = SCORE7_ADD_CONST_INT; 279 return IMM_IN_RANGE (INTVAL (x), 15, 1); 280 case CONST: 281 case LABEL_REF: 282 case SYMBOL_REF: 283 info->type = SCORE7_ADD_SYMBOLIC; 284 return (score7_symbolic_constant_p (x, &info->symbol_type) 285 && (info->symbol_type == SYMBOL_GENERAL 286 || info->symbol_type == SYMBOL_SMALL_DATA)); 287 default: 288 return 0; 289 } 290} 291 292bool 293score7_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED) 294{ 295 return ((TYPE_MODE (type) == BLKmode) 296 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD) 297 || (int_size_in_bytes (type) == -1)); 298} 299 300/* Return a legitimate address for REG + OFFSET. */ 301static rtx 302score7_add_offset (rtx reg, HOST_WIDE_INT offset) 303{ 304 if (!IMM_IN_RANGE (offset, 15, 1)) 305 { 306 reg = expand_simple_binop (GET_MODE (reg), PLUS, 307 gen_int_mode (offset & 0xffffc000, 308 GET_MODE (reg)), 309 reg, NULL, 0, OPTAB_WIDEN); 310 offset &= 0x3fff; 311 } 312 313 return plus_constant (reg, offset); 314} 315 316/* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text 317 in order to avoid duplicating too much logic from elsewhere. */ 318void 319score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 320 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 321 tree function) 322{ 323 rtx this_rtx, temp1, insn, fnaddr; 324 325 /* Pretend to be a post-reload pass while generating rtl. */ 326 reload_completed = 1; 327 328 /* Mark the end of the (empty) prologue. */ 329 emit_note (NOTE_INSN_PROLOGUE_END); 330 331 /* We need two temporary registers in some cases. */ 332 temp1 = gen_rtx_REG (Pmode, 8); 333 334 /* Find out which register contains the "this" pointer. */ 335 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 336 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1); 337 else 338 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST); 339 340 /* Add DELTA to THIS_RTX. */ 341 if (delta != 0) 342 { 343 rtx offset = GEN_INT (delta); 344 if (!CONST_OK_FOR_LETTER_P (delta, 'L')) 345 { 346 emit_move_insn (temp1, offset); 347 offset = temp1; 348 } 349 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset)); 350 } 351 352 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ 353 if (vcall_offset != 0) 354 { 355 rtx addr; 356 357 /* Set TEMP1 to *THIS_RTX. */ 358 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx)); 359 360 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */ 361 addr = score7_add_offset (temp1, vcall_offset); 362 363 /* Load the offset and add it to THIS_RTX. */ 364 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); 365 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1)); 366 } 367 368 /* Jump to the target function. */ 369 fnaddr = XEXP (DECL_RTL (function), 0); 370 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx)); 371 SIBLING_CALL_P (insn) = 1; 372 373 /* Run just enough of rest_of_compilation. This sequence was 374 "borrowed" from alpha.c. */ 375 insn = get_insns (); 376 insn_locators_alloc (); 377 split_all_insns_noflow (); 378 shorten_branches (insn); 379 final_start_function (insn, file, 1); 380 final (insn, file, 1); 381 final_end_function (); 382 383 /* Clean up the vars set above. Note that final_end_function resets 384 the global pointer for us. */ 385 reload_completed = 0; 386} 387 388/* Copy VALUE to a register and return that register. If new psuedos 389 are allowed, copy it into a new register, otherwise use DEST. */ 390static rtx 391score7_force_temporary (rtx dest, rtx value) 392{ 393 if (can_create_pseudo_p ()) 394 return force_reg (Pmode, value); 395 else 396 { 397 emit_move_insn (copy_rtx (dest), value); 398 return dest; 399 } 400} 401 402/* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary 403 and is used to load the high part into a register. */ 404static rtx 405score7_split_symbol (rtx temp, rtx addr) 406{ 407 rtx high = score7_force_temporary (temp, 408 gen_rtx_HIGH (Pmode, copy_rtx (addr))); 409 return gen_rtx_LO_SUM (Pmode, high, addr); 410} 411 412/* This function is used to implement LEGITIMIZE_ADDRESS. If X can 413 be legitimized in a way that the generic machinery might not expect, 414 return the new address. */ 415rtx 416score7_legitimize_address (rtx x) 417{ 418 enum score_symbol_type symbol_type; 419 420 if (score7_symbolic_constant_p (x, &symbol_type) 421 && symbol_type == SYMBOL_GENERAL) 422 return score7_split_symbol (0, x); 423 424 if (GET_CODE (x) == PLUS 425 && GET_CODE (XEXP (x, 1)) == CONST_INT) 426 { 427 rtx reg = XEXP (x, 0); 428 if (!score7_valid_base_register_p (reg, 0)) 429 reg = copy_to_mode_reg (Pmode, reg); 430 return score7_add_offset (reg, INTVAL (XEXP (x, 1))); 431 } 432 433 return x; 434} 435 436/* Fill INFO with information about a single argument. CUM is the 437 cumulative state for earlier arguments. MODE is the mode of this 438 argument and TYPE is its type (if known). NAMED is true if this 439 is a named (fixed) argument rather than a variable one. */ 440static void 441score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, 442 tree type, int named, struct score7_arg_info *info) 443{ 444 int even_reg_p; 445 unsigned int num_words, max_regs; 446 447 even_reg_p = 0; 448 if (GET_MODE_CLASS (mode) == MODE_INT 449 || GET_MODE_CLASS (mode) == MODE_FLOAT) 450 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD); 451 else 452 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named) 453 even_reg_p = 1; 454 455 if (TARGET_MUST_PASS_IN_STACK (mode, type)) 456 info->reg_offset = ARG_REG_NUM; 457 else 458 { 459 info->reg_offset = cum->num_gprs; 460 if (even_reg_p) 461 info->reg_offset += info->reg_offset & 1; 462 } 463 464 if (mode == BLKmode) 465 info->num_bytes = int_size_in_bytes (type); 466 else 467 info->num_bytes = GET_MODE_SIZE (mode); 468 469 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 470 max_regs = ARG_REG_NUM - info->reg_offset; 471 472 /* Partition the argument between registers and stack. */ 473 info->reg_words = MIN (num_words, max_regs); 474 info->stack_words = num_words - info->reg_words; 475 476 /* The alignment applied to registers is also applied to stack arguments. */ 477 if (info->stack_words) 478 { 479 info->stack_offset = cum->stack_words; 480 if (even_reg_p) 481 info->stack_offset += info->stack_offset & 1; 482 } 483} 484 485/* Set up the stack and frame (if desired) for the function. */ 486void 487score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) 488{ 489 const char *fnname; 490 struct score7_frame_info *f = score7_cached_frame (); 491 HOST_WIDE_INT tsize = f->total_size; 492 493 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 494 if (!flag_inhibit_size_directive) 495 { 496 fputs ("\t.ent\t", file); 497 assemble_name (file, fnname); 498 fputs ("\n", file); 499 } 500 assemble_name (file, fnname); 501 fputs (":\n", file); 502 503 if (!flag_inhibit_size_directive) 504 { 505 fprintf (file, 506 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t" 507 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d" 508 ", args= " HOST_WIDE_INT_PRINT_DEC 509 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n", 510 (reg_names[(frame_pointer_needed) 511 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]), 512 tsize, 513 reg_names[RA_REGNUM], 514 current_function_is_leaf ? 1 : 0, 515 f->var_size, 516 f->num_gp, 517 f->args_size, 518 f->cprestore_size); 519 520 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n", 521 f->mask, 522 (f->gp_sp_offset - f->total_size)); 523 } 524} 525 526/* Do any necessary cleanup after a function to restore stack, frame, 527 and regs. */ 528void 529score7_function_epilogue (FILE *file, 530 HOST_WIDE_INT size ATTRIBUTE_UNUSED) 531{ 532 if (!flag_inhibit_size_directive) 533 { 534 const char *fnname; 535 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 536 fputs ("\t.end\t", file); 537 assemble_name (file, fnname); 538 fputs ("\n", file); 539 } 540} 541 542/* Returns true if X contains a SYMBOL_REF. */ 543static bool 544score7_symbolic_expression_p (rtx x) 545{ 546 if (GET_CODE (x) == SYMBOL_REF) 547 return true; 548 549 if (GET_CODE (x) == CONST) 550 return score7_symbolic_expression_p (XEXP (x, 0)); 551 552 if (UNARY_P (x)) 553 return score7_symbolic_expression_p (XEXP (x, 0)); 554 555 if (ARITHMETIC_P (x)) 556 return (score7_symbolic_expression_p (XEXP (x, 0)) 557 || score7_symbolic_expression_p (XEXP (x, 1))); 558 559 return false; 560} 561 562/* Choose the section to use for the constant rtx expression X that has 563 mode MODE. */ 564section * 565score7_select_rtx_section (enum machine_mode mode, rtx x, 566 unsigned HOST_WIDE_INT align) 567{ 568 if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX) 569 return get_named_section (0, ".sdata", 0); 570 else if (flag_pic && score7_symbolic_expression_p (x)) 571 return get_named_section (0, ".data.rel.ro", 3); 572 else 573 return mergeable_constant_section (mode, align, 0); 574} 575 576/* Implement TARGET_IN_SMALL_DATA_P. */ 577bool 578score7_in_small_data_p (tree decl) 579{ 580 HOST_WIDE_INT size; 581 582 if (TREE_CODE (decl) == STRING_CST 583 || TREE_CODE (decl) == FUNCTION_DECL) 584 return false; 585 586 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0) 587 { 588 const char *name; 589 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); 590 if (strcmp (name, ".sdata") != 0 591 && strcmp (name, ".sbss") != 0) 592 return true; 593 if (!DECL_EXTERNAL (decl)) 594 return false; 595 } 596 size = int_size_in_bytes (TREE_TYPE (decl)); 597 return (size > 0 && size <= SCORE7_SDATA_MAX); 598} 599 600/* Implement TARGET_ASM_FILE_START. */ 601void 602score7_asm_file_start (void) 603{ 604 default_file_start (); 605 fprintf (asm_out_file, ASM_COMMENT_START 606 "GCC for S+core %s \n", SCORE_GCC_VERSION); 607 608 if (flag_pic) 609 fprintf (asm_out_file, "\t.set pic\n"); 610} 611 612/* Implement TARGET_ASM_FILE_END. When using assembler macros, emit 613 .externs for any small-data variables that turned out to be external. */ 614void 615score7_asm_file_end (void) 616{ 617 tree name_tree; 618 struct extern_list *p; 619 if (extern_head) 620 { 621 fputs ("\n", asm_out_file); 622 for (p = extern_head; p != 0; p = p->next) 623 { 624 name_tree = get_identifier (p->name); 625 if (!TREE_ASM_WRITTEN (name_tree) 626 && TREE_SYMBOL_REFERENCED (name_tree)) 627 { 628 TREE_ASM_WRITTEN (name_tree) = 1; 629 fputs ("\t.extern\t", asm_out_file); 630 assemble_name (asm_out_file, p->name); 631 fprintf (asm_out_file, ", %d\n", p->size); 632 } 633 } 634 } 635} 636 637/* Implement OVERRIDE_OPTIONS macro. */ 638void 639score7_override_options (void) 640{ 641 flag_pic = false; 642 if (!flag_pic) 643 score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX; 644 else 645 { 646 score7_sdata_max = 0; 647 if (g_switch_set && (g_switch_value != 0)) 648 warning (0, "-fPIC and -G are incompatible"); 649 } 650 651 score_char_to_class['d'] = G32_REGS; 652 score_char_to_class['e'] = G16_REGS; 653 score_char_to_class['t'] = T32_REGS; 654 655 score_char_to_class['h'] = HI_REG; 656 score_char_to_class['l'] = LO_REG; 657 score_char_to_class['x'] = CE_REGS; 658 659 score_char_to_class['q'] = CN_REG; 660 score_char_to_class['y'] = LC_REG; 661 score_char_to_class['z'] = SC_REG; 662 score_char_to_class['a'] = SP_REGS; 663 664 score_char_to_class['c'] = CR_REGS; 665} 666 667/* Implement REGNO_REG_CLASS macro. */ 668int 669score7_reg_class (int regno) 670{ 671 int c; 672 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER); 673 674 if (regno == FRAME_POINTER_REGNUM 675 || regno == ARG_POINTER_REGNUM) 676 return ALL_REGS; 677 678 for (c = 0; c < N_REG_CLASSES; c++) 679 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno)) 680 return c; 681 682 return NO_REGS; 683} 684 685/* Implement PREFERRED_RELOAD_CLASS macro. */ 686enum reg_class 687score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass) 688{ 689 if (reg_class_subset_p (G16_REGS, rclass)) 690 return G16_REGS; 691 if (reg_class_subset_p (G32_REGS, rclass)) 692 return G32_REGS; 693 return rclass; 694} 695 696/* Implement SECONDARY_INPUT_RELOAD_CLASS 697 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */ 698enum reg_class 699score7_secondary_reload_class (enum reg_class rclass, 700 enum machine_mode mode ATTRIBUTE_UNUSED, 701 rtx x) 702{ 703 int regno = -1; 704 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG) 705 regno = true_regnum (x); 706 707 if (!GR_REG_CLASS_P (rclass)) 708 return GP_REG_P (regno) ? NO_REGS : G32_REGS; 709 return NO_REGS; 710} 711 712/* Implement CONST_OK_FOR_LETTER_P macro. */ 713/* imm constraints 714 I imm16 << 16 715 J uimm5 716 K uimm16 717 L simm16 718 M uimm14 719 N simm14 */ 720int 721score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c) 722{ 723 switch (c) 724 { 725 case 'I': return ((value & 0xffff) == 0); 726 case 'J': return IMM_IN_RANGE (value, 5, 0); 727 case 'K': return IMM_IN_RANGE (value, 16, 0); 728 case 'L': return IMM_IN_RANGE (value, 16, 1); 729 case 'M': return IMM_IN_RANGE (value, 14, 0); 730 case 'N': return IMM_IN_RANGE (value, 14, 1); 731 default : return 0; 732 } 733} 734 735/* Implement EXTRA_CONSTRAINT macro. */ 736/* Z symbol_ref */ 737int 738score7_extra_constraint (rtx op, char c) 739{ 740 switch (c) 741 { 742 case 'Z': 743 return GET_CODE (op) == SYMBOL_REF; 744 default: 745 gcc_unreachable (); 746 } 747} 748 749/* Return truth value on whether or not a given hard register 750 can support a given mode. */ 751int 752score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) 753{ 754 int size = GET_MODE_SIZE (mode); 755 enum mode_class mclass = GET_MODE_CLASS (mode); 756 757 if (mclass == MODE_CC) 758 return regno == CC_REGNUM; 759 else if (regno == FRAME_POINTER_REGNUM 760 || regno == ARG_POINTER_REGNUM) 761 return mclass == MODE_INT; 762 else if (GP_REG_P (regno)) 763 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */ 764 return !(regno & 1) || (size <= UNITS_PER_WORD); 765 else if (CE_REG_P (regno)) 766 return (mclass == MODE_INT 767 && ((size <= UNITS_PER_WORD) 768 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD))); 769 else 770 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD); 771} 772 773/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame 774 pointer or argument pointer. TO is either the stack pointer or 775 hard frame pointer. */ 776HOST_WIDE_INT 777score7_initial_elimination_offset (int from, 778 int to ATTRIBUTE_UNUSED) 779{ 780 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ()); 781 switch (from) 782 { 783 case ARG_POINTER_REGNUM: 784 return f->total_size; 785 case FRAME_POINTER_REGNUM: 786 return 0; 787 default: 788 gcc_unreachable (); 789 } 790} 791 792/* Implement FUNCTION_ARG_ADVANCE macro. */ 793void 794score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, 795 tree type, int named) 796{ 797 struct score7_arg_info info; 798 score7_classify_arg (cum, mode, type, named, &info); 799 cum->num_gprs = info.reg_offset + info.reg_words; 800 if (info.stack_words > 0) 801 cum->stack_words = info.stack_offset + info.stack_words; 802 cum->arg_number++; 803} 804 805/* Implement TARGET_ARG_PARTIAL_BYTES macro. */ 806int 807score7_arg_partial_bytes (CUMULATIVE_ARGS *cum, 808 enum machine_mode mode, tree type, bool named) 809{ 810 struct score7_arg_info info; 811 score7_classify_arg (cum, mode, type, named, &info); 812 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0; 813} 814 815/* Implement FUNCTION_ARG macro. */ 816rtx 817score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, 818 tree type, int named) 819{ 820 struct score7_arg_info info; 821 822 if (mode == VOIDmode || !named) 823 return 0; 824 825 score7_classify_arg (cum, mode, type, named, &info); 826 827 if (info.reg_offset == ARG_REG_NUM) 828 return 0; 829 830 if (!info.stack_words) 831 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset); 832 else 833 { 834 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words)); 835 unsigned int i, part_offset = 0; 836 for (i = 0; i < info.reg_words; i++) 837 { 838 rtx reg; 839 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i); 840 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg, 841 GEN_INT (part_offset)); 842 part_offset += UNITS_PER_WORD; 843 } 844 return ret; 845 } 846} 847 848/* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls, 849 VALTYPE is the return type and MODE is VOIDmode. For libcalls, 850 VALTYPE is null and MODE is the mode of the return value. */ 851rtx 852score7_function_value (tree valtype, tree func, enum machine_mode mode) 853{ 854 if (valtype) 855 { 856 int unsignedp; 857 mode = TYPE_MODE (valtype); 858 unsignedp = TYPE_UNSIGNED (valtype); 859 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1); 860 } 861 return gen_rtx_REG (mode, RT_REGNUM); 862} 863 864/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 865 866void 867score7_asm_trampoline_template (FILE *f) 868{ 869 fprintf (f, "\t.set r1\n"); 870 fprintf (f, "\tmv r31, r3\n"); 871 fprintf (f, "\tbl nextinsn\n"); 872 fprintf (f, "nextinsn:\n"); 873 fprintf (f, "\tlw r1, [r3, 6*4-8]\n"); 874 fprintf (f, "\tlw r23, [r3, 6*4-4]\n"); 875 fprintf (f, "\tmv r3, r31\n"); 876 fprintf (f, "\tbr! r1\n"); 877 fprintf (f, "\tnop!\n"); 878 fprintf (f, "\t.set nor1\n"); 879} 880 881/* Implement TARGET_TRAMPOLINE_INIT. */ 882void 883score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) 884{ 885#define FFCACHE "_flush_cache" 886#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD) 887 888 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 889 rtx addr = XEXP (m_tramp, 0); 890 rtx mem; 891 892 emit_block_move (m_tramp, assemble_trampoline_template (), 893 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); 894 895 mem = adjust_address (m_tramp, SImode, CODE_SIZE); 896 emit_move_insn (mem, fnaddr); 897 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode)); 898 emit_move_insn (mem, chain_value); 899 900 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE), 901 0, VOIDmode, 2, 902 addr, Pmode, 903 GEN_INT (TRAMPOLINE_SIZE), SImode); 904#undef FFCACHE 905#undef CODE_SIZE 906} 907 908/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */ 909int 910score7_regno_mode_ok_for_base_p (int regno, int strict) 911{ 912 if (regno >= FIRST_PSEUDO_REGISTER) 913 { 914 if (!strict) 915 return 1; 916 regno = reg_renumber[regno]; 917 } 918 if (regno == ARG_POINTER_REGNUM 919 || regno == FRAME_POINTER_REGNUM) 920 return 1; 921 return GP_REG_P (regno); 922} 923 924/* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */ 925bool 926score7_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) 927{ 928 struct score7_address_info addr; 929 930 return score7_classify_address (&addr, mode, x, strict); 931} 932 933/* Return a number assessing the cost of moving a register in class 934 FROM to class TO. */ 935int 936score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, 937 enum reg_class from, enum reg_class to) 938{ 939 if (GR_REG_CLASS_P (from)) 940 { 941 if (GR_REG_CLASS_P (to)) 942 return 2; 943 else if (SP_REG_CLASS_P (to)) 944 return 4; 945 else if (CP_REG_CLASS_P (to)) 946 return 5; 947 else if (CE_REG_CLASS_P (to)) 948 return 6; 949 } 950 if (GR_REG_CLASS_P (to)) 951 { 952 if (GR_REG_CLASS_P (from)) 953 return 2; 954 else if (SP_REG_CLASS_P (from)) 955 return 4; 956 else if (CP_REG_CLASS_P (from)) 957 return 5; 958 else if (CE_REG_CLASS_P (from)) 959 return 6; 960 } 961 return 12; 962} 963 964/* Return the number of instructions needed to load a symbol of the 965 given type into a register. */ 966static int 967score7_symbol_insns (enum score_symbol_type type) 968{ 969 switch (type) 970 { 971 case SYMBOL_GENERAL: 972 return 2; 973 974 case SYMBOL_SMALL_DATA: 975 return 1; 976 } 977 978 gcc_unreachable (); 979} 980 981/* Return the number of instructions needed to load or store a value 982 of mode MODE at X. Return 0 if X isn't valid for MODE. */ 983static int 984score7_address_insns (rtx x, enum machine_mode mode) 985{ 986 struct score7_address_info addr; 987 int factor; 988 989 if (mode == BLKmode) 990 factor = 1; 991 else 992 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 993 994 if (score7_classify_address (&addr, mode, x, false)) 995 switch (addr.type) 996 { 997 case SCORE7_ADD_REG: 998 case SCORE7_ADD_CONST_INT: 999 return factor; 1000 1001 case SCORE7_ADD_SYMBOLIC: 1002 return factor * score7_symbol_insns (addr.symbol_type); 1003 } 1004 return 0; 1005} 1006 1007/* Implement TARGET_RTX_COSTS macro. */ 1008bool 1009score7_rtx_costs (rtx x, int code, int outer_code, int *total, 1010 bool speed ATTRIBUTE_UNUSED) 1011{ 1012 enum machine_mode mode = GET_MODE (x); 1013 1014 switch (code) 1015 { 1016 case CONST_INT: 1017 if (outer_code == SET) 1018 { 1019 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I') 1020 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')) 1021 *total = COSTS_N_INSNS (1); 1022 else 1023 *total = COSTS_N_INSNS (2); 1024 } 1025 else if (outer_code == PLUS || outer_code == MINUS) 1026 { 1027 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N')) 1028 *total = 0; 1029 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I') 1030 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')) 1031 *total = 1; 1032 else 1033 *total = COSTS_N_INSNS (2); 1034 } 1035 else if (outer_code == AND || outer_code == IOR) 1036 { 1037 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M')) 1038 *total = 0; 1039 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I') 1040 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')) 1041 *total = 1; 1042 else 1043 *total = COSTS_N_INSNS (2); 1044 } 1045 else 1046 { 1047 *total = 0; 1048 } 1049 return true; 1050 1051 case CONST: 1052 case SYMBOL_REF: 1053 case LABEL_REF: 1054 case CONST_DOUBLE: 1055 *total = COSTS_N_INSNS (2); 1056 return true; 1057 1058 case MEM: 1059 { 1060 /* If the address is legitimate, return the number of 1061 instructions it needs, otherwise use the default handling. */ 1062 int n = score7_address_insns (XEXP (x, 0), GET_MODE (x)); 1063 if (n > 0) 1064 { 1065 *total = COSTS_N_INSNS (n + 1); 1066 return true; 1067 } 1068 return false; 1069 } 1070 1071 case FFS: 1072 *total = COSTS_N_INSNS (6); 1073 return true; 1074 1075 case NOT: 1076 *total = COSTS_N_INSNS (1); 1077 return true; 1078 1079 case AND: 1080 case IOR: 1081 case XOR: 1082 if (mode == DImode) 1083 { 1084 *total = COSTS_N_INSNS (2); 1085 return true; 1086 } 1087 return false; 1088 1089 case ASHIFT: 1090 case ASHIFTRT: 1091 case LSHIFTRT: 1092 if (mode == DImode) 1093 { 1094 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT) 1095 ? 4 : 12); 1096 return true; 1097 } 1098 return false; 1099 1100 case ABS: 1101 *total = COSTS_N_INSNS (4); 1102 return true; 1103 1104 case PLUS: 1105 case MINUS: 1106 if (mode == DImode) 1107 { 1108 *total = COSTS_N_INSNS (4); 1109 return true; 1110 } 1111 *total = COSTS_N_INSNS (1); 1112 return true; 1113 1114 case NEG: 1115 if (mode == DImode) 1116 { 1117 *total = COSTS_N_INSNS (4); 1118 return true; 1119 } 1120 return false; 1121 1122 case MULT: 1123 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12); 1124 return true; 1125 1126 case DIV: 1127 case MOD: 1128 case UDIV: 1129 case UMOD: 1130 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33); 1131 return true; 1132 1133 case SIGN_EXTEND: 1134 case ZERO_EXTEND: 1135 switch (GET_MODE (XEXP (x, 0))) 1136 { 1137 case QImode: 1138 case HImode: 1139 if (GET_CODE (XEXP (x, 0)) == MEM) 1140 { 1141 *total = COSTS_N_INSNS (2); 1142 1143 if (!TARGET_LITTLE_ENDIAN && 1144 side_effects_p (XEXP (XEXP (x, 0), 0))) 1145 *total = 100; 1146 } 1147 else 1148 *total = COSTS_N_INSNS (1); 1149 break; 1150 1151 default: 1152 *total = COSTS_N_INSNS (1); 1153 break; 1154 } 1155 return true; 1156 1157 default: 1158 return false; 1159 } 1160} 1161 1162/* Implement TARGET_ADDRESS_COST macro. */ 1163int 1164score7_address_cost (rtx addr) 1165{ 1166 return score7_address_insns (addr, SImode); 1167} 1168 1169/* Implement ASM_OUTPUT_EXTERNAL macro. */ 1170int 1171score7_output_external (FILE *file ATTRIBUTE_UNUSED, 1172 tree decl, const char *name) 1173{ 1174 register struct extern_list *p; 1175 1176 if (score7_in_small_data_p (decl)) 1177 { 1178 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list)); 1179 p->next = extern_head; 1180 p->name = name; 1181 p->size = int_size_in_bytes (TREE_TYPE (decl)); 1182 extern_head = p; 1183 } 1184 return 0; 1185} 1186 1187/* Implement RETURN_ADDR_RTX. Note, we do not support moving 1188 back to a previous frame. */ 1189rtx 1190score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 1191{ 1192 if (count != 0) 1193 return const0_rtx; 1194 return get_hard_reg_initial_val (Pmode, RA_REGNUM); 1195} 1196 1197/* Implement PRINT_OPERAND macro. */ 1198/* Score-specific operand codes: 1199 '[' print .set nor1 directive 1200 ']' print .set r1 directive 1201 'U' print hi part of a CONST_INT rtx 1202 'E' print log2(v) 1203 'F' print log2(~v) 1204 'D' print SFmode const double 1205 'S' selectively print "!" if operand is 15bit instruction accessible 1206 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!" 1207 'L' low part of DImode reg operand 1208 'H' high part of DImode reg operand 1209 'C' print part of opcode for a branch condition. */ 1210void 1211score7_print_operand (FILE *file, rtx op, int c) 1212{ 1213 enum rtx_code code = -1; 1214 if (!PRINT_OPERAND_PUNCT_VALID_P (c)) 1215 code = GET_CODE (op); 1216 1217 if (c == '[') 1218 { 1219 fprintf (file, ".set r1\n"); 1220 } 1221 else if (c == ']') 1222 { 1223 fprintf (file, "\n\t.set nor1"); 1224 } 1225 else if (c == 'U') 1226 { 1227 gcc_assert (code == CONST_INT); 1228 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 1229 (INTVAL (op) >> 16) & 0xffff); 1230 } 1231 else if (c == 'D') 1232 { 1233 if (GET_CODE (op) == CONST_DOUBLE) 1234 { 1235 rtx temp = gen_lowpart (SImode, op); 1236 gcc_assert (GET_MODE (op) == SFmode); 1237 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff); 1238 } 1239 else 1240 output_addr_const (file, op); 1241 } 1242 else if (c == 'S') 1243 { 1244 gcc_assert (code == REG); 1245 if (G16_REG_P (REGNO (op))) 1246 fprintf (file, "!"); 1247 } 1248 else if (c == 'V') 1249 { 1250 gcc_assert (code == REG); 1251 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!"); 1252 } 1253 else if (c == 'C') 1254 { 1255 enum machine_mode mode = GET_MODE (XEXP (op, 0)); 1256 1257 switch (code) 1258 { 1259 case EQ: fputs ("eq", file); break; 1260 case NE: fputs ("ne", file); break; 1261 case GT: fputs ("gt", file); break; 1262 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break; 1263 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break; 1264 case LE: fputs ("le", file); break; 1265 case GTU: fputs ("gtu", file); break; 1266 case GEU: fputs ("cs", file); break; 1267 case LTU: fputs ("cc", file); break; 1268 case LEU: fputs ("leu", file); break; 1269 default: 1270 output_operand_lossage ("invalid operand for code: '%c'", code); 1271 } 1272 } 1273 else if (c == 'E') 1274 { 1275 unsigned HOST_WIDE_INT i; 1276 unsigned HOST_WIDE_INT pow2mask = 1; 1277 unsigned HOST_WIDE_INT val; 1278 1279 val = INTVAL (op); 1280 for (i = 0; i < 32; i++) 1281 { 1282 if (val == pow2mask) 1283 break; 1284 pow2mask <<= 1; 1285 } 1286 gcc_assert (i < 32); 1287 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i); 1288 } 1289 else if (c == 'F') 1290 { 1291 unsigned HOST_WIDE_INT i; 1292 unsigned HOST_WIDE_INT pow2mask = 1; 1293 unsigned HOST_WIDE_INT val; 1294 1295 val = ~INTVAL (op); 1296 for (i = 0; i < 32; i++) 1297 { 1298 if (val == pow2mask) 1299 break; 1300 pow2mask <<= 1; 1301 } 1302 gcc_assert (i < 32); 1303 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i); 1304 } 1305 else if (code == REG) 1306 { 1307 int regnum = REGNO (op); 1308 if ((c == 'H' && !WORDS_BIG_ENDIAN) 1309 || (c == 'L' && WORDS_BIG_ENDIAN)) 1310 regnum ++; 1311 fprintf (file, "%s", reg_names[regnum]); 1312 } 1313 else 1314 { 1315 switch (code) 1316 { 1317 case MEM: 1318 score7_print_operand_address (file, op); 1319 break; 1320 default: 1321 output_addr_const (file, op); 1322 } 1323 } 1324} 1325 1326/* Implement PRINT_OPERAND_ADDRESS macro. */ 1327void 1328score7_print_operand_address (FILE *file, rtx x) 1329{ 1330 struct score7_address_info addr; 1331 enum rtx_code code = GET_CODE (x); 1332 enum machine_mode mode = GET_MODE (x); 1333 1334 if (code == MEM) 1335 x = XEXP (x, 0); 1336 1337 if (score7_classify_address (&addr, mode, x, true)) 1338 { 1339 switch (addr.type) 1340 { 1341 case SCORE7_ADD_REG: 1342 { 1343 switch (addr.code) 1344 { 1345 case PRE_DEC: 1346 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)], 1347 INTVAL (addr.offset)); 1348 break; 1349 case POST_DEC: 1350 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)], 1351 INTVAL (addr.offset)); 1352 break; 1353 case PRE_INC: 1354 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)], 1355 INTVAL (addr.offset)); 1356 break; 1357 case POST_INC: 1358 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)], 1359 INTVAL (addr.offset)); 1360 break; 1361 default: 1362 if (INTVAL(addr.offset) == 0) 1363 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]); 1364 else 1365 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)], 1366 INTVAL(addr.offset)); 1367 break; 1368 } 1369 } 1370 return; 1371 case SCORE7_ADD_CONST_INT: 1372 case SCORE7_ADD_SYMBOLIC: 1373 output_addr_const (file, x); 1374 return; 1375 } 1376 } 1377 print_rtl (stderr, x); 1378 gcc_unreachable (); 1379} 1380 1381/* Implement SELECT_CC_MODE macro. */ 1382enum machine_mode 1383score7_select_cc_mode (enum rtx_code op, rtx x, rtx y) 1384{ 1385 if ((op == EQ || op == NE || op == LT || op == GE) 1386 && y == const0_rtx 1387 && GET_MODE (x) == SImode) 1388 { 1389 switch (GET_CODE (x)) 1390 { 1391 case PLUS: 1392 case MINUS: 1393 case NEG: 1394 case AND: 1395 case IOR: 1396 case XOR: 1397 case NOT: 1398 case ASHIFT: 1399 case LSHIFTRT: 1400 case ASHIFTRT: 1401 return CC_NZmode; 1402 1403 case SIGN_EXTEND: 1404 case ZERO_EXTEND: 1405 case ROTATE: 1406 case ROTATERT: 1407 return (op == LT || op == GE) ? CC_Nmode : CCmode; 1408 1409 default: 1410 return CCmode; 1411 } 1412 } 1413 1414 if ((op == EQ || op == NE) 1415 && (GET_CODE (y) == NEG) 1416 && register_operand (XEXP (y, 0), SImode) 1417 && register_operand (x, SImode)) 1418 { 1419 return CC_NZmode; 1420 } 1421 1422 return CCmode; 1423} 1424 1425/* Generate the prologue instructions for entry into a S+core function. */ 1426void 1427score7_prologue (void) 1428{ 1429#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1 1430 1431 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ()); 1432 HOST_WIDE_INT size; 1433 int regno; 1434 1435 size = f->total_size - f->gp_reg_size; 1436 1437 if (flag_pic) 1438 emit_insn (gen_cpload_score7 ()); 1439 1440 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--) 1441 { 1442 if (BITSET_P (f->mask, regno - GP_REG_FIRST)) 1443 { 1444 rtx mem = gen_rtx_MEM (SImode, 1445 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)); 1446 rtx reg = gen_rtx_REG (SImode, regno); 1447 if (!crtl->calls_eh_return) 1448 MEM_READONLY_P (mem) = 1; 1449 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg))); 1450 } 1451 } 1452 1453 if (size > 0) 1454 { 1455 rtx insn; 1456 1457 if (CONST_OK_FOR_LETTER_P (-size, 'L')) 1458 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx, 1459 stack_pointer_rtx, 1460 GEN_INT (-size)))); 1461 else 1462 { 1463 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM), 1464 GEN_INT (size))); 1465 EMIT_PL (emit_insn 1466 (gen_sub3_insn (stack_pointer_rtx, 1467 stack_pointer_rtx, 1468 gen_rtx_REG (Pmode, 1469 SCORE7_PROLOGUE_TEMP_REGNUM)))); 1470 } 1471 insn = get_last_insn (); 1472 REG_NOTES (insn) = 1473 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, 1474 gen_rtx_SET (VOIDmode, stack_pointer_rtx, 1475 plus_constant (stack_pointer_rtx, 1476 -size)), 1477 REG_NOTES (insn)); 1478 } 1479 1480 if (frame_pointer_needed) 1481 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); 1482 1483 if (flag_pic && f->cprestore_size) 1484 { 1485 if (frame_pointer_needed) 1486 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size))); 1487 else 1488 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size))); 1489 } 1490 1491#undef EMIT_PL 1492} 1493 1494/* Generate the epilogue instructions in a S+core function. */ 1495void 1496score7_epilogue (int sibcall_p) 1497{ 1498 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ()); 1499 HOST_WIDE_INT size; 1500 int regno; 1501 rtx base; 1502 1503 size = f->total_size - f->gp_reg_size; 1504 1505 if (!frame_pointer_needed) 1506 base = stack_pointer_rtx; 1507 else 1508 base = hard_frame_pointer_rtx; 1509 1510 if (size) 1511 { 1512 if (CONST_OK_FOR_LETTER_P (size, 'L')) 1513 emit_insn (gen_add3_insn (base, base, GEN_INT (size))); 1514 else 1515 { 1516 emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM), 1517 GEN_INT (size)); 1518 emit_insn (gen_add3_insn (base, base, 1519 gen_rtx_REG (Pmode, 1520 SCORE7_EPILOGUE_TEMP_REGNUM))); 1521 } 1522 } 1523 1524 if (base != stack_pointer_rtx) 1525 emit_move_insn (stack_pointer_rtx, base); 1526 1527 if (crtl->calls_eh_return) 1528 emit_insn (gen_add3_insn (stack_pointer_rtx, 1529 stack_pointer_rtx, 1530 EH_RETURN_STACKADJ_RTX)); 1531 1532 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++) 1533 { 1534 if (BITSET_P (f->mask, regno - GP_REG_FIRST)) 1535 { 1536 rtx mem = gen_rtx_MEM (SImode, 1537 gen_rtx_POST_INC (SImode, stack_pointer_rtx)); 1538 rtx reg = gen_rtx_REG (SImode, regno); 1539 1540 if (!crtl->calls_eh_return) 1541 MEM_READONLY_P (mem) = 1; 1542 1543 emit_insn (gen_popsi_score7 (reg, mem)); 1544 } 1545 } 1546 1547 if (!sibcall_p) 1548 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM))); 1549} 1550 1551/* Return true if X is a symbolic constant that can be calculated in 1552 the same way as a bare symbol. If it is, store the type of the 1553 symbol in *SYMBOL_TYPE. */ 1554int 1555score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) 1556{ 1557 HOST_WIDE_INT offset; 1558 1559 score7_split_const (x, &x, &offset); 1560 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) 1561 *symbol_type = score7_classify_symbol (x); 1562 else 1563 return 0; 1564 1565 if (offset == 0) 1566 return 1; 1567 1568 /* if offset > 15bit, must reload */ 1569 if (!IMM_IN_RANGE (offset, 15, 1)) 1570 return 0; 1571 1572 switch (*symbol_type) 1573 { 1574 case SYMBOL_GENERAL: 1575 return 1; 1576 case SYMBOL_SMALL_DATA: 1577 return score7_offset_within_object_p (x, offset); 1578 } 1579 gcc_unreachable (); 1580} 1581 1582void 1583score7_movsicc (rtx *ops) 1584{ 1585 enum machine_mode mode; 1586 1587 mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]); 1588 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM), 1589 gen_rtx_COMPARE (mode, XEXP (ops[1], 0), 1590 XEXP (ops[1], 1)))); 1591} 1592 1593/* Call and sibcall pattern all need call this function. */ 1594void 1595score7_call (rtx *ops, bool sib) 1596{ 1597 rtx addr = XEXP (ops[0], 0); 1598 if (!call_insn_operand (addr, VOIDmode)) 1599 { 1600 rtx oaddr = addr; 1601 addr = gen_reg_rtx (Pmode); 1602 gen_move_insn (addr, oaddr); 1603 } 1604 1605 if (sib) 1606 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1])); 1607 else 1608 emit_call_insn (gen_call_internal_score7 (addr, ops[1])); 1609} 1610 1611/* Call value and sibcall value pattern all need call this function. */ 1612void 1613score7_call_value (rtx *ops, bool sib) 1614{ 1615 rtx result = ops[0]; 1616 rtx addr = XEXP (ops[1], 0); 1617 rtx arg = ops[2]; 1618 1619 if (!call_insn_operand (addr, VOIDmode)) 1620 { 1621 rtx oaddr = addr; 1622 addr = gen_reg_rtx (Pmode); 1623 gen_move_insn (addr, oaddr); 1624 } 1625 1626 if (sib) 1627 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg)); 1628 else 1629 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg)); 1630} 1631 1632/* Machine Split */ 1633void 1634score7_movdi (rtx *ops) 1635{ 1636 rtx dst = ops[0]; 1637 rtx src = ops[1]; 1638 rtx dst0 = score7_subw (dst, 0); 1639 rtx dst1 = score7_subw (dst, 1); 1640 rtx src0 = score7_subw (src, 0); 1641 rtx src1 = score7_subw (src, 1); 1642 1643 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src)) 1644 { 1645 emit_move_insn (dst1, src1); 1646 emit_move_insn (dst0, src0); 1647 } 1648 else 1649 { 1650 emit_move_insn (dst0, src0); 1651 emit_move_insn (dst1, src1); 1652 } 1653} 1654 1655void 1656score7_zero_extract_andi (rtx *ops) 1657{ 1658 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode)) 1659 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2])); 1660 else 1661 { 1662 unsigned HOST_WIDE_INT mask; 1663 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U)); 1664 mask = mask << INTVAL (ops[2]); 1665 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0], 1666 gen_int_mode (mask, SImode))); 1667 } 1668} 1669 1670/* Check addr could be present as PRE/POST mode. */ 1671static bool 1672score7_pindex_mem (rtx addr) 1673{ 1674 if (GET_CODE (addr) == MEM) 1675 { 1676 switch (GET_CODE (XEXP (addr, 0))) 1677 { 1678 case PRE_DEC: 1679 case POST_DEC: 1680 case PRE_INC: 1681 case POST_INC: 1682 return true; 1683 default: 1684 break; 1685 } 1686 } 1687 return false; 1688} 1689 1690/* Output asm code for ld/sw insn. */ 1691static int 1692score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit) 1693{ 1694 struct score7_address_info ai; 1695 1696 gcc_assert (GET_CODE (ops[idata]) == REG); 1697 gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true)); 1698 1699 if (!score7_pindex_mem (ops[iaddr]) 1700 && ai.type == SCORE7_ADD_REG 1701 && GET_CODE (ai.offset) == CONST_INT 1702 && G16_REG_P (REGNO (ops[idata])) 1703 && G16_REG_P (REGNO (ai.reg))) 1704 { 1705 if (INTVAL (ai.offset) == 0) 1706 { 1707 ops[iaddr] = ai.reg; 1708 return snprintf (ip, INS_BUF_SZ, 1709 "!\t%%%d, [%%%d]", idata, iaddr); 1710 } 1711 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM) 1712 { 1713 HOST_WIDE_INT offset = INTVAL (ai.offset); 1714 if (SCORE_ALIGN_UNIT (offset, unit) 1715 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J')) 1716 { 1717 ops[iaddr] = ai.offset; 1718 return snprintf (ip, INS_BUF_SZ, 1719 "p!\t%%%d, %%c%d", idata, iaddr); 1720 } 1721 } 1722 } 1723 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr); 1724} 1725 1726/* Output asm insn for load. */ 1727const char * 1728score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign) 1729{ 1730 const char *pre_ins[] = 1731 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"}; 1732 char *ip; 1733 1734 strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]); 1735 ip = score7_ins + strlen (score7_ins); 1736 1737 if ((!sign && unit != SCORE_HWORD) 1738 || (sign && unit != SCORE_BYTE)) 1739 score7_pr_addr_post (ops, 0, 1, ip, unit); 1740 else 1741 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1"); 1742 1743 return score7_ins; 1744} 1745 1746/* Output asm insn for store. */ 1747const char * 1748score7_sinsn (rtx *ops, enum score_mem_unit unit) 1749{ 1750 const char *pre_ins[] = {"sb", "sh", "sw"}; 1751 char *ip; 1752 1753 strcpy (score7_ins, pre_ins[unit]); 1754 ip = score7_ins + strlen (score7_ins); 1755 score7_pr_addr_post (ops, 1, 0, ip, unit); 1756 return score7_ins; 1757} 1758 1759/* Output asm insn for load immediate. */ 1760const char * 1761score7_limm (rtx *ops) 1762{ 1763 HOST_WIDE_INT v; 1764 1765 gcc_assert (GET_CODE (ops[0]) == REG); 1766 gcc_assert (GET_CODE (ops[1]) == CONST_INT); 1767 1768 v = INTVAL (ops[1]); 1769 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0)) 1770 return "ldiu!\t%0, %c1"; 1771 else if (IMM_IN_RANGE (v, 16, 1)) 1772 return "ldi\t%0, %c1"; 1773 else if ((v & 0xffff) == 0) 1774 return "ldis\t%0, %U1"; 1775 else 1776 return "li\t%0, %c1"; 1777} 1778 1779/* Output asm insn for move. */ 1780const char * 1781score7_move (rtx *ops) 1782{ 1783 gcc_assert (GET_CODE (ops[0]) == REG); 1784 gcc_assert (GET_CODE (ops[1]) == REG); 1785 1786 if (G16_REG_P (REGNO (ops[0]))) 1787 { 1788 if (G16_REG_P (REGNO (ops[1]))) 1789 return "mv!\t%0, %1"; 1790 else 1791 return "mlfh!\t%0, %1"; 1792 } 1793 else if (G16_REG_P (REGNO (ops[1]))) 1794 return "mhfl!\t%0, %1"; 1795 else 1796 return "mv\t%0, %1"; 1797} 1798 1799/* Generate add insn. */ 1800const char * 1801score7_select_add_imm (rtx *ops, bool set_cc) 1802{ 1803 HOST_WIDE_INT v = INTVAL (ops[2]); 1804 1805 gcc_assert (GET_CODE (ops[2]) == CONST_INT); 1806 gcc_assert (REGNO (ops[0]) == REGNO (ops[1])); 1807 1808 if (set_cc && G16_REG_P (REGNO (ops[0]))) 1809 { 1810 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15)) 1811 { 1812 ops[2] = GEN_INT (ffs (v) - 1); 1813 return "addei!\t%0, %c2"; 1814 } 1815 1816 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15)) 1817 { 1818 ops[2] = GEN_INT (ffs (-v) - 1); 1819 return "subei!\t%0, %c2"; 1820 } 1821 } 1822 1823 if (set_cc) 1824 return "addi.c\t%0, %c2"; 1825 else 1826 return "addi\t%0, %c2"; 1827} 1828 1829/* Output arith insn. */ 1830const char * 1831score7_select (rtx *ops, const char *inst_pre, 1832 bool commu, const char *letter, bool set_cc) 1833{ 1834 gcc_assert (GET_CODE (ops[0]) == REG); 1835 gcc_assert (GET_CODE (ops[1]) == REG); 1836 1837 if (set_cc && G16_REG_P (REGNO (ops[0])) 1838 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1) 1839 && REGNO (ops[0]) == REGNO (ops[1])) 1840 { 1841 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter); 1842 return score7_ins; 1843 } 1844 1845 if (commu && set_cc && G16_REG_P (REGNO (ops[0])) 1846 && G16_REG_P (REGNO (ops[1])) 1847 && REGNO (ops[0]) == REGNO (ops[2])) 1848 { 1849 gcc_assert (GET_CODE (ops[2]) == REG); 1850 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter); 1851 return score7_ins; 1852 } 1853 1854 if (set_cc) 1855 snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter); 1856 else 1857 snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter); 1858 return score7_ins; 1859} 1860 1861