OSDN Git Service

* config/mips/mips.c (mips_explicit_type_size_string): Correct
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index e10c048..a4b38e1 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,14 +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"
@@ -46,25 +40,16 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "insn-codes.h"
 #include "recog.h"
-#include "output.h"
+#include "toplev.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 "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"
 
 #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;
 
 /* Enumeration for all of the relational tests, so that we can build
    arrays indexed by the test type, and not worry about the order
@@ -132,6 +106,8 @@ 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;
 
 
 /* Global variables for machine-dependent things.  */
@@ -174,7 +150,7 @@ struct extern_list
 } *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 +208,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 +219,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 +235,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 +251,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];
@@ -499,7 +483,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 +494,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 +550,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 +599,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 +964,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 +983,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 +1166,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 +1228,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 +1236,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 +1244,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 +1252,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 +1260,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 +1268,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 +1276,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 +1284,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 +1292,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 +1300,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 +1308,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 +1316,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 +1324,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 +1332,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 +1340,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 +1348,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 +1362,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 +1389,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)
@@ -1645,13 +1656,13 @@ embedded_pic_offset (x)
 
 /* 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 +1801,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 +2025,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 +2050,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 +2358,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 +2469,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 +2716,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 +2744,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))
            {
@@ -3136,6 +3148,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 +3231,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 +3251,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 +3265,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 +3361,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)
@@ -3561,9 +3577,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 +3627,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 +3710,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 +3760,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 +3784,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,7 +3816,7 @@ function_arg (cum, mode, type, named)
        abort ();
 
       if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
-         || mips_abi == ABI_EABI || ! named)
+         || mips_abi == ABI_EABI || mips_abi == ABI_O64 || ! named)
        ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
       else
        {
@@ -3925,7 +3950,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
@@ -3964,10 +3989,10 @@ function_arg_partial_nregs (cum, mode, type, named)
 \f
 /* Abort after printing out a specific insn.  */
 
-void
+static void
 abort_with_insn (insn, reason)
      rtx insn;
-     char *reason;
+     const char *reason;
 {
   error (reason);
   debug_rtx (insn);
@@ -4018,7 +4043,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 +4076,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 +4093,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 +4103,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 +4117,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 +4127,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 +4181,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 +4198,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 +4281,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.  */
@@ -4475,6 +4492,10 @@ 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;
 }
 
 /* On the mips16, we want to allocate $24 (T_REG) before other
@@ -4527,6 +4548,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;
     }
 
@@ -4980,7 +5005,7 @@ print_operand_address (file, addr)
 
 int
 mips_output_external (file, decl, name)
-     FILE *file;
+     FILE *file ATTRIBUTE_UNUSED;
      tree decl;
      char *name;
 {
@@ -5054,7 +5079,7 @@ static FILE *
 make_temp_file ()
 {
   FILE *stream;
-  char *base = getenv ("TMPDIR");
+  const char *base = getenv ("TMPDIR");
   int len;
 
   if (base == 0)
@@ -5192,8 +5217,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 +5286,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
@@ -5335,7 +5360,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)
@@ -5521,7 +5546,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 +5573,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 +5594,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 +5610,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 +5638,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 +5717,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.  */
@@ -5768,13 +5800,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 +5832,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 +5842,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 +5904,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 +5921,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 +5939,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;
@@ -5981,16 +6019,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 +6058,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,7 +6079,7 @@ 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;
@@ -6074,22 +6122,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,7 +6264,7 @@ 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];
 
@@ -6335,7 +6392,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 +6414,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 +6462,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 +6478,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 +6505,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;
@@ -6494,7 +6552,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 +6583,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,7 +6626,7 @@ 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)));
     }
@@ -6588,8 +6646,8 @@ 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;
 
@@ -6620,7 +6678,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',
@@ -6752,7 +6810,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 ());
@@ -6822,7 +6880,7 @@ mips_can_use_return_insn ()
 void
 mips_select_rtx_section (mode, x)
      enum machine_mode mode;
-     rtx x;
+     rtx x ATTRIBUTE_UNUSED;
 {
   if (TARGET_MIPS16)
     {
@@ -6851,7 +6909,16 @@ mips_select_rtx_section (mode, x)
 }
 
 /* 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 +6989,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 +7012,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.  */
@@ -7017,10 +7086,10 @@ mips_function_value (valtype, func)
 
 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;
 
@@ -7086,14 +7155,14 @@ mips_secondary_reload_class (class, mode, x, in_p)
      to a general register, or when copying from register 0.  */
   if (class == HILO_REG && regno != GP_REG_FIRST + 0)
     return ((! in_p
-            && GP_REG_P (regno)
+            && gp_reg_p
             && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
-           ? NO_REGS : GR_REGS);
+           ? NO_REGS : gr_regs);
   else if (regno == HILO_REGNUM)
     return ((in_p
-            && class == GR_REGS
+            && class == gr_regs
             && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
-           ? NO_REGS : GR_REGS);
+           ? NO_REGS : gr_regs);
 
   /* Copying from HI or LO to anywhere other than a general register
      requires a general register.  */
@@ -7104,7 +7173,7 @@ mips_secondary_reload_class (class, mode, x, in_p)
          /* We can't really copy to HI or LO at all in mips16 mode.  */
          return M16_REGS;
        }
-      return gp_reg_p ? NO_REGS : GR_REGS;
+      return gp_reg_p ? NO_REGS : gr_regs;
     }
   if (MD_REG_P (regno))
     {
@@ -7113,7 +7182,7 @@ mips_secondary_reload_class (class, mode, x, in_p)
          /* We can't really copy to HI or LO at all in mips16 mode.  */
          return M16_REGS;
        }
-      return class == gr_regs ? NO_REGS : GR_REGS;
+      return class == gr_regs ? NO_REGS : gr_regs;
     }
 
   /* We can only copy a value to a condition code register from a
@@ -7403,12 +7472,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 +7504,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;
            }
@@ -7605,9 +7679,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 +7852,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.  */
@@ -8413,7 +8499,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 +8512,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