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

unix.superglobalmegacorp.com

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