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

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

unix.superglobalmegacorp.com

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