OSDN Git Service

include:
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 56f5210..f24452b 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for MIPS
-   Copyright (C) 1989, 90, 91, 93-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1989, 90, 91, 93-98, 1999 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
@@ -27,15 +27,8 @@ Boston, MA 02111-1307, USA.  */
    be replaced with something better designed.  */
 
 #include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
+#include "system.h"
+#include <signal.h>
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -46,25 +39,17 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "insn-codes.h"
 #include "recog.h"
+#include "toplev.h"
 #include "output.h"
 
-#undef MAX                     /* sys/param.h may also define these */
-#undef MIN
-
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <ctype.h>
 #include "tree.h"
+#include "function.h"
 #include "expr.h"
 #include "flags.h"
 #include "reload.h"
-
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
-#endif
+#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.  */
@@ -78,19 +63,8 @@ Boston, MA 02111-1307, USA.  */
 #define STAB_CODE_TYPE int
 #endif
 
-extern void   abort ();
-extern int    atoi ();
-extern char  *getenv ();
-extern char  *mktemp ();
-extern rtx    adj_offsettable_operand ();
-extern rtx    copy_to_reg ();
-extern void   error ();
-extern tree   lookup_name ();
-extern void   pfatal_with_name ();
-extern void   warning ();
-
-extern FILE  *asm_out_file;
+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
@@ -119,7 +93,7 @@ static int m16_check_op                              PROTO ((rtx, int, int, int));
 static void block_move_loop                    PROTO ((rtx, rtx, int, int,
                                                        rtx, rtx));
 static void block_move_call                    PROTO ((rtx, rtx, rtx));
-static FILE *make_temp_file                    PROTO ((void));
+static FILE *mips_make_temp_file               PROTO ((void));
 static void save_restore_insns                 PROTO ((int, rtx,
                                                        long, FILE *));
 static void mips16_output_gp_offset            PROTO ((FILE *, rtx));
@@ -132,7 +106,10 @@ static rtx add_constant                            PROTO ((struct constant **,
 static void dump_constants                     PROTO ((struct constant *,
                                                        rtx));
 static rtx mips_find_symbol                    PROTO ((rtx));
-
+static void abort_with_insn                    PROTO ((rtx, const char *))
+  ATTRIBUTE_NORETURN;
+static int symbolic_expression_p                PROTO ((rtx));
+static void mips_add_gc_roots                   PROTO ((void));
 
 /* Global variables for machine-dependent things.  */
 
@@ -169,12 +146,12 @@ FILE *asm_out_text_file;
 struct extern_list
 {
   struct extern_list *next;    /* next external */
-  char *name;                  /* name of the external */
+  const char *name;            /* name of the external */
   int size;                    /* size in bytes */
 } *extern_head = 0;
 
 /* Name of the file containing the current function.  */
-char *current_function_file = "";
+const char *current_function_file = "";
 
 /* Warning given that Mips ECOFF can't support changing files
    within a function.  */
@@ -232,9 +209,9 @@ int mips_abi;
 #endif
 
 /* Strings to hold which cpu and instruction set architecture to use.  */
-char *mips_cpu_string;         /* for -mcpu=<xxx> */
-char *mips_isa_string;         /* for -mips{1,2,3,4} */
-char *mips_abi_string;         /* for -mabi={o32,32,n32,n64,64,eabi} */
+const char *mips_cpu_string;   /* for -mcpu=<xxx> */
+const char *mips_isa_string;   /* for -mips{1,2,3,4} */
+const char *mips_abi_string;   /* for -mabi={32,n32,64,eabi} */
 
 /* Whether we are generating mips16 code.  This is a synonym for
    TARGET_MIPS16, and exists for use as an attribute.  */
@@ -243,7 +220,12 @@ int mips16;
 /* This variable is set by -mno-mips16.  We only care whether
    -mno-mips16 appears or not, and using a string in this fashion is
    just a way to avoid using up another bit in target_flags.  */
-char *mips_no_mips16_string;
+const char *mips_no_mips16_string;
+
+/* This is only used to determine if an type size setting option was 
+   explicitly specified (-mlong64, -mint64, -mlong32).  The specs
+   set this option if such an option is used. */
+const char *mips_explicit_type_size_string;
 
 /* Whether we are generating mips16 hard float code.  In mips16 mode
    we always set TARGET_SOFT_FLOAT; this variable is nonzero if
@@ -254,7 +236,7 @@ int mips16_hard_float;
 /* This variable is set by -mentry.  We only care whether -mentry
    appears or not, and using a string in this fashion is just a way to
    avoid using up another bit in target_flags.  */
-char *mips_entry_string;
+const char *mips_entry_string;
 
 /* Whether we should entry and exit pseudo-ops in mips16 mode.  */
 int mips_entry;
@@ -270,6 +252,9 @@ enum mips_abicalls_type mips_abicalls;
    initialized in override_options.  */
 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
 
+/* Mode used for saving/restoring general purpose registers.  */
+static enum machine_mode gpr_mode;
+
 /* Array giving truth value on whether or not a given hard register
    can support a given mode.  */
 char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
@@ -305,7 +290,7 @@ rtx mips16_gp_pseudo_rtx;
 struct string_constant
 {
   struct string_constant *next;
-  char *label;
+  const char *label;
 };
 
 static struct string_constant *string_constants;
@@ -499,7 +484,7 @@ arith32_operand (op, mode)
 int
 small_int (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
 }
@@ -510,7 +495,7 @@ small_int (op, mode)
 int
 large_int (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   HOST_WIDE_INT value;
 
@@ -566,6 +551,33 @@ reg_or_0_operand (op, mode)
   return 0;
 }
 
+/* Return truth value of whether OP is a register or the constant 0,
+   even in mips16 mode. */
+
+int
+true_reg_or_0_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    case CONST_INT:
+      return INTVAL (op) == 0;
+
+    case CONST_DOUBLE:
+      return op == CONST0_RTX (mode);
+
+    case REG:
+    case SUBREG:
+      return register_operand (op, mode);
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+
 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant.  */
 
 int
@@ -588,7 +600,7 @@ mips_const_double_ok (op, mode)
     return 1;
 
   /* ??? li.s does not work right with SGI's Irix 6 assembler.  */
-  if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
+  if (mips_abi != ABI_32 && mips_abi != ABI_O64 && mips_abi != ABI_EABI)
     return 0;
 
   REAL_VALUE_FROM_CONST_DOUBLE (d, op);
@@ -953,7 +965,7 @@ cmp_op (op, mode)
 int
 pc_or_label_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (op == pc_rtx)
     return 1;
@@ -972,7 +984,7 @@ pc_or_label_operand (op, mode)
 int
 call_insn_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return (CONSTANT_ADDRESS_P (op)
          || (GET_CODE (op) == REG && op != arg_pointer_rtx
@@ -1155,7 +1167,7 @@ se_nonimmediate_operand (op, mode)
 int
 consttable_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return CONSTANT_P (op);
 }
@@ -1217,7 +1229,7 @@ m16_check_op (op, low, high, mask)
 int
 m16_uimm3_b (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, 0x1, 0x8, 0);
 }
@@ -1225,7 +1237,7 @@ m16_uimm3_b (op, mode)
 int
 m16_simm4_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0x8, 0x7, 0);
 }
@@ -1233,7 +1245,7 @@ m16_simm4_1 (op, mode)
 int
 m16_nsimm4_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0x7, 0x8, 0);
 }
@@ -1241,7 +1253,7 @@ m16_nsimm4_1 (op, mode)
 int
 m16_simm5_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0x10, 0xf, 0);
 }
@@ -1249,7 +1261,7 @@ m16_simm5_1 (op, mode)
 int
 m16_nsimm5_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0xf, 0x10, 0);
 }
@@ -1257,7 +1269,7 @@ m16_nsimm5_1 (op, mode)
 int
 m16_uimm5_4 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, (- 0x10) << 2, 0xf << 2, 3);
 }
@@ -1265,7 +1277,7 @@ m16_uimm5_4 (op, mode)
 int
 m16_nuimm5_4 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, (- 0xf) << 2, 0x10 << 2, 3);
 }
@@ -1273,7 +1285,7 @@ m16_nuimm5_4 (op, mode)
 int
 m16_simm8_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0x80, 0x7f, 0);
 }
@@ -1281,7 +1293,7 @@ m16_simm8_1 (op, mode)
 int
 m16_nsimm8_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0x7f, 0x80, 0);
 }
@@ -1289,7 +1301,7 @@ m16_nsimm8_1 (op, mode)
 int
 m16_uimm8_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, 0x0, 0xff, 0);
 }
@@ -1297,7 +1309,7 @@ m16_uimm8_1 (op, mode)
 int
 m16_nuimm8_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0xff, 0x0, 0);
 }
@@ -1305,7 +1317,7 @@ m16_nuimm8_1 (op, mode)
 int
 m16_uimm8_m1_1 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, - 0x1, 0xfe, 0);
 }
@@ -1313,7 +1325,7 @@ m16_uimm8_m1_1 (op, mode)
 int
 m16_uimm8_4 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, 0x0, 0xff << 2, 3);
 }
@@ -1321,7 +1333,7 @@ m16_uimm8_4 (op, mode)
 int
 m16_nuimm8_4 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, (- 0xff) << 2, 0x0, 3);
 }
@@ -1329,7 +1341,7 @@ m16_nuimm8_4 (op, mode)
 int
 m16_simm8_8 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, (- 0x80) << 3, 0x7f << 3, 7);
 }
@@ -1337,7 +1349,7 @@ m16_simm8_8 (op, mode)
 int
 m16_nsimm8_8 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);
 }
@@ -1351,7 +1363,7 @@ m16_nsimm8_8 (op, mode)
 int
 m16_usym8_4 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == SYMBOL_REF
       && SYMBOL_REF_FLAG (op)
@@ -1378,7 +1390,7 @@ m16_usym8_4 (op, mode)
 int
 m16_usym5_4 (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == SYMBOL_REF
       && SYMBOL_REF_FLAG (op)
@@ -1414,9 +1426,9 @@ m16_usym5_4 (op, mode)
 /* ??? This function no longer does anything useful, because final_prescan_insn
    now will never emit a nop.  */
 
-char *
+const char *
 mips_fill_delay_slot (ret, type, operands, cur_insn)
-     char *ret;                        /* normal string to return */
+     const char *ret;          /* normal string to return */
      enum delay_type type;     /* type of delay */
      rtx operands[];           /* operands to use */
      rtx cur_insn;             /* current insn */
@@ -1470,14 +1482,14 @@ mips_fill_delay_slot (ret, type, operands, cur_insn)
   mips_load_reg = set_reg;
   if (GET_MODE_SIZE (mode)
       > (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD))
-    mips_load_reg2 = gen_rtx (REG, SImode, REGNO (set_reg) + 1);
+    mips_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1);
   else
     mips_load_reg2 = 0;
 
   if (type == DELAY_HILO)
     {
-      mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);
-      mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);
+      mips_load_reg3 = gen_rtx_REG (SImode, MD_REG_FIRST);
+      mips_load_reg4 = gen_rtx_REG (SImode, MD_REG_FIRST+1);
     }
   else
     {
@@ -1638,20 +1650,21 @@ embedded_pic_offset (x)
       pop_topmost_sequence ();
     }
 
-  return gen_rtx (CONST, Pmode,
-                 gen_rtx (MINUS, Pmode, x,
-                          XEXP (DECL_RTL (current_function_decl), 0)));
+  return
+    gen_rtx_CONST (Pmode,
+                  gen_rtx_MINUS (Pmode, x,
+                                 XEXP (DECL_RTL (current_function_decl), 0)));
 }
 
 /* Return the appropriate instructions to move one operand to another.  */
 
-char *
+const char *
 mips_move_1word (operands, insn, unsignedp)
      rtx operands[];
      rtx insn;
      int unsignedp;
 {
-  char *ret = 0;
+  const char *ret = 0;
   rtx op0 = operands[0];
   rtx op1 = operands[1];
   enum rtx_code code0 = GET_CODE (op0);
@@ -1790,7 +1803,7 @@ mips_move_1word (operands, insn, unsignedp)
 
          if (ret != (char *)0 && MEM_VOLATILE_P (op1))
            {
-             int i = strlen (ret);
+             size_t i = strlen (ret);
              if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
                abort ();
 
@@ -2014,7 +2027,7 @@ mips_move_1word (operands, insn, unsignedp)
 
       if (ret != 0 && MEM_VOLATILE_P (op0))
        {
-         int i = strlen (ret);
+         size_t i = strlen (ret);
 
          if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
            abort ();
@@ -2039,12 +2052,12 @@ mips_move_1word (operands, insn, unsignedp)
 \f
 /* Return the appropriate instructions to move 2 words */
 
-char *
+const char *
 mips_move_2words (operands, insn)
      rtx operands[];
      rtx insn;
 {
-  char *ret = 0;
+  const char *ret = 0;
   rtx op0 = operands[0];
   rtx op1 = operands[1];
   enum rtx_code code0 = GET_CODE (operands[0]);
@@ -2347,7 +2360,7 @@ mips_move_2words (operands, insn)
 
          if (ret != 0 && MEM_VOLATILE_P (op1))
            {
-             int i = strlen (ret);
+             size_t i = strlen (ret);
 
              if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
                abort ();
@@ -2458,7 +2471,7 @@ mips_move_2words (operands, insn)
 
       if (ret != 0 && MEM_VOLATILE_P (op0))
        {
-         int i = strlen (ret);
+         size_t i = strlen (ret);
 
          if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
            abort ();
@@ -2705,7 +2718,7 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
              && p_info->const_add != 0
              && ((p_info->unsignedp
                   ? ((unsigned HOST_WIDE_INT) (value + p_info->const_add)
-                     > INTVAL (cmp1))
+                     > (unsigned HOST_WIDE_INT) INTVAL (cmp1))
                   : (value + p_info->const_add) > INTVAL (cmp1))
                  != (p_info->const_add > 0))))
        cmp1 = force_reg (mode, cmp1);
@@ -2733,7 +2746,8 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
             we would get the wrong answer if we follow the usual path;
             thus, x > 0xffffffffU would turn into x > 0U.  */
          if ((p_info->unsignedp
-              ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1)
+              ? (unsigned HOST_WIDE_INT) new >
+              (unsigned HOST_WIDE_INT) INTVAL (cmp1)
               : new > INTVAL (cmp1))
              != (p_info->const_add > 0))
            {
@@ -2781,7 +2795,7 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
   else if (test == ITEST_EQ)
     {
       reg2 = invert ? gen_reg_rtx (mode) : result;
-      convert_move (reg2, gen_rtx (LTU, mode, reg, const1_rtx), 0);
+      convert_move (reg2, gen_rtx_LTU (mode, reg, const1_rtx), 0);
       reg = reg2;
     }
 
@@ -2848,7 +2862,7 @@ gen_conditional_branch (operands, test_code)
     case CMP_SF:
     case CMP_DF:
       if (mips_isa < 4)
-       reg = gen_rtx (REG, CCmode, FPSW_REGNUM);
+       reg = gen_rtx_REG (CCmode, FPSW_REGNUM);
       else
        reg = gen_reg_rtx (CCmode);
 
@@ -2856,10 +2870,10 @@ gen_conditional_branch (operands, test_code)
          0 in the instruction built below.  The MIPS FPU handles
          inequality testing by testing for equality and looking for a
          false result.  */
-      emit_insn (gen_rtx (SET, VOIDmode, reg,
-                         gen_rtx (test_code == NE ? EQ : test_code,
-                                  CCmode, cmp0, cmp1)));
-
+      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;
@@ -2873,7 +2887,7 @@ gen_conditional_branch (operands, test_code)
 
   /* Generate the branch.  */
 
-  label1 = gen_rtx (LABEL_REF, VOIDmode, operands[0]);
+  label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]);
   label2 = pc_rtx;
 
   if (invert)
@@ -2882,10 +2896,11 @@ gen_conditional_branch (operands, test_code)
       label1 = pc_rtx;
     }
 
-  emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
-                          gen_rtx (IF_THEN_ELSE, VOIDmode,
-                                   gen_rtx (test_code, mode, cmp0, cmp1),
-                                   label1, label2)));
+  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
+                              gen_rtx_IF_THEN_ELSE (VOIDmode,
+                                                    gen_rtx (test_code, mode,
+                                                             cmp0, cmp1),
+                                                    label1, label2)));
 }
 
 /* Emit the common code for conditional moves.  OPERANDS is the array
@@ -2964,14 +2979,15 @@ gen_conditional_move (operands)
     abort ();
 
   cmp_reg = gen_reg_rtx (cmp_mode);
-  emit_insn (gen_rtx (SET, cmp_mode, cmp_reg,
-                     gen_rtx (cmp_code, cmp_mode, op0, op1)));
-
-  emit_insn (gen_rtx (SET, op_mode, operands[0],
-                     gen_rtx (IF_THEN_ELSE, op_mode,
-                              gen_rtx (move_code, VOIDmode,
-                                       cmp_reg, CONST0_RTX (SImode)),
-                              operands[2], operands[3])));
+  emit_insn (gen_rtx_SET (cmp_mode, cmp_reg,
+                         gen_rtx (cmp_code, cmp_mode, op0, op1)));
+
+  emit_insn (gen_rtx_SET (op_mode, operands[0],
+                         gen_rtx_IF_THEN_ELSE (op_mode,
+                                               gen_rtx (move_code, VOIDmode,
+                                                        cmp_reg,
+                                                        CONST0_RTX (SImode)),
+                                               operands[2], operands[3])));
 }
 \f
 /* Write a loop to move a constant number of bytes.
@@ -3088,13 +3104,13 @@ block_move_call (dest_reg, src_reg, bytes_rtx)
     bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);
 
 #ifdef TARGET_MEM_FUNCTIONS
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,
                     VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode,
                     convert_to_mode (TYPE_MODE (sizetype), bytes_rtx,
                                      TREE_UNSIGNED (sizetype)),
                     TYPE_MODE (sizetype));
 #else
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "bcopy"), 0,
                     VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode,
                     convert_to_mode (TYPE_MODE (integer_type_node), bytes_rtx,
                                      TREE_UNSIGNED (integer_type_node)),
@@ -3136,6 +3152,10 @@ expand_block_move (operands)
   if (TARGET_MEMCPY)
     block_move_call (dest_reg, src_reg, bytes_rtx);
 
+  else if (constp && bytes <= 2 * MAX_MOVE_BYTES
+          && align == UNITS_PER_WORD)
+    move_by_pieces (orig_dest, orig_src, bytes, align);
+       
   else if (constp && bytes <= 2 * MAX_MOVE_BYTES)
     emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
                                                      dest_reg),
@@ -3215,7 +3235,7 @@ expand_block_move (operands)
        BLOCK_MOVE_NOT_LAST     Do all but the last store.
        BLOCK_MOVE_LAST         Do just the last store. */
 
-char *
+const char *
 output_block_move (insn, operands, num_regs, move_type)
      rtx insn;
      rtx operands[];
@@ -3235,11 +3255,11 @@ output_block_move (insn, operands, num_regs, move_type)
   rtx xoperands[10];
 
   struct {
-    char *load;                        /* load insn without nop */
-    char *load_nop;            /* load insn with trailing nop */
-    char *store;               /* store insn */
-    char *final;               /* if last_store used: NULL or swr */
-    char *last_store;          /* last store instruction */
+    const char *load;          /* load insn without nop */
+    const char *load_nop;      /* load insn with trailing nop */
+    const char *store;         /* store insn */
+    const char *final;         /* if last_store used: NULL or swr */
+    const char *last_store;    /* last store instruction */
     int offset;                        /* current offset */
     enum machine_mode mode;    /* mode to use on (MEM) */
   } load_store[4];
@@ -3249,7 +3269,7 @@ output_block_move (insn, operands, num_regs, move_type)
      the number of registers available.  */
   for (i = 4;
        i < last_operand
-       && safe_regs < (sizeof(xoperands) / sizeof(xoperands[0]));
+       && safe_regs < (int)(sizeof(xoperands) / sizeof(xoperands[0]));
        i++)
     if (! reg_mentioned_p (operands[i], operands[0])
        && ! reg_mentioned_p (operands[i], operands[1]))
@@ -3345,7 +3365,7 @@ output_block_move (insn, operands, num_regs, move_type)
        }
     }
 
-  if (num_regs > sizeof (load_store) / sizeof (load_store[0]))
+  if (num_regs > (int)(sizeof (load_store) / sizeof (load_store[0])))
     num_regs = sizeof (load_store) / sizeof (load_store[0]);
 
   else if (num_regs < 1)
@@ -3489,23 +3509,23 @@ output_block_move (insn, operands, num_regs, move_type)
                    abort ();
 
                  if (GET_MODE (operands[i + 4]) != load_store[i].mode)
-                   operands[i + 4] = gen_rtx (REG, load_store[i].mode,
-                                              REGNO (operands[i + 4]));
+                   operands[i + 4] = gen_rtx_REG (load_store[i].mode,
+                                                  REGNO (operands[i + 4]));
 
                  offset = load_store[i].offset;
                  xoperands[0] = operands[i + 4];
-                 xoperands[1] = gen_rtx (MEM, load_store[i].mode,
-                                         plus_constant (src_reg, offset));
+                 xoperands[1] = gen_rtx_MEM (load_store[i].mode,
+                                             plus_constant (src_reg, offset));
 
                  if (use_lwl_lwr)
                    {
                      int extra_offset
                        = GET_MODE_SIZE (load_store[i].mode) - 1;
 
-                     xoperands[2] = gen_rtx (MEM, load_store[i].mode,
-                                             plus_constant (src_reg,
-                                                            extra_offset
-                                                            + offset));
+                     xoperands[2] = gen_rtx_MEM (load_store[i].mode,
+                                                 plus_constant (src_reg,
+                                                                extra_offset
+                                                                + offset));
                    }
 
                  output_asm_insn (load_store[i].load, xoperands);
@@ -3518,17 +3538,17 @@ output_block_move (insn, operands, num_regs, move_type)
              int offset = load_store[i].offset;
 
              xoperands[0] = operands[i + 4];
-             xoperands[1] = gen_rtx (MEM, load_store[i].mode,
-                                     plus_constant (dest_reg, offset));
+             xoperands[1] = gen_rtx_MEM (load_store[i].mode,
+                                         plus_constant (dest_reg, offset));
 
 
              if (use_lwl_lwr)
                {
                  int extra_offset = GET_MODE_SIZE (load_store[i].mode) - 1;
-                 xoperands[2] = gen_rtx (MEM, load_store[i].mode,
-                                         plus_constant (dest_reg,
-                                                        extra_offset
-                                                        + offset));
+                 xoperands[2] = gen_rtx_MEM (load_store[i].mode,
+                                             plus_constant (dest_reg,
+                                                            extra_offset
+                                                            + offset));
                }
 
              if (move_type == BLOCK_MOVE_NORMAL)
@@ -3561,9 +3581,9 @@ output_block_move (insn, operands, num_regs, move_type)
 
 void
 init_cumulative_args (cum, fntype, libname)
-     CUMULATIVE_ARGS *cum;     /* argument info to initialize */
-     tree fntype;              /* tree ptr for function decl */
-     rtx libname;              /* SYMBOL_REF of library name or 0 */
+     CUMULATIVE_ARGS *cum;             /* argument info to initialize */
+     tree fntype;                      /* tree ptr for function decl */
+     rtx libname ATTRIBUTE_UNUSED;     /* SYMBOL_REF of library name or 0 */
 {
   static CUMULATIVE_ARGS zero_cum;
   tree param, next_param;
@@ -3611,10 +3631,14 @@ function_arg_advance (cum, mode, type, named)
      int named;                        /* whether or not the argument was named */
 {
   if (TARGET_DEBUG_E_MODE)
-    fprintf (stderr,
-            "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n",
-            cum->gp_reg_found, cum->arg_number, cum->arg_words,
-            GET_MODE_NAME (mode), type, named);
+    {
+      fprintf (stderr,
+              "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
+              cum->gp_reg_found, cum->arg_number, cum->arg_words,
+              GET_MODE_NAME (mode));
+      fprintf (stderr, HOST_PTR_PRINTF, type);
+      fprintf (stderr, ", %d )\n\n", named);
+    }
 
   cum->arg_number++;
   switch (mode)
@@ -3690,16 +3714,21 @@ function_arg (cum, mode, type, named)
                      || TREE_CODE (type) == QUAL_UNION_TYPE));
 
   if (TARGET_DEBUG_E_MODE)
-    fprintf (stderr,
-            "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ",
-            cum->gp_reg_found, cum->arg_number, cum->arg_words,
-            GET_MODE_NAME (mode), type, named);
+    {
+      fprintf (stderr,
+              "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
+              cum->gp_reg_found, cum->arg_number, cum->arg_words,
+              GET_MODE_NAME (mode));
+      fprintf (stderr, HOST_PTR_PRINTF, type);
+      fprintf (stderr, ", %d ) = ", named);
+    }
+  
 
   cum->last_arg_fp = 0;
   switch (mode)
     {
     case SFmode:
-      if (mips_abi == ABI_32)
+      if (mips_abi == ABI_32 || mips_abi == ABI_O64)
        {
          if (cum->gp_reg_found || cum->arg_number >= 2 || TARGET_SOFT_FLOAT)
            regbase = GP_ARG_FIRST;
@@ -3735,7 +3764,7 @@ function_arg (cum, mode, type, named)
            cum->arg_words += cum->arg_words & 1;
        }
 
-      if (mips_abi == ABI_32)
+      if (mips_abi == ABI_32 || mips_abi == ABI_O64)
        regbase = ((cum->gp_reg_found
                    || TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT
                    || cum->arg_number >= 2)
@@ -3759,7 +3788,7 @@ function_arg (cum, mode, type, named)
 
       /* Drops through.  */
     case BLKmode:
-      if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD
+      if (type != (tree)0 && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD
          && ! TARGET_64BIT && mips_abi != ABI_EABI)
        cum->arg_words += (cum->arg_words & 1);
       regbase = GP_ARG_FIRST;
@@ -3791,8 +3820,8 @@ function_arg (cum, mode, type, named)
        abort ();
 
       if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
-         || mips_abi == ABI_EABI || ! named)
-       ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
+         || mips_abi == ABI_EABI || mips_abi == ABI_O64 || ! named)
+       ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
       else
        {
          /* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
@@ -3812,7 +3841,7 @@ function_arg (cum, mode, type, named)
          /* If the whole struct fits a DFmode register,
             we don't need the PARALLEL.  */
          if (! field || mode == DFmode)
-           ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
+           ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
          else
            {
              /* Now handle the special case by returning a PARALLEL
@@ -3831,7 +3860,7 @@ function_arg (cum, mode, type, named)
 
              /* assign_parms checks the mode of ENTRY_PARM, so we must
                 use the actual mode here.  */
-             ret = gen_rtx (PARALLEL, mode, rtvec_alloc (chunks));
+             ret = gen_rtx_PARALLEL (mode, rtvec_alloc (chunks));
 
              bitpos = 0;
              regno = regbase + *arg_words + bias;
@@ -3850,14 +3879,14 @@ function_arg (cum, mode, type, named)
                      && TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)) == bitpos
                      && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
                      && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
-                   reg = gen_rtx (REG, DFmode,
-                                  regno + FP_ARG_FIRST - GP_ARG_FIRST);
+                   reg = gen_rtx_REG (DFmode,
+                                      regno + FP_ARG_FIRST - GP_ARG_FIRST);
                  else
-                   reg = gen_rtx (REG, word_mode, regno);
-
+                   reg = gen_rtx_REG (word_mode, regno);
+                 
                  XVECEXP (ret, 0, i) 
-                   = gen_rtx (EXPR_LIST, VOIDmode, reg,
-                              GEN_INT (bitpos / BITS_PER_UNIT));
+                   = gen_rtx_EXPR_LIST (VOIDmode, reg,
+                                        GEN_INT (bitpos / BITS_PER_UNIT));
 
                  bitpos += 64;
                  regno++;
@@ -3893,7 +3922,7 @@ function_arg (cum, mode, type, named)
        {
          rtx amount = GEN_INT (BITS_PER_WORD
                                - int_size_in_bytes (type) * BITS_PER_UNIT);
-         rtx reg = gen_rtx (REG, word_mode, regbase + *arg_words + bias);
+         rtx reg = gen_rtx_REG (word_mode, regbase + *arg_words + bias);
 
          if (TARGET_64BIT)
            cum->adjust[cum->num_adjusts++] = gen_ashldi3 (reg, reg, amount);
@@ -3925,7 +3954,7 @@ function_arg_partial_nregs (cum, mode, type, named)
      CUMULATIVE_ARGS *cum;     /* current arg information */
      enum machine_mode mode;   /* current arg mode */
      tree type;                        /* type of the argument or 0 if lib support */
-     int named;                        /* != 0 for normal args, == 0 for ... args */
+     int named ATTRIBUTE_UNUSED;/* != 0 for normal args, == 0 for ... args */
 {
   if ((mode == BLKmode
        || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
@@ -3962,27 +3991,282 @@ function_arg_partial_nregs (cum, mode, type, named)
   return 0;
 }
 \f
-/* Abort after printing out a specific insn.  */
+/* Create the va_list data type.  */
+
+tree
+mips_build_va_list ()
+{
+  if (mips_abi == ABI_EABI && !TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+    {
+      tree f_fpr, f_rem, f_gpr, record;
+
+      record = make_node (RECORD_TYPE);
+
+      f_fpr = build_decl (FIELD_DECL, get_identifier ("__fp_regs"),
+                         ptr_type_node);
+      f_rem = build_decl (FIELD_DECL, get_identifier ("__fp_left"),
+                         integer_type_node);
+      f_gpr = build_decl (FIELD_DECL, get_identifier ("__gp_regs"),
+                         ptr_type_node);
+
+      DECL_FIELD_CONTEXT (f_fpr) = record;
+      DECL_FIELD_CONTEXT (f_rem) = record;
+      DECL_FIELD_CONTEXT (f_gpr) = record;
+
+      TYPE_FIELDS (record) = f_fpr;
+      TREE_CHAIN (f_fpr) = f_rem;
+      TREE_CHAIN (f_gpr) = f_gpr;
+
+      layout_type (record);
+
+      return record;
+    }
+  else
+    return ptr_type_node;
+}
+
+/* Implement va_start.  */
 
 void
+mips_va_start (stdarg_p, valist, nextarg)
+     int stdarg_p;
+     tree valist;
+     rtx nextarg;
+{
+  int arg_words, fp_arg_words;
+  tree t;
+
+  arg_words = current_function_args_info.arg_words;
+  fp_arg_words = current_function_args_info.fp_arg_words;
+
+  if (mips_abi == ABI_EABI)
+    {
+      if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+       {
+         tree f_fpr, f_rem, f_gpr, fpr, rem, gpr;
+         tree gprv, fprv;
+         int gpro, fpro;
+
+         f_fpr = TYPE_FIELDS (va_list_type_node);
+         f_rem = TREE_CHAIN (f_fpr);
+         f_gpr = TREE_CHAIN (f_gpr);
+
+         fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+         rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
+         gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+
+         if (arg_words < 8)
+           gpro = (8 - arg_words) * UNITS_PER_WORD;
+         else
+           gpro = (stdarg_p ? 0 : UNITS_PER_WORD);
+
+         gprv = make_tree (ptr_type_node, nextarg);
+         if (gpro != 0)
+           {
+             gprv = build (PLUS_EXPR, ptr_type_node, gprv,
+                           build_int_2 (-gpro, -1));
+           }
+
+         t = build (MODIFY_EXPR, ptr_type_node, gpr, gprv);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+         t = build (MODIFY_EXPR, integer_type_node, rem,
+                    build_int_2 (8 - fp_arg_words, 0));
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+         fpro = (8 - fp_arg_words) * 8;
+         if (fpro == 0)
+           fprv = gprv;
+         else
+           fprv = fold (build (PLUS_EXPR, ptr_type_node, gprv,
+                               build_int_2 (-fpro, -1)));
+
+         if (! TARGET_64BIT)
+           fprv = fold (build (BIT_AND_EXPR, ptr_type_node, fprv,
+                               build_int_2 (-8, -1)));
+
+         t = build (MODIFY_EXPR, ptr_type_node, fpr, fprv);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+      else
+       {
+         int ofs;
+
+         if (arg_words >= 8)
+           ofs = (stdarg_p ? 0 : UNITS_PER_WORD);
+         else
+           ofs = (8 - arg_words) * UNITS_PER_WORD;
+
+         nextarg = plus_constant (nextarg, -ofs);
+         std_expand_builtin_va_start (1, valist, nextarg);
+       }
+    }
+  else
+    {
+      int ofs;
+
+      if (stdarg_p)
+       ofs = 0;
+      else
+       {
+         /* ??? This had been conditional on
+              _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
+            and both iris5.h and iris6.h define _MIPS_SIM.  */
+         if (mips_abi == ABI_N32 || mips_abi == ABI_64)
+           ofs = (arg_words >= 8 ? -UNITS_PER_WORD : 0);
+         else
+           ofs = -UNITS_PER_WORD;
+       }
+
+      nextarg = plus_constant (nextarg, ofs);
+      std_expand_builtin_va_start (1, valist, nextarg);
+    }
+}
+
+/* Implement va_arg.  */
+
+rtx
+mips_va_arg (valist, type)
+     tree valist, type;
+{
+  HOST_WIDE_INT size, rsize;
+  rtx addr_rtx;
+  tree t;
+
+  size = int_size_in_bytes (type);
+  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+
+  if (mips_abi == ABI_EABI)
+    {
+      tree gpr;
+      int indirect;
+      rtx lab_over = NULL_RTX, lab_false, r;
+
+      indirect
+       = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
+      if (indirect)
+       size = rsize = POINTER_SIZE / BITS_PER_UNIT;
+
+      addr_rtx = gen_reg_rtx (Pmode);
+
+      if (!TARGET_SOFT_FLOAT && !TARGET_SINGLE_FLOAT)
+       {
+         tree f_fpr, f_rem, f_gpr, fpr, rem;
+
+         f_fpr = TYPE_FIELDS (va_list_type_node);
+         f_rem = TREE_CHAIN (f_fpr);
+         f_gpr = TREE_CHAIN (f_gpr);
+
+         fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+         rem = build (COMPONENT_REF, TREE_TYPE (f_rem), valist, f_rem);
+         gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+
+         if (TREE_CODE (type) == REAL_TYPE)
+           {
+             lab_false = gen_label_rtx ();
+             lab_over = gen_label_rtx ();
+
+             r = expand_expr (rem, NULL_RTX, TYPE_MODE (TREE_TYPE (rem)),
+                              EXPAND_NORMAL);
+             emit_cmp_and_jump_insns (r, const0_rtx, LE, const1_rtx,
+                                      GET_MODE (r), 1, 1, lab_false);
+
+             t = build (PLUS_EXPR, TREE_TYPE (rem), rem,
+                        build_int_2 (-1, -1));
+             t = build (MODIFY_EXPR, TREE_TYPE (rem), rem, t);
+             TREE_SIDE_EFFECTS (t) = 1;
+             expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+             t = build (POSTINCREMENT_EXPR, TREE_TYPE (fpr), fpr,
+                        build_int_2 (8, 0));
+             TREE_SIDE_EFFECTS (t) = 1;
+             r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+             if (r != addr_rtx)
+               emit_move_insn (addr_rtx, r);
+
+             emit_jump (gen_jump (lab_over));
+             emit_barrier ();
+             emit_label (lab_false);
+           }
+       }
+      else
+       gpr = valist;
+
+      if (! indirect
+         && ! TARGET_64BIT
+         && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
+       {
+         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, 
+                    build_int_2 (-2*UNITS_PER_WORD, -1));
+         t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+
+      t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr, rsize);
+      TREE_SIDE_EFFECTS (t) = 1;
+      r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+      if (r != addr_rtx)
+       emit_move_insn (addr_rtx, r);
+
+      if (lab_over)
+       emit_label (lab_over);
+
+      if (indirect)
+       {
+         r = gen_rtx_MEM (Pmode, addr_rtx);
+         MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+         emit_move_insn (addr_rtx, r);
+       }
+      else
+       {
+         if (BYTES_BIG_ENDIAN && rsize != size)
+           addr_rtx = plus_constant (addr_rtx, rsize - size);
+       }
+    }
+  else
+    {
+      int align;
+
+      /* ??? The original va-mips.h did always align, despite the fact 
+        that alignments <= UNITS_PER_WORD are preserved by the va_arg
+        increment mechanism.  */
+
+      if (TARGET_64BIT)
+       align = 8;
+      else if (TYPE_ALIGN (type) > 32)
+       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));
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* Everything past the alignment is standard.  */
+      return std_expand_builtin_va_arg (valist, type);
+    }
+}
+\f
+/* Abort after printing out a specific insn.  */
+
+static void
 abort_with_insn (insn, reason)
      rtx insn;
-     char *reason;
+     const char *reason;
 {
   error (reason);
   debug_rtx (insn);
   abort ();
 }
-
-/* Write a message to stderr (for use in macros expanded in files that do not
-   include stdio.h).  */
-
-void
-trace (s, s1, s2)
-     char *s, *s1, *s2;
-{
-  fprintf (stderr, s, s1, s2);
-}
 \f
 /* Set up the threshold for data to go into the small data area, instead
    of the normal data area, and detect any conflicts in the switches.  */
@@ -4018,7 +4302,7 @@ override_options ()
   if (mips_isa_string == 0)
     mips_isa = MIPS_ISA_DEFAULT;
 
-  else if (isdigit (*mips_isa_string))
+  else if (ISDIGIT (*mips_isa_string))
     {
       mips_isa = atoi (mips_isa_string);
       if (mips_isa == 16)
@@ -4051,16 +4335,16 @@ override_options ()
     }
 
 #ifdef MIPS_ABI_DEFAULT
-  /* Get the ABI to use.  Currently this code is only used for Irix 6.  */
+  /* Get the ABI to use. */
   if (mips_abi_string == (char *) 0)
     mips_abi = MIPS_ABI_DEFAULT;
-  else if (! strcmp (mips_abi_string, "32")
-          || ! strcmp (mips_abi_string, "o32"))
+  else if (! strcmp (mips_abi_string, "32"))
     mips_abi = ABI_32;
+  else if (! strcmp (mips_abi_string, "o64"))
+    mips_abi = ABI_O64;
   else if (! strcmp (mips_abi_string, "n32"))
     mips_abi = ABI_N32;
-  else if (! strcmp (mips_abi_string, "64")
-          || ! strcmp (mips_abi_string, "n64"))
+  else if (! strcmp (mips_abi_string, "64"))
     mips_abi = ABI_64;
   else if (! strcmp (mips_abi_string, "eabi"))
     mips_abi = ABI_EABI;
@@ -4068,7 +4352,8 @@ override_options ()
     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)
+  if (mips_abi_string == 0 && mips_isa_string 
+      && mips_abi != ABI_EABI && mips_abi != ABI_O64)
     {
       if (mips_isa <= 2)
        mips_abi = ABI_32;
@@ -4077,7 +4362,8 @@ override_options ()
     }
 
   /* A specified ABI defaults the ISA if it was not specified.  */
-  else if (mips_isa_string == 0 && mips_abi_string && mips_abi != ABI_EABI)
+  else if (mips_isa_string == 0 && mips_abi_string 
+          && mips_abi != ABI_EABI && mips_abi != ABI_O64)
     {
       if (mips_abi == ABI_32)
        mips_isa = 1;
@@ -4090,7 +4376,8 @@ override_options ()
   /* If both ABI and ISA were specified, check for conflicts.  */
   else if (mips_isa_string && mips_abi_string)
     {
-      if ((mips_isa <= 2 && (mips_abi == ABI_N32 || mips_abi == ABI_64))
+      if ((mips_isa <= 2 && (mips_abi == ABI_N32 || mips_abi == ABI_64
+                            || mips_abi == ABI_O64))
          || (mips_isa >= 3 && mips_abi == ABI_32))
        error ("-mabi=%s does not support -mips%d", mips_abi_string, mips_isa);
     }
@@ -4099,10 +4386,12 @@ override_options ()
   if (mips_abi == ABI_32)
     target_flags &= ~ (MASK_FLOAT64|MASK_64BIT);
 
-  /* In the EABI in 64 bit mode, longs and pointers are 64 bits.  Likewise
-   for the SGI Irix6 N64 ABI.  */
-  if ((mips_abi == ABI_EABI && TARGET_64BIT)
-      || mips_abi == ABI_64)
+  /* If no type size setting options (-mlong64,-mint64,-mlong32) were used
+     then set the type sizes.  In the EABI in 64 bit mode, longs and
+     pointers are 64 bits.  Likewise for the SGI Irix6 N64 ABI.  */
+  if (mips_explicit_type_size_string == NULL
+      && ((mips_abi == ABI_EABI && TARGET_64BIT)
+         || mips_abi == ABI_64))
     target_flags |= MASK_LONG64;
 
   /* ??? This doesn't work yet, so don't let people try to use it.  */
@@ -4151,7 +4440,7 @@ override_options ()
 
   else
     {
-      char *p = mips_cpu_string;
+      const char *p = mips_cpu_string;
       int seen_v = 0;
 
       /* We need to cope with the various "vr" prefixes for the NEC 4300
@@ -4168,13 +4457,6 @@ override_options ()
       mips_cpu = PROCESSOR_DEFAULT;
       switch (*p)
        {
-       /* start-sanitize-tx19 */
-       case '1':
-         if (!strcmp (p, "1900"))
-           mips_cpu = PROCESSOR_R3900;
-         break;
-       /* end-sanitize-tx19 */
-
        case '2':
          if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
            mips_cpu = PROCESSOR_R3000;
@@ -4258,20 +4540,14 @@ override_options ()
   /* make sure sizes of ints/longs/etc. are ok */
   if (mips_isa < 3)
     {
-      if (TARGET_INT64)
-       fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit ints");
-
-      else if (TARGET_LONG64)
-       fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit longs");
-
-      else if (TARGET_FLOAT64)
+      if (TARGET_FLOAT64)
        fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit fp registers");
 
       else if (TARGET_64BIT)
        fatal ("Only MIPS-III or MIPS-IV CPUs can support 64 bit gp registers");
     }
 
-  if (mips_abi != ABI_32)
+  if (mips_abi != ABI_32 && mips_abi != ABI_O64)
     flag_pcc_struct_return = 0;
 
   /* Tell halfpic.c that we have half-pic code if we do.  */
@@ -4399,6 +4675,7 @@ override_options ()
   mips_print_operand_punct['^'] = 1;
   mips_print_operand_punct['$'] = 1;
   mips_print_operand_punct['+'] = 1;
+  mips_print_operand_punct['~'] = 1;
 
   mips_char_to_class['d'] = TARGET_MIPS16 ? M16_REGS : GR_REGS;
   mips_char_to_class['e'] = M16_NA_REGS;
@@ -4475,6 +4752,24 @@ override_options ()
          mips_hard_regno_mode_ok[(int)mode][regno] = temp;
        }
     }
+
+  /* Save GPR registers in word_mode sized hunks.  word_mode hasn't been
+     initialized yet, so we can't use that here.  */
+  gpr_mode = TARGET_64BIT ? DImode : SImode;
+
+  /* Provide default values for align_* for 64-bit targets.  */
+  if (TARGET_64BIT)
+    {
+      if (align_loops == 0) 
+       align_loops = 8;
+      if (align_jumps == 0) 
+       align_jumps = 8;
+      if (align_functions == 0) 
+       align_functions = 8;
+    }
+
+  /* Register global variables with the garbage collector.  */
+  mips_add_gc_roots ();
 }
 
 /* On the mips16, we want to allocate $24 (T_REG) before other
@@ -4527,6 +4822,10 @@ mips_debugger_offset (addr, offset)
                                  ? compute_frame_size (get_frame_size ())
                                  : current_frame_info.total_size;
 
+      /* MIPS16 frame is smaller */
+      if (frame_pointer_needed && TARGET_MIPS16)
+       frame_size -= current_function_outgoing_args_size;
+
       offset = offset - frame_size;
     }
 
@@ -4569,7 +4868,9 @@ mips_debugger_offset (addr, offset)
    '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.
+   'F'  print part of opcode for a floating-point branch condition.
    'N'  print part of opcode for a branch condition, inverted.
+   'W'  print part of opcode for a floating-point branch condition, inverted.
    'S'  X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
    'B'  print 'z' for EQ, 'n' for NE
    'b'  print 'n' for EQ, 'z' for NE
@@ -4593,7 +4894,8 @@ mips_debugger_offset (addr, offset)
    '.' Print the name of the register with a hard-wired zero (zero or $0).
    '^' Print the name of the pic call-through register (t9 or $25).
    '$' Print the name of the stack pointer register (sp or $29).
-   '+' Print the name of the gp register (gp or $28).  */
+   '+' Print the name of the gp register (gp or $28).
+   '~' Output an branch alignment to LABEL_ALIGN(NULL).  */
 
 void
 print_operand (file, op, letter)
@@ -4714,6 +5016,13 @@ print_operand (file, op, letter)
 
          break;
 
+       case '~':
+         {
+           if (align_labels_log > 0)
+             ASM_OUTPUT_ALIGN (file, align_labels_log);
+         }
+       break;
+
        default:
          error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
          break;
@@ -4767,6 +5076,24 @@ print_operand (file, op, letter)
        abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%N");
       }
 
+  else if (letter == 'F')
+    switch (code)
+      {
+      case EQ: fputs ("c1f", file); break;
+      case NE: fputs ("c1t", file); break;
+      default:
+       abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%F");
+      }
+
+  else if (letter == 'W')
+    switch (code)
+      {
+      case EQ: fputs ("c1t", file); break;
+      case NE: fputs ("c1f", file); break;
+      default:
+       abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%W");
+      }
+
   else if (letter == 'S')
     {
       char buffer[100];
@@ -4980,9 +5307,9 @@ print_operand_address (file, addr)
 
 int
 mips_output_external (file, decl, name)
-     FILE *file;
+     FILE *file ATTRIBUTE_UNUSED;
      tree decl;
-     char *name;
+     const char *name;
 {
   register struct extern_list *p;
   int len;
@@ -5026,7 +5353,7 @@ mips_output_external (file, decl, name)
 int
 mips_output_external_libcall (file, name)
      FILE *file;
-     char *name;
+     const char *name;
 {
   register struct extern_list *p;
 
@@ -5051,10 +5378,10 @@ mips_output_external_libcall (file, name)
 #endif
 
 static FILE *
-make_temp_file ()
+mips_make_temp_file ()
 {
   FILE *stream;
-  char *base = getenv ("TMPDIR");
+  const char *base = getenv ("TMPDIR");
   int len;
 
   if (base == 0)
@@ -5100,7 +5427,7 @@ make_temp_file ()
 void
 mips_output_filename (stream, name)
      FILE *stream;
-     char *name;
+     const char *name;
 {
   static int first_time = 1;
   char ltext_label_name[100];
@@ -5192,8 +5519,8 @@ mips_output_lineno (stream, line)
 void
 final_prescan_insn (insn, opvec, noperands)
      rtx insn;
-     rtx opvec[];
-     int noperands;
+     rtx opvec[] ATTRIBUTE_UNUSED;
+     int noperands ATTRIBUTE_UNUSED;
 {
   if (dslots_number_nops > 0)
     {
@@ -5261,7 +5588,7 @@ mips_asm_file_start (stream)
 
   /* 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_EABI)
+  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
@@ -5270,7 +5597,7 @@ mips_asm_file_start (stream)
   if (TARGET_FILE_SWITCHING && ! TARGET_MIPS16)
     {
       asm_out_data_file = stream;
-      asm_out_text_file = make_temp_file ();
+      asm_out_text_file = mips_make_temp_file ();
     }
 
   else
@@ -5335,7 +5662,7 @@ mips_asm_file_end (file)
        fatal_io_error (temp_filename);
 
       while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
-       if (fwrite (buffer, 1, len, file) != len)
+       if ((int) fwrite (buffer, 1, len, file) != len)
          pfatal_with_name (asm_file_name);
 
       if (len < 0)
@@ -5356,9 +5683,9 @@ mips_asm_file_end (file)
 void
 mips_declare_object (stream, name, init_string, final_string, size)
      FILE *stream;
-     char *name;
-     char *init_string;
-     char *final_string;
+     const char *name;
+     const char *init_string;
+     const char *final_string;
      int size;
 {
   fputs (init_string, stream);         /* "", "\t.comm\t", or "\t.lcomm\t" */
@@ -5521,7 +5848,7 @@ compute_frame_size (size)
                  || (GET_MODE_SIZE (DECL_MODE (DECL_RESULT (current_function_decl)))
                      <= 4))))
        {
-         gp_reg_size += UNITS_PER_WORD;
+         gp_reg_size += GET_MODE_SIZE (gpr_mode);
          mask |= 1L << (regno - GP_REG_FIRST);
 
          /* The entry and exit pseudo instructions can not save $17
@@ -5548,7 +5875,11 @@ compute_frame_size (size)
       fp_bits = 3;
     }
 
-  for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc)
+  /* This loop must iterate over the same space as its companion in
+     save_restore_regs.  */
+  for (regno = (FP_REG_LAST - fp_inc + 1);
+       regno >= FP_REG_FIRST;
+       regno -= fp_inc)
     {
       if (regs_ever_live[regno] && !call_used_regs[regno])
        {
@@ -5565,7 +5896,8 @@ 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 && (mips_abi == ABI_32 || mips_abi == ABI_EABI)
+  if (total_size == extra_size 
+      && (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
       && ! profile_flag)
     total_size = extra_size = 0;
   else if (TARGET_ABICALLS)
@@ -5580,7 +5912,7 @@ compute_frame_size (size)
 
   /* Add in space reserved on the stack by the callee for storing arguments
      passed in registers.  */
-  if (mips_abi != ABI_32)
+  if (mips_abi != ABI_32 && mips_abi != ABI_O64)
     total_size += MIPS_STACK_ALIGN (current_function_pretend_args_size);
 
   /* The entry pseudo instruction will allocate 32 bytes on the stack.  */
@@ -5608,9 +5940,10 @@ compute_frame_size (size)
          top of the stack.  */
       if (! mips_entry)
        offset = (args_size + extra_size + var_size
-                 + gp_reg_size - UNITS_PER_WORD);
+                 + gp_reg_size - GET_MODE_SIZE (gpr_mode));
       else
-       offset = total_size - UNITS_PER_WORD;
+       offset = total_size - GET_MODE_SIZE (gpr_mode);
+
       current_frame_info.gp_sp_offset = offset;
       current_frame_info.gp_save_offset = offset - total_size;
     }
@@ -5686,11 +6019,12 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 
       gp_offset = current_frame_info.gp_sp_offset;
       end_offset
-       = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD);
+       = gp_offset - (current_frame_info.gp_reg_size
+                      - GET_MODE_SIZE (gpr_mode));
 
       if (gp_offset < 0 || end_offset < 0)
        fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
-              gp_offset, end_offset);
+              (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.  */
@@ -5704,7 +6038,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
               && (unsigned HOST_WIDE_INT) (large_offset - gp_offset) < 32768
               && (unsigned HOST_WIDE_INT) (large_offset - end_offset) < 32768)
        {
-         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
          base_offset = large_offset;
          if (file == 0)
            {
@@ -5727,7 +6061,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 
       else
        {
-         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
          base_offset = gp_offset;
          if (file == 0)
            {
@@ -5738,7 +6072,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                 split.  */
              /* ??? There is no DImode ori immediate pattern, so we can only
                 do this for 32 bit code.  */
-             if (large_int (gp_offset_rtx)
+             if (large_int (gp_offset_rtx, GET_MODE (gp_offset_rtx))
                  && GET_MODE (base_reg_rtx) == SImode)
                {
                  insn = emit_move_insn (base_reg_rtx,
@@ -5768,13 +6102,16 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                RTX_FRAME_RELATED_P (insn) = 1;
            }
          else
-           fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n",
-                    reg_names[MIPS_TEMP2_REGNUM],
-                    base_offset, base_offset,
-                    Pmode == DImode ? "daddu" : "addu",
-                    reg_names[MIPS_TEMP2_REGNUM],
-                    reg_names[MIPS_TEMP2_REGNUM],
-                    reg_names[STACK_POINTER_REGNUM]);
+           {
+             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]);
+           }
        }
 
       /* When we restore the registers in MIPS16 mode, then if we are
@@ -5797,7 +6134,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
              {
                rtx reg_rtx;
                rtx mem_rtx
-                 = gen_rtx (MEM, word_mode,
+                 = gen_rtx (MEM, gpr_mode,
                             gen_rtx (PLUS, Pmode, base_reg_rtx,
                                      GEN_INT (gp_offset - base_offset)));
 
@@ -5807,43 +6144,45 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                    $31, so we load $7 instead, and work things out
                    in the caller.  */
                if (TARGET_MIPS16 && ! store_p && regno == GP_REG_FIRST + 31)
-                 reg_rtx = gen_rtx (REG, word_mode, GP_REG_FIRST + 7);
+                 reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 7);
                /* The mips16 sometimes needs to save $18.  */
                else if (TARGET_MIPS16
                         && regno != GP_REG_FIRST + 31
                         && ! M16_REG_P (regno))
                  {
                    if (! store_p)
-                     reg_rtx = gen_rtx (REG, word_mode, 6);
+                     reg_rtx = gen_rtx (REG, gpr_mode, 6);
                    else
                      {
-                       reg_rtx = gen_rtx (REG, word_mode, 3);
+                       reg_rtx = gen_rtx (REG, gpr_mode, 3);
                        emit_move_insn (reg_rtx,
-                                       gen_rtx (REG, word_mode, regno));
+                                       gen_rtx (REG, gpr_mode, regno));
                      }
                  }
                else
-                 reg_rtx = gen_rtx (REG, word_mode, regno);
+                 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
+               else if (!TARGET_ABICALLS 
+                        || (mips_abi != ABI_32 && mips_abi != ABI_O64)
                         || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
                  {
                    emit_move_insn (reg_rtx, mem_rtx);
                    if (TARGET_MIPS16
                        && regno != GP_REG_FIRST + 31
                        && ! M16_REG_P (regno))
-                     emit_move_insn (gen_rtx (REG, word_mode, regno),
+                     emit_move_insn (gen_rtx (REG, gpr_mode, regno),
                                      reg_rtx);
                  }
              }
            else
              {
-               if (store_p || !TARGET_ABICALLS || mips_abi != ABI_32
+               if (store_p || !TARGET_ABICALLS 
+                   || (mips_abi != ABI_32 && mips_abi != ABI_O64)
                    || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
                  {
                    int r = regno;
@@ -5867,13 +6206,14 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                                     reg_names[r], reg_names[regno]);
                          }
                      }
-                   fprintf (file, "\t%s\t%s,%ld(%s)\n",
+                   fprintf (file, "\t%s\t%s,",
                             (TARGET_64BIT
                              ? (store_p) ? "sd" : "ld"
                              : (store_p) ? "sw" : "lw"),
-                            reg_names[r],
-                            gp_offset - base_offset,
-                            reg_names[REGNO(base_reg_rtx)]);
+                            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
@@ -5883,7 +6223,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                  }
 
              }
-           gp_offset -= UNITS_PER_WORD;
+           gp_offset -= GET_MODE_SIZE (gpr_mode);
          }
     }
   else
@@ -5901,7 +6241,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 
       if (fp_offset < 0 || end_offset < 0)
        fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
-              fp_offset, end_offset);
+              (long) fp_offset, (long) end_offset);
 
       else if (fp_offset < 32768)
        base_reg_rtx = stack_pointer_rtx, base_offset  = 0;
@@ -5915,7 +6255,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
               && (unsigned HOST_WIDE_INT) (large_offset - fp_offset) < 32768
               && (unsigned HOST_WIDE_INT) (large_offset - end_offset) < 32768)
        {
-         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
          base_offset = large_offset;
          if (file == 0)
            {
@@ -5939,7 +6279,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 
       else
        {
-         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
          base_offset = fp_offset;
          if (file == 0)
            {
@@ -5950,7 +6290,7 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                 split.  */
              /* ??? There is no DImode ori immediate pattern, so we can only
                 do this for 32 bit code.  */
-             if (large_int (fp_offset_rtx)
+             if (large_int (fp_offset_rtx, GET_MODE (fp_offset_rtx))
                  && GET_MODE (base_reg_rtx) == SImode)
                {
                  insn = emit_move_insn (base_reg_rtx,
@@ -5981,16 +6321,23 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                RTX_FRAME_RELATED_P (insn) = 1;
            }
          else
-           fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\t%s\t%s,%s,%s\n",
-                    reg_names[MIPS_TEMP2_REGNUM],
-                    base_offset, base_offset,
-                    Pmode == DImode ? "daddu" : "addu",
-                    reg_names[MIPS_TEMP2_REGNUM],
-                    reg_names[MIPS_TEMP2_REGNUM],
-                    reg_names[STACK_POINTER_REGNUM]);
+           {
+             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]);
+           }
        }
 
-      for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
+      /* This loop must iterate over the same space as its companion in
+        compute_frame_size.  */
+      for (regno = (FP_REG_LAST - fp_inc + 1);
+          regno >= FP_REG_FIRST;
+          regno -= fp_inc)
        if (BITSET_P (fmask, regno - FP_REG_FIRST))
          {
            if (file == 0)
@@ -6013,13 +6360,16 @@ save_restore_insns (store_p, large_reg, large_offset, file)
                  emit_move_insn (reg_rtx, mem_rtx);
              }
            else
-             fprintf (file, "\t%s\t%s,%ld(%s)\n",
-                      (TARGET_SINGLE_FLOAT
-                       ? (store_p ? "s.s" : "l.s")
-                       : (store_p ? "s.d" : "l.d")),
-                      reg_names[regno],
-                      fp_offset - base_offset,
-                      reg_names[REGNO(base_reg_rtx)]);
+             {
+               fprintf (file, "\t%s\t%s,",
+                        (TARGET_SINGLE_FLOAT
+                         ? (store_p ? "s.s" : "l.s")
+                         : (store_p ? "s.d" : "l.d")),
+                        reg_names[regno]);
+               fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+                        fp_offset - base_offset);
+               fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
+             }
 
            fp_offset -= fp_size;
          }
@@ -6031,10 +6381,10 @@ save_restore_insns (store_p, large_reg, large_offset, file)
 void
 function_prologue (file, size)
      FILE *file;
-     int size;
+     int size ATTRIBUTE_UNUSED;
 {
 #ifndef FUNCTION_NAME_ALREADY_DECLARED
-  char *fnname;
+  const char *fnname;
 #endif
   long tsize = current_frame_info.total_size;
 
@@ -6074,22 +6424,31 @@ function_prologue (file, size)
 
   if (!flag_inhibit_size_directive)
     {
+      /* .frame FRAMEREG, FRAMESIZE, RETREG */
       fprintf (file,
               "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
               (reg_names[(frame_pointer_needed)
                          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
-              tsize, reg_names[31 + GP_REG_FIRST],
+              ((frame_pointer_needed && TARGET_MIPS16)
+               ? (tsize - current_function_outgoing_args_size)
+               : tsize),
+              reg_names[31 + GP_REG_FIRST],
               current_frame_info.var_size,
               current_frame_info.num_gp,
               current_frame_info.num_fp,
               current_function_outgoing_args_size,
               current_frame_info.extra_size);
 
+      /* .mask MASK, GPOFFSET; .fmask FPOFFSET */
       fprintf (file, "\t.mask\t0x%08lx,%ld\n\t.fmask\t0x%08lx,%ld\n",
               current_frame_info.mask,
               current_frame_info.gp_save_offset,
               current_frame_info.fmask,
               current_frame_info.fp_save_offset);
+
+      /* Require:
+        OLD_SP == *FRAMEREG + FRAMESIZE => can find old_sp from nominated FP reg.
+        HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs. */
     }
 
   if (mips_entry && ! mips_can_use_return_insn ())
@@ -6207,9 +6566,9 @@ function_prologue (file, size)
       fprintf (file, "\n");
     }
 
-  if (TARGET_ABICALLS && mips_abi == ABI_32)
+  if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64))
     {
-      char *sp_str = reg_names[STACK_POINTER_REGNUM];
+      const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
 
       fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
               reg_names[PIC_FUNCTION_ADDR_REGNUM]);
@@ -6234,7 +6593,7 @@ mips_expand_prologue ()
   int regno;
   HOST_WIDE_INT tsize;
   rtx tmp_rtx = 0;
-  char *arg_name = 0;
+  const char *arg_name = 0;
   tree fndecl = current_function_decl;
   tree fntype = TREE_TYPE (fndecl);
   tree fnargs = DECL_ARGUMENTS (fndecl);
@@ -6335,7 +6694,7 @@ mips_expand_prologue ()
 
   /* If this function is a varargs function, store any registers that
      would normally hold arguments ($4 - $7) on the stack.  */
-  if (mips_abi == ABI_32
+  if ((mips_abi == ABI_32 || mips_abi == ABI_O64)
       && (! mips_entry || mips_can_use_return_insn ())
       && ((TYPE_ARG_TYPES (fntype) != 0
           && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -6357,9 +6716,10 @@ mips_expand_prologue ()
        {
          if (offset != 0)
            ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset));
-         emit_move_insn (gen_rtx (MEM, word_mode, ptr),
-                         gen_rtx (REG, word_mode, regno));
-         offset += UNITS_PER_WORD;
+         emit_move_insn (gen_rtx (MEM, gpr_mode, ptr),
+                         gen_rtx (REG, gpr_mode, regno));
+
+         offset += GET_MODE_SIZE (gpr_mode);
        }
     }
 
@@ -6404,7 +6764,7 @@ mips_expand_prologue ()
         moment.  */
       if (TARGET_MIPS16 && BITSET_P (current_frame_info.mask, 18))
        {
-         rtx reg_rtx = gen_rtx (REG, word_mode, GP_REG_FIRST + 3);
+         rtx reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 3);
          long gp_offset, base_offset;
 
          gp_offset = current_frame_info.gp_sp_offset;
@@ -6420,8 +6780,8 @@ mips_expand_prologue ()
            base_offset = 0;
          start_sequence ();
          emit_move_insn (reg_rtx,
-                         gen_rtx (REG, word_mode, GP_REG_FIRST + 18));
-         emit_move_insn (gen_rtx (MEM, word_mode,
+                         gen_rtx (REG, gpr_mode, GP_REG_FIRST + 18));
+         emit_move_insn (gen_rtx (MEM, gpr_mode,
                                   gen_rtx (PLUS, Pmode, stack_pointer_rtx,
                                            GEN_INT (gp_offset
                                                     - base_offset))),
@@ -6447,7 +6807,7 @@ mips_expand_prologue ()
       /* If we are doing svr4-abi, sp move is done by
          function_prologue.  In mips16 mode with a large frame, we
          save the registers before adjusting the stack.  */
-      if ((!TARGET_ABICALLS || mips_abi != ABI_32)
+      if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
          && (!TARGET_MIPS16 || tsize <= 32767))
        {
          rtx insn;
@@ -6461,7 +6821,8 @@ mips_expand_prologue ()
                 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 (tmp_rtx) == SImode)
+             if (large_int (tsize_rtx, GET_MODE (tsize_rtx))
+                 && GET_MODE (tmp_rtx) == SImode)
                {
                  insn = emit_move_insn (tmp_rtx,
                                         GEN_INT (tsize & 0xffff0000));
@@ -6494,7 +6855,7 @@ mips_expand_prologue ()
       else if (reg_18_save != NULL_RTX)
        emit_insn (reg_18_save);
 
-      if ((!TARGET_ABICALLS || mips_abi != ABI_32)
+      if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
          && TARGET_MIPS16
          && tsize > 32767)
        {
@@ -6525,7 +6886,7 @@ mips_expand_prologue ()
              instructions when using the frame pointer by pointing the
              frame pointer ahead of the argument space allocated on
              the stack.  */
-         if ((! TARGET_ABICALLS || mips_abi != ABI_32)
+         if ((! TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
              && TARGET_MIPS16
              && tsize > 32767)
            {
@@ -6568,9 +6929,9 @@ mips_expand_prologue ()
            RTX_FRAME_RELATED_P (insn) = 1;
        }
 
-      if (TARGET_ABICALLS && mips_abi != ABI_32)
+      if (TARGET_ABICALLS && (mips_abi != ABI_32 && mips_abi != ABI_O64))
        emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0),
-                              gen_rtx (REG, DImode, 25)));
+                              gen_rtx_REG (DImode, 25)));
     }
 
   /* If we are profiling, make sure no instructions are scheduled before
@@ -6588,10 +6949,10 @@ mips_expand_prologue ()
 
 void
 function_epilogue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+     FILE *file ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
 {
-  char *fnname;
+  const char *fnname;
 
 #ifndef FUNCTION_NAME_ALREADY_DECLARED
   /* Get the function name the same way that toplev.c does before calling
@@ -6612,7 +6973,7 @@ function_epilogue (file, size)
       int num_gp_regs = current_frame_info.gp_reg_size / 4;
       int num_fp_regs = current_frame_info.fp_reg_size / 8;
       int num_regs = num_gp_regs + num_fp_regs;
-      char *name = fnname;
+      const char *name = fnname;
 
       if (name[0] == '*')
        name++;
@@ -6620,7 +6981,7 @@ function_epilogue (file, size)
       dslots_load_total += num_regs;
 
       fprintf (stderr,
-              "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
+              "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3d reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
               name, frame_pointer_needed ? 'y' : 'n',
               (current_frame_info.mask & RA_MASK) != 0 ? 'n' : 'y',
               current_function_calls_alloca ? 'y' : 'n',
@@ -6699,7 +7060,7 @@ mips_expand_epilogue ()
 
   if (tsize > 32767 && ! TARGET_MIPS16)
     {
-      tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
+      tmp_rtx = gen_rtx_REG (Pmode, MIPS_TEMP1_REGNUM);
       emit_move_insn (tmp_rtx, tsize_rtx);
       tsize_rtx = tmp_rtx;
     }
@@ -6752,7 +7113,7 @@ mips_expand_epilogue ()
       /* The GP/PIC register is implicitly used by all SYMBOL_REFs, so if we
         are going to restore it, then we must emit a blockage insn to
         prevent the scheduler from moving the restore out of the epilogue.  */
-      else if (TARGET_ABICALLS && mips_abi != ABI_32
+      else if (TARGET_ABICALLS && mips_abi != ABI_32 && mips_abi != ABI_O64
               && (current_frame_info.mask
                   & (1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))))
        emit_insn (gen_blockage ());
@@ -6816,20 +7177,43 @@ mips_can_use_return_insn ()
   return compute_frame_size (get_frame_size ()) == 0;
 }
 \f
+/* Returns non-zero if X contains a SYMBOL_REF.  */
+
+static int
+symbolic_expression_p (x)
+     rtx x;
+{
+  if (GET_CODE (x) == SYMBOL_REF)
+    return 1;
+
+  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));
+
+  if (GET_RTX_CLASS (GET_CODE (x)) == 'c'
+      || GET_RTX_CLASS (GET_CODE (x)) == '2')
+    return (symbolic_expression_p (XEXP (x, 0))
+           || symbolic_expression_p (XEXP (x, 1)));
+
+  return 0;
+}
+
 /* Choose the section to use for the constant rtx expression X that has
    mode MODE.  */
 
 void
 mips_select_rtx_section (mode, x)
      enum machine_mode mode;
-     rtx x;
+     rtx x ATTRIBUTE_UNUSED;
 {
   if (TARGET_MIPS16)
     {
-      /* In mips16 mode, the constant table always goes in the .text
-         section, so that constants can be loaded using PC relative
+      /* In mips16 mode, the constant table always goes in the same section
+         as the function, so that constants can be loaded using PC relative
          addressing.  */
-      text_section ();
+      function_section (current_function_decl);
     }
   else if (TARGET_EMBEDDED_DATA)
     {
@@ -6845,13 +7229,30 @@ mips_select_rtx_section (mode, x)
       if (GET_MODE_SIZE (mode) <= mips_section_threshold
          && mips_section_threshold > 0)
        SMALL_DATA_SECTION ();
+      else if (flag_pic && symbolic_expression_p (x))
+       /* Any expression involving a SYMBOL_REF might need a run-time
+          relocation.  (The symbol might be defined in a shared
+          library loaded at an unexpected base address.)  So, we must
+          put such expressions in the data segment (which is
+          writable), rather than the text segment (which is
+          read-only).  */
+       data_section ();
       else
        READONLY_DATA_SECTION ();
     }
 }
 
 /* Choose the section to use for DECL.  RELOC is true if its value contains
-   any relocatable expression.  */
+   any relocatable expression.
+
+   Some of the logic used here needs to be replicated in
+   ENCODE_SECTION_INFO in mips.h so that references to these symbols
+   are done correctly.  Specifically, at least all symbols assigned
+   here to rom (.text and/or .rodata) must not be referenced via
+   ENCODE_SECTION_INFO with %gprel, as the rom might be too far away.
+
+   If you need to make a change here, you probably should check
+   ENCODE_SECTION_INFO to see if it needs a similar change.  */
 
 void
 mips_select_section (decl, reloc)
@@ -6922,7 +7323,7 @@ mips_select_section (decl, reloc)
 rtx
 mips_function_value (valtype, func)
      tree valtype;
-     tree func;
+     tree func ATTRIBUTE_UNUSED;
 {
   int reg = GP_RETURN;
   enum machine_mode mode = TYPE_MODE (valtype);
@@ -6945,7 +7346,9 @@ mips_function_value (valtype, func)
     }
 
   else if (TREE_CODE (valtype) == RECORD_TYPE
-          && mips_abi != ABI_32 && mips_abi != ABI_EABI)
+          && 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
         the floating point registers.  */
@@ -6974,12 +7377,13 @@ mips_function_value (valtype, func)
                 strictly necessary.  */
              enum machine_mode field_mode = TYPE_MODE (TREE_TYPE (fields[0]));
 
-             return gen_rtx (PARALLEL, mode,
-                             gen_rtvec (1,
-                                        gen_rtx (EXPR_LIST, VOIDmode,
-                                                 gen_rtx (REG, field_mode,
-                                                          FP_RETURN),
-                                                 const0_rtx)));
+             return gen_rtx_PARALLEL
+               (mode,
+                gen_rtvec (1,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (field_mode,
+                                                           FP_RETURN),
+                                              const0_rtx)));
            }
 
          else if (i == 2)
@@ -6993,37 +7397,51 @@ mips_function_value (valtype, func)
              int second_offset
                = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fields[1]));
 
-             return gen_rtx (PARALLEL, mode,
-                             gen_rtvec (2,
-                                        gen_rtx (EXPR_LIST, VOIDmode,
-                                                 gen_rtx (REG, first_mode,
-                                                          FP_RETURN),
-                                                 GEN_INT (first_offset
-                                                          / BITS_PER_UNIT)),
-                                        gen_rtx (EXPR_LIST, VOIDmode,
-                                                 gen_rtx (REG, second_mode,
-                                                          FP_RETURN + 2),
-                                                 GEN_INT (second_offset
-                                                          / BITS_PER_UNIT))));
+             return gen_rtx_PARALLEL
+               (mode,
+                gen_rtvec (2,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (first_mode,
+                                                           FP_RETURN),
+                                              GEN_INT (first_offset
+                                                       / BITS_PER_UNIT)),
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (second_mode,
+                                                           FP_RETURN + 2),
+                                              GEN_INT (second_offset
+                                                       / BITS_PER_UNIT))));
            }
        }
     }
 
-  return gen_rtx (REG, mode, reg);
+  return gen_rtx_REG (mode, reg);
 }
+#endif
 
 /* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE.  Return
    nonzero when an argument must be passed by reference.  */
 
 int
 function_arg_pass_by_reference (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;
+     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
      enum machine_mode mode;
      tree type;
-     int named;
+     int named ATTRIBUTE_UNUSED;
 {
   int size;
 
+  /* We must pass by reference if we would be both passing in registers
+     and the stack.  This is because any subsequent partial arg would be
+     handled incorrectly in this case.
+
+     ??? This is really a kludge.  We should either fix GCC so that such
+     a situation causes an abort and then do something in the MIPS port
+     to prevent it, or add code to function.c to properly handle the case.  */
+  if (FUNCTION_ARG (*cum, mode, type, named) != 0
+      && MUST_PASS_IN_STACK (mode, type))
+    return 1;
+
+  /* Otherwise, we only do this if EABI is selected.  */
   if (mips_abi != ABI_EABI)
     return 0;
 
@@ -7034,7 +7452,6 @@ function_arg_pass_by_reference (cum, mode, type, named)
   size = int_size_in_bytes (type);
   return size == -1 || size > UNITS_PER_WORD;
 }
-#endif
 
 /* This function returns the register class required for a secondary
    register when copying between one of the registers in CLASS, and X,
@@ -7145,6 +7562,19 @@ mips_secondary_reload_class (class, mode, x, in_p)
        }
       if (! gp_reg_p)
        {
+         /* The stack pointer isn't a valid operand to an add instruction,
+            so we need to load it into M16_REGS first.  This can happen as
+            a result of register elimination and form_sum converting
+            (plus reg (plus SP CONST)) to (plus (plus reg SP) CONST).  We
+            need an extra register if the dest is the same as the other
+            register.  In that case, we can't fix the problem by loading SP
+            into the dest first.  */
+         if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG
+             && GET_CODE (XEXP (x, 1)) == REG
+             && (XEXP (x, 0) == stack_pointer_rtx
+                 || XEXP (x, 1) == stack_pointer_rtx))
+           return (class == M16_REGS ? M16_NA_REGS : M16_REGS);
+
          if (class == M16_REGS || class == M16_NA_REGS)
            return NO_REGS;
          return M16_REGS;
@@ -7365,7 +7795,7 @@ mips16_constant (x, mode, addr, addend)
          ASM_GENERATE_INTERNAL_LABEL as called by output_constant_def.  */
       if (SYMBOL_REF_FLAG (x))
        {
-         char *name = XSTR (x, 0);
+         const char *name = XSTR (x, 0);
 
          return (name[0] == '*'
                  && strncmp (name + 1, LOCAL_LABEL_PREFIX,
@@ -7403,12 +7833,12 @@ mips16_fp_args (file, fp_code, from_fp_p)
      int fp_code;
      int from_fp_p;
 {
-  char *s;
+  const char *s;
   int gparg, fparg;
   unsigned int f;
 
-  /* This code only works for the original 32 bit ABI.  */
-  if (mips_abi != ABI_32)
+  /* This code only works for the original 32 bit ABI and the O64 ABI.  */
+  if (mips_abi != ABI_32 && mips_abi != ABI_O64)
     abort ();
 
   if (from_fp_p)
@@ -7435,9 +7865,14 @@ mips16_fp_args (file, fp_code, from_fp_p)
            {
              if ((fparg & 1) != 0)
                ++fparg;
-             fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
-                      reg_names[gparg], reg_names[fparg + 1], s,
-                      reg_names[gparg + 1], reg_names[fparg]);
+             if (TARGET_BIG_ENDIAN)
+               fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
+                        reg_names[gparg], reg_names[fparg + 1], s,
+                        reg_names[gparg + 1], reg_names[fparg]);
+             else
+               fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
+                        reg_names[gparg], reg_names[fparg], s,
+                        reg_names[gparg + 1], reg_names[fparg + 1]);
              ++gparg;
              ++fparg;
            }
@@ -7459,7 +7894,7 @@ static void
 build_mips16_function_stub (file)
      FILE *file;
 {
-  char *fnname;
+  const char *fnname;
   char *secname, *stubname;
   tree stubid, stubdecl;
   int need_comma;
@@ -7571,7 +8006,8 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
 {
   int fpret;
   rtx fn;
-  char *fnname, *secname, *stubname;
+  const char *fnname;
+  char *secname, *stubname;
   struct mips16_stub *l;
   tree stubid, stubdecl;
   int need_comma;
@@ -7605,9 +8041,9 @@ 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 the standard ABI.  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)
+  if (mips_abi != ABI_32 && mips_abi != ABI_O64)
     abort ();
 
   /* We can only handle SFmode and DFmode floating point return
@@ -7778,12 +8214,24 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
                     reg_names[GP_REG_FIRST + 2], reg_names[FP_REG_FIRST + 0]);
          else
            {
-             fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
-                      reg_names[GP_REG_FIRST + 2],
-                      reg_names[FP_REG_FIRST + 1]);
-             fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
-                      reg_names[GP_REG_FIRST + 3],
-                      reg_names[FP_REG_FIRST + 0]);
+             if (TARGET_BIG_ENDIAN)
+               {
+                 fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                          reg_names[GP_REG_FIRST + 2],
+                          reg_names[FP_REG_FIRST + 1]);
+                 fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                          reg_names[GP_REG_FIRST + 3],
+                          reg_names[FP_REG_FIRST + 0]);
+               }
+             else
+               {
+                 fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                          reg_names[GP_REG_FIRST + 2],
+                          reg_names[FP_REG_FIRST + 0]);
+                 fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                          reg_names[GP_REG_FIRST + 3],
+                          reg_names[FP_REG_FIRST + 1]);
+               }
            }
          fprintf (asm_out_file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 18]);
          /* As above, we can't fill the delay slot.  */
@@ -7806,8 +8254,7 @@ build_mips16_call_stub (retval, fnmem, arg_size, fp_code)
 
       /* Record this stub.  */
       l = (struct mips16_stub *) xmalloc (sizeof *l);
-      l->name = (char *) xmalloc (strlen (fnname) + 1);
-      strcpy (l->name, fnname);
+      l->name = xstrdup (fnname);
       l->fpret = fpret;
       l->next = mips16_stubs;
       mips16_stubs = l;
@@ -8225,7 +8672,7 @@ void
 machine_dependent_reorg (first)
      rtx first;
 {
-  int insns_len, max_internal_pool_size, pool_size, addr;
+  int insns_len, max_internal_pool_size, pool_size, addr, first_constant_ref;
   rtx insn;
   struct constant *constants;
 
@@ -8246,7 +8693,7 @@ machine_dependent_reorg (first)
   insns_len = 0;
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
-      insns_len += get_attr_length (insn) * 2;
+      insns_len += get_attr_length (insn);
 
       /* ??? We put switch tables in .text, but we don't define
          JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
@@ -8293,6 +8740,7 @@ machine_dependent_reorg (first)
 
   constants = NULL;
   addr = 0;
+  first_constant_ref = -1;
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
@@ -8351,10 +8799,13 @@ machine_dependent_reorg (first)
                                        SET_DEST (PATTERN (insn)),
                                        newsrc);
              INSN_CODE (insn) = -1;
+
+             if (first_constant_ref < 0)
+               first_constant_ref = addr;
            }
        }
 
-      addr += get_attr_length (insn) * 2;
+      addr += get_attr_length (insn);
 
       /* ??? We put switch tables in .text, but we don't define
          JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
@@ -8382,27 +8833,33 @@ machine_dependent_reorg (first)
          if (constants != NULL)
            dump_constants (constants, insn);
          constants = NULL;
+         first_constant_ref = -1;
        }
+      
+      if (constants != NULL
+              && (NEXT_INSN (insn) == NULL 
+                  || (first_constant_ref >= 0 
+                      && (((addr - first_constant_ref)
+                           + 2 /* for alignment */
+                           + 2 /* for a short jump insn */
+                           + pool_size)
+                          >= 0x8000))))
+       {
+         /* 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. */
 
-      /* ??? If we don't find a barrier within 0x8000 bytes of
-         instructions and constants in CONSTANTS, we need to invent
-         one.  This seems sufficiently unlikely that I am not going to
-         worry about it.  */
-    }
-
-  if (constants != NULL)
-    {
-      rtx label, jump, barrier;
-
-      label = gen_label_rtx ();
-      jump = emit_jump_insn_after (gen_jump (label), get_last_insn ());
-      JUMP_LABEL (jump) = label;
-      LABEL_NUSES (label) = 1;
-      barrier = emit_barrier_after (jump);
-      emit_label_after (label, barrier);
-      dump_constants (constants, barrier);
-      constants = NULL;
-    }
+         rtx label, jump, barrier;
+             
+         label = gen_label_rtx ();
+         jump = emit_jump_insn_after (gen_jump (label), insn);
+         JUMP_LABEL (jump) = label;
+         LABEL_NUSES (label) = 1;
+         barrier = emit_barrier_after (jump);
+         emit_label_after (label, barrier);
+         first_constant_ref = -1;
+       }
+     }
 
   /* ??? If we output all references to a constant in internal
      constants table, we don't need to output the constant in the real
@@ -8413,7 +8870,7 @@ machine_dependent_reorg (first)
 int
 extend_operator (x, mode)
      rtx x;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   enum rtx_code code = GET_CODE (x);
   return code == SIGN_EXTEND || code == ZERO_EXTEND;
@@ -8426,7 +8883,7 @@ extend_operator (x, mode)
 int
 highpart_shift_operator (x, mode)
      rtx x;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   enum rtx_code code = GET_CODE (x);
   return (code == LSHIFTRT
@@ -8434,3 +8891,312 @@ highpart_shift_operator (x, mode)
          || code == ROTATERT
          || code == ROTATE);
 }
+
+/* Return the length of INSN.  LENGTH is the initial length computed by 
+   attributes in the machine-description file.  */
+
+int
+mips_adjust_insn_length (insn, length)
+     rtx insn;
+     int length;
+{
+  /* A unconditional jump has an unfilled delay slot if it is not part
+     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 
+                             || GET_CODE (insn) == CALL_INSN)))
+    length += 4;
+
+  /* All MIPS16 instructions are a measly two bytes.  */
+  if (TARGET_MIPS16)
+    length /= 2;
+
+  return length;
+}
+
+/* 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
+   of the first operand to the condition.  If TWO_OPERANDS_P is
+   non-zero the comparison takes two operands; OPERANDS[3] will be the
+   second operand.
+
+   If INVERTED_P is non-zero we are to branch if the condition does
+   not hold.  If FLOAT_P is non-zero this is a floating-point comparison.
+
+   LENGTH is the length (in bytes) of the sequence we are to generate.
+   That tells us whether to generate a simple conditional branch, or a
+   reversed conditional branch around a `jr' instruction.  */
+char *
+mips_output_conditional_branch (insn, 
+                               operands, 
+                               two_operands_p,
+                               float_p,
+                               inverted_p,
+                               length)
+     rtx insn;
+     rtx *operands;
+     int two_operands_p;
+     int float_p;
+     int inverted_p;
+     int length;
+{
+  static char buffer[200];
+  /* The kind of comparison we are doing.  */
+  enum rtx_code code = GET_CODE (operands[0]);
+  /* Non-zero if the opcode for the comparison needs a `z' indicating
+     that it is a comparision against zero.  */
+  int need_z_p;
+  /* A string to use in the assembly output to represent the first
+     operand.  */
+  const char *op1 = "%z2";
+  /* A string to use in the assembly output to represent the second
+     operand.  Use the hard-wired zero register if there's no second
+     operand.  */
+  const char *op2 = (two_operands_p ? ",%z3" : ",%.");
+  /* The operand-printing string for the comparison.  */
+  const char *comp = (float_p ? "%F0" : "%C0");
+  /* The operand-printing string for the inverted comparison.  */
+  const char *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
+     annul the instruction in the delay slot if the branch is not
+     taken.  */
+  mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
+
+  if (!two_operands_p)
+    {
+      /* To compute whether than A > B, for example, we normally
+        subtract B from A and then look at the sign bit.  But, if we
+        are doing an unsigned comparison, and B is zero, we don't
+        have to do the subtraction.  Instead, we can just check to
+        see if A is non-zero.  Thus, we change the CODE here to
+        reflect the simpler comparison operation.  */
+      switch (code)
+       {
+       case GTU:
+         code = NE;
+         break;
+
+       case LEU:
+         code = EQ;
+         break;
+
+       case GEU:
+         /* A condition which will always be true.  */
+         code = EQ;
+         op1 = "%.";
+         break;
+
+       case LTU:
+         /* A condition which will always be false. */
+         code = NE;
+         op1 = "%.";
+         break;
+
+       default:
+         /* Not a special case.  */
+         break;
+       }
+    }
+
+  /* Relative comparisons are always done against zero.  But
+     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 
+     explicitly.  */
+  if (need_z_p)
+    op2 = "";
+
+  /* Begin by terminating the buffer.  That way we can always use
+     strcat to add to it.  */
+  buffer[0] = '\0';
+
+  switch (length) 
+    {
+    case 4:
+    case 8:
+      /* Just a simple conditional branch.  */
+      if (float_p)
+       sprintf (buffer, "%%*b%s%%?\t%%Z2%%1",
+                inverted_p ? inverted_comp : comp);
+      else
+       sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1",
+                inverted_p ? inverted_comp : comp,
+                need_z_p ? "z" : "",
+                op1,
+                op2);
+      return buffer;
+
+    case 12:
+    case 16:
+      {
+       /* Generate a reversed conditional branch around ` j'
+          instruction:
+
+               .set noreorder
+               .set nomacro
+               bc    l
+               nop
+               j     target
+               .set macro
+               .set reorder
+            l:
+
+          Because we have to jump four bytes *past* the following
+          instruction if this branch was annulled, we can't just use
+          a label, as in the picture above; there's no way to put the
+          label after the next instruction, as the assembler does not
+          accept `.L+4' as the target of a branch.  (We can't just
+          wait until the next instruction is output; it might be a
+          macro and take up more than four bytes.  Once again, we see
+          why we want to eliminate macros.)
+          
+          If the branch is annulled, we jump four more bytes that we
+          would otherwise; that way we skip the annulled instruction
+          in the delay slot.  */
+
+       const char *target 
+         = ((mips_branch_likely || length == 16) ? ".+16" : ".+12");
+       char *c;
+
+       strcpy (buffer, "%(%<");
+       c = strchr (buffer, '\0');
+       /* Generate the reversed comparision.  This takes four 
+          bytes.  */
+       if (float_p)
+         sprintf (c, "%%*b%s\t%%Z2%s",
+                  inverted_p ? comp : inverted_comp,
+                  target);
+       else
+         sprintf (c, "%%*b%s%s\t%s%s,%s",
+                  inverted_p ? comp : inverted_comp,
+                  need_z_p ? "z" : "",
+                  op1,
+                  op2,
+                  target);
+       strcat (c, "\n\tnop\n\tj\t%1");
+       if (length == 16)
+         /* The delay slot was unfilled.  Since we're inside
+            .noreorder, the assembler will not fill in the NOP for
+            us, so we must do it ourselves.  */
+         strcat (buffer, "\n\tnop");
+       strcat (buffer, "%>%)");
+       return buffer;
+      }
+
+    /* We do not currently use this code.  It handles jumps to
+       arbitrary locations, using `jr', even across a 256MB boundary.
+       We could add a -mhuge switch, and then use this code instead of
+       the `j' alternative above when -mhuge was used.  */
+#if 0
+    case 16:
+    case 20:
+      {
+       /* Generate a reversed conditional branch around a `jr'
+          instruction:
+
+                .set noreorder
+                .set nomacro
+                .set noat
+                bc    l
+                la    $at, target
+                jr    $at
+                .set at
+                .set macro
+                .set reorder
+             l:
+
+          Not pretty, but allows a conditional branch anywhere in the
+          32-bit address space.  If the original branch is annulled,
+          then the instruction in the delay slot should be executed
+          only if the branch is taken.  The la instruction is really
+          a macro which will usually take eight bytes, but sometimes
+          takes only four, if the instruction to which we're jumping
+          gets its own entry in the global pointer table, which will
+          happen if its a case label.  The assembler will then
+          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'.  
+
+          So, we resort to using the explicit relocation syntax
+          available in the assembler and do:
+
+             lw $at,%got_page(target)($gp)
+             daddiu $at,$at,%got_ofst(target)
+
+          That way, this always takes up eight bytes, and we can use
+          the `.+x' form.  Of course, these explicit machinations
+          with relocation will not work with old assemblers.  Then
+          again, neither do out-of-range branches, so we haven't lost
+          anything.  */
+
+       /* The target of the reversed branch.  */
+       const char *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];
+       char *c;
+
+       strcpy (buffer, "%(%<%[");
+       c = strchr (buffer, '\0');
+       /* Generate the reversed comparision.  This takes four 
+          bytes.  */
+       if (float_p)
+         sprintf (c, "%%*b%s\t%%Z2%s",
+                  inverted_p ? comp : inverted_comp,
+                  target);
+       else
+         sprintf (c, "%%*b%s%s\t%s%s,%s",
+                  inverted_p ? comp : inverted_comp,
+                  need_z_p ? "z" : "",
+                  op1,
+                  op2,
+                  target);
+       c = strchr (buffer, '\0');
+       /* Generate the load-address, and jump.  This takes twelve
+          bytes, for a total of 16.  */
+       sprintf (c,
+                "\n\tlw\t%s,%%%%got_page(%%1)(%s)\n\tdaddiu\t%s,%s,%%%%got_ofst(%%1)\n\tjr\t%s",
+                at_register,
+                gp_register,
+                at_register,
+                at_register,
+                at_register);
+       if (length == 20)
+         /* The delay slot was unfilled.  Since we're inside
+            .noreorder, the assembler will not fill in the NOP for
+            us, so we must do it ourselves.  */
+         strcat (buffer, "\n\tnop");
+       strcat (buffer, "%]%>%)");
+       return buffer;
+      }
+#endif
+
+    default:
+      abort ();
+    }
+
+  /* NOTREACHED */
+  return 0;
+}
+
+/* Called to register all of our global variables with the garbage
+   collector.  */
+
+static void
+mips_add_gc_roots ()
+{
+  ggc_add_rtx_root (&mips_load_reg, 1);
+  ggc_add_rtx_root (&mips_load_reg2, 1);
+  ggc_add_rtx_root (&mips_load_reg3, 1);
+  ggc_add_rtx_root (&mips_load_reg4, 1);
+  ggc_add_rtx_root (branch_cmp, sizeof (branch_cmp) / sizeof (rtx));
+  ggc_add_rtx_root (&embedded_pic_fnaddr_rtx, 1);
+  ggc_add_rtx_root (&mips16_gp_pseudo_rtx, 1);
+}