OSDN Git Service

2001-11-09 H.J. Lu <hjl@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 860ce95..23491ca 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines for insn-output.c for MIPS
    Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by A. Lichnewsky, lich@inria.inria.fr.
    Changes by Michael Meissner, meissner@osf.org.
    64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
@@ -36,13 +36,10 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "insn-attr.h"
-#include "insn-codes.h"
 #include "recog.h"
 #include "toplev.h"
 #include "output.h"
-
 #include "tree.h"
 #include "function.h"
 #include "expr.h"
@@ -51,12 +48,11 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "tm_p.h"
 #include "ggc.h"
-
-#if defined(USG) || !defined(HAVE_STAB_H)
-#include "gstab.h"  /* If doing DBX on sysV, use our own stab.h.  */
-#else
-#include <stab.h>  /* On BSD, use the system's stab.h.  */
-#endif /* not USG */
+#include "gstab.h"
+#include "hashtab.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.h"
 
 #ifdef __GNU_STAB__
 #define STAB_CODE_TYPE enum __stab_debug_code
@@ -64,12 +60,11 @@ Boston, MA 02111-1307, USA.  */
 #define STAB_CODE_TYPE int
 #endif
 
-extern char  *mktemp PARAMS ((char *));
 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,
@@ -92,11 +87,17 @@ static int mips16_simple_memory_operand             PARAMS ((rtx, rtx,
                                                        enum machine_mode));
 static int m16_check_op                                PARAMS ((rtx, int, int, int));
 static void block_move_loop                    PARAMS ((rtx, rtx,
-                                                        unsigned int, 
+                                                        unsigned int,
                                                         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));
@@ -113,6 +114,21 @@ 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 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.  */
 
@@ -129,7 +145,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
@@ -199,20 +215,22 @@ enum cmp_type branch_type;
 static int prev_half_pic_ptrs = 0;
 static int prev_half_pic_refs = 0;
 
-/* which cpu are we scheduling for */
-enum processor_type mips_cpu;
+/* The target cpu for code generation.  */
+enum processor_type mips_arch;
+
+/* The target cpu for optimization and scheduling.  */
+enum processor_type mips_tune;
 
 /* 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> */
+const char *mips_arch_string;   /* for -march=<xxx> */
+const char *mips_tune_string;   /* for -mtune=<xxx> */
 const char *mips_isa_string;   /* for -mips{1,2,3,4} */
 const char *mips_abi_string;   /* for -mabi={32,n32,64,eabi} */
 
@@ -225,9 +243,9 @@ int mips16;
    just a way to avoid using up another bit in target_flags.  */
 const char *mips_no_mips16_string;
 
-/* This is only used to determine if an type size setting option was 
+/* 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
@@ -241,6 +259,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;
 
@@ -268,10 +288,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.  */
@@ -328,7 +344,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",
@@ -343,7 +359,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,
@@ -434,7 +450,17 @@ enum reg_class mips_char_to_class[256] =
   NO_REGS,     NO_REGS,        NO_REGS,        NO_REGS,
   NO_REGS,     NO_REGS,        NO_REGS,        NO_REGS,
 };
+\f
+/* Initialize the GCC target structure.  */
+#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
    where a register or 16 bit unsigned integer is needed.  */
@@ -482,7 +508,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)
@@ -555,7 +581,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)
@@ -770,7 +796,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;
       }
@@ -826,8 +852,6 @@ double_memory_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  rtx addr;
-
   if (GET_CODE (op) != MEM
       || ! memory_operand (op, mode))
     {
@@ -877,7 +901,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;
@@ -927,15 +951,12 @@ double_memory_operand (op, mode)
   /* Make sure that 4 added to the address is a valid memory address.
      This essentially just checks for overflow in an added constant.  */
 
-  addr = XEXP (op, 0);
-
-  if (CONSTANT_ADDRESS_P (addr))
+  if (CONSTANT_ADDRESS_P (XEXP (op, 0)))
     return 1;
 
-  return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
-                           ? SImode
-                           : SFmode),
-                          plus_constant_for_output (addr, 4));
+  op = adjust_address_nv (op, GET_MODE_CLASS (mode) == MODE_INT
+                         ? SImode : SFmode, 4);
+  return memory_address_p (GET_MODE (op), XEXP (op, 0));
 }
 
 /* Return nonzero if the code of this rtx pattern is EQ or NE.  */
@@ -1224,7 +1245,7 @@ int
 mips_check_split (address, mode)
      rtx address;
      enum machine_mode mode;
-{     
+{
   /* ??? This is the same check used in simple_memory_operand.
      We use it here because LO_SUM is not offsettable.  */
   if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD)
@@ -1248,7 +1269,7 @@ mips_reg_mode_ok_for_base_p (reg, mode, strict)
      enum machine_mode mode;
      int strict;
 {
-  return (strict 
+  return (strict
          ? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode)
          : GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));
 }
@@ -1264,111 +1285,115 @@ mips_legitimate_address_p (mode, xinsn, strict)
      rtx xinsn;
      int strict;
 {
-  if (TARGET_DEBUG_B_MODE)                                             
-    {                                                                  
-      GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n", 
-                 strict ? "" : "not ");                        
-      GO_DEBUG_RTX (xinsn);                                            
-    }                                                                  
-                                                                       
-  /* Check for constant before stripping off SUBREG, so that we don't  
-     accept (subreg (const_int)) which will fail to reload. */         
-  if (CONSTANT_ADDRESS_P (xinsn)                                       
+  if (TARGET_DEBUG_B_MODE)
+    {
+      GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
+                 strict ? "" : "not ");
+      GO_DEBUG_RTX (xinsn);
+    }
+
+  /* Check for constant before stripping off SUBREG, so that we don't
+     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)))     
-    return 1;                                                          
-                                                                       
-  while (GET_CODE (xinsn) == SUBREG)                                   
-    xinsn = SUBREG_REG (xinsn);                                                
-                                                                       
-  /* The mips16 can only use the stack pointer as a base register when 
-     loading SImode or DImode values.  */                              
-  if (GET_CODE (xinsn) == REG 
-      && mips_reg_mode_ok_for_base_p (xinsn, mode, strict))    
-    return 1;                                                          
-                                                                       
-  if (GET_CODE (xinsn) == LO_SUM && mips_split_addresses)              
-    {                                                                  
-      register rtx xlow0 = XEXP (xinsn, 0);                            
-      register rtx xlow1 = XEXP (xinsn, 1);                            
-                                                                       
-      while (GET_CODE (xlow0) == SUBREG)                               
-       xlow0 = SUBREG_REG (xlow0);                                     
-      if (GET_CODE (xlow0) == REG                                      
+      && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))
+    return 1;
+
+  while (GET_CODE (xinsn) == SUBREG)
+    xinsn = SUBREG_REG (xinsn);
+
+  /* The mips16 can only use the stack pointer as a base register when
+     loading SImode or DImode values.  */
+  if (GET_CODE (xinsn) == REG
+      && mips_reg_mode_ok_for_base_p (xinsn, mode, strict))
+    return 1;
+
+  if (GET_CODE (xinsn) == LO_SUM && mips_split_addresses)
+    {
+      register rtx xlow0 = XEXP (xinsn, 0);
+      register rtx xlow1 = XEXP (xinsn, 1);
+
+      while (GET_CODE (xlow0) == SUBREG)
+       xlow0 = SUBREG_REG (xlow0);
+      if (GET_CODE (xlow0) == REG
          && mips_reg_mode_ok_for_base_p (xlow0, mode, strict)
          && mips_check_split (xlow1, mode))
-       return 1;                                                       
-    }                                                                  
-                                                                       
-  if (GET_CODE (xinsn) == PLUS)                                                
-    {                                                                  
-      register rtx xplus0 = XEXP (xinsn, 0);                           
-      register rtx xplus1 = XEXP (xinsn, 1);                           
-      register enum rtx_code code0;                                    
-      register enum rtx_code code1;                                    
-                                                                       
-      while (GET_CODE (xplus0) == SUBREG)                              
-       xplus0 = SUBREG_REG (xplus0);                                   
-      code0 = GET_CODE (xplus0);                                       
-                                                                       
-      while (GET_CODE (xplus1) == SUBREG)                              
-       xplus1 = SUBREG_REG (xplus1);                                   
-      code1 = GET_CODE (xplus1);                                       
-                                                                       
-      /* The mips16 can only use the stack pointer as a base register  
-         when loading SImode or DImode values.  */                     
-      if (code0 == REG 
-         && mips_reg_mode_ok_for_base_p (xplus0, mode, strict))        
-       {                                                               
+       return 1;
+    }
+
+  if (GET_CODE (xinsn) == PLUS)
+    {
+      register rtx xplus0 = XEXP (xinsn, 0);
+      register rtx xplus1 = XEXP (xinsn, 1);
+      register enum rtx_code code0;
+      register enum rtx_code code1;
+
+      while (GET_CODE (xplus0) == SUBREG)
+       xplus0 = SUBREG_REG (xplus0);
+      code0 = GET_CODE (xplus0);
+
+      while (GET_CODE (xplus1) == SUBREG)
+       xplus1 = SUBREG_REG (xplus1);
+      code1 = GET_CODE (xplus1);
+
+      /* The mips16 can only use the stack pointer as a base register
+         when loading SImode or DImode values.  */
+      if (code0 == REG
+         && mips_reg_mode_ok_for_base_p (xplus0, mode, strict))
+       {
          if (code1 == CONST_INT && SMALL_INT (xplus1))
            return 1;
-                                                                       
-         /* On the mips16, we represent GP relative offsets in RTL.    
-             These are 16 bit signed values, and can serve as register 
-             offsets.  */                                              
-         if (TARGET_MIPS16                                             
-             && mips16_gp_offset_p (xplus1))                           
-           return 1;                                                   
-                                                                       
-         /* For some code sequences, you actually get better code by   
-            pretending that the MIPS supports an address mode of a     
-            constant address + a register, even though the real        
-            machine doesn't support it.  This is because the           
-            assembler can use $r1 to load just the high 16 bits, add   
-            in the register, and fold the low 16 bits into the memory  
-            reference, whereas the compiler generates a 4 instruction  
-            sequence.  On the other hand, CSE is not as effective.     
-            It would be a win to generate the lui directly, but the    
-            MIPS assembler does not have syntax to generate the        
-            appropriate relocation.  */                                
-                                                                       
-         /* Also accept CONST_INT addresses here, so no else.  */      
-         /* Reject combining an embedded PIC text segment reference    
-            with a register.  That requires an additional              
-            instruction.  */                                           
-          /* ??? Reject combining an address with a register for the MIPS  
-            64 bit ABI, because the SGI assembler can not handle this.  */ 
-         if (!TARGET_DEBUG_A_MODE                                      
-             && (mips_abi == ABI_32                                    
-                 || mips_abi == ABI_O64                                
-                 || mips_abi == ABI_EABI)                              
-             && CONSTANT_ADDRESS_P (xplus1)                            
-             && ! mips_split_addresses                                 
-             && (!TARGET_EMBEDDED_PIC                                  
-                 || 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))
-             && !TARGET_MIPS16)                                        
-           return 1;                                                   
-       }                                                               
-    }                                                                  
-                                                                       
-  if (TARGET_DEBUG_B_MODE)                                             
+
+         /* On the mips16, we represent GP relative offsets in RTL.
+             These are 16 bit signed values, and can serve as register
+             offsets.  */
+         if (TARGET_MIPS16
+             && mips16_gp_offset_p (xplus1))
+           return 1;
+
+         /* For some code sequences, you actually get better code by
+            pretending that the MIPS supports an address mode of a
+            constant address + a register, even though the real
+            machine doesn't support it.  This is because the
+            assembler can use $r1 to load just the high 16 bits, add
+            in the register, and fold the low 16 bits into the memory
+            reference, whereas the compiler generates a 4 instruction
+            sequence.  On the other hand, CSE is not as effective.
+            It would be a win to generate the lui directly, but the
+            MIPS assembler does not have syntax to generate the
+            appropriate relocation.  */
+
+         /* Also accept CONST_INT addresses here, so no else.  */
+         /* Reject combining an embedded PIC text segment reference
+            with a register.  That requires an additional
+            instruction.  */
+          /* ??? Reject combining an address with a register for the MIPS
+            64 bit ABI, because the SGI assembler can not handle this.  */
+         if (!TARGET_DEBUG_A_MODE
+             && (mips_abi == ABI_32
+                 || mips_abi == ABI_O64
+                 || mips_abi == ABI_EABI)
+             && CONSTANT_ADDRESS_P (xplus1)
+             && ! mips_split_addresses
+             && (!TARGET_EMBEDDED_PIC
+                 || code1 != CONST
+                 || GET_CODE (XEXP (xplus1, 0)) != MINUS)
+             /* When assembling for machines with 64 bit registers,
+                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;
+       }
+    }
+
+  if (TARGET_DEBUG_B_MODE)
     GO_PRINTF ("Not a legitimate address\n");
-  
+
   /* The address was not legitimate.  */
   return 0;
 }
@@ -1797,7 +1822,7 @@ embedded_pic_offset (x)
       rtx seq;
 
       embedded_pic_fnaddr_rtx = gen_reg_rtx (Pmode);
-      
+
       /* Output code at function start to initialize the pseudo-reg.  */
       /* ??? We used to do this in FINALIZE_PIC, but that does not work for
         inline functions, because it is called after RTL for the function
@@ -1836,20 +1861,26 @@ mips_move_1word (operands, insn, unsignedp)
   enum rtx_code code0 = GET_CODE (op0);
   enum rtx_code code1 = GET_CODE (op1);
   enum machine_mode mode = GET_MODE (op0);
-  int subreg_word0 = 0;
-  int subreg_word1 = 0;
+  int subreg_offset0 = 0;
+  int subreg_offset1 = 0;
   enum delay_type delay = DELAY_NONE;
 
   while (code0 == SUBREG)
     {
-      subreg_word0 += SUBREG_WORD (op0);
+      subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
+                                            GET_MODE (SUBREG_REG (op0)),
+                                            SUBREG_BYTE (op0),
+                                            GET_MODE (op0));
       op0 = SUBREG_REG (op0);
       code0 = GET_CODE (op0);
     }
 
   while (code1 == SUBREG)
     {
-      subreg_word1 += SUBREG_WORD (op1);
+      subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
+                                            GET_MODE (SUBREG_REG (op1)),
+                                            SUBREG_BYTE (op1),
+                                            GET_MODE (op1));
       op1 = SUBREG_REG (op1);
       code1 = GET_CODE (op1);
     }
@@ -1860,11 +1891,11 @@ mips_move_1word (operands, insn, unsignedp)
 
   if (code0 == REG)
     {
-      int regno0 = REGNO (op0) + subreg_word0;
+      int regno0 = REGNO (op0) + subreg_offset0;
 
       if (code1 == REG)
        {
-         int regno1 = REGNO (op1) + subreg_word1;
+         int regno1 = REGNO (op1) + subreg_offset1;
 
          /* Just in case, don't do anything for assigning a register
             to itself, unless we are filling a delay slot.  */
@@ -2149,7 +2180,7 @@ mips_move_1word (operands, insn, unsignedp)
 
       if (code1 == REG)
        {
-         int regno1 = REGNO (op1) + subreg_word1;
+         int regno1 = REGNO (op1) + subreg_offset1;
 
          if (GP_REG_P (regno1))
            {
@@ -2197,7 +2228,7 @@ mips_move_1word (operands, insn, unsignedp)
 
          if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
            abort ();
-         
+
          sprintf (volatile_buffer, "%%{%s%%}", ret);
          ret = volatile_buffer;
        }
@@ -2228,13 +2259,16 @@ mips_move_2words (operands, insn)
   rtx op1 = operands[1];
   enum rtx_code code0 = GET_CODE (operands[0]);
   enum rtx_code code1 = GET_CODE (operands[1]);
-  int subreg_word0 = 0;
-  int subreg_word1 = 0;
+  int subreg_offset0 = 0;
+  int subreg_offset1 = 0;
   enum delay_type delay = DELAY_NONE;
 
   while (code0 == SUBREG)
     {
-      subreg_word0 += SUBREG_WORD (op0);
+      subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
+                                            GET_MODE (SUBREG_REG (op0)),
+                                            SUBREG_BYTE (op0),
+                                            GET_MODE (op0));
       op0 = SUBREG_REG (op0);
       code0 = GET_CODE (op0);
     }
@@ -2247,11 +2281,14 @@ mips_move_2words (operands, insn)
 
   while (code1 == SUBREG)
     {
-      subreg_word1 += SUBREG_WORD (op1);
+      subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
+                                            GET_MODE (SUBREG_REG (op1)),
+                                            SUBREG_BYTE (op1),
+                                            GET_MODE (op1));
       op1 = SUBREG_REG (op1);
       code1 = GET_CODE (op1);
     }
-      
+
   /* Sanity check.  */
   if (GET_CODE (operands[1]) == SIGN_EXTEND
       && code1 != REG
@@ -2265,11 +2302,11 @@ mips_move_2words (operands, insn)
 
   if (code0 == REG)
     {
-      int regno0 = REGNO (op0) + subreg_word0;
+      int regno0 = REGNO (op0) + subreg_offset0;
 
       if (code1 == REG)
        {
-         int regno1 = REGNO (op1) + subreg_word1;
+         int regno1 = REGNO (op1) + subreg_offset1;
 
          /* Just in case, don't do anything for assigning a register
             to itself, unless we are filling a delay slot.  */
@@ -2384,7 +2421,7 @@ mips_move_2words (operands, insn)
                       or higher.  For !TARGET_64BIT && gp registers we
                       need to avoid this by using two li instructions
                       instead.  */
-                   if (ISA_HAS_64BIT_REGS 
+                   if (ISA_HAS_64BIT_REGS
                        && ! TARGET_64BIT
                        && ! FP_REG_P (regno0))
                      {
@@ -2452,7 +2489,7 @@ mips_move_2words (operands, insn)
                      : "mt%0\t%.\n");
            }
        }
-       
+
       else if (code1 == CONST_INT && GET_MODE (op0) == DImode
               && GP_REG_P (regno0))
        {
@@ -2529,12 +2566,9 @@ mips_move_2words (operands, insn)
            }
 
          else if (double_memory_operand (op1, GET_MODE (op1)))
-           {
-             operands[2] = adj_offsettable_operand (op1, 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))
            {
@@ -2606,7 +2640,7 @@ mips_move_2words (operands, insn)
     {
       if (code1 == REG)
        {
-         int regno1 = REGNO (op1) + subreg_word1;
+         int regno1 = REGNO (op1) + subreg_offset1;
 
          if (FP_REG_P (regno1))
            ret = "s.d\t%1,%0";
@@ -2623,10 +2657,7 @@ mips_move_2words (operands, insn)
            }
 
          else if (double_memory_operand (op0, GET_MODE (op0)))
-           {
-             operands[2] = adj_offsettable_operand (op0, 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)
@@ -2638,10 +2669,7 @@ mips_move_2words (operands, insn)
          if (TARGET_64BIT)
            ret = "sd\t%.,%0";
          else
-           {
-             operands[2] = adj_offsettable_operand (op0, 4);
-             ret = "sw\t%.,%0\n\tsw\t%.,%2";
-           }
+           ret = "sw\t%.,%0\n\tsw\t%.,%D0";
        }
 
       if (TARGET_STATS)
@@ -2653,7 +2681,7 @@ mips_move_2words (operands, insn)
 
          if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
            abort ();
-         
+
          sprintf (volatile_buffer, "%%{%s%%}", ret);
          ret = volatile_buffer;
        }
@@ -2700,7 +2728,7 @@ mips_address_cost (addr)
          return 2;
       }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case SYMBOL_REF:
       return SYMBOL_REF_FLAG (addr) ? 1 : 2;
@@ -2740,7 +2768,7 @@ mips_address_cost (addr)
   return 4;
 }
 
-/* Return nonzero if X is an address which needs a temporary register when 
+/* Return nonzero if X is an address which needs a temporary register when
    reloaded while generating PIC code.  */
 
 int
@@ -2960,6 +2988,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
@@ -3051,7 +3081,7 @@ gen_conditional_branch (operands, test_code)
       emit_insn (gen_rtx_SET (VOIDmode, reg,
                              gen_rtx (test_code == NE ? EQ : test_code,
                                       CCmode, cmp0, cmp1)));
-      
+
       test_code = test_code == NE ? EQ : NE;
       mode = CCmode;
       cmp0 = reg;
@@ -3148,7 +3178,7 @@ gen_conditional_move (operands)
     }
   else if (cmp_code == NE)
     cmp_code = EQ, move_code = EQ;
-         
+
   if (mode == SImode || mode == DImode)
     cmp_mode = mode;
   else if (mode == SFmode || mode == DFmode)
@@ -3240,11 +3270,11 @@ block_move_loop (dest_reg, src_reg, bytes, align, orig_dest, orig_src)
      rtx src_reg;              /* register holding source address */
      unsigned int bytes;       /* # bytes to move */
      int align;                        /* alignment */
-     rtx orig_dest;            /* original dest for change_address */
+     rtx orig_dest;            /* original dest */
      rtx orig_src;             /* original source for making a reg note */
 {
-  rtx dest_mem = change_address (orig_dest, BLKmode, dest_reg);
-  rtx src_mem = change_address (orig_src, BLKmode, src_reg);
+  rtx dest_mem = replace_equiv_address (orig_dest, dest_reg);
+  rtx src_mem = replace_equiv_address (orig_src, src_reg);
   rtx align_rtx = GEN_INT (align);
   rtx label;
   rtx final_src;
@@ -3373,12 +3403,12 @@ expand_block_move (operands)
   else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES
           && align == (unsigned) UNITS_PER_WORD)
     move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD);
-       
+
   else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES)
-    emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
-                                                     dest_reg),
-                                     change_address (orig_src, BLKmode,
-                                                     src_reg),
+    emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest,
+                                                            dest_reg),
+                                     replace_equiv_address (orig_src,
+                                                            src_reg),
                                      bytes_rtx, align_rtx));
 
   else if (constp && align >= (unsigned) UNITS_PER_WORD && optimize)
@@ -3425,10 +3455,10 @@ expand_block_move (operands)
 
       /* Bytes at the end of the loop.  */
       if (leftover)
-       emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
-                                                         dest_reg),
-                                         change_address (orig_src, BLKmode,
-                                                         src_reg),
+       emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest,
+                                                                dest_reg),
+                                         replace_equiv_address (orig_src,
+                                                                src_reg),
                                          GEN_INT (leftover),
                                          GEN_INT (align)));
     }
@@ -3437,7 +3467,7 @@ expand_block_move (operands)
     block_move_call (dest_reg, src_reg, bytes_rtx);
 }
 \f
-/* Emit load/stores for a small constant block_move. 
+/* Emit load/stores for a small constant block_move.
 
    operands[0] is the memory address of the destination.
    operands[1] is the memory address of the source.
@@ -3451,7 +3481,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)
@@ -3507,7 +3537,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))
        {
@@ -3821,11 +3853,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)
@@ -3937,7 +3970,7 @@ function_arg (cum, mode, type, named)
       fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type);
       fprintf (stderr, ", %d ) = ", named);
     }
-  
+
 
   cum->last_arg_fp = 0;
   switch (mode)
@@ -3965,6 +3998,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;
@@ -4034,10 +4072,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
@@ -4094,13 +4152,14 @@ 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);
                  else
                    reg = gen_rtx_REG (word_mode, regno);
-                 
-                 XVECEXP (ret, 0, i) 
+
+                 XVECEXP (ret, 0, i)
                    = gen_rtx_EXPR_LIST (VOIDmode, reg,
                                         GEN_INT (bitpos / BITS_PER_UNIT));
 
@@ -4134,7 +4193,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);
@@ -4210,15 +4271,15 @@ function_arg_partial_nregs (cum, mode, type, named)
 \f
 /* Create the va_list data type.
    We keep 3 pointers, and two offsets.
-   Two pointers are to the overflow area, which starts at the CFA. 
+   Two pointers are to the overflow area, which starts at the CFA.
      One of these is constant, for addressing into the GPR save area below it.
      The other is advanced up the stack through the overflow region.
    The third pointer is to the GPR save area.  Since the FPR save area
      is just below it, we can address FPR slots off this pointer.
    We also keep two one-byte offsets, which are to be subtracted from the
      constant pointers to yield addresses in the GPR and FPR save areas.
-     These are downcounted as float or non-float arguments are used, 
-     and when they get to zero, the argument must be obtained from the 
+     These are downcounted as float or non-float arguments are used,
+     and when they get to zero, the argument must be obtained from the
      overflow region.
    If TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT, then no FPR save area exists,
      and a single pointer is enough.  It's started at the GPR save area,
@@ -4226,7 +4287,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
@@ -4289,7 +4350,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;
@@ -4298,8 +4359,8 @@ mips_va_start (stdarg_p, valist, nextarg)
 
       if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
        {
-         tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff; 
-         tree ovfl, gtop, ftop, goff, foff; 
+         tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+         tree ovfl, gtop, ftop, goff, foff;
          tree gprv;
          int float_formals, fpr_offset, size_excess, floats_passed_in_regs;
          int fpr_save_offset;
@@ -4325,7 +4386,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;
@@ -4338,8 +4399,8 @@ mips_va_start (stdarg_p, valist, nextarg)
             8 byte boundary.  This means that the above calculation should
             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. */
+            into the code which sets the current_function_args_info struct.
+            The above then reduces to a fetch from that struct.  */
 
 
          t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
@@ -4349,7 +4410,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);
@@ -4359,7 +4420,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)
@@ -4368,7 +4429,7 @@ mips_va_start (stdarg_p, valist, nextarg)
                fpr_save_offset += 4;
            }
          if (fpr_save_offset)
-           gprv = build (PLUS_EXPR, TREE_TYPE (ftop), gprv, 
+           gprv = build (PLUS_EXPR, TREE_TYPE (ftop), gprv,
                build_int_2 (-fpr_save_offset,-1));
          t = build (MODIFY_EXPR, TREE_TYPE (ftop), ftop, gprv);
          expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -4401,7 +4462,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)
@@ -4424,6 +4485,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;
        }
@@ -4450,20 +4513,23 @@ mips_va_arg (valist, type)
     {
       int indirect;
       rtx r, lab_over = NULL_RTX, lab_false;
-      tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff; 
-      tree ovfl, gtop, ftop, goff, foff; 
+      tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+      tree ovfl, gtop, ftop, goff, foff;
 
       indirect
        = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
       if (indirect)
-       size = rsize = POINTER_SIZE / BITS_PER_UNIT;
+       {
+         size = POINTER_SIZE / BITS_PER_UNIT;
+         rsize = UNITS_PER_WORD;
+       }
 
       addr_rtx = gen_reg_rtx (Pmode);
 
       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
@@ -4472,13 +4538,13 @@ mips_va_arg (valist, type)
            {
              t = build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
                     build_int_2 (2*UNITS_PER_WORD - 1, 0));
-             t = build (BIT_AND_EXPR, TREE_TYPE (t), t, 
+             t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
                     build_int_2 (-2*UNITS_PER_WORD, -1));
              t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
              expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
            }
 
-         t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr, 
+         t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
                size_int (rsize));
          r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
          if (r != addr_rtx)
@@ -4490,7 +4556,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
@@ -4501,7 +4567,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);
@@ -4521,7 +4587,7 @@ 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,
@@ -4533,7 +4599,7 @@ mips_va_arg (valist, type)
           if (r != addr_rtx)
            emit_move_insn (addr_rtx, r);
 
-          /* Emit code for foff-=8. 
+          /* Emit code for foff-=8.
             Advances the offset up FPR save area by one double */
           t = build (MINUS_EXPR, TREE_TYPE (foff), foff, build_int_2 (8, 0));
           t = build (MODIFY_EXPR, TREE_TYPE (foff), foff, t);
@@ -4543,13 +4609,13 @@ mips_va_arg (valist, type)
           emit_jump (lab_over);
           emit_barrier ();
           emit_label (lab_false);
-             
-         if (!TARGET_64BIT) 
+
+         if (!TARGET_64BIT)
            {
              /* 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);
@@ -4558,8 +4624,8 @@ 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. */
-          t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl, 
+            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);
           if (r != addr_rtx)
@@ -4578,37 +4644,37 @@ mips_va_arg (valist, type)
              && TREE_CODE (type) == INTEGER_TYPE
              && TYPE_PRECISION (type) == 64)
            {
-             /* In mips2, int takes 32 bits of the GPR save area, but 
+             /* 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 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. */
-          t = build (MINUS_EXPR, TREE_TYPE (goff), goff, 
+            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);
           expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -4617,9 +4683,9 @@ mips_va_arg (valist, type)
           emit_jump (lab_over);
           emit_barrier ();
           emit_label (lab_false);
-             
+
           /* Emit code for addr_rtx -> overflow area, postinc by step_size */
-          t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl, 
+          t = build (POSTINCREMENT_EXPR, TREE_TYPE(ovfl), ovfl,
                size_int (step_size));
           r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
           if (r != addr_rtx)
@@ -4631,7 +4697,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
@@ -4644,10 +4710,10 @@ mips_va_arg (valist, type)
     }
   else
     {
-      /* Not EABI. */
+      /* Not EABI.  */
       int align;
 
-      /* ??? The original va-mips.h did always align, despite the fact 
+      /* ??? The original va-mips.h did always align, despite the fact
         that alignments <= UNITS_PER_WORD are preserved by the va_arg
         increment mechanism.  */
 
@@ -4657,7 +4723,7 @@ mips_va_arg (valist, type)
        align = 8;
       else
        align = 4;
-       
+
       t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
                 build_int_2 (align - 1, 0));
       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
@@ -4690,6 +4756,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;
 
@@ -4700,8 +4767,8 @@ 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.  We assume here that the specs prevent both being set by the
+     user.  */
 #ifdef TARGET_DEFAULT
   if (TARGET_SINGLE_FLOAT && TARGET_SOFT_FLOAT)
     target_flags &= ~((TARGET_DEFAULT) & (MASK_SOFT_FLOAT | MASK_SINGLE_FLOAT));
@@ -4730,7 +4797,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;
@@ -4744,7 +4814,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"))
@@ -4757,21 +4827,31 @@ 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)
+  if (mips_abi_string == 0 && mips_isa_string
+      && 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 
+  else if (mips_isa_string == 0 && mips_abi_string
           && mips_abi != ABI_EABI && mips_abi != ABI_O64)
     {
       if (mips_abi == ABI_32)
@@ -4781,13 +4861,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);
     }
 
@@ -4803,10 +4883,6 @@ 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.");
@@ -4817,142 +4893,148 @@ override_options ()
      greater than that supported by the default processor, then the user gets
      an error.  Normally, the compiler will just default to the base level cpu
      for the indicated isa.  */
-  if (mips_cpu_string == 0)
-    mips_cpu_string = MIPS_CPU_STRING_DEFAULT;
+  if (mips_arch_string == 0)
+    mips_arch_string = MIPS_CPU_STRING_DEFAULT;
+  if (mips_tune_string == 0)
+    mips_tune_string = MIPS_CPU_STRING_DEFAULT;
 #endif
 
   /* Identify the processor type.  */
-  if (mips_cpu_string == 0
-      || ! strcmp (mips_cpu_string, "default")
-      || ! strcmp (mips_cpu_string, "DEFAULT"))
+
+  if (mips_cpu_string != 0)
+    {
+      mips_cpu = mips_parse_cpu (mips_cpu_string);
+      if (mips_cpu == PROCESSOR_DEFAULT)
+       {
+         error ("bad value (%s) for -mcpu= switch", mips_arch_string);
+         mips_cpu_string = "default";
+       }
+      mips_arch = mips_cpu;
+      mips_tune = mips_cpu;
+    }
+
+  if (mips_arch_string == 0
+      || ! strcmp (mips_arch_string, "default")
+      || ! strcmp (mips_arch_string, "DEFAULT"))
     {
       switch (mips_isa)
        {
        default:
-         mips_cpu_string = "3000";
-         mips_cpu = PROCESSOR_R3000;
+         mips_arch_string = "3000";
+         mips_arch = PROCESSOR_R3000;
          break;
        case 2:
-         mips_cpu_string = "6000";
-         mips_cpu = PROCESSOR_R6000;
+         mips_arch_string = "6000";
+         mips_arch = PROCESSOR_R6000;
          break;
        case 3:
-         mips_cpu_string = "4000";
-         mips_cpu = PROCESSOR_R4000;
+         mips_arch_string = "4000";
+         mips_arch = PROCESSOR_R4000;
          break;
        case 4:
-         mips_cpu_string = "8000";
-         mips_cpu = PROCESSOR_R8000;
+         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
     {
-      const char *p = mips_cpu_string;
-      int seen_v = 0;
-
-      /* We need to cope with the various "vr" prefixes for the NEC 4300
-        and 4100 processors.  */
-      if (*p == 'v' || *p == 'V')
-       seen_v = 1, p++;
-
-      if (*p == 'r' || *p == 'R')
-       p++;
-
-      /* Since there is no difference between a R2000 and R3000 in
-        terms of the scheduler, we collapse them into just an R3000.  */
-
-      mips_cpu = PROCESSOR_DEFAULT;
-      switch (*p)
+      mips_arch = mips_parse_cpu (mips_arch_string);
+      if (mips_arch == PROCESSOR_DEFAULT)
        {
-       case '2':
-         if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
-           mips_cpu = PROCESSOR_R3000;
-         break;
-
-       case '3':
-         if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K"))
-           mips_cpu = PROCESSOR_R3000;
-         else if (!strcmp (p, "3900"))
-           mips_cpu = PROCESSOR_R3900;
+         error ("bad value (%s) for -march= switch", mips_arch_string);
+         mips_arch_string = "default";
+       }
+    }
+  if (mips_tune_string == 0
+      || ! strcmp (mips_tune_string, "default")
+      || ! strcmp (mips_tune_string, "DEFAULT"))
+    {
+      if (mips_arch != PROCESSOR_DEFAULT)
+       mips_tune = mips_arch;
+      else
+      switch (mips_isa)
+       {
+       default:
+         mips_tune_string = "3000";
+         mips_tune = PROCESSOR_R3000;
          break;
-
-       case '4':
-         if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K"))
-           mips_cpu = PROCESSOR_R4000;
-          /* The vr4100 is a non-FP ISA III processor with some extra
-             instructions.  */
-         else if (!strcmp (p, "4100"))
-           {
-              mips_cpu = PROCESSOR_R4100;
-              target_flags |= MASK_SOFT_FLOAT ;
-           }
-         /* The vr4300 is a standard ISA III processor, but with a different
-            pipeline.  */
-         else if (!strcmp (p, "4300"))
-            mips_cpu = PROCESSOR_R4300;
-         /* The r4400 is exactly the same as the r4000 from the compiler's
-            viewpoint.  */
-         else if (!strcmp (p, "4400"))
-           mips_cpu = PROCESSOR_R4000;
-         else if (!strcmp (p, "4600"))
-           mips_cpu = PROCESSOR_R4600;
-         else if (!strcmp (p, "4650"))
-           mips_cpu = PROCESSOR_R4650;
+       case 2:
+         mips_tune_string = "6000";
+         mips_tune = PROCESSOR_R6000;
          break;
-
-       case '5':
-         if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
-           mips_cpu = PROCESSOR_R5000;
+       case 3:
+         mips_tune_string = "4000";
+         mips_tune = PROCESSOR_R4000;
          break;
-
-       case '6':
-         if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
-           mips_cpu = PROCESSOR_R6000;
+       case 4:
+         mips_tune_string = "8000";
+         mips_tune = PROCESSOR_R8000;
          break;
-
-       case '8':
-         if (!strcmp (p, "8000"))
-           mips_cpu = PROCESSOR_R8000;
+       case 32:
+         mips_arch_string = "4kc";
+         mips_arch = PROCESSOR_R4KC;
          break;
-
-       case 'o':
-         if (!strcmp (p, "orion"))
-           mips_cpu = PROCESSOR_R4600;
+       case 64:
+         mips_arch_string = "5kc";
+         mips_arch = PROCESSOR_R5KC;
          break;
        }
 
-      if (seen_v
-         && mips_cpu != PROCESSOR_R4300
-         && mips_cpu != PROCESSOR_R4100
-         && mips_cpu != PROCESSOR_R5000)
-       mips_cpu = PROCESSOR_DEFAULT;
-
-      if (mips_cpu == PROCESSOR_DEFAULT)
+    }
+  else
+    {
+       mips_tune = mips_parse_cpu (mips_tune_string);
+      if (mips_tune == PROCESSOR_DEFAULT)
        {
-         error ("bad value (%s) for -mcpu= switch", mips_cpu_string);
-         mips_cpu_string = "default";
+         error ("bad value (%s) for -mtune= switch", mips_tune_string);
+         mips_tune_string = "default";
        }
     }
 
-  if ((mips_cpu == PROCESSOR_R3000 && (mips_isa != 1))
-      || (mips_cpu == PROCESSOR_R6000 && mips_isa != 1 && mips_isa != 2)
-      || ((mips_cpu == PROCESSOR_R4000
-           || mips_cpu == PROCESSOR_R4100
-           || mips_cpu == PROCESSOR_R4300
-          || mips_cpu == PROCESSOR_R4600
-          || mips_cpu == PROCESSOR_R4650)
+  /* Handle processor configuration based on architecture.  */
+  if (TARGET_MIPS4100
+      || TARGET_MIPS3900
+      || TARGET_MIPS4KC
+      || TARGET_MIPS5KC)
+    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_R4600
+          || mips_arch == PROCESSOR_R4650)
          && mips_isa != 1 && mips_isa != 2 && mips_isa != 3))
-    error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa);
+    error ("-march=%s does not support -mips%d", mips_arch_string, mips_isa);
 
   /* make sure sizes of ints/longs/etc. are ok */
   if (! ISA_HAS_64BIT_REGS)
     {
       if (TARGET_FLOAT64)
-       fatal ("-mips%d does not support 64 bit fp registers", mips_isa);
+       {
+         error ("-mips%d does not support 64 bit fp registers", mips_isa);
+         target_flags &= ~ MASK_FLOAT64;
+       }
 
       else if (TARGET_64BIT)
-       fatal ("-mips%d does not support 64 bit gp registers", mips_isa);
+       {
+         error ("-mips%d does not support 64 bit gp registers", mips_isa);
+         target_flags &= ~MASK_64BIT;
+       }
     }
 
   if (mips_abi != ABI_32 && mips_abi != ABI_O64)
@@ -5019,8 +5101,7 @@ override_options ()
      reg_names points into via the REGISTER_NAMES macro.  */
 
   if (TARGET_NAME_REGS)
-    bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names,
-          sizeof (mips_reg_names));
+    memcpy (mips_reg_names, mips_sw_reg_names, sizeof (mips_reg_names));
 
   /* When compiling for the mips16, we can not use floating point.  We
      record the original hard float value in mips16_hard_float.  */
@@ -5142,7 +5223,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))
@@ -5168,11 +5256,11 @@ override_options ()
   /* Provide default values for align_* for 64-bit targets.  */
   if (TARGET_64BIT && !TARGET_MIPS16)
     {
-      if (align_loops == 0) 
+      if (align_loops == 0)
        align_loops = 8;
-      if (align_jumps == 0) 
+      if (align_jumps == 0)
        align_jumps = 8;
-      if (align_functions == 0) 
+      if (align_functions == 0)
        align_functions = 8;
     }
 
@@ -5272,7 +5360,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.
@@ -5390,7 +5478,7 @@ print_operand (file, op, letter)
            fputs (".set\tnoat\n\t", file);
          break;
 
-       case ']': 
+       case ']':
          if (set_noat == 0)
            error ("internal error: %%] found without a %%[ in assembler pattern");
          else if (--set_noat == 0)
@@ -5543,7 +5631,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)
@@ -5569,8 +5662,7 @@ print_operand (file, op, letter)
     fputs (reg_names[GP_REG_FIRST], file);
 
   else if (letter == 'd' || letter == 'x' || letter == 'X')
-    fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT",
-          letter);
+    output_operand_lossage ("invalid use of %%d, %%x, or %%X");
 
   else if (letter == 'B')
     fputs (code == EQ ? "z" : "n", file);
@@ -5775,59 +5867,6 @@ mips_output_external_libcall (file, name)
 }
 #endif
 \f
-/* Compute a string to use as a temporary file name.  */
-
-/* On MSDOS, write temp files in current dir
-   because there's no place else we can expect to use.  */
-#if __MSDOS__
-#ifndef P_tmpdir
-#define P_tmpdir "./"
-#endif
-#endif
-
-static FILE *
-mips_make_temp_file ()
-{
-  FILE *stream;
-  const char *base = getenv ("TMPDIR");
-  int len;
-
-  if (base == 0)
-    {
-#ifdef P_tmpdir
-      if (access (P_tmpdir, R_OK | W_OK) == 0)
-       base = P_tmpdir;
-      else
-#endif
-       if (access ("/usr/tmp", R_OK | W_OK) == 0)
-         base = "/usr/tmp/";
-       else
-         base = "/tmp/";
-    }
-
-  len = strlen (base);
-  /* temp_filename is global, so we must use malloc, not alloca.  */
-  temp_filename = (char *) xmalloc (len + sizeof("/ctXXXXXX"));
-  strcpy (temp_filename, base);
-  if (len > 0 && temp_filename[len-1] != '/')
-    temp_filename[len++] = '/';
-
-  strcpy (temp_filename + len, "ctXXXXXX");
-  mktemp (temp_filename);
-
-  stream = fopen (temp_filename, "w+");
-  if (!stream)
-    pfatal_with_name (temp_filename);
-
-#ifndef __MSDOS__
-  /* In MSDOS, we cannot unlink the temporary file until we are finished using
-     it.  Otherwise, we delete it now, so that it will be gone even if the
-     compiler happens to crash.  */
-  unlink (temp_filename);
-#endif
-  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.  */
@@ -5854,7 +5893,7 @@ mips_output_filename (stream, name)
   else if (write_symbols == DBX_DEBUG)
     {
       ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
-      fprintf (stream, "%s ", ASM_STABS_OP);
+      fprintf (stream, "%s", ASM_STABS_OP);
       output_quoted_string (stream, name);
       fprintf (stream, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
     }
@@ -5893,21 +5932,99 @@ mips_output_lineno (stream, line)
   if (write_symbols == DBX_DEBUG)
     {
       ++sym_lineno;
-      fprintf (stream, "%sLM%d:\n\t%s %d,0,%d,%sLM%d\n",
+      fprintf (stream, "%sLM%d:\n%s%d,0,%d,%sLM%d\n",
               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",
               (ignore_line_number) ? "#" : "",
               num_source_filenames, line);
-  
+
       LABEL_AFTER_LOC (stream);
     }
 }
 \f
+/* Output an ASCII string, in a space-saving way.  */
+
+void
+mips_output_ascii (stream, string_param, len)
+     FILE *stream;
+     const char *string_param;
+     size_t len;
+{
+  size_t i;
+  int cur_pos = 17;
+  register const unsigned char *string =
+    (const unsigned char *)string_param;
+
+  fprintf (stream, "\t.ascii\t\"");
+  for (i = 0; i < len; i++)
+    {
+      register int c = string[i];
+
+      switch (c)
+       {
+       case '\"':
+       case '\\':
+         putc ('\\', stream);
+         putc (c, stream);
+         cur_pos += 2;
+         break;
+
+       case TARGET_NEWLINE:
+         fputs ("\\n", stream);
+         if (i+1 < len
+             && (((c = string[i+1]) >= '\040' && c <= '~')
+                 || c == TARGET_TAB))
+           cur_pos = 32767;            /* break right here */
+         else
+           cur_pos += 2;
+         break;
+
+       case TARGET_TAB:
+         fputs ("\\t", stream);
+         cur_pos += 2;
+         break;
+
+       case TARGET_FF:
+         fputs ("\\f", stream);
+         cur_pos += 2;
+         break;
+
+       case TARGET_BS:
+         fputs ("\\b", stream);
+         cur_pos += 2;
+         break;
+
+       case TARGET_CR:
+         fputs ("\\r", stream);
+         cur_pos += 2;
+         break;
+
+       default:
+         if (c >= ' ' && c < 0177)
+           {
+             putc (c, stream);
+             cur_pos++;
+           }
+         else
+           {
+             fprintf (stream, "\\%03o", c);
+             cur_pos += 4;
+           }
+       }
+
+      if (cur_pos > 72 && i+1 < len)
+       {
+         cur_pos = 17;
+         fprintf (stream, "\"\n\t.ascii\t\"");
+       }
+    }
+  fprintf (stream, "\"\n");
+}
+\f
 /* If defined, a C statement to be executed just prior to the output of
    assembler code for INSN, to modify the extracted operands so they will be
    output differently.
@@ -5973,6 +6090,8 @@ void
 mips_asm_file_start (stream)
      FILE *stream;
 {
+  const char * abi_string = NULL;
+
   ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
 
   /* Versions of the MIPS assembler before 2.20 generate errors if a branch
@@ -5983,38 +6102,66 @@ 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.  */
+
+      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 ".abicalls"
+#define ABICALLS_ASM_OP "\t.abicalls"
 #endif
   if (TARGET_ABICALLS)
     /* ??? but do not want this (or want pic0) if -non-shared? */
-    fprintf (stream, "\t%s\n", ABICALLS_ASM_OP);
+    fprintf (stream, "%s\n", ABICALLS_ASM_OP);
 
   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;
 
   if (flag_verbose_asm)
-    fprintf (stream, "\n%s -G value = %d, Cpu = %s, ISA = %d\n",
+    fprintf (stream, "\n%s -G value = %d, Arch = %s, ISA = %d\n",
             ASM_COMMENT_START,
-            mips_section_threshold, mips_cpu_string, mips_isa);
+            mips_section_threshold, mips_arch_string, mips_isa);
 }
 \f
 /* If we are optimizing the global pointer, emit the text section now and any
@@ -6026,10 +6173,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 ())
     {
@@ -6061,28 +6206,33 @@ 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 (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)
-         pfatal_with_name (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)
-       pfatal_with_name (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)
-       pfatal_with_name (temp_filename);
+  if (ferror (from))
+    fatal_io_error ("can't read from temp file");
 
-#ifdef __MSDOS__
-      unlink (temp_filename);
-#endif
-    }
+  if (fclose (from))
+    fatal_io_error ("can't close temp file");
 }
 
 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
@@ -6201,7 +6351,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 */
@@ -6271,6 +6421,20 @@ compute_frame_size (size)
        }
     }
 
+  /* We need to restore these for the handler.  */
+  if (current_function_calls_eh_return)
+    {
+      unsigned int i;
+      for (i = 0; ; ++i)
+       {
+         regno = EH_RETURN_DATA_REGNO (i);
+         if (regno == INVALID_REGNUM)
+           break;
+         gp_reg_size += GET_MODE_SIZE (gpr_mode);
+         mask |= 1L << (regno - GP_REG_FIRST);
+       }
+    }
+
   /* Calculate space needed for fp registers.  */
   if (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT)
     {
@@ -6304,7 +6468,7 @@ compute_frame_size (size)
      The gp reg is callee saved in the 64 bit ABI, so all routines must
      save the gp reg.  This is not a leaf routine if -p, because of the
      call to mcount.  */
-  if (total_size == extra_size 
+  if (total_size == extra_size
       && (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
       && ! profile_flag)
     total_size = extra_size = 0;
@@ -6387,6 +6551,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 */
@@ -6396,6 +6659,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;
@@ -6408,6 +6672,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;
 
@@ -6431,8 +6701,9 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                       - GET_MODE_SIZE (gpr_mode));
 
       if (gp_offset < 0 || end_offset < 0)
-       fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
-              (long) gp_offset, (long) end_offset);
+       internal_error
+         ("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
          before adjusting the stack pointer, and load them afterward.  */
@@ -6456,8 +6727,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",
@@ -6466,60 +6735,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 & 0xffff0000));
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 insn
-                   = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
-                                            GEN_INT (gp_offset & 0x0000ffff)));
-                 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
@@ -6546,7 +6765,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
@@ -6571,13 +6791,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
@@ -6589,50 +6804,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;
@@ -6648,8 +6863,9 @@ save_restore_insns (store_p, large_reg, large_offset, file)
       end_offset = fp_offset - (current_frame_info.fp_reg_size - fp_size);
 
       if (fp_offset < 0 || end_offset < 0)
-       fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
-              (long) fp_offset, (long) end_offset);
+       internal_error
+         ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
+          (long) fp_offset, (long) end_offset);
 
       else if (fp_offset < 32768)
        base_reg_rtx = stack_pointer_rtx, base_offset  = 0;
@@ -6673,8 +6889,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
@@ -6684,61 +6898,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 & 0xffff0000));
-                 if (store_p)
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 insn = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
-                                               GEN_INT (fp_offset & 0x0000ffff)));
-                 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
@@ -6757,13 +6920,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);
              }
@@ -6786,15 +6947,15 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 \f
 /* Set up the stack and frame (if desired) for the function.  */
 
-void
-function_prologue (file, size)
+static void
+mips_output_function_prologue (file, size)
      FILE *file;
      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
 {
 #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));
 
@@ -6838,9 +6999,9 @@ 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,
@@ -6856,7 +7017,7 @@ 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 ())
@@ -6917,11 +7078,10 @@ 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)))
@@ -6985,7 +7145,7 @@ 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);
        }
 
@@ -7030,11 +7190,11 @@ mips_expand_prologue ()
 
   /* For arguments passed in registers, find the register number
      of the first argument in the variable part of the argument list,
-     otherwise GP_ARG_LAST+1.  Note also if the last argument is 
+     otherwise GP_ARG_LAST+1.  Note also if the last argument is
      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;
@@ -7105,13 +7265,22 @@ mips_expand_prologue ()
 
       for (i = 0; i < num; i++)
        {
-         rtx pattern = RTVEC_ELT (adjust, i);
+         rtx insn, pattern;
+
+         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");
-
          PUT_CODE (SET_SRC (pattern), ASHIFTRT);
-         emit_insn (pattern);
+
+         insn = emit_insn (pattern);
+
+         /* Global life information isn't valid at this point, so we
+            can't check whether these shifts are actually used.  Mark
+            them MAYBE_DEAD so that flow2 will remove them, and not
+            complain about dead code in the prologue.  */
+         REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
+                                              REG_NOTES (insn));
        }
     }
 
@@ -7128,7 +7297,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;
 
@@ -7230,44 +7399,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 & 0xffff0000));
-                 RTX_FRAME_RELATED_P (insn) = 1;
-                 insn = emit_insn (gen_iorsi3 (tmp_rtx, tmp_rtx,
-                                               GEN_INT (tsize & 0x0000ffff)));
-                 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));
 
-         RTX_FRAME_RELATED_P (insn) = 1;
+         dwarf_pattern = gen_rtx_SET (Pmode, stack_pointer_rtx,
+                                      plus_constant (stack_pointer_rtx,
+                                                     -tsize));
+
+         mips_annotate_frame_insn (insn, dwarf_pattern);
        }
 
       if (! mips_entry)
@@ -7362,17 +7515,17 @@ mips_expand_prologue ()
 }
 \f
 /* Do any necessary cleanup after a function to restore stack, frame,
-   and regs. */
+   and regs.  */
 
-#define RA_MASK 0x80000000L    /* 1 << 31 */
+#define RA_MASK BITMASK_HIGH   /* 1 << 31 */
 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
 
-void
-function_epilogue (file, size)
+static void
+mips_output_function_epilogue (file, size)
      FILE *file ATTRIBUTE_UNUSED;
      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
 {
-  const char *fnname;
+  const char *fnname = "";     /* FIXME: Correct initialisation?  */
 
 #ifndef FUNCTION_NAME_ALREADY_DECLARED
   /* Get the function name the same way that toplev.c does before calling
@@ -7455,9 +7608,11 @@ 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.  */
@@ -7519,7 +7674,7 @@ mips_expand_epilogue ()
                                           g6_rtx));
                  tsize = 0;
                }
-             
+
              if (tsize && tsize != orig_tsize)
                tsize_rtx = GEN_INT (tsize);
            }
@@ -7547,13 +7702,27 @@ mips_expand_epilogue ()
       if (tsize > 32767 && TARGET_MIPS16)
        abort ();
 
+      if (current_function_calls_eh_return)
+       {
+         rtx eh_ofs = EH_RETURN_STACKADJ_RTX;
+         if (Pmode == DImode)
+           emit_insn (gen_adddi3 (eh_ofs, eh_ofs, tsize_rtx));
+         else
+           emit_insn (gen_addsi3 (eh_ofs, eh_ofs, tsize_rtx));
+         tsize_rtx = eh_ofs;
+       }
+
       emit_insn (gen_blockage ());
-      if (Pmode == DImode && tsize != 0)
-       emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
-                              tsize_rtx));
-      else if (tsize != 0)
-       emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                              tsize_rtx));
+
+      if (tsize != 0 || current_function_calls_eh_return)
+       {
+         if (Pmode == DImode)
+           emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  tsize_rtx));
+         else
+           emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  tsize_rtx));
+       }
     }
 
   /* The mips16 loads the return address into $7, not $31.  */
@@ -7608,7 +7777,7 @@ symbolic_expression_p (x)
 
   if (GET_CODE (x) == CONST)
     return symbolic_expression_p (XEXP (x, 0));
-  
+
   if (GET_RTX_CLASS (GET_CODE (x)) == '1')
     return symbolic_expression_p (XEXP (x, 0));
 
@@ -7645,7 +7814,7 @@ mips_select_rtx_section (mode, x)
     {
       /* For hosted applications, always put constants in small data if
         possible, as this gives the best performance.  */
-     
+
       if (GET_MODE_SIZE (mode) <= (unsigned) mips_section_threshold
          && mips_section_threshold > 0)
        SMALL_DATA_SECTION ();
@@ -7754,8 +7923,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
@@ -7765,9 +7933,36 @@ 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 
+          && mips_abi != ABI_32
+          && mips_abi != ABI_O64
           && mips_abi != ABI_EABI)
     {
       /* A struct with only one or two floating point fields is returned in
@@ -7786,7 +7981,7 @@ mips_function_value (valtype, func)
 
          fields[i++] = field;
        }
-         
+
       /* Must check i, so that we reject structures with no elements.  */
       if (! field)
        {
@@ -7855,11 +8050,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. */
+       /* 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.  */
        CUMULATIVE_ARGS temp;
        temp = *cum;
        if (FUNCTION_ARG (temp, mode, type, named) != 0)
@@ -7909,7 +8105,10 @@ mips_secondary_reload_class (class, mode, x, in_p)
        {
          while (GET_CODE (x) == SUBREG)
            {
-             off += SUBREG_WORD (x);
+             off += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+                                         GET_MODE (SUBREG_REG (x)),
+                                         SUBREG_BYTE (x),
+                                         GET_MODE (x));
              x = SUBREG_REG (x);
            }
 
@@ -8469,7 +8668,7 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
       && strncmp (XSTR (fn, 0), "__mips16_", 9) == 0)
     return 0;
 
-  /* This code will only work for o32 and o64 abis.  The other ABI's 
+  /* This code will only work for o32 and o64 abis.  The other ABI's
      require more sophisticated support.  */
   if (mips_abi != ABI_32 && mips_abi != ABI_O64)
     abort ();
@@ -8609,7 +8808,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");
@@ -8900,7 +9099,7 @@ mips16_optimize_gp (first)
              emit_insn_after (gen_rtx (SET, VOIDmode, SET_DEST (set1),
                                        force_const_mem (Pmode, sym)),
                               next);
-             
+
              PUT_CODE (insn, NOTE);
              NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
              NOTE_SOURCE_FILE (insn) = 0;
@@ -9265,10 +9464,10 @@ machine_dependent_reorg (first)
          constants = NULL;
          first_constant_ref = -1;
        }
-      
+
       if (constants != NULL
-              && (NEXT_INSN (insn) == NULL 
-                  || (first_constant_ref >= 0 
+              && (NEXT_INSN (insn) == NULL
+                  || (first_constant_ref >= 0
                       && (((addr - first_constant_ref)
                            + 2 /* for alignment */
                            + 2 /* for a short jump insn */
@@ -9277,10 +9476,10 @@ 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;
-             
+
          label = gen_label_rtx ();
          jump = emit_jump_insn_after (gen_jump (label), insn);
          JUMP_LABEL (jump) = label;
@@ -9322,7 +9521,7 @@ highpart_shift_operator (x, mode)
          || code == ROTATE);
 }
 
-/* Return the length of INSN.  LENGTH is the initial length computed by 
+/* Return the length of INSN.  LENGTH is the initial length computed by
    attributes in the machine-description file.  */
 
 int
@@ -9334,7 +9533,7 @@ mips_adjust_insn_length (insn, length)
      of a sequence.  A conditional jump normally has a delay slot, but
      does not on MIPS16.  */
   if (simplejump_p (insn)
-      || (!TARGET_MIPS16  && (GET_CODE (insn) == JUMP_INSN 
+      || (!TARGET_MIPS16  && (GET_CODE (insn) == JUMP_INSN
                              || GET_CODE (insn) == CALL_INSN)))
     length += 4;
 
@@ -9345,7 +9544,7 @@ mips_adjust_insn_length (insn, length)
   return length;
 }
 
-/* Output assembly instructions to peform a conditional branch.  
+/* Output assembly instructions to peform a conditional branch.
 
    INSN is the branch instruction.  OPERANDS[0] is the condition.
    OPERANDS[1] is the target of the branch.  OPERANDS[2] is the target
@@ -9360,8 +9559,8 @@ mips_adjust_insn_length (insn, length)
    That tells us whether to generate a simple conditional branch, or a
    reversed conditional branch around a `jr' instruction.  */
 char *
-mips_output_conditional_branch (insn, 
-                               operands, 
+mips_output_conditional_branch (insn,
+                               operands,
                                two_operands_p,
                                float_p,
                                inverted_p,
@@ -9387,9 +9586,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
@@ -9422,7 +9621,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;
@@ -9437,7 +9636,7 @@ mips_output_conditional_branch (insn,
      equality comparisons are done between two operands, and therefore
      do not require a `z' in the assembly language output.  */
   need_z_p = (!float_p && code != EQ && code != NE);
-  /* For comparisons against zero, the zero is not provided 
+  /* For comparisons against zero, the zero is not provided
      explicitly.  */
   if (need_z_p)
     op2 = "";
@@ -9446,7 +9645,7 @@ mips_output_conditional_branch (insn,
      strcat to add to it.  */
   buffer[0] = '\0';
 
-  switch (length) 
+  switch (length)
     {
     case 4:
     case 8:
@@ -9485,18 +9684,18 @@ mips_output_conditional_branch (insn,
           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 
+       const char *const target
          = ((mips_branch_likely || length == 16) ? ".+16" : ".+12");
        char *c;
 
        strcpy (buffer, "%(%<");
        c = strchr (buffer, '\0');
-       /* Generate the reversed comparision.  This takes four 
+       /* Generate the reversed comparision.  This takes four
           bytes.  */
        if (float_p)
          sprintf (c, "%%*b%s\t%%Z2%s",
@@ -9552,7 +9751,7 @@ mips_output_conditional_branch (insn,
           generate only a four-byte sequence, rather than eight, and
           there seems to be no way to tell it not to.  Thus, we can't
           just use a `.+x' addressing form; we don't know what value
-          to give for `x'.  
+          to give for `x'.
 
           So, we resort to using the explicit relocation syntax
           available in the assembler and do:
@@ -9567,7 +9766,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];
@@ -9575,7 +9774,7 @@ mips_output_conditional_branch (insn,
 
        strcpy (buffer, "%(%<%[");
        c = strchr (buffer, '\0');
-       /* Generate the reversed comparision.  This takes four 
+       /* Generate the reversed comparision.  This takes four
           bytes.  */
        if (float_p)
          sprintf (c, "%%*b%s\t%%Z2%s",
@@ -9630,3 +9829,361 @@ mips_add_gc_roots ()
   ggc_add_rtx_root (&embedded_pic_fnaddr_rtx, 1);
   ggc_add_rtx_root (&mips16_gp_pseudo_rtx, 1);
 }
+
+static enum processor_type
+mips_parse_cpu (cpu_string)
+     const char *cpu_string;
+{
+  const char *p = cpu_string;
+  int seen_v = 0;
+  enum processor_type cpu;
+
+  /* We need to cope with the various "vr" prefixes for the NEC 4300
+     and 4100 processors.  */
+  if (*p == 'v' || *p == 'V')
+    seen_v = 1, p++;
+
+  if (*p == 'r' || *p == 'R')
+    p++;
+
+  /* Since there is no difference between a R2000 and R3000 in
+     terms of the scheduler, we collapse them into just an R3000.  */
+
+  cpu = PROCESSOR_DEFAULT;
+  switch (*p)
+    {
+    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':
+      if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K"))
+       cpu = PROCESSOR_R3000;
+      else if (!strcmp (p, "3900"))
+       cpu = PROCESSOR_R3900;
+      break;
+
+    case '4':
+      if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K"))
+       cpu = PROCESSOR_R4000;
+      /* The vr4100 is a non-FP ISA III processor with some extra
+        instructions.  */
+      else if (!strcmp (p, "4100"))
+         cpu = PROCESSOR_R4100;
+      /* The vr4300 is a standard ISA III processor, but with a different
+        pipeline.  */
+      else if (!strcmp (p, "4300"))
+       cpu = PROCESSOR_R4300;
+      /* The r4400 is exactly the same as the r4000 from the compiler's
+        viewpoint.  */
+      else if (!strcmp (p, "4400"))
+       cpu = PROCESSOR_R4000;
+      else if (!strcmp (p, "4600"))
+       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':
+      if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
+       cpu = PROCESSOR_R6000;
+      break;
+
+    case '8':
+      if (!strcmp (p, "8000"))
+       cpu = PROCESSOR_R8000;
+      break;
+
+    case 'o':
+      if (!strcmp (p, "orion"))
+       cpu = PROCESSOR_R4600;
+      break;
+    }
+
+  if (seen_v
+      && cpu != PROCESSOR_R4300
+      && cpu != PROCESSOR_R4100
+      && cpu != PROCESSOR_R5000)
+    cpu = PROCESSOR_DEFAULT;
+
+  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 */