OSDN Git Service

* function.h (struct function): Add profile.
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index c09a246..83df738 100644 (file)
@@ -40,7 +40,6 @@ Boston, MA 02111-1307, USA.  */
 #include "recog.h"
 #include "toplev.h"
 #include "output.h"
-
 #include "tree.h"
 #include "function.h"
 #include "expr.h"
@@ -50,9 +49,15 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "ggc.h"
 #include "gstab.h"
+#include "hashtab.h"
+#include "debug.h"
 #include "target.h"
 #include "target-def.h"
 
+#ifdef HALF_PIC_DEBUG
+#include "halfpic.h"
+#endif
+
 #ifdef __GNU_STAB__
 #define STAB_CODE_TYPE enum __stab_debug_code
 #else
@@ -63,7 +68,7 @@ extern tree   lookup_name PARAMS ((tree));
 
 /* Enumeration for all of the relational tests, so that we can build
    arrays indexed by the test type, and not worry about the order
-   of EQ, NE, etc. */
+   of EQ, NE, etc.  */
 
 enum internal_test {
     ITEST_EQ,
@@ -90,7 +95,13 @@ static void block_move_loop                  PARAMS ((rtx, rtx,
                                                         int,
                                                         rtx, rtx));
 static void block_move_call                    PARAMS ((rtx, rtx, rtx));
-static FILE *mips_make_temp_file               PARAMS ((void));
+static rtx mips_add_large_offset_to_sp         PARAMS ((HOST_WIDE_INT,
+                                                        FILE *));
+static void mips_annotate_frame_insn           PARAMS ((rtx, rtx));
+static rtx mips_frame_set                      PARAMS ((enum machine_mode,
+                                                        int, int));
+static void mips_emit_frame_related_store      PARAMS ((rtx, rtx,
+                                                        HOST_WIDE_INT));
 static void save_restore_insns                 PARAMS ((int, rtx,
                                                        long, FILE *));
 static void mips16_output_gp_offset            PARAMS ((FILE *, rtx));
@@ -107,9 +118,22 @@ static void abort_with_insn                        PARAMS ((rtx, const char *))
   ATTRIBUTE_NORETURN;
 static int symbolic_expression_p                PARAMS ((rtx));
 static void mips_add_gc_roots                   PARAMS ((void));
+static bool mips_assemble_integer        PARAMS ((rtx, unsigned int, int));
 static void mips_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
 static void mips_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
 static enum processor_type mips_parse_cpu       PARAMS ((const char *));
+static void copy_file_data                     PARAMS ((FILE *, FILE *));
+#ifdef TARGET_IRIX6
+static void iris6_asm_named_section_1          PARAMS ((const char *,
+                                                        unsigned int,
+                                                        unsigned int));
+static void iris6_asm_named_section            PARAMS ((const char *,
+                                                        unsigned int));
+static int iris_section_align_entry_eq         PARAMS ((const PTR, const PTR));
+static hashval_t iris_section_align_entry_hash PARAMS ((const PTR));
+static int iris6_section_align_1               PARAMS ((void **, void *));
+#endif
+static int mips_adjust_cost                    PARAMS ((rtx, rtx, rtx, int));
 
 /* Global variables for machine-dependent things.  */
 
@@ -126,7 +150,7 @@ int num_source_filenames = 0;
    start and end boundaries).  */
 int sdb_label_count = 0;
 
-/* Next label # for each statement for Silicon Graphics IRIS systems. */
+/* Next label # for each statement for Silicon Graphics IRIS systems.  */
 int sym_lineno = 0;
 
 /* Non-zero if inside of a function, because the stupid MIPS asm can't
@@ -202,17 +226,11 @@ enum processor_type mips_arch;
 /* The target cpu for optimization and scheduling.  */
 enum processor_type mips_tune;
 
-/* Historical option for code generation and scheduling.  */
-enum processor_type mips_cpu;
-
 /* which instruction set architecture to use.  */
 int mips_isa;
 
-#ifdef MIPS_ABI_DEFAULT
-/* Which ABI to use.  This is defined to a constant in mips.h if the target
-   doesn't support multiple ABIs.  */
+/* which abi to use.  */
 int mips_abi;
-#endif
 
 /* Strings to hold which cpu and instruction set architecture to use.  */
 const char *mips_cpu_string;   /* for -mcpu=<xxx> */
@@ -232,7 +250,7 @@ const char *mips_no_mips16_string;
 
 /* This is only used to determine if an type size setting option was
    explicitly specified (-mlong64, -mint64, -mlong32).  The specs
-   set this option if such an option is used. */
+   set this option if such an option is used.  */
 const char *mips_explicit_type_size_string;
 
 /* Whether we are generating mips16 hard float code.  In mips16 mode
@@ -246,6 +264,8 @@ int mips16_hard_float;
    avoid using up another bit in target_flags.  */
 const char *mips_entry_string;
 
+const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
+
 /* Whether we should entry and exit pseudo-ops in mips16 mode.  */
 int mips_entry;
 
@@ -273,10 +293,6 @@ struct mips_frame_info current_frame_info;
 /* Zero structure to initialize current_frame_info.  */
 struct mips_frame_info zero_frame_info;
 
-/* Temporary filename used to buffer .text until end of program
-   for -mgpopt.  */
-static char *temp_filename;
-
 /* Pseudo-reg holding the address of the current function when
    generating embedded PIC code.  Created by LEGITIMIZE_ADDRESS, used
    by mips_finalize_pic if it was created.  */
@@ -333,7 +349,7 @@ char mips_reg_names[][8] =
 /* Mips software names for the registers, used to overwrite the
    mips_reg_names array.  */
 
-char mips_sw_reg_names[][8] =
+static const char mips_sw_reg_names[][8] =
 {
   "$zero","$at",  "$v0",  "$v1",  "$a0",  "$a1",  "$a2",  "$a3",
   "$t0",  "$t1",  "$t2",  "$t3",  "$t4",  "$t5",  "$t6",  "$t7",
@@ -348,7 +364,7 @@ char mips_sw_reg_names[][8] =
 };
 
 /* Map hard register number to register class */
-enum reg_class mips_regno_to_class[] =
+const enum reg_class mips_regno_to_class[] =
 {
   GR_REGS,     GR_REGS,        M16_NA_REGS,    M16_NA_REGS,
   M16_REGS,    M16_REGS,       M16_REGS,       M16_REGS,
@@ -441,11 +457,28 @@ enum reg_class mips_char_to_class[256] =
 };
 \f
 /* Initialize the GCC target structure.  */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER mips_assemble_integer
+
+#if TARGET_IRIX5 && !TARGET_IRIX6
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.half\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.word\t"
+#endif
+
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE mips_output_function_prologue
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE mips_output_function_epilogue
 
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST mips_adjust_cost
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Return truth value of whether OP can be used as an operands
@@ -494,7 +527,7 @@ arith32_operand (op, mode)
   return register_operand (op, mode);
 }
 
-/* Return truth value of whether OP is a integer which fits in 16 bits  */
+/* Return truth value of whether OP is an integer which fits in 16 bits.  */
 
 int
 small_int (op, mode)
@@ -567,7 +600,7 @@ reg_or_0_operand (op, mode)
 }
 
 /* Return truth value of whether OP is a register or the constant 0,
-   even in mips16 mode. */
+   even in mips16 mode.  */
 
 int
 true_reg_or_0_operand (op, mode)
@@ -782,7 +815,7 @@ simple_memory_operand (op, mode)
        if (GET_CODE (op) != SYMBOL_REF)
          return 0;
 
-       /* let's be paranoid.... */
+       /* let's be paranoid....  */
        if (! SMALL_INT (offset))
          return 0;
       }
@@ -887,7 +920,7 @@ double_memory_operand (op, mode)
            return 1;
 
          /* Similarly, we accept a case where the memory address is
-             itself on the stack, and will be reloaded. */
+             itself on the stack, and will be reloaded.  */
          if (GET_CODE (addr) == MEM)
            {
              rtx maddr;
@@ -1279,7 +1312,7 @@ mips_legitimate_address_p (mode, xinsn, strict)
     }
 
   /* Check for constant before stripping off SUBREG, so that we don't
-     accept (subreg (const_int)) which will fail to reload. */
+     accept (subreg (const_int)) which will fail to reload.  */
   if (CONSTANT_ADDRESS_P (xinsn)
       && ! (mips_split_addresses && mips_check_split (xinsn, mode))
       && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))
@@ -1365,9 +1398,13 @@ mips_legitimate_address_p (mode, xinsn, strict)
                  || code1 != CONST
                  || GET_CODE (XEXP (xplus1, 0)) != MINUS)
              /* When assembling for machines with 64 bit registers,
-                the assembler will not sign-extend the constant "foo"
-                in "la x, foo(x)" */
-             && (!TARGET_64BIT || (INTVAL (xplus1) > 0))
+                the assembler will sign-extend the constant "foo"
+                in "la x, foo(x)" yielding the wrong result for:
+                (set (blah:DI) (plus x y)).  */
+             && (!TARGET_64BIT
+                 || (code1 == CONST_INT
+                     && trunc_int_for_mode (INTVAL (xplus1),
+                                            SImode) == INTVAL (xplus1)))
              && !TARGET_MIPS16)
            return 1;
        }
@@ -2218,7 +2255,7 @@ mips_move_1word (operands, insn, unsignedp)
 
   if (ret == 0)
     {
-      abort_with_insn (insn, "Bad move");
+      abort_with_insn (insn, "bad move");
       return 0;
     }
 
@@ -2306,7 +2343,7 @@ mips_move_2words (operands, insn)
                  if (TARGET_FLOAT64)
                    {
                      if (!TARGET_64BIT)
-                       abort_with_insn (insn, "Bad move");
+                       abort_with_insn (insn, "bad move");
 
 #ifdef TARGET_FP_CALL_32
                      if (FP_CALL_GP_REG_P (regno1))
@@ -2326,7 +2363,7 @@ mips_move_2words (operands, insn)
              if (TARGET_FLOAT64)
                {
                  if (!TARGET_64BIT)
-                   abort_with_insn (insn, "Bad move");
+                   abort_with_insn (insn, "bad move");
 
 #ifdef TARGET_FP_CALL_32
                  if (FP_CALL_GP_REG_P (regno0))
@@ -2548,12 +2585,9 @@ mips_move_2words (operands, insn)
            }
 
          else if (double_memory_operand (op1, GET_MODE (op1)))
-           {
-             operands[2] = adjust_address (op1, SImode, 4);
-             ret = (reg_mentioned_p (op0, op1)
-                    ? "lw\t%D0,%2\n\tlw\t%0,%1"
-                    : "lw\t%0,%1\n\tlw\t%D0,%2");
-           }
+           ret = (reg_mentioned_p (op0, op1)
+                  ? "lw\t%D0,%D1\n\tlw\t%0,%1"
+                  : "lw\t%0,%1\n\tlw\t%D0,%D1");
 
          if (ret != 0 && MEM_VOLATILE_P (op1))
            {
@@ -2642,10 +2676,7 @@ mips_move_2words (operands, insn)
            }
 
          else if (double_memory_operand (op0, GET_MODE (op0)))
-           {
-             operands[2] = adjust_address (op0, SImode, 4);
-             ret = "sw\t%1,%0\n\tsw\t%D1,%2";
-           }
+           ret = "sw\t%1,%0\n\tsw\t%D1,%D0";
        }
 
       else if (((code1 == CONST_INT && INTVAL (op1) == 0)
@@ -2657,10 +2688,7 @@ mips_move_2words (operands, insn)
          if (TARGET_64BIT)
            ret = "sd\t%.,%0";
          else
-           {
-             operands[2] = adjust_address (op0, SImode, 4);
-             ret = "sw\t%.,%0\n\tsw\t%.,%2";
-           }
+           ret = "sw\t%.,%0\n\tsw\t%.,%D0";
        }
 
       if (TARGET_STATS)
@@ -2680,7 +2708,7 @@ mips_move_2words (operands, insn)
 
   if (ret == 0)
     {
-      abort_with_insn (insn, "Bad move");
+      abort_with_insn (insn, "bad move");
       return 0;
     }
 
@@ -2719,7 +2747,7 @@ mips_address_cost (addr)
          return 2;
       }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case SYMBOL_REF:
       return SYMBOL_REF_FLAG (addr) ? 1 : 2;
@@ -2979,6 +3007,8 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
       if (! TARGET_MIPS16)
        {
          convert_move (result, gen_rtx (GTU, mode, reg, const0_rtx), 0);
+         if (p_invert != NULL)
+           *p_invert = 0;
          invert = 0;
        }
       else
@@ -3470,7 +3500,7 @@ expand_block_move (operands)
    The block move type can be one of the following:
        BLOCK_MOVE_NORMAL       Do all of the block move.
        BLOCK_MOVE_NOT_LAST     Do all but the last store.
-       BLOCK_MOVE_LAST         Do just the last store. */
+       BLOCK_MOVE_LAST         Do just the last store.  */
 
 const char *
 output_block_move (insn, operands, num_regs, move_type)
@@ -3526,7 +3556,9 @@ output_block_move (insn, operands, num_regs, move_type)
      constant addresses into registers when generating N32/N64 code, just
      in case we might emit an unaligned load instruction.  */
   if (num_regs > 2 && (bytes > 2 * align || move_type != BLOCK_MOVE_NORMAL
-                      || mips_abi == ABI_N32 || mips_abi == ABI_64))
+                      || mips_abi == ABI_MEABI
+                      || mips_abi == ABI_N32
+                      || mips_abi == ABI_64))
     {
       if (CONSTANT_P (src_reg))
        {
@@ -3604,7 +3636,7 @@ output_block_move (insn, operands, num_regs, move_type)
 
   else if (num_regs < 1)
     abort_with_insn (insn,
-                    "Cannot do block move, not enough scratch registers");
+                    "cannot do block move, not enough scratch registers");
 
   while (bytes > 0)
     {
@@ -3840,11 +3872,12 @@ init_cumulative_args (cum, fntype, libname)
     }
 
   *cum = zero_cum;
+  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
 
   /* Determine if this function has variable arguments.  This is
      indicated by the last argument being 'void_type_mode' if there
      are no variable arguments.  The standard MIPS calling sequence
-     passes all arguments in the general purpose registers in this case. */
+     passes all arguments in the general purpose registers in this case.  */
 
   for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
        param != 0; param = next_param)
@@ -3984,6 +4017,11 @@ function_arg (cum, mode, type, named)
          arg_words = &cum->fp_arg_words;
          regbase = FP_ARG_FIRST;
        }
+      /* The MIPS eabi says only structures containing doubles get passed in a
+         fp register, so force a structure containing a float to be passed in
+         the integer registers.  */
+      else if (mips_abi == ABI_MEABI && struct_p)
+       regbase = GP_ARG_FIRST;
       else
        regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST);
       break;
@@ -4053,11 +4091,30 @@ function_arg (cum, mode, type, named)
       if (regbase == -1)
        abort ();
 
-      if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
-         || mips_abi == ABI_EABI || mips_abi == ABI_O64 || ! named
+      if (! type || TREE_CODE (type) != RECORD_TYPE
+         || mips_abi == ABI_32  || mips_abi == ABI_EABI
+         || mips_abi == ABI_O64 || mips_abi == ABI_MEABI
+         || ! named
          || ! TYPE_SIZE_UNIT (type)
          || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
-       ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
+       {
+
+         unsigned int arg_reg = (regbase + *arg_words + bias);
+         ret = gen_rtx_REG (mode, arg_reg);
+         if (mips_abi == ABI_MEABI
+             && regbase == FP_ARG_FIRST
+             && ! cum->prototype)
+           {
+              /* To make K&R varargs work we need to pass floating
+                 point arguments in both integer and FP registers.  */
+              ret = gen_rtx_PARALLEL (mode,
+                                     gen_rtvec (2,
+                                                gen_rtx_EXPR_LIST (VOIDmode,
+                                                                   gen_rtx_REG (mode,
+                                                                                arg_reg + GP_ARG_FIRST - FP_ARG_FIRST),
+                                                                   const0_rtx),                                                gen_rtx_EXPR_LIST (VOIDmode, ret, const0_rtx)));
+            }
+       }
       else
        {
          /* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
@@ -4114,6 +4171,7 @@ function_arg (cum, mode, type, named)
                  if (field
                      && int_bit_position (field) == bitpos
                      && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
+                     && !TARGET_SOFT_FLOAT
                      && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
                    reg = gen_rtx_REG (DFmode,
                                       regno + FP_ARG_FIRST - GP_ARG_FIRST);
@@ -4154,7 +4212,9 @@ function_arg (cum, mode, type, named)
         calling convention for now.  */
 
       if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD
-         && ! TARGET_64BIT && mips_abi != ABI_EABI)
+         && ! TARGET_64BIT
+         && mips_abi != ABI_EABI
+         && mips_abi != ABI_MEABI)
        {
          rtx amount = GEN_INT (BITS_PER_WORD
                                - int_size_in_bytes (type) * BITS_PER_UNIT);
@@ -4246,7 +4306,7 @@ function_arg_partial_nregs (cum, mode, type, named)
    Note that the GPR save area is not constant size, due to optimization
      in the prologue.  Hence, we can't use a design with two pointers
      and two offsets, although we could have designed this with two pointers
-     and three offsets. */
+     and three offsets.  */
 
 
 tree
@@ -4309,7 +4369,7 @@ mips_va_start (stdarg_p, valist, nextarg)
   if (mips_abi == ABI_EABI)
     {
       int gpr_save_area_size;
-      /* Note UNITS_PER_WORD is 4 bytes or 8, depending on TARGET_64BIT. */
+      /* Note UNITS_PER_WORD is 4 bytes or 8, depending on TARGET_64BIT.  */
       if (int_arg_words < 8 )
        /* Adjust for the prologue's economy measure */
        gpr_save_area_size = (8 - int_arg_words) * UNITS_PER_WORD;
@@ -4345,7 +4405,7 @@ mips_va_start (stdarg_p, valist, nextarg)
          /* Emit code setting a pointer into the overflow (shared-stack) area.
             If there were more than 8 non-float formals, or more than 8
             float formals, then this pointer isn't to the base of the area.
-            In that case, it must point to where the first vararg is. */
+            In that case, it must point to where the first vararg is.  */
          size_excess = 0;
          if (float_formals > floats_passed_in_regs)
            size_excess += (float_formals-floats_passed_in_regs) * 8;
@@ -4359,7 +4419,7 @@ mips_va_start (stdarg_p, valist, nextarg)
             take into account the exact sequence of floats and non-floats
             which make up the excess.  That calculation should be rolled
             into the code which sets the current_function_args_info struct.
-            The above then reduces to a fetch from that struct. */
+            The above then reduces to a fetch from that struct.  */
 
 
          t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
@@ -4369,7 +4429,7 @@ mips_va_start (stdarg_p, valist, nextarg)
          t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
          expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-         /* Emit code setting a ptr to the base of the overflow area. */
+         /* Emit code setting a ptr to the base of the overflow area.  */
          t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx);
          t = build (MODIFY_EXPR, TREE_TYPE (gtop), gtop, t);
          expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -4379,7 +4439,7 @@ mips_va_start (stdarg_p, valist, nextarg)
             If mips4, this is gpr_save_area_size below the overflow area.
             If mips2, also round down to an 8-byte boundary, since the FPR
             save area is 8-byte aligned, and GPR is 4-byte-aligned.
-            Therefore there can be a 4-byte gap between the save areas. */
+            Therefore there can be a 4-byte gap between the save areas.  */
          gprv = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx);
          fpr_save_offset = gpr_save_area_size;
          if (!TARGET_64BIT)
@@ -4421,7 +4481,7 @@ mips_va_start (stdarg_p, valist, nextarg)
          /* TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT */
 
          /* Everything is in the GPR save area, or in the overflow
-            area which is contiguous with it. */
+            area which is contiguous with it.  */
 
          int offset = -gpr_save_area_size;
          if (gpr_save_area_size == 0)
@@ -4444,6 +4504,8 @@ mips_va_start (stdarg_p, valist, nextarg)
             and both iris5.h and iris6.h define _MIPS_SIM.  */
          if (mips_abi == ABI_N32 || mips_abi == ABI_64)
            ofs = (int_arg_words >= 8 ? -UNITS_PER_WORD : 0);
+         else if (mips_abi == ABI_MEABI)
+           ofs = (int_arg_words >= 8 ? -UNITS_PER_WORD : 0);
          else
            ofs = -UNITS_PER_WORD;
        }
@@ -4486,7 +4548,7 @@ mips_va_arg (valist, type)
       if (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
        {
          /* Case of all args in a merged stack. No need to check bounds,
-            just advance valist along the stack. */
+            just advance valist along the stack.  */
 
          tree gpr = valist;
          if (! indirect
@@ -4513,7 +4575,7 @@ mips_va_arg (valist, type)
          if (indirect)
            {
              r = gen_rtx_MEM (Pmode, addr_rtx);
-             MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+             set_mem_alias_set (r, get_varargs_alias_set ());
              emit_move_insn (addr_rtx, r);
            }
          else
@@ -4524,7 +4586,7 @@ mips_va_arg (valist, type)
          return addr_rtx;
        }
 
-      /* Not a simple merged stack.  Need ptrs and indexes left by va_start. */
+      /* Not a simple merged stack.  Need ptrs and indexes left by va_start.  */
 
       f_ovfl  = TYPE_FIELDS (va_list_type_node);
       f_gtop = TREE_CHAIN (f_ovfl);
@@ -4544,11 +4606,11 @@ mips_va_arg (valist, type)
       if (TREE_CODE (type) == REAL_TYPE)
         {
 
-         /* Emit code to branch if foff == 0. */
+         /* Emit code to branch if foff == 0.  */
           r = expand_expr (foff, NULL_RTX, TYPE_MODE (TREE_TYPE (foff)),
                EXPAND_NORMAL);
-          emit_cmp_and_jump_insns (r, const0_rtx, EQ,
-               const1_rtx, GET_MODE (r), 1, 1, lab_false);
+          emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
+                                  1, lab_false);
 
           /* Emit code for addr_rtx = ftop - foff */
           t = build (MINUS_EXPR, TREE_TYPE (ftop), ftop, foff );
@@ -4572,7 +4634,7 @@ mips_va_arg (valist, type)
              /* For mips2, the overflow area contains mixed size items.
                 If a 4-byte int is followed by an 8-byte float, then
                 natural alignment causes a 4 byte gap.
-                So, dynamically adjust ovfl up to a multiple of 8. */
+                So, dynamically adjust ovfl up to a multiple of 8.  */
              t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), ovfl,
                        build_int_2 (7, 0));
              t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, t);
@@ -4581,7 +4643,7 @@ mips_va_arg (valist, type)
            }
 
           /* Emit code for addr_rtx = the ovfl pointer into overflow area.
-            Regardless of mips2, postincrement the ovfl pointer by 8. */
+            Regardless of mips2, postincrement the ovfl pointer by 8.  */
           t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
                size_int (8));
           r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
@@ -4604,33 +4666,33 @@ mips_va_arg (valist, type)
              /* In mips2, int takes 32 bits of the GPR save area, but
                 longlong takes an aligned 64 bits.  So, emit code
                 to zero the low order bits of goff, thus aligning
-                the later calculation of (gtop-goff) upwards. */
+                the later calculation of (gtop-goff) upwards.  */
               t = build (BIT_AND_EXPR, TREE_TYPE (goff), goff,
                        build_int_2 (-8, -1));
               t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
               expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
            }
 
-         /* Emit code to branch if goff == 0. */
+         /* Emit code to branch if goff == 0.  */
           r = expand_expr (goff, NULL_RTX, TYPE_MODE (TREE_TYPE (goff)),
                EXPAND_NORMAL);
-          emit_cmp_and_jump_insns (r, const0_rtx, EQ,
-               const1_rtx, GET_MODE (r), 1, 1, lab_false);
+          emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
+                                  1, lab_false);
 
-          /* Emit code for addr_rtx = gtop - goff. */
+          /* Emit code for addr_rtx = gtop - goff.  */
           t = build (MINUS_EXPR, TREE_TYPE (gtop), gtop, goff);
           r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
           if (r != addr_rtx)
            emit_move_insn (addr_rtx, r);
 
-         /* Note that mips2 int is 32 bit, but mips2 longlong is 64. */
+         /* Note that mips2 int is 32 bit, but mips2 longlong is 64.  */
          if (! TARGET_64BIT && TYPE_PRECISION (type) == 64)
            step_size = 8;
          else
            step_size = UNITS_PER_WORD;
 
           /* Emit code for goff = goff - step_size.
-            Advances the offset up GPR save area over the item. */
+            Advances the offset up GPR save area over the item.  */
           t = build (MINUS_EXPR, TREE_TYPE (goff), goff,
                build_int_2 (step_size, 0));
           t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, t);
@@ -4654,7 +4716,7 @@ mips_va_arg (valist, type)
           if (indirect)
            {
                      r = gen_rtx_MEM (Pmode, addr_rtx);
-             MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+             set_mem_alias_set (r, get_varargs_alias_set ());
              emit_move_insn (addr_rtx, r);
            }
          else
@@ -4667,7 +4729,7 @@ mips_va_arg (valist, type)
     }
   else
     {
-      /* Not EABI. */
+      /* Not EABI.  */
       int align;
 
       /* ??? The original va-mips.h did always align, despite the fact
@@ -4713,6 +4775,7 @@ override_options ()
   register int i, start;
   register int regno;
   register enum machine_mode mode;
+  register enum processor_type mips_cpu;
 
   mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE;
 
@@ -4724,7 +4787,7 @@ override_options ()
   /* If both single-float and soft-float are set, then clear the one that
      was set by TARGET_DEFAULT, leaving the one that was set by the
      user.  We assume here that the specs prevent both being set by the
-     user. */
+     user.  */
 #ifdef TARGET_DEFAULT
   if (TARGET_SINGLE_FLOAT && TARGET_SOFT_FLOAT)
     target_flags &= ~((TARGET_DEFAULT) & (MASK_SOFT_FLOAT | MASK_SINGLE_FLOAT));
@@ -4753,7 +4816,10 @@ override_options ()
              mips_isa = MIPS_ISA_DEFAULT;
            }
        }
-      else if (mips_isa < 1 || mips_isa > 4)
+      else if (mips_isa < 1
+              || (mips_isa > 4
+                  && mips_isa != 32
+                  && mips_isa != 64))
        {
          error ("-mips%d not supported", mips_isa);
          mips_isa = 1;
@@ -4767,7 +4833,7 @@ override_options ()
     }
 
 #ifdef MIPS_ABI_DEFAULT
-  /* Get the ABI to use. */
+  /* Get the ABI to use.  */
   if (mips_abi_string == (char *) 0)
     mips_abi = MIPS_ABI_DEFAULT;
   else if (! strcmp (mips_abi_string, "32"))
@@ -4780,19 +4846,29 @@ override_options ()
     mips_abi = ABI_64;
   else if (! strcmp (mips_abi_string, "eabi"))
     mips_abi = ABI_EABI;
+  else if (! strcmp (mips_abi_string, "meabi"))
+    mips_abi = ABI_MEABI;
   else
     error ("bad value (%s) for -mabi= switch", mips_abi_string);
 
   /* A specified ISA defaults the ABI if it was not specified.  */
   if (mips_abi_string == 0 && mips_isa_string
-      && mips_abi != ABI_EABI && mips_abi != ABI_O64)
+      && mips_abi != ABI_EABI
+      && mips_abi != ABI_O64
+      && mips_abi != ABI_MEABI)
     {
-      if (! ISA_HAS_64BIT_REGS)
-       mips_abi = ABI_32;
+      if (mips_isa == 64)
+       mips_abi = ABI_O64;
       else
-       mips_abi = ABI_64;
+       {
+         if (! ISA_HAS_64BIT_REGS)
+           mips_abi = ABI_32;
+         else
+           mips_abi = ABI_64;
+       }
     }
 
+#ifdef MIPS_CPU_STRING_DEFAULT
   /* A specified ABI defaults the ISA if it was not specified.  */
   else if (mips_isa_string == 0 && mips_abi_string
           && mips_abi != ABI_EABI && mips_abi != ABI_O64)
@@ -4804,13 +4880,13 @@ override_options ()
       else
        mips_isa = 4;
     }
+#endif
 
   /* If both ABI and ISA were specified, check for conflicts.  */
   else if (mips_isa_string && mips_abi_string)
     {
-      if ((! ISA_HAS_64BIT_REGS && (mips_abi == ABI_N32 || mips_abi == ABI_64
+      if (! ISA_HAS_64BIT_REGS && (mips_abi == ABI_N32 || mips_abi == ABI_64
                             || mips_abi == ABI_O64))
-         || (ISA_HAS_64BIT_REGS && mips_abi == ABI_32))
        error ("-mabi=%s does not support -mips%d", mips_abi_string, mips_isa);
     }
 
@@ -4826,13 +4902,9 @@ override_options ()
          || mips_abi == ABI_64))
     target_flags |= MASK_LONG64;
 
-  /* ??? This doesn't work yet, so don't let people try to use it.  */
-  if (mips_abi == ABI_32)
-    error ("The -mabi=32 support does not work yet.");
-
 #else
   if (mips_abi_string)
-    error ("This target does not support the -mabi switch.");
+    error ("this target does not support the -mabi switch");
 #endif
 
 #ifdef MIPS_CPU_STRING_DEFAULT
@@ -4882,6 +4954,14 @@ override_options ()
          mips_arch_string = "8000";
          mips_arch = PROCESSOR_R8000;
          break;
+       case 32:
+          mips_arch_string = "4kc";
+          mips_arch = PROCESSOR_R4KC;
+          break;
+        case 64:
+          mips_arch_string = "5kc";
+          mips_arch = PROCESSOR_R5KC;
+          break;
        }
     }
   else
@@ -4918,6 +4998,14 @@ override_options ()
          mips_tune_string = "8000";
          mips_tune = PROCESSOR_R8000;
          break;
+       case 32:
+         mips_tune_string = "4kc";
+         mips_tune = PROCESSOR_R4KC;
+         break;
+       case 64:
+         mips_tune_string = "5kc";
+         mips_tune = PROCESSOR_R5KC;
+         break;
        }
 
     }
@@ -4931,16 +5019,14 @@ override_options ()
        }
     }
 
-   /* Handle processor configuration based on architecture.  */
-   if (TARGET_MIPS4100 || TARGET_MIPS3900)
-     target_flags |= MASK_SOFT_FLOAT;
-
-
   if ((mips_arch == PROCESSOR_R3000 && (mips_isa != 1))
+      || (mips_arch == PROCESSOR_R4KC && mips_isa != 32)
+      || ((mips_arch == PROCESSOR_R5KC
+          || mips_arch == PROCESSOR_R20KC) && mips_isa != 64)
       || (mips_arch == PROCESSOR_R6000 && mips_isa != 1 && mips_isa != 2)
       || ((mips_arch == PROCESSOR_R4000
-           || mips_arch == PROCESSOR_R4100
-           || mips_arch == PROCESSOR_R4300
+          || mips_arch == PROCESSOR_R4100
+          || mips_arch == PROCESSOR_R4300
           || mips_arch == PROCESSOR_R4600
           || mips_arch == PROCESSOR_R4650)
          && mips_isa != 1 && mips_isa != 2 && mips_isa != 3))
@@ -5048,7 +5134,7 @@ override_options ()
   if (mips_entry_string != NULL)
     {
       if (*mips_entry_string != '\0')
-       error ("Invalid option `entry%s'", mips_entry_string);
+       error ("invalid option `entry%s'", mips_entry_string);
 
       if (! TARGET_MIPS16)
        warning ("-mentry is only meaningful with -mips-16");
@@ -5148,7 +5234,14 @@ override_options ()
            temp = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
 
          else if (FP_REG_P (regno))
-           temp = ((TARGET_FLOAT64 || ((regno & 1) == 0))
+           temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)
+                     /* I think this change is OK regardless of abi, but
+                        I'm being cautions untill I can test this more.
+                        HARD_REGNO_MODE_OK is about whether or not you
+                        can move to and from a register without changing
+                        the value, not about whether math works on the
+                        register.  */
+                     || (mips_abi == ABI_MEABI && size <= 4))
                    && (class == MODE_FLOAT
                        || class == MODE_COMPLEX_FLOAT
                        || (TARGET_DEBUG_H_MODE && class == MODE_INT))
@@ -5246,7 +5339,7 @@ mips_debugger_offset (addr, offset)
   /* sdbout_parms does not want this to crash for unrecognized cases.  */
 #if 0
   else if (reg != arg_pointer_rtx)
-    abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer.");
+    abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer");
 #endif
 
   return offset;
@@ -5278,7 +5371,7 @@ mips_debugger_offset (addr, offset)
    'x'  X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
    'd'  output integer constant in decimal,
    'z' if the operand is 0, use $0 instead of normal operand.
-   'D'  print second register of double-word register operand.
+   'D'  print second part of double-word register or memory operand.
    'L'  print low-order register of double-word register operand.
    'M'  print high-order register of double-word register operand.
    'C'  print part of opcode for a branch condition.
@@ -5438,7 +5531,7 @@ print_operand (file, op, letter)
        break;
 
        default:
-         error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
+         error ("PRINT_OPERAND: unknown punctuation '%c'", letter);
          break;
        }
 
@@ -5549,7 +5642,12 @@ print_operand (file, op, letter)
     }
 
   else if (code == MEM)
-    output_address (XEXP (op, 0));
+    {
+      if (letter == 'D')
+       output_address (plus_constant (XEXP (op, 0), 4));
+      else
+       output_address (XEXP (op, 0));
+    }
 
   else if (code == CONST_DOUBLE
           && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
@@ -5625,7 +5723,7 @@ print_operand_address (file, addr)
       {
       case REG:
        if (! TARGET_MIPS16 && REGNO (addr) == ARG_POINTER_REGNUM)
-         abort_with_insn (addr, "Arg pointer not eliminated.");
+         abort_with_insn (addr, "arg pointer not eliminated");
 
        fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
        break;
@@ -5636,11 +5734,11 @@ print_operand_address (file, addr)
          register rtx arg1 = XEXP (addr, 1);
 
          if (! mips_split_addresses)
-           abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, Spurious LO_SUM.");
+           abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, Spurious LO_SUM");
 
          if (GET_CODE (arg0) != REG)
            abort_with_insn (addr,
-                            "PRINT_OPERAND_ADDRESS, LO_SUM with #1 not REG.");
+                            "PRINT_OPERAND_ADDRESS, LO_SUM with #1 not REG");
 
          fprintf (file, "%%lo(");
          print_operand_address (file, arg1);
@@ -5677,7 +5775,7 @@ print_operand_address (file, addr)
            abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #2");
 
          if (REGNO (reg) == ARG_POINTER_REGNUM)
-           abort_with_insn (addr, "Arg pointer not eliminated.");
+           abort_with_insn (addr, "arg pointer not eliminated");
 
          if (TARGET_MIPS16
              && GET_CODE (offset) == CONST
@@ -5705,7 +5803,29 @@ print_operand_address (file, addr)
        break;
     }
 }
+\f
+/* Target hook for assembling integer objects.  It appears that the Irix
+   6 assembler can't handle 64-bit decimal integers, so avoid printing
+   such an integer here.  */
 
+static bool
+mips_assemble_integer (x, size, aligned_p)
+     rtx x;
+     unsigned int size;
+     int aligned_p;
+{
+  if ((TARGET_64BIT || TARGET_GAS) && size == 8 && aligned_p)
+    {
+      fputs ("\t.dword\t", asm_out_file);
+      if (HOST_BITS_PER_WIDE_INT < 64 || GET_CODE (x) != CONST_INT)
+       output_addr_const (asm_out_file, x);
+      else
+       print_operand (asm_out_file, x, 'X');
+      fputc ('\n', asm_out_file);
+      return true;
+    }
+  return default_assemble_integer (x, size, aligned_p);
+}
 \f
 /* If optimizing for the global pointer, keep track of all of the externs, so
    that at the end of the file, we can emit the appropriate .extern
@@ -5765,7 +5885,7 @@ mips_output_external (file, decl, name)
 #ifdef ASM_OUTPUT_UNDEF_FUNCTION
 int
 mips_output_external_libcall (file, name)
-     FILE *file;
+     FILE *file ATTRIBUTE_UNUSED;
      const char *name;
 {
   register struct extern_list *p;
@@ -5780,20 +5900,6 @@ mips_output_external_libcall (file, name)
 }
 #endif
 \f
-/* Compute a string to use as a temporary file name.  */
-
-static FILE *
-mips_make_temp_file ()
-{
-  FILE *stream;
-
-  temp_filename = make_temp_file (0);
-  stream = fopen (temp_filename, "w+");
-  if (!stream)
-    fatal_io_error ("can't open %s", temp_filename);
-  return stream;
-}
-\f
 /* Emit a new filename to a stream.  If this is MIPS ECOFF, watch out
    for .file's that start within a function.  If we are smuggling stabs, try to
    put out a MIPS ECOFF file and a stab.  */
@@ -5863,7 +5969,6 @@ mips_output_lineno (stream, line)
               LOCAL_LABEL_PREFIX, sym_lineno, ASM_STABN_OP, N_SLINE, line,
               LOCAL_LABEL_PREFIX, sym_lineno);
     }
-
   else
     {
       fprintf (stream, "\n\t%s.loc\t%d %d\n",
@@ -6028,6 +6133,41 @@ mips_asm_file_start (stream)
   if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
     fprintf (stream, "\t.set\tnobopt\n");
 
+  if (TARGET_GAS)
+    {
+#if defined(OBJECT_FORMAT_ELF)
+      /* Generate a special section to describe the ABI switches used to
+        produce the resultant binary.  This used to be done by the assembler
+        setting bits in the ELF header's flags field, but we have run out of
+        bits.  GDB needs this information in order to be able to correctly
+        debug these binaries. See the function mips_gdbarch_init() in
+        gdb/mips-tdep.c.  */
+      const char * abi_string = NULL;
+
+      switch (mips_abi)
+       {
+       case ABI_32:   abi_string = "abi32"; break;
+       case ABI_N32:  abi_string = "abiN32"; break;
+       case ABI_64:   abi_string = "abi64"; break;
+       case ABI_O64:  abi_string = "abiO64"; break;
+       case ABI_EABI: abi_string = TARGET_64BIT ? "eabi64" : "eabi32"; break;
+       case ABI_MEABI:abi_string = TARGET_64BIT ? "meabi64" : "meabi32"; break;
+       default:
+         abort ();
+       }
+      /* Note - we use fprintf directly rather than called named_section()
+        because in this way we can avoid creating an allocated section.  We
+        do not want this section to take up any space in the running
+        executable.  */
+      fprintf (stream, "\t.section .mdebug.%s\n", abi_string);
+
+      /* Restore the default section.  */
+      fprintf (stream, "\t.previous\n");
+#endif
+    }
+
+
+
   /* Generate the pseudo ops that System V.4 wants.  */
 #ifndef ABICALLS_ASM_OP
 #define ABICALLS_ASM_OP "\t.abicalls"
@@ -6039,20 +6179,14 @@ mips_asm_file_start (stream)
   if (TARGET_MIPS16)
     fprintf (stream, "\t.set\tmips16\n");
 
-  /* Start a section, so that the first .popsection directive is guaranteed
-     to have a previously defined section to pop back to.  */
-  if (mips_abi != ABI_32 && mips_abi != ABI_O64 && mips_abi != ABI_EABI)
-    fprintf (stream, "\t.section\t.text\n");
-
   /* This code exists so that we can put all externs before all symbol
      references.  This is necessary for the MIPS assembler's global pointer
      optimizations to work.  */
-  if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
+  if (TARGET_FILE_SWITCHING)
     {
       asm_out_data_file = stream;
-      asm_out_text_file = mips_make_temp_file ();
+      asm_out_text_file = tmpfile ();
     }
-
   else
     asm_out_data_file = asm_out_text_file = stream;
 
@@ -6071,10 +6205,8 @@ void
 mips_asm_file_end (file)
      FILE *file;
 {
-  char buffer[8192];
   tree name_tree;
   struct extern_list *p;
-  int len;
 
   if (HALF_PIC_P ())
     {
@@ -6107,26 +6239,32 @@ mips_asm_file_end (file)
        }
     }
 
-  if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
+  if (TARGET_FILE_SWITCHING)
     {
       fprintf (file, "\n\t.text\n");
-      rewind (asm_out_text_file);
-      if (ferror (asm_out_text_file))
-       fatal_io_error ("can't rewind %s", temp_filename);
+      copy_file_data (file, asm_out_text_file);
+    }
+}
 
-      while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
-       if ((int) fwrite (buffer, 1, len, file) != len)
-         fatal_io_error ("can't write to %s", asm_file_name);
+static void
+copy_file_data (to, from)
+     FILE *to, *from;
+{
+  char buffer[8192];
+  size_t len;
+  rewind (from);
+  if (ferror (from))
+    fatal_io_error ("can't rewind temp file");
 
-      if (len < 0)
-       fatal_io_error ("can't read from %s", temp_filename);
+  while ((len = fread (buffer, 1, sizeof (buffer), from)) > 0)
+    if (fwrite (buffer, 1, len, to) != len)
+      fatal_io_error ("can't write to output file");
 
-      if (fclose (asm_out_text_file) != 0)
-       fatal_io_error ("can't close %s", temp_filename);
+  if (ferror (from))
+    fatal_io_error ("can't read from temp file");
 
-      unlink (temp_filename);
-      free (temp_filename);
-    }
+  if (fclose (from))
+    fatal_io_error ("can't close temp file");
 }
 
 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
@@ -6151,43 +6289,6 @@ mips_declare_object (stream, name, init_string, final_string, size)
     }
 }
 \f
-/* Output a double precision value to the assembler.  If both the
-   host and target are IEEE, emit the values in hex.  */
-
-void
-mips_output_double (stream, value)
-     FILE *stream;
-     REAL_VALUE_TYPE value;
-{
-#ifdef REAL_VALUE_TO_TARGET_DOUBLE
-  long value_long[2];
-  REAL_VALUE_TO_TARGET_DOUBLE (value, value_long);
-
-  fprintf (stream, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n",
-          value_long[0], value, value_long[1]);
-#else
-  fprintf (stream, "\t.double\t%.20g\n", value);
-#endif
-}
-
-/* Output a single precision value to the assembler.  If both the
-   host and target are IEEE, emit the values in hex.  */
-
-void
-mips_output_float (stream, value)
-     FILE *stream;
-     REAL_VALUE_TYPE value;
-{
-#ifdef REAL_VALUE_TO_TARGET_SINGLE
-  long value_long;
-  REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
-
-  fprintf (stream, "\t.word\t0x%08lx\t\t# %.12g (float)\n", value_long, value);
-#else
-  fprintf (stream, "\t.float\t%.12g\n", value);
-#endif
-}
-\f
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.
 
@@ -6245,7 +6346,7 @@ HOST_WIDE_INT
 compute_frame_size (size)
      HOST_WIDE_INT size;       /* # of var. bytes allocated */
 {
-  int regno;
+  unsigned int regno;
   HOST_WIDE_INT total_size;    /* # bytes that the entire frame takes up */
   HOST_WIDE_INT var_size;      /* # bytes that variables take up */
   HOST_WIDE_INT args_size;     /* # bytes that outgoing arguments take up */
@@ -6318,7 +6419,7 @@ compute_frame_size (size)
   /* We need to restore these for the handler.  */
   if (current_function_calls_eh_return)
     {
-      int i;
+      unsigned int i;
       for (i = 0; ; ++i)
        {
          regno = EH_RETURN_DATA_REGNO (i);
@@ -6364,7 +6465,7 @@ compute_frame_size (size)
      call to mcount.  */
   if (total_size == extra_size
       && (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
-      && ! profile_flag)
+      && ! current_function_profile)
     total_size = extra_size = 0;
   else if (TARGET_ABICALLS)
     {
@@ -6445,6 +6546,105 @@ compute_frame_size (size)
 
 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
 
+/* Emit instructions to load the value (SP + OFFSET) into MIPS_TEMP2_REGNUM
+   and return an rtl expression for the register.  Write the assembly
+   instructions directly to FILE if it is not null, otherwise emit them as
+   rtl.
+
+   This function is a subroutine of save_restore_insns.  It is used when
+   OFFSET is too large to add in a single instruction.  */
+
+static rtx
+mips_add_large_offset_to_sp (offset, file)
+     HOST_WIDE_INT offset;
+     FILE *file;
+{
+  rtx reg = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
+  if (file == 0)
+    {
+      rtx offset_rtx = GEN_INT (offset);
+
+      emit_move_insn (reg, offset_rtx);
+      if (Pmode == DImode)
+       emit_insn (gen_adddi3 (reg, reg, stack_pointer_rtx));
+      else
+       emit_insn (gen_addsi3 (reg, reg, stack_pointer_rtx));
+    }
+  else
+    {
+      fprintf (file, "\tli\t%s,0x%.08lx\t# ",
+              reg_names[MIPS_TEMP2_REGNUM], (long) offset);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
+      fprintf (file, "\n\t%s\t%s,%s,%s\n",
+              Pmode == DImode ? "daddu" : "addu",
+              reg_names[MIPS_TEMP2_REGNUM],
+              reg_names[MIPS_TEMP2_REGNUM],
+              reg_names[STACK_POINTER_REGNUM]);
+    }
+  return reg;
+}
+
+/* Make INSN frame related and note that it performs the frame-related
+   operation DWARF_PATTERN.  */
+
+static void
+mips_annotate_frame_insn (insn, dwarf_pattern)
+     rtx insn, dwarf_pattern;
+{
+  RTX_FRAME_RELATED_P (insn) = 1;
+  REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                     dwarf_pattern,
+                                     REG_NOTES (insn));
+}
+
+/* Return a frame-related rtx that stores register REGNO at (SP + OFFSET).
+   The expression should only be used to store single registers.  */
+
+static rtx
+mips_frame_set (mode, regno, offset)
+     enum machine_mode mode;
+     int regno;
+     int offset;
+{
+  rtx address = plus_constant (stack_pointer_rtx, offset);
+  rtx set = gen_rtx_SET (mode,
+                        gen_rtx_MEM (mode, address),
+                        gen_rtx_REG (mode, regno));
+  RTX_FRAME_RELATED_P (set) = 1;
+  return set;
+}
+
+
+/* Emit a move instruction that stores REG in MEM.  Make the instruction
+   frame related and note that it stores REG at (SP + OFFSET).  This
+   function may be asked to store an FPR pair.  */
+
+static void
+mips_emit_frame_related_store (mem, reg, offset)
+     rtx mem;
+     rtx reg;
+     HOST_WIDE_INT offset;
+{
+  rtx dwarf_expr;
+
+  if (GET_MODE (reg) == DFmode && ! TARGET_FLOAT64)
+    {
+      /* Two registers are being stored, so the frame-related expression
+        must be a PARALLEL rtx with one SET for each register.  The
+        higher numbered register is stored in the lower address on
+        big-endian targets.  */
+      int regno1 = TARGET_BIG_ENDIAN ? REGNO (reg) + 1 : REGNO (reg);
+      int regno2 = TARGET_BIG_ENDIAN ? REGNO (reg) : REGNO (reg) + 1;
+      rtx set1 = mips_frame_set (SFmode, regno1, offset);
+      rtx set2 = mips_frame_set (SFmode, regno2, offset + UNITS_PER_FPREG);
+      dwarf_expr = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set1, set2));
+    }
+  else
+    dwarf_expr = mips_frame_set (GET_MODE (reg), REGNO (reg), offset);
+
+  mips_annotate_frame_insn (emit_move_insn (mem, reg), dwarf_expr);
+}
+
 static void
 save_restore_insns (store_p, large_reg, large_offset, file)
      int store_p;      /* true if this is prologue */
@@ -6454,6 +6654,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 {
   long mask = current_frame_info.mask;
   long fmask = current_frame_info.fmask;
+  long real_mask = mask;
   int regno;
   rtx base_reg_rtx;
   HOST_WIDE_INT base_offset;
@@ -6466,6 +6667,12 @@ save_restore_insns (store_p, large_reg, large_offset, file)
       && ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
     abort ();
 
+  /* Do not restore GP under certain conditions.  */
+  if (! store_p
+      && TARGET_ABICALLS
+      && (mips_abi == ABI_32 || mips_abi == ABI_O64))
+    mask &= ~(1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST));
+
   if (mask == 0 && fmask == 0)
     return;
 
@@ -6490,7 +6697,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 
       if (gp_offset < 0 || end_offset < 0)
        internal_error
-         ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
+         ("gp_offset (%ld) or end_offset (%ld) is less than zero",
           (long) gp_offset, (long) end_offset);
 
       /* If we see a large frame in mips16 mode, we save the registers
@@ -6515,8 +6722,6 @@ save_restore_insns (store_p, large_reg, large_offset, file)
              else
                insn = emit_insn (gen_addsi3 (base_reg_rtx, large_reg,
                                              stack_pointer_rtx));
-             if (store_p)
-               RTX_FRAME_RELATED_P (insn) = 1;
            }
          else
            fprintf (file, "\t%s\t%s,%s,%s\n",
@@ -6525,61 +6730,10 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                     reg_names[REGNO (large_reg)],
                     reg_names[STACK_POINTER_REGNUM]);
        }
-
       else
        {
-         base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
          base_offset = gp_offset;
-         if (file == 0)
-           {
-             rtx gp_offset_rtx = GEN_INT (gp_offset);
-
-             /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
-                bit, so make sure that we don't emit anything that can be
-                split.  */
-             /* ??? There is no DImode ori immediate pattern, so we can only
-                do this for 32 bit code.  */
-             if (large_int (gp_offset_rtx, GET_MODE (gp_offset_rtx))
-                 && GET_MODE (base_reg_rtx) == SImode)
-               {
-                 insn = emit_move_insn (base_reg_rtx,
-                                        GEN_INT (gp_offset & BITMASK_UPPER16));
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 insn
-                   = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
-                                            GEN_INT (gp_offset
-                                                     & BITMASK_LOWER16)));
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-               }
-             else
-               {
-                 insn = emit_move_insn (base_reg_rtx, gp_offset_rtx);
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-               }
-
-             if (Pmode == DImode)
-               insn = emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx,
-                                             stack_pointer_rtx));
-             else
-               insn = emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx,
-                                             stack_pointer_rtx));
-             if (store_p)
-               RTX_FRAME_RELATED_P (insn) = 1;
-           }
-         else
-           {
-             fprintf (file, "\tli\t%s,0x%.08lx\t# ",
-                      reg_names[MIPS_TEMP2_REGNUM], (long) base_offset);
-             fprintf (file, HOST_WIDE_INT_PRINT_DEC, base_offset);
-             fprintf (file, "\n\t%s\t%s,%s,%s\n",
-                      Pmode == DImode ? "daddu" : "addu",
-                      reg_names[MIPS_TEMP2_REGNUM],
-                      reg_names[MIPS_TEMP2_REGNUM],
-                      reg_names[STACK_POINTER_REGNUM]);
-           }
+         base_reg_rtx = mips_add_large_offset_to_sp (base_offset, file);
        }
 
       /* When we restore the registers in MIPS16 mode, then if we are
@@ -6606,7 +6760,8 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                             gen_rtx (PLUS, Pmode, base_reg_rtx,
                                      GEN_INT (gp_offset - base_offset)));
 
-               RTX_UNCHANGING_P (mem_rtx) = 1;
+               if (! current_function_calls_eh_return)
+                 RTX_UNCHANGING_P (mem_rtx) = 1;
 
                /* The mips16 does not have an instruction to load
                    $31, so we load $7 instead, and work things out
@@ -6631,13 +6786,8 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                  reg_rtx = gen_rtx (REG, gpr_mode, regno);
 
                if (store_p)
-                 {
-                   insn = emit_move_insn (mem_rtx, reg_rtx);
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 }
-               else if (!TARGET_ABICALLS
-                        || (mips_abi != ABI_32 && mips_abi != ABI_O64)
-                        || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
+                 mips_emit_frame_related_store (mem_rtx, reg_rtx, gp_offset);
+               else
                  {
                    emit_move_insn (reg_rtx, mem_rtx);
                    if (TARGET_MIPS16
@@ -6649,50 +6799,50 @@ save_restore_insns (store_p, large_reg, large_offset, file)
              }
            else
              {
-               if (store_p || !TARGET_ABICALLS
-                   || (mips_abi != ABI_32 && mips_abi != ABI_O64)
-                   || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
+               int r = regno;
+
+               /* The mips16 does not have an instruction to
+                  load $31, so we load $7 instead, and work
+                  things out in the caller.  */
+               if (TARGET_MIPS16 && ! store_p && r == GP_REG_FIRST + 31)
+                 r = GP_REG_FIRST + 7;
+               /* The mips16 sometimes needs to save $18.  */
+               if (TARGET_MIPS16
+                   && regno != GP_REG_FIRST + 31
+                   && ! M16_REG_P (regno))
                  {
-                   int r = regno;
-
-                   /* The mips16 does not have an instruction to
-                       load $31, so we load $7 instead, and work
-                       things out in the caller.  */
-                   if (TARGET_MIPS16 && ! store_p && r == GP_REG_FIRST + 31)
-                     r = GP_REG_FIRST + 7;
-                     /* The mips16 sometimes needs to save $18.  */
-                   if (TARGET_MIPS16
-                       && regno != GP_REG_FIRST + 31
-                       && ! M16_REG_P (regno))
+                   if (! store_p)
+                     r = GP_REG_FIRST + 6;
+                   else
                      {
-                       if (! store_p)
-                         r = GP_REG_FIRST + 6;
-                       else
-                         {
-                           r = GP_REG_FIRST + 3;
-                           fprintf (file, "\tmove\t%s,%s\n",
-                                    reg_names[r], reg_names[regno]);
-                         }
+                       r = GP_REG_FIRST + 3;
+                       fprintf (file, "\tmove\t%s,%s\n",
+                                reg_names[r], reg_names[regno]);
                      }
-                   fprintf (file, "\t%s\t%s,",
-                            (TARGET_64BIT
-                             ? (store_p) ? "sd" : "ld"
-                             : (store_p) ? "sw" : "lw"),
-                            reg_names[r]);
-                   fprintf (file, HOST_WIDE_INT_PRINT_DEC,
-                            gp_offset - base_offset);
-                   fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
-                   if (! store_p
-                       && TARGET_MIPS16
-                       && regno != GP_REG_FIRST + 31
-                       && ! M16_REG_P (regno))
-                     fprintf (file, "\tmove\t%s,%s\n",
-                              reg_names[regno], reg_names[r]);
                  }
-
+               fprintf (file, "\t%s\t%s,",
+                        (TARGET_64BIT
+                         ? (store_p) ? "sd" : "ld"
+                         : (store_p) ? "sw" : "lw"),
+                        reg_names[r]);
+               fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+                        gp_offset - base_offset);
+               fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
+               if (! store_p
+                   && TARGET_MIPS16
+                   && regno != GP_REG_FIRST + 31
+                   && ! M16_REG_P (regno))
+                 fprintf (file, "\tmove\t%s,%s\n",
+                          reg_names[regno], reg_names[r]);
              }
            gp_offset -= GET_MODE_SIZE (gpr_mode);
          }
+        /* If the restore is being supressed, still take into account
+          the offset at which it is stored.  */
+       else if (BITSET_P (real_mask, regno - GP_REG_FIRST))
+         {
+           gp_offset -= GET_MODE_SIZE (gpr_mode);
+         }
     }
   else
     base_reg_rtx = 0, base_offset  = 0;
@@ -6709,7 +6859,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 
       if (fp_offset < 0 || end_offset < 0)
        internal_error
-         ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
+         ("fp_offset (%ld) or end_offset (%ld) is less than zero",
           (long) fp_offset, (long) end_offset);
 
       else if (fp_offset < 32768)
@@ -6734,8 +6884,6 @@ save_restore_insns (store_p, large_reg, large_offset, file)
              else
                insn = emit_insn (gen_addsi3 (base_reg_rtx, large_reg,
                                              stack_pointer_rtx));
-             if (store_p)
-               RTX_FRAME_RELATED_P (insn) = 1;
            }
 
          else
@@ -6745,62 +6893,10 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                     reg_names[REGNO (large_reg)],
                     reg_names[STACK_POINTER_REGNUM]);
        }
-
       else
        {
-         base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
          base_offset = fp_offset;
-         if (file == 0)
-           {
-             rtx fp_offset_rtx = GEN_INT (fp_offset);
-
-             /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
-                bit, so make sure that we don't emit anything that can be
-                split.  */
-             /* ??? There is no DImode ori immediate pattern, so we can only
-                do this for 32 bit code.  */
-             if (large_int (fp_offset_rtx, GET_MODE (fp_offset_rtx))
-                 && GET_MODE (base_reg_rtx) == SImode)
-               {
-                 insn = emit_move_insn (base_reg_rtx,
-                                        GEN_INT (fp_offset & BITMASK_UPPER16));
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 insn = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
-                                               GEN_INT (fp_offset
-                                                        & BITMASK_LOWER16)));
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-               }
-             else
-               {
-                 insn = emit_move_insn (base_reg_rtx, fp_offset_rtx);
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-               }
-
-             if (store_p)
-               RTX_FRAME_RELATED_P (insn) = 1;
-             if (Pmode == DImode)
-               insn = emit_insn (gen_adddi3 (base_reg_rtx, base_reg_rtx,
-                                             stack_pointer_rtx));
-             else
-               insn = emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx,
-                                             stack_pointer_rtx));
-             if (store_p)
-               RTX_FRAME_RELATED_P (insn) = 1;
-           }
-         else
-           {
-             fprintf (file, "\tli\t%s,0x%.08lx\t# ",
-                      reg_names[MIPS_TEMP2_REGNUM], (long) base_offset);
-             fprintf (file, HOST_WIDE_INT_PRINT_DEC, base_offset);
-             fprintf (file, "\n\t%s\t%s,%s,%s\n",
-                      Pmode == DImode ? "daddu" : "addu",
-                      reg_names[MIPS_TEMP2_REGNUM],
-                      reg_names[MIPS_TEMP2_REGNUM],
-                      reg_names[STACK_POINTER_REGNUM]);
-           }
+         base_reg_rtx = mips_add_large_offset_to_sp (fp_offset, file);
        }
 
       /* This loop must iterate over the same space as its companion in
@@ -6819,13 +6915,11 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                                       gen_rtx (PLUS, Pmode, base_reg_rtx,
                                                GEN_INT (fp_offset
                                                         - base_offset)));
-               RTX_UNCHANGING_P (mem_rtx) = 1;
+               if (! current_function_calls_eh_return)
+                 RTX_UNCHANGING_P (mem_rtx) = 1;
 
                if (store_p)
-                 {
-                   insn = emit_move_insn (mem_rtx, reg_rtx);
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 }
+                 mips_emit_frame_related_store (mem_rtx, reg_rtx, fp_offset);
                else
                  emit_move_insn (reg_rtx, mem_rtx);
              }
@@ -6856,7 +6950,7 @@ mips_output_function_prologue (file, size)
 #ifndef FUNCTION_NAME_ALREADY_DECLARED
   const char *fnname;
 #endif
-  long tsize = current_frame_info.total_size;
+  HOST_WIDE_INT tsize = current_frame_info.total_size;
 
   ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
 
@@ -6900,9 +6994,9 @@ mips_output_function_prologue (file, size)
               (reg_names[(frame_pointer_needed)
                          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
               ((frame_pointer_needed && TARGET_MIPS16)
-               ? (tsize - current_function_outgoing_args_size)
-               : tsize),
-              reg_names[31 + GP_REG_FIRST],
+               ? ((long) tsize - current_function_outgoing_args_size)
+               : (long) tsize),
+              reg_names[GP_REG_FIRST + 31],
               current_frame_info.var_size,
               current_frame_info.num_gp,
               current_frame_info.num_fp,
@@ -6918,7 +7012,7 @@ mips_output_function_prologue (file, size)
 
       /* Require:
         OLD_SP == *FRAMEREG + FRAMESIZE => can find old_sp from nominated FP reg.
-        HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs. */
+        HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs.  */
     }
 
   if (mips_entry && ! mips_can_use_return_insn ())
@@ -6979,11 +7073,10 @@ mips_output_function_prologue (file, size)
              || GET_CODE (offset) != CONST_INT)
            continue;
          if (REGNO (base) == (unsigned) STACK_POINTER_REGNUM
-             && (unsigned HOST_WIDE_INT) INTVAL (offset)
-             == tsize + (REGNO (src) - 4) * UNITS_PER_WORD)
+             && INTVAL (offset) == tsize + (REGNO (src) - 4) * UNITS_PER_WORD)
            ;
          else if (REGNO (base) == (unsigned) HARD_FRAME_POINTER_REGNUM
-                  && ((unsigned HOST_WIDE_INT) INTVAL (offset)
+                  && (INTVAL (offset)
                       == (tsize
                           + (REGNO (src) - 4) * UNITS_PER_WORD
                           - current_function_outgoing_args_size)))
@@ -7047,7 +7140,7 @@ mips_output_function_prologue (file, size)
        {
          fprintf (file, "\t%s\t%s,%s,%ld\n",
                   (Pmode == DImode ? "dsubu" : "subu"),
-                  sp_str, sp_str, tsize);
+                  sp_str, sp_str, (long) tsize);
          fprintf (file, "\t.cprestore %ld\n", current_frame_info.args_size);
        }
 
@@ -7096,7 +7189,7 @@ mips_expand_prologue ()
      the varargs special argument, and treat it as part of the
      variable arguments.
 
-     This is only needed if store_args_on_stack is true. */
+     This is only needed if store_args_on_stack is true.  */
 
   INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0);
   regno = GP_ARG_FIRST;
@@ -7172,7 +7265,7 @@ mips_expand_prologue ()
          pattern = RTVEC_ELT (adjust, i);
          if (GET_CODE (pattern) != SET
              || GET_CODE (SET_SRC (pattern)) != ASHIFT)
-           abort_with_insn (pattern, "Insn is not a shift");
+           abort_with_insn (pattern, "insn is not a shift");
          PUT_CODE (SET_SRC (pattern), ASHIFTRT);
 
          insn = emit_insn (pattern);
@@ -7199,7 +7292,7 @@ mips_expand_prologue ()
       int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
       rtx ptr = stack_pointer_rtx;
 
-      /* If we are doing svr4-abi, sp has already been decremented by tsize. */
+      /* If we are doing svr4-abi, sp has already been decremented by tsize.  */
       if (TARGET_ABICALLS)
        offset += tsize;
 
@@ -7301,45 +7394,28 @@ mips_expand_prologue ()
       if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
          && (!TARGET_MIPS16 || tsize <= 32767))
        {
-         rtx insn;
+         rtx adjustment_rtx, insn, dwarf_pattern;
 
          if (tsize > 32767)
            {
-             tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
-
-             /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
-                bit, so make sure that we don't emit anything that can be
-                split.  */
-             /* ??? There is no DImode ori immediate pattern, so we can only
-                do this for 32 bit code.  */
-             if (large_int (tsize_rtx, GET_MODE (tsize_rtx))
-                 && GET_MODE (tmp_rtx) == SImode)
-               {
-                 insn = emit_move_insn (tmp_rtx,
-                                        GEN_INT (tsize & BITMASK_UPPER16));
-                 RTX_FRAME_RELATED_P (insn) = 1;
-                 insn = emit_insn (gen_iorsi3 (tmp_rtx, tmp_rtx,
-                                               GEN_INT (tsize
-                                                        & BITMASK_LOWER16)));
-                 RTX_FRAME_RELATED_P (insn) = 1;
-               }
-             else
-               {
-                 insn = emit_move_insn (tmp_rtx, tsize_rtx);
-                 RTX_FRAME_RELATED_P (insn) = 1;
-               }
-
-             tsize_rtx = tmp_rtx;
+             adjustment_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
+             emit_move_insn (adjustment_rtx, tsize_rtx);
            }
+         else
+           adjustment_rtx = tsize_rtx;
 
          if (Pmode == DImode)
            insn = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                         tsize_rtx));
+                                         adjustment_rtx));
          else
            insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                         tsize_rtx));
+                                         adjustment_rtx));
+
+         dwarf_pattern = gen_rtx_SET (Pmode, stack_pointer_rtx,
+                                      plus_constant (stack_pointer_rtx,
+                                                     -tsize));
 
-         RTX_FRAME_RELATED_P (insn) = 1;
+         mips_annotate_frame_insn (insn, dwarf_pattern);
        }
 
       if (! mips_entry)
@@ -7429,12 +7505,12 @@ mips_expand_prologue ()
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  */
 
-  if (profile_flag || profile_block_flag)
+  if (current_function_profile)
     emit_insn (gen_blockage ());
 }
 \f
 /* Do any necessary cleanup after a function to restore stack, frame,
-   and regs. */
+   and regs.  */
 
 #define RA_MASK BITMASK_HIGH   /* 1 << 31 */
 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
@@ -7527,9 +7603,11 @@ mips_output_function_epilogue (file, size)
   /* Restore the output file if optimizing the GP (optimizing the GP causes
      the text to be diverted to a tempfile, so that data decls come before
      references to the data).  */
-
-  if (TARGET_GP_OPT && ! TARGET_MIPS16 && ! TARGET_GAS)
-    asm_out_file = asm_out_data_file;
+  if (TARGET_FILE_SWITCHING)
+    {
+      asm_out_file = asm_out_data_file;
+      data_section ();
+    }
 }
 \f
 /* Expand the epilogue into a bunch of separate insns.  */
@@ -7661,7 +7739,7 @@ mips_can_use_return_insn ()
   if (! reload_completed)
     return 0;
 
-  if (regs_ever_live[31] || profile_flag)
+  if (regs_ever_live[31] || current_function_profile)
     return 0;
 
   /* In mips16 mode, a function which returns a floating point value
@@ -7840,8 +7918,7 @@ mips_function_value (valtype, func)
      just as PROMOTE_MODE does.  */
   mode = promote_mode (valtype, mode, &unsignedp, 1);
 
-  /* ??? How should we return complex float?  */
-  if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+  if (mclass == MODE_FLOAT)
     {
       if (TARGET_SINGLE_FLOAT
          && (mclass == MODE_FLOAT
@@ -7851,6 +7928,33 @@ mips_function_value (valtype, func)
        reg = FP_RETURN;
     }
 
+  else if (mclass == MODE_COMPLEX_FLOAT)
+    {
+      if (TARGET_FLOAT64)
+       reg = FP_RETURN;
+      else if (mode == SCmode)
+       {
+         /* When FP registers are 32 bits, we can't directly reference
+            the odd numbered ones, so let's make a pair of evens.  */
+
+         enum machine_mode cmode = TYPE_MODE (TREE_TYPE (valtype));
+
+         return gen_rtx_PARALLEL
+           (VOIDmode,
+            gen_rtvec (2,
+                       gen_rtx_EXPR_LIST (VOIDmode,
+                                          gen_rtx_REG (cmode,
+                                                       FP_RETURN),
+                                          GEN_INT (0)),
+                       gen_rtx_EXPR_LIST (VOIDmode,
+                                          gen_rtx_REG (cmode,
+                                                       FP_RETURN + 2),
+                                          GEN_INT (4))));
+       }
+      else
+       reg = FP_RETURN;
+    }
+
   else if (TREE_CODE (valtype) == RECORD_TYPE
           && mips_abi != ABI_32
           && mips_abi != ABI_O64
@@ -7941,11 +8045,12 @@ function_arg_pass_by_reference (cum, mode, type, named)
      to prevent it, or add code to function.c to properly handle the case.  */
   /* ??? cum can be NULL when called from mips_va_arg.  The problem handled
      here hopefully is not relevant to mips_va_arg.  */
-  if (cum && MUST_PASS_IN_STACK (mode, type))
+  if (cum && MUST_PASS_IN_STACK (mode, type)
+      && mips_abi != ABI_MEABI)
      {
        /* Don't pass the actual CUM to FUNCTION_ARG, because we would
          get double copies of any offsets generated for small structs
-         passed in registers. */
+         passed in registers.  */
        CUMULATIVE_ARGS temp;
        temp = *cum;
        if (FUNCTION_ARG (temp, mode, type, named) != 0)
@@ -8698,7 +8803,7 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
 
       /* We build the stub code by hand.  That's the only way we can
         do it, since we can't generate 32 bit code during a 16 bit
-        compilation. */
+        compilation.  */
 
       /* We don't want the assembler to insert any nops here.  */
       fprintf (asm_out_file, "\t.set\tnoreorder\n");
@@ -9366,7 +9471,7 @@ machine_dependent_reorg (first)
        {
          /* If we haven't had a barrier within 0x8000 bytes of a
              constant reference or we are at the end of the function,
-             emit a barrier now. */
+             emit a barrier now.  */
 
          rtx label, jump, barrier;
 
@@ -9448,7 +9553,7 @@ mips_adjust_insn_length (insn, length)
    LENGTH is the length (in bytes) of the sequence we are to generate.
    That tells us whether to generate a simple conditional branch, or a
    reversed conditional branch around a `jr' instruction.  */
-char *
+const char *
 mips_output_conditional_branch (insn,
                                operands,
                                two_operands_p,
@@ -9476,9 +9581,9 @@ mips_output_conditional_branch (insn,
      operand.  */
   const char *op2 = (two_operands_p ? ",%z3" : ",%.");
   /* The operand-printing string for the comparison.  */
-  const char *comp = (float_p ? "%F0" : "%C0");
+  const char *const comp = (float_p ? "%F0" : "%C0");
   /* The operand-printing string for the inverted comparison.  */
-  const char *inverted_comp = (float_p ? "%W0" : "%N0");
+  const char *const inverted_comp = (float_p ? "%W0" : "%N0");
 
   /* The MIPS processors (for levels of the ISA at least two), have
      "likely" variants of each branch instruction.  These instructions
@@ -9511,7 +9616,7 @@ mips_output_conditional_branch (insn,
          break;
 
        case LTU:
-         /* A condition which will always be false. */
+         /* A condition which will always be false.  */
          code = NE;
          op1 = "%.";
          break;
@@ -9566,46 +9671,44 @@ mips_output_conditional_branch (insn,
                .set reorder
             l:
 
-          Because we have to jump four bytes *past* the following
-          instruction if this branch was annulled, we can't just use
-          a label, as in the picture above; there's no way to put the
-          label after the next instruction, as the assembler does not
-          accept `.L+4' as the target of a branch.  (We can't just
-          wait until the next instruction is output; it might be a
-          macro and take up more than four bytes.  Once again, we see
-          why we want to eliminate macros.)
-
-          If the branch is annulled, we jump four more bytes that we
-          would otherwise; that way we skip the annulled instruction
-          in the delay slot.  */
-
-       const char *target
-         = ((mips_branch_likely || length == 16) ? ".+16" : ".+12");
-       char *c;
+       */
 
-       strcpy (buffer, "%(%<");
-       c = strchr (buffer, '\0');
-       /* Generate the reversed comparision.  This takes four
+        rtx orig_target;
+       rtx target = gen_label_rtx ();
+
+        output_asm_insn ("%(%<", 0);
+        orig_target = operands[1];
+        operands[1] = target;
+       /* Generate the reversed comparison.  This takes four
           bytes.  */
        if (float_p)
-         sprintf (c, "%%*b%s\t%%Z2%s",
-                  inverted_p ? comp : inverted_comp,
-                  target);
+         sprintf (buffer, "%%*b%s\t%%Z2%%1",
+                  inverted_p ? comp : inverted_comp);
        else
-         sprintf (c, "%%*b%s%s\t%s%s,%s",
+         sprintf (buffer, "%%*b%s%s\t%s%s,%%1",
                   inverted_p ? comp : inverted_comp,
                   need_z_p ? "z" : "",
                   op1,
-                  op2,
-                  target);
-       strcat (c, "\n\tnop\n\tj\t%1");
-       if (length == 16)
-         /* The delay slot was unfilled.  Since we're inside
-            .noreorder, the assembler will not fill in the NOP for
-            us, so we must do it ourselves.  */
-         strcat (buffer, "\n\tnop");
-       strcat (buffer, "%>%)");
-       return buffer;
+                  op2);
+        output_asm_insn (buffer, operands);
+        operands[1] = orig_target;
+
+       output_asm_insn ("nop\n\tj\t%1", operands);
+
+        if (length == 16)
+         output_asm_insn ("nop", 0);
+        else
+          {
+            /* Output delay slot instruction.  */
+            rtx insn = final_sequence;
+            final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
+                             optimize, 0, 1);
+            INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
+          }
+       output_asm_insn ("%>%)", 0);
+        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                   CODE_LABEL_NUMBER (target));
+        return "";
       }
 
     /* We do not currently use this code.  It handles jumps to
@@ -9656,7 +9759,7 @@ mips_output_conditional_branch (insn,
           anything.  */
 
        /* The target of the reversed branch.  */
-       const char *target
+       const char *const target
          = ((mips_branch_likely || length == 20) ? ".+20" : ".+16");
        const char *at_register = mips_reg_names[ASSEMBLER_SCRATCH_REGNUM];
        const char *gp_register = mips_reg_names[PIC_OFFSET_TABLE_REGNUM];
@@ -9745,6 +9848,8 @@ mips_parse_cpu (cpu_string)
     case '2':
       if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
        cpu = PROCESSOR_R3000;
+      else if (!strcmp (p, "20kc") || !strcmp (p, "20Kc") )
+        cpu = PROCESSOR_R20KC;
       break;
 
     case '3':
@@ -9773,11 +9878,20 @@ mips_parse_cpu (cpu_string)
        cpu = PROCESSOR_R4600;
       else if (!strcmp (p, "4650"))
        cpu = PROCESSOR_R4650;
+      /* The 4kc and 4kp processor cores are the same for
+        scheduling purposes; they both implement the MIPS32
+        ISA and only differ in their memory management
+        methods.  */
+      else if (!strcmp (p, "4kc") || !strcmp (p, "4Kc")
+               || !strcmp (p, "4kp") || !strcmp (p, "4Kp") )
+       cpu = PROCESSOR_R4KC;
       break;
 
     case '5':
       if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
        cpu = PROCESSOR_R5000;
+      else if (!strcmp (p, "5kc") || !strcmp (p, "5Kc") )
+          cpu = PROCESSOR_R5KC;
       break;
 
     case '6':
@@ -9804,3 +9918,265 @@ mips_parse_cpu (cpu_string)
 
   return cpu;
 }
+
+/* Adjust the cost of INSN based on the relationship between INSN that
+   is dependent on DEP_INSN through the dependence LINK.  The default
+   is to make no adjustment to COST.
+
+   On the MIPS, ignore the cost of anti- and output-dependencies.  */
+static int
+mips_adjust_cost (insn, link, dep, cost)
+     rtx insn ATTRIBUTE_UNUSED;
+     rtx link;
+     rtx dep ATTRIBUTE_UNUSED;
+     int cost;
+{
+  if (REG_NOTE_KIND (link) != 0)
+    return 0;  /* Anti or output dependence.  */
+  return cost;
+}
+
+/* Cover function for UNIQUE_SECTION.  */
+
+void
+mips_unique_section (decl, reloc)
+     tree decl;
+     int reloc;
+{
+  int len, size, sec;
+  const char *name, *prefix;
+  char *string;
+  static const char *const prefixes[4][2] = {
+    { ".text.", ".gnu.linkonce.t." },
+    { ".rodata.", ".gnu.linkonce.r." },
+    { ".data.", ".gnu.linkonce.d." },
+    { ".sdata.", ".gnu.linkonce.s." }
+  };
+
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  size = int_size_in_bytes (TREE_TYPE (decl));
+
+  /* Determine the base section we are interested in:
+     0=text, 1=rodata, 2=data, 3=sdata, [4=bss].  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    sec = 0;
+  else if (DECL_INITIAL (decl) == 0
+           || DECL_INITIAL (decl) == error_mark_node)
+    sec = 2;
+  else if ((TARGET_EMBEDDED_PIC || TARGET_MIPS16)
+      && TREE_CODE (decl) == STRING_CST
+      && !flag_writable_strings)
+    {
+      /* For embedded position independent code, put constant
+        strings in the text section, because the data section
+        is limited to 64K in size.  For mips16 code, put
+        strings in the text section so that a PC relative load
+        instruction can be used to get their address.  */
+      sec = 0;
+    }
+  else if (TARGET_EMBEDDED_DATA)
+    {
+      /* For embedded applications, always put an object in
+        read-only data if possible, in order to reduce RAM
+        usage.  */
+
+      if (DECL_READONLY_SECTION (decl, reloc))
+       sec = 1;
+      else if (size > 0 && size <= mips_section_threshold)
+       sec = 3;
+      else
+       sec = 2;
+    }
+  else
+    {
+      /* For hosted applications, always put an object in
+        small data if possible, as this gives the best
+        performance.  */
+
+      if (size > 0 && size <= mips_section_threshold)
+       sec = 3;
+      else if (DECL_READONLY_SECTION (decl, reloc))
+       sec = 1;
+      else
+       sec = 2;
+    }
+
+  prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
+  len = strlen (name) + strlen (prefix);
+  string = alloca (len + 1);
+  sprintf (string, "%s%s", prefix, name);
+
+  DECL_SECTION_NAME (decl) = build_string (len, string);
+}
+
+unsigned int
+mips_hard_regno_nregs (regno, mode)
+    int regno;
+    enum machine_mode mode;
+{
+  if (! FP_REG_P (regno))
+    return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
+  else
+    return ((GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG);
+}
+
+\f
+#ifdef TARGET_IRIX6
+/* Output assembly to switch to section NAME with attribute FLAGS.  */
+
+static void
+iris6_asm_named_section_1 (name, flags, align)
+     const char *name;
+     unsigned int flags;
+     unsigned int align;
+{
+  unsigned int sh_type, sh_flags, sh_entsize;
+
+  sh_flags = 0;
+  if (!(flags & SECTION_DEBUG))
+    sh_flags |= 2; /* SHF_ALLOC */
+  if (flags & SECTION_WRITE)
+    sh_flags |= 1; /* SHF_WRITE */
+  if (flags & SECTION_CODE)
+    sh_flags |= 4; /* SHF_EXECINSTR */
+  if (flags & SECTION_SMALL)
+    sh_flags |= 0x10000000; /* SHF_MIPS_GPREL */
+  if (strcmp (name, ".debug_frame") == 0)
+    sh_flags |= 0x08000000; /* SHF_MIPS_NOSTRIP */
+  if (flags & SECTION_DEBUG)
+    sh_type = 0x7000001e; /* SHT_MIPS_DWARF */
+  else if (flags & SECTION_BSS)
+    sh_type = 8; /* SHT_NOBITS */
+  else
+    sh_type = 1; /* SHT_PROGBITS */
+
+  if (flags & SECTION_CODE)
+    sh_entsize = 4;
+  else
+    sh_entsize = 0;
+
+  fprintf (asm_out_file, "\t.section %s,%#x,%#x,%u,%u\n",
+          name, sh_type, sh_flags, sh_entsize, align);
+}
+
+static void
+iris6_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  if (TARGET_FILE_SWITCHING && (flags & SECTION_CODE))
+    asm_out_file = asm_out_text_file;
+  iris6_asm_named_section_1 (name, flags, 0);
+}
+
+/* In addition to emitting a .align directive, record the maximum
+   alignment requested for the current section.  */
+
+struct iris_section_align_entry
+{
+  const char *name;
+  unsigned int log;
+  unsigned int flags;
+};
+
+static htab_t iris_section_align_htab;
+static FILE *iris_orig_asm_out_file;
+
+static int
+iris_section_align_entry_eq (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  const struct iris_section_align_entry *old = p1;
+  const char *new = p2;
+
+  return strcmp (old->name, new) == 0;
+}
+
+static hashval_t
+iris_section_align_entry_hash (p)
+     const PTR p;
+{
+  const struct iris_section_align_entry *old = p;
+  return htab_hash_string (old->name);
+}
+
+void
+iris6_asm_output_align (file, log)
+     FILE *file;
+     unsigned int log;
+{
+  const char *section = current_section_name ();
+  struct iris_section_align_entry **slot, *entry;
+
+  if (! section)
+    abort ();
+
+  slot = (struct iris_section_align_entry **)
+    htab_find_slot_with_hash (iris_section_align_htab, section,
+                             htab_hash_string (section), INSERT);
+  entry = *slot;
+  if (! entry)
+    {
+      entry = (struct iris_section_align_entry *)
+       xmalloc (sizeof (struct iris_section_align_entry));
+      *slot = entry;
+      entry->name = section;
+      entry->log = log;
+      entry->flags = current_section_flags ();
+    }
+  else if (entry->log < log)
+    entry->log = log;
+
+  fprintf (file, "\t.align\t%u\n", log);
+}
+
+/* The Iris assembler does not record alignment from .align directives,
+   but takes it from the first .section directive seen.  Play yet more
+   file switching games so that we can emit a .section directive at the
+   beginning of the file with the proper alignment attached.  */
+
+void
+iris6_asm_file_start (stream)
+     FILE *stream;
+{
+  mips_asm_file_start (stream);
+
+  iris_orig_asm_out_file = asm_out_file;
+  stream = tmpfile ();
+  asm_out_file = stream;
+  asm_out_data_file = stream;
+  if (! TARGET_FILE_SWITCHING)
+    asm_out_text_file = stream;
+
+  iris_section_align_htab = htab_create (31, iris_section_align_entry_hash,
+                                        iris_section_align_entry_eq, NULL);
+}
+
+static int
+iris6_section_align_1 (slot, data)
+     void **slot;
+     void *data ATTRIBUTE_UNUSED;
+{
+  const struct iris_section_align_entry *entry
+    = *(const struct iris_section_align_entry **) slot;
+
+  iris6_asm_named_section_1 (entry->name, entry->flags, 1 << entry->log);
+  return 1;
+}
+
+void
+iris6_asm_file_end (stream)
+     FILE *stream;
+{
+  /* Emit section directives with the proper alignment at the top of the
+     real output file.  */
+  asm_out_file = iris_orig_asm_out_file;
+  htab_traverse (iris_section_align_htab, iris6_section_align_1, NULL);
+
+  /* Copy the data emitted to the temp file to the real output file.  */
+  copy_file_data (asm_out_file, stream);
+
+  mips_asm_file_end (stream);
+}
+#endif /* TARGET_IRIX6 */