Annotation of GNUtools/cc/config/mips/mips.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.