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

unix.superglobalmegacorp.com

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