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

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

unix.superglobalmegacorp.com

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