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

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

unix.superglobalmegacorp.com

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