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