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

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

unix.superglobalmegacorp.com

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