|
|
1.1 root 1: /* Subroutines for insn-output.c for MIPS 1.1.1.4 root 2: Copyright (C) 1989, 90, 91, 93, 94, 1995 Free Software Foundation, Inc. 1.1 root 3: Contributed by A. Lichnewsky, [email protected]. 1.1.1.4 root 4: Changes by Michael Meissner, [email protected]. 1.1.1.3 root 5: 64 bit r4000 support by Ian Lance Taylor, [email protected], and 6: Brendan Eich, [email protected]. 1.1 root 7: 8: This file is part of GNU CC. 9: 10: GNU CC is free software; you can redistribute it and/or modify 11: it under the terms of the GNU General Public License as published by 12: the Free Software Foundation; either version 2, or (at your option) 13: any later version. 14: 15: GNU CC is distributed in the hope that it will be useful, 16: but WITHOUT ANY WARRANTY; without even the implied warranty of 17: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: GNU General Public License for more details. 19: 20: You should have received a copy of the GNU General Public License 21: along with GNU CC; see the file COPYING. If not, write to 1.1.1.4 root 22: the Free Software Foundation, 59 Temple Place - Suite 330, 23: Boston, MA 02111-1307, USA. */ 1.1 root 24: 1.1.1.3 root 25: /* ??? The TARGET_FP_CALL_32 macros are intended to simulate a 32 bit 26: calling convention in 64 bit mode. It doesn't work though, and should 27: be replaced with something better designed. */ 28: 1.1 root 29: #include "config.h" 30: #include "rtl.h" 31: #include "regs.h" 32: #include "hard-reg-set.h" 33: #include "real.h" 34: #include "insn-config.h" 35: #include "conditions.h" 36: #include "insn-flags.h" 37: #include "insn-attr.h" 38: #include "insn-codes.h" 39: #include "recog.h" 40: #include "output.h" 41: 42: #undef MAX /* sys/param.h may also define these */ 43: #undef MIN 44: 45: #include <stdio.h> 46: #include <signal.h> 47: #include <sys/types.h> 48: #include <sys/file.h> 49: #include <ctype.h> 50: #include "tree.h" 51: #include "expr.h" 52: #include "flags.h" 53: 54: #ifndef R_OK 55: #define R_OK 4 56: #define W_OK 2 57: #define X_OK 1 58: #endif 59: 60: #if defined(USG) || defined(NO_STAB_H) 61: #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ 62: #else 63: #include <stab.h> /* On BSD, use the system's stab.h. */ 64: #endif /* not USG */ 65: 66: #ifdef __GNU_STAB__ 67: #define STAB_CODE_TYPE enum __stab_debug_code 68: #else 69: #define STAB_CODE_TYPE int 70: #endif 71: 72: extern void abort (); 73: extern int atoi (); 74: extern char *getenv (); 75: extern char *mktemp (); 76: 77: extern rtx adj_offsettable_operand (); 78: extern rtx copy_to_reg (); 79: extern void error (); 80: extern void fatal (); 81: extern tree lookup_name (); 82: extern void pfatal_with_name (); 83: extern void warning (); 84: 85: extern FILE *asm_out_file; 86: 87: /* Enumeration for all of the relational tests, so that we can build 88: arrays indexed by the test type, and not worry about the order 89: of EQ, NE, etc. */ 90: 91: enum internal_test { 92: ITEST_EQ, 93: ITEST_NE, 94: ITEST_GT, 95: ITEST_GE, 96: ITEST_LT, 97: ITEST_LE, 98: ITEST_GTU, 99: ITEST_GEU, 100: ITEST_LTU, 101: ITEST_LEU, 102: ITEST_MAX 103: }; 104: 105: /* Global variables for machine-dependent things. */ 106: 107: /* Threshold for data being put into the small data/bss area, instead 108: of the normal data area (references to the small data/bss area take 109: 1 instruction, and use the global pointer, references to the normal 110: data area takes 2 instructions). */ 111: int mips_section_threshold = -1; 112: 113: /* Count the number of .file directives, so that .loc is up to date. */ 114: int num_source_filenames = 0; 115: 116: /* Count the number of sdb related labels are generated (to find block 117: start and end boundaries). */ 118: int sdb_label_count = 0; 119: 1.1.1.4 root 120: /* Next label # for each statement for Silicon Graphics IRIS systems. */ 1.1 root 121: int sym_lineno = 0; 122: 123: /* Non-zero if inside of a function, because the stupid MIPS asm can't 124: handle .files inside of functions. */ 125: int inside_function = 0; 126: 127: /* Files to separate the text and the data output, so that all of the data 128: can be emitted before the text, which will mean that the assembler will 129: generate smaller code, based on the global pointer. */ 130: FILE *asm_out_data_file; 131: FILE *asm_out_text_file; 132: 133: /* Linked list of all externals that are to be emitted when optimizing 134: for the global pointer if they haven't been declared by the end of 135: the program with an appropriate .comm or initialization. */ 136: 137: struct extern_list { 138: struct extern_list *next; /* next external */ 139: char *name; /* name of the external */ 140: int size; /* size in bytes */ 141: } *extern_head = 0; 142: 143: /* Name of the file containing the current function. */ 144: char *current_function_file = ""; 145: 146: /* Warning given that Mips ECOFF can't support changing files 147: within a function. */ 148: int file_in_function_warning = FALSE; 149: 150: /* Whether to suppress issuing .loc's because the user attempted 151: to change the filename within a function. */ 152: int ignore_line_number = FALSE; 153: 154: /* Number of nested .set noreorder, noat, nomacro, and volatile requests. */ 155: int set_noreorder; 156: int set_noat; 157: int set_nomacro; 158: int set_volatile; 159: 160: /* The next branch instruction is a branch likely, not branch normal. */ 161: int mips_branch_likely; 162: 163: /* Count of delay slots and how many are filled. */ 164: int dslots_load_total; 165: int dslots_load_filled; 166: int dslots_jump_total; 167: int dslots_jump_filled; 168: 169: /* # of nops needed by previous insn */ 170: int dslots_number_nops; 171: 172: /* Number of 1/2/3 word references to data items (ie, not jal's). */ 173: int num_refs[3]; 174: 175: /* registers to check for load delay */ 176: rtx mips_load_reg, mips_load_reg2, mips_load_reg3, mips_load_reg4; 177: 178: /* Cached operands, and operator to compare for use in set/branch on 179: condition codes. */ 180: rtx branch_cmp[2]; 181: 182: /* what type of branch to use */ 183: enum cmp_type branch_type; 184: 185: /* Number of previously seen half-pic pointers and references. */ 186: static int prev_half_pic_ptrs = 0; 187: static int prev_half_pic_refs = 0; 188: 189: /* which cpu are we scheduling for */ 190: enum processor_type mips_cpu; 191: 192: /* which instruction set architecture to use. */ 193: int mips_isa; 194: 195: /* Strings to hold which cpu and instruction set architecture to use. */ 196: char *mips_cpu_string; /* for -mcpu=<xxx> */ 1.1.1.4 root 197: char *mips_isa_string; /* for -mips{1,2,3,4} */ 1.1 root 198: 1.1.1.2 root 199: /* Generating calls to position independent functions? */ 200: enum mips_abicalls_type mips_abicalls; 201: 1.1.1.3 root 202: /* High and low marks for floating point values which we will accept 203: as legitimate constants for LEGITIMATE_CONSTANT_P. These are 204: initialized in override_options. */ 205: REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow; 1.1 root 206: 207: /* Array giving truth value on whether or not a given hard register 208: can support a given mode. */ 209: char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER]; 210: 211: /* Current frame information calculated by compute_frame_size. */ 212: struct mips_frame_info current_frame_info; 213: 214: /* Zero structure to initialize current_frame_info. */ 215: struct mips_frame_info zero_frame_info; 216: 217: /* Temporary filename used to buffer .text until end of program 218: for -mgpopt. */ 219: static char *temp_filename; 220: 1.1.1.3 root 221: /* Pseudo-reg holding the address of the current function when 222: generating embedded PIC code. Created by LEGITIMIZE_ADDRESS, used 223: by mips_finalize_pic if it was created. */ 224: rtx embedded_pic_fnaddr_rtx; 225: 1.1 root 226: /* List of all MIPS punctuation characters used by print_operand. */ 227: char mips_print_operand_punct[256]; 228: 229: /* Map GCC register number to debugger register number. */ 230: int mips_dbx_regno[FIRST_PSEUDO_REGISTER]; 231: 232: /* Buffer to use to enclose a load/store operation with %{ %} to 233: turn on .set volatile. */ 234: static char volatile_buffer[60]; 235: 236: /* Hardware names for the registers. If -mrnames is used, this 237: will be overwritten with mips_sw_reg_names. */ 238: 239: char mips_reg_names[][8] = 240: { 241: "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", 242: "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 243: "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 244: "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31", 245: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 246: "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 247: "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 248: "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", 1.1.1.4 root 249: "hi", "lo", "accum","$fcr31" 1.1 root 250: }; 251: 252: /* Mips software names for the registers, used to overwrite the 253: mips_reg_names array. */ 254: 255: char mips_sw_reg_names[][8] = 256: { 1.1.1.3 root 257: "$zero","$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", 258: "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", 259: "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", 260: "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", 1.1 root 261: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 262: "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 263: "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 264: "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", 1.1.1.4 root 265: "hi", "lo", "accum","$fcr31" 1.1 root 266: }; 267: 268: /* Map hard register number to register class */ 269: enum reg_class mips_regno_to_class[] = 270: { 271: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 272: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 273: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 274: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 275: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 276: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 277: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 278: GR_REGS, GR_REGS, GR_REGS, GR_REGS, 279: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 280: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 281: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 282: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 283: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 284: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 285: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 286: FP_REGS, FP_REGS, FP_REGS, FP_REGS, 1.1.1.4 root 287: HI_REG, LO_REG, HILO_REG, ST_REGS 1.1 root 288: }; 289: 290: /* Map register constraint character to register class. */ 291: enum reg_class mips_char_to_class[256] = 292: { 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: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 345: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 346: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 347: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 348: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 349: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 350: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 351: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 352: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 353: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 354: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 355: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 356: NO_REGS, NO_REGS, NO_REGS, NO_REGS, 357: }; 358: 359: 360: /* Return truth value of whether OP can be used as an operands 361: where a register or 16 bit unsigned integer is needed. */ 362: 363: int 364: uns_arith_operand (op, mode) 365: rtx op; 366: enum machine_mode mode; 367: { 368: if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)) 369: return TRUE; 370: 371: return register_operand (op, mode); 372: } 373: 374: /* Return truth value of whether OP can be used as an operands 375: where a 16 bit integer is needed */ 376: 377: int 378: arith_operand (op, mode) 379: rtx op; 380: enum machine_mode mode; 381: { 382: if (GET_CODE (op) == CONST_INT && SMALL_INT (op)) 383: return TRUE; 384: 385: return register_operand (op, mode); 386: } 387: 388: /* Return truth value of whether OP can be used as an operand in a two 389: address arithmetic insn (such as set 123456,%o4) of mode MODE. */ 390: 391: int 392: arith32_operand (op, mode) 393: rtx op; 394: enum machine_mode mode; 395: { 396: if (GET_CODE (op) == CONST_INT) 397: return TRUE; 398: 399: return register_operand (op, mode); 400: } 401: 402: /* Return truth value of whether OP is a integer which fits in 16 bits */ 403: 404: int 405: small_int (op, mode) 406: rtx op; 407: enum machine_mode mode; 408: { 409: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); 410: } 411: 1.1.1.4 root 412: /* Return truth value of whether OP is a 32 bit integer which is too big to 1.1 root 413: be loaded with one instruction. */ 414: 415: int 416: large_int (op, mode) 417: rtx op; 418: enum machine_mode mode; 419: { 420: HOST_WIDE_INT value; 421: 422: if (GET_CODE (op) != CONST_INT) 423: return FALSE; 424: 425: value = INTVAL (op); 426: if ((value & ~0x0000ffff) == 0) /* ior reg,$r0,value */ 427: return FALSE; 428: 429: if (((unsigned long)(value + 32768)) <= 32767) /* subu reg,$r0,value */ 430: return FALSE; 431: 1.1.1.4 root 432: if ((value & 0x0000ffff) == 0) /* lui reg,value>>16 */ 1.1 root 433: return FALSE; 434: 435: return TRUE; 436: } 437: 438: /* Return truth value of whether OP is a register or the constant 0. */ 439: 440: int 441: reg_or_0_operand (op, mode) 442: rtx op; 443: enum machine_mode mode; 444: { 445: switch (GET_CODE (op)) 446: { 447: default: 448: break; 449: 450: case CONST_INT: 451: return (INTVAL (op) == 0); 452: 453: case CONST_DOUBLE: 1.1.1.3 root 454: if (op != CONST0_RTX (mode)) 1.1 root 455: return FALSE; 456: 457: return TRUE; 458: 459: case REG: 460: case SUBREG: 461: return register_operand (op, mode); 462: } 463: 464: return FALSE; 465: } 466: 467: /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */ 468: 469: int 470: mips_const_double_ok (op, mode) 471: rtx op; 472: enum machine_mode mode; 473: { 1.1.1.3 root 474: REAL_VALUE_TYPE d; 475: 1.1 root 476: if (GET_CODE (op) != CONST_DOUBLE) 477: return FALSE; 478: 1.1.1.4 root 479: if (mode == VOIDmode) 1.1 root 480: return TRUE; 481: 482: if (mode != SFmode && mode != DFmode) 483: return FALSE; 484: 1.1.1.3 root 485: if (op == CONST0_RTX (mode)) 1.1 root 486: return TRUE; 487: 1.1.1.4 root 488: /* ??? li.s does not work right with SGI's Irix 6 assembler. */ 489: if (ABI_64BIT) 490: return FALSE; 491: 1.1.1.3 root 492: REAL_VALUE_FROM_CONST_DOUBLE (d, op); 1.1 root 493: 1.1.1.3 root 494: if (REAL_VALUE_ISNAN (d)) 495: return FALSE; 1.1 root 496: 1.1.1.3 root 497: if (REAL_VALUE_NEGATIVE (d)) 498: d = REAL_VALUE_NEGATE (d); 1.1 root 499: 1.1.1.3 root 500: if (mode == DFmode) 501: { 502: if (REAL_VALUES_LESS (d, dfhigh) 503: && REAL_VALUES_LESS (dflow, d)) 1.1 root 504: return TRUE; 1.1.1.3 root 505: } 506: else 507: { 508: if (REAL_VALUES_LESS (d, sfhigh) 509: && REAL_VALUES_LESS (sflow, d)) 1.1 root 510: return TRUE; 511: } 512: 513: return FALSE; 514: } 515: 516: /* Return truth value if a memory operand fits in a single instruction 517: (ie, register + small offset). */ 518: 519: int 520: simple_memory_operand (op, mode) 521: rtx op; 522: enum machine_mode mode; 523: { 524: rtx addr, plus0, plus1; 525: 526: /* Eliminate non-memory operations */ 527: if (GET_CODE (op) != MEM) 528: return FALSE; 529: 530: /* dword operations really put out 2 instructions, so eliminate them. */ 1.1.1.3 root 531: if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD) 1.1 root 532: return FALSE; 533: 534: /* Decode the address now. */ 535: addr = XEXP (op, 0); 536: switch (GET_CODE (addr)) 537: { 538: default: 539: break; 540: 541: case REG: 542: return TRUE; 543: 544: case CONST_INT: 545: return SMALL_INT (op); 546: 547: case PLUS: 548: plus0 = XEXP (addr, 0); 549: plus1 = XEXP (addr, 1); 550: if (GET_CODE (plus0) == REG 551: && GET_CODE (plus1) == CONST_INT 552: && SMALL_INT (plus1)) 553: return TRUE; 554: 555: else if (GET_CODE (plus1) == REG 556: && GET_CODE (plus0) == CONST_INT 557: && SMALL_INT (plus0)) 558: return TRUE; 559: 560: else 561: return FALSE; 562: 563: #if 0 564: /* We used to allow small symbol refs here (ie, stuff in .sdata 565: or .sbss), but this causes some bugs in G++. Also, it won't 566: interfere if the MIPS linker rewrites the store instruction 567: because the function is PIC. */ 568: 569: case LABEL_REF: /* never gp relative */ 570: break; 571: 572: case CONST: 573: /* If -G 0, we can never have a GP relative memory operation. 574: Also, save some time if not optimizing. */ 1.1.1.3 root 575: if (!TARGET_GP_OPT) 1.1 root 576: return FALSE; 577: 578: { 579: rtx offset = const0_rtx; 1.1.1.3 root 580: addr = eliminate_constant_term (XEXP (addr, 0), &offset); 1.1 root 581: if (GET_CODE (op) != SYMBOL_REF) 582: return FALSE; 583: 584: /* let's be paranoid.... */ 1.1.1.3 root 585: if (! SMALL_INT (offset)) 1.1 root 586: return FALSE; 587: } 588: /* fall through */ 589: 590: case SYMBOL_REF: 591: return SYMBOL_REF_FLAG (addr); 592: #endif 593: } 594: 595: return FALSE; 596: } 597: 598: /* Return true if the code of this rtx pattern is EQ or NE. */ 599: 600: int 601: equality_op (op, mode) 602: rtx op; 603: enum machine_mode mode; 604: { 605: if (mode != GET_MODE (op)) 606: return FALSE; 607: 1.1.1.3 root 608: return (GET_CODE (op) == EQ || GET_CODE (op) == NE); 1.1 root 609: } 610: 611: /* Return true if the code is a relational operations (EQ, LE, etc.) */ 612: 613: int 614: cmp_op (op, mode) 615: rtx op; 616: enum machine_mode mode; 617: { 618: if (mode != GET_MODE (op)) 619: return FALSE; 620: 1.1.1.3 root 621: return (GET_RTX_CLASS (GET_CODE (op)) == '<'); 1.1 root 622: } 623: 624: /* Return true if the operand is either the PC or a label_ref. */ 625: 626: int 627: pc_or_label_operand (op, mode) 628: rtx op; 629: enum machine_mode mode; 630: { 631: if (op == pc_rtx) 632: return TRUE; 633: 634: if (GET_CODE (op) == LABEL_REF) 635: return TRUE; 636: 637: return FALSE; 638: } 639: 640: /* Test for a valid operand for a call instruction. 641: Don't allow the arg pointer register or virtual regs 642: since they may change into reg + const, which the patterns 643: can't handle yet. */ 644: 645: int 646: call_insn_operand (op, mode) 647: rtx op; 648: enum machine_mode mode; 649: { 650: if (GET_CODE (op) == MEM 651: && (CONSTANT_ADDRESS_P (XEXP (op, 0)) 652: || (GET_CODE (XEXP (op, 0)) == REG 653: && XEXP (op, 0) != arg_pointer_rtx 654: && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER 655: && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) 656: return 1; 657: return 0; 658: } 659: 1.1.1.3 root 660: /* Returns an operand string for the given instruction's delay slot, 661: after updating filled delay slot statistics. 1.1 root 662: 663: We assume that operands[0] is the target register that is set. 664: 665: In order to check the next insn, most of this functionality is moved 666: to FINAL_PRESCAN_INSN, and we just set the global variables that 667: it needs. */ 668: 1.1.1.3 root 669: /* ??? This function no longer does anything useful, because final_prescan_insn 670: now will never emit a nop. */ 671: 1.1 root 672: char * 673: mips_fill_delay_slot (ret, type, operands, cur_insn) 674: char *ret; /* normal string to return */ 675: enum delay_type type; /* type of delay */ 676: rtx operands[]; /* operands to use */ 677: rtx cur_insn; /* current insn */ 678: { 679: register rtx set_reg; 680: register enum machine_mode mode; 681: register rtx next_insn = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0; 682: register int num_nops; 683: 684: if (type == DELAY_LOAD || type == DELAY_FCMP) 685: num_nops = 1; 686: 687: else if (type == DELAY_HILO) 688: num_nops = 2; 689: 690: else 691: num_nops = 0; 692: 693: /* Make sure that we don't put nop's after labels. */ 694: next_insn = NEXT_INSN (cur_insn); 695: while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE) 696: next_insn = NEXT_INSN (next_insn); 697: 698: dslots_load_total += num_nops; 699: if (TARGET_DEBUG_F_MODE 700: || !optimize 701: || type == DELAY_NONE 702: || operands == (rtx *)0 703: || cur_insn == (rtx)0 704: || next_insn == (rtx)0 705: || GET_CODE (next_insn) == CODE_LABEL 706: || (set_reg = operands[0]) == (rtx)0) 707: { 708: dslots_number_nops = 0; 709: mips_load_reg = (rtx)0; 710: mips_load_reg2 = (rtx)0; 711: mips_load_reg3 = (rtx)0; 712: mips_load_reg4 = (rtx)0; 713: return ret; 714: } 715: 716: set_reg = operands[0]; 717: if (set_reg == (rtx)0) 718: return ret; 719: 720: while (GET_CODE (set_reg) == SUBREG) 721: set_reg = SUBREG_REG (set_reg); 722: 723: mode = GET_MODE (set_reg); 724: dslots_number_nops = num_nops; 1.1.1.3 root 725: mips_load_reg = set_reg; 726: if (GET_MODE_SIZE (mode) 1.1.1.4 root 727: > (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD)) 1.1.1.3 root 728: mips_load_reg2 = gen_rtx (REG, SImode, REGNO (set_reg) + 1); 729: else 730: mips_load_reg2 = 0; 1.1 root 731: 732: if (type == DELAY_HILO) 733: { 734: mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST); 735: mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1); 736: } 737: else 738: { 739: mips_load_reg3 = 0; 740: mips_load_reg4 = 0; 741: } 742: 743: return ret; 744: } 745: 746: 747: /* Determine whether a memory reference takes one (based off of the GP pointer), 748: two (normal), or three (label + reg) instructions, and bump the appropriate 749: counter for -mstats. */ 750: 751: void 752: mips_count_memory_refs (op, num) 753: rtx op; 754: int num; 755: { 756: int additional = 0; 757: int n_words = 0; 758: rtx addr, plus0, plus1; 759: enum rtx_code code0, code1; 760: int looping; 761: 762: if (TARGET_DEBUG_B_MODE) 763: { 764: fprintf (stderr, "\n========== mips_count_memory_refs:\n"); 765: debug_rtx (op); 766: } 767: 768: /* Skip MEM if passed, otherwise handle movsi of address. */ 769: addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0); 770: 771: /* Loop, going through the address RTL */ 772: do 773: { 774: looping = FALSE; 775: switch (GET_CODE (addr)) 776: { 777: default: 778: break; 779: 780: case REG: 781: case CONST_INT: 782: break; 783: 784: case PLUS: 785: plus0 = XEXP (addr, 0); 786: plus1 = XEXP (addr, 1); 787: code0 = GET_CODE (plus0); 788: code1 = GET_CODE (plus1); 789: 790: if (code0 == REG) 791: { 792: additional++; 793: addr = plus1; 794: looping = TRUE; 795: continue; 796: } 797: 798: if (code0 == CONST_INT) 799: { 800: addr = plus1; 801: looping = TRUE; 802: continue; 803: } 804: 805: if (code1 == REG) 806: { 807: additional++; 808: addr = plus0; 809: looping = TRUE; 810: continue; 811: } 812: 813: if (code1 == CONST_INT) 814: { 815: addr = plus0; 816: looping = TRUE; 817: continue; 818: } 819: 820: if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST) 821: { 822: addr = plus0; 823: looping = TRUE; 824: continue; 825: } 826: 827: if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST) 828: { 829: addr = plus1; 830: looping = TRUE; 831: continue; 832: } 833: 834: break; 835: 836: case LABEL_REF: 837: n_words = 2; /* always 2 words */ 838: break; 839: 840: case CONST: 841: addr = XEXP (addr, 0); 842: looping = TRUE; 843: continue; 844: 845: case SYMBOL_REF: 846: n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2; 847: break; 848: } 849: } 850: while (looping); 851: 852: if (n_words == 0) 853: return; 854: 855: n_words += additional; 856: if (n_words > 3) 857: n_words = 3; 858: 859: num_refs[n_words-1] += num; 860: } 861: 862: 1.1.1.3 root 863: /* Return RTL for the offset from the current function to the 864: argument. */ 865: 866: rtx 867: embedded_pic_offset (x) 868: rtx x; 869: { 870: if (embedded_pic_fnaddr_rtx == NULL) 1.1.1.4 root 871: { 872: rtx seq; 873: 874: embedded_pic_fnaddr_rtx = gen_reg_rtx (Pmode); 875: 876: /* Output code at function start to initialize the pseudo-reg. */ 877: /* ??? We used to do this in FINALIZE_PIC, but that does not work for 878: inline functions, because it is called after RTL for the function 879: has been copied. The pseudo-reg in embedded_pic_fnaddr_rtx however 880: does not get copied, and ends up not matching the rest of the RTL. 881: This solution works, but means that we get unnecessary code to 882: initialize this value every time a function is inlined into another 883: function. */ 884: start_sequence (); 885: emit_insn (gen_get_fnaddr (embedded_pic_fnaddr_rtx, 886: XEXP (DECL_RTL (current_function_decl), 0))); 887: seq = gen_sequence (); 888: end_sequence (); 889: push_topmost_sequence (); 890: emit_insn_after (seq, get_insns ()); 891: pop_topmost_sequence (); 892: } 893: 1.1.1.3 root 894: return gen_rtx (CONST, Pmode, 895: gen_rtx (MINUS, Pmode, x, 896: XEXP (DECL_RTL (current_function_decl), 0))); 897: } 898: 1.1 root 899: /* Return the appropriate instructions to move one operand to another. */ 900: 901: char * 902: mips_move_1word (operands, insn, unsignedp) 903: rtx operands[]; 904: rtx insn; 905: int unsignedp; 906: { 907: char *ret = 0; 908: rtx op0 = operands[0]; 909: rtx op1 = operands[1]; 910: enum rtx_code code0 = GET_CODE (op0); 911: enum rtx_code code1 = GET_CODE (op1); 912: enum machine_mode mode = GET_MODE (op0); 913: int subreg_word0 = 0; 914: int subreg_word1 = 0; 915: enum delay_type delay = DELAY_NONE; 916: 917: while (code0 == SUBREG) 918: { 919: subreg_word0 += SUBREG_WORD (op0); 920: op0 = SUBREG_REG (op0); 921: code0 = GET_CODE (op0); 922: } 923: 924: while (code1 == SUBREG) 925: { 926: subreg_word1 += SUBREG_WORD (op1); 927: op1 = SUBREG_REG (op1); 928: code1 = GET_CODE (op1); 929: } 930: 931: if (code0 == REG) 932: { 933: int regno0 = REGNO (op0) + subreg_word0; 934: 935: if (code1 == REG) 936: { 937: int regno1 = REGNO (op1) + subreg_word1; 938: 939: /* Just in case, don't do anything for assigning a register 940: to itself, unless we are filling a delay slot. */ 941: if (regno0 == regno1 && set_nomacro == 0) 942: ret = ""; 943: 944: else if (GP_REG_P (regno0)) 945: { 946: if (GP_REG_P (regno1)) 947: ret = "move\t%0,%1"; 948: 949: else if (MD_REG_P (regno1)) 950: { 951: delay = DELAY_HILO; 1.1.1.4 root 952: if (regno1 != HILO_REGNUM) 953: ret = "mf%1\t%0"; 954: else 955: ret = "mflo\t%0"; 1.1 root 956: } 957: 958: else 959: { 960: delay = DELAY_LOAD; 961: if (FP_REG_P (regno1)) 962: ret = "mfc1\t%0,%1"; 963: 964: else if (regno1 == FPSW_REGNUM) 965: ret = "cfc1\t%0,$31"; 966: } 967: } 968: 969: else if (FP_REG_P (regno0)) 970: { 971: if (GP_REG_P (regno1)) 972: { 973: delay = DELAY_LOAD; 974: ret = "mtc1\t%1,%0"; 975: } 976: 977: if (FP_REG_P (regno1)) 978: ret = "mov.s\t%0,%1"; 979: } 980: 981: else if (MD_REG_P (regno0)) 982: { 983: if (GP_REG_P (regno1)) 984: { 985: delay = DELAY_HILO; 1.1.1.4 root 986: if (regno0 != HILO_REGNUM) 987: ret = "mt%0\t%1"; 1.1 root 988: } 989: } 990: 991: else if (regno0 == FPSW_REGNUM) 992: { 993: if (GP_REG_P (regno1)) 994: { 995: delay = DELAY_LOAD; 996: ret = "ctc1\t%0,$31"; 997: } 998: } 999: } 1000: 1001: else if (code1 == MEM) 1002: { 1003: delay = DELAY_LOAD; 1004: 1005: if (TARGET_STATS) 1006: mips_count_memory_refs (op1, 1); 1007: 1008: if (GP_REG_P (regno0)) 1009: { 1010: /* For loads, use the mode of the memory item, instead of the 1011: target, so zero/sign extend can use this code as well. */ 1012: switch (GET_MODE (op1)) 1013: { 1.1.1.3 root 1014: default: 1015: break; 1016: case SFmode: 1017: ret = "lw\t%0,%1"; 1018: break; 1019: case SImode: 1020: ret = ((unsignedp && TARGET_64BIT) 1021: ? "lwu\t%0,%1" 1022: : "lw\t%0,%1"); 1023: break; 1024: case HImode: 1025: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; 1026: break; 1027: case QImode: 1028: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; 1029: break; 1.1 root 1030: } 1031: } 1032: 1033: else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode)) 1034: ret = "l.s\t%0,%1"; 1035: 1036: if (ret != (char *)0 && MEM_VOLATILE_P (op1)) 1037: { 1038: int i = strlen (ret); 1039: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1040: abort (); 1041: 1042: sprintf (volatile_buffer, "%%{%s%%}", ret); 1043: ret = volatile_buffer; 1044: } 1045: } 1046: 1.1.1.4 root 1047: else if (code1 == CONST_INT 1048: || (code1 == CONST_DOUBLE 1049: && GET_MODE (op1) == VOIDmode)) 1050: { 1051: if (code1 == CONST_DOUBLE) 1052: { 1053: /* This can happen when storing constants into long long 1054: bitfields. Just store the least significant word of 1055: the value. */ 1056: operands[1] = op1 = GEN_INT (CONST_DOUBLE_LOW (op1)); 1057: } 1058: 1.1 root 1059: if (INTVAL (op1) == 0) 1060: { 1061: if (GP_REG_P (regno0)) 1062: ret = "move\t%0,%z1"; 1063: 1064: else if (FP_REG_P (regno0)) 1065: { 1066: delay = DELAY_LOAD; 1067: ret = "mtc1\t%z1,%0"; 1068: } 1.1.1.4 root 1069: 1070: else if (MD_REG_P (regno0)) 1071: { 1072: delay = DELAY_HILO; 1073: ret = "mt%0\t%."; 1074: } 1.1 root 1075: } 1076: 1077: else if (GP_REG_P (regno0)) 1078: ret = (INTVAL (op1) < 0) ? "li\t%0,%1\t\t\t# %X1" : "li\t%0,%X1\t\t# %1"; 1079: } 1080: 1081: else if (code1 == CONST_DOUBLE && mode == SFmode) 1082: { 1.1.1.3 root 1083: if (op1 == CONST0_RTX (SFmode)) 1.1 root 1084: { 1085: if (GP_REG_P (regno0)) 1086: ret = "move\t%0,%."; 1087: 1088: else if (FP_REG_P (regno0)) 1089: { 1090: delay = DELAY_LOAD; 1091: ret = "mtc1\t%.,%0"; 1092: } 1093: } 1094: 1095: else 1096: { 1097: delay = DELAY_LOAD; 1098: ret = "li.s\t%0,%1"; 1099: } 1100: } 1101: 1102: else if (code1 == LABEL_REF) 1103: { 1104: if (TARGET_STATS) 1105: mips_count_memory_refs (op1, 1); 1106: 1107: ret = "la\t%0,%a1"; 1108: } 1109: 1110: else if (code1 == SYMBOL_REF || code1 == CONST) 1111: { 1112: if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1)) 1113: { 1114: rtx offset = const0_rtx; 1115: 1116: if (GET_CODE (op1) == CONST) 1117: op1 = eliminate_constant_term (XEXP (op1, 0), &offset); 1118: 1119: if (GET_CODE (op1) == SYMBOL_REF) 1120: { 1121: operands[2] = HALF_PIC_PTR (op1); 1122: 1123: if (TARGET_STATS) 1124: mips_count_memory_refs (operands[2], 1); 1125: 1126: if (INTVAL (offset) == 0) 1127: { 1128: delay = DELAY_LOAD; 1.1.1.3 root 1129: ret = (unsignedp && TARGET_64BIT 1130: ? "lwu\t%0,%2" 1131: : "lw\t%0,%2"); 1.1 root 1132: } 1133: else 1134: { 1135: dslots_load_total++; 1136: operands[3] = offset; 1.1.1.3 root 1137: if (unsignedp && TARGET_64BIT) 1138: ret = (SMALL_INT (offset)) 1139: ? "lwu\t%0,%2%#\n\tadd\t%0,%0,%3" 1140: : "lwu\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"; 1141: else 1142: ret = (SMALL_INT (offset)) 1143: ? "lw\t%0,%2%#\n\tadd\t%0,%0,%3" 1144: : "lw\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"; 1.1 root 1145: } 1146: } 1147: } 1148: else 1149: { 1150: if (TARGET_STATS) 1151: mips_count_memory_refs (op1, 1); 1152: 1153: ret = "la\t%0,%a1"; 1154: } 1155: } 1156: 1157: else if (code1 == PLUS) 1158: { 1159: rtx add_op0 = XEXP (op1, 0); 1160: rtx add_op1 = XEXP (op1, 1); 1161: 1162: if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT) 1163: { 1164: add_op0 = XEXP (op1, 1); /* reverse operands */ 1165: add_op1 = XEXP (op1, 0); 1166: } 1167: 1168: operands[2] = add_op0; 1169: operands[3] = add_op1; 1170: ret = "add%:\t%0,%2,%3"; 1171: } 1172: } 1173: 1174: else if (code0 == MEM) 1175: { 1176: if (TARGET_STATS) 1177: mips_count_memory_refs (op0, 1); 1178: 1179: if (code1 == REG) 1180: { 1181: int regno1 = REGNO (op1) + subreg_word1; 1182: 1183: if (GP_REG_P (regno1)) 1184: { 1185: switch (mode) 1186: { 1187: default: break; 1188: case SFmode: ret = "sw\t%1,%0"; break; 1189: case SImode: ret = "sw\t%1,%0"; break; 1190: case HImode: ret = "sh\t%1,%0"; break; 1191: case QImode: ret = "sb\t%1,%0"; break; 1192: } 1193: } 1194: 1195: else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode)) 1196: ret = "s.s\t%1,%0"; 1197: } 1198: 1199: else if (code1 == CONST_INT && INTVAL (op1) == 0) 1200: { 1201: switch (mode) 1202: { 1203: default: break; 1204: case SFmode: ret = "sw\t%z1,%0"; break; 1205: case SImode: ret = "sw\t%z1,%0"; break; 1206: case HImode: ret = "sh\t%z1,%0"; break; 1207: case QImode: ret = "sb\t%z1,%0"; break; 1208: } 1209: } 1210: 1.1.1.3 root 1211: else if (code1 == CONST_DOUBLE && op1 == CONST0_RTX (mode)) 1.1 root 1212: { 1213: switch (mode) 1214: { 1215: default: break; 1216: case SFmode: ret = "sw\t%.,%0"; break; 1217: case SImode: ret = "sw\t%.,%0"; break; 1218: case HImode: ret = "sh\t%.,%0"; break; 1219: case QImode: ret = "sb\t%.,%0"; break; 1220: } 1221: } 1222: 1223: if (ret != (char *)0 && MEM_VOLATILE_P (op0)) 1224: { 1225: int i = strlen (ret); 1226: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1227: abort (); 1228: 1229: sprintf (volatile_buffer, "%%{%s%%}", ret); 1230: ret = volatile_buffer; 1231: } 1232: } 1233: 1234: if (ret == (char *)0) 1235: { 1236: abort_with_insn (insn, "Bad move"); 1237: return 0; 1238: } 1239: 1240: if (delay != DELAY_NONE) 1241: return mips_fill_delay_slot (ret, delay, operands, insn); 1242: 1243: return ret; 1244: } 1245: 1246: 1247: /* Return the appropriate instructions to move 2 words */ 1248: 1249: char * 1250: mips_move_2words (operands, insn) 1251: rtx operands[]; 1252: rtx insn; 1253: { 1254: char *ret = 0; 1255: rtx op0 = operands[0]; 1256: rtx op1 = operands[1]; 1257: enum rtx_code code0 = GET_CODE (operands[0]); 1258: enum rtx_code code1 = GET_CODE (operands[1]); 1259: int subreg_word0 = 0; 1260: int subreg_word1 = 0; 1261: enum delay_type delay = DELAY_NONE; 1262: 1263: while (code0 == SUBREG) 1264: { 1265: subreg_word0 += SUBREG_WORD (op0); 1266: op0 = SUBREG_REG (op0); 1267: code0 = GET_CODE (op0); 1268: } 1269: 1270: while (code1 == SUBREG) 1271: { 1272: subreg_word1 += SUBREG_WORD (op1); 1273: op1 = SUBREG_REG (op1); 1274: code1 = GET_CODE (op1); 1275: } 1276: 1277: if (code0 == REG) 1278: { 1279: int regno0 = REGNO (op0) + subreg_word0; 1280: 1281: if (code1 == REG) 1282: { 1283: int regno1 = REGNO (op1) + subreg_word1; 1284: 1285: /* Just in case, don't do anything for assigning a register 1286: to itself, unless we are filling a delay slot. */ 1287: if (regno0 == regno1 && set_nomacro == 0) 1288: ret = ""; 1289: 1290: else if (FP_REG_P (regno0)) 1291: { 1292: if (FP_REG_P (regno1)) 1293: ret = "mov.d\t%0,%1"; 1294: 1295: else 1296: { 1297: delay = DELAY_LOAD; 1.1.1.3 root 1298: if (TARGET_FLOAT64) 1299: { 1300: if (!TARGET_64BIT) 1301: abort_with_insn (insn, "Bad move"); 1302: #ifdef TARGET_FP_CALL_32 1303: if (FP_CALL_GP_REG_P (regno1)) 1304: ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tdmtc1\t%1,%0"; 1305: else 1306: #endif 1307: ret = "dmtc1\t%1,%0"; 1308: } 1309: else 1310: ret = "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; 1.1 root 1311: } 1312: } 1313: 1314: else if (FP_REG_P (regno1)) 1315: { 1316: delay = DELAY_LOAD; 1.1.1.3 root 1317: if (TARGET_FLOAT64) 1318: { 1319: if (!TARGET_64BIT) 1320: abort_with_insn (insn, "Bad move"); 1321: #ifdef TARGET_FP_CALL_32 1322: if (FP_CALL_GP_REG_P (regno0)) 1323: ret = "dmfc1\t%0,%1\n\tmfc1\t%D0,%1\n\tdsrl\t%0,32"; 1324: else 1325: #endif 1326: ret = "dmfc1\t%0,%1"; 1327: } 1328: else 1329: ret = "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; 1.1 root 1330: } 1331: 1332: else if (MD_REG_P (regno0) && GP_REG_P (regno1)) 1333: { 1334: delay = DELAY_HILO; 1.1.1.3 root 1335: if (TARGET_64BIT) 1.1.1.4 root 1336: { 1337: if (regno0 != HILO_REGNUM) 1338: ret = "mt%0\t%1"; 1339: else if (regno1 == 0) 1340: ret = "mtlo\t%.\n\tmthi\t%."; 1341: } 1.1.1.3 root 1342: else 1343: ret = "mthi\t%M1\n\tmtlo\t%L1"; 1.1 root 1344: } 1345: 1346: else if (GP_REG_P (regno0) && MD_REG_P (regno1)) 1347: { 1348: delay = DELAY_HILO; 1.1.1.3 root 1349: if (TARGET_64BIT) 1.1.1.4 root 1350: { 1351: if (regno1 != HILO_REGNUM) 1352: ret = "mf%1\t%0"; 1353: } 1.1.1.3 root 1354: else 1355: ret = "mfhi\t%M0\n\tmflo\t%L0"; 1.1 root 1356: } 1357: 1.1.1.3 root 1358: else if (TARGET_64BIT) 1359: ret = "move\t%0,%1"; 1360: 1.1 root 1361: else if (regno0 != (regno1+1)) 1362: ret = "move\t%0,%1\n\tmove\t%D0,%D1"; 1363: 1364: else 1365: ret = "move\t%D0,%D1\n\tmove\t%0,%1"; 1366: } 1367: 1368: else if (code1 == CONST_DOUBLE) 1369: { 1.1.1.3 root 1370: /* Move zero from $0 unless !TARGET_64BIT and recipient 1371: is 64-bit fp reg, in which case generate a constant. */ 1372: if (op1 != CONST0_RTX (GET_MODE (op1)) 1373: || (TARGET_FLOAT64 && !TARGET_64BIT && FP_REG_P (regno0))) 1.1 root 1374: { 1375: if (GET_MODE (op1) == DFmode) 1376: { 1377: delay = DELAY_LOAD; 1.1.1.3 root 1378: #ifdef TARGET_FP_CALL_32 1379: if (FP_CALL_GP_REG_P (regno0)) 1380: { 1381: if (TARGET_FLOAT64 && !TARGET_64BIT) 1382: { 1.1.1.4 root 1383: split_double (op1, operands + 2, operands + 3); 1384: ret = "li\t%0,%2\n\tli\t%D0,%3"; 1.1.1.3 root 1385: } 1386: else 1387: ret = "li.d\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32"; 1388: } 1389: else 1390: #endif 1391: ret = "li.d\t%0,%1"; 1.1 root 1392: } 1393: 1.1.1.4 root 1394: else if (TARGET_64BIT) 1395: ret = "dli\t%0,%1"; 1.1.1.3 root 1396: 1.1 root 1397: else 1398: { 1.1.1.4 root 1399: split_double (op1, operands + 2, operands + 3); 1400: ret = "li\t%0,%2\n\tli\t%D0,%3"; 1.1 root 1401: } 1402: } 1403: 1404: else 1405: { 1406: if (GP_REG_P (regno0)) 1.1.1.3 root 1407: ret = (TARGET_64BIT 1408: #ifdef TARGET_FP_CALL_32 1409: && ! FP_CALL_GP_REG_P (regno0) 1410: #endif 1411: ) 1412: ? "move\t%0,%." 1413: : "move\t%0,%.\n\tmove\t%D0,%."; 1.1 root 1414: 1415: else if (FP_REG_P (regno0)) 1416: { 1417: delay = DELAY_LOAD; 1.1.1.3 root 1418: ret = (TARGET_64BIT) 1.1 root 1419: ? "dmtc1\t%.,%0" 1420: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; 1421: } 1422: } 1423: } 1424: 1425: else if (code1 == CONST_INT && INTVAL (op1) == 0) 1426: { 1427: if (GP_REG_P (regno0)) 1.1.1.3 root 1428: ret = (TARGET_64BIT) 1429: ? "move\t%0,%." 1430: : "move\t%0,%.\n\tmove\t%D0,%."; 1.1 root 1431: 1432: else if (FP_REG_P (regno0)) 1433: { 1434: delay = DELAY_LOAD; 1.1.1.3 root 1435: ret = (TARGET_64BIT) 1.1 root 1436: ? "dmtc1\t%.,%0" 1.1.1.3 root 1437: : (TARGET_FLOAT64 1438: ? "li.d\t%0,%1" 1439: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"); 1.1 root 1440: } 1.1.1.4 root 1441: else if (MD_REG_P (regno0)) 1442: { 1443: delay = DELAY_HILO; 1444: if (regno0 != HILO_REGNUM) 1445: ret = "mt%0\t%.\n"; 1446: else 1447: ret = "mtlo\t%.\n\tmthi\t%."; 1448: } 1.1 root 1449: } 1450: 1451: else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) 1452: { 1.1.1.3 root 1453: if (TARGET_64BIT) 1.1.1.4 root 1454: { 1455: if (HOST_BITS_PER_WIDE_INT < 64) 1456: /* We can't use 'X' for negative numbers, because then we won't 1457: get the right value for the upper 32 bits. */ 1458: ret = ((INTVAL (op1) < 0) ? "dli\t%0,%1\t\t\t# %X1" 1459: : "dli\t%0,%X1\t\t# %1"); 1460: else 1461: /* We must use 'X', because otherwise LONG_MIN will print as 1462: a number that the assembler won't accept. */ 1463: ret = "dli\t%0,%X1\t\t# %1"; 1464: } 1.1.1.3 root 1465: else 1466: { 1467: operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1); 1468: ret = "li\t%M0,%2\n\tli\t%L0,%1"; 1469: } 1.1 root 1470: } 1471: 1472: else if (code1 == MEM) 1473: { 1474: delay = DELAY_LOAD; 1475: 1476: if (TARGET_STATS) 1477: mips_count_memory_refs (op1, 2); 1478: 1479: if (FP_REG_P (regno0)) 1480: ret = "l.d\t%0,%1"; 1481: 1.1.1.3 root 1482: else if (TARGET_64BIT) 1483: { 1484: #ifdef TARGET_FP_CALL_32 1485: if (FP_CALL_GP_REG_P (regno0)) 1486: { 1487: if (offsettable_address_p (FALSE, SImode, op1)) 1488: ret = "lwu\t%0,%1\n\tlwu\t%D0,4+%1"; 1489: else 1490: ret = "ld\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32"; 1491: } 1492: else 1493: #endif 1494: ret = "ld\t%0,%1"; 1495: } 1496: 1.1 root 1497: else if (offsettable_address_p (1, DFmode, XEXP (op1, 0))) 1498: { 1499: operands[2] = adj_offsettable_operand (op1, 4); 1500: if (reg_mentioned_p (op0, op1)) 1501: ret = "lw\t%D0,%2\n\tlw\t%0,%1"; 1502: else 1503: ret = "lw\t%0,%1\n\tlw\t%D0,%2"; 1504: } 1505: 1506: if (ret != (char *)0 && MEM_VOLATILE_P (op1)) 1507: { 1508: int i = strlen (ret); 1509: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1510: abort (); 1511: 1512: sprintf (volatile_buffer, "%%{%s%%}", ret); 1513: ret = volatile_buffer; 1514: } 1515: } 1.1.1.3 root 1516: 1517: else if (code1 == LABEL_REF 1518: || code1 == SYMBOL_REF 1519: || code1 == CONST) 1520: { 1.1.1.4 root 1521: if (TARGET_STATS) 1522: mips_count_memory_refs (op1, 2); 1523: 1524: ret = "dla\t%0,%a1"; 1.1.1.3 root 1525: } 1.1 root 1526: } 1527: 1528: else if (code0 == MEM) 1529: { 1530: if (code1 == REG) 1531: { 1532: int regno1 = REGNO (op1) + subreg_word1; 1533: 1534: if (FP_REG_P (regno1)) 1535: ret = "s.d\t%1,%0"; 1536: 1.1.1.3 root 1537: else if (TARGET_64BIT) 1538: { 1539: #ifdef TARGET_FP_CALL_32 1540: if (FP_CALL_GP_REG_P (regno1)) 1541: ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tsd\t%1,%0"; 1542: else 1543: #endif 1544: ret = "sd\t%1,%0"; 1545: } 1546: 1.1 root 1547: else if (offsettable_address_p (1, DFmode, XEXP (op0, 0))) 1548: { 1549: operands[2] = adj_offsettable_operand (op0, 4); 1550: ret = "sw\t%1,%0\n\tsw\t%D1,%2"; 1551: } 1552: } 1553: 1.1.1.3 root 1554: else if (((code1 == CONST_INT && INTVAL (op1) == 0) 1555: || (code1 == CONST_DOUBLE 1556: && op1 == CONST0_RTX (GET_MODE (op1)))) 1557: && (TARGET_64BIT 1558: || offsettable_address_p (1, DFmode, XEXP (op0, 0)))) 1.1 root 1559: { 1.1.1.3 root 1560: if (TARGET_64BIT) 1.1 root 1561: ret = "sd\t%.,%0"; 1562: else 1563: { 1564: operands[2] = adj_offsettable_operand (op0, 4); 1565: ret = "sw\t%.,%0\n\tsw\t%.,%2"; 1566: } 1567: } 1568: 1569: if (TARGET_STATS) 1570: mips_count_memory_refs (op0, 2); 1571: 1572: if (ret != (char *)0 && MEM_VOLATILE_P (op0)) 1573: { 1574: int i = strlen (ret); 1575: if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1576: abort (); 1577: 1578: sprintf (volatile_buffer, "%%{%s%%}", ret); 1579: ret = volatile_buffer; 1580: } 1581: } 1582: 1583: if (ret == (char *)0) 1584: { 1585: abort_with_insn (insn, "Bad move"); 1586: return 0; 1587: } 1588: 1589: if (delay != DELAY_NONE) 1590: return mips_fill_delay_slot (ret, delay, operands, insn); 1591: 1592: return ret; 1593: } 1594: 1595: 1596: /* Provide the costs of an addressing mode that contains ADDR. 1597: If ADDR is not a valid address, its cost is irrelevant. */ 1598: 1599: int 1600: mips_address_cost (addr) 1601: rtx addr; 1602: { 1603: switch (GET_CODE (addr)) 1604: { 1605: default: 1606: break; 1607: 1608: case LO_SUM: 1609: case HIGH: 1610: return 1; 1611: 1612: case LABEL_REF: 1613: return 2; 1614: 1615: case CONST: 1616: { 1617: rtx offset = const0_rtx; 1.1.1.3 root 1618: addr = eliminate_constant_term (XEXP (addr, 0), &offset); 1.1 root 1619: if (GET_CODE (addr) == LABEL_REF) 1620: return 2; 1621: 1622: if (GET_CODE (addr) != SYMBOL_REF) 1623: return 4; 1624: 1.1.1.3 root 1625: if (! SMALL_INT (offset)) 1.1 root 1626: return 2; 1627: } 1628: /* fall through */ 1629: 1630: case SYMBOL_REF: 1631: return SYMBOL_REF_FLAG (addr) ? 1 : 2; 1632: 1633: case PLUS: 1634: { 1635: register rtx plus0 = XEXP (addr, 0); 1636: register rtx plus1 = XEXP (addr, 1); 1637: 1638: if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG) 1639: { 1640: plus0 = XEXP (addr, 1); 1641: plus1 = XEXP (addr, 0); 1642: } 1643: 1644: if (GET_CODE (plus0) != REG) 1645: break; 1646: 1647: switch (GET_CODE (plus1)) 1648: { 1649: default: 1650: break; 1651: 1652: case CONST_INT: 1.1.1.3 root 1653: return (SMALL_INT (plus1) ? 1 : 2); 1.1 root 1654: 1655: case CONST: 1656: case SYMBOL_REF: 1657: case LABEL_REF: 1658: case HIGH: 1659: case LO_SUM: 1660: return mips_address_cost (plus1) + 1; 1661: } 1662: } 1663: } 1664: 1665: return 4; 1666: } 1667: 1.1.1.3 root 1668: /* Return true if X is an address which needs a temporary register when 1669: reloaded while generating PIC code. */ 1670: 1671: int 1672: pic_address_needs_scratch (x) 1673: rtx x; 1674: { 1675: /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ 1676: if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS 1677: && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 1678: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT 1679: && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) 1680: return 1; 1681: 1682: return 0; 1683: } 1.1 root 1684: 1685: /* Make normal rtx_code into something we can index from an array */ 1686: 1687: static enum internal_test 1688: map_test_to_internal_test (test_code) 1689: enum rtx_code test_code; 1690: { 1691: enum internal_test test = ITEST_MAX; 1692: 1693: switch (test_code) 1694: { 1695: default: break; 1696: case EQ: test = ITEST_EQ; break; 1697: case NE: test = ITEST_NE; break; 1698: case GT: test = ITEST_GT; break; 1699: case GE: test = ITEST_GE; break; 1700: case LT: test = ITEST_LT; break; 1701: case LE: test = ITEST_LE; break; 1702: case GTU: test = ITEST_GTU; break; 1703: case GEU: test = ITEST_GEU; break; 1704: case LTU: test = ITEST_LTU; break; 1705: case LEU: test = ITEST_LEU; break; 1706: } 1707: 1708: return test; 1709: } 1710: 1711: 1712: /* Generate the code to compare two integer values. The return value is: 1713: (reg:SI xx) The pseudo register the comparison is in 1.1.1.3 root 1714: (rtx)0 No register, generate a simple branch. 1715: 1716: ??? This is called with result nonzero by the Scond patterns in 1717: mips.md. These patterns are called with a target in the mode of 1718: the Scond instruction pattern. Since this must be a constant, we 1719: must use SImode. This means that if RESULT is non-zero, it will 1720: always be an SImode register, even if TARGET_64BIT is true. We 1721: cope with this by calling convert_move rather than emit_move_insn. 1722: This will sometimes lead to an unnecessary extension of the result; 1723: for example: 1724: 1725: long long 1726: foo (long long i) 1727: { 1728: return i < 5; 1729: } 1730: 1731: */ 1.1 root 1732: 1733: rtx 1734: gen_int_relational (test_code, result, cmp0, cmp1, p_invert) 1735: enum rtx_code test_code; /* relational test (EQ, etc) */ 1736: rtx result; /* result to store comp. or 0 if branch */ 1737: rtx cmp0; /* first operand to compare */ 1738: rtx cmp1; /* second operand to compare */ 1739: int *p_invert; /* NULL or ptr to hold whether branch needs */ 1740: /* to reverse its test */ 1741: { 1742: struct cmp_info { 1743: enum rtx_code test_code; /* code to use in instruction (LT vs. LTU) */ 1744: int const_low; /* low bound of constant we can accept */ 1745: int const_high; /* high bound of constant we can accept */ 1746: int const_add; /* constant to add (convert LE -> LT) */ 1747: int reverse_regs; /* reverse registers in test */ 1748: int invert_const; /* != 0 if invert value if cmp1 is constant */ 1749: int invert_reg; /* != 0 if invert value if cmp1 is register */ 1750: int unsignedp; /* != 0 for unsigned comparisons. */ 1751: }; 1752: 1753: static struct cmp_info info[ (int)ITEST_MAX ] = { 1754: 1755: { XOR, 0, 65535, 0, 0, 0, 0, 0 }, /* EQ */ 1756: { XOR, 0, 65535, 0, 0, 1, 1, 0 }, /* NE */ 1757: { LT, -32769, 32766, 1, 1, 1, 0, 0 }, /* GT */ 1758: { LT, -32768, 32767, 0, 0, 1, 1, 0 }, /* GE */ 1759: { LT, -32768, 32767, 0, 0, 0, 0, 0 }, /* LT */ 1760: { LT, -32769, 32766, 1, 1, 0, 1, 0 }, /* LE */ 1761: { LTU, -32769, 32766, 1, 1, 1, 0, 1 }, /* GTU */ 1762: { LTU, -32768, 32767, 0, 0, 1, 1, 1 }, /* GEU */ 1763: { LTU, -32768, 32767, 0, 0, 0, 0, 1 }, /* LTU */ 1764: { LTU, -32769, 32766, 1, 1, 0, 1, 1 }, /* LEU */ 1765: }; 1766: 1767: enum internal_test test; 1.1.1.3 root 1768: enum machine_mode mode; 1.1 root 1769: struct cmp_info *p_info; 1770: int branch_p; 1771: int eqne_p; 1772: int invert; 1773: rtx reg; 1774: rtx reg2; 1775: 1776: test = map_test_to_internal_test (test_code); 1777: if (test == ITEST_MAX) 1778: abort (); 1779: 1780: p_info = &info[ (int)test ]; 1781: eqne_p = (p_info->test_code == XOR); 1782: 1.1.1.3 root 1783: mode = GET_MODE (cmp0); 1784: if (mode == VOIDmode) 1785: mode = GET_MODE (cmp1); 1786: 1.1 root 1787: /* Eliminate simple branches */ 1788: branch_p = (result == (rtx)0); 1789: if (branch_p) 1790: { 1791: if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG) 1792: { 1793: /* Comparisons against zero are simple branches */ 1794: if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) 1795: return (rtx)0; 1796: 1797: /* Test for beq/bne. */ 1798: if (eqne_p) 1799: return (rtx)0; 1800: } 1801: 1802: /* allocate a pseudo to calculate the value in. */ 1.1.1.3 root 1803: result = gen_reg_rtx (mode); 1.1 root 1804: } 1805: 1806: /* Make sure we can handle any constants given to us. */ 1807: if (GET_CODE (cmp0) == CONST_INT) 1.1.1.3 root 1808: cmp0 = force_reg (mode, cmp0); 1.1 root 1809: 1810: if (GET_CODE (cmp1) == CONST_INT) 1811: { 1812: HOST_WIDE_INT value = INTVAL (cmp1); 1.1.1.3 root 1813: if (value < p_info->const_low 1814: || value > p_info->const_high 1815: /* ??? Why? And why wasn't the similar code below modified too? */ 1816: || (TARGET_64BIT 1817: && HOST_BITS_PER_WIDE_INT < 64 1818: && p_info->const_add != 0 1819: && ((p_info->unsignedp 1820: ? ((unsigned HOST_WIDE_INT) (value + p_info->const_add) 1821: > INTVAL (cmp1)) 1822: : (value + p_info->const_add) > INTVAL (cmp1)) 1823: != (p_info->const_add > 0)))) 1824: cmp1 = force_reg (mode, cmp1); 1.1 root 1825: } 1826: 1827: /* See if we need to invert the result. */ 1828: invert = (GET_CODE (cmp1) == CONST_INT) 1829: ? p_info->invert_const 1830: : p_info->invert_reg; 1831: 1832: if (p_invert != (int *)0) 1833: { 1834: *p_invert = invert; 1835: invert = FALSE; 1836: } 1837: 1838: /* Comparison to constants, may involve adding 1 to change a LT into LE. 1839: Comparison between two registers, may involve switching operands. */ 1840: if (GET_CODE (cmp1) == CONST_INT) 1841: { 1842: if (p_info->const_add != 0) 1843: { 1844: HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; 1845: /* If modification of cmp1 caused overflow, 1846: we would get the wrong answer if we follow the usual path; 1.1.1.4 root 1847: thus, x > 0xffffffffU would turn into x > 0U. */ 1.1 root 1848: if ((p_info->unsignedp 1849: ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1) 1850: : new > INTVAL (cmp1)) 1851: != (p_info->const_add > 0)) 1.1.1.2 root 1852: { 1853: /* This test is always true, but if INVERT is true then 1854: the result of the test needs to be inverted so 0 should 1855: be returned instead. */ 1856: emit_move_insn (result, invert ? const0_rtx : const_true_rtx); 1857: return result; 1858: } 1.1 root 1859: else 1860: cmp1 = GEN_INT (new); 1861: } 1862: } 1863: else if (p_info->reverse_regs) 1864: { 1865: rtx temp = cmp0; 1866: cmp0 = cmp1; 1867: cmp1 = temp; 1868: } 1869: 1870: if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) 1871: reg = cmp0; 1872: else 1873: { 1.1.1.3 root 1874: reg = (invert || eqne_p) ? gen_reg_rtx (mode) : result; 1875: convert_move (reg, gen_rtx (p_info->test_code, mode, cmp0, cmp1), 0); 1.1 root 1876: } 1877: 1878: if (test == ITEST_NE) 1879: { 1.1.1.3 root 1880: convert_move (result, gen_rtx (GTU, mode, reg, const0_rtx), 0); 1.1 root 1881: invert = FALSE; 1882: } 1883: 1884: else if (test == ITEST_EQ) 1885: { 1.1.1.3 root 1886: reg2 = (invert) ? gen_reg_rtx (mode) : result; 1887: convert_move (reg2, gen_rtx (LTU, mode, reg, const1_rtx), 0); 1.1 root 1888: reg = reg2; 1889: } 1890: 1891: if (invert) 1.1.1.3 root 1892: convert_move (result, gen_rtx (XOR, mode, reg, const1_rtx), 0); 1.1 root 1893: 1894: return result; 1895: } 1896: 1897: 1898: /* Emit the common code for doing conditional branches. 1899: operand[0] is the label to jump to. 1.1.1.3 root 1900: The comparison operands are saved away by cmp{si,di,sf,df}. */ 1.1 root 1901: 1902: void 1903: gen_conditional_branch (operands, test_code) 1904: rtx operands[]; 1905: enum rtx_code test_code; 1906: { 1907: static enum machine_mode mode_map[(int)CMP_MAX][(int)ITEST_MAX] = { 1908: { /* CMP_SI */ 1909: SImode, /* eq */ 1910: SImode, /* ne */ 1911: SImode, /* gt */ 1912: SImode, /* ge */ 1913: SImode, /* lt */ 1914: SImode, /* le */ 1915: SImode, /* gtu */ 1916: SImode, /* geu */ 1917: SImode, /* ltu */ 1918: SImode, /* leu */ 1919: }, 1.1.1.3 root 1920: { /* CMP_DI */ 1921: DImode, /* eq */ 1922: DImode, /* ne */ 1923: DImode, /* gt */ 1924: DImode, /* ge */ 1925: DImode, /* lt */ 1926: DImode, /* le */ 1927: DImode, /* gtu */ 1928: DImode, /* geu */ 1929: DImode, /* ltu */ 1930: DImode, /* leu */ 1931: }, 1.1 root 1932: { /* CMP_SF */ 1933: CC_FPmode, /* eq */ 1934: CC_REV_FPmode, /* ne */ 1935: CC_FPmode, /* gt */ 1936: CC_FPmode, /* ge */ 1937: CC_FPmode, /* lt */ 1938: CC_FPmode, /* le */ 1939: VOIDmode, /* gtu */ 1940: VOIDmode, /* geu */ 1941: VOIDmode, /* ltu */ 1942: VOIDmode, /* leu */ 1943: }, 1944: { /* CMP_DF */ 1945: CC_FPmode, /* eq */ 1946: CC_REV_FPmode, /* ne */ 1947: CC_FPmode, /* gt */ 1948: CC_FPmode, /* ge */ 1949: CC_FPmode, /* lt */ 1950: CC_FPmode, /* le */ 1951: VOIDmode, /* gtu */ 1952: VOIDmode, /* geu */ 1953: VOIDmode, /* ltu */ 1954: VOIDmode, /* leu */ 1955: }, 1956: }; 1957: 1958: enum machine_mode mode; 1959: enum cmp_type type = branch_type; 1960: rtx cmp0 = branch_cmp[0]; 1961: rtx cmp1 = branch_cmp[1]; 1962: rtx label1 = gen_rtx (LABEL_REF, VOIDmode, operands[0]); 1963: rtx label2 = pc_rtx; 1964: rtx reg = (rtx)0; 1965: int invert = 0; 1966: enum internal_test test = map_test_to_internal_test (test_code); 1967: 1968: if (test == ITEST_MAX) 1969: { 1.1.1.3 root 1970: mode = word_mode; 1.1 root 1971: goto fail; 1972: } 1973: 1974: /* Get the machine mode to use (CCmode, CC_EQmode, CC_FPmode, or CC_REV_FPmode). */ 1975: mode = mode_map[(int)type][(int)test]; 1976: if (mode == VOIDmode) 1977: goto fail; 1978: 1.1.1.3 root 1979: switch (type) 1.1 root 1980: { 1981: default: 1982: goto fail; 1983: 1984: case CMP_SI: 1.1.1.3 root 1985: case CMP_DI: 1.1 root 1986: reg = gen_int_relational (test_code, (rtx)0, cmp0, cmp1, &invert); 1987: if (reg != (rtx)0) 1988: { 1989: cmp0 = reg; 1990: cmp1 = const0_rtx; 1991: test_code = NE; 1992: } 1993: 1994: /* Make sure not non-zero constant if ==/!= */ 1995: else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) 1.1.1.3 root 1996: cmp1 = force_reg (mode, cmp1); 1.1 root 1997: 1998: break; 1999: 2000: case CMP_DF: 2001: case CMP_SF: 2002: { 2003: rtx reg = gen_rtx (REG, mode, FPSW_REGNUM); 2004: emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (test_code, mode, cmp0, cmp1))); 2005: cmp0 = reg; 2006: cmp1 = const0_rtx; 2007: test_code = NE; 2008: } 2009: break; 2010: } 2011: 2012: /* Generate the jump */ 2013: if (invert) 2014: { 2015: label2 = label1; 2016: label1 = pc_rtx; 2017: } 2018: 2019: emit_jump_insn (gen_rtx (SET, VOIDmode, 2020: pc_rtx, 2021: gen_rtx (IF_THEN_ELSE, VOIDmode, 2022: gen_rtx (test_code, mode, cmp0, cmp1), 2023: label1, 2024: label2))); 2025: 2026: return; 2027: 2028: fail: 2029: abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test"); 2030: } 2031: 2032: 1.1.1.3 root 2033: #if 0 1.1 root 2034: /* Internal code to generate the load and store of one word/short/byte. 2035: The load is emitted directly, and the store insn is returned. */ 2036: 1.1.1.3 root 2037: #define UNITS_PER_MIPS_DWORD 8 2038: #define UNITS_PER_MIPS_WORD 4 2039: #define UNITS_PER_MIPS_HWORD 2 2040: 1.1 root 2041: static rtx 2042: block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src) 2043: rtx src_reg; /* register holding source memory address */ 2044: rtx dest_reg; /* register holding dest. memory address */ 2045: int *p_bytes; /* pointer to # bytes remaining */ 2046: int *p_offset; /* pointer to current offset */ 2047: int align; /* alignment */ 2048: rtx orig_src; /* original source for making a reg note */ 2049: { 2050: int bytes; /* # bytes remaining */ 2051: int offset; /* offset to use */ 2052: int size; /* size in bytes of load/store */ 2053: enum machine_mode mode; /* mode to use for load/store */ 2054: rtx reg; /* temporary register */ 2055: rtx src_addr; /* source address */ 2056: rtx dest_addr; /* destination address */ 2057: rtx insn; /* insn of the load */ 2058: rtx orig_src_addr; /* original source address */ 2059: rtx (*load_func)(); /* function to generate load insn */ 2060: rtx (*store_func)(); /* function to generate destination insn */ 2061: 2062: bytes = *p_bytes; 2063: if (bytes <= 0 || align <= 0) 2064: abort (); 2065: 1.1.1.3 root 2066: if (bytes >= UNITS_PER_MIPS_DWORD && align >= UNIS_PER_MIPS_DWORD) 2067: { 2068: mode = DImode; 2069: size = UNITS_PER_MIPS_DWORD; 2070: load_func = gen_movdi; 2071: store_func = gen_movdi; 2072: } 2073: else if (bytes >= UNITS_PER_MIPS_WORD && align >= UNITS_PER_MIPS_WORD) 1.1 root 2074: { 2075: mode = SImode; 1.1.1.3 root 2076: size = UNITS_PER_MIPS_WORD; 1.1 root 2077: load_func = gen_movsi; 2078: store_func = gen_movsi; 2079: } 2080: 2081: #if 0 2082: /* Don't generate unaligned moves here, rather defer those to the 1.1.1.3 root 2083: general movestrsi_internal pattern. 2084: If this gets commented back in, then should add the dword equivalent. */ 2085: else if (bytes >= UNITS_PER_MIPS_WORD) 1.1 root 2086: { 2087: mode = SImode; 1.1.1.3 root 2088: size = UNITS_PER_MIPS_WORD; 1.1 root 2089: load_func = gen_movsi_ulw; 2090: store_func = gen_movsi_usw; 2091: } 2092: #endif 2093: 1.1.1.3 root 2094: else if (bytes >= UNITS_PER_MIPS_SHORT && align >= UNITS_PER_MIPS_SHORT) 1.1 root 2095: { 2096: mode = HImode; 1.1.1.3 root 2097: size = UNITS_PER_MIPS_SHORT; 1.1 root 2098: load_func = gen_movhi; 2099: store_func = gen_movhi; 2100: } 2101: 2102: else 2103: { 2104: mode = QImode; 2105: size = 1; 2106: load_func = gen_movqi; 2107: store_func = gen_movqi; 2108: } 2109: 2110: offset = *p_offset; 2111: *p_offset = offset + size; 2112: *p_bytes = bytes - size; 2113: 2114: if (offset == 0) 2115: { 2116: src_addr = src_reg; 2117: dest_addr = dest_reg; 2118: } 2119: else 2120: { 2121: src_addr = gen_rtx (PLUS, Pmode, src_reg, GEN_INT (offset)); 2122: dest_addr = gen_rtx (PLUS, Pmode, dest_reg, GEN_INT (offset)); 2123: } 2124: 2125: reg = gen_reg_rtx (mode); 2126: insn = emit_insn ((*load_func) (reg, gen_rtx (MEM, mode, src_addr))); 2127: orig_src_addr = XEXP (orig_src, 0); 2128: if (CONSTANT_P (orig_src_addr)) 2129: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV, 2130: plus_constant (orig_src_addr, offset), 2131: REG_NOTES (insn)); 2132: 2133: return (*store_func) (gen_rtx (MEM, mode, dest_addr), reg); 2134: } 2135: #endif 2136: 2137: 2138: /* Write a series of loads/stores to move some bytes. Generate load/stores as follows: 2139: 2140: load 1 2141: load 2 2142: load 3 2143: store 1 2144: load 4 2145: store 2 2146: load 5 2147: store 3 2148: ... 2149: 2150: This way, no NOP's are needed, except at the end, and only 2151: two temp registers are needed. Two delay slots are used 2152: in deference to the R4000. */ 2153: 2154: #if 0 2155: static void 2156: block_move_sequence (dest_reg, src_reg, bytes, align, orig_src) 2157: rtx dest_reg; /* register holding destination address */ 2158: rtx src_reg; /* register holding source address */ 2159: int bytes; /* # bytes to move */ 2160: int align; /* max alignment to assume */ 2161: rtx orig_src; /* original source for making a reg note */ 2162: { 2163: int offset = 0; 2164: rtx prev2_store = (rtx)0; 2165: rtx prev_store = (rtx)0; 2166: rtx cur_store = (rtx)0; 2167: 2168: while (bytes > 0) 2169: { 2170: /* Is there a store to do? */ 2171: if (prev2_store) 2172: emit_insn (prev2_store); 2173: 2174: prev2_store = prev_store; 2175: prev_store = cur_store; 2176: cur_store = block_move_load_store (dest_reg, src_reg, 2177: &bytes, &offset, 2178: align, orig_src); 2179: } 2180: 2181: /* Finish up last three stores. */ 2182: if (prev2_store) 2183: emit_insn (prev2_store); 2184: 2185: if (prev_store) 2186: emit_insn (prev_store); 2187: 2188: if (cur_store) 2189: emit_insn (cur_store); 2190: } 2191: #endif 2192: 2193: 2194: /* Write a loop to move a constant number of bytes. Generate load/stores as follows: 2195: 2196: do { 2197: temp1 = src[0]; 2198: temp2 = src[1]; 2199: ... 2200: temp<last> = src[MAX_MOVE_REGS-1]; 2201: dest[0] = temp1; 2202: dest[1] = temp2; 2203: ... 2204: dest[MAX_MOVE_REGS-1] = temp<last>; 2205: src += MAX_MOVE_REGS; 2206: dest += MAX_MOVE_REGS; 2207: } while (src != final); 2208: 2209: This way, no NOP's are needed, and only MAX_MOVE_REGS+3 temp 2210: registers are needed. 2211: 2212: Aligned moves move MAX_MOVE_REGS*4 bytes every (2*MAX_MOVE_REGS)+3 2213: cycles, unaligned moves move MAX_MOVE_REGS*4 bytes every 2214: (4*MAX_MOVE_REGS)+3 cycles, assuming no cache misses. */ 2215: 2216: #define MAX_MOVE_REGS 4 2217: #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD) 2218: 1.1.1.3 root 2219: /* ??? Should add code to use DWORD load/stores. */ 2220: 1.1 root 2221: static void 2222: block_move_loop (dest_reg, src_reg, bytes, align, orig_src) 2223: rtx dest_reg; /* register holding destination address */ 2224: rtx src_reg; /* register holding source address */ 2225: int bytes; /* # bytes to move */ 2226: int align; /* alignment */ 2227: rtx orig_src; /* original source for making a reg note */ 2228: { 2229: rtx dest_mem = gen_rtx (MEM, BLKmode, dest_reg); 2230: rtx src_mem = gen_rtx (MEM, BLKmode, src_reg); 2231: rtx align_rtx = GEN_INT (align); 2232: rtx label; 2233: rtx final_src; 2234: rtx bytes_rtx; 2235: int leftover; 2236: 2237: if (bytes < 2*MAX_MOVE_BYTES) 2238: abort (); 2239: 2240: leftover = bytes % MAX_MOVE_BYTES; 2241: bytes -= leftover; 2242: 2243: label = gen_label_rtx (); 2244: final_src = gen_reg_rtx (Pmode); 2245: bytes_rtx = GEN_INT (bytes); 2246: 2247: if (bytes > 0x7fff) 2248: { 1.1.1.3 root 2249: if (TARGET_LONG64) 2250: { 2251: emit_insn (gen_movdi (final_src, bytes_rtx)); 2252: emit_insn (gen_adddi3 (final_src, final_src, src_reg)); 2253: } 2254: else 2255: { 2256: emit_insn (gen_movsi (final_src, bytes_rtx)); 2257: emit_insn (gen_addsi3 (final_src, final_src, src_reg)); 2258: } 1.1 root 2259: } 2260: else 1.1.1.3 root 2261: { 2262: if (TARGET_LONG64) 2263: emit_insn (gen_adddi3 (final_src, src_reg, bytes_rtx)); 2264: else 2265: emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx)); 2266: } 1.1 root 2267: 2268: emit_label (label); 2269: 2270: bytes_rtx = GEN_INT (MAX_MOVE_BYTES); 2271: emit_insn (gen_movstrsi_internal (dest_mem, src_mem, bytes_rtx, align_rtx)); 1.1.1.3 root 2272: if (TARGET_LONG64) 2273: { 2274: emit_insn (gen_adddi3 (src_reg, src_reg, bytes_rtx)); 2275: emit_insn (gen_adddi3 (dest_reg, dest_reg, bytes_rtx)); 2276: emit_insn (gen_cmpdi (src_reg, final_src)); 2277: } 2278: else 2279: { 2280: emit_insn (gen_addsi3 (src_reg, src_reg, bytes_rtx)); 2281: emit_insn (gen_addsi3 (dest_reg, dest_reg, bytes_rtx)); 2282: emit_insn (gen_cmpsi (src_reg, final_src)); 2283: } 1.1 root 2284: emit_jump_insn (gen_bne (label)); 2285: 2286: if (leftover) 2287: emit_insn (gen_movstrsi_internal (dest_mem, src_mem, 2288: GEN_INT (leftover), 2289: align_rtx)); 2290: } 2291: 2292: 2293: /* Use a library function to move some bytes. */ 2294: 2295: static void 2296: block_move_call (dest_reg, src_reg, bytes_rtx) 2297: rtx dest_reg; 2298: rtx src_reg; 2299: rtx bytes_rtx; 2300: { 1.1.1.3 root 2301: /* We want to pass the size as Pmode, which will normally be SImode 2302: but will be DImode if we are using 64 bit longs and pointers. */ 2303: if (GET_MODE (bytes_rtx) != VOIDmode 2304: && GET_MODE (bytes_rtx) != Pmode) 2305: bytes_rtx = convert_to_mode (Pmode, bytes_rtx, TRUE); 2306: 1.1 root 2307: #ifdef TARGET_MEM_FUNCTIONS 2308: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, 2309: VOIDmode, 3, 2310: dest_reg, Pmode, 2311: src_reg, Pmode, 1.1.1.3 root 2312: bytes_rtx, Pmode); 1.1 root 2313: #else 2314: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, 2315: VOIDmode, 3, 2316: src_reg, Pmode, 2317: dest_reg, Pmode, 1.1.1.3 root 2318: bytes_rtx, Pmode); 1.1 root 2319: #endif 2320: } 2321: 2322: 2323: /* Expand string/block move operations. 2324: 2325: operands[0] is the pointer to the destination. 2326: operands[1] is the pointer to the source. 2327: operands[2] is the number of bytes to move. 2328: operands[3] is the alignment. */ 2329: 2330: void 2331: expand_block_move (operands) 2332: rtx operands[]; 2333: { 2334: rtx bytes_rtx = operands[2]; 2335: rtx align_rtx = operands[3]; 2336: int constp = (GET_CODE (bytes_rtx) == CONST_INT); 2337: int bytes = (constp ? INTVAL (bytes_rtx) : 0); 2338: int align = INTVAL (align_rtx); 2339: rtx orig_src = operands[1]; 2340: rtx src_reg; 2341: rtx dest_reg; 2342: 2343: if (constp && bytes <= 0) 2344: return; 2345: 2346: if (align > UNITS_PER_WORD) 2347: align = UNITS_PER_WORD; 2348: 2349: /* Move the address into scratch registers. */ 2350: dest_reg = copy_addr_to_reg (XEXP (operands[0], 0)); 2351: src_reg = copy_addr_to_reg (XEXP (orig_src, 0)); 2352: 2353: if (TARGET_MEMCPY) 2354: block_move_call (dest_reg, src_reg, bytes_rtx); 2355: 2356: #if 0 2357: else if (constp && bytes <= 3*align) 2358: block_move_sequence (dest_reg, src_reg, bytes, align, orig_src); 2359: #endif 2360: 2361: else if (constp && bytes <= 2*MAX_MOVE_BYTES) 2362: emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg), 2363: gen_rtx (MEM, BLKmode, src_reg), 2364: bytes_rtx, align_rtx)); 2365: 2366: else if (constp && align >= UNITS_PER_WORD && optimize) 2367: block_move_loop (dest_reg, src_reg, bytes, align, orig_src); 2368: 2369: else if (constp && optimize) 2370: { 2371: /* If the alignment is not word aligned, generate a test at 2372: runtime, to see whether things wound up aligned, and we 2373: can use the faster lw/sw instead ulw/usw. */ 2374: 2375: rtx temp = gen_reg_rtx (Pmode); 2376: rtx aligned_label = gen_label_rtx (); 2377: rtx join_label = gen_label_rtx (); 2378: int leftover = bytes % MAX_MOVE_BYTES; 2379: 2380: bytes -= leftover; 2381: 1.1.1.3 root 2382: if (TARGET_LONG64) 2383: { 2384: emit_insn (gen_iordi3 (temp, src_reg, dest_reg)); 2385: emit_insn (gen_anddi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1))); 2386: emit_insn (gen_cmpdi (temp, const0_rtx)); 2387: } 2388: else 2389: { 2390: emit_insn (gen_iorsi3 (temp, src_reg, dest_reg)); 2391: emit_insn (gen_andsi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1))); 2392: emit_insn (gen_cmpsi (temp, const0_rtx)); 2393: } 1.1 root 2394: emit_jump_insn (gen_beq (aligned_label)); 2395: 2396: /* Unaligned loop. */ 2397: block_move_loop (dest_reg, src_reg, bytes, 1, orig_src); 2398: emit_jump_insn (gen_jump (join_label)); 2399: emit_barrier (); 2400: 2401: /* Aligned loop. */ 2402: emit_label (aligned_label); 2403: block_move_loop (dest_reg, src_reg, bytes, UNITS_PER_WORD, orig_src); 2404: emit_label (join_label); 2405: 2406: /* Bytes at the end of the loop. */ 2407: if (leftover) 2408: { 2409: #if 0 2410: if (leftover <= 3*align) 2411: block_move_sequence (dest_reg, src_reg, leftover, align, orig_src); 2412: 2413: else 2414: #endif 2415: emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg), 2416: gen_rtx (MEM, BLKmode, src_reg), 2417: GEN_INT (leftover), 2418: GEN_INT (align))); 2419: } 2420: } 2421: 2422: else 2423: block_move_call (dest_reg, src_reg, bytes_rtx); 2424: } 2425: 2426: 2427: /* Emit load/stores for a small constant block_move. 2428: 2429: operands[0] is the memory address of the destination. 2430: operands[1] is the memory address of the source. 2431: operands[2] is the number of bytes to move. 2432: operands[3] is the alignment. 2433: operands[4] is a temp register. 2434: operands[5] is a temp register. 2435: ... 2436: operands[3+num_regs] is the last temp register. 2437: 2438: The block move type can be one of the following: 2439: BLOCK_MOVE_NORMAL Do all of the block move. 2440: BLOCK_MOVE_NOT_LAST Do all but the last store. 2441: BLOCK_MOVE_LAST Do just the last store. */ 2442: 2443: char * 2444: output_block_move (insn, operands, num_regs, move_type) 2445: rtx insn; 2446: rtx operands[]; 2447: int num_regs; 2448: enum block_move_type move_type; 2449: { 2450: rtx dest_reg = XEXP (operands[0], 0); 2451: rtx src_reg = XEXP (operands[1], 0); 2452: int bytes = INTVAL (operands[2]); 2453: int align = INTVAL (operands[3]); 2454: int num = 0; 2455: int offset = 0; 2456: int use_lwl_lwr = FALSE; 2457: int last_operand = num_regs+4; 2458: int safe_regs = 4; 2459: int i; 2460: rtx xoperands[10]; 2461: 2462: struct { 2463: char *load; /* load insn without nop */ 2464: char *load_nop; /* load insn with trailing nop */ 2465: char *store; /* store insn */ 2466: char *final; /* if last_store used: NULL or swr */ 2467: char *last_store; /* last store instruction */ 2468: int offset; /* current offset */ 2469: enum machine_mode mode; /* mode to use on (MEM) */ 2470: } load_store[4]; 2471: 2472: /* Detect a bug in GCC, where it can give us a register 2473: the same as one of the addressing registers and reduce 2474: the number of registers available. */ 2475: for (i = 4; 2476: i < last_operand && safe_regs < (sizeof(xoperands) / sizeof(xoperands[0])); 2477: i++) 2478: { 2479: if (!reg_mentioned_p (operands[i], operands[0]) 2480: && !reg_mentioned_p (operands[i], operands[1])) 2481: 2482: xoperands[safe_regs++] = operands[i]; 2483: } 2484: 2485: if (safe_regs < last_operand) 2486: { 2487: xoperands[0] = operands[0]; 2488: xoperands[1] = operands[1]; 2489: xoperands[2] = operands[2]; 2490: xoperands[3] = operands[3]; 2491: return output_block_move (insn, xoperands, safe_regs-4, move_type); 2492: } 2493: 2494: /* If we are given global or static addresses, and we would be 2495: emitting a few instructions, try to save time by using a 2496: temporary register for the pointer. */ 2497: if (num_regs > 2 && (bytes > 2*align || move_type != BLOCK_MOVE_NORMAL)) 2498: { 2499: if (CONSTANT_P (src_reg)) 2500: { 2501: if (TARGET_STATS) 2502: mips_count_memory_refs (operands[1], 1); 2503: 2504: src_reg = operands[ 3 + num_regs-- ]; 2505: if (move_type != BLOCK_MOVE_LAST) 2506: { 2507: xoperands[1] = operands[1]; 2508: xoperands[0] = src_reg; 1.1.1.4 root 2509: if (Pmode == DImode) 2510: output_asm_insn ("dla\t%0,%1", xoperands); 2511: else 2512: output_asm_insn ("la\t%0,%1", xoperands); 1.1 root 2513: } 2514: } 2515: 2516: if (CONSTANT_P (dest_reg)) 2517: { 2518: if (TARGET_STATS) 2519: mips_count_memory_refs (operands[0], 1); 2520: 2521: dest_reg = operands[ 3 + num_regs-- ]; 2522: if (move_type != BLOCK_MOVE_LAST) 2523: { 2524: xoperands[1] = operands[0]; 2525: xoperands[0] = dest_reg; 1.1.1.4 root 2526: if (Pmode == DImode) 2527: output_asm_insn ("dla\t%0,%1", xoperands); 2528: else 2529: output_asm_insn ("la\t%0,%1", xoperands); 1.1 root 2530: } 2531: } 2532: } 2533: 2534: if (num_regs > (sizeof (load_store) / sizeof (load_store[0]))) 2535: num_regs = (sizeof (load_store) / sizeof (load_store[0])); 2536: 2537: else if (num_regs < 1) 2538: abort_with_insn (insn, "Cannot do block move, not enough scratch registers"); 2539: 2540: while (bytes > 0) 2541: { 2542: load_store[num].offset = offset; 2543: 1.1.1.3 root 2544: if (TARGET_64BIT && bytes >= 8 && align >= 8) 2545: { 2546: load_store[num].load = "ld\t%0,%1"; 2547: load_store[num].load_nop = "ld\t%0,%1%#"; 2548: load_store[num].store = "sd\t%0,%1"; 2549: load_store[num].last_store = "sd\t%0,%1"; 2550: load_store[num].final = (char *)0; 2551: load_store[num].mode = DImode; 2552: offset += 8; 2553: bytes -= 8; 2554: } 2555: 2556: /* ??? Fails because of a MIPS assembler bug? */ 2557: else if (TARGET_64BIT && bytes >= 8) 2558: { 1.1.1.4 root 2559: if (BYTES_BIG_ENDIAN) 2560: { 2561: load_store[num].load = "ldl\t%0,%1\n\tldr\t%0,%2"; 2562: load_store[num].load_nop = "ldl\t%0,%1\n\tldr\t%0,%2%#"; 2563: load_store[num].store = "sdl\t%0,%1\n\tsdr\t%0,%2"; 2564: load_store[num].last_store = "sdr\t%0,%2"; 2565: load_store[num].final = "sdl\t%0,%1"; 2566: } 2567: else 2568: { 2569: load_store[num].load = "ldl\t%0,%2\n\tldr\t%0,%1"; 2570: load_store[num].load_nop = "ldl\t%0,%2\n\tldr\t%0,%1%#"; 2571: load_store[num].store = "sdl\t%0,%2\n\tsdr\t%0,%1"; 2572: load_store[num].last_store = "sdr\t%0,%1"; 2573: load_store[num].final = "sdl\t%0,%2"; 2574: } 1.1.1.3 root 2575: load_store[num].mode = DImode; 2576: offset += 8; 2577: bytes -= 8; 2578: use_lwl_lwr = TRUE; 2579: } 2580: 2581: else if (bytes >= 4 && align >= 4) 1.1 root 2582: { 2583: load_store[num].load = "lw\t%0,%1"; 2584: load_store[num].load_nop = "lw\t%0,%1%#"; 2585: load_store[num].store = "sw\t%0,%1"; 2586: load_store[num].last_store = "sw\t%0,%1"; 2587: load_store[num].final = (char *)0; 2588: load_store[num].mode = SImode; 1.1.1.3 root 2589: offset += 4; 2590: bytes -= 4; 1.1 root 2591: } 2592: 1.1.1.3 root 2593: else if (bytes >= 4) 1.1 root 2594: { 1.1.1.4 root 2595: if (BYTES_BIG_ENDIAN) 2596: { 2597: load_store[num].load = "lwl\t%0,%1\n\tlwr\t%0,%2"; 2598: load_store[num].load_nop = "lwl\t%0,%1\n\tlwr\t%0,%2%#"; 2599: load_store[num].store = "swl\t%0,%1\n\tswr\t%0,%2"; 2600: load_store[num].last_store = "swr\t%0,%2"; 2601: load_store[num].final = "swl\t%0,%1"; 2602: } 2603: else 2604: { 2605: load_store[num].load = "lwl\t%0,%2\n\tlwr\t%0,%1"; 2606: load_store[num].load_nop = "lwl\t%0,%2\n\tlwr\t%0,%1%#"; 2607: load_store[num].store = "swl\t%0,%2\n\tswr\t%0,%1"; 2608: load_store[num].last_store = "swr\t%0,%1"; 2609: load_store[num].final = "swl\t%0,%2"; 2610: } 1.1 root 2611: load_store[num].mode = SImode; 1.1.1.3 root 2612: offset += 4; 2613: bytes -= 4; 1.1 root 2614: use_lwl_lwr = TRUE; 2615: } 2616: 1.1.1.3 root 2617: else if (bytes >= 2 && align >= 2) 1.1 root 2618: { 2619: load_store[num].load = "lh\t%0,%1"; 2620: load_store[num].load_nop = "lh\t%0,%1%#"; 2621: load_store[num].store = "sh\t%0,%1"; 2622: load_store[num].last_store = "sh\t%0,%1"; 2623: load_store[num].final = (char *)0; 2624: load_store[num].mode = HImode; 1.1.1.3 root 2625: offset += 2; 2626: bytes -= 2; 1.1 root 2627: } 2628: 2629: else 2630: { 2631: load_store[num].load = "lb\t%0,%1"; 2632: load_store[num].load_nop = "lb\t%0,%1%#"; 2633: load_store[num].store = "sb\t%0,%1"; 2634: load_store[num].last_store = "sb\t%0,%1"; 2635: load_store[num].final = (char *)0; 2636: load_store[num].mode = QImode; 2637: offset++; 2638: bytes--; 2639: } 2640: 2641: if (TARGET_STATS && move_type != BLOCK_MOVE_LAST) 2642: { 2643: dslots_load_total++; 2644: dslots_load_filled++; 2645: 2646: if (CONSTANT_P (src_reg)) 2647: mips_count_memory_refs (src_reg, 1); 2648: 2649: if (CONSTANT_P (dest_reg)) 2650: mips_count_memory_refs (dest_reg, 1); 2651: } 2652: 2653: /* Emit load/stores now if we have run out of registers or are 2654: at the end of the move. */ 2655: 2656: if (++num == num_regs || bytes == 0) 2657: { 2658: /* If only load/store, we need a NOP after the load. */ 2659: if (num == 1) 2660: { 2661: load_store[0].load = load_store[0].load_nop; 2662: if (TARGET_STATS && move_type != BLOCK_MOVE_LAST) 2663: dslots_load_filled--; 2664: } 2665: 2666: if (move_type != BLOCK_MOVE_LAST) 2667: { 2668: for (i = 0; i < num; i++) 2669: { 2670: int offset; 2671: 2672: if (!operands[i+4]) 2673: abort (); 2674: 2675: if (GET_MODE (operands[i+4]) != load_store[i].mode) 2676: operands[i+4] = gen_rtx (REG, load_store[i].mode, REGNO (operands[i+4])); 2677: 2678: offset = load_store[i].offset; 2679: xoperands[0] = operands[i+4]; 2680: xoperands[1] = gen_rtx (MEM, load_store[i].mode, 2681: plus_constant (src_reg, offset)); 2682: 2683: if (use_lwl_lwr) 1.1.1.3 root 2684: { 2685: int extra_offset; 2686: extra_offset = GET_MODE_SIZE (load_store[i].mode) - 1; 2687: xoperands[2] = gen_rtx (MEM, load_store[i].mode, 2688: plus_constant (src_reg, 2689: extra_offset 2690: + offset)); 2691: } 1.1 root 2692: 2693: output_asm_insn (load_store[i].load, xoperands); 2694: } 2695: } 2696: 2697: for (i = 0; i < num; i++) 2698: { 2699: int last_p = (i == num-1 && bytes == 0); 2700: int offset = load_store[i].offset; 2701: 2702: xoperands[0] = operands[i+4]; 2703: xoperands[1] = gen_rtx (MEM, load_store[i].mode, 2704: plus_constant (dest_reg, offset)); 2705: 2706: 2707: if (use_lwl_lwr) 1.1.1.3 root 2708: { 2709: int extra_offset; 2710: extra_offset = GET_MODE_SIZE (load_store[i].mode) - 1; 2711: xoperands[2] = gen_rtx (MEM, load_store[i].mode, 2712: plus_constant (dest_reg, 2713: extra_offset 2714: + offset)); 2715: } 1.1 root 2716: 2717: if (move_type == BLOCK_MOVE_NORMAL) 2718: output_asm_insn (load_store[i].store, xoperands); 2719: 2720: else if (move_type == BLOCK_MOVE_NOT_LAST) 2721: { 2722: if (!last_p) 2723: output_asm_insn (load_store[i].store, xoperands); 2724: 2725: else if (load_store[i].final != (char *)0) 2726: output_asm_insn (load_store[i].final, xoperands); 2727: } 2728: 2729: else if (last_p) 2730: output_asm_insn (load_store[i].last_store, xoperands); 2731: } 2732: 2733: num = 0; /* reset load_store */ 1.1.1.3 root 2734: use_lwl_lwr = FALSE; 1.1 root 2735: } 2736: } 2737: 2738: return ""; 2739: } 2740: 2741: 2742: /* Argument support functions. */ 2743: 2744: /* Initialize CUMULATIVE_ARGS for a function. */ 2745: 2746: void 2747: init_cumulative_args (cum, fntype, libname) 2748: CUMULATIVE_ARGS *cum; /* argument info to initialize */ 2749: tree fntype; /* tree ptr for function decl */ 2750: rtx libname; /* SYMBOL_REF of library name or 0 */ 2751: { 2752: static CUMULATIVE_ARGS zero_cum; 2753: tree param, next_param; 2754: 2755: if (TARGET_DEBUG_E_MODE) 2756: { 2757: fprintf (stderr, "\ninit_cumulative_args, fntype = 0x%.8lx", (long)fntype); 2758: if (!fntype) 2759: fputc ('\n', stderr); 2760: 2761: else 2762: { 2763: tree ret_type = TREE_TYPE (fntype); 2764: fprintf (stderr, ", fntype code = %s, ret code = %s\n", 2765: tree_code_name[ (int)TREE_CODE (fntype) ], 2766: tree_code_name[ (int)TREE_CODE (ret_type) ]); 2767: } 2768: } 2769: 2770: *cum = zero_cum; 2771: 2772: /* Determine if this function has variable arguments. This is 2773: indicated by the last argument being 'void_type_mode' if there 2774: are no variable arguments. The standard MIPS calling sequence 2775: passes all arguments in the general purpose registers in this 2776: case. */ 2777: 2778: for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; 2779: param != (tree)0; 2780: param = next_param) 2781: { 2782: next_param = TREE_CHAIN (param); 2783: if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) 2784: cum->gp_reg_found = 1; 2785: } 2786: } 2787: 2788: /* Advance the argument to the next argument position. */ 2789: 2790: void 2791: function_arg_advance (cum, mode, type, named) 2792: CUMULATIVE_ARGS *cum; /* current arg information */ 2793: enum machine_mode mode; /* current arg mode */ 2794: tree type; /* type of the argument or 0 if lib support */ 2795: int named; /* whether or not the argument was named */ 2796: { 2797: if (TARGET_DEBUG_E_MODE) 2798: fprintf (stderr, 2799: "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n", 2800: cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), 2801: type, named); 2802: 2803: cum->arg_number++; 2804: switch (mode) 2805: { 1.1.1.2 root 2806: case VOIDmode: 1.1 root 2807: break; 2808: 1.1.1.2 root 2809: default: 2810: if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT 2811: && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) 2812: abort (); 2813: cum->gp_reg_found = 1; 1.1.1.3 root 2814: cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) 2815: / UNITS_PER_WORD); 1.1 root 2816: break; 2817: 2818: case BLKmode: 2819: cum->gp_reg_found = 1; 1.1.1.3 root 2820: cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1) 2821: / UNITS_PER_WORD); 1.1 root 2822: break; 2823: 2824: case SFmode: 2825: cum->arg_words++; 2826: break; 2827: 2828: case DFmode: 1.1.1.3 root 2829: cum->arg_words += (TARGET_64BIT ? 1 : 2); 1.1 root 2830: break; 2831: 2832: case DImode: 2833: cum->gp_reg_found = 1; 1.1.1.3 root 2834: cum->arg_words += (TARGET_64BIT ? 1 : 2); 1.1 root 2835: break; 2836: 2837: case QImode: 2838: case HImode: 2839: case SImode: 2840: cum->gp_reg_found = 1; 2841: cum->arg_words++; 2842: break; 2843: } 2844: } 2845: 1.1.1.3 root 2846: /* Return an RTL expression containing the register for the given mode, 2847: or 0 if the argument is to be passed on the stack. */ 1.1 root 2848: 2849: struct rtx_def * 2850: function_arg (cum, mode, type, named) 2851: CUMULATIVE_ARGS *cum; /* current arg information */ 2852: enum machine_mode mode; /* current arg mode */ 2853: tree type; /* type of the argument or 0 if lib support */ 2854: int named; /* != 0 for normal args, == 0 for ... args */ 2855: { 2856: rtx ret; 2857: int regbase = -1; 2858: int bias = 0; 2859: int struct_p = ((type != (tree)0) 2860: && (TREE_CODE (type) == RECORD_TYPE 2861: || TREE_CODE (type) == UNION_TYPE)); 2862: 2863: if (TARGET_DEBUG_E_MODE) 2864: fprintf (stderr, 2865: "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ", 2866: cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), 2867: type, named); 2868: 2869: switch (mode) 2870: { 2871: case SFmode: 1.1.1.4 root 2872: if (! ABI_64BIT || mips_isa < 3) 1.1.1.3 root 2873: { 1.1.1.4 root 2874: if (cum->gp_reg_found || cum->arg_number >= 2 || TARGET_SOFT_FLOAT) 2875: regbase = GP_ARG_FIRST; 2876: else 2877: { 2878: regbase = FP_ARG_FIRST; 2879: /* If the first arg was a float in a floating point register, 2880: then set bias to align this float arg properly. */ 2881: if (cum->arg_words == 1) 2882: bias = 1; 2883: } 1.1.1.3 root 2884: } 1.1.1.4 root 2885: else 2886: regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST); 1.1 root 2887: break; 2888: 2889: case DFmode: 1.1.1.3 root 2890: if (! TARGET_64BIT) 2891: cum->arg_words += (cum->arg_words & 1); 1.1.1.4 root 2892: if (! ABI_64BIT || mips_isa < 3) 2893: regbase = ((cum->gp_reg_found 2894: || TARGET_SOFT_FLOAT 2895: || TARGET_SINGLE_FLOAT 2896: || cum->arg_number >= 2) 2897: ? GP_ARG_FIRST 2898: : FP_ARG_FIRST); 2899: else 2900: regbase = (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT || ! named 2901: ? GP_ARG_FIRST : FP_ARG_FIRST); 1.1 root 2902: break; 2903: 1.1.1.2 root 2904: default: 2905: if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT 2906: && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) 2907: abort (); 2908: 2909: /* Drops through. */ 1.1 root 2910: case BLKmode: 1.1.1.3 root 2911: if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD 2912: && ! TARGET_64BIT) 1.1 root 2913: cum->arg_words += (cum->arg_words & 1); 2914: 2915: regbase = GP_ARG_FIRST; 2916: break; 2917: 2918: case VOIDmode: 2919: case QImode: 2920: case HImode: 2921: case SImode: 2922: regbase = GP_ARG_FIRST; 2923: break; 2924: 2925: case DImode: 1.1.1.3 root 2926: if (! TARGET_64BIT) 2927: cum->arg_words += (cum->arg_words & 1); 1.1 root 2928: regbase = GP_ARG_FIRST; 2929: } 2930: 2931: if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) 2932: { 2933: if (TARGET_DEBUG_E_MODE) 2934: fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : ""); 2935: 2936: ret = (rtx)0; 2937: } 2938: else 2939: { 2940: if (regbase == -1) 2941: abort (); 2942: 2943: ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias); 2944: 2945: if (TARGET_DEBUG_E_MODE) 2946: fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias], 2947: struct_p ? ", [struct]" : ""); 2948: 2949: /* The following is a hack in order to pass 1 byte structures 2950: the same way that the MIPS compiler does (namely by passing 2951: the structure in the high byte or half word of the register). 2952: This also makes varargs work. If we have such a structure, 2953: we save the adjustment RTL, and the call define expands will 2954: emit them. For the VOIDmode argument (argument after the 1.1.1.3 root 2955: last real argument), pass back a parallel vector holding each 1.1 root 2956: of the adjustments. */ 2957: 1.1.1.2 root 2958: /* ??? function_arg can be called more than once for each argument. 2959: As a result, we compute more adjustments than we need here. 2960: See the CUMULATIVE_ARGS definition in mips.h. */ 2961: 1.1.1.3 root 2962: /* ??? This scheme requires everything smaller than the word size to 2963: shifted to the left, but when TARGET_64BIT and ! TARGET_INT64, 2964: that would mean every int needs to be shifted left, which is very 2965: inefficient. Let's not carry this compatibility to the 64 bit 2966: calling convention for now. */ 2967: 2968: if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD 2969: && ! TARGET_64BIT) 1.1 root 2970: { 1.1.1.2 root 2971: rtx amount = GEN_INT (BITS_PER_WORD 2972: - int_size_in_bytes (type) * BITS_PER_UNIT); 1.1.1.3 root 2973: rtx reg = gen_rtx (REG, word_mode, regbase + cum->arg_words + bias); 2974: if (TARGET_64BIT) 2975: cum->adjust[ cum->num_adjusts++ ] = gen_ashldi3 (reg, reg, amount); 2976: else 2977: cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount); 1.1 root 2978: } 2979: } 2980: 2981: if (mode == VOIDmode && cum->num_adjusts > 0) 2982: ret = gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (cum->num_adjusts, cum->adjust)); 2983: 2984: return ret; 2985: } 2986: 2987: 2988: int 2989: function_arg_partial_nregs (cum, mode, type, named) 2990: CUMULATIVE_ARGS *cum; /* current arg information */ 2991: enum machine_mode mode; /* current arg mode */ 2992: tree type; /* type of the argument or 0 if lib support */ 2993: int named; /* != 0 for normal args, == 0 for ... args */ 2994: { 1.1.1.2 root 2995: if ((mode == BLKmode 2996: || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT 2997: || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) 2998: && cum->arg_words < MAX_ARGS_IN_REGISTERS) 2999: { 3000: int words; 3001: if (mode == BLKmode) 1.1.1.3 root 3002: words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1) 3003: / UNITS_PER_WORD); 1.1.1.2 root 3004: else 1.1.1.3 root 3005: words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 1.1 root 3006: 3007: if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS) 3008: return 0; /* structure fits in registers */ 3009: 3010: if (TARGET_DEBUG_E_MODE) 3011: fprintf (stderr, "function_arg_partial_nregs = %d\n", 3012: MAX_ARGS_IN_REGISTERS - cum->arg_words); 3013: 3014: return MAX_ARGS_IN_REGISTERS - cum->arg_words; 3015: } 3016: 1.1.1.3 root 3017: else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1 3018: && ! TARGET_64BIT) 1.1 root 3019: { 3020: if (TARGET_DEBUG_E_MODE) 3021: fprintf (stderr, "function_arg_partial_nregs = 1\n"); 3022: 3023: return 1; 3024: } 3025: 3026: return 0; 3027: } 3028: 3029: 3030: /* Print the options used in the assembly file. */ 3031: 3032: static struct {char *name; int value;} target_switches [] 3033: = TARGET_SWITCHES; 3034: 3035: void 3036: print_options (out) 3037: FILE *out; 3038: { 3039: int line_len; 3040: int len; 3041: int j; 3042: char **p; 3043: int mask = TARGET_DEFAULT; 3044: 3045: /* Allow assembly language comparisons with -mdebug eliminating the 3046: compiler version number and switch lists. */ 3047: 3048: if (TARGET_DEBUG_MODE) 3049: return; 3050: 3051: fprintf (out, "\n # %s %s", language_string, version_string); 3052: #ifdef TARGET_VERSION_INTERNAL 3053: TARGET_VERSION_INTERNAL (out); 3054: #endif 3055: #ifdef __GNUC__ 3056: fprintf (out, " compiled by GNU C\n\n"); 3057: #else 3058: fprintf (out, " compiled by CC\n\n"); 3059: #endif 3060: 3061: fprintf (out, " # Cc1 defaults:"); 3062: line_len = 32767; 3063: for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++) 3064: { 3065: if (target_switches[j].name[0] != '\0' 3066: && target_switches[j].value > 0 3067: && (target_switches[j].value & mask) == target_switches[j].value) 3068: { 3069: mask &= ~ target_switches[j].value; 3070: len = strlen (target_switches[j].name) + 1; 3071: if (len + line_len > 79) 3072: { 3073: line_len = 2; 3074: fputs ("\n #", out); 3075: } 3076: fprintf (out, " -m%s", target_switches[j].name); 3077: line_len += len; 3078: } 3079: } 3080: 3081: fprintf (out, "\n\n # Cc1 arguments (-G value = %d, Cpu = %s, ISA = %d):", 3082: mips_section_threshold, mips_cpu_string, mips_isa); 3083: 3084: line_len = 32767; 3085: for (p = &save_argv[1]; *p != (char *)0; p++) 3086: { 3087: char *arg = *p; 3088: if (*arg == '-') 3089: { 3090: len = strlen (arg) + 1; 3091: if (len + line_len > 79) 3092: { 3093: line_len = 2; 3094: fputs ("\n #", out); 3095: } 3096: fprintf (out, " %s", *p); 3097: line_len += len; 3098: } 3099: } 3100: 3101: fputs ("\n\n", out); 3102: } 3103: 3104: 3105: /* Abort after printing out a specific insn. */ 3106: 3107: void 3108: abort_with_insn (insn, reason) 3109: rtx insn; 3110: char *reason; 3111: { 3112: error (reason); 3113: debug_rtx (insn); 3114: abort (); 3115: } 3116: 3117: /* Write a message to stderr (for use in macros expanded in files that do not 3118: include stdio.h). */ 3119: 3120: void 3121: trace (s, s1, s2) 3122: char *s, *s1, *s2; 3123: { 3124: fprintf (stderr, s, s1, s2); 3125: } 3126: 3127: 3128: #ifdef SIGINFO 3129: 3130: static void 3131: siginfo (signo) 3132: int signo; 3133: { 3134: fprintf (stderr, "compiling '%s' in '%s'\n", 3135: (current_function_name != (char *)0) ? current_function_name : "<toplevel>", 3136: (current_function_file != (char *)0) ? current_function_file : "<no file>"); 3137: fflush (stderr); 3138: } 3139: #endif /* SIGINFO */ 3140: 3141: 3142: /* Set up the threshold for data to go into the small data area, instead 3143: of the normal data area, and detect any conflicts in the switches. */ 3144: 3145: void 3146: override_options () 3147: { 3148: register int i, start; 3149: register int regno; 3150: register enum machine_mode mode; 3151: 3152: mips_section_threshold = (g_switch_set) ? g_switch_value : MIPS_DEFAULT_GVALUE; 3153: 1.1.1.3 root 3154: if (mips_section_threshold <= 0) 3155: target_flags &= ~MASK_GPOPT; 3156: else if (optimize) 3157: target_flags |= MASK_GPOPT; 3158: 3159: /* Get the architectural level. */ 3160: if (mips_isa_string == (char *)0) 3161: { 3162: #ifdef MIPS_ISA_DEFAULT 3163: mips_isa = MIPS_ISA_DEFAULT; 3164: #else 3165: mips_isa = 1; 3166: #endif 3167: } 3168: 3169: else if (isdigit (*mips_isa_string)) 3170: { 3171: mips_isa = atoi (mips_isa_string); 1.1.1.4 root 3172: if (mips_isa < 1 || mips_isa > 4) 1.1.1.3 root 3173: { 3174: error ("-mips%d not supported", mips_isa); 3175: mips_isa = 1; 3176: } 3177: } 3178: 3179: else 3180: { 3181: error ("bad value (%s) for -mips switch", mips_isa_string); 3182: mips_isa = 1; 3183: } 3184: 1.1.1.4 root 3185: #ifdef MIPS_CPU_STRING_DEFAULT 3186: /* ??? There is a minor inconsistency here. If the user specifies an ISA 3187: greater than that supported by the default processor, then the user gets 3188: an error. Normally, the compiler will just default to the base level cpu 3189: for the indicated isa. */ 3190: if (mips_cpu_string == (char *)0) 3191: mips_cpu_string = MIPS_CPU_STRING_DEFAULT; 3192: #endif 3193: 1.1 root 3194: /* Identify the processor type */ 3195: if (mips_cpu_string == (char *)0 3196: || !strcmp (mips_cpu_string, "default") 3197: || !strcmp (mips_cpu_string, "DEFAULT")) 3198: { 1.1.1.3 root 3199: switch (mips_isa) 3200: { 3201: default: 3202: mips_cpu_string = "3000"; 3203: mips_cpu = PROCESSOR_R3000; 3204: break; 3205: case 2: 3206: mips_cpu_string = "6000"; 3207: mips_cpu = PROCESSOR_R6000; 3208: break; 3209: case 3: 3210: mips_cpu_string = "4000"; 3211: mips_cpu = PROCESSOR_R4000; 3212: break; 1.1.1.4 root 3213: case 4: 3214: mips_cpu_string = "8000"; 3215: mips_cpu = PROCESSOR_R8000; 3216: break; 1.1.1.3 root 3217: } 1.1 root 3218: } 3219: 3220: else 3221: { 3222: char *p = mips_cpu_string; 3223: 3224: if (*p == 'r' || *p == 'R') 3225: p++; 3226: 3227: /* Since there is no difference between a R2000 and R3000 in 3228: terms of the scheduler, we collapse them into just an R3000. */ 3229: 3230: mips_cpu = PROCESSOR_DEFAULT; 3231: switch (*p) 3232: { 3233: case '2': 3234: if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K")) 3235: mips_cpu = PROCESSOR_R3000; 3236: break; 3237: 3238: case '3': 3239: if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K")) 3240: mips_cpu = PROCESSOR_R3000; 3241: break; 3242: 3243: case '4': 3244: if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K")) 3245: mips_cpu = PROCESSOR_R4000; 1.1.1.3 root 3246: /* The r4400 is exactly the same as the r4000 from the compiler's 3247: viewpoint. */ 3248: else if (!strcmp (p, "4400")) 3249: mips_cpu = PROCESSOR_R4000; 3250: else if (!strcmp (p, "4600")) 3251: mips_cpu = PROCESSOR_R4600; 1.1.1.4 root 3252: else if (!strcmp (p, "4650")) 3253: mips_cpu = PROCESSOR_R4650; 1.1 root 3254: break; 3255: 3256: case '6': 3257: if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K")) 3258: mips_cpu = PROCESSOR_R6000; 3259: break; 1.1.1.3 root 3260: 1.1.1.4 root 3261: case '8': 3262: if (!strcmp (p, "8000")) 3263: mips_cpu = PROCESSOR_R8000; 3264: break; 3265: 1.1.1.3 root 3266: case 'o': 3267: if (!strcmp (p, "orion")) 3268: mips_cpu = PROCESSOR_R4600; 3269: break; 1.1 root 3270: } 3271: 3272: if (mips_cpu == PROCESSOR_DEFAULT) 3273: { 3274: error ("bad value (%s) for -mcpu= switch", mips_cpu_string); 3275: mips_cpu_string = "default"; 3276: } 3277: } 3278: 1.1.1.3 root 3279: if ((mips_cpu == PROCESSOR_R3000 && mips_isa > 1) 1.1.1.4 root 3280: || (mips_cpu == PROCESSOR_R6000 && mips_isa > 2) 3281: || ((mips_cpu == PROCESSOR_R4000 3282: || mips_cpu == PROCESSOR_R4600 3283: || mips_cpu == PROCESSOR_R4650) 3284: && mips_isa > 3)) 1.1 root 3285: error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); 3286: 3287: /* make sure sizes of ints/longs/etc. are ok */ 3288: if (mips_isa < 3) 3289: { 3290: if (TARGET_INT64) 1.1.1.4 root 3291: fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit ints"); 1.1 root 3292: 3293: else if (TARGET_LONG64) 1.1.1.4 root 3294: fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit longs"); 1.1 root 3295: 3296: else if (TARGET_FLOAT64) 1.1.1.4 root 3297: fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit fp registers"); 1.1.1.3 root 3298: 3299: else if (TARGET_64BIT) 1.1.1.4 root 3300: fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit gp registers"); 1.1 root 3301: } 3302: 1.1.1.4 root 3303: if (ABI_64BIT && mips_isa >= 3) 3304: flag_pcc_struct_return = 0; 3305: 1.1 root 3306: /* Tell halfpic.c that we have half-pic code if we do. */ 3307: if (TARGET_HALF_PIC) 3308: HALF_PIC_INIT (); 3309: 1.1.1.3 root 3310: /* -fpic (-KPIC) is the default when TARGET_ABICALLS is defined. We need 3311: to set flag_pic so that the LEGITIMATE_PIC_OPERAND_P macro will work. */ 3312: /* ??? -non_shared turns off pic code generation, but this is not 3313: implemented. */ 1.1.1.2 root 3314: if (TARGET_ABICALLS) 1.1.1.3 root 3315: { 3316: mips_abicalls = MIPS_ABICALLS_YES; 3317: flag_pic = 1; 3318: if (mips_section_threshold > 0) 3319: warning ("-G is incompatible with PIC code which is the default"); 3320: } 1.1.1.2 root 3321: else 3322: mips_abicalls = MIPS_ABICALLS_NO; 3323: 1.1.1.3 root 3324: /* -membedded-pic is a form of PIC code suitable for embedded 3325: systems. All calls are made using PC relative addressing, and 3326: all data is addressed using the $gp register. This requires gas, 3327: which does most of the work, and GNU ld, which automatically 3328: expands PC relative calls which are out of range into a longer 3329: instruction sequence. All gcc really does differently is 3330: generate a different sequence for a switch. */ 3331: if (TARGET_EMBEDDED_PIC) 3332: { 3333: flag_pic = 1; 3334: if (TARGET_ABICALLS) 3335: warning ("-membedded-pic and -mabicalls are incompatible"); 3336: if (g_switch_set) 3337: warning ("-G and -membedded-pic are incompatible"); 3338: /* Setting mips_section_threshold is not required, because gas 3339: will force everything to be GP addressable anyhow, but 3340: setting it will cause gcc to make better estimates of the 3341: number of instructions required to access a particular data 3342: item. */ 3343: mips_section_threshold = 0x7fffffff; 3344: } 3345: 1.1 root 3346: /* -mrnames says to use the MIPS software convention for register 1.1.1.3 root 3347: names instead of the hardware names (ie, $a0 instead of $4). 1.1 root 3348: We do this by switching the names in mips_reg_names, which the 3349: reg_names points into via the REGISTER_NAMES macro. */ 3350: 3351: if (TARGET_NAME_REGS) 1.1.1.3 root 3352: bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names)); 1.1 root 3353: 3354: /* If this is OSF/1, set up a SIGINFO handler so we can see what function 3355: is currently being compiled. */ 3356: #ifdef SIGINFO 3357: if (getenv ("GCC_SIGINFO") != (char *)0) 3358: { 3359: struct sigaction action; 3360: action.sa_handler = siginfo; 3361: action.sa_mask = 0; 3362: action.sa_flags = SA_RESTART; 3363: sigaction (SIGINFO, &action, (struct sigaction *)0); 3364: } 3365: #endif 3366: 3367: #if defined(_IOLBF) 3368: #if defined(ultrix) || defined(__ultrix) || defined(__OSF1__) || defined(__osf__) || defined(osf) 3369: /* If -mstats and -quiet, make stderr line buffered. */ 3370: if (quiet_flag && TARGET_STATS) 3371: setvbuf (stderr, (char *)0, _IOLBF, BUFSIZ); 3372: #endif 3373: #endif 3374: 1.1.1.3 root 3375: /* Initialize the high and low values for legitimate floating point 3376: constants. Rather than trying to get the accuracy down to the 3377: last bit, just use approximate ranges. */ 3378: dfhigh = REAL_VALUE_ATOF ("1.0e300", DFmode); 3379: dflow = REAL_VALUE_ATOF ("1.0e-300", DFmode); 3380: sfhigh = REAL_VALUE_ATOF ("1.0e38", SFmode); 3381: sflow = REAL_VALUE_ATOF ("1.0e-38", SFmode); 1.1 root 3382: 3383: mips_print_operand_punct['?'] = TRUE; 3384: mips_print_operand_punct['#'] = TRUE; 3385: mips_print_operand_punct['&'] = TRUE; 3386: mips_print_operand_punct['!'] = TRUE; 3387: mips_print_operand_punct['*'] = TRUE; 3388: mips_print_operand_punct['@'] = TRUE; 3389: mips_print_operand_punct['.'] = TRUE; 3390: mips_print_operand_punct['('] = TRUE; 3391: mips_print_operand_punct[')'] = TRUE; 3392: mips_print_operand_punct['['] = TRUE; 3393: mips_print_operand_punct[']'] = TRUE; 3394: mips_print_operand_punct['<'] = TRUE; 3395: mips_print_operand_punct['>'] = TRUE; 3396: mips_print_operand_punct['{'] = TRUE; 3397: mips_print_operand_punct['}'] = TRUE; 1.1.1.2 root 3398: mips_print_operand_punct['^'] = TRUE; 1.1 root 3399: 3400: mips_char_to_class['d'] = GR_REGS; 3401: mips_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS); 3402: mips_char_to_class['h'] = HI_REG; 3403: mips_char_to_class['l'] = LO_REG; 1.1.1.4 root 3404: mips_char_to_class['a'] = HILO_REG; 1.1 root 3405: mips_char_to_class['x'] = MD_REGS; 1.1.1.4 root 3406: mips_char_to_class['b'] = ALL_REGS; 1.1 root 3407: mips_char_to_class['y'] = GR_REGS; 3408: mips_char_to_class['z'] = ST_REGS; 3409: 3410: /* Set up array to map GCC register number to debug register number. 3411: Ignore the special purpose register numbers. */ 3412: 3413: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 3414: mips_dbx_regno[i] = -1; 3415: 3416: start = GP_DBX_FIRST - GP_REG_FIRST; 3417: for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++) 3418: mips_dbx_regno[i] = i + start; 3419: 3420: start = FP_DBX_FIRST - FP_REG_FIRST; 3421: for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++) 3422: mips_dbx_regno[i] = i + start; 3423: 3424: /* Set up array giving whether a given register can hold a given mode. 3425: At present, restrict ints from being in FP registers, because reload 3426: is a little enthusiastic about storing extra values in FP registers, 3427: and this is not good for things like OS kernels. Also, due to the 3428: mandatory delay, it is as fast to load from cached memory as to move 3429: from the FP register. */ 3430: 3431: for (mode = VOIDmode; 3432: mode != MAX_MACHINE_MODE; 3433: mode = (enum machine_mode)((int)mode + 1)) 3434: { 3435: register int size = GET_MODE_SIZE (mode); 3436: register enum mode_class class = GET_MODE_CLASS (mode); 3437: 3438: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 3439: { 3440: register int temp; 3441: 3442: if (mode == CC_FPmode || mode == CC_REV_FPmode) 3443: temp = (regno == FPSW_REGNUM); 3444: 3445: else if (GP_REG_P (regno)) 3446: temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD)); 3447: 3448: else if (FP_REG_P (regno)) 3449: temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)) 3450: && (class == MODE_FLOAT 3451: || class == MODE_COMPLEX_FLOAT 1.1.1.4 root 3452: || (TARGET_DEBUG_H_MODE && class == MODE_INT)) 3453: && (! TARGET_SINGLE_FLOAT || size <= 4)); 1.1 root 3454: 3455: else if (MD_REG_P (regno)) 1.1.1.4 root 3456: temp = (class == MODE_INT 3457: && (size <= UNITS_PER_WORD 3458: || (regno == MD_REG_FIRST && size == 2 * UNITS_PER_WORD))); 1.1 root 3459: 3460: else 3461: temp = FALSE; 3462: 3463: mips_hard_regno_mode_ok[(int)mode][regno] = temp; 3464: } 3465: } 3466: } 3467: 3468: 3469: /* 3470: * The MIPS debug format wants all automatic variables and arguments 3471: * to be in terms of the virtual frame pointer (stack pointer before 3472: * any adjustment in the function), while the MIPS 3.0 linker wants 3473: * the frame pointer to be the stack pointer after the initial 3474: * adjustment. So, we do the adjustment here. The arg pointer (which 3475: * is eliminated) points to the virtual frame pointer, while the frame 3476: * pointer (which may be eliminated) points to the stack pointer after 3477: * the initial adjustments. 3478: */ 3479: 3480: int 3481: mips_debugger_offset (addr, offset) 3482: rtx addr; 3483: int offset; 3484: { 3485: rtx offset2 = const0_rtx; 3486: rtx reg = eliminate_constant_term (addr, &offset2); 3487: 3488: if (!offset) 3489: offset = INTVAL (offset2); 3490: 3491: if (reg == stack_pointer_rtx || reg == frame_pointer_rtx) 3492: { 3493: int frame_size = (!current_frame_info.initialized) 3494: ? compute_frame_size (get_frame_size ()) 3495: : current_frame_info.total_size; 3496: 3497: offset = offset - frame_size; 3498: } 3499: /* sdbout_parms does not want this to crash for unrecognized cases. */ 3500: #if 0 3501: else if (reg != arg_pointer_rtx) 3502: abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer."); 3503: #endif 3504: 3505: return offset; 3506: } 3507: 3508: 3509: /* A C compound statement to output to stdio stream STREAM the 3510: assembler syntax for an instruction operand X. X is an RTL 3511: expression. 3512: 3513: CODE is a value that can be used to specify one of several ways 3514: of printing the operand. It is used when identical operands 3515: must be printed differently depending on the context. CODE 3516: comes from the `%' specification that was used to request 3517: printing of the operand. If the specification was just `%DIGIT' 3518: then CODE is 0; if the specification was `%LTR DIGIT' then CODE 3519: is the ASCII code for LTR. 3520: 3521: If X is a register, this macro should print the register's name. 3522: The names can be found in an array `reg_names' whose type is 3523: `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. 3524: 3525: When the machine description has a specification `%PUNCT' (a `%' 3526: followed by a punctuation character), this macro is called with 3527: a null pointer for X and the punctuation character for CODE. 3528: 3529: The MIPS specific codes are: 3530: 3531: 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x", 3532: 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x", 3533: 'd' output integer constant in decimal, 3534: 'z' if the operand is 0, use $0 instead of normal operand. 3535: 'D' print second register of double-word register operand. 3536: 'L' print low-order register of double-word register operand. 3537: 'M' print high-order register of double-word register operand. 3538: 'C' print part of opcode for a branch condition. 3539: 'N' print part of opcode for a branch condition, inverted. 1.1.1.3 root 3540: 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch). 1.1.1.4 root 3541: 'B' print 'z' for EQ, 'n' for NE 3542: 'b' print 'n' for EQ, 'z' for NE 3543: 'T' print 'f' for EQ, 't' for NE 3544: 't' print 't' for EQ, 'f' for NE 1.1 root 3545: '(' Turn on .set noreorder 3546: ')' Turn on .set reorder 3547: '[' Turn on .set noat 3548: ']' Turn on .set at 3549: '<' Turn on .set nomacro 3550: '>' Turn on .set macro 3551: '{' Turn on .set volatile (not GAS) 3552: '}' Turn on .set novolatile (not GAS) 3553: '&' Turn on .set noreorder if filling delay slots 3554: '*' Turn on both .set noreorder and .set nomacro if filling delay slots 3555: '!' Turn on .set nomacro if filling delay slots 3556: '#' Print nop if in a .set noreorder section. 3557: '?' Print 'l' if we are to use a branch likely instead of normal branch. 3558: '@' Print the name of the assembler temporary register (at or $1). 1.1.1.2 root 3559: '.' Print the name of the register with a hard-wired zero (zero or $0). 3560: '^' Print the name of the pic call-through register (t9 or $25). */ 1.1 root 3561: 3562: void 3563: print_operand (file, op, letter) 3564: FILE *file; /* file to write to */ 3565: rtx op; /* operand to print */ 3566: int letter; /* %<letter> or 0 */ 3567: { 3568: register enum rtx_code code; 3569: 3570: if (PRINT_OPERAND_PUNCT_VALID_P (letter)) 3571: { 3572: switch (letter) 3573: { 3574: default: 3575: error ("PRINT_OPERAND: Unknown punctuation '%c'", letter); 3576: break; 3577: 3578: case '?': 3579: if (mips_branch_likely) 3580: putc ('l', file); 3581: break; 3582: 3583: case '@': 3584: fputs (reg_names [GP_REG_FIRST + 1], file); 3585: break; 3586: 1.1.1.2 root 3587: case '^': 3588: fputs (reg_names [PIC_FUNCTION_ADDR_REGNUM], file); 3589: break; 3590: 1.1 root 3591: case '.': 3592: fputs (reg_names [GP_REG_FIRST + 0], file); 3593: break; 3594: 3595: case '&': 3596: if (final_sequence != 0 && set_noreorder++ == 0) 3597: fputs (".set\tnoreorder\n\t", file); 3598: break; 3599: 3600: case '*': 3601: if (final_sequence != 0) 3602: { 3603: if (set_noreorder++ == 0) 3604: fputs (".set\tnoreorder\n\t", file); 3605: 3606: if (set_nomacro++ == 0) 3607: fputs (".set\tnomacro\n\t", file); 3608: } 3609: break; 3610: 3611: case '!': 3612: if (final_sequence != 0 && set_nomacro++ == 0) 3613: fputs ("\n\t.set\tnomacro", file); 3614: break; 3615: 3616: case '#': 3617: if (set_noreorder != 0) 3618: fputs ("\n\tnop", file); 3619: 1.1.1.3 root 3620: else if (TARGET_STATS) 1.1 root 3621: fputs ("\n\t#nop", file); 3622: 3623: break; 3624: 3625: case '(': 3626: if (set_noreorder++ == 0) 3627: fputs (".set\tnoreorder\n\t", file); 3628: break; 3629: 3630: case ')': 3631: if (set_noreorder == 0) 3632: error ("internal error: %%) found without a %%( in assembler pattern"); 3633: 3634: else if (--set_noreorder == 0) 3635: fputs ("\n\t.set\treorder", file); 3636: 3637: break; 3638: 3639: case '[': 3640: if (set_noat++ == 0) 3641: fputs (".set\tnoat\n\t", file); 3642: break; 3643: 3644: case ']': 3645: if (set_noat == 0) 3646: error ("internal error: %%] found without a %%[ in assembler pattern"); 3647: 3648: else if (--set_noat == 0) 3649: fputs ("\n\t.set\tat", file); 3650: 3651: break; 3652: 3653: case '<': 3654: if (set_nomacro++ == 0) 3655: fputs (".set\tnomacro\n\t", file); 3656: break; 3657: 3658: case '>': 3659: if (set_nomacro == 0) 3660: error ("internal error: %%> found without a %%< in assembler pattern"); 3661: 3662: else if (--set_nomacro == 0) 3663: fputs ("\n\t.set\tmacro", file); 3664: 3665: break; 3666: 3667: case '{': 3668: if (set_volatile++ == 0) 3669: fprintf (file, "%s.set\tvolatile\n\t", (TARGET_MIPS_AS) ? "" : "#"); 3670: break; 3671: 3672: case '}': 3673: if (set_volatile == 0) 3674: error ("internal error: %%} found without a %%{ in assembler pattern"); 3675: 3676: else if (--set_volatile == 0) 3677: fprintf (file, "\n\t%s.set\tnovolatile", (TARGET_MIPS_AS) ? "" : "#"); 3678: 3679: break; 3680: } 3681: return; 3682: } 3683: 3684: if (! op) 3685: { 3686: error ("PRINT_OPERAND null pointer"); 3687: return; 3688: } 3689: 3690: code = GET_CODE (op); 3691: if (letter == 'C') 3692: switch (code) 3693: { 3694: case EQ: fputs ("eq", file); break; 3695: case NE: fputs ("ne", file); break; 3696: case GT: fputs ("gt", file); break; 3697: case GE: fputs ("ge", file); break; 3698: case LT: fputs ("lt", file); break; 3699: case LE: fputs ("le", file); break; 3700: case GTU: fputs ("gtu", file); break; 3701: case GEU: fputs ("geu", file); break; 3702: case LTU: fputs ("ltu", file); break; 3703: case LEU: fputs ("leu", file); break; 3704: 3705: default: 1.1.1.4 root 3706: abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%C"); 1.1 root 3707: } 3708: 3709: else if (letter == 'N') 3710: switch (code) 3711: { 3712: case EQ: fputs ("ne", file); break; 3713: case NE: fputs ("eq", file); break; 3714: case GT: fputs ("le", file); break; 3715: case GE: fputs ("lt", file); break; 3716: case LT: fputs ("ge", file); break; 3717: case LE: fputs ("gt", file); break; 3718: case GTU: fputs ("leu", file); break; 3719: case GEU: fputs ("ltu", file); break; 3720: case LTU: fputs ("geu", file); break; 3721: case LEU: fputs ("gtu", file); break; 3722: 3723: default: 1.1.1.4 root 3724: abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%N"); 1.1 root 3725: } 3726: 1.1.1.3 root 3727: else if (letter == 'S') 3728: { 3729: char buffer[100]; 3730: 3731: ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op)); 3732: assemble_name (file, buffer); 3733: } 3734: 1.1 root 3735: else if (code == REG) 3736: { 3737: register int regnum = REGNO (op); 3738: 1.1.1.4 root 3739: if ((letter == 'M' && ! WORDS_BIG_ENDIAN) 3740: || (letter == 'L' && WORDS_BIG_ENDIAN) 3741: || letter == 'D') 1.1 root 3742: regnum++; 3743: 3744: fprintf (file, "%s", reg_names[regnum]); 3745: } 3746: 3747: else if (code == MEM) 3748: output_address (XEXP (op, 0)); 3749: 1.1.1.4 root 3750: else if (code == CONST_DOUBLE 3751: && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT) 1.1 root 3752: { 1.1.1.3 root 3753: REAL_VALUE_TYPE d; 3754: char s[30]; 3755: 3756: REAL_VALUE_FROM_CONST_DOUBLE (d, op); 3757: REAL_VALUE_TO_DECIMAL (d, "%.20e", s); 3758: fprintf (file, s); 1.1 root 3759: } 3760: 3761: else if ((letter == 'x') && (GET_CODE(op) == CONST_INT)) 3762: fprintf (file, "0x%04x", 0xffff & (INTVAL(op))); 3763: 1.1.1.4 root 3764: else if ((letter == 'X') && (GET_CODE(op) == CONST_INT) 3765: && HOST_BITS_PER_WIDE_INT == 32) 1.1 root 3766: fprintf (file, "0x%08x", INTVAL(op)); 3767: 1.1.1.4 root 3768: else if ((letter == 'X') && (GET_CODE(op) == CONST_INT) 3769: && HOST_BITS_PER_WIDE_INT == 64) 3770: fprintf (file, "0x%016lx", INTVAL(op)); 3771: 1.1 root 3772: else if ((letter == 'd') && (GET_CODE(op) == CONST_INT)) 3773: fprintf (file, "%d", (INTVAL(op))); 3774: 3775: else if (letter == 'z' 3776: && (GET_CODE (op) == CONST_INT) 3777: && INTVAL (op) == 0) 3778: fputs (reg_names[GP_REG_FIRST], file); 3779: 3780: else if (letter == 'd' || letter == 'x' || letter == 'X') 3781: fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT", letter); 3782: 1.1.1.4 root 3783: else if (letter == 'B') 3784: fputs (code == EQ ? "z" : "n", file); 3785: else if (letter == 'b') 3786: fputs (code == EQ ? "n" : "z", file); 3787: else if (letter == 'T') 3788: fputs (code == EQ ? "f" : "t", file); 3789: else if (letter == 't') 3790: fputs (code == EQ ? "t" : "f", file); 3791: 1.1 root 3792: else 3793: output_addr_const (file, op); 3794: } 3795: 3796: 3797: /* A C compound statement to output to stdio stream STREAM the 3798: assembler syntax for an instruction operand that is a memory 3799: reference whose address is ADDR. ADDR is an RTL expression. 3800: 3801: On some machines, the syntax for a symbolic address depends on 3802: the section that the address refers to. On these machines, 3803: define the macro `ENCODE_SECTION_INFO' to store the information 3804: into the `symbol_ref', and then check for it here. */ 3805: 3806: void 3807: print_operand_address (file, addr) 3808: FILE *file; 3809: rtx addr; 3810: { 3811: if (!addr) 3812: error ("PRINT_OPERAND_ADDRESS, null pointer"); 3813: 3814: else 3815: switch (GET_CODE (addr)) 3816: { 3817: default: 1.1.1.4 root 3818: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #1"); 1.1 root 3819: break; 3820: 3821: case REG: 3822: if (REGNO (addr) == ARG_POINTER_REGNUM) 3823: abort_with_insn (addr, "Arg pointer not eliminated."); 3824: 3825: fprintf (file, "0(%s)", reg_names [REGNO (addr)]); 3826: break; 3827: 3828: case PLUS: 3829: { 3830: register rtx reg = (rtx)0; 3831: register rtx offset = (rtx)0; 3832: register rtx arg0 = XEXP (addr, 0); 3833: register rtx arg1 = XEXP (addr, 1); 3834: 3835: if (GET_CODE (arg0) == REG) 3836: { 3837: reg = arg0; 3838: offset = arg1; 3839: if (GET_CODE (offset) == REG) 3840: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs"); 3841: } 3842: else if (GET_CODE (arg1) == REG) 3843: { 3844: reg = arg1; 3845: offset = arg0; 3846: } 3847: else if (CONSTANT_P (arg0) && CONSTANT_P (arg1)) 3848: { 3849: output_addr_const (file, addr); 3850: break; 3851: } 3852: else 3853: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs"); 3854: 3855: if (!CONSTANT_P (offset)) 1.1.1.4 root 3856: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #2"); 1.1 root 3857: 3858: if (REGNO (reg) == ARG_POINTER_REGNUM) 3859: abort_with_insn (addr, "Arg pointer not eliminated."); 3860: 3861: output_addr_const (file, offset); 3862: fprintf (file, "(%s)", reg_names [REGNO (reg)]); 3863: } 3864: break; 3865: 3866: case LABEL_REF: 3867: case SYMBOL_REF: 3868: case CONST_INT: 3869: case CONST: 3870: output_addr_const (file, addr); 3871: break; 3872: } 3873: } 3874: 3875: 3876: /* If optimizing for the global pointer, keep track of all of 3877: the externs, so that at the end of the file, we can emit 3878: the appropriate .extern declaration for them, before writing 3879: out the text section. We assume that all names passed to 3880: us are in the permanent obstack, so that they will be valid 3881: at the end of the compilation. 3882: 3883: If we have -G 0, or the extern size is unknown, don't bother 3884: emitting the .externs. */ 3885: 3886: int 3887: mips_output_external (file, decl, name) 3888: FILE *file; 3889: tree decl; 3890: char *name; 3891: { 3892: register struct extern_list *p; 3893: int len; 3894: 3895: if (TARGET_GP_OPT 3896: && ((TREE_CODE (decl)) != FUNCTION_DECL) 3897: && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0)) 3898: { 3899: p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); 3900: p->next = extern_head; 3901: p->name = name; 3902: p->size = len; 3903: extern_head = p; 3904: } 1.1.1.3 root 3905: 3906: #ifdef ASM_OUTPUT_UNDEF_FUNCTION 3907: if (TREE_CODE (decl) == FUNCTION_DECL 3908: /* ??? Don't include alloca, since gcc will always expand it 3909: inline. If we don't do this, libg++ fails to build. */ 3910: && strcmp (name, "alloca") 3911: /* ??? Don't include __builtin_next_arg, because then gcc will not 3912: bootstrap under Irix 5.1. */ 3913: && strcmp (name, "__builtin_next_arg")) 3914: { 3915: p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); 3916: p->next = extern_head; 3917: p->name = name; 3918: p->size = -1; 3919: extern_head = p; 3920: } 3921: #endif 3922: 3923: return 0; 3924: } 3925: 3926: #ifdef ASM_OUTPUT_UNDEF_FUNCTION 3927: int 3928: mips_output_external_libcall (file, name) 3929: FILE *file; 3930: char *name; 3931: { 3932: register struct extern_list *p; 3933: 3934: p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); 3935: p->next = extern_head; 3936: p->name = name; 3937: p->size = -1; 3938: extern_head = p; 3939: 1.1 root 3940: return 0; 3941: } 1.1.1.3 root 3942: #endif 1.1 root 3943: 3944: 3945: /* Compute a string to use as a temporary file name. */ 3946: 1.1.1.3 root 3947: /* On MSDOS, write temp files in current dir 3948: because there's no place else we can expect to use. */ 3949: #if __MSDOS__ 3950: #ifndef P_tmpdir 3951: #define P_tmpdir "./" 3952: #endif 3953: #endif 3954: 1.1 root 3955: static FILE * 3956: make_temp_file () 3957: { 3958: FILE *stream; 3959: char *base = getenv ("TMPDIR"); 3960: int len; 3961: 3962: if (base == (char *)0) 3963: { 3964: #ifdef P_tmpdir 3965: if (access (P_tmpdir, R_OK | W_OK) == 0) 3966: base = P_tmpdir; 3967: else 3968: #endif 3969: if (access ("/usr/tmp", R_OK | W_OK) == 0) 3970: base = "/usr/tmp/"; 3971: else 3972: base = "/tmp/"; 3973: } 3974: 3975: len = strlen (base); 1.1.1.3 root 3976: /* temp_filename is global, so we must use malloc, not alloca. */ 3977: temp_filename = (char *) xmalloc (len + sizeof("/ctXXXXXX")); 1.1 root 3978: strcpy (temp_filename, base); 3979: if (len > 0 && temp_filename[len-1] != '/') 3980: temp_filename[len++] = '/'; 3981: 1.1.1.3 root 3982: strcpy (temp_filename + len, "ctXXXXXX"); 1.1 root 3983: mktemp (temp_filename); 3984: 3985: stream = fopen (temp_filename, "w+"); 3986: if (!stream) 3987: pfatal_with_name (temp_filename); 3988: 1.1.1.3 root 3989: #ifndef __MSDOS__ 3990: /* In MSDOS, we cannot unlink the temporary file until we are finished using 3991: it. Otherwise, we delete it now, so that it will be gone even if the 3992: compiler happens to crash. */ 1.1 root 3993: unlink (temp_filename); 1.1.1.3 root 3994: #endif 1.1 root 3995: return stream; 3996: } 3997: 3998: 3999: /* Emit a new filename to a stream. If this is MIPS ECOFF, watch out 4000: for .file's that start within a function. If we are smuggling stabs, try to 4001: put out a MIPS ECOFF file and a stab. */ 4002: 4003: void 4004: mips_output_filename (stream, name) 4005: FILE *stream; 4006: char *name; 4007: { 4008: static int first_time = TRUE; 4009: char ltext_label_name[100]; 4010: 4011: if (first_time) 4012: { 4013: first_time = FALSE; 4014: SET_FILE_NUMBER (); 4015: current_function_file = name; 1.1.1.4 root 4016: ASM_OUTPUT_FILENAME (stream, num_source_filenames, name); 1.1.1.2 root 4017: /* This tells mips-tfile that stabs will follow. */ 1.1 root 4018: if (!TARGET_GAS && write_symbols == DBX_DEBUG) 4019: fprintf (stream, "\t#@stabs\n"); 4020: } 4021: 1.1.1.2 root 4022: else if (write_symbols == DBX_DEBUG) 1.1 root 4023: { 4024: ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); 1.1.1.2 root 4025: fprintf (stream, "%s ", ASM_STABS_OP); 4026: output_quoted_string (stream, name); 4027: fprintf (stream, ",%d,0,0,%s\n", N_SOL, <ext_label_name[1]); 1.1 root 4028: } 4029: 4030: else if (name != current_function_file 4031: && strcmp (name, current_function_file) != 0) 4032: { 4033: if (inside_function && !TARGET_GAS) 4034: { 4035: if (!file_in_function_warning) 4036: { 4037: file_in_function_warning = TRUE; 4038: ignore_line_number = TRUE; 4039: warning ("MIPS ECOFF format does not allow changing filenames within functions with #line"); 4040: } 4041: } 4042: else 4043: { 4044: SET_FILE_NUMBER (); 4045: current_function_file = name; 1.1.1.4 root 4046: ASM_OUTPUT_FILENAME (stream, num_source_filenames, name); 1.1 root 4047: } 4048: } 4049: } 4050: 4051: 4052: /* Emit a linenumber. For encapsulated stabs, we need to put out a stab 4053: as well as a .loc, since it is possible that MIPS ECOFF might not be 4054: able to represent the location for inlines that come from a different 4055: file. */ 4056: 4057: void 4058: mips_output_lineno (stream, line) 4059: FILE *stream; 4060: int line; 4061: { 1.1.1.2 root 4062: if (write_symbols == DBX_DEBUG) 1.1 root 4063: { 4064: ++sym_lineno; 1.1.1.4 root 4065: fprintf (stream, "%sLM%d:\n\t%s %d,0,%d,%sLM%d\n", 4066: LOCAL_LABEL_PREFIX, sym_lineno, ASM_STABN_OP, N_SLINE, line, 4067: LOCAL_LABEL_PREFIX, sym_lineno); 1.1 root 4068: } 4069: 4070: else 4071: { 4072: fprintf (stream, "\n\t%s.loc\t%d %d\n", 4073: (ignore_line_number) ? "#" : "", 4074: num_source_filenames, line); 4075: 4076: LABEL_AFTER_LOC (stream); 4077: } 4078: } 4079: 4080: 4081: /* If defined, a C statement to be executed just prior to the 4082: output of assembler code for INSN, to modify the extracted 4083: operands so they will be output differently. 4084: 4085: Here the argument OPVEC is the vector containing the operands 4086: extracted from INSN, and NOPERANDS is the number of elements of 4087: the vector which contain meaningful data for this insn. The 4088: contents of this vector are what will be used to convert the 4089: insn template into assembler code, so you can change the 4090: assembler output by changing the contents of the vector. 4091: 4092: We use it to check if the current insn needs a nop in front of it 4093: because of load delays, and also to update the delay slot 4094: statistics. */ 4095: 1.1.1.3 root 4096: /* ??? There is no real need for this function, because it never actually 4097: emits a NOP anymore. */ 4098: 1.1 root 4099: void 4100: final_prescan_insn (insn, opvec, noperands) 4101: rtx insn; 4102: rtx opvec[]; 4103: int noperands; 4104: { 4105: if (dslots_number_nops > 0) 4106: { 4107: rtx pattern = PATTERN (insn); 4108: int length = get_attr_length (insn); 4109: 4110: /* Do we need to emit a NOP? */ 4111: if (length == 0 4112: || (mips_load_reg != (rtx)0 && reg_mentioned_p (mips_load_reg, pattern)) 4113: || (mips_load_reg2 != (rtx)0 && reg_mentioned_p (mips_load_reg2, pattern)) 4114: || (mips_load_reg3 != (rtx)0 && reg_mentioned_p (mips_load_reg3, pattern)) 4115: || (mips_load_reg4 != (rtx)0 && reg_mentioned_p (mips_load_reg4, pattern))) 1.1.1.3 root 4116: fputs ("\t#nop\n", asm_out_file); 1.1 root 4117: 4118: else 4119: dslots_load_filled++; 4120: 4121: while (--dslots_number_nops > 0) 1.1.1.3 root 4122: fputs ("\t#nop\n", asm_out_file); 1.1 root 4123: 4124: mips_load_reg = (rtx)0; 4125: mips_load_reg2 = (rtx)0; 4126: mips_load_reg3 = (rtx)0; 4127: mips_load_reg4 = (rtx)0; 4128: } 4129: 4130: if (TARGET_STATS) 4131: { 4132: enum rtx_code code = GET_CODE (insn); 4133: if (code == JUMP_INSN || code == CALL_INSN) 4134: dslots_jump_total++; 4135: } 4136: } 4137: 4138: 4139: /* Output at beginning of assembler file. 4140: If we are optimizing to use the global pointer, create a temporary 4141: file to hold all of the text stuff, and write it out to the end. 4142: This is needed because the MIPS assembler is evidently one pass, 4143: and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata 4144: declaration when the code is processed, it generates a two 4145: instruction sequence. */ 4146: 4147: void 4148: mips_asm_file_start (stream) 4149: FILE *stream; 4150: { 4151: ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename); 4152: 4153: /* Versions of the MIPS assembler before 2.20 generate errors 4154: if a branch inside of a .set noreorder section jumps to a 4155: label outside of the .set noreorder section. Revision 2.20 4156: just set nobopt silently rather than fixing the bug. */ 4157: 4158: if (TARGET_MIPS_AS && optimize && flag_delayed_branch) 4159: fprintf (stream, "\t.set\tnobopt\n"); 4160: 1.1.1.2 root 4161: /* Generate the pseudo ops that System V.4 wants. */ 4162: #ifndef ABICALLS_ASM_OP 4163: #define ABICALLS_ASM_OP ".abicalls" 4164: #endif 1.1 root 4165: if (TARGET_ABICALLS) 1.1.1.2 root 4166: /* ??? but do not want this (or want pic0) if -non-shared? */ 4167: fprintf (stream, "\t%s\n", ABICALLS_ASM_OP); 1.1 root 4168: 1.1.1.4 root 4169: /* Start a section, so that the first .popsection directive is guaranteed 4170: to have a previously defined section to pop back to. */ 4171: if (ABI_64BIT && mips_isa >= 3) 4172: fprintf (stream, "\t.section\t.text\n"); 4173: 1.1.1.3 root 4174: /* This code exists so that we can put all externs before all symbol 4175: references. This is necessary for the assembler's global pointer 4176: optimizations to work. */ 4177: /* ??? Current versions of gas do not require that externs occur before 4178: symbol references. This means that this code is unnecessary when 4179: gas is being used. This gas feature hasn't been well tested as yet 4180: though. */ 1.1 root 4181: if (TARGET_GP_OPT) 4182: { 4183: asm_out_data_file = stream; 4184: asm_out_text_file = make_temp_file (); 4185: } 4186: else 4187: asm_out_data_file = asm_out_text_file = stream; 4188: 4189: print_options (stream); 4190: } 4191: 4192: 4193: /* If we are optimizing the global pointer, emit the text section now 4194: and any small externs which did not have .comm, etc that are 4195: needed. Also, give a warning if the data area is more than 32K and 4196: -pic because 3 instructions are needed to reference the data 4197: pointers. */ 4198: 4199: void 4200: mips_asm_file_end (file) 4201: FILE *file; 4202: { 4203: char buffer[8192]; 4204: tree name_tree; 4205: struct extern_list *p; 4206: int len; 4207: 4208: if (HALF_PIC_P ()) 4209: HALF_PIC_FINISH (file); 4210: 1.1.1.3 root 4211: if (extern_head) 1.1 root 4212: { 1.1.1.3 root 4213: fputs ("\n", file); 1.1 root 4214: 4215: for (p = extern_head; p != 0; p = p->next) 4216: { 4217: name_tree = get_identifier (p->name); 4218: 4219: /* Positively ensure only one .extern for any given symbol. */ 4220: if (! TREE_ASM_WRITTEN (name_tree)) 4221: { 4222: TREE_ASM_WRITTEN (name_tree) = 1; 1.1.1.3 root 4223: #ifdef ASM_OUTPUT_UNDEF_FUNCTION 4224: if (p->size == -1) 4225: ASM_OUTPUT_UNDEF_FUNCTION (file, p->name); 4226: else 4227: #endif 4228: { 4229: fputs ("\t.extern\t", file); 4230: assemble_name (file, p->name); 4231: fprintf (file, ", %d\n", p->size); 4232: } 1.1 root 4233: } 4234: } 1.1.1.3 root 4235: } 4236: 4237: if (TARGET_GP_OPT) 4238: { 1.1 root 4239: fprintf (file, "\n\t.text\n"); 4240: rewind (asm_out_text_file); 4241: if (ferror (asm_out_text_file)) 4242: fatal_io_error (temp_filename); 4243: 4244: while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0) 4245: if (fwrite (buffer, 1, len, file) != len) 4246: pfatal_with_name (asm_file_name); 4247: 4248: if (len < 0) 4249: pfatal_with_name (temp_filename); 4250: 4251: if (fclose (asm_out_text_file) != 0) 4252: pfatal_with_name (temp_filename); 1.1.1.3 root 4253: 4254: #ifdef __MSDOS__ 4255: unlink (temp_filename); 4256: #endif 1.1 root 4257: } 4258: } 4259: 4260: 4261: /* Emit either a label, .comm, or .lcomm directive, and mark 4262: that the symbol is used, so that we don't emit an .extern 4263: for it in mips_asm_file_end. */ 4264: 4265: void 4266: mips_declare_object (stream, name, init_string, final_string, size) 4267: FILE *stream; 4268: char *name; 4269: char *init_string; 4270: char *final_string; 4271: int size; 4272: { 4273: fputs (init_string, stream); /* "", "\t.comm\t", or "\t.lcomm\t" */ 4274: assemble_name (stream, name); 4275: fprintf (stream, final_string, size); /* ":\n", ",%u\n", ",%u\n" */ 4276: 1.1.1.3 root 4277: if (TARGET_GP_OPT) 1.1 root 4278: { 4279: tree name_tree = get_identifier (name); 4280: TREE_ASM_WRITTEN (name_tree) = 1; 4281: } 4282: } 4283: 4284: 4285: /* Output a double precision value to the assembler. If both the 4286: host and target are IEEE, emit the values in hex. */ 4287: 4288: void 4289: mips_output_double (stream, value) 4290: FILE *stream; 4291: REAL_VALUE_TYPE value; 4292: { 4293: #ifdef REAL_VALUE_TO_TARGET_DOUBLE 4294: long value_long[2]; 4295: REAL_VALUE_TO_TARGET_DOUBLE (value, value_long); 4296: 4297: fprintf (stream, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n", 4298: value_long[0], value, value_long[1]); 4299: #else 4300: fprintf (stream, "\t.double\t%.20g\n", value); 4301: #endif 4302: } 4303: 4304: 4305: /* Output a single precision value to the assembler. If both the 4306: host and target are IEEE, emit the values in hex. */ 4307: 4308: void 4309: mips_output_float (stream, value) 4310: FILE *stream; 4311: REAL_VALUE_TYPE value; 4312: { 4313: #ifdef REAL_VALUE_TO_TARGET_SINGLE 4314: long value_long; 4315: REAL_VALUE_TO_TARGET_SINGLE (value, value_long); 4316: 4317: fprintf (stream, "\t.word\t0x%08lx\t\t# %.12g (float)\n", value_long, value); 4318: #else 4319: fprintf (stream, "\t.float\t%.12g\n", value); 4320: #endif 4321: } 4322: 4323: 4324: /* Return TRUE if any register used in the epilogue is used. This to insure 4325: any insn put into the epilogue delay slots is safe. */ 4326: 4327: int 4328: epilogue_reg_mentioned_p (insn) 4329: rtx insn; 4330: { 4331: register char *fmt; 4332: register int i; 4333: register enum rtx_code code; 4334: register int regno; 4335: 4336: if (insn == (rtx)0) 4337: return 0; 4338: 4339: if (GET_CODE (insn) == LABEL_REF) 4340: return 0; 4341: 4342: code = GET_CODE (insn); 4343: switch (code) 4344: { 4345: case REG: 4346: regno = REGNO (insn); 4347: if (regno == STACK_POINTER_REGNUM) 4348: return 1; 4349: 4350: if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) 4351: return 1; 4352: 4353: if (!call_used_regs[regno]) 4354: return 1; 4355: 4356: if (regno != MIPS_TEMP1_REGNUM && regno != MIPS_TEMP2_REGNUM) 4357: return 0; 4358: 4359: if (!current_frame_info.initialized) 4360: compute_frame_size (get_frame_size ()); 4361: 4362: return (current_frame_info.total_size >= 32768); 4363: 4364: case SCRATCH: 4365: case CC0: 4366: case PC: 4367: case CONST_INT: 4368: case CONST_DOUBLE: 4369: return 0; 4370: } 4371: 4372: fmt = GET_RTX_FORMAT (code); 4373: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 4374: { 4375: if (fmt[i] == 'E') 4376: { 4377: register int j; 4378: for (j = XVECLEN (insn, i) - 1; j >= 0; j--) 4379: if (epilogue_reg_mentioned_p (XVECEXP (insn, i, j))) 4380: return 1; 4381: } 4382: else if (fmt[i] == 'e' && epilogue_reg_mentioned_p (XEXP (insn, i))) 4383: return 1; 4384: } 4385: 4386: return 0; 4387: } 1.1.1.3 root 4388: 1.1 root 4389: /* Return the bytes needed to compute the frame pointer from the current 4390: stack pointer. 4391: 4392: Mips stack frames look like: 4393: 4394: Before call After call 4395: +-----------------------+ +-----------------------+ 4396: high | | | | 4397: mem. | | | | 4398: | caller's temps. | | caller's temps. | 4399: | | | | 4400: +-----------------------+ +-----------------------+ 4401: | | | | 4402: | arguments on stack. | | arguments on stack. | 4403: | | | | 4404: +-----------------------+ +-----------------------+ 4405: | 4 words to save | | 4 words to save | 4406: | arguments passed | | arguments passed | 4407: | in registers, even | | in registers, even | 1.1.1.2 root 4408: SP->| if not passed. | VFP->| if not passed. | 1.1 root 4409: +-----------------------+ +-----------------------+ 4410: | | 4411: | fp register save | 4412: | | 4413: +-----------------------+ 4414: | | 4415: | gp register save | 4416: | | 4417: +-----------------------+ 4418: | | 4419: | local variables | 4420: | | 4421: +-----------------------+ 4422: | | 4423: | alloca allocations | 4424: | | 4425: +-----------------------+ 4426: | | 1.1.1.2 root 4427: | GP save for V.4 abi | 4428: | | 4429: +-----------------------+ 4430: | | 1.1 root 4431: | arguments on stack | 4432: | | 4433: +-----------------------+ 4434: | 4 words to save | 4435: | arguments passed | 4436: | in registers, even | 4437: low SP->| if not passed. | 4438: memory +-----------------------+ 4439: 4440: */ 4441: 4442: long 4443: compute_frame_size (size) 4444: int size; /* # of var. bytes allocated */ 4445: { 4446: int regno; 4447: long total_size; /* # bytes that the entire frame takes up */ 4448: long var_size; /* # bytes that variables take up */ 4449: long args_size; /* # bytes that outgoing arguments take up */ 4450: long extra_size; /* # extra bytes */ 4451: long gp_reg_rounded; /* # bytes needed to store gp after rounding */ 4452: long gp_reg_size; /* # bytes needed to store gp regs */ 4453: long fp_reg_size; /* # bytes needed to store fp regs */ 4454: long mask; /* mask of saved gp registers */ 4455: long fmask; /* mask of saved fp registers */ 4456: int fp_inc; /* 1 or 2 depending on the size of fp regs */ 4457: long fp_bits; /* bitmask to use for each fp register */ 4458: 4459: gp_reg_size = 0; 4460: fp_reg_size = 0; 4461: mask = 0; 4462: fmask = 0; 4463: extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)); 4464: var_size = MIPS_STACK_ALIGN (size); 4465: args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size); 4466: 4467: /* The MIPS 3.0 linker does not like functions that dynamically 4468: allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it 4469: looks like we are trying to create a second frame pointer to the 4470: function, so allocate some stack space to make it happy. */ 4471: 4472: if (args_size == 0 && current_function_calls_alloca) 4473: args_size = 4*UNITS_PER_WORD; 4474: 4475: total_size = var_size + args_size + extra_size; 4476: 4477: /* Calculate space needed for gp registers. */ 4478: for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) 4479: { 4480: if (MUST_SAVE_REGISTER (regno)) 4481: { 4482: gp_reg_size += UNITS_PER_WORD; 4483: mask |= 1L << (regno - GP_REG_FIRST); 4484: } 4485: } 4486: 4487: /* Calculate space needed for fp registers. */ 1.1.1.4 root 4488: if (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT) 1.1 root 4489: { 4490: fp_inc = 1; 4491: fp_bits = 1; 4492: } 4493: else 4494: { 4495: fp_inc = 2; 4496: fp_bits = 3; 4497: } 4498: 4499: for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc) 4500: { 4501: if (regs_ever_live[regno] && !call_used_regs[regno]) 4502: { 1.1.1.3 root 4503: fp_reg_size += fp_inc * UNITS_PER_FPREG; 1.1 root 4504: fmask |= fp_bits << (regno - FP_REG_FIRST); 4505: } 4506: } 4507: 4508: gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); 1.1.1.4 root 4509: total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size); 1.1 root 4510: 1.1.1.4 root 4511: /* The gp reg is caller saved in the 32 bit ABI, so there is no need 4512: for leaf routines (total_size == extra_size) to save the gp reg. 4513: The gp reg is callee saved in the 64 bit ABI, so all routines must 4514: save the gp reg. */ 4515: if (total_size == extra_size && ! (ABI_64BIT && mips_isa >= 3)) 1.1 root 4516: total_size = extra_size = 0; 1.1.1.2 root 4517: else if (TARGET_ABICALLS) 4518: { 4519: /* Add the context-pointer to the saved registers. */ 4520: gp_reg_size += UNITS_PER_WORD; 4521: mask |= 1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST); 4522: total_size -= gp_reg_rounded; 4523: gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); 4524: total_size += gp_reg_rounded; 4525: } 1.1 root 4526: 1.1.1.4 root 4527: /* Add in space reserved on the stack by the callee for storing arguments 4528: passed in registers. */ 4529: if (ABI_64BIT && mips_isa >= 3) 4530: total_size += MIPS_STACK_ALIGN (current_function_pretend_args_size); 4531: 1.1 root 4532: /* Save other computed information. */ 4533: current_frame_info.total_size = total_size; 4534: current_frame_info.var_size = var_size; 4535: current_frame_info.args_size = args_size; 4536: current_frame_info.extra_size = extra_size; 4537: current_frame_info.gp_reg_size = gp_reg_size; 4538: current_frame_info.fp_reg_size = fp_reg_size; 4539: current_frame_info.mask = mask; 4540: current_frame_info.fmask = fmask; 4541: current_frame_info.initialized = reload_completed; 4542: current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD; 1.1.1.3 root 4543: current_frame_info.num_fp = fp_reg_size / (fp_inc * UNITS_PER_FPREG); 1.1 root 4544: 4545: if (mask) 4546: { 1.1.1.4 root 4547: unsigned long offset = (args_size + extra_size + var_size 4548: + gp_reg_size - UNITS_PER_WORD); 1.1 root 4549: current_frame_info.gp_sp_offset = offset; 4550: current_frame_info.gp_save_offset = offset - total_size; 4551: } 4552: else 4553: { 4554: current_frame_info.gp_sp_offset = 0; 4555: current_frame_info.gp_save_offset = 0; 4556: } 4557: 4558: 4559: if (fmask) 4560: { 1.1.1.3 root 4561: unsigned long offset = (args_size + extra_size + var_size 4562: + gp_reg_rounded + fp_reg_size 4563: - fp_inc * UNITS_PER_FPREG); 1.1 root 4564: current_frame_info.fp_sp_offset = offset; 4565: current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD; 4566: } 4567: else 4568: { 4569: current_frame_info.fp_sp_offset = 0; 4570: current_frame_info.fp_save_offset = 0; 4571: } 4572: 4573: /* Ok, we're done. */ 4574: return total_size; 4575: } 4576: 4577: 4578: /* Common code to emit the insns (or to write the instructions to a file) 4579: to save/restore registers. 4580: 4581: Other parts of the code assume that MIPS_TEMP1_REGNUM (aka large_reg) 4582: is not modified within save_restore_insns. */ 4583: 4584: #define BITSET_P(value,bit) (((value) & (1L << (bit))) != 0) 4585: 4586: static void 4587: save_restore_insns (store_p, large_reg, large_offset, file) 4588: int store_p; /* true if this is prologue */ 4589: rtx large_reg; /* register holding large offset constant or NULL */ 4590: long large_offset; /* large constant offset value */ 4591: FILE *file; /* file to write instructions to instead of making RTL */ 4592: { 4593: long mask = current_frame_info.mask; 4594: long fmask = current_frame_info.fmask; 4595: int regno; 4596: rtx base_reg_rtx; 4597: long base_offset; 4598: long gp_offset; 4599: long fp_offset; 4600: long end_offset; 4601: 4602: if (frame_pointer_needed && !BITSET_P (mask, FRAME_POINTER_REGNUM - GP_REG_FIRST)) 4603: abort (); 4604: 4605: if (mask == 0 && fmask == 0) 4606: return; 4607: 4608: /* Save registers starting from high to low. The debuggers prefer 4609: at least the return register be stored at func+4, and also it 4610: allows us not to need a nop in the epilog if at least one 4611: register is reloaded in addition to return address. */ 4612: 4613: /* Save GP registers if needed. */ 4614: if (mask) 4615: { 4616: /* Pick which pointer to use as a base register. For small 4617: frames, just use the stack pointer. Otherwise, use a 4618: temporary register. Save 2 cycles if the save area is near 4619: the end of a large frame, by reusing the constant created in 4620: the prologue/epilogue to adjust the stack frame. */ 4621: 4622: gp_offset = current_frame_info.gp_sp_offset; 4623: end_offset = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD); 4624: 4625: if (gp_offset < 0 || end_offset < 0) 4626: fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.", 4627: gp_offset, end_offset); 4628: 4629: else if (gp_offset < 32768) 4630: { 4631: base_reg_rtx = stack_pointer_rtx; 4632: base_offset = 0; 4633: } 4634: 4635: else if (large_reg != (rtx)0 4636: && (((unsigned long)(large_offset - gp_offset)) < 32768) 4637: && (((unsigned long)(large_offset - end_offset)) < 32768)) 4638: { 4639: base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4640: base_offset = large_offset; 4641: if (file == (FILE *)0) 1.1.1.3 root 4642: { 4643: if (TARGET_LONG64) 4644: emit_insn (gen_adddi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); 4645: else 4646: emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); 4647: } 1.1 root 4648: else 1.1.1.3 root 4649: fprintf (file, "\t%s\t%s,%s,%s\n", 4650: TARGET_LONG64 ? "daddu" : "addu", 1.1 root 4651: reg_names[MIPS_TEMP2_REGNUM], 4652: reg_names[REGNO (large_reg)], 4653: reg_names[STACK_POINTER_REGNUM]); 4654: } 4655: 4656: else 4657: { 4658: base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4659: base_offset = gp_offset; 4660: if (file == (FILE *)0) 4661: { 4662: emit_move_insn (base_reg_rtx, GEN_INT (gp_offset)); 1.1.1.3 root 4663: if (TARGET_LONG64) 4664: emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); 4665: else 4666: emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); 1.1 root 4667: } 4668: else 1.1.1.3 root 4669: fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n", 1.1 root 4670: reg_names[MIPS_TEMP2_REGNUM], 4671: (long)base_offset, 4672: (long)base_offset, 1.1.1.3 root 4673: TARGET_LONG64 ? "daddu" : "addu", 1.1 root 4674: reg_names[MIPS_TEMP2_REGNUM], 4675: reg_names[MIPS_TEMP2_REGNUM], 4676: reg_names[STACK_POINTER_REGNUM]); 4677: } 4678: 4679: for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) 4680: { 4681: if (BITSET_P (mask, regno - GP_REG_FIRST)) 4682: { 4683: if (file == (FILE *)0) 4684: { 1.1.1.3 root 4685: rtx reg_rtx = gen_rtx (REG, word_mode, regno); 4686: rtx mem_rtx = gen_rtx (MEM, word_mode, 1.1 root 4687: gen_rtx (PLUS, Pmode, base_reg_rtx, 4688: GEN_INT (gp_offset - base_offset))); 4689: 4690: if (store_p) 4691: emit_move_insn (mem_rtx, reg_rtx); 1.1.1.4 root 4692: else if (!TARGET_ABICALLS || (ABI_64BIT && mips_isa >= 3) 1.1.1.2 root 4693: || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) 1.1 root 4694: emit_move_insn (reg_rtx, mem_rtx); 4695: } 4696: else 1.1.1.2 root 4697: { 1.1.1.4 root 4698: if (store_p || !TARGET_ABICALLS || (ABI_64BIT && mips_isa >= 3) 1.1.1.2 root 4699: || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) 4700: fprintf (file, "\t%s\t%s,%ld(%s)\n", 1.1.1.3 root 4701: (TARGET_64BIT 4702: ? (store_p) ? "sd" : "ld" 4703: : (store_p) ? "sw" : "lw"), 1.1.1.2 root 4704: reg_names[regno], 4705: gp_offset - base_offset, 4706: reg_names[REGNO(base_reg_rtx)]); 1.1 root 4707: 1.1.1.2 root 4708: } 1.1 root 4709: gp_offset -= UNITS_PER_WORD; 4710: } 4711: } 4712: } 4713: else 4714: { 1.1.1.4 root 4715: base_reg_rtx = (rtx)0; /* Make sure these are initialized */ 1.1 root 4716: base_offset = 0; 4717: } 4718: 4719: /* Save floating point registers if needed. */ 4720: if (fmask) 4721: { 1.1.1.4 root 4722: int fp_inc = (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT) ? 1 : 2; 1.1.1.3 root 4723: int fp_size = fp_inc * UNITS_PER_FPREG; 1.1 root 4724: 4725: /* Pick which pointer to use as a base register. */ 4726: fp_offset = current_frame_info.fp_sp_offset; 1.1.1.3 root 4727: end_offset = fp_offset - (current_frame_info.fp_reg_size - fp_size); 1.1 root 4728: 4729: if (fp_offset < 0 || end_offset < 0) 4730: fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.", 4731: fp_offset, end_offset); 4732: 4733: else if (fp_offset < 32768) 4734: { 4735: base_reg_rtx = stack_pointer_rtx; 4736: base_offset = 0; 4737: } 4738: 4739: else if (base_reg_rtx != (rtx)0 4740: && (((unsigned long)(base_offset - fp_offset)) < 32768) 4741: && (((unsigned long)(base_offset - end_offset)) < 32768)) 4742: { 4743: ; /* already set up for gp registers above */ 4744: } 4745: 4746: else if (large_reg != (rtx)0 4747: && (((unsigned long)(large_offset - fp_offset)) < 32768) 4748: && (((unsigned long)(large_offset - end_offset)) < 32768)) 4749: { 4750: base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4751: base_offset = large_offset; 4752: if (file == (FILE *)0) 1.1.1.3 root 4753: { 4754: if (TARGET_LONG64) 4755: emit_insn (gen_adddi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); 4756: else 4757: emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); 4758: } 1.1 root 4759: else 1.1.1.3 root 4760: fprintf (file, "\t%s\t%s,%s,%s\n", 4761: TARGET_LONG64 ? "daddu" : "addu", 1.1 root 4762: reg_names[MIPS_TEMP2_REGNUM], 4763: reg_names[REGNO (large_reg)], 4764: reg_names[STACK_POINTER_REGNUM]); 4765: } 4766: 4767: else 4768: { 4769: base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4770: base_offset = fp_offset; 4771: if (file == (FILE *)0) 4772: { 4773: emit_move_insn (base_reg_rtx, GEN_INT (fp_offset)); 1.1.1.3 root 4774: if (TARGET_LONG64) 4775: emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); 4776: else 4777: emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); 1.1 root 4778: } 4779: else 1.1.1.3 root 4780: fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n", 1.1 root 4781: reg_names[MIPS_TEMP2_REGNUM], 4782: (long)base_offset, 4783: (long)base_offset, 1.1.1.3 root 4784: TARGET_LONG64 ? "daddu" : "addu", 1.1 root 4785: reg_names[MIPS_TEMP2_REGNUM], 4786: reg_names[MIPS_TEMP2_REGNUM], 4787: reg_names[STACK_POINTER_REGNUM]); 4788: } 4789: 4790: for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc) 4791: { 4792: if (BITSET_P (fmask, regno - FP_REG_FIRST)) 4793: { 4794: if (file == (FILE *)0) 4795: { 1.1.1.4 root 4796: enum machine_mode sz = 4797: TARGET_SINGLE_FLOAT ? SFmode : DFmode; 4798: rtx reg_rtx = gen_rtx (REG, sz, regno); 4799: rtx mem_rtx = gen_rtx (MEM, sz, 1.1 root 4800: gen_rtx (PLUS, Pmode, base_reg_rtx, 4801: GEN_INT (fp_offset - base_offset))); 4802: 4803: if (store_p) 4804: emit_move_insn (mem_rtx, reg_rtx); 4805: else 4806: emit_move_insn (reg_rtx, mem_rtx); 4807: } 4808: else 4809: fprintf (file, "\t%s\t%s,%ld(%s)\n", 1.1.1.4 root 4810: (TARGET_SINGLE_FLOAT 4811: ? ((store_p) ? "s.s" : "l.s") 4812: : ((store_p) ? "s.d" : "l.d")), 1.1 root 4813: reg_names[regno], 4814: fp_offset - base_offset, 4815: reg_names[REGNO(base_reg_rtx)]); 4816: 4817: 1.1.1.3 root 4818: fp_offset -= fp_size; 1.1 root 4819: } 4820: } 4821: } 4822: } 4823: 4824: 4825: /* Set up the stack and frame (if desired) for the function. */ 4826: 4827: void 4828: function_prologue (file, size) 4829: FILE *file; 4830: int size; 4831: { 1.1.1.4 root 4832: char *fnname; 1.1 root 4833: long tsize = current_frame_info.total_size; 4834: 4835: ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl)); 4836: 1.1.1.4 root 4837: #ifdef SDB_DEBUGGING_INFO 1.1.1.3 root 4838: if (debug_info_level != DINFO_LEVEL_TERSE && write_symbols == SDB_DEBUG) 1.1 root 4839: ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl)); 1.1.1.4 root 4840: #endif 4841: 4842: /* Get the function name the same way that toplev.c does before calling 4843: assemble_start_function. This is needed so that the name used here 4844: exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */ 4845: fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 1.1 root 4846: 4847: inside_function = 1; 4848: fputs ("\t.ent\t", file); 1.1.1.4 root 4849: assemble_name (file, fnname); 1.1 root 4850: fputs ("\n", file); 4851: 1.1.1.4 root 4852: assemble_name (file, fnname); 1.1 root 4853: fputs (":\n", file); 4854: 1.1.1.2 root 4855: fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args= %d, extra= %d\n", 1.1 root 4856: reg_names[ (frame_pointer_needed) ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ], 4857: tsize, 4858: reg_names[31 + GP_REG_FIRST], 4859: current_frame_info.var_size, 4860: current_frame_info.num_gp, 4861: current_frame_info.num_fp, 4862: current_function_outgoing_args_size, 4863: current_frame_info.extra_size); 4864: 4865: fprintf (file, "\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n", 4866: current_frame_info.mask, 4867: current_frame_info.gp_save_offset, 4868: current_frame_info.fmask, 4869: current_frame_info.fp_save_offset); 1.1.1.2 root 4870: 1.1.1.4 root 4871: if (TARGET_ABICALLS && ! (ABI_64BIT && mips_isa >= 3)) 1.1.1.2 root 4872: { 4873: char *sp_str = reg_names[STACK_POINTER_REGNUM]; 4874: 4875: fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n", 4876: reg_names[PIC_FUNCTION_ADDR_REGNUM]); 4877: if (tsize > 0) 4878: { 1.1.1.3 root 4879: fprintf (file, "\t%s\t%s,%s,%d\n", 4880: (TARGET_LONG64 ? "dsubu" : "subu"), 4881: sp_str, sp_str, tsize); 1.1.1.2 root 4882: fprintf (file, "\t.cprestore %d\n", current_frame_info.args_size); 4883: } 4884: } 1.1 root 4885: } 4886: 4887: 4888: /* Expand the prologue into a bunch of separate insns. */ 4889: 4890: void 4891: mips_expand_prologue () 4892: { 4893: int regno; 4894: long tsize; 4895: rtx tmp_rtx = (rtx)0; 4896: char *arg_name = (char *)0; 4897: tree fndecl = current_function_decl; 4898: tree fntype = TREE_TYPE (fndecl); 4899: tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) 4900: ? DECL_ARGUMENTS (fndecl) 4901: : 0; 4902: rtx next_arg_reg; 4903: int i; 4904: tree next_arg; 4905: tree cur_arg; 4906: CUMULATIVE_ARGS args_so_far; 4907: 1.1.1.2 root 4908: /* If struct value address is treated as the first argument, make it so. */ 4909: if (aggregate_value_p (DECL_RESULT (fndecl)) 4910: && ! current_function_returns_pcc_struct 4911: && struct_value_incoming_rtx == 0) 4912: { 4913: tree type = build_pointer_type (fntype); 4914: tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type); 4915: DECL_ARG_TYPE (function_result_decl) = type; 4916: TREE_CHAIN (function_result_decl) = fnargs; 4917: fnargs = function_result_decl; 4918: } 4919: 1.1 root 4920: /* Determine the last argument, and get its name. */ 4921: 4922: INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0); 4923: regno = GP_ARG_FIRST; 4924: 4925: for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg) 4926: { 1.1.1.3 root 4927: tree passed_type = DECL_ARG_TYPE (cur_arg); 4928: enum machine_mode passed_mode = TYPE_MODE (passed_type); 4929: rtx entry_parm; 4930: 1.1.1.5 ! root 4931: if (TREE_ADDRESSABLE (passed_type)) 1.1.1.3 root 4932: { 4933: passed_type = build_pointer_type (passed_type); 4934: passed_mode = Pmode; 4935: } 4936: 4937: entry_parm = FUNCTION_ARG (args_so_far, passed_mode, passed_type, 1); 1.1 root 4938: 4939: if (entry_parm) 4940: { 4941: int words; 4942: 4943: /* passed in a register, so will get homed automatically */ 4944: if (GET_MODE (entry_parm) == BLKmode) 1.1.1.3 root 4945: words = (int_size_in_bytes (passed_type) + 3) / 4; 1.1 root 4946: else 4947: words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; 4948: 4949: regno = REGNO (entry_parm) + words - 1; 4950: } 4951: else 4952: { 4953: regno = GP_ARG_LAST+1; 4954: break; 4955: } 4956: 1.1.1.3 root 4957: FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, passed_type, 1); 1.1 root 4958: 4959: next_arg = TREE_CHAIN (cur_arg); 4960: if (next_arg == (tree)0) 4961: { 4962: if (DECL_NAME (cur_arg)) 4963: arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg)); 4964: 4965: break; 4966: } 4967: } 4968: 4969: /* In order to pass small structures by value in registers 4970: compatibly with the MIPS compiler, we need to shift the value 4971: into the high part of the register. Function_arg has encoded a 4972: PARALLEL rtx, holding a vector of adjustments to be made as the 4973: next_arg_reg variable, so we split up the insns, and emit them 4974: separately. */ 4975: 4976: next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1); 4977: if (next_arg_reg != (rtx)0 && GET_CODE (next_arg_reg) == PARALLEL) 4978: { 4979: rtvec adjust = XVEC (next_arg_reg, 0); 4980: int num = GET_NUM_ELEM (adjust); 4981: 4982: for (i = 0; i < num; i++) 4983: { 4984: rtx pattern = RTVEC_ELT (adjust, i); 4985: if (GET_CODE (pattern) != SET 4986: || GET_CODE (SET_SRC (pattern)) != ASHIFT) 4987: abort_with_insn (pattern, "Insn is not a shift"); 4988: 4989: PUT_CODE (SET_SRC (pattern), ASHIFTRT); 4990: emit_insn (pattern); 4991: } 4992: } 4993: 1.1.1.2 root 4994: tsize = compute_frame_size (get_frame_size ()); 4995: 1.1 root 4996: /* If this function is a varargs function, store any registers that 4997: would normally hold arguments ($4 - $7) on the stack. */ 1.1.1.4 root 4998: if ((! ABI_64BIT || mips_isa < 3) 4999: && ((TYPE_ARG_TYPES (fntype) != 0 5000: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) 5001: || (arg_name != (char *)0 5002: && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0) 5003: || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0))))) 1.1 root 5004: { 1.1.1.2 root 5005: int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD; 5006: rtx ptr = stack_pointer_rtx; 5007: 5008: /* If we are doing svr4-abi, sp has already been decremented by tsize. */ 1.1.1.4 root 5009: if (TARGET_ABICALLS && ! (ABI_64BIT && mips_isa >= 3)) 1.1.1.2 root 5010: offset += tsize; 5011: 1.1 root 5012: for (; regno <= GP_ARG_LAST; regno++) 5013: { 1.1.1.2 root 5014: if (offset != 0) 5015: ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset)); 1.1.1.3 root 5016: emit_move_insn (gen_rtx (MEM, word_mode, ptr), 5017: gen_rtx (REG, word_mode, regno)); 1.1.1.2 root 5018: offset += UNITS_PER_WORD; 1.1 root 5019: } 5020: } 5021: 5022: if (tsize > 0) 5023: { 5024: rtx tsize_rtx = GEN_INT (tsize); 5025: 1.1.1.2 root 5026: /* If we are doing svr4-abi, sp move is done by function_prologue. */ 1.1.1.4 root 5027: if (!TARGET_ABICALLS || (ABI_64BIT && mips_isa >= 3)) 1.1 root 5028: { 1.1.1.2 root 5029: if (tsize > 32767) 5030: { 1.1.1.3 root 5031: tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM); 1.1.1.2 root 5032: emit_move_insn (tmp_rtx, tsize_rtx); 5033: tsize_rtx = tmp_rtx; 5034: } 1.1 root 5035: 1.1.1.3 root 5036: if (TARGET_LONG64) 5037: emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, 5038: tsize_rtx)); 5039: else 5040: emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, 5041: tsize_rtx)); 1.1.1.2 root 5042: } 1.1 root 5043: 5044: save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0); 5045: 5046: if (frame_pointer_needed) 1.1.1.3 root 5047: { 5048: if (TARGET_64BIT) 5049: emit_insn (gen_movdi (frame_pointer_rtx, stack_pointer_rtx)); 5050: else 5051: emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); 5052: } 1.1.1.4 root 5053: 5054: if (TARGET_ABICALLS && (ABI_64BIT && mips_isa >= 3)) 5055: emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0))); 1.1 root 5056: } 5057: 5058: /* If we are profiling, make sure no instructions are scheduled before 5059: the call to mcount. */ 5060: 5061: if (profile_flag || profile_block_flag) 5062: emit_insn (gen_blockage ()); 5063: } 5064: 5065: 5066: /* Do any necessary cleanup after a function to restore stack, frame, and regs. */ 5067: 5068: #define RA_MASK ((long) 0x80000000) /* 1 << 31 */ 1.1.1.2 root 5069: #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) 1.1 root 5070: 5071: void 5072: function_epilogue (file, size) 5073: FILE *file; 5074: int size; 5075: { 1.1.1.4 root 5076: char *fnname; 1.1 root 5077: long tsize; 5078: char *sp_str = reg_names[STACK_POINTER_REGNUM]; 5079: char *t1_str = reg_names[MIPS_TEMP1_REGNUM]; 5080: rtx epilogue_delay = current_function_epilogue_delay_list; 1.1.1.3 root 5081: int noreorder = (epilogue_delay != 0); 1.1 root 5082: int noepilogue = FALSE; 5083: int load_nop = FALSE; 5084: int load_only_r31; 5085: rtx tmp_rtx = (rtx)0; 5086: rtx restore_rtx; 5087: int i; 5088: 5089: /* The epilogue does not depend on any registers, but the stack 5090: registers, so we assume that if we have 1 pending nop, it can be 5091: ignored, and 2 it must be filled (2 nops occur for integer 5092: multiply and divide). */ 5093: 5094: if (dslots_number_nops > 0) 5095: { 5096: if (dslots_number_nops == 1) 5097: { 5098: dslots_number_nops = 0; 5099: dslots_load_filled++; 5100: } 5101: else 5102: { 5103: while (--dslots_number_nops > 0) 1.1.1.3 root 5104: fputs ("\t#nop\n", asm_out_file); 1.1 root 5105: } 5106: } 5107: 5108: if (set_noat != 0) 5109: { 5110: set_noat = 0; 5111: fputs ("\t.set\tat\n", file); 5112: error ("internal gcc error: .set noat left on in epilogue"); 5113: } 5114: 5115: if (set_nomacro != 0) 5116: { 5117: set_nomacro = 0; 5118: fputs ("\t.set\tmacro\n", file); 5119: error ("internal gcc error: .set nomacro left on in epilogue"); 5120: } 5121: 5122: if (set_noreorder != 0) 5123: { 5124: set_noreorder = 0; 5125: fputs ("\t.set\treorder\n", file); 5126: error ("internal gcc error: .set noreorder left on in epilogue"); 5127: } 5128: 5129: if (set_volatile != 0) 5130: { 5131: set_volatile = 0; 1.1.1.3 root 5132: fprintf (file, "\t%s.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#"); 1.1 root 5133: error ("internal gcc error: .set volatile left on in epilogue"); 5134: } 5135: 5136: size = MIPS_STACK_ALIGN (size); 5137: tsize = (!current_frame_info.initialized) 5138: ? compute_frame_size (size) 5139: : current_frame_info.total_size; 5140: 5141: if (tsize == 0 && epilogue_delay == 0) 5142: { 5143: rtx insn = get_last_insn (); 5144: 5145: /* If the last insn was a BARRIER, we don't have to write any code 5146: because a jump (aka return) was put there. */ 5147: if (GET_CODE (insn) == NOTE) 5148: insn = prev_nonnote_insn (insn); 5149: if (insn && GET_CODE (insn) == BARRIER) 5150: noepilogue = TRUE; 5151: 5152: noreorder = FALSE; 5153: } 5154: 5155: if (!noepilogue) 5156: { 5157: /* In the reload sequence, we don't need to fill the load delay 5158: slots for most of the loads, also see if we can fill the final 5159: delay slot if not otherwise filled by the reload sequence. */ 5160: 5161: if (noreorder) 5162: fprintf (file, "\t.set\tnoreorder\n"); 5163: 5164: if (tsize > 32767) 5165: { 5166: fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n", t1_str, (long)tsize, (long)tsize); 5167: tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM); 5168: } 5169: 5170: if (frame_pointer_needed) 5171: fprintf (file, "\tmove\t%s,%s\t\t\t# sp not trusted here\n", 5172: sp_str, reg_names[FRAME_POINTER_REGNUM]); 5173: 5174: save_restore_insns (FALSE, tmp_rtx, tsize, file); 5175: 1.1.1.2 root 5176: load_only_r31 = (((current_frame_info.mask 1.1.1.4 root 5177: & ~ (TARGET_ABICALLS && ! (ABI_64BIT && mips_isa >= 3) 5178: ? PIC_OFFSET_TABLE_MASK : 0)) 1.1.1.2 root 5179: == RA_MASK) 1.1 root 5180: && current_frame_info.fmask == 0); 5181: 5182: if (noreorder) 5183: { 5184: /* If the only register saved is the return address, we need a 5185: nop, unless we have an instruction to put into it. Otherwise 5186: we don't since reloading multiple registers doesn't reference 5187: the register being loaded. */ 5188: 5189: if (load_only_r31) 5190: { 5191: if (epilogue_delay) 5192: final_scan_insn (XEXP (epilogue_delay, 0), 5193: file, 5194: 1, /* optimize */ 5195: -2, /* prescan */ 5196: 1); /* nopeepholes */ 5197: else 5198: { 5199: fprintf (file, "\tnop\n"); 5200: load_nop = TRUE; 5201: } 5202: } 5203: 5204: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); 5205: 5206: if (tsize > 32767) 1.1.1.3 root 5207: fprintf (file, "\t%s\t%s,%s,%s\n", 5208: TARGET_LONG64 ? "daddu" : "addu", 5209: sp_str, sp_str, t1_str); 1.1 root 5210: 5211: else if (tsize > 0) 1.1.1.3 root 5212: fprintf (file, "\t%s\t%s,%s,%d\n", 5213: TARGET_LONG64 ? "daddu" : "addu", 5214: sp_str, sp_str, tsize); 1.1 root 5215: 5216: else if (!load_only_r31 && epilogue_delay != 0) 5217: final_scan_insn (XEXP (epilogue_delay, 0), 5218: file, 5219: 1, /* optimize */ 5220: -2, /* prescan */ 5221: 1); /* nopeepholes */ 5222: 5223: fprintf (file, "\t.set\treorder\n"); 5224: } 5225: 5226: else 5227: { 5228: if (tsize > 32767) 1.1.1.3 root 5229: fprintf (file, "\t%s\t%s,%s,%s\n", 5230: TARGET_LONG64 ? "daddu" : "addu", 5231: sp_str, sp_str, t1_str); 1.1 root 5232: 5233: else if (tsize > 0) 1.1.1.3 root 5234: fprintf (file, "\t%s\t%s,%s,%d\n", 5235: TARGET_LONG64 ? "daddu" : "addu", 5236: sp_str, sp_str, tsize); 1.1 root 5237: 5238: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); 5239: } 5240: } 5241: 1.1.1.4 root 5242: /* Get the function name the same way that toplev.c does before calling 5243: assemble_start_function. This is needed so that the name used here 5244: exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */ 5245: fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 5246: 1.1 root 5247: fputs ("\t.end\t", file); 1.1.1.4 root 5248: assemble_name (file, fnname); 1.1 root 5249: fputs ("\n", file); 5250: 5251: if (TARGET_STATS) 5252: { 5253: int num_gp_regs = current_frame_info.gp_reg_size / 4; 5254: int num_fp_regs = current_frame_info.fp_reg_size / 8; 5255: int num_regs = num_gp_regs + num_fp_regs; 1.1.1.4 root 5256: char *name = fnname; 1.1 root 5257: 5258: if (name[0] == '*') 5259: name++; 5260: 5261: dslots_load_total += num_regs; 5262: 5263: if (!noepilogue) 5264: dslots_jump_total++; 5265: 5266: if (noreorder) 5267: { 5268: dslots_load_filled += num_regs; 5269: 5270: /* If the only register saved is the return register, we 5271: can't fill this register's delay slot. */ 5272: 5273: if (load_only_r31 && epilogue_delay == 0) 5274: dslots_load_filled--; 5275: 5276: if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0)) 5277: dslots_jump_filled++; 5278: } 5279: 5280: fprintf (stderr, 5281: "%-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", 5282: name, 5283: (frame_pointer_needed) ? 'y' : 'n', 5284: ((current_frame_info.mask & RA_MASK) != 0) ? 'n' : 'y', 5285: (current_function_calls_alloca) ? 'y' : 'n', 5286: (current_function_calls_setjmp) ? 'y' : 'n', 5287: (long)current_frame_info.total_size, 5288: (long)current_function_outgoing_args_size, 5289: num_gp_regs, num_fp_regs, 5290: dslots_load_total, dslots_load_filled, 5291: dslots_jump_total, dslots_jump_filled, 5292: num_refs[0], num_refs[1], num_refs[2]); 5293: 5294: if (HALF_PIC_NUMBER_PTRS > prev_half_pic_ptrs) 5295: { 5296: fprintf (stderr, " half-pic=%3d", HALF_PIC_NUMBER_PTRS - prev_half_pic_ptrs); 5297: prev_half_pic_ptrs = HALF_PIC_NUMBER_PTRS; 5298: } 5299: 5300: if (HALF_PIC_NUMBER_REFS > prev_half_pic_refs) 5301: { 5302: fprintf (stderr, " pic-ref=%3d", HALF_PIC_NUMBER_REFS - prev_half_pic_refs); 5303: prev_half_pic_refs = HALF_PIC_NUMBER_REFS; 5304: } 5305: 5306: fputc ('\n', stderr); 5307: } 5308: 5309: /* Reset state info for each function. */ 5310: inside_function = FALSE; 5311: ignore_line_number = FALSE; 5312: dslots_load_total = 0; 5313: dslots_jump_total = 0; 5314: dslots_load_filled = 0; 5315: dslots_jump_filled = 0; 5316: num_refs[0] = 0; 5317: num_refs[1] = 0; 5318: num_refs[2] = 0; 5319: mips_load_reg = (rtx)0; 5320: mips_load_reg2 = (rtx)0; 5321: current_frame_info = zero_frame_info; 5322: 5323: /* Restore the output file if optimizing the GP (optimizing the GP causes 5324: the text to be diverted to a tempfile, so that data decls come before 5325: references to the data). */ 5326: 5327: if (TARGET_GP_OPT) 5328: asm_out_file = asm_out_data_file; 5329: } 5330: 5331: 5332: /* Expand the epilogue into a bunch of separate insns. */ 5333: 5334: void 5335: mips_expand_epilogue () 5336: { 5337: long tsize = current_frame_info.total_size; 5338: rtx tsize_rtx = GEN_INT (tsize); 5339: rtx tmp_rtx = (rtx)0; 5340: 5341: if (tsize > 32767) 5342: { 1.1.1.3 root 5343: tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM); 1.1 root 5344: emit_move_insn (tmp_rtx, tsize_rtx); 5345: tsize_rtx = tmp_rtx; 5346: } 5347: 5348: if (tsize > 0) 5349: { 5350: if (frame_pointer_needed) 1.1.1.3 root 5351: { 5352: if (TARGET_LONG64) 5353: emit_insn (gen_movdi (stack_pointer_rtx, frame_pointer_rtx)); 5354: else 5355: emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx)); 5356: } 1.1 root 5357: 5358: save_restore_insns (FALSE, tmp_rtx, tsize, (FILE *)0); 5359: 1.1.1.3 root 5360: if (TARGET_LONG64) 5361: emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, 5362: tsize_rtx)); 5363: else 5364: emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, 5365: tsize_rtx)); 1.1 root 5366: } 5367: 5368: emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, GP_REG_FIRST+31))); 5369: } 5370: 5371: 5372: /* Define the number of delay slots needed for the function epilogue. 5373: 5374: On the mips, we need a slot if either no stack has been allocated, 5375: or the only register saved is the return register. */ 5376: 5377: int 5378: mips_epilogue_delay_slots () 5379: { 5380: if (!current_frame_info.initialized) 5381: (void) compute_frame_size (get_frame_size ()); 5382: 5383: if (current_frame_info.total_size == 0) 5384: return 1; 5385: 5386: if (current_frame_info.mask == RA_MASK && current_frame_info.fmask == 0) 5387: return 1; 5388: 5389: return 0; 5390: } 5391: 5392: 5393: /* Return true if this function is known to have a null epilogue. 5394: This allows the optimizer to omit jumps to jumps if no stack 5395: was created. */ 5396: 5397: int 5398: simple_epilogue_p () 5399: { 5400: if (!reload_completed) 5401: return 0; 5402: 5403: if (current_frame_info.initialized) 5404: return current_frame_info.total_size == 0; 5405: 5406: return (compute_frame_size (get_frame_size ())) == 0; 5407: } 1.1.1.3 root 5408: 5409: /* Choose the section to use for the constant rtx expression X that has 5410: mode MODE. */ 5411: 5412: mips_select_rtx_section (mode, x) 5413: enum machine_mode mode; 5414: rtx x; 5415: { 5416: if (TARGET_EMBEDDED_DATA) 5417: { 5418: /* For embedded applications, always put constants in read-only data, 5419: in order to reduce RAM usage. */ 1.1.1.4 root 5420: READONLY_DATA_SECTION (); 1.1.1.3 root 5421: } 5422: else 5423: { 5424: /* For hosted applications, always put constants in small data if 5425: possible, as this gives the best performance. */ 5426: 5427: if (GET_MODE_SIZE (mode) <= mips_section_threshold 5428: && mips_section_threshold > 0) 1.1.1.4 root 5429: SMALL_DATA_SECTION (); 1.1.1.3 root 5430: else 1.1.1.4 root 5431: READONLY_DATA_SECTION (); 1.1.1.3 root 5432: } 5433: } 5434: 5435: /* Choose the section to use for DECL. RELOC is true if its value contains 5436: any relocatable expression. */ 5437: 5438: mips_select_section (decl, reloc) 5439: tree decl; 5440: int reloc; 5441: { 5442: int size = int_size_in_bytes (TREE_TYPE (decl)); 5443: 5444: if (TARGET_EMBEDDED_PIC 5445: && TREE_CODE (decl) == STRING_CST 5446: && !flag_writable_strings) 5447: { 5448: /* For embedded position independent code, put constant strings 5449: in the text section, because the data section is limited to 5450: 64K in size. */ 5451: 5452: text_section (); 5453: } 5454: else if (TARGET_EMBEDDED_DATA) 5455: { 5456: /* For embedded applications, always put an object in read-only data 5457: if possible, in order to reduce RAM usage. */ 5458: 1.1.1.4 root 5459: if (((TREE_CODE (decl) == VAR_DECL 5460: && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl) 1.1.1.3 root 5461: && DECL_INITIAL (decl) 5462: && (DECL_INITIAL (decl) == error_mark_node 5463: || TREE_CONSTANT (DECL_INITIAL (decl)))) 5464: /* Deal with calls from output_constant_def_contents. */ 5465: || (TREE_CODE (decl) != VAR_DECL 5466: && (TREE_CODE (decl) != STRING_CST 5467: || !flag_writable_strings))) 5468: && ! (flag_pic && reloc)) 1.1.1.4 root 5469: READONLY_DATA_SECTION (); 1.1.1.3 root 5470: else if (size > 0 && size <= mips_section_threshold) 1.1.1.4 root 5471: SMALL_DATA_SECTION (); 1.1.1.3 root 5472: else 5473: data_section (); 5474: } 5475: else 5476: { 5477: /* For hosted applications, always put an object in small data if 5478: possible, as this gives the best performance. */ 5479: 5480: if (size > 0 && size <= mips_section_threshold) 1.1.1.4 root 5481: SMALL_DATA_SECTION (); 5482: else if (((TREE_CODE (decl) == VAR_DECL 5483: && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl) 1.1.1.3 root 5484: && DECL_INITIAL (decl) 5485: && (DECL_INITIAL (decl) == error_mark_node 5486: || TREE_CONSTANT (DECL_INITIAL (decl)))) 5487: /* Deal with calls from output_constant_def_contents. */ 5488: || (TREE_CODE (decl) != VAR_DECL 5489: && (TREE_CODE (decl) != STRING_CST 5490: || !flag_writable_strings))) 5491: && ! (flag_pic && reloc)) 1.1.1.4 root 5492: READONLY_DATA_SECTION (); 1.1.1.3 root 5493: else 5494: data_section (); 5495: } 5496: } 1.1.1.4 root 5497: 5498: #if ABI_64BIT 5499: /* Support functions for the 64 bit ABI. */ 5500: 5501: /* Return the register to be used for word INDEX of a variable with type TYPE 5502: being passed starting at general purpose reg REGNO. 5503: 5504: If the word being passed is a single field of a structure which has type 5505: double, then pass it in a floating point reg instead of a general purpose 5506: reg. Otherwise, we return the default value REGNO + INDEX. */ 5507: 5508: rtx 5509: type_dependent_reg (regno, index, type) 5510: int regno; 5511: int index; 5512: tree type; 5513: { 5514: tree field; 5515: tree offset; 5516: 5517: /* If type isn't a structure type, return the default value now. */ 5518: if (! type || TREE_CODE (type) != RECORD_TYPE || mips_isa < 3) 5519: return gen_rtx (REG, word_mode, regno + index); 5520: 5521: /* Iterate through the structure fields to find which one corresponds to 5522: this index. */ 5523: offset = size_int (index * BITS_PER_WORD); 5524: for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 5525: { 5526: if (! tree_int_cst_lt (DECL_FIELD_BITPOS (field), offset)) 5527: break; 5528: } 5529: 5530: if (field && tree_int_cst_equal (DECL_FIELD_BITPOS (field), offset) 5531: && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE 5532: && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD) 5533: return gen_rtx (REG, DFmode, 5534: regno + index + FP_ARG_FIRST - GP_ARG_FIRST); 5535: else 5536: return gen_rtx (REG, word_mode, regno + index); 5537: } 5538: 5539: /* Return register to use for a function return value with VALTYPE for function 5540: FUNC. */ 5541: 5542: rtx 5543: mips_function_value (valtype, func) 5544: tree valtype; 5545: tree func; 5546: { 5547: int reg = GP_RETURN; 5548: enum machine_mode mode = TYPE_MODE (valtype); 5549: enum mode_class mclass = GET_MODE_CLASS (mode); 5550: 5551: if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) 5552: reg = FP_RETURN; 5553: else if (TREE_CODE (valtype) == RECORD_TYPE && mips_isa >= 3) 5554: { 5555: /* A struct with only one or two floating point fields is returned in 5556: the floating point registers. */ 5557: tree field; 5558: int i; 5559: 5560: for (i = 0, field = TYPE_FIELDS (valtype); field; 5561: field = TREE_CHAIN (field), i++) 5562: { 5563: if (TREE_CODE (TREE_TYPE (field)) != REAL_TYPE || i >= 2) 5564: break; 5565: } 5566: 5567: if (! field) 5568: reg = FP_RETURN; 5569: } 5570: 5571: return gen_rtx (REG, mode, reg); 5572: } 5573: #endif 5574: 5575: /* This function returns the register class required for a secondary 5576: register when copying between one of the registers in CLASS, and X, 5577: using MODE. If IN_P is nonzero, the copy is going from X to the 5578: register, otherwise the register is the source. A return value of 5579: NO_REGS means that no secondary register is required. */ 5580: 5581: enum reg_class 5582: mips_secondary_reload_class (class, mode, x, in_p) 5583: enum reg_class class; 5584: enum machine_mode mode; 5585: rtx x; 5586: int in_p; 5587: { 5588: int regno = -1; 5589: 5590: if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG) 5591: regno = true_regnum (x); 5592: 5593: /* We always require a general register when copying anything to 5594: HILO_REGNUM, except when copying an SImode value from HILO_REGNUM 5595: to a general register, or when copying from register 0. */ 5596: if (class == HILO_REG && regno != GP_REG_FIRST + 0) 5597: { 5598: if (! in_p 5599: && GP_REG_P (regno) 5600: && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode)) 5601: return NO_REGS; 5602: return GR_REGS; 5603: } 5604: if (regno == HILO_REGNUM) 5605: { 5606: if (in_p 5607: && class == GR_REGS 5608: && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode)) 5609: return NO_REGS; 5610: return GR_REGS; 5611: } 5612: 5613: /* Copying from HI or LO to anywhere other than a general register 5614: requires a general register. */ 5615: if (class == HI_REG || class == LO_REG || class == MD_REGS) 5616: { 5617: if (GP_REG_P (regno)) 5618: return NO_REGS; 5619: return GR_REGS; 5620: } 5621: if (MD_REG_P (regno)) 5622: { 5623: if (class == GR_REGS) 5624: return NO_REGS; 5625: return GR_REGS; 5626: } 5627: 5628: return NO_REGS; 5629: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.