|
|
1.1 ! root 1: /* Subroutines for insn-output.c for MIPS ! 2: Contributed by A. Lichnewsky, [email protected]. ! 3: Changes by Michael Meissner, [email protected]. ! 4: Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc. ! 5: ! 6: This file is part of GNU CC. ! 7: ! 8: GNU CC is free software; you can redistribute it and/or modify ! 9: it under the terms of the GNU General Public License as published by ! 10: the Free Software Foundation; either version 2, or (at your option) ! 11: any later version. ! 12: ! 13: GNU CC is distributed in the hope that it will be useful, ! 14: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: GNU General Public License for more details. ! 17: ! 18: You should have received a copy of the GNU General Public License ! 19: along with GNU CC; see the file COPYING. If not, write to ! 20: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 21: ! 22: #include "config.h" ! 23: #include "rtl.h" ! 24: #include "regs.h" ! 25: #include "hard-reg-set.h" ! 26: #include "real.h" ! 27: #include "insn-config.h" ! 28: #include "conditions.h" ! 29: #include "insn-flags.h" ! 30: #include "insn-attr.h" ! 31: #include "insn-codes.h" ! 32: #include "recog.h" ! 33: #include "output.h" ! 34: ! 35: #undef MAX /* sys/param.h may also define these */ ! 36: #undef MIN ! 37: ! 38: #include <stdio.h> ! 39: #include <signal.h> ! 40: #include <sys/types.h> ! 41: #include <sys/file.h> ! 42: #include <ctype.h> ! 43: #include "tree.h" ! 44: #include "expr.h" ! 45: #include "flags.h" ! 46: ! 47: #ifndef R_OK ! 48: #define R_OK 4 ! 49: #define W_OK 2 ! 50: #define X_OK 1 ! 51: #endif ! 52: ! 53: #ifdef USG ! 54: #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ ! 55: #else ! 56: #include <stab.h> /* On BSD, use the system's stab.h. */ ! 57: #endif /* not USG */ ! 58: ! 59: #ifdef __GNU_STAB__ ! 60: #define STAB_CODE_TYPE enum __stab_debug_code ! 61: #else ! 62: #define STAB_CODE_TYPE int ! 63: #endif ! 64: ! 65: extern char *getenv (); ! 66: ! 67: extern char *permalloc (); ! 68: extern void debug_rtx (); ! 69: extern void abort_with_insn (); ! 70: extern rtx copy_to_reg (); ! 71: extern rtx adj_offsettable_operand (); ! 72: extern int offsettable_address_p (); ! 73: extern tree lookup_name (); ! 74: ! 75: extern rtx gen_movqi (); ! 76: extern rtx gen_movhi (); ! 77: extern rtx gen_movsi (); ! 78: extern rtx gen_movsi_ulw (); ! 79: extern rtx gen_movsi_usw (); ! 80: extern rtx gen_addsi3 (); ! 81: extern rtx gen_iorsi3 (); ! 82: extern rtx gen_andsi3 (); ! 83: extern rtx gen_bne (); ! 84: extern rtx gen_beq (); ! 85: extern rtx gen_cmpsi (); ! 86: extern rtx gen_jump (); ! 87: ! 88: extern char call_used_regs[]; ! 89: extern char *asm_file_name; ! 90: extern FILE *asm_out_file; ! 91: extern tree current_function_decl; ! 92: extern char **save_argv; ! 93: extern char *version_string; ! 94: extern char *language_string; ! 95: ! 96: /* Global variables for machine-dependent things. */ ! 97: ! 98: /* Threshold for data being put into the small data/bss area, instead ! 99: of the normal data area (references to the small data/bss area take ! 100: 1 instruction, and use the global pointer, references to the normal ! 101: data area takes 2 instructions). */ ! 102: int mips_section_threshold = -1; ! 103: ! 104: /* Count the number of .file directives, so that .loc is up to date. */ ! 105: int num_source_filenames = 0; ! 106: ! 107: /* Count of the number of functions created so far, in order to make ! 108: unique labels for omitting the frame pointer. */ ! 109: int number_functions_processed = 0; ! 110: ! 111: /* Count the number of sdb related labels are generated (to find block ! 112: start and end boundaries). */ ! 113: int sdb_label_count = 0; ! 114: ! 115: /* Next label # for each statment for Silicon Graphics IRIS systems. */ ! 116: int sym_lineno = 0; ! 117: ! 118: /* Non-zero if inside of a function, because the stupid MIPS asm can't ! 119: handle .files inside of functions. */ ! 120: int inside_function = 0; ! 121: ! 122: /* Files to separate the text and the data output, so that all of the data ! 123: can be emitted before the text, which will mean that the assembler will ! 124: generate smaller code, based on the global pointer. */ ! 125: FILE *asm_out_data_file; ! 126: FILE *asm_out_text_file; ! 127: ! 128: /* Linked list of all externals that are to be emitted when optimizing ! 129: for the global pointer if they haven't been declared by the end of ! 130: the program with an appropriate .comm or initialization. */ ! 131: ! 132: struct extern_list { ! 133: struct extern_list *next; /* next external */ ! 134: char *name; /* name of the external */ ! 135: int size; /* size in bytes */ ! 136: } *extern_head = 0; ! 137: ! 138: /* Name of the current function. */ ! 139: char *current_function_name; ! 140: ! 141: /* Name of the file containing the current function. */ ! 142: char *current_function_file = ""; ! 143: ! 144: /* Warning given that Mips ECOFF can't support changing files ! 145: within a function. */ ! 146: int file_in_function_warning = FALSE; ! 147: ! 148: /* Whether to supress issuing .loc's because the user attempted ! 149: to change the filename within a function. */ ! 150: int ignore_line_number = FALSE; ! 151: ! 152: /* Number of nested .set noreorder, noat, nomacro, and volatile requests. */ ! 153: int set_noreorder; ! 154: int set_noat; ! 155: int set_nomacro; ! 156: int set_volatile; ! 157: ! 158: /* The next branch instruction is a branch likely, not branch normal. */ ! 159: int mips_branch_likely; ! 160: ! 161: /* Count of delay slots and how many are filled. */ ! 162: int dslots_load_total; ! 163: int dslots_load_filled; ! 164: int dslots_jump_total; ! 165: int dslots_jump_filled; ! 166: ! 167: /* # of nops needed by previous insn */ ! 168: int dslots_number_nops; ! 169: ! 170: /* Number of 1/2/3 word references to data items (ie, not jal's). */ ! 171: int num_refs[3]; ! 172: ! 173: /* registers to check for load delay */ ! 174: rtx mips_load_reg, mips_load_reg2, mips_load_reg3, mips_load_reg4; ! 175: ! 176: /* Cached operands, and operator to compare for use in set/branch on ! 177: condition codes. */ ! 178: rtx branch_cmp[2]; ! 179: ! 180: /* what type of branch to use */ ! 181: enum cmp_type branch_type; ! 182: ! 183: /* which cpu are we scheduling for */ ! 184: enum processor_type mips_cpu; ! 185: ! 186: /* which instruction set architecture to use. */ ! 187: int mips_isa; ! 188: ! 189: /* Strings to hold which cpu and instruction set architecture to use. */ ! 190: char *mips_cpu_string; /* for -mcpu=<xxx> */ ! 191: char *mips_isa_string; /* for -mips{1,2,3} */ ! 192: ! 193: /* Array to RTX class classification. At present, we care about ! 194: whether the operator is an add-type operator, or a divide/modulus, ! 195: and if divide/modulus, whether it is unsigned. This is for the ! 196: peephole code. */ ! 197: char mips_rtx_classify[NUM_RTX_CODE]; ! 198: ! 199: /* Array giving truth value on whether or not a given hard register ! 200: can support a given mode. */ ! 201: char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER]; ! 202: ! 203: /* Current frame information calculated by compute_frame_size. */ ! 204: struct mips_frame_info current_frame_info; ! 205: ! 206: /* Zero structure to initialize current_frame_info. */ ! 207: struct mips_frame_info zero_frame_info; ! 208: ! 209: /* Temporary filename used to buffer .text until end of program ! 210: for -mgpopt. */ ! 211: static char *temp_filename; ! 212: ! 213: /* List of all MIPS punctuation characters used by print_operand. */ ! 214: char mips_print_operand_punct[256]; ! 215: ! 216: /* Map GCC register number to debugger register number. */ ! 217: int mips_dbx_regno[FIRST_PSEUDO_REGISTER]; ! 218: ! 219: /* Buffer to use to enclose a load/store operation with %{ %} to ! 220: turn on .set volatile. */ ! 221: static char volatile_buffer[60]; ! 222: ! 223: /* Hardware names for the registers. If -mrnames is used, this ! 224: will be overwritten with mips_sw_reg_names. */ ! 225: ! 226: char mips_reg_names[][8] = ! 227: { ! 228: "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", ! 229: "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", ! 230: "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", ! 231: "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31", ! 232: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", ! 233: "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", ! 234: "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", ! 235: "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", ! 236: "hi", "lo", "$fcr31" ! 237: }; ! 238: ! 239: /* Mips software names for the registers, used to overwrite the ! 240: mips_reg_names array. */ ! 241: ! 242: char mips_sw_reg_names[][8] = ! 243: { ! 244: "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3", ! 245: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", ! 246: "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", ! 247: "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra", ! 248: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", ! 249: "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", ! 250: "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", ! 251: "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", ! 252: "hi", "lo", "$fcr31" ! 253: }; ! 254: ! 255: /* Map hard register number to register class */ ! 256: enum reg_class mips_regno_to_class[] = ! 257: { ! 258: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 259: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 260: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 261: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 262: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 263: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 264: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 265: GR_REGS, GR_REGS, GR_REGS, GR_REGS, ! 266: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 267: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 268: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 269: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 270: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 271: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 272: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 273: FP_REGS, FP_REGS, FP_REGS, FP_REGS, ! 274: HI_REG, LO_REG, ST_REGS ! 275: }; ! 276: ! 277: /* Map register constraint character to register class. */ ! 278: enum reg_class mips_char_to_class[256] = ! 279: { ! 280: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 281: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 282: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 283: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 284: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 285: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 286: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 287: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 288: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 289: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 290: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 291: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 292: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 293: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 294: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 295: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 296: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 297: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 298: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 299: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 300: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 301: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 302: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 303: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 304: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 305: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 306: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 307: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 308: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 309: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 310: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 311: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 312: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 313: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 314: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 315: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 316: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 317: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 318: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 319: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 320: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 321: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 322: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 323: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 324: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 325: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 326: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 327: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 328: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 329: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 330: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 331: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 332: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 333: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 334: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 335: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 336: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 337: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 338: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 339: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 340: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 341: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 342: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 343: NO_REGS, NO_REGS, NO_REGS, NO_REGS, ! 344: }; ! 345: ! 346: ! 347: /* Return truth value of whether OP can be used as an operands ! 348: where a register or 16 bit unsigned integer is needed. */ ! 349: ! 350: int ! 351: uns_arith_operand (op, mode) ! 352: rtx op; ! 353: enum machine_mode mode; ! 354: { ! 355: if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)) ! 356: return TRUE; ! 357: ! 358: return register_operand (op, mode); ! 359: } ! 360: ! 361: /* Return truth value of whether OP can be used as an operands ! 362: where a 16 bit integer is needed */ ! 363: ! 364: int ! 365: arith_operand (op, mode) ! 366: rtx op; ! 367: enum machine_mode mode; ! 368: { ! 369: if (GET_CODE (op) == CONST_INT && SMALL_INT (op)) ! 370: return TRUE; ! 371: ! 372: return register_operand (op, mode); ! 373: } ! 374: ! 375: /* Return truth value of whether OP can be used as an operand in a two ! 376: address arithmetic insn (such as set 123456,%o4) of mode MODE. */ ! 377: ! 378: int ! 379: arith32_operand (op, mode) ! 380: rtx op; ! 381: enum machine_mode mode; ! 382: { ! 383: if (GET_CODE (op) == CONST_INT) ! 384: return TRUE; ! 385: ! 386: return register_operand (op, mode); ! 387: } ! 388: ! 389: /* Return truth value of whether OP is a integer which fits in 16 bits */ ! 390: ! 391: int ! 392: small_int (op, mode) ! 393: rtx op; ! 394: enum machine_mode mode; ! 395: { ! 396: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); ! 397: } ! 398: ! 399: /* Return truth value of whether OP is an integer which is too big to ! 400: be loaded with one instruction. */ ! 401: ! 402: int ! 403: large_int (op, mode) ! 404: rtx op; ! 405: enum machine_mode mode; ! 406: { ! 407: long value; ! 408: ! 409: if (GET_CODE (op) != CONST_INT) ! 410: return FALSE; ! 411: ! 412: value = INTVAL (op); ! 413: if ((value & 0xffff0000) == 0) /* ior reg,$r0,value */ ! 414: return FALSE; ! 415: ! 416: if ((value & 0xffff0000) == 0xffff0000) /* subu reg,$r0,value */ ! 417: return FALSE; ! 418: ! 419: if ((value & 0x0000ffff) == 0) /* lui reg,value>>16 */ ! 420: return FALSE; ! 421: ! 422: return TRUE; ! 423: } ! 424: ! 425: /* Return truth value of whether OP is a register or the constant 0. */ ! 426: ! 427: int ! 428: reg_or_0_operand (op, mode) ! 429: rtx op; ! 430: enum machine_mode mode; ! 431: { ! 432: switch (GET_CODE (op)) ! 433: { ! 434: case CONST_INT: ! 435: return (INTVAL (op) == 0); ! 436: ! 437: case CONST_DOUBLE: ! 438: if (CONST_DOUBLE_HIGH (op) != 0 || CONST_DOUBLE_LOW (op) != 0) ! 439: return FALSE; ! 440: ! 441: return TRUE; ! 442: ! 443: case REG: ! 444: case SUBREG: ! 445: return register_operand (op, mode); ! 446: } ! 447: ! 448: return FALSE; ! 449: } ! 450: ! 451: /* Return truth value of whether OP is one of the special multiply/divide ! 452: registers (hi, lo). */ ! 453: ! 454: int ! 455: md_register_operand (op, mode) ! 456: rtx op; ! 457: enum machine_mode mode; ! 458: { ! 459: return (GET_MODE_CLASS (mode) == MODE_INT ! 460: && GET_CODE (op) == REG ! 461: && MD_REG_P (REGNO (op))); ! 462: } ! 463: ! 464: /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */ ! 465: ! 466: int ! 467: mips_const_double_ok (op, mode) ! 468: rtx op; ! 469: enum machine_mode mode; ! 470: { ! 471: if (GET_CODE (op) != CONST_DOUBLE) ! 472: return FALSE; ! 473: ! 474: if (mode == DImode) ! 475: return TRUE; ! 476: ! 477: if (mode != SFmode && mode != DFmode) ! 478: return FALSE; ! 479: ! 480: if (CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0) ! 481: return TRUE; ! 482: ! 483: #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT ! 484: if (TARGET_MIPS_AS) /* gas doesn't like li.d/li.s yet */ ! 485: { ! 486: union { double d; int i[2]; } u; ! 487: double d; ! 488: ! 489: u.i[0] = CONST_DOUBLE_LOW (op); ! 490: u.i[1] = CONST_DOUBLE_HIGH (op); ! 491: d = u.d; ! 492: ! 493: if (d != d) ! 494: return FALSE; /* NAN */ ! 495: ! 496: if (d < 0.0) ! 497: d = - d; ! 498: ! 499: /* Rather than trying to get the accuracy down to the last bit, ! 500: just use approximate ranges. */ ! 501: ! 502: if (mode == DFmode && d > 1.0e-300 && d < 1.0e300) ! 503: return TRUE; ! 504: ! 505: if (mode == SFmode && d > 1.0e-38 && d < 1.0e+38) ! 506: return TRUE; ! 507: } ! 508: #endif ! 509: ! 510: return FALSE; ! 511: } ! 512: ! 513: /* Return truth value if a memory operand fits in a single instruction ! 514: (ie, register + small offset). */ ! 515: ! 516: int ! 517: simple_memory_operand (op, mode) ! 518: rtx op; ! 519: enum machine_mode mode; ! 520: { ! 521: rtx addr, plus0, plus1; ! 522: int offset = 0; ! 523: ! 524: /* Eliminate non-memory operations */ ! 525: if (GET_CODE (op) != MEM) ! 526: return FALSE; ! 527: ! 528: /* dword operations really put out 2 instructions, so eliminate them. */ ! 529: if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) ! 530: return FALSE; ! 531: ! 532: /* Decode the address now. */ ! 533: addr = XEXP (op, 0); ! 534: switch (GET_CODE (addr)) ! 535: { ! 536: case REG: ! 537: return TRUE; ! 538: ! 539: case CONST_INT: ! 540: return SMALL_INT (op); ! 541: ! 542: case PLUS: ! 543: plus0 = XEXP (addr, 0); ! 544: plus1 = XEXP (addr, 1); ! 545: if (GET_CODE (plus0) == REG ! 546: && GET_CODE (plus1) == CONST_INT ! 547: && SMALL_INT (plus1)) ! 548: return TRUE; ! 549: ! 550: else if (GET_CODE (plus1) == REG ! 551: && GET_CODE (plus0) == CONST_INT ! 552: && SMALL_INT (plus0)) ! 553: return TRUE; ! 554: ! 555: else ! 556: return FALSE; ! 557: ! 558: #if 0 ! 559: /* We used to allow small symbol refs here (ie, stuff in .sdata ! 560: or .sbss), but this causes some bugs in G++. Also, it won't ! 561: interfere if the MIPS linker rewrites the store instruction ! 562: because the function is PIC. */ ! 563: ! 564: case LABEL_REF: /* never gp relative */ ! 565: break; ! 566: ! 567: case CONST: ! 568: /* If -G 0, we can never have a GP relative memory operation. ! 569: Also, save some time if not optimizing. */ ! 570: if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT) ! 571: return FALSE; ! 572: ! 573: addr = eliminate_constant_term (addr, &offset); ! 574: if (GET_CODE (op) != SYMBOL_REF) ! 575: return FALSE; ! 576: ! 577: /* fall through */ ! 578: ! 579: case SYMBOL_REF: ! 580: /* let's be paranoid.... */ ! 581: if (offset < 0 || offset > 0xffff) ! 582: return FALSE; ! 583: ! 584: return SYMBOL_REF_FLAG (addr); ! 585: #endif ! 586: } ! 587: ! 588: return FALSE; ! 589: } ! 590: ! 591: /* Return true if the address is suitable for function call. */ ! 592: ! 593: int ! 594: call_memory_operand (op, mode) ! 595: rtx op; ! 596: enum machine_mode mode; ! 597: { ! 598: rtx addr; ! 599: enum rtx_code code; ! 600: ! 601: if (GET_CODE (op) != MEM) ! 602: return FALSE; ! 603: ! 604: addr = XEXP (op, 0); ! 605: code = GET_CODE (addr); ! 606: ! 607: if (GET_MODE (addr) != FUNCTION_MODE) ! 608: return FALSE; ! 609: ! 610: if (code == REG || code == SUBREG) ! 611: return TRUE; ! 612: ! 613: if (CONSTANT_ADDRESS_P (addr)) ! 614: return TRUE; ! 615: ! 616: return FALSE; ! 617: } ! 618: ! 619: /* Return true if the code of this rtx pattern is EQ or NE. */ ! 620: ! 621: int ! 622: equality_op (op, mode) ! 623: rtx op; ! 624: enum machine_mode mode; ! 625: { ! 626: if (mode != GET_MODE (op)) ! 627: return FALSE; ! 628: ! 629: return (classify_op (op, mode) & CLASS_EQUALITY_OP) != 0; ! 630: } ! 631: ! 632: /* Return true if the code is a relational operations (EQ, LE, etc.) */ ! 633: ! 634: int ! 635: cmp_op (op, mode) ! 636: rtx op; ! 637: enum machine_mode mode; ! 638: { ! 639: if (mode != GET_MODE (op)) ! 640: return FALSE; ! 641: ! 642: return (classify_op (op, mode) & CLASS_CMP_OP) != 0; ! 643: } ! 644: ! 645: ! 646: /* Genrecog does not take the type of match_operator into consideration, ! 647: and would complain about two patterns being the same if the same ! 648: function is used, so make it believe they are different. */ ! 649: ! 650: int ! 651: cmp2_op (op, mode) ! 652: rtx op; ! 653: enum machine_mode mode; ! 654: { ! 655: if (mode != GET_MODE (op)) ! 656: return FALSE; ! 657: ! 658: return (classify_op (op, mode) & CLASS_CMP_OP) != 0; ! 659: } ! 660: ! 661: /* Return true if the code is an unsigned relational operations (LEU, etc.) */ ! 662: ! 663: int ! 664: uns_cmp_op (op,mode) ! 665: rtx op; ! 666: enum machine_mode mode; ! 667: { ! 668: if (mode != GET_MODE (op)) ! 669: return FALSE; ! 670: ! 671: return (classify_op (op, mode) & CLASS_UNS_CMP_OP) == CLASS_UNS_CMP_OP; ! 672: } ! 673: ! 674: /* Return true if the code is a relational operation FP can use. */ ! 675: ! 676: int ! 677: fcmp_op (op, mode) ! 678: rtx op; ! 679: enum machine_mode mode; ! 680: { ! 681: if (mode != GET_MODE (op)) ! 682: return FALSE; ! 683: ! 684: return (classify_op (op, mode) & CLASS_FCMP_OP) != 0; ! 685: } ! 686: ! 687: ! 688: /* Return an operand string if the given instruction's delay slot or ! 689: wrap it in a .set noreorder section. This is for filling delay ! 690: slots on load type instructions under GAS, which does no reordering ! 691: on its own. For the MIPS assembler, all we do is update the filled ! 692: delay slot statistics. ! 693: ! 694: We assume that operands[0] is the target register that is set. ! 695: ! 696: In order to check the next insn, most of this functionality is moved ! 697: to FINAL_PRESCAN_INSN, and we just set the global variables that ! 698: it needs. */ ! 699: ! 700: char * ! 701: mips_fill_delay_slot (ret, type, operands, cur_insn) ! 702: char *ret; /* normal string to return */ ! 703: enum delay_type type; /* type of delay */ ! 704: rtx operands[]; /* operands to use */ ! 705: rtx cur_insn; /* current insn */ ! 706: { ! 707: register rtx set_reg; ! 708: register enum machine_mode mode; ! 709: register rtx next_insn = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0; ! 710: register int num_nops; ! 711: ! 712: if (type == DELAY_LOAD) ! 713: num_nops = 1; ! 714: ! 715: else if (type == DELAY_HILO) ! 716: num_nops = 2; ! 717: ! 718: else ! 719: num_nops = 0; ! 720: ! 721: /* Make sure that we don't put nop's after labels. */ ! 722: next_insn = NEXT_INSN (cur_insn); ! 723: while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE) ! 724: next_insn = NEXT_INSN (next_insn); ! 725: ! 726: dslots_load_total += num_nops; ! 727: if (TARGET_DEBUG_F_MODE ! 728: || !optimize ! 729: || type == DELAY_NONE ! 730: || operands == (rtx *)0 ! 731: || cur_insn == (rtx)0 ! 732: || next_insn == (rtx)0 ! 733: || GET_CODE (next_insn) == CODE_LABEL ! 734: || (set_reg = operands[0]) == (rtx)0) ! 735: { ! 736: dslots_number_nops = 0; ! 737: mips_load_reg = (rtx)0; ! 738: mips_load_reg2 = (rtx)0; ! 739: mips_load_reg3 = (rtx)0; ! 740: mips_load_reg4 = (rtx)0; ! 741: return ret; ! 742: } ! 743: ! 744: set_reg = operands[0]; ! 745: if (set_reg == (rtx)0) ! 746: return ret; ! 747: ! 748: while (GET_CODE (set_reg) == SUBREG) ! 749: set_reg = SUBREG_REG (set_reg); ! 750: ! 751: mode = GET_MODE (set_reg); ! 752: dslots_number_nops = num_nops; ! 753: mips_load_reg = set_reg; ! 754: mips_load_reg2 = (mode == DImode || mode == DFmode) ! 755: ? gen_rtx (REG, SImode, REGNO (set_reg) + 1) ! 756: : (rtx)0; ! 757: ! 758: if (type == DELAY_HILO) ! 759: { ! 760: mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST); ! 761: mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1); ! 762: } ! 763: else ! 764: { ! 765: mips_load_reg3 = 0; ! 766: mips_load_reg4 = 0; ! 767: } ! 768: ! 769: if (TARGET_GAS && set_noreorder++ == 0) ! 770: fputs ("\t.set\tnoreorder\n", asm_out_file); ! 771: ! 772: return ret; ! 773: } ! 774: ! 775: ! 776: /* Determine whether a memory reference takes one (based off of the GP pointer), ! 777: two (normal), or three (label + reg) instructins, and bump the appropriate ! 778: counter for -mstats. */ ! 779: ! 780: void ! 781: mips_count_memory_refs (op, num) ! 782: rtx op; ! 783: int num; ! 784: { ! 785: int additional = 0; ! 786: int n_words = 0; ! 787: rtx addr, plus0, plus1; ! 788: enum rtx_code code0, code1; ! 789: int looping; ! 790: ! 791: if (TARGET_DEBUG_B_MODE) ! 792: { ! 793: fprintf (stderr, "\n========== mips_count_memory_refs:\n"); ! 794: debug_rtx (op); ! 795: } ! 796: ! 797: /* Skip MEM if passed, otherwise handle movsi of address. */ ! 798: addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0); ! 799: ! 800: /* Loop, going through the address RTL */ ! 801: do ! 802: { ! 803: looping = FALSE; ! 804: switch (GET_CODE (addr)) ! 805: { ! 806: case REG: ! 807: case CONST_INT: ! 808: break; ! 809: ! 810: case PLUS: ! 811: plus0 = XEXP (addr, 0); ! 812: plus1 = XEXP (addr, 1); ! 813: code0 = GET_CODE (plus0); ! 814: code1 = GET_CODE (plus1); ! 815: ! 816: if (code0 == REG) ! 817: { ! 818: additional++; ! 819: addr = plus1; ! 820: looping = TRUE; ! 821: continue; ! 822: } ! 823: ! 824: if (code0 == CONST_INT) ! 825: { ! 826: addr = plus1; ! 827: looping = TRUE; ! 828: continue; ! 829: } ! 830: ! 831: if (code1 == REG) ! 832: { ! 833: additional++; ! 834: addr = plus0; ! 835: looping = TRUE; ! 836: continue; ! 837: } ! 838: ! 839: if (code1 == CONST_INT) ! 840: { ! 841: addr = plus0; ! 842: looping = TRUE; ! 843: continue; ! 844: } ! 845: ! 846: if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST) ! 847: { ! 848: addr = plus0; ! 849: looping = TRUE; ! 850: continue; ! 851: } ! 852: ! 853: if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST) ! 854: { ! 855: addr = plus1; ! 856: looping = TRUE; ! 857: continue; ! 858: } ! 859: ! 860: break; ! 861: ! 862: case LABEL_REF: ! 863: n_words = 2; /* always 2 words */ ! 864: break; ! 865: ! 866: case CONST: ! 867: addr = XEXP (addr, 0); ! 868: looping = TRUE; ! 869: continue; ! 870: ! 871: case SYMBOL_REF: ! 872: n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2; ! 873: break; ! 874: } ! 875: } ! 876: while (looping); ! 877: ! 878: if (n_words == 0) ! 879: return; ! 880: ! 881: n_words += additional; ! 882: if (n_words > 3) ! 883: n_words = 3; ! 884: ! 885: num_refs[n_words-1] += num; ! 886: } ! 887: ! 888: ! 889: /* Return the appropriate instructions to move one operand to another. */ ! 890: ! 891: char * ! 892: mips_move_1word (operands, insn, unsignedp) ! 893: rtx operands[]; ! 894: rtx insn; ! 895: int unsignedp; ! 896: { ! 897: char *ret = 0; ! 898: rtx op0 = operands[0]; ! 899: rtx op1 = operands[1]; ! 900: enum rtx_code code0 = GET_CODE (op0); ! 901: enum rtx_code code1 = GET_CODE (op1); ! 902: enum machine_mode mode = GET_MODE (op0); ! 903: int subreg_word0 = 0; ! 904: int subreg_word1 = 0; ! 905: enum delay_type delay = DELAY_NONE; ! 906: ! 907: while (code0 == SUBREG) ! 908: { ! 909: subreg_word0 += SUBREG_WORD (op0); ! 910: op0 = SUBREG_REG (op0); ! 911: code0 = GET_CODE (op0); ! 912: } ! 913: ! 914: while (code1 == SUBREG) ! 915: { ! 916: subreg_word1 += SUBREG_WORD (op1); ! 917: op1 = SUBREG_REG (op1); ! 918: code1 = GET_CODE (op1); ! 919: } ! 920: ! 921: if (code0 == REG) ! 922: { ! 923: int regno0 = REGNO (op0) + subreg_word0; ! 924: ! 925: if (code1 == REG) ! 926: { ! 927: int regno1 = REGNO (op1) + subreg_word1; ! 928: ! 929: /* Just in case, don't do anything for assigning a register ! 930: to itself, unless we are filling a delay slot. */ ! 931: if (regno0 == regno1 && set_nomacro == 0) ! 932: ret = ""; ! 933: ! 934: else if (GP_REG_P (regno0)) ! 935: { ! 936: if (GP_REG_P (regno1)) ! 937: ret = "move\t%0,%1"; ! 938: ! 939: else if (MD_REG_P (regno1)) ! 940: { ! 941: delay = DELAY_HILO; ! 942: ret = "mf%1\t%0"; ! 943: } ! 944: ! 945: else ! 946: { ! 947: delay = DELAY_LOAD; ! 948: if (FP_REG_P (regno1)) ! 949: ret = "mfc1\t%0,%1"; ! 950: ! 951: else if (regno1 == FPSW_REGNUM) ! 952: ret = "cfc1\t%0,$31"; ! 953: } ! 954: } ! 955: ! 956: else if (FP_REG_P (regno0)) ! 957: { ! 958: if (GP_REG_P (regno1)) ! 959: { ! 960: delay = DELAY_LOAD; ! 961: ret = "mtc1\t%1,%0"; ! 962: } ! 963: ! 964: if (FP_REG_P (regno1)) ! 965: ret = "mov.s\t%0,%1"; ! 966: } ! 967: ! 968: else if (MD_REG_P (regno0)) ! 969: { ! 970: if (GP_REG_P (regno1)) ! 971: { ! 972: delay = DELAY_HILO; ! 973: ret = "mt%0\t%1"; ! 974: } ! 975: } ! 976: ! 977: else if (regno0 == FPSW_REGNUM) ! 978: { ! 979: if (GP_REG_P (regno1)) ! 980: { ! 981: delay = DELAY_LOAD; ! 982: ret = "ctc1\t%0,$31"; ! 983: } ! 984: } ! 985: } ! 986: ! 987: else if (code1 == MEM) ! 988: { ! 989: delay = DELAY_LOAD; ! 990: ! 991: if (TARGET_STATS) ! 992: mips_count_memory_refs (op1, 1); ! 993: ! 994: if (GP_REG_P (regno0)) ! 995: { ! 996: /* For loads, use the mode of the memory item, instead of the ! 997: target, so zero/sign extend can use this code as well. */ ! 998: switch (GET_MODE (op1)) ! 999: { ! 1000: case SFmode: ret = "lw\t%0,%1"; break; ! 1001: case SImode: ret = "lw\t%0,%1"; break; ! 1002: case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break; ! 1003: case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break; ! 1004: } ! 1005: } ! 1006: ! 1007: else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode)) ! 1008: ret = "l.s\t%0,%1"; ! 1009: ! 1010: if (ret != (char *)0 && MEM_VOLATILE_P (op1)) ! 1011: { ! 1012: int i = strlen (ret); ! 1013: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) ! 1014: abort (); ! 1015: ! 1016: sprintf (volatile_buffer, "%%{%s%%}", ret); ! 1017: ret = volatile_buffer; ! 1018: } ! 1019: } ! 1020: ! 1021: else if (code1 == CONST_INT) ! 1022: { ! 1023: if (INTVAL (op1) == 0) ! 1024: { ! 1025: if (GP_REG_P (regno0)) ! 1026: ret = "move\t%0,%z1"; ! 1027: ! 1028: else if (FP_REG_P (regno0)) ! 1029: { ! 1030: delay = DELAY_LOAD; ! 1031: return "mtc1\t%z1,%0"; ! 1032: } ! 1033: } ! 1034: ! 1035: else if (GP_REG_P (regno0)) ! 1036: { ! 1037: if ((INTVAL (operands[1]) & 0x0000ffff) == 0) ! 1038: ret = "lui\t%0,(%X1)>>16"; ! 1039: else ! 1040: ret = "li\t%0,%1"; ! 1041: } ! 1042: } ! 1043: ! 1044: else if (code1 == CONST_DOUBLE && mode == SFmode) ! 1045: { ! 1046: if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) ! 1047: { ! 1048: if (GP_REG_P (regno0)) ! 1049: ret = "move\t%0,%."; ! 1050: ! 1051: else if (FP_REG_P (regno0)) ! 1052: { ! 1053: delay = DELAY_LOAD; ! 1054: ret = "mtc1\t%.,%0"; ! 1055: } ! 1056: } ! 1057: ! 1058: else ! 1059: { ! 1060: delay = DELAY_LOAD; ! 1061: ret = "li.s\t%0,%1"; ! 1062: } ! 1063: } ! 1064: ! 1065: else if (code1 == LABEL_REF) ! 1066: ret = "la\t%0,%a1"; ! 1067: ! 1068: else if (code1 == SYMBOL_REF || code1 == CONST) ! 1069: { ! 1070: if (TARGET_STATS) ! 1071: mips_count_memory_refs (op1, 1); ! 1072: ! 1073: if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1)) ! 1074: { ! 1075: delay = DELAY_LOAD; ! 1076: ret = "la\t%0,%a1\t\t# pic reference"; ! 1077: } ! 1078: else ! 1079: ret = "la\t%0,%a1"; ! 1080: } ! 1081: ! 1082: else if (code1 == PLUS) ! 1083: { ! 1084: rtx add_op0 = XEXP (op1, 0); ! 1085: rtx add_op1 = XEXP (op1, 1); ! 1086: ! 1087: if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT) ! 1088: { ! 1089: add_op0 = XEXP (op1, 1); /* reverse operands */ ! 1090: add_op1 = XEXP (op1, 0); ! 1091: } ! 1092: ! 1093: operands[2] = add_op0; ! 1094: operands[3] = add_op1; ! 1095: ret = "add%:\t%0,%2,%3"; ! 1096: } ! 1097: } ! 1098: ! 1099: else if (code0 == MEM) ! 1100: { ! 1101: if (TARGET_STATS) ! 1102: mips_count_memory_refs (op0, 1); ! 1103: ! 1104: if (code1 == REG) ! 1105: { ! 1106: int regno1 = REGNO (op1) + subreg_word1; ! 1107: ! 1108: if (GP_REG_P (regno1)) ! 1109: { ! 1110: switch (mode) ! 1111: { ! 1112: case SFmode: ret = "sw\t%1,%0"; break; ! 1113: case SImode: ret = "sw\t%1,%0"; break; ! 1114: case HImode: ret = "sh\t%1,%0"; break; ! 1115: case QImode: ret = "sb\t%1,%0"; break; ! 1116: } ! 1117: } ! 1118: ! 1119: else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode)) ! 1120: ret = "s.s\t%1,%0"; ! 1121: } ! 1122: ! 1123: else if (code1 == CONST_INT && INTVAL (op1) == 0) ! 1124: { ! 1125: switch (mode) ! 1126: { ! 1127: case SFmode: ret = "sw\t%z1,%0"; break; ! 1128: case SImode: ret = "sw\t%z1,%0"; break; ! 1129: case HImode: ret = "sh\t%z1,%0"; break; ! 1130: case QImode: ret = "sb\t%z1,%0"; break; ! 1131: } ! 1132: } ! 1133: ! 1134: else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) ! 1135: { ! 1136: switch (mode) ! 1137: { ! 1138: case SFmode: ret = "sw\t%.,%0"; break; ! 1139: case SImode: ret = "sw\t%.,%0"; break; ! 1140: case HImode: ret = "sh\t%.,%0"; break; ! 1141: case QImode: ret = "sb\t%.,%0"; break; ! 1142: } ! 1143: } ! 1144: ! 1145: if (ret != (char *)0 && MEM_VOLATILE_P (op0)) ! 1146: { ! 1147: int i = strlen (ret); ! 1148: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) ! 1149: abort (); ! 1150: ! 1151: sprintf (volatile_buffer, "%%{%s%%}", ret); ! 1152: ret = volatile_buffer; ! 1153: } ! 1154: } ! 1155: ! 1156: if (ret == (char *)0) ! 1157: { ! 1158: abort_with_insn (insn, "Bad move"); ! 1159: return 0; ! 1160: } ! 1161: ! 1162: if (delay != DELAY_NONE) ! 1163: return mips_fill_delay_slot (ret, delay, operands, insn); ! 1164: ! 1165: return ret; ! 1166: } ! 1167: ! 1168: ! 1169: /* Return the appropriate instructions to move 2 words */ ! 1170: ! 1171: char * ! 1172: mips_move_2words (operands, insn) ! 1173: rtx operands[]; ! 1174: rtx insn; ! 1175: { ! 1176: char *ret = 0; ! 1177: rtx op0 = operands[0]; ! 1178: rtx op1 = operands[1]; ! 1179: enum rtx_code code0 = GET_CODE (operands[0]); ! 1180: enum rtx_code code1 = GET_CODE (operands[1]); ! 1181: int subreg_word0 = 0; ! 1182: int subreg_word1 = 0; ! 1183: enum delay_type delay = DELAY_NONE; ! 1184: ! 1185: while (code0 == SUBREG) ! 1186: { ! 1187: subreg_word0 += SUBREG_WORD (op0); ! 1188: op0 = SUBREG_REG (op0); ! 1189: code0 = GET_CODE (op0); ! 1190: } ! 1191: ! 1192: while (code1 == SUBREG) ! 1193: { ! 1194: subreg_word1 += SUBREG_WORD (op1); ! 1195: op1 = SUBREG_REG (op1); ! 1196: code1 = GET_CODE (op1); ! 1197: } ! 1198: ! 1199: if (code0 == REG) ! 1200: { ! 1201: int regno0 = REGNO (op0) + subreg_word0; ! 1202: ! 1203: if (code1 == REG) ! 1204: { ! 1205: int regno1 = REGNO (op1) + subreg_word1; ! 1206: ! 1207: /* Just in case, don't do anything for assigning a register ! 1208: to itself, unless we are filling a delay slot. */ ! 1209: if (regno0 == regno1 && set_nomacro == 0) ! 1210: ret = ""; ! 1211: ! 1212: else if (FP_REG_P (regno0)) ! 1213: { ! 1214: if (FP_REG_P (regno1)) ! 1215: ret = "mov.d\t%0,%1"; ! 1216: ! 1217: else ! 1218: { ! 1219: delay = DELAY_LOAD; ! 1220: ret = (TARGET_FLOAT64) ! 1221: ? "dmtc1\t%1,%0" ! 1222: : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; ! 1223: } ! 1224: } ! 1225: ! 1226: else if (FP_REG_P (regno1)) ! 1227: { ! 1228: delay = DELAY_LOAD; ! 1229: ret = (TARGET_FLOAT64) ! 1230: ? "dmfc1\t%0,%1" ! 1231: : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; ! 1232: } ! 1233: ! 1234: else if (MD_REG_P (regno0) && GP_REG_P (regno1)) ! 1235: { ! 1236: delay = DELAY_HILO; ! 1237: ret = "mthi\t%M1\n\tmtlo\t%L1"; ! 1238: } ! 1239: ! 1240: else if (GP_REG_P (regno0) && MD_REG_P (regno1)) ! 1241: { ! 1242: delay = DELAY_HILO; ! 1243: ret = "mfhi\t%M0\n\tmflo\t%L0"; ! 1244: } ! 1245: ! 1246: else if (regno0 != (regno1+1)) ! 1247: ret = "move\t%0,%1\n\tmove\t%D0,%D1"; ! 1248: ! 1249: else ! 1250: ret = "move\t%D0,%D1\n\tmove\t%0,%1"; ! 1251: } ! 1252: ! 1253: else if (code1 == CONST_DOUBLE) ! 1254: { ! 1255: if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0) ! 1256: { ! 1257: if (GET_MODE (op1) == DFmode) ! 1258: { ! 1259: delay = DELAY_LOAD; ! 1260: ret = "li.d\t%0,%1"; ! 1261: } ! 1262: ! 1263: else ! 1264: { ! 1265: operands[2] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (op1)); ! 1266: operands[3] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (op1)); ! 1267: ret = "li\t%M0,%3\n\tli\t%L0,%2"; ! 1268: } ! 1269: } ! 1270: ! 1271: else ! 1272: { ! 1273: if (GP_REG_P (regno0)) ! 1274: ret = "move\t%0,%.\n\tmove\t%D0,%."; ! 1275: ! 1276: else if (FP_REG_P (regno0)) ! 1277: { ! 1278: delay = DELAY_LOAD; ! 1279: ret = (TARGET_FLOAT64) ! 1280: ? "dmtc1\t%.,%0" ! 1281: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; ! 1282: } ! 1283: } ! 1284: } ! 1285: ! 1286: else if (code1 == CONST_INT && INTVAL (op1) == 0) ! 1287: { ! 1288: if (GP_REG_P (regno0)) ! 1289: ret = "move\t%0,%.\n\tmove\t%D0,%."; ! 1290: ! 1291: else if (FP_REG_P (regno0)) ! 1292: { ! 1293: delay = DELAY_LOAD; ! 1294: ret = (TARGET_FLOAT64) ! 1295: ? "dmtc1\t%.,%0" ! 1296: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; ! 1297: } ! 1298: } ! 1299: ! 1300: else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) ! 1301: { ! 1302: operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >= 0 ? 0 : -1); ! 1303: ret = "li\t%M0,%2\n\tli\t%L0,%1"; ! 1304: } ! 1305: ! 1306: else if (code1 == MEM) ! 1307: { ! 1308: delay = DELAY_LOAD; ! 1309: ! 1310: if (TARGET_STATS) ! 1311: mips_count_memory_refs (op1, 2); ! 1312: ! 1313: if (FP_REG_P (regno0)) ! 1314: ret = "l.d\t%0,%1"; ! 1315: ! 1316: else if (offsettable_address_p (1, DFmode, XEXP (op1, 0))) ! 1317: { ! 1318: operands[2] = adj_offsettable_operand (op1, 4); ! 1319: if (reg_mentioned_p (op0, op1)) ! 1320: ret = "lw\t%D0,%2\n\tlw\t%0,%1"; ! 1321: else ! 1322: ret = "lw\t%0,%1\n\tlw\t%D0,%2"; ! 1323: } ! 1324: ! 1325: if (ret != (char *)0 && MEM_VOLATILE_P (op1)) ! 1326: { ! 1327: int i = strlen (ret); ! 1328: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) ! 1329: abort (); ! 1330: ! 1331: sprintf (volatile_buffer, "%%{%s%%}", ret); ! 1332: ret = volatile_buffer; ! 1333: } ! 1334: } ! 1335: } ! 1336: ! 1337: else if (code0 == MEM) ! 1338: { ! 1339: if (code1 == REG) ! 1340: { ! 1341: int regno1 = REGNO (op1) + subreg_word1; ! 1342: ! 1343: if (FP_REG_P (regno1)) ! 1344: ret = "s.d\t%1,%0"; ! 1345: ! 1346: else if (offsettable_address_p (1, DFmode, XEXP (op0, 0))) ! 1347: { ! 1348: operands[2] = adj_offsettable_operand (op0, 4); ! 1349: ret = "sw\t%1,%0\n\tsw\t%D1,%2"; ! 1350: } ! 1351: } ! 1352: ! 1353: else if (code1 == CONST_DOUBLE ! 1354: && CONST_DOUBLE_HIGH (op1) == 0 ! 1355: && CONST_DOUBLE_LOW (op1) == 0 ! 1356: && offsettable_address_p (1, DFmode, XEXP (op0, 0))) ! 1357: { ! 1358: if (TARGET_FLOAT64) ! 1359: ret = "sd\t%.,%0"; ! 1360: else ! 1361: { ! 1362: operands[2] = adj_offsettable_operand (op0, 4); ! 1363: ret = "sw\t%.,%0\n\tsw\t%.,%2"; ! 1364: } ! 1365: } ! 1366: ! 1367: if (TARGET_STATS) ! 1368: mips_count_memory_refs (op0, 2); ! 1369: ! 1370: if (ret != (char *)0 && MEM_VOLATILE_P (op0)) ! 1371: { ! 1372: int i = strlen (ret); ! 1373: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) ! 1374: abort (); ! 1375: ! 1376: sprintf (volatile_buffer, "%%{%s%%}", ret); ! 1377: ret = volatile_buffer; ! 1378: } ! 1379: } ! 1380: ! 1381: if (ret == (char *)0) ! 1382: { ! 1383: abort_with_insn (insn, "Bad move"); ! 1384: return 0; ! 1385: } ! 1386: ! 1387: if (delay != DELAY_NONE) ! 1388: return mips_fill_delay_slot (ret, delay, operands, insn); ! 1389: ! 1390: return ret; ! 1391: } ! 1392: ! 1393: ! 1394: /* Provide the costs of an addressing mode that contains ADDR. ! 1395: If ADDR is not a valid address, its cost is irrelavent. */ ! 1396: ! 1397: int ! 1398: mips_address_cost (addr) ! 1399: rtx addr; ! 1400: { ! 1401: int offset; ! 1402: ! 1403: switch (GET_CODE (addr)) ! 1404: { ! 1405: case LO_SUM: ! 1406: case HIGH: ! 1407: return 1; ! 1408: ! 1409: case LABEL_REF: ! 1410: return 2; ! 1411: ! 1412: case CONST: ! 1413: offset = 0; ! 1414: addr = eliminate_constant_term (addr, &offset); ! 1415: if (GET_CODE (addr) == LABEL_REF) ! 1416: return 2; ! 1417: ! 1418: if (GET_CODE (addr) != SYMBOL_REF) ! 1419: return 4; ! 1420: ! 1421: if (offset < -32768 || offset > 32767) ! 1422: return 2; ! 1423: ! 1424: /* fall through */ ! 1425: ! 1426: case SYMBOL_REF: ! 1427: return SYMBOL_REF_FLAG (addr) ? 1 : 2; ! 1428: ! 1429: case PLUS: ! 1430: { ! 1431: register rtx plus0 = XEXP (addr, 0); ! 1432: register rtx plus1 = XEXP (addr, 1); ! 1433: ! 1434: if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG) ! 1435: { ! 1436: plus0 = XEXP (addr, 1); ! 1437: plus1 = XEXP (addr, 0); ! 1438: } ! 1439: ! 1440: if (GET_CODE (plus0) != REG) ! 1441: break; ! 1442: ! 1443: switch (GET_CODE (plus1)) ! 1444: { ! 1445: case CONST_INT: ! 1446: { ! 1447: int value = INTVAL (plus1); ! 1448: return (value < -32768 || value > 32767) ? 2 : 1; ! 1449: } ! 1450: ! 1451: case CONST: ! 1452: case SYMBOL_REF: ! 1453: case LABEL_REF: ! 1454: case HIGH: ! 1455: case LO_SUM: ! 1456: return mips_address_cost (plus1) + 1; ! 1457: } ! 1458: } ! 1459: } ! 1460: ! 1461: return 4; ! 1462: } ! 1463: ! 1464: ! 1465: /* Emit the common code for doing conditional branches. ! 1466: operand[0] is the label to jump to. ! 1467: The comparison operands are saved away by cmp{si,sf,df}. */ ! 1468: ! 1469: void ! 1470: gen_conditional_branch (operands, test_code) ! 1471: rtx operands[]; ! 1472: enum rtx_code test_code; ! 1473: { ! 1474: enum { ! 1475: I_EQ, ! 1476: I_NE, ! 1477: I_GT, ! 1478: I_GE, ! 1479: I_LT, ! 1480: I_LE, ! 1481: I_GTU, ! 1482: I_GEU, ! 1483: I_LTU, ! 1484: I_LEU, ! 1485: I_MAX ! 1486: } test = I_MAX; ! 1487: ! 1488: static enum machine_mode mode_map[(int)CMP_MAX][(int)I_MAX] = { ! 1489: { /* CMP_SI */ ! 1490: CC_EQmode, /* eq */ ! 1491: CC_EQmode, /* ne */ ! 1492: CCmode, /* gt */ ! 1493: CCmode, /* ge */ ! 1494: CCmode, /* lt */ ! 1495: CCmode, /* le */ ! 1496: CCmode, /* gtu */ ! 1497: CCmode, /* geu */ ! 1498: CCmode, /* ltu */ ! 1499: CCmode, /* leu */ ! 1500: }, ! 1501: { /* CMP_SF */ ! 1502: CC_FPmode, /* eq */ ! 1503: CC_FPmode, /* ne */ ! 1504: CC_FPmode, /* gt */ ! 1505: CC_FPmode, /* ge */ ! 1506: CC_FPmode, /* lt */ ! 1507: CC_FPmode, /* le */ ! 1508: VOIDmode, /* gtu */ ! 1509: VOIDmode, /* geu */ ! 1510: VOIDmode, /* ltu */ ! 1511: VOIDmode, /* leu */ ! 1512: }, ! 1513: { /* CMP_DF */ ! 1514: CC_FPmode, /* eq */ ! 1515: CC_FPmode, /* ne */ ! 1516: CC_FPmode, /* gt */ ! 1517: CC_FPmode, /* ge */ ! 1518: CC_FPmode, /* lt */ ! 1519: CC_FPmode, /* le */ ! 1520: VOIDmode, /* gtu */ ! 1521: VOIDmode, /* geu */ ! 1522: VOIDmode, /* ltu */ ! 1523: VOIDmode, /* leu */ ! 1524: }, ! 1525: }; ! 1526: ! 1527: enum machine_mode mode; ! 1528: enum cmp_type type = branch_type; ! 1529: rtx cmp0 = branch_cmp[0]; ! 1530: rtx cmp1 = branch_cmp[1]; ! 1531: rtx label = gen_rtx (LABEL_REF, VOIDmode, operands[0]); ! 1532: ! 1533: /* Make normal rtx_code into something we can index from an array */ ! 1534: switch (test_code) ! 1535: { ! 1536: case EQ: test = I_EQ; break; ! 1537: case NE: test = I_NE; break; ! 1538: case GT: test = I_GT; break; ! 1539: case GE: test = I_GE; break; ! 1540: case LT: test = I_LT; break; ! 1541: case LE: test = I_LE; break; ! 1542: case GTU: test = I_GTU; break; ! 1543: case GEU: test = I_GEU; break; ! 1544: case LTU: test = I_LTU; break; ! 1545: case LEU: test = I_LEU; break; ! 1546: } ! 1547: ! 1548: if (test == I_MAX) ! 1549: { ! 1550: mode = CCmode; ! 1551: goto fail; ! 1552: } ! 1553: ! 1554: /* Get the machine mode to use (CCmode, CC_EQmode, or CC_FPmode). */ ! 1555: mode = mode_map[(int)type][(int)test]; ! 1556: if (mode == VOIDmode) ! 1557: goto fail; ! 1558: ! 1559: switch (branch_type) ! 1560: { ! 1561: default: ! 1562: goto fail; ! 1563: ! 1564: case CMP_SI: ! 1565: /* Change >, >=, <, <= tests against 0 to use CC_0mode, since we have ! 1566: special instructions to do these tests directly. */ ! 1567: ! 1568: if (mode == CCmode && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) ! 1569: { ! 1570: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, cmp0)); ! 1571: mode = CC_0mode; ! 1572: } ! 1573: ! 1574: else if (mode == CCmode && GET_CODE (cmp0) == CONST_INT && INTVAL (cmp0) == 0) ! 1575: { ! 1576: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, cmp1)); ! 1577: test_code = reverse_condition (test_code); ! 1578: mode = CC_0mode; ! 1579: } ! 1580: ! 1581: else ! 1582: { ! 1583: /* force args to register for equality comparisons. */ ! 1584: if (mode == CC_EQmode && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) ! 1585: cmp1 = force_reg (SImode, cmp1); ! 1586: ! 1587: emit_insn (gen_rtx (SET, VOIDmode, ! 1588: cc0_rtx, ! 1589: gen_rtx (COMPARE, mode, cmp0, cmp1))); ! 1590: } ! 1591: break; ! 1592: ! 1593: case CMP_DF: ! 1594: emit_insn (gen_cmpdf_internal (cmp0, cmp1)); ! 1595: break; ! 1596: ! 1597: case CMP_SF: ! 1598: emit_insn (gen_cmpsf_internal (cmp0, cmp1)); ! 1599: break; ! 1600: } ! 1601: ! 1602: /* Generate the jump */ ! 1603: emit_jump_insn (gen_rtx (SET, VOIDmode, ! 1604: pc_rtx, ! 1605: gen_rtx (IF_THEN_ELSE, VOIDmode, ! 1606: gen_rtx (test_code, mode, cc0_rtx, const0_rtx), ! 1607: label, ! 1608: pc_rtx))); ! 1609: return; ! 1610: ! 1611: fail: ! 1612: abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test"); ! 1613: } ! 1614: ! 1615: ! 1616: #define UNITS_PER_SHORT (SHORT_TYPE_SIZE / BITS_PER_UNIT) ! 1617: ! 1618: /* Internal code to generate the load and store of one word/short/byte. ! 1619: The load is emitted directly, and the store insn is returned. */ ! 1620: ! 1621: static rtx ! 1622: block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align) ! 1623: rtx src_reg; /* register holding source memory addresss */ ! 1624: rtx dest_reg; /* register holding dest. memory addresss */ ! 1625: int *p_bytes; /* pointer to # bytes remaining */ ! 1626: int *p_offset; /* pointer to current offset */ ! 1627: int align; /* alignment */ ! 1628: { ! 1629: int bytes; /* # bytes remaining */ ! 1630: int offset; /* offset to use */ ! 1631: int size; /* size in bytes of load/store */ ! 1632: enum machine_mode mode; /* mode to use for load/store */ ! 1633: rtx reg; /* temporary register */ ! 1634: rtx src_addr; /* source address */ ! 1635: rtx dest_addr; /* destintation address */ ! 1636: rtx (*load_func)(); /* function to generate load insn */ ! 1637: rtx (*store_func)(); /* function to generate destination insn */ ! 1638: ! 1639: bytes = *p_bytes; ! 1640: if (bytes <= 0 || align <= 0) ! 1641: abort (); ! 1642: ! 1643: if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD) ! 1644: { ! 1645: mode = SImode; ! 1646: size = UNITS_PER_WORD; ! 1647: load_func = gen_movsi; ! 1648: store_func = gen_movsi; ! 1649: } ! 1650: ! 1651: else if (bytes >= UNITS_PER_WORD) ! 1652: { ! 1653: mode = SImode; ! 1654: size = UNITS_PER_WORD; ! 1655: load_func = gen_movsi_ulw; ! 1656: store_func = gen_movsi_usw; ! 1657: } ! 1658: ! 1659: else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT) ! 1660: { ! 1661: mode = HImode; ! 1662: size = UNITS_PER_SHORT; ! 1663: load_func = gen_movhi; ! 1664: store_func = gen_movhi; ! 1665: } ! 1666: ! 1667: else ! 1668: { ! 1669: mode = QImode; ! 1670: size = 1; ! 1671: load_func = gen_movqi; ! 1672: store_func = gen_movqi; ! 1673: } ! 1674: ! 1675: offset = *p_offset; ! 1676: *p_offset = offset + size; ! 1677: *p_bytes = bytes - size; ! 1678: ! 1679: if (offset == 0) ! 1680: { ! 1681: src_addr = src_reg; ! 1682: dest_addr = dest_reg; ! 1683: } ! 1684: else ! 1685: { ! 1686: src_addr = gen_rtx (PLUS, Pmode, src_reg, gen_rtx (CONST_INT, VOIDmode, offset)); ! 1687: dest_addr = gen_rtx (PLUS, Pmode, dest_reg, gen_rtx (CONST_INT, VOIDmode, offset)); ! 1688: } ! 1689: ! 1690: reg = gen_reg_rtx (mode); ! 1691: emit_insn ((*load_func) (reg, gen_rtx (MEM, mode, src_addr))); ! 1692: return (*store_func) (gen_rtx (MEM, mode, dest_addr), reg); ! 1693: } ! 1694: ! 1695: ! 1696: /* Write a series of loads/stores to move some bytes. Generate load/stores as follows: ! 1697: ! 1698: load 1 ! 1699: load 2 ! 1700: load 3 ! 1701: store 1 ! 1702: load 4 ! 1703: store 2 ! 1704: load 5 ! 1705: store 3 ! 1706: ... ! 1707: ! 1708: This way, no NOP's are needed, except at the end, and only ! 1709: two temp registers are needed. Two delay slots are used ! 1710: in deference to the R4000. */ ! 1711: ! 1712: static void ! 1713: block_move_sequence (dest_reg, src_reg, bytes, align) ! 1714: rtx dest_reg; /* register holding destination address */ ! 1715: rtx src_reg; /* register holding source address */ ! 1716: int bytes; /* # bytes to move */ ! 1717: int align; /* max alignment to assume */ ! 1718: { ! 1719: int offset = 0; ! 1720: rtx prev2_store = (rtx)0; ! 1721: rtx prev_store = (rtx)0; ! 1722: rtx cur_store = (rtx)0; ! 1723: ! 1724: while (bytes > 0) ! 1725: { ! 1726: /* Is there a store to do? */ ! 1727: if (prev2_store) ! 1728: emit_insn (prev2_store); ! 1729: ! 1730: prev2_store = prev_store; ! 1731: prev_store = cur_store; ! 1732: cur_store = block_move_load_store (dest_reg, src_reg, &bytes, &offset, align); ! 1733: } ! 1734: ! 1735: /* Finish up last three stores. */ ! 1736: if (prev2_store) ! 1737: emit_insn (prev2_store); ! 1738: ! 1739: if (prev_store) ! 1740: emit_insn (prev_store); ! 1741: ! 1742: if (cur_store) ! 1743: emit_insn (cur_store); ! 1744: } ! 1745: ! 1746: ! 1747: /* Write a loop to move a constant number of bytes. Generate load/stores as follows: ! 1748: ! 1749: do { ! 1750: temp1 = src[0]; ! 1751: temp2 = src[1]; ! 1752: ... ! 1753: temp<last> = src[MAX_MOVE_REGS-1]; ! 1754: src += MAX_MOVE_REGS; ! 1755: dest[0] = temp1; ! 1756: dest[1] = temp2; ! 1757: ... ! 1758: dest[MAX_MOVE_REGS-1] = temp<last>; ! 1759: dest += MAX_MOVE_REGS; ! 1760: } while (src != final); ! 1761: ! 1762: This way, no NOP's are needed, and only MAX_MOVE_REGS+3 temp ! 1763: registers are needed. ! 1764: ! 1765: Aligned moves move MAX_MOVE_REGS*4 bytes every (2*MAX_MOVE_REGS)+3 ! 1766: cycles, unaligned moves move MAX_MOVE_REGS*4 bytes every ! 1767: (4*MAX_MOVE_REGS)+3 cycles, assuming no cache misses. */ ! 1768: ! 1769: #define MAX_MOVE_REGS 4 ! 1770: #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD) ! 1771: ! 1772: static void ! 1773: block_move_loop (dest_reg, src_reg, bytes, align) ! 1774: rtx dest_reg; /* register holding destination address */ ! 1775: rtx src_reg; /* register holding source address */ ! 1776: int bytes; /* # bytes to move */ ! 1777: int align; /* alignment */ ! 1778: { ! 1779: rtx stores[MAX_MOVE_REGS]; ! 1780: rtx label; ! 1781: rtx final_src; ! 1782: rtx bytes_rtx; ! 1783: int i; ! 1784: int leftover; ! 1785: int offset; ! 1786: ! 1787: if (bytes < 2*MAX_MOVE_BYTES) ! 1788: abort (); ! 1789: ! 1790: leftover = bytes % MAX_MOVE_BYTES; ! 1791: bytes -= leftover; ! 1792: ! 1793: label = gen_label_rtx (); ! 1794: final_src = gen_reg_rtx (Pmode); ! 1795: bytes_rtx = gen_rtx (CONST_INT, VOIDmode, bytes); ! 1796: ! 1797: if (bytes > 0x7fff) ! 1798: { ! 1799: emit_insn (gen_movsi (final_src, bytes_rtx)); ! 1800: emit_insn (gen_addsi3 (final_src, final_src, src_reg)); ! 1801: } ! 1802: else ! 1803: emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx)); ! 1804: ! 1805: emit_label (label); ! 1806: ! 1807: offset = 0; ! 1808: for (i = 0; i < MAX_MOVE_REGS; i++) ! 1809: stores[i] = block_move_load_store (dest_reg, src_reg, &bytes, &offset, align); ! 1810: ! 1811: emit_insn (gen_addsi3 (src_reg, src_reg, gen_rtx (CONST_INT, VOIDmode, MAX_MOVE_BYTES))); ! 1812: for (i = 0; i < MAX_MOVE_REGS; i++) ! 1813: emit_insn (stores[i]); ! 1814: ! 1815: emit_insn (gen_addsi3 (dest_reg, dest_reg, gen_rtx (CONST_INT, VOIDmode, MAX_MOVE_BYTES))); ! 1816: emit_insn (gen_cmpsi (src_reg, final_src)); ! 1817: emit_jump_insn (gen_bne (label)); ! 1818: ! 1819: if (leftover) ! 1820: block_move_sequence (dest_reg, src_reg, leftover, align); ! 1821: } ! 1822: ! 1823: ! 1824: /* Use a library function to move some bytes. */ ! 1825: ! 1826: static void ! 1827: block_move_call (dest_reg, src_reg, bytes_rtx) ! 1828: rtx dest_reg; ! 1829: rtx src_reg; ! 1830: rtx bytes_rtx; ! 1831: { ! 1832: #ifdef TARGET_MEM_FUNCTIONS ! 1833: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, ! 1834: VOIDmode, 3, ! 1835: dest_reg, Pmode, ! 1836: src_reg, Pmode, ! 1837: bytes_rtx, SImode); ! 1838: #else ! 1839: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, ! 1840: VOIDmode, 3, ! 1841: src_reg, Pmode, ! 1842: dest_reg, Pmode, ! 1843: bytes_rtx, SImode); ! 1844: #endif ! 1845: } ! 1846: ! 1847: ! 1848: /* Expand string/block move operations. ! 1849: ! 1850: operands[0] is the pointer to the destination. ! 1851: operands[1] is the pointer to the source. ! 1852: operands[2] is the number of bytes to move. ! 1853: operands[3] is the alignment. */ ! 1854: ! 1855: void ! 1856: expand_block_move (operands) ! 1857: rtx operands[]; ! 1858: { ! 1859: rtx bytes_rtx = operands[2]; ! 1860: int constp = (GET_CODE (bytes_rtx) == CONST_INT); ! 1861: int bytes = (constp ? INTVAL (bytes_rtx) : 0); ! 1862: int align = INTVAL (operands[3]); ! 1863: rtx src_reg; ! 1864: rtx dest_reg; ! 1865: ! 1866: if (constp && bytes <= 0) ! 1867: return; ! 1868: ! 1869: /* Move the address into scratch registers. */ ! 1870: dest_reg = copy_addr_to_reg (XEXP (operands[0], 0)); ! 1871: src_reg = copy_addr_to_reg (XEXP (operands[1], 0)); ! 1872: ! 1873: if (TARGET_MEMCPY) ! 1874: block_move_call (dest_reg, src_reg, bytes_rtx); ! 1875: ! 1876: else if (constp && bytes <= 2*MAX_MOVE_BYTES) ! 1877: block_move_sequence (dest_reg, src_reg, bytes, align); ! 1878: ! 1879: else if (constp && align >= UNITS_PER_WORD && optimize) ! 1880: block_move_loop (dest_reg, src_reg, bytes, align); ! 1881: ! 1882: else if (constp && optimize) ! 1883: { ! 1884: /* If the alignment is not word aligned, generate a test at ! 1885: runtime, to see whether things wound up aligned, and we ! 1886: can use the faster lw/sw instead ulw/usw. */ ! 1887: ! 1888: rtx temp = gen_reg_rtx (Pmode); ! 1889: rtx aligned_label = gen_label_rtx (); ! 1890: rtx join_label = gen_label_rtx (); ! 1891: int leftover = bytes % MAX_MOVE_BYTES; ! 1892: ! 1893: bytes -= leftover; ! 1894: ! 1895: emit_insn (gen_iorsi3 (temp, src_reg, dest_reg)); ! 1896: emit_insn (gen_andsi3 (temp, temp, gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD-1))); ! 1897: emit_insn (gen_cmpsi (temp, const0_rtx)); ! 1898: emit_jump_insn (gen_beq (aligned_label)); ! 1899: ! 1900: /* Unaligned loop. */ ! 1901: block_move_loop (dest_reg, src_reg, bytes, 1); ! 1902: emit_jump_insn (gen_jump (join_label)); ! 1903: emit_barrier (); ! 1904: ! 1905: /* Aligned loop. */ ! 1906: emit_label (aligned_label); ! 1907: block_move_loop (dest_reg, src_reg, bytes, UNITS_PER_WORD); ! 1908: emit_label (join_label); ! 1909: ! 1910: /* Bytes at the end of the loop. */ ! 1911: if (leftover) ! 1912: block_move_sequence (dest_reg, src_reg, leftover, align); ! 1913: } ! 1914: ! 1915: else ! 1916: block_move_call (dest_reg, src_reg, bytes_rtx); ! 1917: } ! 1918: ! 1919: ! 1920: /* Argument support functions. */ ! 1921: ! 1922: /* Initialize CUMULATIVE_ARGS for a function. */ ! 1923: ! 1924: void ! 1925: init_cumulative_args (cum, fntype, libname) ! 1926: CUMULATIVE_ARGS *cum; /* argument info to initialize */ ! 1927: tree fntype; /* tree ptr for function decl */ ! 1928: rtx libname; /* SYMBOL_REF of library name or 0 */ ! 1929: { ! 1930: tree param, next_param; ! 1931: ! 1932: if (TARGET_DEBUG_E_MODE) ! 1933: fprintf (stderr, "\ninit_cumulative_args\n"); ! 1934: ! 1935: cum->gp_reg_found = 0; ! 1936: cum->arg_number = 0; ! 1937: cum->arg_words = 0; ! 1938: ! 1939: /* Determine if this function has variable arguments. This is ! 1940: indicated by the last argument being 'void_type_mode' if there ! 1941: are no variable arguments. The standard MIPS calling sequence ! 1942: passes all arguments in the general purpose registers in this ! 1943: case. */ ! 1944: ! 1945: for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; ! 1946: param != (tree)0; ! 1947: param = next_param) ! 1948: { ! 1949: next_param = TREE_CHAIN (param); ! 1950: if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) ! 1951: cum->gp_reg_found = 1; ! 1952: } ! 1953: ! 1954: /* Determine if the function is returning a structure, if so, ! 1955: advance by one argument. */ ! 1956: ! 1957: if (fntype ! 1958: && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE) ! 1959: && TREE_TYPE (fntype) != 0) ! 1960: { ! 1961: tree ret_type = TREE_TYPE (fntype); ! 1962: enum tree_code ret_code = TREE_CODE (ret_type); ! 1963: ! 1964: if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE) ! 1965: { ! 1966: cum->gp_reg_found = 1; ! 1967: cum->arg_number = 1; ! 1968: cum->arg_words = 1; ! 1969: } ! 1970: } ! 1971: } ! 1972: ! 1973: /* Advance the argument to the next argument position. */ ! 1974: ! 1975: void ! 1976: function_arg_advance (cum, mode, type, named) ! 1977: CUMULATIVE_ARGS *cum; /* current arg information */ ! 1978: enum machine_mode mode; /* current arg mode */ ! 1979: tree type; /* type of the argument or 0 if lib support */ ! 1980: { ! 1981: if (TARGET_DEBUG_E_MODE) ! 1982: fprintf (stderr, ! 1983: "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n", ! 1984: cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), ! 1985: type, named); ! 1986: ! 1987: cum->arg_number++; ! 1988: switch (mode) ! 1989: { ! 1990: default: ! 1991: error ("Illegal mode given to function_arg_advance"); ! 1992: break; ! 1993: ! 1994: case VOIDmode: ! 1995: break; ! 1996: ! 1997: case BLKmode: ! 1998: cum->gp_reg_found = 1; ! 1999: cum->arg_words += (int_size_in_bytes (type) + 3) / 4; ! 2000: break; ! 2001: ! 2002: case SFmode: ! 2003: cum->arg_words++; ! 2004: break; ! 2005: ! 2006: case DFmode: ! 2007: cum->arg_words += 2; ! 2008: break; ! 2009: ! 2010: case DImode: ! 2011: cum->gp_reg_found = 1; ! 2012: cum->arg_words += 2; ! 2013: break; ! 2014: ! 2015: case QImode: ! 2016: case HImode: ! 2017: case SImode: ! 2018: cum->gp_reg_found = 1; ! 2019: cum->arg_words++; ! 2020: break; ! 2021: } ! 2022: } ! 2023: ! 2024: /* Return a RTL expression containing the register for the given mode, ! 2025: or 0 if the argument is too be passed on the stack. */ ! 2026: ! 2027: struct rtx_def * ! 2028: function_arg (cum, mode, type, named) ! 2029: CUMULATIVE_ARGS *cum; /* current arg information */ ! 2030: enum machine_mode mode; /* current arg mode */ ! 2031: tree type; /* type of the argument or 0 if lib support */ ! 2032: int named; /* != 0 for normal args, == 0 for ... args */ ! 2033: { ! 2034: int regbase = -1; ! 2035: int bias = 0; ! 2036: ! 2037: if (TARGET_DEBUG_E_MODE) ! 2038: fprintf (stderr, ! 2039: "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ", ! 2040: cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), ! 2041: type, named); ! 2042: ! 2043: switch (mode) ! 2044: { ! 2045: default: ! 2046: error ("Illegal mode given to function_arg"); ! 2047: break; ! 2048: ! 2049: case SFmode: ! 2050: if (cum->gp_reg_found || cum->arg_number >= 2) ! 2051: regbase = GP_ARG_FIRST; ! 2052: else { ! 2053: regbase = (TARGET_SOFT_FLOAT) ? GP_ARG_FIRST : FP_ARG_FIRST; ! 2054: if (cum->arg_words == 1) /* first arg was float */ ! 2055: bias = 1; /* use correct reg */ ! 2056: } ! 2057: ! 2058: break; ! 2059: ! 2060: case DFmode: ! 2061: cum->arg_words += (cum->arg_words & 1); ! 2062: regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT) ! 2063: ? GP_ARG_FIRST ! 2064: : FP_ARG_FIRST; ! 2065: break; ! 2066: ! 2067: case VOIDmode: ! 2068: case BLKmode: ! 2069: case QImode: ! 2070: case HImode: ! 2071: case SImode: ! 2072: regbase = GP_ARG_FIRST; ! 2073: break; ! 2074: ! 2075: case DImode: ! 2076: cum->arg_words += (cum->arg_words & 1); ! 2077: regbase = GP_ARG_FIRST; ! 2078: } ! 2079: ! 2080: if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) ! 2081: { ! 2082: if (TARGET_DEBUG_E_MODE) ! 2083: fprintf (stderr, "<stack>\n"); ! 2084: ! 2085: return 0; ! 2086: } ! 2087: ! 2088: if (regbase == -1) ! 2089: abort (); ! 2090: ! 2091: if (TARGET_DEBUG_E_MODE) ! 2092: fprintf (stderr, "%s\n", reg_names[regbase + cum->arg_words + bias]); ! 2093: ! 2094: return gen_rtx (REG, mode, regbase + cum->arg_words + bias); ! 2095: } ! 2096: ! 2097: ! 2098: int ! 2099: function_arg_partial_nregs (cum, mode, type, named) ! 2100: CUMULATIVE_ARGS *cum; /* current arg information */ ! 2101: enum machine_mode mode; /* current arg mode */ ! 2102: tree type; /* type of the argument or 0 if lib support */ ! 2103: int named; /* != 0 for normal args, == 0 for ... args */ ! 2104: { ! 2105: if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS) ! 2106: { ! 2107: int words = (int_size_in_bytes (type) + 3) / 4; ! 2108: ! 2109: if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS) ! 2110: return 0; /* structure fits in registers */ ! 2111: ! 2112: if (TARGET_DEBUG_E_MODE) ! 2113: fprintf (stderr, "function_arg_partial_nregs = %d\n", ! 2114: MAX_ARGS_IN_REGISTERS - cum->arg_words); ! 2115: ! 2116: return MAX_ARGS_IN_REGISTERS - cum->arg_words; ! 2117: } ! 2118: ! 2119: else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1) ! 2120: { ! 2121: if (TARGET_DEBUG_E_MODE) ! 2122: fprintf (stderr, "function_arg_partial_nregs = 1\n"); ! 2123: ! 2124: return 1; ! 2125: } ! 2126: ! 2127: return 0; ! 2128: } ! 2129: ! 2130: ! 2131: /* Print the options used in the assembly file. */ ! 2132: ! 2133: static struct {char *name; int value;} target_switches [] ! 2134: = TARGET_SWITCHES; ! 2135: ! 2136: void ! 2137: print_options (out) ! 2138: FILE *out; ! 2139: { ! 2140: int line_len; ! 2141: int len; ! 2142: int j; ! 2143: char **p; ! 2144: int mask = TARGET_DEFAULT; ! 2145: ! 2146: /* Allow assembly language comparisons with -mdebug eliminating the ! 2147: compiler version number and switch lists. */ ! 2148: ! 2149: if (TARGET_DEBUG_MODE) ! 2150: return; ! 2151: ! 2152: fprintf (out, "\n # %s %s", language_string, version_string); ! 2153: #ifdef TARGET_VERSION_INTERNAL ! 2154: TARGET_VERSION_INTERNAL (out); ! 2155: #endif ! 2156: #ifdef __GNUC__ ! 2157: fprintf (out, " compiled by GNU C\n\n"); ! 2158: #else ! 2159: fprintf (out, " compiled by CC\n\n"); ! 2160: #endif ! 2161: ! 2162: fprintf (out, " # Cc1 defaults:"); ! 2163: line_len = 32767; ! 2164: for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++) ! 2165: { ! 2166: if (target_switches[j].name[0] != '\0' ! 2167: && target_switches[j].value > 0 ! 2168: && (target_switches[j].value & mask) == target_switches[j].value) ! 2169: { ! 2170: mask &= ~ target_switches[j].value; ! 2171: len = strlen (target_switches[j].name) + 1; ! 2172: if (len + line_len > 79) ! 2173: { ! 2174: line_len = 2; ! 2175: fputs ("\n #", out); ! 2176: } ! 2177: fprintf (out, " -m%s", target_switches[j].name); ! 2178: line_len += len; ! 2179: } ! 2180: } ! 2181: ! 2182: fprintf (out, "\n\n # Cc1 arguments (-G value = %d, Cpu = %s, ISA = %d):", ! 2183: mips_section_threshold, mips_cpu_string, mips_isa); ! 2184: ! 2185: line_len = 32767; ! 2186: for (p = &save_argv[1]; *p != (char *)0; p++) ! 2187: { ! 2188: char *arg = *p; ! 2189: if (*arg == '-') ! 2190: { ! 2191: len = strlen (arg) + 1; ! 2192: if (len + line_len > 79) ! 2193: { ! 2194: line_len = 2; ! 2195: fputs ("\n #", out); ! 2196: } ! 2197: fprintf (out, " %s", *p); ! 2198: line_len += len; ! 2199: } ! 2200: } ! 2201: ! 2202: fputs ("\n\n", out); ! 2203: } ! 2204: ! 2205: ! 2206: /* Abort after printing out a specific insn. */ ! 2207: ! 2208: void ! 2209: abort_with_insn (insn, reason) ! 2210: rtx insn; ! 2211: char *reason; ! 2212: { ! 2213: error (reason); ! 2214: debug_rtx (insn); ! 2215: abort (); ! 2216: } ! 2217: ! 2218: /* Write a message to stderr (for use in macros expanded in files that do not ! 2219: include stdio.h). */ ! 2220: ! 2221: void ! 2222: trace (s, s1, s2) ! 2223: char *s, *s1, *s2; ! 2224: { ! 2225: fprintf (stderr, s, s1, s2); ! 2226: } ! 2227: ! 2228: ! 2229: #ifdef SIGINFO ! 2230: ! 2231: #include <sys/wait.h> ! 2232: ! 2233: static void ! 2234: siginfo (signo) ! 2235: int signo; ! 2236: { ! 2237: char print_pid[50]; ! 2238: char *argv[4]; ! 2239: pid_t pid; ! 2240: int status; ! 2241: ! 2242: fprintf (stderr, "compiling '%s' in '%s'\n", ! 2243: (current_function_name != (char *)0) ? current_function_name : "<toplevel>", ! 2244: (current_function_file != (char *)0) ? current_function_file : "<no file>"); ! 2245: ! 2246: /* Spawn a ps to tell about current memory usage, etc. */ ! 2247: sprintf (print_pid, "-p%d,%d", getpid (), getppid ()); ! 2248: argv[0] = "ps"; ! 2249: argv[1] = print_pid; ! 2250: argv[2] = "-ouser,state,pid,pri,nice,wchan,tt,start,usertime,systime,pcpu,cp,inblock,oublock,vsize,rss,pmem,ucomm"; ! 2251: argv[3] = (char *)0; ! 2252: ! 2253: pid = vfork (); ! 2254: if (pid == 0) /* child context */ ! 2255: { ! 2256: execv ("/usr/bin/ps", argv); ! 2257: execv ("/usr/sbin/ps", argv); ! 2258: execvp ("ps", argv); ! 2259: perror ("ps"); ! 2260: _exit (1); ! 2261: } ! 2262: ! 2263: else if (pid > 0) /* parent context */ ! 2264: { ! 2265: void (*sigint)(int) = signal (SIGINT, SIG_IGN); ! 2266: void (*sigquit)(int) = signal (SIGQUIT, SIG_IGN); ! 2267: ! 2268: (void) waitpid (pid, &status, 0); ! 2269: ! 2270: (void) signal (SIGINT, sigint); ! 2271: (void) signal (SIGQUIT, sigquit); ! 2272: } ! 2273: ! 2274: signal (SIGINFO, siginfo); ! 2275: } ! 2276: ! 2277: #endif /* SIGINFO */ ! 2278: ! 2279: ! 2280: /* Set up the threshold for data to go into the small data area, instead ! 2281: of the normal data area, and detect any conflicts in the switches. */ ! 2282: ! 2283: void ! 2284: override_options () ! 2285: { ! 2286: register int i, start; ! 2287: register int regno; ! 2288: register enum machine_mode mode; ! 2289: ! 2290: if (g_switch_set) ! 2291: mips_section_threshold = g_switch_value; ! 2292: ! 2293: else ! 2294: mips_section_threshold = (TARGET_MIPS_AS) ? 8 : 0; ! 2295: ! 2296: /* Identify the processor type */ ! 2297: if (mips_cpu_string == (char *)0 ! 2298: || !strcmp (mips_cpu_string, "default") ! 2299: || !strcmp (mips_cpu_string, "DEFAULT")) ! 2300: { ! 2301: mips_cpu_string = "default"; ! 2302: mips_cpu = PROCESSOR_DEFAULT; ! 2303: } ! 2304: ! 2305: else ! 2306: { ! 2307: char *p = mips_cpu_string; ! 2308: ! 2309: if (*p == 'r' || *p == 'R') ! 2310: p++; ! 2311: ! 2312: /* Since there is no difference between a R2000 and R3000 in ! 2313: terms of the scheduler, we collapse them into just an R3000. */ ! 2314: ! 2315: mips_cpu = PROCESSOR_DEFAULT; ! 2316: switch (*p) ! 2317: { ! 2318: case '2': ! 2319: if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K")) ! 2320: mips_cpu = PROCESSOR_R3000; ! 2321: break; ! 2322: ! 2323: case '3': ! 2324: if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K")) ! 2325: mips_cpu = PROCESSOR_R3000; ! 2326: break; ! 2327: ! 2328: case '4': ! 2329: if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K")) ! 2330: mips_cpu = PROCESSOR_R4000; ! 2331: break; ! 2332: ! 2333: case '6': ! 2334: if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K")) ! 2335: mips_cpu = PROCESSOR_R6000; ! 2336: break; ! 2337: } ! 2338: ! 2339: if (mips_cpu == PROCESSOR_DEFAULT) ! 2340: { ! 2341: error ("bad value (%s) for -mcpu= switch", mips_cpu_string); ! 2342: mips_cpu_string = "default"; ! 2343: } ! 2344: } ! 2345: ! 2346: /* Now get the architectural level. */ ! 2347: if (mips_isa_string == (char *)0) ! 2348: mips_isa = 1; ! 2349: ! 2350: else if (isdigit (*mips_isa_string)) ! 2351: mips_isa = atoi (mips_isa_string); ! 2352: ! 2353: else ! 2354: { ! 2355: error ("bad value (%s) for -mips switch", mips_isa_string); ! 2356: mips_isa = 1; ! 2357: } ! 2358: ! 2359: if (mips_isa < 0 || mips_isa > 3) ! 2360: error ("-mips%d not supported", mips_isa); ! 2361: ! 2362: else if (mips_isa > 1 ! 2363: && (mips_cpu == PROCESSOR_DEFAULT || mips_cpu == PROCESSOR_R3000)) ! 2364: error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); ! 2365: ! 2366: else if (mips_cpu == PROCESSOR_R6000 && mips_isa > 2) ! 2367: error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); ! 2368: ! 2369: /* make sure sizes of ints/longs/etc. are ok */ ! 2370: if (mips_isa < 3) ! 2371: { ! 2372: if (TARGET_INT64) ! 2373: fatal ("Only the r4000 can support 64 bit ints"); ! 2374: ! 2375: else if (TARGET_LONG64) ! 2376: fatal ("Only the r4000 can support 64 bit longs"); ! 2377: ! 2378: else if (TARGET_LLONG128) ! 2379: fatal ("Only the r4000 can support 128 bit long longs"); ! 2380: ! 2381: else if (TARGET_FLOAT64) ! 2382: fatal ("Only the r4000 can support 64 bit fp registers"); ! 2383: } ! 2384: else if (TARGET_INT64 || TARGET_LONG64 || TARGET_LLONG128 || TARGET_FLOAT64) ! 2385: warning ("r4000 64/128 bit types not yet supported"); ! 2386: ! 2387: /* Tell halfpic.c that we have half-pic code if we do. */ ! 2388: if (TARGET_HALF_PIC) ! 2389: HALF_PIC_INIT (); ! 2390: ! 2391: /* -mrnames says to use the MIPS software convention for register ! 2392: names instead of the hardware names (ie, a0 instead of $4). ! 2393: We do this by switching the names in mips_reg_names, which the ! 2394: reg_names points into via the REGISTER_NAMES macro. */ ! 2395: ! 2396: if (TARGET_NAME_REGS) ! 2397: { ! 2398: if (TARGET_GAS) ! 2399: { ! 2400: target_flags &= ~ MASK_NAME_REGS; ! 2401: error ("Gas does not support the MIPS software register name convention."); ! 2402: } ! 2403: else ! 2404: bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names)); ! 2405: } ! 2406: ! 2407: /* If this is OSF/1, set up a SIGINFO handler so we can see what function ! 2408: is currently being compiled. */ ! 2409: #ifdef SIGINFO ! 2410: if (getenv ("GCC_SIGINFO") != (char *)0) ! 2411: { ! 2412: struct sigaction action; ! 2413: action.sa_handler = siginfo; ! 2414: action.sa_mask = 0; ! 2415: action.sa_flags = SA_RESTART; ! 2416: sigaction (SIGINFO, &action, (struct sigaction *)0); ! 2417: } ! 2418: #endif ! 2419: ! 2420: /* Set up the classificaiton arrays now. */ ! 2421: mips_rtx_classify[(int)PLUS] = CLASS_ADD_OP; ! 2422: mips_rtx_classify[(int)MINUS] = CLASS_ADD_OP; ! 2423: mips_rtx_classify[(int)DIV] = CLASS_DIVMOD_OP; ! 2424: mips_rtx_classify[(int)MOD] = CLASS_DIVMOD_OP; ! 2425: mips_rtx_classify[(int)UDIV] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP; ! 2426: mips_rtx_classify[(int)UMOD] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP; ! 2427: mips_rtx_classify[(int)EQ] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP; ! 2428: mips_rtx_classify[(int)NE] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP; ! 2429: mips_rtx_classify[(int)GT] = CLASS_CMP_OP | CLASS_FCMP_OP; ! 2430: mips_rtx_classify[(int)GE] = CLASS_CMP_OP | CLASS_FCMP_OP; ! 2431: mips_rtx_classify[(int)LT] = CLASS_CMP_OP | CLASS_FCMP_OP; ! 2432: mips_rtx_classify[(int)LE] = CLASS_CMP_OP | CLASS_FCMP_OP; ! 2433: mips_rtx_classify[(int)GTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; ! 2434: mips_rtx_classify[(int)GEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; ! 2435: mips_rtx_classify[(int)LTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; ! 2436: mips_rtx_classify[(int)LEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; ! 2437: ! 2438: mips_print_operand_punct['?'] = TRUE; ! 2439: mips_print_operand_punct['#'] = TRUE; ! 2440: mips_print_operand_punct['&'] = TRUE; ! 2441: mips_print_operand_punct['!'] = TRUE; ! 2442: mips_print_operand_punct['*'] = TRUE; ! 2443: mips_print_operand_punct['@'] = TRUE; ! 2444: mips_print_operand_punct['.'] = TRUE; ! 2445: mips_print_operand_punct['('] = TRUE; ! 2446: mips_print_operand_punct[')'] = TRUE; ! 2447: mips_print_operand_punct['['] = TRUE; ! 2448: mips_print_operand_punct[']'] = TRUE; ! 2449: mips_print_operand_punct['<'] = TRUE; ! 2450: mips_print_operand_punct['>'] = TRUE; ! 2451: mips_print_operand_punct['{'] = TRUE; ! 2452: mips_print_operand_punct['}'] = TRUE; ! 2453: ! 2454: mips_char_to_class['d'] = GR_REGS; ! 2455: mips_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS); ! 2456: mips_char_to_class['h'] = HI_REG; ! 2457: mips_char_to_class['l'] = LO_REG; ! 2458: mips_char_to_class['s'] = ST_REGS; ! 2459: mips_char_to_class['x'] = MD_REGS; ! 2460: mips_char_to_class['y'] = GR_REGS; ! 2461: ! 2462: /* Set up array to map GCC register number to debug register number. ! 2463: Ignore the special purpose register numbers. */ ! 2464: ! 2465: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 2466: mips_dbx_regno[i] = -1; ! 2467: ! 2468: start = GP_DBX_FIRST - GP_REG_FIRST; ! 2469: for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++) ! 2470: mips_dbx_regno[i] = i + start; ! 2471: ! 2472: start = FP_DBX_FIRST - FP_REG_FIRST; ! 2473: for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++) ! 2474: mips_dbx_regno[i] = i + start; ! 2475: ! 2476: /* Set up array giving whether a given register can hold a given mode. ! 2477: At present, restrict ints from being in FP registers, because reload ! 2478: is a little enthusiastic about storing extra values in FP registers, ! 2479: and this is not good for things like OS kernels. Also, due to the ! 2480: manditory delay, it is as fast to load from cached memory as to move ! 2481: from the FP register. */ ! 2482: ! 2483: for (mode = VOIDmode; ! 2484: mode != MAX_MACHINE_MODE; ! 2485: mode = (enum machine_mode)((int)mode + 1)) ! 2486: { ! 2487: register int size = GET_MODE_SIZE (mode); ! 2488: register enum mode_class class = GET_MODE_CLASS (mode); ! 2489: ! 2490: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) ! 2491: { ! 2492: register int temp = FALSE; ! 2493: ! 2494: if (GP_REG_P (regno)) ! 2495: temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD)); ! 2496: ! 2497: else if (FP_REG_P (regno)) ! 2498: temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)) ! 2499: && (TARGET_DEBUG_H_MODE ! 2500: || class == MODE_FLOAT ! 2501: || class == MODE_COMPLEX_FLOAT)); ! 2502: ! 2503: else if (MD_REG_P (regno)) ! 2504: temp = (mode == SImode || (regno == MD_REG_FIRST && mode == DImode)); ! 2505: ! 2506: else if (ST_REG_P (regno)) ! 2507: temp = ((mode == SImode) || (class == MODE_CC)); ! 2508: ! 2509: mips_hard_regno_mode_ok[(int)mode][regno] = temp; ! 2510: } ! 2511: } ! 2512: } ! 2513: ! 2514: ! 2515: /* ! 2516: * If the frame pointer has been eliminated, the offset for an auto ! 2517: * or argument will be based on the stack pointer. But this is not ! 2518: * what the debugger expects--it needs to find an offset off of the ! 2519: * frame pointer (whether it exists or not). So here we turn all ! 2520: * offsets into those based on the (possibly virtual) frame pointer. ! 2521: */ ! 2522: ! 2523: int ! 2524: mips_debugger_offset (addr, offset) ! 2525: rtx addr; ! 2526: int offset; ! 2527: { ! 2528: int offset2 = 0; ! 2529: rtx reg = eliminate_constant_term (addr, &offset2); ! 2530: ! 2531: if (!offset) ! 2532: offset = offset2; ! 2533: ! 2534: if (reg == stack_pointer_rtx) ! 2535: { ! 2536: int frame_size = (!current_frame_info.initialized) ! 2537: ? compute_frame_size (get_frame_size ()) ! 2538: : current_frame_info.total_size; ! 2539: ! 2540: offset = offset - frame_size; ! 2541: } ! 2542: ! 2543: /* Any other register is, we hope, either the frame pointer, ! 2544: or a pseudo equivalent to the frame pointer. (Assign_parms ! 2545: copies the arg pointer to a pseudo if ARG_POINTER_REGNUM is ! 2546: equal to FRAME_POINTER_REGNUM, so references off of the ! 2547: arg pointer are all off a pseudo.) Seems like all we can ! 2548: do is to just return OFFSET and hope for the best. */ ! 2549: ! 2550: return offset; ! 2551: } ! 2552: ! 2553: /* A C compound statement to output to stdio stream STREAM the ! 2554: assembler syntax for an instruction operand X. X is an RTL ! 2555: expression. ! 2556: ! 2557: CODE is a value that can be used to specify one of several ways ! 2558: of printing the operand. It is used when identical operands ! 2559: must be printed differently depending on the context. CODE ! 2560: comes from the `%' specification that was used to request ! 2561: printing of the operand. If the specification was just `%DIGIT' ! 2562: then CODE is 0; if the specification was `%LTR DIGIT' then CODE ! 2563: is the ASCII code for LTR. ! 2564: ! 2565: If X is a register, this macro should print the register's name. ! 2566: The names can be found in an array `reg_names' whose type is ! 2567: `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. ! 2568: ! 2569: When the machine description has a specification `%PUNCT' (a `%' ! 2570: followed by a punctuation character), this macro is called with ! 2571: a null pointer for X and the punctuation character for CODE. ! 2572: ! 2573: The MIPS specific codes are: ! 2574: ! 2575: 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x", ! 2576: 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x", ! 2577: 'd' output integer constant in decimal, ! 2578: 'z' if the operand is 0, use $0 instead of normal operand. ! 2579: 'D' print second register of double-word register operand. ! 2580: 'L' print low-order register of double-word register operand. ! 2581: 'M' print high-order register of double-word register operand. ! 2582: 'C' print part of opcode for a branch condition. ! 2583: 'N' print part of opcode for a branch condition, inverted. ! 2584: '(' Turn on .set noreorder ! 2585: ')' Turn on .set reorder ! 2586: '[' Turn on .set noat ! 2587: ']' Turn on .set at ! 2588: '<' Turn on .set nomacro ! 2589: '>' Turn on .set macro ! 2590: '{' Turn on .set volatile (not GAS) ! 2591: '}' Turn on .set novolatile (not GAS) ! 2592: '&' Turn on .set noreorder if filling delay slots ! 2593: '*' Turn on both .set noreorder and .set nomacro if filling delay slots ! 2594: '!' Turn on .set nomacro if filling delay slots ! 2595: '#' Print nop if in a .set noreorder section. ! 2596: '?' Print 'l' if we are to use a branch likely instead of normal branch. ! 2597: '@' Print the name of the assembler temporary register (at or $1). ! 2598: '.' Print the name of the register with a hard-wired zero (zero or $0). */ ! 2599: ! 2600: void ! 2601: print_operand (file, op, letter) ! 2602: FILE *file; /* file to write to */ ! 2603: rtx op; /* operand to print */ ! 2604: int letter; /* %<letter> or 0 */ ! 2605: { ! 2606: register enum rtx_code code; ! 2607: ! 2608: if (PRINT_OPERAND_PUNCT_VALID_P (letter)) ! 2609: { ! 2610: switch (letter) ! 2611: { ! 2612: default: ! 2613: error ("PRINT_OPERAND: Unknown punctuation '%c'", letter); ! 2614: break; ! 2615: ! 2616: case '?': ! 2617: if (mips_branch_likely) ! 2618: putc ('l', file); ! 2619: break; ! 2620: ! 2621: case '@': ! 2622: fputs (reg_names [GP_REG_FIRST + 1], file); ! 2623: break; ! 2624: ! 2625: case '.': ! 2626: fputs (reg_names [GP_REG_FIRST + 0], file); ! 2627: break; ! 2628: ! 2629: case '&': ! 2630: if (final_sequence != 0 && set_noreorder++ == 0) ! 2631: fputs (".set\tnoreorder\n\t", file); ! 2632: break; ! 2633: ! 2634: case '*': ! 2635: if (final_sequence != 0) ! 2636: { ! 2637: if (set_noreorder++ == 0) ! 2638: fputs (".set\tnoreorder\n\t", file); ! 2639: ! 2640: if (set_nomacro++ == 0) ! 2641: fputs (".set\tnomacro\n\t", file); ! 2642: } ! 2643: break; ! 2644: ! 2645: case '!': ! 2646: if (final_sequence != 0 && set_nomacro++ == 0) ! 2647: fputs ("\n\t.set\tnomacro", file); ! 2648: break; ! 2649: ! 2650: case '#': ! 2651: if (set_noreorder != 0) ! 2652: fputs ("\n\tnop", file); ! 2653: ! 2654: else if (TARGET_GAS || TARGET_STATS) ! 2655: fputs ("\n\t#nop", file); ! 2656: ! 2657: break; ! 2658: ! 2659: case '(': ! 2660: if (set_noreorder++ == 0) ! 2661: fputs (".set\tnoreorder\n\t", file); ! 2662: break; ! 2663: ! 2664: case ')': ! 2665: if (set_noreorder == 0) ! 2666: error ("internal error: %%) found without a %%( in assembler pattern"); ! 2667: ! 2668: else if (--set_noreorder == 0) ! 2669: fputs ("\n\t.set\treorder", file); ! 2670: ! 2671: break; ! 2672: ! 2673: case '[': ! 2674: if (set_noat++ == 0) ! 2675: fputs (".set\tnoat\n\t", file); ! 2676: break; ! 2677: ! 2678: case ']': ! 2679: if (set_noat == 0) ! 2680: error ("internal error: %%] found without a %%[ in assembler pattern"); ! 2681: ! 2682: else if (--set_noat == 0) ! 2683: fputs ("\n\t.set\tat", file); ! 2684: ! 2685: break; ! 2686: ! 2687: case '<': ! 2688: if (set_nomacro++ == 0) ! 2689: fputs (".set\tnomacro\n\t", file); ! 2690: break; ! 2691: ! 2692: case '>': ! 2693: if (set_nomacro == 0) ! 2694: error ("internal error: %%> found without a %%< in assembler pattern"); ! 2695: ! 2696: else if (--set_nomacro == 0) ! 2697: fputs ("\n\t.set\tmacro", file); ! 2698: ! 2699: break; ! 2700: ! 2701: case '{': ! 2702: if (set_volatile++ == 0) ! 2703: fprintf (file, "%s.set\tvolatile\n\t", (TARGET_MIPS_AS) ? "" : "#"); ! 2704: break; ! 2705: ! 2706: case '}': ! 2707: if (set_volatile == 0) ! 2708: error ("internal error: %%} found without a %%{ in assembler pattern"); ! 2709: ! 2710: else if (--set_volatile == 0) ! 2711: fprintf (file, "\n\t%s.set\tnovolatile", (TARGET_MIPS_AS) ? "" : "#"); ! 2712: ! 2713: break; ! 2714: } ! 2715: return; ! 2716: } ! 2717: ! 2718: if (! op) ! 2719: { ! 2720: error ("PRINT_OPERAND null pointer"); ! 2721: return; ! 2722: } ! 2723: ! 2724: code = GET_CODE (op); ! 2725: if (letter == 'C') ! 2726: switch (code) ! 2727: { ! 2728: case EQ: fputs ("eq", file); break; ! 2729: case NE: fputs ("ne", file); break; ! 2730: case GT: fputs ("gt", file); break; ! 2731: case GE: fputs ("ge", file); break; ! 2732: case LT: fputs ("lt", file); break; ! 2733: case LE: fputs ("le", file); break; ! 2734: case GTU: fputs ("gtu", file); break; ! 2735: case GEU: fputs ("geu", file); break; ! 2736: case LTU: fputs ("ltu", file); break; ! 2737: case LEU: fputs ("leu", file); break; ! 2738: ! 2739: default: ! 2740: abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%C"); ! 2741: } ! 2742: ! 2743: else if (letter == 'N') ! 2744: switch (code) ! 2745: { ! 2746: case EQ: fputs ("ne", file); break; ! 2747: case NE: fputs ("eq", file); break; ! 2748: case GT: fputs ("le", file); break; ! 2749: case GE: fputs ("lt", file); break; ! 2750: case LT: fputs ("ge", file); break; ! 2751: case LE: fputs ("gt", file); break; ! 2752: case GTU: fputs ("leu", file); break; ! 2753: case GEU: fputs ("ltu", file); break; ! 2754: case LTU: fputs ("geu", file); break; ! 2755: case LEU: fputs ("gtu", file); break; ! 2756: ! 2757: default: ! 2758: abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%N"); ! 2759: } ! 2760: ! 2761: else if (code == REG) ! 2762: { ! 2763: register int regnum = REGNO (op); ! 2764: ! 2765: if (letter == 'M') ! 2766: regnum += MOST_SIGNIFICANT_WORD; ! 2767: ! 2768: else if (letter == 'L') ! 2769: regnum += LEAST_SIGNIFICANT_WORD; ! 2770: ! 2771: else if (letter == 'D') ! 2772: regnum++; ! 2773: ! 2774: fprintf (file, "%s", reg_names[regnum]); ! 2775: } ! 2776: ! 2777: else if (code == MEM) ! 2778: output_address (XEXP (op, 0)); ! 2779: ! 2780: else if (code == CONST_DOUBLE) ! 2781: { ! 2782: #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT ! 2783: union { double d; int i[2]; } u; ! 2784: u.i[0] = CONST_DOUBLE_LOW (op); ! 2785: u.i[1] = CONST_DOUBLE_HIGH (op); ! 2786: if (GET_MODE (op) == SFmode) ! 2787: { ! 2788: float f; ! 2789: f = u.d; ! 2790: u.d = f; ! 2791: } ! 2792: fprintf (file, "%.20e", u.d); ! 2793: #else ! 2794: fatal ("CONST_DOUBLE found in cross compilation"); ! 2795: #endif ! 2796: } ! 2797: ! 2798: else if ((letter == 'x') && (GET_CODE(op) == CONST_INT)) ! 2799: fprintf (file, "0x%04x", 0xffff & (INTVAL(op))); ! 2800: ! 2801: else if ((letter == 'X') && (GET_CODE(op) == CONST_INT)) ! 2802: fprintf (file, "0x%08x", INTVAL(op)); ! 2803: ! 2804: else if ((letter == 'd') && (GET_CODE(op) == CONST_INT)) ! 2805: fprintf (file, "%d", (INTVAL(op))); ! 2806: ! 2807: else if (letter == 'z' ! 2808: && (GET_CODE (op) == CONST_INT) ! 2809: && INTVAL (op) == 0) ! 2810: fputs (reg_names[GP_REG_FIRST], file); ! 2811: ! 2812: else if (letter == 'd' || letter == 'x' || letter == 'X') ! 2813: fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT", letter); ! 2814: ! 2815: else ! 2816: output_addr_const (file, op); ! 2817: } ! 2818: ! 2819: ! 2820: /* A C compound statement to output to stdio stream STREAM the ! 2821: assembler syntax for an instruction operand that is a memory ! 2822: reference whose address is ADDR. ADDR is an RTL expression. ! 2823: ! 2824: On some machines, the syntax for a symbolic address depends on ! 2825: the section that the address refers to. On these machines, ! 2826: define the macro `ENCODE_SECTION_INFO' to store the information ! 2827: into the `symbol_ref', and then check for it here. */ ! 2828: ! 2829: void ! 2830: print_operand_address (file, addr) ! 2831: FILE *file; ! 2832: rtx addr; ! 2833: { ! 2834: if (!addr) ! 2835: error ("PRINT_OPERAND_ADDRESS, null pointer"); ! 2836: ! 2837: else ! 2838: switch (GET_CODE (addr)) ! 2839: { ! 2840: default: ! 2841: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #1"); ! 2842: break; ! 2843: ! 2844: case REG: ! 2845: fprintf (file, "0(%s)", reg_names [REGNO (addr)]); ! 2846: break; ! 2847: ! 2848: case PLUS: ! 2849: { ! 2850: register rtx reg = (rtx)0; ! 2851: register rtx offset = (rtx)0; ! 2852: register rtx arg0 = XEXP (addr, 0); ! 2853: register rtx arg1 = XEXP (addr, 1); ! 2854: ! 2855: if (GET_CODE (arg0) == REG) ! 2856: { ! 2857: reg = arg0; ! 2858: offset = arg1; ! 2859: if (GET_CODE (offset) == REG) ! 2860: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs"); ! 2861: } ! 2862: else if (GET_CODE (arg1) == REG) ! 2863: { ! 2864: reg = arg1; ! 2865: offset = arg0; ! 2866: } ! 2867: else if (CONSTANT_P (arg0) && CONSTANT_P (arg1)) ! 2868: { ! 2869: output_addr_const (file, addr); ! 2870: break; ! 2871: } ! 2872: else ! 2873: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs"); ! 2874: ! 2875: if (!CONSTANT_P (offset)) ! 2876: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2"); ! 2877: ! 2878: output_addr_const (file, offset); ! 2879: fprintf (file, "(%s)", reg_names [REGNO (reg)]); ! 2880: } ! 2881: break; ! 2882: ! 2883: case LABEL_REF: ! 2884: case SYMBOL_REF: ! 2885: case CONST_INT: ! 2886: case CONST: ! 2887: output_addr_const (file, addr); ! 2888: break; ! 2889: } ! 2890: } ! 2891: ! 2892: ! 2893: /* If optimizing for the global pointer, keep track of all of ! 2894: the externs, so that at the end of the file, we can emit ! 2895: the appropriate .extern declaration for them, before writing ! 2896: out the text section. We assume that all names passed to ! 2897: us are in the permanent obstack, so that they will be valid ! 2898: at the end of the compilation. ! 2899: ! 2900: If we have -G 0, or the extern size is unknown, don't bother ! 2901: emitting the .externs. */ ! 2902: ! 2903: int ! 2904: mips_output_external (file, decl, name) ! 2905: FILE *file; ! 2906: tree decl; ! 2907: char *name; ! 2908: { ! 2909: register struct extern_list *p; ! 2910: int len; ! 2911: ! 2912: if (TARGET_GP_OPT ! 2913: && mips_section_threshold != 0 ! 2914: && ((TREE_CODE (decl)) != FUNCTION_DECL) ! 2915: && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0)) ! 2916: { ! 2917: p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); ! 2918: p->next = extern_head; ! 2919: p->name = name; ! 2920: p->size = len; ! 2921: extern_head = p; ! 2922: } ! 2923: return 0; ! 2924: } ! 2925: ! 2926: ! 2927: /* Compute a string to use as a temporary file name. */ ! 2928: ! 2929: static FILE * ! 2930: make_temp_file () ! 2931: { ! 2932: FILE *stream; ! 2933: char *base = getenv ("TMPDIR"); ! 2934: int len; ! 2935: ! 2936: if (base == (char *)0) ! 2937: { ! 2938: #ifdef P_tmpdir ! 2939: if (access (P_tmpdir, R_OK | W_OK) == 0) ! 2940: base = P_tmpdir; ! 2941: else ! 2942: #endif ! 2943: if (access ("/usr/tmp", R_OK | W_OK) == 0) ! 2944: base = "/usr/tmp/"; ! 2945: else ! 2946: base = "/tmp/"; ! 2947: } ! 2948: ! 2949: len = strlen (base); ! 2950: temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX")); ! 2951: strcpy (temp_filename, base); ! 2952: if (len > 0 && temp_filename[len-1] != '/') ! 2953: temp_filename[len++] = '/'; ! 2954: ! 2955: strcpy (temp_filename + len, "ccXXXXXX"); ! 2956: mktemp (temp_filename); ! 2957: ! 2958: stream = fopen (temp_filename, "w+"); ! 2959: if (!stream) ! 2960: pfatal_with_name (temp_filename); ! 2961: ! 2962: unlink (temp_filename); ! 2963: return stream; ! 2964: } ! 2965: ! 2966: ! 2967: /* Emit a new filename to a stream. If this is MIPS ECOFF, watch out ! 2968: for .file's that start within a function. If we are smuggling stabs, try to ! 2969: put out a MIPS ECOFF file and a stab. */ ! 2970: ! 2971: void ! 2972: mips_output_filename (stream, name) ! 2973: FILE *stream; ! 2974: char *name; ! 2975: { ! 2976: static int first_time = TRUE; ! 2977: char ltext_label_name[100]; ! 2978: ! 2979: if (first_time) ! 2980: { ! 2981: first_time = FALSE; ! 2982: SET_FILE_NUMBER (); ! 2983: current_function_file = name; ! 2984: fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name); ! 2985: } ! 2986: ! 2987: else if (!TARGET_GAS && write_symbols == DBX_DEBUG) ! 2988: { ! 2989: ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); ! 2990: fprintf (stream, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP, ! 2991: name, N_SOL, <ext_label_name[1]); ! 2992: } ! 2993: ! 2994: else if (name != current_function_file ! 2995: && strcmp (name, current_function_file) != 0) ! 2996: { ! 2997: if (inside_function && !TARGET_GAS) ! 2998: { ! 2999: if (!file_in_function_warning) ! 3000: { ! 3001: file_in_function_warning = TRUE; ! 3002: ignore_line_number = TRUE; ! 3003: warning ("MIPS ECOFF format does not allow changing filenames within functions with #line"); ! 3004: } ! 3005: ! 3006: fprintf (stream, "\t#.file\t%d \"%s\"\n", num_source_filenames, name); ! 3007: } ! 3008: ! 3009: else ! 3010: { ! 3011: SET_FILE_NUMBER (); ! 3012: current_function_file = name; ! 3013: fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name); ! 3014: } ! 3015: } ! 3016: } ! 3017: ! 3018: ! 3019: /* Emit a linenumber. For encapsulated stabs, we need to put out a stab ! 3020: as well as a .loc, since it is possible that MIPS ECOFF might not be ! 3021: able to represent the location for inlines that come from a different ! 3022: file. */ ! 3023: ! 3024: void ! 3025: mips_output_lineno (stream, line) ! 3026: FILE *stream; ! 3027: int line; ! 3028: { ! 3029: if (!TARGET_GAS && write_symbols == DBX_DEBUG) ! 3030: { ! 3031: ++sym_lineno; ! 3032: fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n", ! 3033: sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno); ! 3034: } ! 3035: ! 3036: else ! 3037: { ! 3038: fprintf (stream, "\n\t%s.loc\t%d %d\n", ! 3039: (ignore_line_number) ? "#" : "", ! 3040: num_source_filenames, line); ! 3041: ! 3042: LABEL_AFTER_LOC (stream); ! 3043: } ! 3044: } ! 3045: ! 3046: ! 3047: /* Output at beginning of assembler file. ! 3048: If we are optimizing to use the global pointer, create a temporary ! 3049: file to hold all of the text stuff, and write it out to the end. ! 3050: This is needed because the MIPS assembler is evidently one pass, ! 3051: and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata ! 3052: declaration when the code is processed, it generates a two ! 3053: instruction sequence. */ ! 3054: ! 3055: void ! 3056: mips_asm_file_start (stream) ! 3057: FILE *stream; ! 3058: { ! 3059: ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename); ! 3060: ! 3061: /* Versions of the MIPS assembler before 2.20 generate errors ! 3062: if a branch inside of a .set noreorder section jumps to a ! 3063: label outside of the .set noreorder section. Revision 2.20 ! 3064: just set nobopt silently rather than fixing the bug. */ ! 3065: ! 3066: if (TARGET_MIPS_AS && optimize && flag_delayed_branch) ! 3067: fprintf (stream, "\t.set\tnobopt\n"); ! 3068: ! 3069: /* Generate the pseudo ops that the Pyramid based System V.4 wants. */ ! 3070: if (TARGET_ABICALLS) ! 3071: fprintf (stream, "\t.abicalls\n"); ! 3072: ! 3073: /* put gcc_compiled. in data, not text */ ! 3074: data_section (); ! 3075: ! 3076: if (TARGET_GP_OPT) ! 3077: { ! 3078: asm_out_data_file = stream; ! 3079: asm_out_text_file = make_temp_file (); ! 3080: } ! 3081: else ! 3082: asm_out_data_file = asm_out_text_file = stream; ! 3083: ! 3084: if (TARGET_NAME_REGS) ! 3085: fprintf (asm_out_file, "#include <regdef.h>\n"); ! 3086: ! 3087: print_options (stream); ! 3088: } ! 3089: ! 3090: ! 3091: /* If we are optimizing the global pointer, emit the text section now ! 3092: and any small externs which did not have .comm, etc that are ! 3093: needed. Also, give a warning if the data area is more than 32K and ! 3094: -pic because 3 instructions are needed to reference the data ! 3095: pointers. */ ! 3096: ! 3097: void ! 3098: mips_asm_file_end (file) ! 3099: FILE *file; ! 3100: { ! 3101: char buffer[8192]; ! 3102: tree name_tree; ! 3103: struct extern_list *p; ! 3104: int len; ! 3105: ! 3106: if (TARGET_GP_OPT) ! 3107: { ! 3108: if (extern_head) ! 3109: fputs ("\n", file); ! 3110: ! 3111: for (p = extern_head; p != 0; p = p->next) ! 3112: { ! 3113: name_tree = get_identifier (p->name); ! 3114: if (!TREE_ADDRESSABLE (name_tree)) ! 3115: { ! 3116: TREE_ADDRESSABLE (name_tree) = 1; ! 3117: fputs ("\t.extern\t", file); ! 3118: assemble_name (file, p->name); ! 3119: fprintf (file, ", %d\n", p->size); ! 3120: } ! 3121: } ! 3122: ! 3123: fprintf (file, "\n\t.text\n"); ! 3124: rewind (asm_out_text_file); ! 3125: if (ferror (asm_out_text_file)) ! 3126: fatal_io_error (temp_filename); ! 3127: ! 3128: while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0) ! 3129: if (fwrite (buffer, 1, len, file) != len) ! 3130: pfatal_with_name (asm_file_name); ! 3131: ! 3132: if (len < 0) ! 3133: pfatal_with_name (temp_filename); ! 3134: ! 3135: if (fclose (asm_out_text_file) != 0) ! 3136: pfatal_with_name (temp_filename); ! 3137: } ! 3138: } ! 3139: ! 3140: ! 3141: /* Return the bytes needed to compute the frame pointer from the current ! 3142: stack pointer. ! 3143: ! 3144: Mips stack frames look like: ! 3145: ! 3146: Before call After call ! 3147: +-----------------------+ +-----------------------+ ! 3148: high | | | | ! 3149: mem. | | | | ! 3150: | caller's temps. | | caller's temps. | ! 3151: | | | | ! 3152: +-----------------------+ +-----------------------+ ! 3153: | | | | ! 3154: | arguments on stack. | | arguments on stack. | ! 3155: | | | | ! 3156: +-----------------------+ +-----------------------+ ! 3157: | 4 words to save | | 4 words to save | ! 3158: | arguments passed | | arguments passed | ! 3159: | in registers, even | | in registers, even | ! 3160: SP->| if not passed. | FP->| if not passed. | ! 3161: +-----------------------+ +-----------------------+ ! 3162: | | ! 3163: | GP save for V.4 abi | ! 3164: | | ! 3165: +-----------------------+ ! 3166: | | ! 3167: | local variables | ! 3168: | | ! 3169: +-----------------------+ ! 3170: | | ! 3171: | fp register save | ! 3172: | | ! 3173: +-----------------------+ ! 3174: | | ! 3175: | gp register save | ! 3176: | | ! 3177: +-----------------------+ ! 3178: | | ! 3179: | alloca allocations | ! 3180: | | ! 3181: +-----------------------+ ! 3182: | | ! 3183: | arguments on stack | ! 3184: | | ! 3185: +-----------------------+ ! 3186: | 4 words to save | ! 3187: | arguments passed | ! 3188: | in registers, even | ! 3189: low SP->| if not passed. | ! 3190: memory +-----------------------+ ! 3191: ! 3192: */ ! 3193: ! 3194: unsigned long ! 3195: compute_frame_size (size) ! 3196: int size; /* # of var. bytes allocated */ ! 3197: { ! 3198: int regno; ! 3199: unsigned long total_size; /* # bytes that the entire frame takes up */ ! 3200: unsigned long var_size; /* # bytes that variables take up */ ! 3201: unsigned long args_size; /* # bytes that outgoing arguments take up */ ! 3202: unsigned long extra_size; /* # extra bytes */ ! 3203: unsigned int gp_reg_rounded; /* # bytes needed to store gp after rounding */ ! 3204: unsigned int gp_reg_size; /* # bytes needed to store gp regs */ ! 3205: unsigned int fp_reg_size; /* # bytes needed to store fp regs */ ! 3206: unsigned long mask; /* mask of saved gp registers */ ! 3207: unsigned long fmask; /* mask of saved fp registers */ ! 3208: int fp_inc; /* 1 or 2 depending on the size of fp regs */ ! 3209: int fp_bits; /* bitmask to use for each fp register */ ! 3210: ! 3211: extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0) ! 3212: -STARTING_FRAME_OFFSET); ! 3213: ! 3214: var_size = MIPS_STACK_ALIGN (size); ! 3215: args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size); ! 3216: total_size = var_size + args_size + extra_size; ! 3217: gp_reg_size = 0; ! 3218: fp_reg_size = 0; ! 3219: mask = 0; ! 3220: fmask = 0; ! 3221: ! 3222: /* Calculate space needed for gp registers. */ ! 3223: for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) ! 3224: { ! 3225: if (MUST_SAVE_REGISTER (regno)) ! 3226: { ! 3227: gp_reg_size += UNITS_PER_WORD; ! 3228: mask |= 1 << (regno - GP_REG_FIRST); ! 3229: } ! 3230: } ! 3231: ! 3232: /* Calculate space needed for fp registers. */ ! 3233: if (TARGET_FLOAT64) ! 3234: { ! 3235: fp_inc = 1; ! 3236: fp_bits = 1; ! 3237: } ! 3238: else ! 3239: { ! 3240: fp_inc = 2; ! 3241: fp_bits = 3; ! 3242: } ! 3243: ! 3244: for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc) ! 3245: { ! 3246: if (regs_ever_live[regno] && !call_used_regs[regno]) ! 3247: { ! 3248: fp_reg_size += 2*UNITS_PER_WORD; ! 3249: fmask |= fp_bits << (regno - FP_REG_FIRST); ! 3250: } ! 3251: } ! 3252: ! 3253: gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); ! 3254: total_size += gp_reg_rounded + fp_reg_size; ! 3255: ! 3256: if (total_size == extra_size) ! 3257: total_size = extra_size = 0; ! 3258: ! 3259: /* Save other computed information. */ ! 3260: current_frame_info.total_size = total_size; ! 3261: current_frame_info.var_size = var_size; ! 3262: current_frame_info.args_size = args_size; ! 3263: current_frame_info.extra_size = extra_size; ! 3264: current_frame_info.gp_reg_size = gp_reg_size; ! 3265: current_frame_info.fp_reg_size = fp_reg_size; ! 3266: current_frame_info.mask = mask; ! 3267: current_frame_info.fmask = fmask; ! 3268: current_frame_info.initialized = reload_completed; ! 3269: ! 3270: if (mask) ! 3271: { ! 3272: unsigned long offset = args_size + gp_reg_size - UNITS_PER_WORD; ! 3273: current_frame_info.gp_sp_offset = offset; ! 3274: current_frame_info.gp_save_offset = offset - total_size; ! 3275: } ! 3276: ! 3277: if (fmask) ! 3278: { ! 3279: unsigned long offset = args_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD; ! 3280: current_frame_info.fp_sp_offset = offset; ! 3281: current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD; ! 3282: } ! 3283: ! 3284: /* Ok, we're done. */ ! 3285: return total_size; ! 3286: } ! 3287: ! 3288: ! 3289: /* Common code to save/restore registers. */ ! 3290: ! 3291: void ! 3292: save_restore (file, gp_op, gp_2word_op, fp_op) ! 3293: FILE *file; /* stream to write to */ ! 3294: char *gp_op; /* operation to do on gp registers */ ! 3295: char *gp_2word_op; /* 2 word op to do on gp registers */ ! 3296: char *fp_op; /* operation to do on fp registers */ ! 3297: { ! 3298: int regno; ! 3299: unsigned long mask = current_frame_info.mask; ! 3300: unsigned long fmask = current_frame_info.fmask; ! 3301: unsigned long gp_offset; ! 3302: unsigned long fp_offset; ! 3303: unsigned long max_offset; ! 3304: char *base_reg; ! 3305: ! 3306: if (mask == 0 && fmask == 0) ! 3307: return; ! 3308: ! 3309: base_reg = reg_names[STACK_POINTER_REGNUM]; ! 3310: gp_offset = current_frame_info.gp_sp_offset; ! 3311: fp_offset = current_frame_info.fp_sp_offset; ! 3312: max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset; ! 3313: ! 3314: /* Deal with calling functions with a large structure. */ ! 3315: if (max_offset >= 32768) ! 3316: { ! 3317: char *temp = reg_names[MIPS_TEMP2_REGNUM]; ! 3318: fprintf (file, "\tli\t%s,%ld\n", temp, max_offset); ! 3319: fprintf (file, "\taddu\t%s,%s,%s\n", temp, temp, base_reg); ! 3320: base_reg = temp; ! 3321: gp_offset = max_offset - gp_offset; ! 3322: fp_offset = max_offset - fp_offset; ! 3323: } ! 3324: ! 3325: /* Save registers starting from high to low. The debuggers prefer ! 3326: at least the return register be stored at func+4, and also it ! 3327: allows us not to need a nop in the epilog if at least one ! 3328: register is reloaded in addition to return address. */ ! 3329: ! 3330: if (mask || frame_pointer_needed) ! 3331: { ! 3332: for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) ! 3333: { ! 3334: if ((mask & (1L << (regno - GP_REG_FIRST))) != 0 ! 3335: || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)) ! 3336: { ! 3337: fprintf (file, "\t%s\t%s,%d(%s)\n", ! 3338: gp_op, reg_names[regno], ! 3339: gp_offset, base_reg); ! 3340: ! 3341: gp_offset -= UNITS_PER_WORD; ! 3342: } ! 3343: } ! 3344: } ! 3345: ! 3346: if (fmask) ! 3347: { ! 3348: int fp_inc = (TARGET_FLOAT64) ? 1 : 2; ! 3349: ! 3350: for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc) ! 3351: { ! 3352: if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0) ! 3353: { ! 3354: fprintf (file, "\t%s\t%s,%d(%s)\n", ! 3355: fp_op, reg_names[regno], fp_offset, base_reg); ! 3356: ! 3357: fp_offset -= 2*UNITS_PER_WORD; ! 3358: } ! 3359: } ! 3360: } ! 3361: } ! 3362: ! 3363: ! 3364: /* Set up the stack and frame (if desired) for the function. */ ! 3365: ! 3366: void ! 3367: function_prologue (file, size) ! 3368: FILE *file; ! 3369: int size; ! 3370: { ! 3371: int regno; ! 3372: int tsize; ! 3373: char *sp_str = reg_names[STACK_POINTER_REGNUM]; ! 3374: char *fp_str = (!frame_pointer_needed) ! 3375: ? sp_str ! 3376: : reg_names[FRAME_POINTER_REGNUM]; ! 3377: tree fndecl = current_function_decl; /* current... is tooo long */ ! 3378: tree fntype = TREE_TYPE (fndecl); ! 3379: tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) ! 3380: ? DECL_ARGUMENTS (fndecl) ! 3381: : 0; ! 3382: tree next_arg; ! 3383: tree cur_arg; ! 3384: char *arg_name = (char *)0; ! 3385: CUMULATIVE_ARGS args_so_far; ! 3386: ! 3387: ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl)); ! 3388: ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl)); ! 3389: ! 3390: inside_function = 1; ! 3391: fputs ("\t.ent\t", file); ! 3392: assemble_name (file, current_function_name); ! 3393: fputs ("\n", file); ! 3394: assemble_name (file, current_function_name); ! 3395: fputs (":\n", file); ! 3396: ! 3397: if (TARGET_ABICALLS) ! 3398: fprintf (file, ! 3399: "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n", ! 3400: reg_names[ GP_REG_FIRST + 25 ]); ! 3401: ! 3402: /* Determine the last argument, and get its name. */ ! 3403: for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg) ! 3404: { ! 3405: next_arg = TREE_CHAIN (cur_arg); ! 3406: if (next_arg == (tree)0) ! 3407: { ! 3408: if (DECL_NAME (cur_arg)) ! 3409: arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg)); ! 3410: ! 3411: break; ! 3412: } ! 3413: } ! 3414: ! 3415: /* If this function is a varargs function, store any registers that ! 3416: would normally hold arguments ($4 - $7) on the stack. */ ! 3417: if ((TYPE_ARG_TYPES (fntype) != 0 ! 3418: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) ! 3419: || (arg_name ! 3420: && (strcmp (arg_name, "__builtin_va_alist") == 0 ! 3421: || strcmp (arg_name, "va_alist") == 0))) ! 3422: { ! 3423: tree parm; ! 3424: ! 3425: regno = GP_ARG_FIRST; ! 3426: INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0); ! 3427: ! 3428: for (parm = fnargs; (parm && (regno <= GP_ARG_LAST)); parm = TREE_CHAIN (parm)) ! 3429: { ! 3430: rtx entry_parm; ! 3431: enum machine_mode passed_mode; ! 3432: tree type; ! 3433: ! 3434: type = DECL_ARG_TYPE (parm); ! 3435: passed_mode = TYPE_MODE (type); ! 3436: entry_parm = FUNCTION_ARG (args_so_far, passed_mode, ! 3437: DECL_ARG_TYPE (parm), 1); ! 3438: ! 3439: if (entry_parm) ! 3440: { ! 3441: int words; ! 3442: ! 3443: /* passed in a register, so will get homed automatically */ ! 3444: if (GET_MODE (entry_parm) == BLKmode) ! 3445: words = (int_size_in_bytes (type) + 3) / 4; ! 3446: else ! 3447: words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; ! 3448: ! 3449: regno = REGNO (entry_parm) + words - 1; ! 3450: } ! 3451: else ! 3452: { ! 3453: regno = GP_ARG_LAST+1; ! 3454: break; ! 3455: } ! 3456: ! 3457: FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, ! 3458: DECL_ARG_TYPE (parm), 1); ! 3459: } ! 3460: ! 3461: if (regno <= GP_ARG_LAST && (regno & 1) != 0) ! 3462: { ! 3463: fprintf (file, "\tsw\t%s,%d(%s)\t\t# varargs home register\n", ! 3464: reg_names[regno], (regno - 4) * 4, sp_str); ! 3465: regno++; ! 3466: } ! 3467: ! 3468: for (; regno <= GP_ARG_LAST; regno += 2) ! 3469: { ! 3470: fprintf (file, "\tsd\t%s,%d(%s)\t\t# varargs home register\n", ! 3471: reg_names[regno], (regno - 4) * 4, sp_str); ! 3472: } ! 3473: } ! 3474: ! 3475: size = MIPS_STACK_ALIGN (size); ! 3476: tsize = (!current_frame_info.initialized) ! 3477: ? compute_frame_size (size) ! 3478: : current_frame_info.total_size; ! 3479: ! 3480: if (tsize > 0) ! 3481: { ! 3482: if (tsize <= 32767) ! 3483: fprintf (file, ! 3484: "\tsubu\t%s,%s,%d\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n", ! 3485: sp_str, sp_str, tsize, current_frame_info.var_size, ! 3486: current_frame_info.gp_reg_size / 4, ! 3487: current_frame_info.fp_reg_size / 8, ! 3488: current_function_outgoing_args_size, ! 3489: current_frame_info.extra_size); ! 3490: else ! 3491: fprintf (file, ! 3492: "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t\t# vars= %d, regs= %d/%d, args = %d, sfo= %d\n", ! 3493: reg_names[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str, ! 3494: reg_names[MIPS_TEMP1_REGNUM], current_frame_info.var_size, ! 3495: current_frame_info.gp_reg_size / 4, ! 3496: current_frame_info.fp_reg_size / 8, ! 3497: current_function_outgoing_args_size, ! 3498: current_frame_info.extra_size); ! 3499: } ! 3500: ! 3501: if (TARGET_ABICALLS) ! 3502: fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET); ! 3503: ! 3504: fprintf (file, "\t.frame\t%s,%d,%s\n\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n", ! 3505: fp_str, ! 3506: (frame_pointer_needed) ? 0 : tsize, ! 3507: reg_names[31 + GP_REG_FIRST], ! 3508: current_frame_info.mask, ! 3509: current_frame_info.gp_save_offset, ! 3510: current_frame_info.fmask, ! 3511: current_frame_info.fp_save_offset); ! 3512: ! 3513: save_restore (file, "sw", "sd", "s.d"); ! 3514: ! 3515: if (frame_pointer_needed) ! 3516: { ! 3517: if (tsize <= 32767) ! 3518: fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize); ! 3519: ! 3520: else ! 3521: fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str, ! 3522: reg_names[MIPS_TEMP1_REGNUM]); ! 3523: } ! 3524: } ! 3525: ! 3526: ! 3527: /* Do any necessary cleanup after a function to restore stack, frame, and regs. */ ! 3528: ! 3529: void ! 3530: function_epilogue (file, size) ! 3531: FILE *file; ! 3532: int size; ! 3533: { ! 3534: int tsize; ! 3535: char *sp_str = reg_names[STACK_POINTER_REGNUM]; ! 3536: char *t1_str = reg_names[MIPS_TEMP1_REGNUM]; ! 3537: rtx epilogue_delay = current_function_epilogue_delay_list; ! 3538: int noreorder = !TARGET_MIPS_AS || (epilogue_delay != 0); ! 3539: int noepilogue = FALSE; ! 3540: int load_nop = FALSE; ! 3541: int load_only_r31; ! 3542: ! 3543: /* The epilogue does not depend on any registers, but the stack ! 3544: registers, so we assume that if we have 1 pending nop, it can be ! 3545: ignored, and 2 it must be filled (2 nops occur for integer ! 3546: multiply and divide). */ ! 3547: ! 3548: if (dslots_number_nops > 0) ! 3549: { ! 3550: if (dslots_number_nops == 1) ! 3551: { ! 3552: dslots_number_nops = 0; ! 3553: dslots_load_filled++; ! 3554: } ! 3555: else ! 3556: { ! 3557: while (--dslots_number_nops > 0) ! 3558: fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file); ! 3559: } ! 3560: ! 3561: if (set_noreorder > 0 && --set_noreorder == 0) ! 3562: fputs ("\t.set\treorder\n", file); ! 3563: } ! 3564: ! 3565: if (set_noat != 0) ! 3566: { ! 3567: set_noat = 0; ! 3568: fputs ("\t.set\tat\n", file); ! 3569: error ("internal gcc error: .set noat left on in epilogue"); ! 3570: } ! 3571: ! 3572: if (set_nomacro != 0) ! 3573: { ! 3574: set_nomacro = 0; ! 3575: fputs ("\t.set\tmacro\n", file); ! 3576: error ("internal gcc error: .set nomacro left on in epilogue"); ! 3577: } ! 3578: ! 3579: if (set_noreorder != 0) ! 3580: { ! 3581: set_noreorder = 0; ! 3582: fputs ("\t.set\treorder\n", file); ! 3583: error ("internal gcc error: .set noreorder left on in epilogue"); ! 3584: } ! 3585: ! 3586: if (set_volatile != 0) ! 3587: { ! 3588: set_volatile = 0; ! 3589: fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#"); ! 3590: error ("internal gcc error: .set volatile left on in epilogue"); ! 3591: } ! 3592: ! 3593: size = MIPS_STACK_ALIGN (size); ! 3594: tsize = (!current_frame_info.initialized) ! 3595: ? compute_frame_size (size) ! 3596: : current_frame_info.total_size; ! 3597: ! 3598: if (tsize == 0 && epilogue_delay == 0) ! 3599: { ! 3600: rtx insn = get_last_insn (); ! 3601: ! 3602: /* If the last insn was a BARRIER, we don't have to write any code ! 3603: because a jump (aka return) was put there. */ ! 3604: if (GET_CODE (insn) == NOTE) ! 3605: insn = prev_nonnote_insn (insn); ! 3606: if (insn && GET_CODE (insn) == BARRIER) ! 3607: noepilogue = TRUE; ! 3608: ! 3609: noreorder = FALSE; ! 3610: } ! 3611: ! 3612: if (!noepilogue) ! 3613: { ! 3614: /* In the reload sequence, we don't need to fill the load delay ! 3615: slots for most of the loads, also see if we can fill the final ! 3616: delay slot if not otherwise filled by the reload sequence. */ ! 3617: ! 3618: if (noreorder) ! 3619: fprintf (file, "\t.set\tnoreorder\n"); ! 3620: ! 3621: if (tsize > 32767) ! 3622: fprintf (file, "\tli\t%s,%d\n", t1_str, tsize); ! 3623: ! 3624: if (frame_pointer_needed) ! 3625: { ! 3626: char *fp_str = reg_names[FRAME_POINTER_REGNUM]; ! 3627: if (tsize > 32767) ! 3628: fprintf (file,"\tsubu\t%s,%s,%s\t\t# sp not trusted here\n", ! 3629: sp_str, fp_str, t1_str); ! 3630: else ! 3631: fprintf (file,"\tsubu\t%s,%s,%d\t\t# sp not trusted here\n", ! 3632: sp_str, fp_str, tsize); ! 3633: } ! 3634: ! 3635: save_restore (file, "lw", "ld", "l.d"); ! 3636: ! 3637: load_only_r31 = (current_frame_info.mask == (1 << 31) ! 3638: && current_frame_info.fmask == 0); ! 3639: ! 3640: if (noreorder) ! 3641: { ! 3642: /* If the only register saved is the return address, we need a ! 3643: nop, unless we have an instruction to put into it. Otherwise ! 3644: we don't since reloading multiple registers doesn't reference ! 3645: the register being loaded. */ ! 3646: ! 3647: if (load_only_r31) ! 3648: { ! 3649: if (epilogue_delay) ! 3650: final_scan_insn (XEXP (epilogue_delay, 0), ! 3651: file, ! 3652: 1, /* optimize */ ! 3653: -2, /* prescan */ ! 3654: 1); /* nopeepholes */ ! 3655: else ! 3656: { ! 3657: fprintf (file, "\tnop\n"); ! 3658: load_nop = TRUE; ! 3659: } ! 3660: } ! 3661: ! 3662: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); ! 3663: ! 3664: if (tsize > 32767) ! 3665: fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); ! 3666: ! 3667: else if (tsize > 0) ! 3668: fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); ! 3669: ! 3670: else if (!load_only_r31 && epilogue_delay != 0) ! 3671: final_scan_insn (XEXP (epilogue_delay, 0), ! 3672: file, ! 3673: 1, /* optimize */ ! 3674: -2, /* prescan */ ! 3675: 1); /* nopeepholes */ ! 3676: ! 3677: fprintf (file, "\t.set\treorder\n"); ! 3678: } ! 3679: ! 3680: else ! 3681: { ! 3682: if (tsize > 32767) ! 3683: fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); ! 3684: ! 3685: else if (tsize > 0) ! 3686: fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); ! 3687: ! 3688: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); ! 3689: } ! 3690: } ! 3691: ! 3692: fputs ("\t.end\t", file); ! 3693: assemble_name (file, current_function_name); ! 3694: fputs ("\n", file); ! 3695: ! 3696: if (TARGET_STATS) ! 3697: { ! 3698: int num_gp_regs = current_frame_info.gp_reg_size / 4; ! 3699: int num_fp_regs = current_frame_info.fp_reg_size / 8; ! 3700: int num_regs = num_gp_regs + num_fp_regs; ! 3701: ! 3702: dslots_load_total += num_regs; ! 3703: ! 3704: if (!noepilogue) ! 3705: dslots_jump_total++; ! 3706: ! 3707: if (noreorder) ! 3708: { ! 3709: dslots_load_filled += num_regs; ! 3710: ! 3711: /* If the only register saved is the return register, we ! 3712: can't fill this register's delay slot. */ ! 3713: ! 3714: if (load_only_r31 && epilogue_delay == 0) ! 3715: dslots_load_filled--; ! 3716: ! 3717: if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0)) ! 3718: dslots_jump_filled++; ! 3719: } ! 3720: ! 3721: fprintf (stderr, ! 3722: "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d\n", ! 3723: current_function_name, ! 3724: (frame_pointer_needed) ? 'y' : 'n', ! 3725: ((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y', ! 3726: (current_function_calls_alloca) ? 'y' : 'n', ! 3727: (current_function_calls_setjmp) ? 'y' : 'n', ! 3728: (long)current_frame_info.total_size, ! 3729: (long)current_function_outgoing_args_size, ! 3730: num_gp_regs, num_fp_regs, ! 3731: dslots_load_total, dslots_load_filled, ! 3732: dslots_jump_total, dslots_jump_filled, ! 3733: num_refs[0], num_refs[1], num_refs[2]); ! 3734: } ! 3735: ! 3736: /* Reset state info for each function. */ ! 3737: inside_function = FALSE; ! 3738: ignore_line_number = FALSE; ! 3739: dslots_load_total = 0; ! 3740: dslots_jump_total = 0; ! 3741: dslots_load_filled = 0; ! 3742: dslots_jump_filled = 0; ! 3743: num_refs[0] = 0; ! 3744: num_refs[1] = 0; ! 3745: num_refs[2] = 0; ! 3746: mips_load_reg = (rtx)0; ! 3747: mips_load_reg2 = (rtx)0; ! 3748: number_functions_processed++; ! 3749: current_frame_info = zero_frame_info; ! 3750: ! 3751: /* Restore the output file if optimizing the GP (optimizing the GP causes ! 3752: the text to be diverted to a tempfile, so that data decls come before ! 3753: references to the data). */ ! 3754: ! 3755: if (TARGET_GP_OPT) ! 3756: asm_out_file = asm_out_data_file; ! 3757: } ! 3758: ! 3759: ! 3760: /* Define the number of delay slots needed for the function epilogue. ! 3761: ! 3762: On the mips, we need a slot if either no stack has been allocated, ! 3763: or the only register saved is the return register. */ ! 3764: ! 3765: int ! 3766: mips_epilogue_delay_slots () ! 3767: { ! 3768: if (!current_frame_info.initialized) ! 3769: (void) compute_frame_size (get_frame_size ()); ! 3770: ! 3771: if (current_frame_info.total_size == 0) ! 3772: return 1; ! 3773: ! 3774: if (current_frame_info.mask == (1 << 31) && current_frame_info.fmask == 0) ! 3775: return 1; ! 3776: ! 3777: return 0; ! 3778: } ! 3779: ! 3780: ! 3781: /* Return true if this function is known to have a null epilogue. ! 3782: This allows the optimizer to omit jumps to jumps if no stack ! 3783: was created. */ ! 3784: ! 3785: int ! 3786: null_epilogue () ! 3787: { ! 3788: if (!reload_completed) ! 3789: return 0; ! 3790: ! 3791: if (current_frame_info.initialized) ! 3792: return current_frame_info.total_size == 0; ! 3793: ! 3794: return (compute_frame_size (get_frame_size ())) == 0; ! 3795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.