Annotation of gcc/config/mips.c, revision 1.1.1.2

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: 
1.1.1.2 ! root      148: /* Whether to suppress issuing .loc's because the user attempted
1.1       root      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: 
                    523:   /* Eliminate non-memory operations */
                    524:   if (GET_CODE (op) != MEM)
                    525:     return FALSE;
                    526: 
                    527:   /* dword operations really put out 2 instructions, so eliminate them.  */
                    528:   if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
                    529:     return FALSE;
                    530: 
                    531:   /* Decode the address now.  */
                    532:   addr = XEXP (op, 0);
                    533:   switch (GET_CODE (addr))
                    534:     {
                    535:     case REG:
                    536:       return TRUE;
                    537: 
                    538:     case CONST_INT:
                    539:       return SMALL_INT (op);
                    540: 
                    541:     case PLUS:
                    542:       plus0 = XEXP (addr, 0);
                    543:       plus1 = XEXP (addr, 1);
                    544:       if (GET_CODE (plus0) == REG
                    545:          && GET_CODE (plus1) == CONST_INT
                    546:          && SMALL_INT (plus1))
                    547:        return TRUE;
                    548: 
                    549:       else if (GET_CODE (plus1) == REG
                    550:               && GET_CODE (plus0) == CONST_INT
                    551:               && SMALL_INT (plus0))
                    552:        return TRUE;
                    553: 
                    554:       else
                    555:        return FALSE;
                    556: 
                    557: #if 0
                    558:       /* We used to allow small symbol refs here (ie, stuff in .sdata
                    559:         or .sbss), but this causes some bugs in G++.  Also, it won't
                    560:         interfere if the MIPS linker rewrites the store instruction
                    561:         because the function is PIC.  */
                    562: 
                    563:     case LABEL_REF:            /* never gp relative */
                    564:       break;
                    565: 
                    566:     case CONST:
                    567:       /* If -G 0, we can never have a GP relative memory operation.
                    568:         Also, save some time if not optimizing.  */
                    569:       if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT)
                    570:        return FALSE;
                    571: 
1.1.1.2 ! root      572:       {
        !           573:        rtx offset = const0_rtx;
        !           574:        addr = eliminate_constant_term (addr, &offset);
        !           575:        if (GET_CODE (op) != SYMBOL_REF)
        !           576:          return FALSE;
        !           577: 
        !           578:        /* let's be paranoid.... */
        !           579:        if (INTVAL (offset) < 0 || INTVAL (offset) > 0xffff)
        !           580:          return FALSE;
        !           581:       }
1.1       root      582:       /* fall through */
                    583: 
                    584:     case SYMBOL_REF:
                    585:       return SYMBOL_REF_FLAG (addr);
                    586: #endif
                    587:     }
                    588: 
                    589:   return FALSE;
                    590: }
                    591: 
                    592: /* Return true if the address is suitable for function call.  */
                    593: 
                    594: int
                    595: call_memory_operand (op, mode)
                    596:      rtx op;
                    597:      enum machine_mode mode;
                    598: {
                    599:   rtx addr;
                    600:   enum rtx_code code;
                    601: 
                    602:   if (GET_CODE (op) != MEM)
                    603:     return FALSE;
                    604: 
                    605:   addr = XEXP (op, 0);
                    606:   code = GET_CODE (addr);
                    607: 
                    608:   if (GET_MODE (addr) != FUNCTION_MODE)
                    609:     return FALSE;
                    610: 
                    611:   if (code == REG || code == SUBREG)
                    612:     return TRUE;
                    613: 
                    614:   if (CONSTANT_ADDRESS_P (addr))
                    615:     return TRUE;
                    616: 
                    617:   return FALSE;
                    618: }
                    619: 
                    620: /* Return true if the code of this rtx pattern is EQ or NE.  */
                    621: 
                    622: int
                    623: equality_op (op, mode)
                    624:      rtx op;
                    625:      enum machine_mode mode;
                    626: {
                    627:   if (mode != GET_MODE (op))
                    628:     return FALSE;
                    629: 
                    630:   return (classify_op (op, mode) & CLASS_EQUALITY_OP) != 0;
                    631: }
                    632: 
                    633: /* Return true if the code is a relational operations (EQ, LE, etc.) */
                    634: 
                    635: int
                    636: cmp_op (op, mode)
                    637:      rtx op;
                    638:      enum machine_mode mode;
                    639: {
                    640:   if (mode != GET_MODE (op))
                    641:     return FALSE;
                    642: 
                    643:   return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
                    644: }
                    645: 
                    646: 
                    647: /* Genrecog does not take the type of match_operator into consideration,
                    648:    and would complain about two patterns being the same if the same
                    649:    function is used, so make it believe they are different.  */
                    650: 
                    651: int
                    652: cmp2_op (op, mode)
                    653:      rtx op;
                    654:      enum machine_mode mode;
                    655: {
                    656:   if (mode != GET_MODE (op))
                    657:     return FALSE;
                    658: 
                    659:   return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
                    660: }
                    661: 
                    662: /* Return true if the code is an unsigned relational operations (LEU, etc.) */
                    663: 
                    664: int
                    665: uns_cmp_op (op,mode)
                    666:      rtx op;
                    667:      enum machine_mode mode;
                    668: {
                    669:   if (mode != GET_MODE (op))
                    670:     return FALSE;
                    671: 
                    672:   return (classify_op (op, mode) & CLASS_UNS_CMP_OP) == CLASS_UNS_CMP_OP;
                    673: }
                    674: 
                    675: /* Return true if the code is a relational operation FP can use.  */
                    676: 
                    677: int
                    678: fcmp_op (op, mode)
                    679:      rtx op;
                    680:      enum machine_mode mode;
                    681: {
                    682:   if (mode != GET_MODE (op))
                    683:     return FALSE;
                    684: 
                    685:   return (classify_op (op, mode) & CLASS_FCMP_OP) != 0;
                    686: }
                    687: 
                    688: 
                    689: /* Return an operand string if the given instruction's delay slot or
                    690:    wrap it in a .set noreorder section.  This is for filling delay
                    691:    slots on load type instructions under GAS, which does no reordering
                    692:    on its own.  For the MIPS assembler, all we do is update the filled
                    693:    delay slot statistics.
                    694: 
                    695:    We assume that operands[0] is the target register that is set.
                    696: 
                    697:    In order to check the next insn, most of this functionality is moved
                    698:    to FINAL_PRESCAN_INSN, and we just set the global variables that
                    699:    it needs.  */
                    700: 
                    701: char *
                    702: mips_fill_delay_slot (ret, type, operands, cur_insn)
                    703:      char *ret;                        /* normal string to return */
                    704:      enum delay_type type;     /* type of delay */
                    705:      rtx operands[];           /* operands to use */
                    706:      rtx cur_insn;             /* current insn */
                    707: {
                    708:   register rtx set_reg;
                    709:   register enum machine_mode mode;
                    710:   register rtx next_insn       = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0;
                    711:   register int num_nops;
                    712: 
                    713:   if (type == DELAY_LOAD)
                    714:     num_nops = 1;
                    715: 
                    716:   else if (type == DELAY_HILO)
                    717:     num_nops = 2;
                    718: 
                    719:   else
                    720:     num_nops = 0;
                    721: 
                    722:   /* Make sure that we don't put nop's after labels.  */
                    723:   next_insn = NEXT_INSN (cur_insn);
                    724:   while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE)
                    725:     next_insn = NEXT_INSN (next_insn);
                    726: 
                    727:   dslots_load_total += num_nops;
                    728:   if (TARGET_DEBUG_F_MODE
                    729:       || !optimize
                    730:       || type == DELAY_NONE
                    731:       || operands == (rtx *)0
                    732:       || cur_insn == (rtx)0
                    733:       || next_insn == (rtx)0
                    734:       || GET_CODE (next_insn) == CODE_LABEL
                    735:       || (set_reg = operands[0]) == (rtx)0)
                    736:     {
                    737:       dslots_number_nops = 0;
                    738:       mips_load_reg  = (rtx)0;
                    739:       mips_load_reg2 = (rtx)0;
                    740:       mips_load_reg3 = (rtx)0;
                    741:       mips_load_reg4 = (rtx)0;
                    742:       return ret;
                    743:     }
                    744: 
                    745:   set_reg = operands[0];
                    746:   if (set_reg == (rtx)0)
                    747:     return ret;
                    748: 
                    749:   while (GET_CODE (set_reg) == SUBREG)
                    750:     set_reg = SUBREG_REG (set_reg);
                    751: 
                    752:   mode = GET_MODE (set_reg);
                    753:   dslots_number_nops = num_nops;
                    754:   mips_load_reg  = set_reg;
                    755:   mips_load_reg2 = (mode == DImode || mode == DFmode)
                    756:                        ? gen_rtx (REG, SImode, REGNO (set_reg) + 1)
                    757:                        : (rtx)0;
                    758: 
                    759:   if (type == DELAY_HILO)
                    760:     {
                    761:       mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);
                    762:       mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);
                    763:     }
                    764:   else
                    765:     {
                    766:       mips_load_reg3 = 0;
                    767:       mips_load_reg4 = 0;
                    768:     }
                    769: 
                    770:   if (TARGET_GAS && set_noreorder++ == 0)
                    771:     fputs ("\t.set\tnoreorder\n", asm_out_file);
                    772: 
                    773:   return ret;
                    774: }
                    775: 
                    776: 
                    777: /* Determine whether a memory reference takes one (based off of the GP pointer),
1.1.1.2 ! root      778:    two (normal), or three (label + reg) instructions, and bump the appropriate
1.1       root      779:    counter for -mstats.  */
                    780: 
                    781: void
                    782: mips_count_memory_refs (op, num)
                    783:      rtx op;
                    784:      int num;
                    785: {
                    786:   int additional = 0;
                    787:   int n_words = 0;
                    788:   rtx addr, plus0, plus1;
                    789:   enum rtx_code code0, code1;
                    790:   int looping;
                    791: 
                    792:   if (TARGET_DEBUG_B_MODE)
                    793:     {
                    794:       fprintf (stderr, "\n========== mips_count_memory_refs:\n");
                    795:       debug_rtx (op);
                    796:     }
                    797: 
                    798:   /* Skip MEM if passed, otherwise handle movsi of address.  */
                    799:   addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0);
                    800: 
                    801:   /* Loop, going through the address RTL */
                    802:   do
                    803:     {
                    804:       looping = FALSE;
                    805:       switch (GET_CODE (addr))
                    806:        {
                    807:        case REG:
                    808:        case CONST_INT:
                    809:          break;
                    810: 
                    811:        case PLUS:
                    812:          plus0 = XEXP (addr, 0);
                    813:          plus1 = XEXP (addr, 1);
                    814:          code0 = GET_CODE (plus0);
                    815:          code1 = GET_CODE (plus1);
                    816: 
                    817:          if (code0 == REG)
                    818:            {
                    819:              additional++;
                    820:              addr = plus1;
                    821:              looping = TRUE;
                    822:              continue;
                    823:            }
                    824: 
                    825:          if (code0 == CONST_INT)
                    826:            {
                    827:              addr = plus1;
                    828:              looping = TRUE;
                    829:              continue;
                    830:            }
                    831: 
                    832:          if (code1 == REG)
                    833:            {
                    834:              additional++;
                    835:              addr = plus0;
                    836:              looping = TRUE;
                    837:              continue;
                    838:            }
                    839: 
                    840:          if (code1 == CONST_INT)
                    841:            {
                    842:              addr = plus0;
                    843:              looping = TRUE;
                    844:              continue;
                    845:            }
                    846: 
                    847:          if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST)
                    848:            {
                    849:              addr = plus0;
                    850:              looping = TRUE;
                    851:              continue;
                    852:            }
                    853: 
                    854:          if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST)
                    855:            {
                    856:              addr = plus1;
                    857:              looping = TRUE;
                    858:              continue;
                    859:            }
                    860: 
                    861:          break;
                    862: 
                    863:        case LABEL_REF:
                    864:          n_words = 2;          /* always 2 words */
                    865:          break;
                    866: 
                    867:        case CONST:
                    868:          addr = XEXP (addr, 0);
                    869:          looping = TRUE;
                    870:          continue;
                    871: 
                    872:        case SYMBOL_REF:
                    873:          n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2;
                    874:          break;
                    875:        }
                    876:     }
                    877:   while (looping);
                    878: 
                    879:   if (n_words == 0)
                    880:     return;
                    881: 
                    882:   n_words += additional;
                    883:   if (n_words > 3)
                    884:     n_words = 3;
                    885: 
                    886:   num_refs[n_words-1] += num;
                    887: }
                    888: 
                    889: 
                    890: /* Return the appropriate instructions to move one operand to another.  */
                    891: 
                    892: char *
                    893: mips_move_1word (operands, insn, unsignedp)
                    894:      rtx operands[];
                    895:      rtx insn;
                    896:      int unsignedp;
                    897: {
                    898:   char *ret = 0;
                    899:   rtx op0 = operands[0];
                    900:   rtx op1 = operands[1];
                    901:   enum rtx_code code0 = GET_CODE (op0);
                    902:   enum rtx_code code1 = GET_CODE (op1);
                    903:   enum machine_mode mode = GET_MODE (op0);
                    904:   int subreg_word0 = 0;
                    905:   int subreg_word1 = 0;
                    906:   enum delay_type delay = DELAY_NONE;
                    907: 
                    908:   while (code0 == SUBREG)
                    909:     {
                    910:       subreg_word0 += SUBREG_WORD (op0);
                    911:       op0 = SUBREG_REG (op0);
                    912:       code0 = GET_CODE (op0);
                    913:     }
                    914: 
                    915:   while (code1 == SUBREG)
                    916:     {
                    917:       subreg_word1 += SUBREG_WORD (op1);
                    918:       op1 = SUBREG_REG (op1);
                    919:       code1 = GET_CODE (op1);
                    920:     }
                    921: 
                    922:   if (code0 == REG)
                    923:     {
                    924:       int regno0 = REGNO (op0) + subreg_word0;
                    925: 
                    926:       if (code1 == REG)
                    927:        {
                    928:          int regno1 = REGNO (op1) + subreg_word1;
                    929: 
                    930:          /* Just in case, don't do anything for assigning a register
                    931:             to itself, unless we are filling a delay slot.  */
                    932:          if (regno0 == regno1 && set_nomacro == 0)
                    933:            ret = "";
                    934: 
                    935:          else if (GP_REG_P (regno0))
                    936:            {
                    937:              if (GP_REG_P (regno1))
                    938:                ret = "move\t%0,%1";
                    939: 
                    940:              else if (MD_REG_P (regno1))
                    941:                {
                    942:                  delay = DELAY_HILO;
                    943:                  ret = "mf%1\t%0";
                    944:                }
                    945: 
                    946:              else
                    947:                {
                    948:                  delay = DELAY_LOAD;
                    949:                  if (FP_REG_P (regno1))
                    950:                    ret = "mfc1\t%0,%1";
                    951: 
                    952:                  else if (regno1 == FPSW_REGNUM)
                    953:                    ret = "cfc1\t%0,$31";
                    954:                }
                    955:            }
                    956: 
                    957:          else if (FP_REG_P (regno0))
                    958:            {
                    959:              if (GP_REG_P (regno1))
                    960:                {
                    961:                  delay = DELAY_LOAD;
                    962:                  ret = "mtc1\t%1,%0";
                    963:                }
                    964: 
                    965:              if (FP_REG_P (regno1))
                    966:                ret = "mov.s\t%0,%1";
                    967:            }
                    968: 
                    969:          else if (MD_REG_P (regno0))
                    970:            {
                    971:              if (GP_REG_P (regno1))
                    972:                {
                    973:                  delay = DELAY_HILO;
                    974:                  ret = "mt%0\t%1";
                    975:                }
                    976:            }
                    977: 
                    978:          else if (regno0 == FPSW_REGNUM)
                    979:            {
                    980:              if (GP_REG_P (regno1))
                    981:                {
                    982:                  delay = DELAY_LOAD;
                    983:                  ret = "ctc1\t%0,$31";
                    984:                }
                    985:            }
                    986:        }
                    987: 
                    988:       else if (code1 == MEM)
                    989:        {
                    990:          delay = DELAY_LOAD;
                    991: 
                    992:          if (TARGET_STATS)
                    993:            mips_count_memory_refs (op1, 1);
                    994: 
                    995:          if (GP_REG_P (regno0))
                    996:            {
                    997:              /* For loads, use the mode of the memory item, instead of the
                    998:                 target, so zero/sign extend can use this code as well.  */
                    999:              switch (GET_MODE (op1))
                   1000:                {
                   1001:                case SFmode: ret = "lw\t%0,%1"; break;
                   1002:                case SImode: ret = "lw\t%0,%1"; break;
                   1003:                case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break;
                   1004:                case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break;
                   1005:                }
                   1006:            }
                   1007: 
                   1008:          else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))
                   1009:            ret = "l.s\t%0,%1";
                   1010: 
                   1011:          if (ret != (char *)0 && MEM_VOLATILE_P (op1))
                   1012:            {
                   1013:              int i = strlen (ret);
                   1014:              if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
                   1015:                abort ();
                   1016: 
                   1017:              sprintf (volatile_buffer, "%%{%s%%}", ret);
                   1018:              ret = volatile_buffer;
                   1019:            }
                   1020:        }
                   1021: 
                   1022:       else if (code1 == CONST_INT)
                   1023:        {
                   1024:          if (INTVAL (op1) == 0)
                   1025:            {
                   1026:              if (GP_REG_P (regno0))
                   1027:                ret = "move\t%0,%z1";
                   1028: 
                   1029:              else if (FP_REG_P (regno0))
                   1030:                {
                   1031:                  delay = DELAY_LOAD;
                   1032:                  return "mtc1\t%z1,%0";
                   1033:                }
                   1034:            }
                   1035: 
                   1036:          else if (GP_REG_P (regno0))
                   1037:            {
                   1038:              if ((INTVAL (operands[1]) & 0x0000ffff) == 0)
                   1039:                ret = "lui\t%0,(%X1)>>16";
                   1040:              else
                   1041:                ret = "li\t%0,%1";
                   1042:            }
                   1043:        }
                   1044: 
                   1045:       else if (code1 == CONST_DOUBLE && mode == SFmode)
                   1046:        {
                   1047:          if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
                   1048:            {
                   1049:              if (GP_REG_P (regno0))
                   1050:                ret = "move\t%0,%.";
                   1051: 
                   1052:              else if (FP_REG_P (regno0))
                   1053:                {
                   1054:                  delay = DELAY_LOAD;
                   1055:                  ret = "mtc1\t%.,%0";
                   1056:                }
                   1057:            }
                   1058: 
                   1059:          else
                   1060:            {
                   1061:              delay = DELAY_LOAD;
                   1062:              ret = "li.s\t%0,%1";
                   1063:            }
                   1064:        }
                   1065: 
                   1066:       else if (code1 == LABEL_REF)
                   1067:        ret = "la\t%0,%a1";
                   1068: 
                   1069:       else if (code1 == SYMBOL_REF || code1 == CONST)
                   1070:        {
                   1071:          if (TARGET_STATS)
                   1072:            mips_count_memory_refs (op1, 1);
                   1073: 
                   1074:          if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1))
                   1075:            {
                   1076:              delay = DELAY_LOAD;
                   1077:              ret = "la\t%0,%a1\t\t# pic reference";
                   1078:            }
                   1079:          else
                   1080:            ret = "la\t%0,%a1";
                   1081:        }
                   1082: 
                   1083:       else if (code1 == PLUS)
                   1084:        {
                   1085:          rtx add_op0 = XEXP (op1, 0);
                   1086:          rtx add_op1 = XEXP (op1, 1);
                   1087: 
                   1088:          if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT)
                   1089:            {
                   1090:              add_op0 = XEXP (op1, 1);          /* reverse operands */
                   1091:              add_op1 = XEXP (op1, 0);
                   1092:            }
                   1093: 
                   1094:          operands[2] = add_op0;
                   1095:          operands[3] = add_op1;
                   1096:          ret = "add%:\t%0,%2,%3";
                   1097:        }
                   1098:     }
                   1099: 
                   1100:   else if (code0 == MEM)
                   1101:     {
                   1102:       if (TARGET_STATS)
                   1103:        mips_count_memory_refs (op0, 1);
                   1104: 
                   1105:       if (code1 == REG)
                   1106:        {
                   1107:          int regno1 = REGNO (op1) + subreg_word1;
                   1108: 
                   1109:          if (GP_REG_P (regno1))
                   1110:            {
                   1111:              switch (mode)
                   1112:                {
                   1113:                case SFmode: ret = "sw\t%1,%0"; break;
                   1114:                case SImode: ret = "sw\t%1,%0"; break;
                   1115:                case HImode: ret = "sh\t%1,%0"; break;
                   1116:                case QImode: ret = "sb\t%1,%0"; break;
                   1117:                }
                   1118:            }
                   1119: 
                   1120:          else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode))
                   1121:            ret = "s.s\t%1,%0";
                   1122:        }
                   1123: 
                   1124:       else if (code1 == CONST_INT && INTVAL (op1) == 0)
                   1125:        {
                   1126:          switch (mode)
                   1127:            {
                   1128:            case SFmode: ret = "sw\t%z1,%0"; break;
                   1129:            case SImode: ret = "sw\t%z1,%0"; break;
                   1130:            case HImode: ret = "sh\t%z1,%0"; break;
                   1131:            case QImode: ret = "sb\t%z1,%0"; break;
                   1132:            }
                   1133:        }
                   1134: 
                   1135:       else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
                   1136:        {
                   1137:          switch (mode)
                   1138:            {
                   1139:            case SFmode: ret = "sw\t%.,%0"; break;
                   1140:            case SImode: ret = "sw\t%.,%0"; break;
                   1141:            case HImode: ret = "sh\t%.,%0"; break;
                   1142:            case QImode: ret = "sb\t%.,%0"; break;
                   1143:            }
                   1144:        }
                   1145: 
                   1146:       if (ret != (char *)0 && MEM_VOLATILE_P (op0))
                   1147:        {
                   1148:          int i = strlen (ret);
                   1149:          if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
                   1150:            abort ();
                   1151:          
                   1152:          sprintf (volatile_buffer, "%%{%s%%}", ret);
                   1153:          ret = volatile_buffer;
                   1154:        }
                   1155:     }
                   1156: 
                   1157:   if (ret == (char *)0)
                   1158:     {
                   1159:       abort_with_insn (insn, "Bad move");
                   1160:       return 0;
                   1161:     }
                   1162: 
                   1163:   if (delay != DELAY_NONE)
                   1164:     return mips_fill_delay_slot (ret, delay, operands, insn);
                   1165: 
                   1166:   return ret;
                   1167: }
                   1168: 
                   1169: 
                   1170: /* Return the appropriate instructions to move 2 words */
                   1171: 
                   1172: char *
                   1173: mips_move_2words (operands, insn)
                   1174:      rtx operands[];
                   1175:      rtx insn;
                   1176: {
                   1177:   char *ret = 0;
                   1178:   rtx op0 = operands[0];
                   1179:   rtx op1 = operands[1];
                   1180:   enum rtx_code code0 = GET_CODE (operands[0]);
                   1181:   enum rtx_code code1 = GET_CODE (operands[1]);
                   1182:   int subreg_word0 = 0;
                   1183:   int subreg_word1 = 0;
                   1184:   enum delay_type delay = DELAY_NONE;
                   1185: 
                   1186:   while (code0 == SUBREG)
                   1187:     {
                   1188:       subreg_word0 += SUBREG_WORD (op0);
                   1189:       op0 = SUBREG_REG (op0);
                   1190:       code0 = GET_CODE (op0);
                   1191:     }
                   1192: 
                   1193:   while (code1 == SUBREG)
                   1194:     {
                   1195:       subreg_word1 += SUBREG_WORD (op1);
                   1196:       op1 = SUBREG_REG (op1);
                   1197:       code1 = GET_CODE (op1);
                   1198:     }
                   1199:       
                   1200:   if (code0 == REG)
                   1201:     {
                   1202:       int regno0 = REGNO (op0) + subreg_word0;
                   1203: 
                   1204:       if (code1 == REG)
                   1205:        {
                   1206:          int regno1 = REGNO (op1) + subreg_word1;
                   1207: 
                   1208:          /* Just in case, don't do anything for assigning a register
                   1209:             to itself, unless we are filling a delay slot.  */
                   1210:          if (regno0 == regno1 && set_nomacro == 0)
                   1211:            ret = "";
                   1212: 
                   1213:          else if (FP_REG_P (regno0))
                   1214:            {
                   1215:              if (FP_REG_P (regno1))
                   1216:                ret = "mov.d\t%0,%1";
                   1217: 
                   1218:              else
                   1219:                {
                   1220:                  delay = DELAY_LOAD;
                   1221:                  ret = (TARGET_FLOAT64)
                   1222:                                ? "dmtc1\t%1,%0"
                   1223:                                : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0";
                   1224:                }
                   1225:            }
                   1226: 
                   1227:          else if (FP_REG_P (regno1))
                   1228:            {
                   1229:              delay = DELAY_LOAD;
                   1230:              ret = (TARGET_FLOAT64)
                   1231:                        ? "dmfc1\t%0,%1"
                   1232:                        : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1";
                   1233:            }
                   1234: 
                   1235:          else if (MD_REG_P (regno0) && GP_REG_P (regno1))
                   1236:            {
                   1237:              delay = DELAY_HILO;
                   1238:              ret = "mthi\t%M1\n\tmtlo\t%L1";
                   1239:            }
                   1240: 
                   1241:          else if (GP_REG_P (regno0) && MD_REG_P (regno1))
                   1242:            {
                   1243:              delay = DELAY_HILO;
                   1244:              ret = "mfhi\t%M0\n\tmflo\t%L0";
                   1245:            }
                   1246: 
                   1247:          else if (regno0 != (regno1+1))
                   1248:            ret = "move\t%0,%1\n\tmove\t%D0,%D1";
                   1249: 
                   1250:          else
                   1251:            ret = "move\t%D0,%D1\n\tmove\t%0,%1";
                   1252:        }
                   1253: 
                   1254:       else if (code1 == CONST_DOUBLE)
                   1255:        {
                   1256:          if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0)
                   1257:            {
                   1258:              if (GET_MODE (op1) == DFmode)
                   1259:                {
                   1260:                  delay = DELAY_LOAD;
                   1261:                  ret = "li.d\t%0,%1";
                   1262:                }
                   1263: 
                   1264:              else
                   1265:                {
                   1266:                  operands[2] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (op1));
                   1267:                  operands[3] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (op1));
                   1268:                  ret = "li\t%M0,%3\n\tli\t%L0,%2";
                   1269:                }
                   1270:            }
                   1271: 
                   1272:          else
                   1273:            {
                   1274:              if (GP_REG_P (regno0))
                   1275:                ret = "move\t%0,%.\n\tmove\t%D0,%.";
                   1276: 
                   1277:              else if (FP_REG_P (regno0))
                   1278:                {
                   1279:                  delay = DELAY_LOAD;
                   1280:                  ret = (TARGET_FLOAT64)
                   1281:                                ? "dmtc1\t%.,%0"
                   1282:                                : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
                   1283:                }
                   1284:            }
                   1285:        }
                   1286: 
                   1287:       else if (code1 == CONST_INT && INTVAL (op1) == 0)
                   1288:        {
                   1289:          if (GP_REG_P (regno0))
                   1290:            ret = "move\t%0,%.\n\tmove\t%D0,%.";
                   1291:          
                   1292:          else if (FP_REG_P (regno0))
                   1293:            {
                   1294:              delay = DELAY_LOAD;
                   1295:              ret = (TARGET_FLOAT64)
                   1296:                                ? "dmtc1\t%.,%0"
                   1297:                                : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
                   1298:            }
                   1299:        }
                   1300:        
                   1301:       else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0))
                   1302:        {
                   1303:          operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >= 0 ? 0 : -1);
                   1304:          ret = "li\t%M0,%2\n\tli\t%L0,%1";
                   1305:        }
                   1306: 
                   1307:       else if (code1 == MEM)
                   1308:        {
                   1309:          delay = DELAY_LOAD;
                   1310: 
                   1311:          if (TARGET_STATS)
                   1312:            mips_count_memory_refs (op1, 2);
                   1313: 
                   1314:          if (FP_REG_P (regno0))
                   1315:            ret = "l.d\t%0,%1";
                   1316: 
                   1317:          else if (offsettable_address_p (1, DFmode, XEXP (op1, 0)))
                   1318:            {
                   1319:              operands[2] = adj_offsettable_operand (op1, 4);
                   1320:              if (reg_mentioned_p (op0, op1))
                   1321:                ret = "lw\t%D0,%2\n\tlw\t%0,%1";
                   1322:              else
                   1323:                ret = "lw\t%0,%1\n\tlw\t%D0,%2";
                   1324:            }
                   1325: 
                   1326:          if (ret != (char *)0 && MEM_VOLATILE_P (op1))
                   1327:            {
                   1328:              int i = strlen (ret);
                   1329:              if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
                   1330:                abort ();
                   1331: 
                   1332:              sprintf (volatile_buffer, "%%{%s%%}", ret);
                   1333:              ret = volatile_buffer;
                   1334:            }
                   1335:        }
                   1336:     }
                   1337: 
                   1338:   else if (code0 == MEM)
                   1339:     {
                   1340:       if (code1 == REG)
                   1341:        {
                   1342:          int regno1 = REGNO (op1) + subreg_word1;
                   1343: 
                   1344:          if (FP_REG_P (regno1))
                   1345:            ret = "s.d\t%1,%0";
                   1346: 
                   1347:          else if (offsettable_address_p (1, DFmode, XEXP (op0, 0)))
                   1348:            {
                   1349:              operands[2] = adj_offsettable_operand (op0, 4);
                   1350:              ret = "sw\t%1,%0\n\tsw\t%D1,%2";
                   1351:            }
                   1352:        }
                   1353: 
                   1354:       else if (code1 == CONST_DOUBLE
                   1355:               && CONST_DOUBLE_HIGH (op1) == 0
                   1356:               && CONST_DOUBLE_LOW (op1) == 0
                   1357:               && offsettable_address_p (1, DFmode, XEXP (op0, 0)))
                   1358:        {
                   1359:          if (TARGET_FLOAT64)
                   1360:            ret = "sd\t%.,%0";
                   1361:          else
                   1362:            {
                   1363:              operands[2] = adj_offsettable_operand (op0, 4);
                   1364:              ret = "sw\t%.,%0\n\tsw\t%.,%2";
                   1365:            }
                   1366:        }
                   1367: 
                   1368:       if (TARGET_STATS)
                   1369:        mips_count_memory_refs (op0, 2);
                   1370: 
                   1371:       if (ret != (char *)0 && MEM_VOLATILE_P (op0))
                   1372:        {
                   1373:          int i = strlen (ret);
                   1374:          if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
                   1375:            abort ();
                   1376:          
                   1377:          sprintf (volatile_buffer, "%%{%s%%}", ret);
                   1378:          ret = volatile_buffer;
                   1379:        }
                   1380:     }
                   1381: 
                   1382:   if (ret == (char *)0)
                   1383:     {
                   1384:       abort_with_insn (insn, "Bad move");
                   1385:       return 0;
                   1386:     }
                   1387: 
                   1388:   if (delay != DELAY_NONE)
                   1389:     return mips_fill_delay_slot (ret, delay, operands, insn);
                   1390: 
                   1391:   return ret;
                   1392: }
                   1393: 
                   1394: 
                   1395: /* Provide the costs of an addressing mode that contains ADDR.
1.1.1.2 ! root     1396:    If ADDR is not a valid address, its cost is irrelevant.  */
1.1       root     1397: 
                   1398: int
                   1399: mips_address_cost (addr)
                   1400:      rtx addr;
                   1401: {
                   1402:   switch (GET_CODE (addr))
                   1403:     {
                   1404:     case LO_SUM:
                   1405:     case HIGH:
                   1406:       return 1;
                   1407: 
                   1408:     case LABEL_REF:
                   1409:       return 2;
                   1410: 
                   1411:     case CONST:
1.1.1.2 ! root     1412:       {
        !          1413:        rtx offset = const0_rtx;
        !          1414:        addr = eliminate_constant_term (addr, &offset);
        !          1415:        if (GET_CODE (addr) == LABEL_REF)
        !          1416:          return 2;
1.1       root     1417: 
1.1.1.2 ! root     1418:        if (GET_CODE (addr) != SYMBOL_REF)
        !          1419:          return 4;
1.1       root     1420: 
1.1.1.2 ! root     1421:        if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767)
        !          1422:          return 2;
        !          1423:       }
1.1       root     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 */
1.1.1.2 ! root     1635:   rtx dest_addr;               /* destination address */
1.1       root     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: 
1.1.1.2 ! root     2420:   /* Set up the classification arrays now.  */
1.1       root     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
1.1.1.2 ! root     2480:      mandatory delay, it is as fast to load from cached memory as to move
1.1       root     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: {
1.1.1.2 ! root     2528:   rtx offset2 = const0_rtx;
1.1       root     2529:   rtx reg = eliminate_constant_term (addr, &offset2);
                   2530: 
                   2531:   if (!offset)
1.1.1.2 ! root     2532:     offset = INTVAL (offset2);
1.1       root     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);
1.1.1.2 ! root     2985:       if (!TARGET_GAS && write_symbols == DBX_DEBUG)
        !          2986:        fprintf (stream, "\t#@stabs\n");
1.1       root     2987:     }
                   2988: 
                   2989:   else if (!TARGET_GAS && write_symbols == DBX_DEBUG)
                   2990:     {
                   2991:       ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
                   2992:       fprintf (stream, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP,
                   2993:               name, N_SOL, &ltext_label_name[1]);
                   2994:     }
                   2995: 
                   2996:   else if (name != current_function_file
                   2997:       && strcmp (name, current_function_file) != 0)
                   2998:     {
                   2999:       if (inside_function && !TARGET_GAS)
                   3000:        {
                   3001:          if (!file_in_function_warning)
                   3002:            {
                   3003:              file_in_function_warning = TRUE;
                   3004:              ignore_line_number = TRUE;
                   3005:              warning ("MIPS ECOFF format does not allow changing filenames within functions with #line");
                   3006:            }
                   3007: 
                   3008:          fprintf (stream, "\t#.file\t%d \"%s\"\n", num_source_filenames, name);
                   3009:        }
                   3010: 
                   3011:       else
                   3012:        {
                   3013:          SET_FILE_NUMBER ();
                   3014:          current_function_file = name;
                   3015:          fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name);
                   3016:        }
                   3017:     }
                   3018: }
                   3019: 
                   3020: 
                   3021: /* Emit a linenumber.  For encapsulated stabs, we need to put out a stab
                   3022:    as well as a .loc, since it is possible that MIPS ECOFF might not be
                   3023:    able to represent the location for inlines that come from a different
                   3024:    file.  */
                   3025: 
                   3026: void
                   3027: mips_output_lineno (stream, line)
                   3028:      FILE *stream;
                   3029:      int line;
                   3030: {
                   3031:   if (!TARGET_GAS && write_symbols == DBX_DEBUG)
                   3032:     {
                   3033:       ++sym_lineno;
                   3034:       fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n",
                   3035:               sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
                   3036:     }
                   3037: 
                   3038:   else
                   3039:     {
                   3040:       fprintf (stream, "\n\t%s.loc\t%d %d\n",
                   3041:               (ignore_line_number) ? "#" : "",
                   3042:               num_source_filenames, line);
                   3043:   
                   3044:       LABEL_AFTER_LOC (stream);
                   3045:     }
                   3046: }
                   3047: 
                   3048: 
                   3049: /* Output at beginning of assembler file.
                   3050:    If we are optimizing to use the global pointer, create a temporary
                   3051:    file to hold all of the text stuff, and write it out to the end.
                   3052:    This is needed because the MIPS assembler is evidently one pass,
                   3053:    and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata
                   3054:    declaration when the code is processed, it generates a two
                   3055:    instruction sequence.  */
                   3056: 
                   3057: void
                   3058: mips_asm_file_start (stream)
                   3059:      FILE *stream;
                   3060: {
                   3061:   ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
                   3062: 
                   3063:   /* Versions of the MIPS assembler before 2.20 generate errors
                   3064:      if a branch inside of a .set noreorder section jumps to a
                   3065:      label outside of the .set noreorder section.  Revision 2.20
                   3066:      just set nobopt silently rather than fixing the bug.  */
                   3067: 
                   3068:   if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
                   3069:     fprintf (stream, "\t.set\tnobopt\n");
                   3070: 
                   3071:   /* Generate the pseudo ops that the Pyramid based System V.4 wants.  */
                   3072:   if (TARGET_ABICALLS)
                   3073:     fprintf (stream, "\t.abicalls\n");
                   3074: 
                   3075:   /* put gcc_compiled. in data, not text */
                   3076:   data_section ();
                   3077: 
                   3078:   if (TARGET_GP_OPT)
                   3079:     {
                   3080:       asm_out_data_file = stream;
                   3081:       asm_out_text_file = make_temp_file ();
                   3082:     }
                   3083:   else
                   3084:     asm_out_data_file = asm_out_text_file = stream;
                   3085: 
                   3086:   if (TARGET_NAME_REGS)
                   3087:     fprintf (asm_out_file, "#include <regdef.h>\n");
                   3088: 
                   3089:   print_options (stream);
                   3090: }
                   3091: 
                   3092: 
                   3093: /* If we are optimizing the global pointer, emit the text section now
                   3094:    and any small externs which did not have .comm, etc that are
                   3095:    needed.  Also, give a warning if the data area is more than 32K and
                   3096:    -pic because 3 instructions are needed to reference the data
                   3097:    pointers.  */
                   3098: 
                   3099: void
                   3100: mips_asm_file_end (file)
                   3101:      FILE *file;
                   3102: {
                   3103:   char buffer[8192];
                   3104:   tree name_tree;
                   3105:   struct extern_list *p;
                   3106:   int len;
                   3107: 
                   3108:   if (TARGET_GP_OPT)
                   3109:     {
                   3110:       if (extern_head)
                   3111:        fputs ("\n", file);
                   3112: 
                   3113:       for (p = extern_head; p != 0; p = p->next)
                   3114:        {
                   3115:          name_tree = get_identifier (p->name);
1.1.1.2 ! root     3116: 
        !          3117:          /* Positively ensure only one .extern for any given symbol.  */
        !          3118:          if (! TREE_ASM_WRITTEN (name_tree))
1.1       root     3119:            {
1.1.1.2 ! root     3120:              TREE_ASM_WRITTEN (name_tree) = 1;
1.1       root     3121:              fputs ("\t.extern\t", file);
                   3122:              assemble_name (file, p->name);
                   3123:              fprintf (file, ", %d\n", p->size);
                   3124:            }
                   3125:        }
                   3126: 
                   3127:       fprintf (file, "\n\t.text\n");
                   3128:       rewind (asm_out_text_file);
                   3129:       if (ferror (asm_out_text_file))
                   3130:        fatal_io_error (temp_filename);
                   3131: 
                   3132:       while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
                   3133:        if (fwrite (buffer, 1, len, file) != len)
                   3134:          pfatal_with_name (asm_file_name);
                   3135: 
                   3136:       if (len < 0)
                   3137:        pfatal_with_name (temp_filename);
                   3138: 
                   3139:       if (fclose (asm_out_text_file) != 0)
                   3140:        pfatal_with_name (temp_filename);
                   3141:     }
                   3142: }
                   3143: 
                   3144: 
1.1.1.2 ! root     3145: /* Emit either a label, .comm, or .lcomm directive, and mark
        !          3146:    that the symbol is used, so that we don't emit an .extern
        !          3147:    for it in mips_asm_file_end.  */
        !          3148: 
        !          3149: void
        !          3150: mips_declare_object (stream, name, init_string, final_string, size)
        !          3151:      FILE *stream;
        !          3152:      char *name;
        !          3153:      char *init_string;
        !          3154:      char *final_string;
        !          3155:      int size;
        !          3156: {
        !          3157:   fputs (init_string, stream);         /* "", "\t.comm\t", or "\t.lcomm\t" */
        !          3158:   assemble_name (stream, name);
        !          3159:   fprintf (stream, final_string, size);        /* ":\n", ",%u\n", ",%u\n" */
        !          3160: 
        !          3161:   if (TARGET_GP_OPT && mips_section_threshold != 0)
        !          3162:     {
        !          3163:       tree name_tree = get_identifier (name);
        !          3164:       TREE_ASM_WRITTEN (name_tree) = 1;
        !          3165:     }
        !          3166: }
        !          3167: 
        !          3168: 
1.1       root     3169: /* Return the bytes needed to compute the frame pointer from the current
                   3170:    stack pointer.
                   3171: 
                   3172:    Mips stack frames look like:
                   3173: 
                   3174:              Before call                       After call
                   3175:         +-----------------------+      +-----------------------+
                   3176:    high |                      |       |                       |
                   3177:    mem. |                      |       |                       |
                   3178:         |  caller's temps.     |       |  caller's temps.      |
                   3179:        |                       |       |                       |
                   3180:         +-----------------------+      +-----------------------+
                   3181:        |                       |       |                       |
                   3182:         |  arguments on stack.  |      |  arguments on stack.  |
                   3183:        |                       |       |                       |
                   3184:         +-----------------------+      +-----------------------+
                   3185:        |  4 words to save      |       |  4 words to save      |
                   3186:        |  arguments passed     |       |  arguments passed     |
                   3187:        |  in registers, even   |       |  in registers, even   |
                   3188:     SP->|  if not passed.       |   FP->|  if not passed.      |
                   3189:        +-----------------------+       +-----------------------+
                   3190:                                        |                       |
                   3191:                                        |  GP save for V.4 abi  |
                   3192:                                        |                       |
                   3193:                                        +-----------------------+
                   3194:                                        |                       |
                   3195:                                        |  local variables      |
                   3196:                                        |                       |
                   3197:                                        +-----------------------+
                   3198:                                        |                       |
                   3199:                                         |  fp register save     |
                   3200:                                        |                       |
                   3201:                                        +-----------------------+
                   3202:                                        |                       |
                   3203:                                         |  gp register save     |
                   3204:                                         |                      |
                   3205:                                        +-----------------------+
                   3206:                                        |                       |
                   3207:                                         |  alloca allocations   |
                   3208:                                        |                       |
                   3209:                                        +-----------------------+
                   3210:                                        |                       |
                   3211:                                         |  arguments on stack   |
                   3212:                                        |                       |
                   3213:                                        +-----------------------+
                   3214:                                         |  4 words to save      |
                   3215:                                        |  arguments passed     |
                   3216:                                         |  in registers, even   |
                   3217:    low                              SP->|  if not passed.       |
                   3218:    memory                              +-----------------------+
                   3219: 
                   3220: */
                   3221: 
                   3222: unsigned long
                   3223: compute_frame_size (size)
                   3224:      int size;                 /* # of var. bytes allocated */
                   3225: {
                   3226:   int regno;
                   3227:   unsigned long total_size;    /* # bytes that the entire frame takes up */
                   3228:   unsigned long var_size;      /* # bytes that variables take up */
                   3229:   unsigned long args_size;     /* # bytes that outgoing arguments take up */
                   3230:   unsigned long extra_size;    /* # extra bytes */
                   3231:   unsigned int  gp_reg_rounded;        /* # bytes needed to store gp after rounding */
                   3232:   unsigned int  gp_reg_size;   /* # bytes needed to store gp regs */
                   3233:   unsigned int  fp_reg_size;   /* # bytes needed to store fp regs */
                   3234:   unsigned long mask;          /* mask of saved gp registers */
                   3235:   unsigned long fmask;         /* mask of saved fp registers */
                   3236:   int fp_inc;                  /* 1 or 2 depending on the size of fp regs */
                   3237:   int fp_bits;                 /* bitmask to use for each fp register */
                   3238: 
                   3239:   extra_size    = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)
                   3240:                                     -STARTING_FRAME_OFFSET);
                   3241: 
                   3242:   var_size      = MIPS_STACK_ALIGN (size);
                   3243:   args_size     = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
                   3244:   total_size    = var_size + args_size + extra_size;
                   3245:   gp_reg_size   = 0;
                   3246:   fp_reg_size   = 0;
                   3247:   mask          = 0;
                   3248:   fmask                 = 0;
                   3249: 
                   3250:   /* Calculate space needed for gp registers.  */
                   3251:   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
                   3252:     {
                   3253:       if (MUST_SAVE_REGISTER (regno))
                   3254:        {
                   3255:          gp_reg_size += UNITS_PER_WORD;
                   3256:          mask |= 1 << (regno - GP_REG_FIRST);
                   3257:        }
                   3258:     }
                   3259: 
                   3260:   /* Calculate space needed for fp registers.  */
                   3261:   if (TARGET_FLOAT64)
                   3262:     {
                   3263:       fp_inc = 1;
                   3264:       fp_bits = 1;
                   3265:     }
                   3266:   else
                   3267:     {
                   3268:       fp_inc = 2;
                   3269:       fp_bits = 3;
                   3270:     }
                   3271: 
                   3272:   for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc)
                   3273:     {
                   3274:       if (regs_ever_live[regno] && !call_used_regs[regno])
                   3275:        {
                   3276:          fp_reg_size += 2*UNITS_PER_WORD;
                   3277:          fmask |= fp_bits << (regno - FP_REG_FIRST);
                   3278:        }
                   3279:     }
                   3280: 
                   3281:   gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
                   3282:   total_size += gp_reg_rounded + fp_reg_size;
                   3283: 
                   3284:   if (total_size == extra_size)
                   3285:     total_size = extra_size = 0;
                   3286: 
                   3287:   /* Save other computed information.  */
                   3288:   current_frame_info.total_size  = total_size;
                   3289:   current_frame_info.var_size    = var_size;
                   3290:   current_frame_info.args_size   = args_size;
                   3291:   current_frame_info.extra_size  = extra_size;
                   3292:   current_frame_info.gp_reg_size = gp_reg_size;
                   3293:   current_frame_info.fp_reg_size = fp_reg_size;
                   3294:   current_frame_info.mask       = mask;
                   3295:   current_frame_info.fmask      = fmask;
                   3296:   current_frame_info.initialized = reload_completed;
                   3297: 
                   3298:   if (mask)
                   3299:     {
                   3300:       unsigned long offset = args_size + gp_reg_size - UNITS_PER_WORD;
                   3301:       current_frame_info.gp_sp_offset = offset;
                   3302:       current_frame_info.gp_save_offset = offset - total_size;
                   3303:     }
                   3304: 
                   3305:   if (fmask)
                   3306:     {
                   3307:       unsigned long offset = args_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
                   3308:       current_frame_info.fp_sp_offset = offset;
                   3309:       current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
                   3310:     }
                   3311: 
                   3312:   /* Ok, we're done.  */
                   3313:   return total_size;
                   3314: }
                   3315: 
                   3316: 
                   3317: /* Common code to save/restore registers.  */
                   3318: 
                   3319: void
                   3320: save_restore (file, gp_op, gp_2word_op, fp_op)
                   3321:      FILE *file;               /* stream to write to */
                   3322:      char *gp_op;              /* operation to do on gp registers */
                   3323:      char *gp_2word_op;                /* 2 word op to do on gp registers */
                   3324:      char *fp_op;              /* operation to do on fp registers */
                   3325: {
                   3326:   int regno;
                   3327:   unsigned long mask     = current_frame_info.mask;
                   3328:   unsigned long fmask    = current_frame_info.fmask;
                   3329:   unsigned long gp_offset;
                   3330:   unsigned long fp_offset;
                   3331:   unsigned long max_offset;
                   3332:   char *base_reg;
                   3333: 
                   3334:   if (mask == 0 && fmask == 0)
                   3335:     return;
                   3336: 
                   3337:   base_reg   = reg_names[STACK_POINTER_REGNUM];
                   3338:   gp_offset  = current_frame_info.gp_sp_offset;
                   3339:   fp_offset  = current_frame_info.fp_sp_offset;
                   3340:   max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset;
                   3341: 
                   3342:   /* Deal with calling functions with a large structure.  */
                   3343:   if (max_offset >= 32768)
                   3344:     {
                   3345:       char *temp = reg_names[MIPS_TEMP2_REGNUM];
                   3346:       fprintf (file, "\tli\t%s,%ld\n", temp, max_offset);
                   3347:       fprintf (file, "\taddu\t%s,%s,%s\n", temp, temp, base_reg);
                   3348:       base_reg = temp;
                   3349:       gp_offset = max_offset - gp_offset;
                   3350:       fp_offset = max_offset - fp_offset;
                   3351:     }
                   3352: 
                   3353:   /* Save registers starting from high to low.  The debuggers prefer
                   3354:      at least the return register be stored at func+4, and also it
                   3355:      allows us not to need a nop in the epilog if at least one
                   3356:      register is reloaded in addition to return address.  */
                   3357: 
                   3358:   if (mask || frame_pointer_needed)
                   3359:     {
                   3360:       for  (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
                   3361:        {
                   3362:          if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
                   3363:              || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
                   3364:            {
                   3365:              fprintf (file, "\t%s\t%s,%d(%s)\n",
                   3366:                       gp_op, reg_names[regno],
                   3367:                       gp_offset, base_reg);
                   3368: 
                   3369:              gp_offset -= UNITS_PER_WORD;
                   3370:            }
                   3371:        }
                   3372:     }
                   3373: 
                   3374:   if (fmask)
                   3375:     {
                   3376:       int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
                   3377: 
                   3378:       for  (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
                   3379:        {
                   3380:          if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
                   3381:            {
                   3382:              fprintf (file, "\t%s\t%s,%d(%s)\n",
                   3383:                       fp_op, reg_names[regno], fp_offset, base_reg);
                   3384: 
                   3385:              fp_offset -= 2*UNITS_PER_WORD;
                   3386:            }
                   3387:        }
                   3388:     }
                   3389: }
                   3390: 
                   3391: 
                   3392: /* Set up the stack and frame (if desired) for the function.  */
                   3393: 
                   3394: void
                   3395: function_prologue (file, size)
                   3396:      FILE *file;
                   3397:      int size;
                   3398: {
                   3399:   int regno;
                   3400:   int tsize;
                   3401:   char *sp_str = reg_names[STACK_POINTER_REGNUM];
                   3402:   char *fp_str = (!frame_pointer_needed)
                   3403:                        ? sp_str
                   3404:                        : reg_names[FRAME_POINTER_REGNUM];
                   3405:   tree fndecl = current_function_decl; /* current... is tooo long */
                   3406:   tree fntype = TREE_TYPE (fndecl);
                   3407:   tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
                   3408:                        ? DECL_ARGUMENTS (fndecl)
                   3409:                        : 0;
                   3410:   tree next_arg;
                   3411:   tree cur_arg;
                   3412:   char *arg_name = (char *)0;
                   3413:   CUMULATIVE_ARGS args_so_far;
                   3414: 
                   3415:   ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
                   3416:   ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
                   3417: 
                   3418:   inside_function = 1;
                   3419:   fputs ("\t.ent\t", file);
                   3420:   assemble_name (file, current_function_name);
                   3421:   fputs ("\n", file);
                   3422:   assemble_name (file, current_function_name);
                   3423:   fputs (":\n", file);
                   3424: 
                   3425:   if (TARGET_ABICALLS)
                   3426:     fprintf (file,
                   3427:             "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
                   3428:             reg_names[ GP_REG_FIRST + 25 ]);
                   3429: 
                   3430:   /* Determine the last argument, and get its name.  */
                   3431:   for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg)
                   3432:     {
                   3433:       next_arg = TREE_CHAIN (cur_arg);
                   3434:       if (next_arg == (tree)0)
                   3435:        {
                   3436:          if (DECL_NAME (cur_arg))
                   3437:            arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
                   3438: 
                   3439:          break;
                   3440:        }
                   3441:     }
                   3442: 
                   3443:   /* If this function is a varargs function, store any registers that
                   3444:      would normally hold arguments ($4 - $7) on the stack.  */
                   3445:   if ((TYPE_ARG_TYPES (fntype) != 0
                   3446:        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
                   3447:       || (arg_name
                   3448:          && (strcmp (arg_name, "__builtin_va_alist") == 0
                   3449:              || strcmp (arg_name, "va_alist") == 0)))
                   3450:     {
                   3451:       tree parm;
                   3452: 
                   3453:       regno = GP_ARG_FIRST;
                   3454:       INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0);
                   3455: 
                   3456:       for (parm = fnargs; (parm && (regno <= GP_ARG_LAST)); parm = TREE_CHAIN (parm))
                   3457:        {
                   3458:          rtx entry_parm;
                   3459:          enum machine_mode passed_mode;
                   3460:          tree type;
                   3461: 
                   3462:          type = DECL_ARG_TYPE (parm);
                   3463:          passed_mode = TYPE_MODE (type);
                   3464:          entry_parm = FUNCTION_ARG (args_so_far, passed_mode,
                   3465:                                     DECL_ARG_TYPE (parm), 1);
                   3466: 
                   3467:          if (entry_parm)
                   3468:            {
                   3469:              int words;
                   3470: 
                   3471:              /* passed in a register, so will get homed automatically */
                   3472:              if (GET_MODE (entry_parm) == BLKmode)
                   3473:                words = (int_size_in_bytes (type) + 3) / 4;
                   3474:              else
                   3475:                words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
                   3476: 
                   3477:              regno = REGNO (entry_parm) + words - 1;
                   3478:            }
                   3479:          else
                   3480:            {
                   3481:              regno = GP_ARG_LAST+1;
                   3482:              break;
                   3483:            }
                   3484: 
                   3485:          FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
                   3486:                                DECL_ARG_TYPE (parm), 1);
                   3487:        }
                   3488: 
                   3489:       if (regno <= GP_ARG_LAST && (regno & 1) != 0)
                   3490:        {
                   3491:          fprintf (file, "\tsw\t%s,%d(%s)\t\t# varargs home register\n",
                   3492:                   reg_names[regno], (regno - 4) * 4, sp_str);
                   3493:          regno++;
                   3494:        }
                   3495: 
                   3496:       for (; regno <= GP_ARG_LAST; regno += 2)
                   3497:        {
                   3498:          fprintf (file, "\tsd\t%s,%d(%s)\t\t# varargs home register\n",
                   3499:                   reg_names[regno], (regno - 4) * 4, sp_str);
                   3500:        }
                   3501:     }
                   3502: 
                   3503:   size = MIPS_STACK_ALIGN (size);
                   3504:   tsize = (!current_frame_info.initialized)
                   3505:                ? compute_frame_size (size)
                   3506:                : current_frame_info.total_size;
                   3507: 
                   3508:   if (tsize > 0)
                   3509:     {
                   3510:       if (tsize <= 32767)
                   3511:        fprintf (file,
                   3512:                 "\tsubu\t%s,%s,%d\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n",
                   3513:                 sp_str, sp_str, tsize, current_frame_info.var_size,
                   3514:                 current_frame_info.gp_reg_size / 4,
                   3515:                 current_frame_info.fp_reg_size / 8,
                   3516:                 current_function_outgoing_args_size,
                   3517:                 current_frame_info.extra_size);
                   3518:       else
                   3519:        fprintf (file,
                   3520:                 "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t\t# vars= %d, regs= %d/%d, args = %d, sfo= %d\n",
                   3521:                 reg_names[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str,
                   3522:                 reg_names[MIPS_TEMP1_REGNUM], current_frame_info.var_size,
                   3523:                 current_frame_info.gp_reg_size / 4,
                   3524:                 current_frame_info.fp_reg_size / 8,
                   3525:                 current_function_outgoing_args_size,
                   3526:                 current_frame_info.extra_size);
                   3527:     }
                   3528: 
                   3529:   if (TARGET_ABICALLS)
                   3530:     fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET);
                   3531: 
                   3532:   fprintf (file, "\t.frame\t%s,%d,%s\n\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n",
                   3533:           fp_str,
                   3534:           (frame_pointer_needed) ? 0 : tsize,
                   3535:           reg_names[31 + GP_REG_FIRST],
                   3536:           current_frame_info.mask,
                   3537:           current_frame_info.gp_save_offset,
                   3538:           current_frame_info.fmask,
                   3539:           current_frame_info.fp_save_offset);
                   3540: 
                   3541:   save_restore (file, "sw", "sd", "s.d");
                   3542: 
                   3543:   if (frame_pointer_needed)
                   3544:     {
                   3545:       if (tsize <= 32767)
                   3546:        fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize);
                   3547: 
                   3548:       else
                   3549:        fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str,
                   3550:                 reg_names[MIPS_TEMP1_REGNUM]);
                   3551:     }
                   3552: }
                   3553: 
                   3554: 
                   3555: /* Do any necessary cleanup after a function to restore stack, frame, and regs. */
                   3556: 
                   3557: void
                   3558: function_epilogue (file, size)
                   3559:      FILE *file;
                   3560:      int size;
                   3561: {
                   3562:   int tsize;
                   3563:   char *sp_str = reg_names[STACK_POINTER_REGNUM];
                   3564:   char *t1_str = reg_names[MIPS_TEMP1_REGNUM];
                   3565:   rtx epilogue_delay = current_function_epilogue_delay_list;
                   3566:   int noreorder = !TARGET_MIPS_AS || (epilogue_delay != 0);
                   3567:   int noepilogue = FALSE;
                   3568:   int load_nop = FALSE;
                   3569:   int load_only_r31;
                   3570: 
                   3571:   /* The epilogue does not depend on any registers, but the stack
                   3572:      registers, so we assume that if we have 1 pending nop, it can be
                   3573:      ignored, and 2 it must be filled (2 nops occur for integer
                   3574:      multiply and divide).  */
                   3575: 
                   3576:   if (dslots_number_nops > 0)
                   3577:     {
                   3578:       if (dslots_number_nops == 1)
                   3579:        {
                   3580:          dslots_number_nops = 0;
                   3581:          dslots_load_filled++;
                   3582:        }
                   3583:       else
                   3584:        {
                   3585:          while (--dslots_number_nops > 0)
                   3586:            fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file);
                   3587:        }
                   3588: 
                   3589:       if (set_noreorder > 0 && --set_noreorder == 0)
                   3590:        fputs ("\t.set\treorder\n", file);
                   3591:     }
                   3592: 
                   3593:   if (set_noat != 0)
                   3594:     {
                   3595:       set_noat = 0;
                   3596:       fputs ("\t.set\tat\n", file);
                   3597:       error ("internal gcc error: .set noat left on in epilogue");
                   3598:     }
                   3599: 
                   3600:   if (set_nomacro != 0)
                   3601:     {
                   3602:       set_nomacro = 0;
                   3603:       fputs ("\t.set\tmacro\n", file);
                   3604:       error ("internal gcc error: .set nomacro left on in epilogue");
                   3605:     }
                   3606: 
                   3607:   if (set_noreorder != 0)
                   3608:     {
                   3609:       set_noreorder = 0;
                   3610:       fputs ("\t.set\treorder\n", file);
                   3611:       error ("internal gcc error: .set noreorder left on in epilogue");
                   3612:     }
                   3613: 
                   3614:   if (set_volatile != 0)
                   3615:     {
                   3616:       set_volatile = 0;
                   3617:       fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#");
                   3618:       error ("internal gcc error: .set volatile left on in epilogue");
                   3619:     }
                   3620: 
                   3621:   size = MIPS_STACK_ALIGN (size);
                   3622:   tsize = (!current_frame_info.initialized)
                   3623:                ? compute_frame_size (size)
                   3624:                : current_frame_info.total_size;
                   3625: 
                   3626:   if (tsize == 0 && epilogue_delay == 0)
                   3627:     {
                   3628:       rtx insn = get_last_insn ();
                   3629: 
                   3630:       /* If the last insn was a BARRIER, we don't have to write any code
                   3631:         because a jump (aka return) was put there.  */
                   3632:       if (GET_CODE (insn) == NOTE)
                   3633:        insn = prev_nonnote_insn (insn);
                   3634:       if (insn && GET_CODE (insn) == BARRIER)
                   3635:        noepilogue = TRUE;
                   3636: 
                   3637:       noreorder = FALSE;
                   3638:     }
                   3639: 
                   3640:   if (!noepilogue)
                   3641:     {
                   3642:       /* In the reload sequence, we don't need to fill the load delay
                   3643:         slots for most of the loads, also see if we can fill the final
                   3644:         delay slot if not otherwise filled by the reload sequence.  */
                   3645: 
                   3646:       if (noreorder)
                   3647:        fprintf (file, "\t.set\tnoreorder\n");
                   3648: 
                   3649:       if (tsize > 32767)
                   3650:        fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
                   3651: 
                   3652:       if (frame_pointer_needed)
                   3653:        {
                   3654:          char *fp_str = reg_names[FRAME_POINTER_REGNUM];
                   3655:          if (tsize > 32767)
                   3656:            fprintf (file,"\tsubu\t%s,%s,%s\t\t# sp not trusted  here\n",
                   3657:                     sp_str, fp_str, t1_str);
                   3658:          else
                   3659:            fprintf (file,"\tsubu\t%s,%s,%d\t\t# sp not trusted  here\n",
                   3660:                     sp_str, fp_str, tsize);
                   3661:        }
                   3662: 
                   3663:       save_restore (file, "lw", "ld", "l.d");
                   3664: 
                   3665:       load_only_r31 = (current_frame_info.mask == (1 << 31)
                   3666:                       && current_frame_info.fmask == 0);
                   3667: 
                   3668:       if (noreorder)
                   3669:        {
                   3670:          /* If the only register saved is the return address, we need a
                   3671:             nop, unless we have an instruction to put into it.  Otherwise
                   3672:             we don't since reloading multiple registers doesn't reference
                   3673:             the register being loaded.  */
                   3674: 
                   3675:          if (load_only_r31)
                   3676:            {
                   3677:              if (epilogue_delay)
                   3678:                  final_scan_insn (XEXP (epilogue_delay, 0),
                   3679:                                   file,
                   3680:                                   1,                   /* optimize */
                   3681:                                   -2,                  /* prescan */
                   3682:                                   1);                  /* nopeepholes */
                   3683:              else
                   3684:                {
                   3685:                  fprintf (file, "\tnop\n");
                   3686:                  load_nop = TRUE;
                   3687:                }
                   3688:            }
                   3689: 
                   3690:          fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
                   3691: 
                   3692:          if (tsize > 32767)
                   3693:            fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
                   3694: 
                   3695:          else if (tsize > 0)
                   3696:            fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
                   3697: 
                   3698:          else if (!load_only_r31 && epilogue_delay != 0)
                   3699:            final_scan_insn (XEXP (epilogue_delay, 0),
                   3700:                             file,
                   3701:                             1,                 /* optimize */
                   3702:                             -2,                /* prescan */
                   3703:                             1);                /* nopeepholes */
                   3704: 
                   3705:          fprintf (file, "\t.set\treorder\n");
                   3706:        }
                   3707: 
                   3708:       else
                   3709:        {
                   3710:          if (tsize > 32767)
                   3711:            fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
                   3712: 
                   3713:          else if (tsize > 0)
                   3714:            fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
                   3715: 
                   3716:          fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
                   3717:        }
                   3718:     }
                   3719: 
                   3720:   fputs ("\t.end\t", file);
                   3721:   assemble_name (file, current_function_name);
                   3722:   fputs ("\n", file);
                   3723: 
                   3724:   if (TARGET_STATS)
                   3725:     {
                   3726:       int num_gp_regs = current_frame_info.gp_reg_size / 4;
                   3727:       int num_fp_regs = current_frame_info.fp_reg_size / 8;
                   3728:       int num_regs    = num_gp_regs + num_fp_regs;
                   3729: 
                   3730:       dslots_load_total += num_regs;
                   3731: 
                   3732:       if (!noepilogue)
                   3733:        dslots_jump_total++;
                   3734: 
                   3735:       if (noreorder)
                   3736:        {
                   3737:          dslots_load_filled += num_regs;
                   3738: 
                   3739:          /* If the only register saved is the return register, we
                   3740:             can't fill this register's delay slot.  */
                   3741: 
                   3742:          if (load_only_r31 && epilogue_delay == 0)
                   3743:            dslots_load_filled--;
                   3744: 
                   3745:          if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0))
                   3746:            dslots_jump_filled++;
                   3747:        }
                   3748: 
                   3749:       fprintf (stderr,
                   3750:               "%-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",
                   3751:               current_function_name,
                   3752:               (frame_pointer_needed) ? 'y' : 'n',
                   3753:               ((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y',
                   3754:               (current_function_calls_alloca) ? 'y' : 'n',
                   3755:               (current_function_calls_setjmp) ? 'y' : 'n',
                   3756:               (long)current_frame_info.total_size,
                   3757:               (long)current_function_outgoing_args_size,
                   3758:               num_gp_regs, num_fp_regs,
                   3759:               dslots_load_total, dslots_load_filled,
                   3760:               dslots_jump_total, dslots_jump_filled,
                   3761:               num_refs[0], num_refs[1], num_refs[2]);
                   3762:     }
                   3763: 
                   3764:   /* Reset state info for each function.  */
                   3765:   inside_function    = FALSE;
                   3766:   ignore_line_number = FALSE;
                   3767:   dslots_load_total  = 0;
                   3768:   dslots_jump_total  = 0;
                   3769:   dslots_load_filled = 0;
                   3770:   dslots_jump_filled = 0;
                   3771:   num_refs[0]       = 0;
                   3772:   num_refs[1]       = 0;
                   3773:   num_refs[2]       = 0;
                   3774:   mips_load_reg      = (rtx)0;
                   3775:   mips_load_reg2     = (rtx)0;
                   3776:   number_functions_processed++;
                   3777:   current_frame_info = zero_frame_info;
                   3778: 
                   3779:   /* Restore the output file if optimizing the GP (optimizing the GP causes
                   3780:      the text to be diverted to a tempfile, so that data decls come before
                   3781:      references to the data).  */
                   3782: 
                   3783:   if (TARGET_GP_OPT)
                   3784:     asm_out_file = asm_out_data_file;
                   3785: }
                   3786: 
                   3787: 
                   3788: /* Define the number of delay slots needed for the function epilogue.
                   3789: 
                   3790:    On the mips, we need a slot if either no stack has been allocated,
                   3791:    or the only register saved is the return register.  */
                   3792: 
                   3793: int
                   3794: mips_epilogue_delay_slots ()
                   3795: {
                   3796:   if (!current_frame_info.initialized)
                   3797:     (void) compute_frame_size (get_frame_size ());
                   3798: 
                   3799:   if (current_frame_info.total_size == 0)
                   3800:     return 1;
                   3801: 
                   3802:   if (current_frame_info.mask == (1 << 31) && current_frame_info.fmask == 0)
                   3803:     return 1;
                   3804: 
                   3805:   return 0;
                   3806: }
                   3807: 
                   3808: 
                   3809: /* Return true if this function is known to have a null epilogue.
                   3810:    This allows the optimizer to omit jumps to jumps if no stack
                   3811:    was created.  */
                   3812: 
                   3813: int
                   3814: null_epilogue ()
                   3815: {
                   3816:   if (!reload_completed)
                   3817:     return 0;
                   3818: 
                   3819:   if (current_frame_info.initialized)
                   3820:     return current_frame_info.total_size == 0;
                   3821: 
                   3822:   return (compute_frame_size (get_frame_size ())) == 0;
                   3823: }

unix.superglobalmegacorp.com

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