OSDN Git Service

* config/mips/mips.c (mips_offset_within_alignment_p): New.
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index d8b39c3..ff83eb7 100644 (file)
@@ -3,7 +3,7 @@
    1999, 2000, 2001, 2002, 2003, 2004, 2005 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
+   64-bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
    Brendan Eich, brendan@microunity.com.
 
 This file is part of GCC.
@@ -20,8 +20,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -56,6 +56,7 @@ Boston, MA 02111-1307, USA.  */
 #include "cfglayout.h"
 #include "sched-int.h"
 #include "tree-gimple.h"
+#include "bitmap.h"
 
 /* True if X is an unspec wrapper around a SYMBOL_REF or LABEL_REF.  */
 #define UNSPEC_ADDRESS_P(X)                                    \
@@ -150,6 +151,43 @@ enum mips_function_type
   MIPS_DF_FTYPE_DF,
   MIPS_DF_FTYPE_DF_DF,
 
+  /* For MIPS DSP ASE  */
+  MIPS_DI_FTYPE_DI_SI,
+  MIPS_DI_FTYPE_DI_SI_SI,
+  MIPS_DI_FTYPE_DI_V2HI_V2HI,
+  MIPS_DI_FTYPE_DI_V4QI_V4QI,
+  MIPS_SI_FTYPE_DI_SI,
+  MIPS_SI_FTYPE_PTR_SI,
+  MIPS_SI_FTYPE_SI,
+  MIPS_SI_FTYPE_SI_SI,
+  MIPS_SI_FTYPE_V2HI,
+  MIPS_SI_FTYPE_V2HI_V2HI,
+  MIPS_SI_FTYPE_V4QI,
+  MIPS_SI_FTYPE_V4QI_V4QI,
+  MIPS_SI_FTYPE_VOID,
+  MIPS_V2HI_FTYPE_SI,
+  MIPS_V2HI_FTYPE_SI_SI,
+  MIPS_V2HI_FTYPE_V2HI,
+  MIPS_V2HI_FTYPE_V2HI_SI,
+  MIPS_V2HI_FTYPE_V2HI_V2HI,
+  MIPS_V2HI_FTYPE_V4QI,
+  MIPS_V2HI_FTYPE_V4QI_V2HI,
+  MIPS_V4QI_FTYPE_SI,
+  MIPS_V4QI_FTYPE_V2HI_V2HI,
+  MIPS_V4QI_FTYPE_V4QI_SI,
+  MIPS_V4QI_FTYPE_V4QI_V4QI,
+  MIPS_VOID_FTYPE_SI_SI,
+  MIPS_VOID_FTYPE_V2HI_V2HI,
+  MIPS_VOID_FTYPE_V4QI_V4QI,
+
+  /* For MIPS DSP REV 2 ASE.  */
+  MIPS_V4QI_FTYPE_V4QI,
+  MIPS_SI_FTYPE_SI_SI_SI,
+  MIPS_DI_FTYPE_DI_USI_USI,
+  MIPS_DI_FTYPE_SI_SI,
+  MIPS_DI_FTYPE_USI_USI,
+  MIPS_V2HI_FTYPE_SI_SI_SI,
+
   /* The last type.  */
   MIPS_MAX_FTYPE_MAX
 };
@@ -162,6 +200,10 @@ enum mips_builtin_type
      operands 1 and above.  */
   MIPS_BUILTIN_DIRECT,
 
+  /* The builtin corresponds directly to an .md pattern.  There is no return
+     value and the arguments are mapped to operands 0 and above.  */
+  MIPS_BUILTIN_DIRECT_NO_TARGET,
+
   /* The builtin corresponds to a comparison instruction followed by
      a mips_cond_move_tf_ps pattern.  The first two arguments are the
      values to compare and the second two arguments are the vector
@@ -185,7 +227,10 @@ enum mips_builtin_type
   MIPS_BUILTIN_CMP_LOWER,
 
   /* As above, but the instruction only sets a single $fcc register.  */
-  MIPS_BUILTIN_CMP_SINGLE
+  MIPS_BUILTIN_CMP_SINGLE,
+
+  /* For generating bposge32 branch instructions in MIPS32 DSP ASE.  */
+  MIPS_BUILTIN_BPOSGE32
 };
 
 /* Invokes MACRO (COND) for each c.cond.fmt condition.  */
@@ -230,17 +275,15 @@ struct mips_integer_op;
 struct mips_sim;
 
 static enum mips_symbol_type mips_classify_symbol (rtx);
-static void mips_split_const (rtx, rtx *, HOST_WIDE_INT *);
-static bool mips_offset_within_object_p (rtx, HOST_WIDE_INT);
 static bool mips_valid_base_register_p (rtx, enum machine_mode, int);
 static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode);
 static bool mips_classify_address (struct mips_address_info *, rtx,
                                   enum machine_mode, int);
 static bool mips_cannot_force_const_mem (rtx);
+static bool mips_use_blocks_for_constant_p (enum machine_mode, rtx);
 static int mips_symbol_insns (enum mips_symbol_type);
 static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
 static rtx mips_force_temporary (rtx, rtx);
-static rtx mips_split_symbol (rtx, rtx);
 static rtx mips_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
 static rtx mips_add_offset (rtx, rtx, HOST_WIDE_INT);
 static unsigned int mips_build_shift (struct mips_integer_op *, HOST_WIDE_INT);
@@ -248,7 +291,6 @@ static unsigned int mips_build_lower (struct mips_integer_op *,
                                      unsigned HOST_WIDE_INT);
 static unsigned int mips_build_integer (struct mips_integer_op *,
                                        unsigned HOST_WIDE_INT);
-static void mips_move_integer (rtx, unsigned HOST_WIDE_INT);
 static void mips_legitimize_const_move (enum machine_mode, rtx, rtx);
 static int m16_check_op (rtx, int, int, int);
 static bool mips_rtx_costs (rtx, int, int, int *);
@@ -267,11 +309,7 @@ static void mips_set_tune (const struct mips_cpu_info *);
 static bool mips_handle_option (size_t, const char *, int);
 static struct machine_function *mips_init_machine_status (void);
 static void print_operand_reloc (FILE *, rtx, const char **);
-#if TARGET_IRIX
-static void irix_output_external_libcall (rtx);
-#endif
 static void mips_file_start (void);
-static void mips_file_end (void);
 static bool mips_rewrite_small_data_p (rtx);
 static int mips_small_data_pattern_1 (rtx *, void *);
 static int mips_rewrite_small_data_1 (rtx *, void *);
@@ -292,10 +330,11 @@ static void mips_restore_reg (rtx, rtx);
 static void mips_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                  HOST_WIDE_INT, tree);
 static int symbolic_expression_p (rtx);
-static void mips_select_rtx_section (enum machine_mode, rtx,
-                                    unsigned HOST_WIDE_INT);
-static void mips_function_rodata_section (tree);
+static section *mips_select_rtx_section (enum machine_mode, rtx,
+                                        unsigned HOST_WIDE_INT);
+static section *mips_function_rodata_section (tree);
 static bool mips_in_small_data_p (tree);
+static bool mips_use_anchors_for_symbol_p (rtx);
 static int mips_fpr_return_fields (tree, tree *);
 static bool mips_return_in_msb (tree);
 static rtx mips_return_fpr_pair (enum machine_mode mode,
@@ -358,17 +397,22 @@ static int mips_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode mode,
                                   tree, bool);
 static bool mips_valid_pointer_mode (enum machine_mode);
 static bool mips_vector_mode_supported_p (enum machine_mode);
-static rtx mips_prepare_builtin_arg (enum insn_code, unsigned int, tree *);
+static rtx mips_prepare_builtin_arg (enum insn_code, unsigned int, tree, unsigned int);
 static rtx mips_prepare_builtin_target (enum insn_code, unsigned int, rtx);
 static rtx mips_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void mips_init_builtins (void);
-static rtx mips_expand_builtin_direct (enum insn_code, rtx, tree);
+static rtx mips_expand_builtin_direct (enum insn_code, rtx, tree, bool);
 static rtx mips_expand_builtin_movtf (enum mips_builtin_type,
                                      enum insn_code, enum mips_fp_condition,
                                      rtx, tree);
 static rtx mips_expand_builtin_compare (enum mips_builtin_type,
                                        enum insn_code, enum mips_fp_condition,
                                        rtx, tree);
+static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx);
+static void mips_encode_section_info (tree, rtx, int);
+static void mips_extra_live_on_entry (bitmap);
+static int mips_mode_rep_extended (enum machine_mode, enum machine_mode);
+static bool mips_offset_within_alignment_p (rtx, HOST_WIDE_INT);
 
 /* Structure to be filled in by compute_frame_size with register
    save masks, and offsets for the current function.  */
@@ -397,6 +441,10 @@ struct machine_function GTY(()) {
      refers to GP relative global variables.  */
   rtx mips16_gp_pseudo_rtx;
 
+  /* The number of extra stack bytes taken up by register varargs.
+     This area is allocated by the callee at the very top of the frame.  */
+  int varargs_size;
+
   /* Current frame information, calculated by compute_frame_size.  */
   struct mips_frame_info frame;
 
@@ -507,19 +555,6 @@ int sdb_label_count = 0;
 /* Next label # for each statement for Silicon Graphics IRIS systems.  */
 int sym_lineno = 0;
 
-/* Linked list of all externals that are to be emitted when optimizing
-   for the global pointer if they haven't been declared by the end of
-   the program with an appropriate .comm or initialization.  */
-
-struct extern_list GTY (())
-{
-  struct extern_list *next;    /* next external */
-  const char *name;            /* name of the external */
-  int size;                    /* size in bytes */
-};
-
-static GTY (()) struct extern_list *extern_head = 0;
-
 /* Name of the file containing the current function.  */
 const char *current_function_file = "";
 
@@ -549,21 +584,18 @@ int mips_isa;
 /* Which ABI to use.  */
 int mips_abi = MIPS_ABI_DEFAULT;
 
+/* Cost information to use.  */
+const struct mips_rtx_cost_data *mips_cost;
+
 /* Whether we are generating mips16 hard float code.  In mips16 mode
    we always set TARGET_SOFT_FLOAT; this variable is nonzero if
    -msoft-float was not specified by the user, which means that we
    should arrange to call mips32 hard floating point code.  */
 int mips16_hard_float;
 
-/* The arguments passed to -march and -mtune.  */
-static const char *mips_arch_string;
-static const char *mips_tune_string;
-
 /* The architecture selected by -mipsN.  */
 static const struct mips_cpu_info *mips_isa_info;
 
-const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
-
 /* If TRUE, we split addresses into their high and low parts in the RTL.  */
 int mips_split_addresses;
 
@@ -587,7 +619,7 @@ static GTY (()) int mips_output_filename_first_time = 1;
 
 /* mips_split_p[X] is true if symbols of type X can be split by
    mips_split_symbol().  */
-static bool mips_split_p[NUM_SYMBOL_TYPES];
+bool mips_split_p[NUM_SYMBOL_TYPES];
 
 /* mips_lo_relocs[X] is the relocation to use when a symbol of type X
    appears in a LO_SUM.  It can be null if such LO_SUMs aren't valid or
@@ -643,11 +675,18 @@ const enum reg_class mips_regno_to_class[] =
   COP3_REGS,   COP3_REGS,      COP3_REGS,      COP3_REGS,
   COP3_REGS,   COP3_REGS,      COP3_REGS,      COP3_REGS,
   COP3_REGS,   COP3_REGS,      COP3_REGS,      COP3_REGS,
-  COP3_REGS,   COP3_REGS,      COP3_REGS,      COP3_REGS
+  COP3_REGS,   COP3_REGS,      COP3_REGS,      COP3_REGS,
+  DSP_ACC_REGS,        DSP_ACC_REGS,   DSP_ACC_REGS,   DSP_ACC_REGS,
+  DSP_ACC_REGS,        DSP_ACC_REGS,   ALL_REGS,       ALL_REGS,
+  ALL_REGS,    ALL_REGS,       ALL_REGS,       ALL_REGS
 };
 
-/* Map register constraint character to register class.  */
-enum reg_class mips_char_to_class[256];
+/* Table of machine dependent attributes.  */
+const struct attribute_spec mips_attribute_table[] =
+{
+  { "long_call",   0, 0, false, true,  true,  NULL },
+  { NULL,         0, 0, false, false, false, NULL }
+};
 \f
 /* A table describing all the processors gcc knows about.  Names are
    matched in the order listed.  The first mention of an ISA level is
@@ -695,20 +734,381 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 
   /* MIPS32 */
   { "4kc", PROCESSOR_4KC, 32 },
-  { "4kp", PROCESSOR_4KC, 32 }, /* = 4kc */
+  { "4km", PROCESSOR_4KC, 32 }, /* = 4kc */
+  { "4kp", PROCESSOR_4KP, 32 },
 
   /* MIPS32 Release 2 */
   { "m4k", PROCESSOR_M4K, 33 },
+  { "4kec", PROCESSOR_4KC, 33 },
+  { "4kem", PROCESSOR_4KC, 33 },
+  { "4kep", PROCESSOR_4KP, 33 },
+  { "24kc", PROCESSOR_24KC, 33 },  /* 24K  no FPU */
+  { "24kf", PROCESSOR_24KF, 33 },  /* 24K 1:2 FPU */
+  { "24kx", PROCESSOR_24KX, 33 },  /* 24K 1:1 FPU */
+  { "24kec", PROCESSOR_24KC, 33 }, /* 24K with DSP */
+  { "24kef", PROCESSOR_24KF, 33 },
+  { "24kex", PROCESSOR_24KX, 33 },
+  { "34kc", PROCESSOR_24KC, 33 },  /* 34K with MT/DSP */
+  { "34kf", PROCESSOR_24KF, 33 },
+  { "34kx", PROCESSOR_24KX, 33 },
+  { "74kc", PROCESSOR_74KC, 33 },
+  { "74kf", PROCESSOR_74KF, 33 },
+  { "74kx", PROCESSOR_74KX, 33 },
 
   /* MIPS64 */
   { "5kc", PROCESSOR_5KC, 64 },
+  { "5kf", PROCESSOR_5KF, 64 },
   { "20kc", PROCESSOR_20KC, 64 },
   { "sb1", PROCESSOR_SB1, 64 },
+  { "sb1a", PROCESSOR_SB1A, 64 },
   { "sr71000", PROCESSOR_SR71000, 64 },
 
   /* End marker */
   { 0, 0, 0 }
 };
+
+/* Default costs. If these are used for a processor we should look
+   up the actual costs.  */
+#define DEFAULT_COSTS COSTS_N_INSNS (6),  /* fp_add */       \
+                      COSTS_N_INSNS (7),  /* fp_mult_sf */   \
+                      COSTS_N_INSNS (8),  /* fp_mult_df */   \
+                      COSTS_N_INSNS (23), /* fp_div_sf */    \
+                      COSTS_N_INSNS (36), /* fp_div_df */    \
+                      COSTS_N_INSNS (10), /* int_mult_si */  \
+                      COSTS_N_INSNS (10), /* int_mult_di */  \
+                      COSTS_N_INSNS (69), /* int_div_si */   \
+                      COSTS_N_INSNS (69), /* int_div_di */   \
+                                       2, /* branch_cost */  \
+                                       4  /* memory_latency */
+
+/* Need to replace these with the costs of calling the appropriate
+   libgcc routine.  */
+#define SOFT_FP_COSTS COSTS_N_INSNS (256), /* fp_add */       \
+                      COSTS_N_INSNS (256), /* fp_mult_sf */   \
+                      COSTS_N_INSNS (256), /* fp_mult_df */   \
+                      COSTS_N_INSNS (256), /* fp_div_sf */    \
+                      COSTS_N_INSNS (256)  /* fp_div_df */
+
+static struct mips_rtx_cost_data const mips_rtx_cost_optimize_size =
+  {
+      COSTS_N_INSNS (1),            /* fp_add */
+      COSTS_N_INSNS (1),            /* fp_mult_sf */
+      COSTS_N_INSNS (1),            /* fp_mult_df */
+      COSTS_N_INSNS (1),            /* fp_div_sf */
+      COSTS_N_INSNS (1),            /* fp_div_df */
+      COSTS_N_INSNS (1),            /* int_mult_si */
+      COSTS_N_INSNS (1),            /* int_mult_di */
+      COSTS_N_INSNS (1),            /* int_div_si */
+      COSTS_N_INSNS (1),            /* int_div_di */
+                       2,           /* branch_cost */
+                       4            /* memory_latency */
+  };
+
+static struct mips_rtx_cost_data const mips_rtx_cost_data[PROCESSOR_MAX] =
+  {
+    { /* R3000 */
+      COSTS_N_INSNS (2),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (5),            /* fp_mult_df */
+      COSTS_N_INSNS (12),           /* fp_div_sf */
+      COSTS_N_INSNS (19),           /* fp_div_df */
+      COSTS_N_INSNS (12),           /* int_mult_si */
+      COSTS_N_INSNS (12),           /* int_mult_di */
+      COSTS_N_INSNS (35),           /* int_div_si */
+      COSTS_N_INSNS (35),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+
+    },
+    { /* 4KC */
+      SOFT_FP_COSTS,
+      COSTS_N_INSNS (6),            /* int_mult_si */
+      COSTS_N_INSNS (6),            /* int_mult_di */
+      COSTS_N_INSNS (36),           /* int_div_si */
+      COSTS_N_INSNS (36),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 4KP */
+      SOFT_FP_COSTS,
+      COSTS_N_INSNS (36),           /* int_mult_si */
+      COSTS_N_INSNS (36),           /* int_mult_di */
+      COSTS_N_INSNS (37),           /* int_div_si */
+      COSTS_N_INSNS (37),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 5KC */
+      SOFT_FP_COSTS,
+      COSTS_N_INSNS (4),            /* int_mult_si */
+      COSTS_N_INSNS (11),           /* int_mult_di */
+      COSTS_N_INSNS (36),           /* int_div_si */
+      COSTS_N_INSNS (68),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 5KF */
+      COSTS_N_INSNS (4),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (5),            /* fp_mult_df */
+      COSTS_N_INSNS (17),           /* fp_div_sf */
+      COSTS_N_INSNS (32),           /* fp_div_df */
+      COSTS_N_INSNS (4),            /* int_mult_si */
+      COSTS_N_INSNS (11),           /* int_mult_di */
+      COSTS_N_INSNS (36),           /* int_div_si */
+      COSTS_N_INSNS (68),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 20KC */
+      DEFAULT_COSTS
+    },
+    { /* 24KC */
+      SOFT_FP_COSTS,
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (41),           /* int_div_si */
+      COSTS_N_INSNS (41),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 24KF */
+      COSTS_N_INSNS (8),            /* fp_add */
+      COSTS_N_INSNS (8),            /* fp_mult_sf */
+      COSTS_N_INSNS (10),           /* fp_mult_df */
+      COSTS_N_INSNS (34),           /* fp_div_sf */
+      COSTS_N_INSNS (64),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (41),           /* int_div_si */
+      COSTS_N_INSNS (41),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 24KX */
+      COSTS_N_INSNS (4),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (5),            /* fp_mult_df */
+      COSTS_N_INSNS (17),           /* fp_div_sf */
+      COSTS_N_INSNS (32),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (41),           /* int_div_si */
+      COSTS_N_INSNS (41),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 74KC */
+      SOFT_FP_COSTS,
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (41),           /* int_div_si */
+      COSTS_N_INSNS (41),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 74KF */
+      COSTS_N_INSNS (8),            /* fp_add */
+      COSTS_N_INSNS (8),            /* fp_mult_sf */
+      COSTS_N_INSNS (10),           /* fp_mult_df */
+      COSTS_N_INSNS (34),           /* fp_div_sf */
+      COSTS_N_INSNS (64),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (41),           /* int_div_si */
+      COSTS_N_INSNS (41),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* 74KX */
+      COSTS_N_INSNS (4),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (5),            /* fp_mult_df */
+      COSTS_N_INSNS (17),           /* fp_div_sf */
+      COSTS_N_INSNS (32),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (41),           /* int_div_si */
+      COSTS_N_INSNS (41),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* M4k */
+      DEFAULT_COSTS
+    },
+    { /* R3900 */
+      COSTS_N_INSNS (2),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (5),            /* fp_mult_df */
+      COSTS_N_INSNS (12),           /* fp_div_sf */
+      COSTS_N_INSNS (19),           /* fp_div_df */
+      COSTS_N_INSNS (2),            /* int_mult_si */
+      COSTS_N_INSNS (2),            /* int_mult_di */
+      COSTS_N_INSNS (35),           /* int_div_si */
+      COSTS_N_INSNS (35),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* R6000 */
+      COSTS_N_INSNS (3),            /* fp_add */
+      COSTS_N_INSNS (5),            /* fp_mult_sf */
+      COSTS_N_INSNS (6),            /* fp_mult_df */
+      COSTS_N_INSNS (15),           /* fp_div_sf */
+      COSTS_N_INSNS (16),           /* fp_div_df */
+      COSTS_N_INSNS (17),           /* int_mult_si */
+      COSTS_N_INSNS (17),           /* int_mult_di */
+      COSTS_N_INSNS (38),           /* int_div_si */
+      COSTS_N_INSNS (38),           /* int_div_di */
+                       2,           /* branch_cost */
+                       6            /* memory_latency */
+    },
+    { /* R4000 */
+       COSTS_N_INSNS (6),           /* fp_add */
+       COSTS_N_INSNS (7),           /* fp_mult_sf */
+       COSTS_N_INSNS (8),           /* fp_mult_df */
+       COSTS_N_INSNS (23),          /* fp_div_sf */
+       COSTS_N_INSNS (36),          /* fp_div_df */
+       COSTS_N_INSNS (10),          /* int_mult_si */
+       COSTS_N_INSNS (10),          /* int_mult_di */
+       COSTS_N_INSNS (69),          /* int_div_si */
+       COSTS_N_INSNS (69),          /* int_div_di */
+                        2,          /* branch_cost */
+                        6           /* memory_latency */
+    },
+    { /* R4100 */
+      DEFAULT_COSTS
+    },
+    { /* R4111 */
+      DEFAULT_COSTS
+    },
+    { /* R4120 */
+      DEFAULT_COSTS
+    },
+    { /* R4130 */
+      /* The only costs that appear to be updated here are
+        integer multiplication.  */
+      SOFT_FP_COSTS,
+      COSTS_N_INSNS (4),            /* int_mult_si */
+      COSTS_N_INSNS (6),            /* int_mult_di */
+      COSTS_N_INSNS (69),           /* int_div_si */
+      COSTS_N_INSNS (69),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* R4300 */
+      DEFAULT_COSTS
+    },
+    { /* R4600 */
+      DEFAULT_COSTS
+    },
+    { /* R4650 */
+      DEFAULT_COSTS
+    },
+    { /* R5000 */
+      COSTS_N_INSNS (6),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (5),            /* fp_mult_df */
+      COSTS_N_INSNS (23),           /* fp_div_sf */
+      COSTS_N_INSNS (36),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (5),            /* int_mult_di */
+      COSTS_N_INSNS (36),           /* int_div_si */
+      COSTS_N_INSNS (36),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* R5400 */
+      COSTS_N_INSNS (6),            /* fp_add */
+      COSTS_N_INSNS (5),            /* fp_mult_sf */
+      COSTS_N_INSNS (6),            /* fp_mult_df */
+      COSTS_N_INSNS (30),           /* fp_div_sf */
+      COSTS_N_INSNS (59),           /* fp_div_df */
+      COSTS_N_INSNS (3),            /* int_mult_si */
+      COSTS_N_INSNS (4),            /* int_mult_di */
+      COSTS_N_INSNS (42),           /* int_div_si */
+      COSTS_N_INSNS (74),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* R5500 */
+      COSTS_N_INSNS (6),            /* fp_add */
+      COSTS_N_INSNS (5),            /* fp_mult_sf */
+      COSTS_N_INSNS (6),            /* fp_mult_df */
+      COSTS_N_INSNS (30),           /* fp_div_sf */
+      COSTS_N_INSNS (59),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (9),            /* int_mult_di */
+      COSTS_N_INSNS (42),           /* int_div_si */
+      COSTS_N_INSNS (74),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* R7000 */
+      /* The only costs that are changed here are
+        integer multiplication.  */
+      COSTS_N_INSNS (6),            /* fp_add */
+      COSTS_N_INSNS (7),            /* fp_mult_sf */
+      COSTS_N_INSNS (8),            /* fp_mult_df */
+      COSTS_N_INSNS (23),           /* fp_div_sf */
+      COSTS_N_INSNS (36),           /* fp_div_df */
+      COSTS_N_INSNS (5),            /* int_mult_si */
+      COSTS_N_INSNS (9),            /* int_mult_di */
+      COSTS_N_INSNS (69),           /* int_div_si */
+      COSTS_N_INSNS (69),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* R8000 */
+      DEFAULT_COSTS
+    },
+    { /* R9000 */
+      /* The only costs that are changed here are
+        integer multiplication.  */
+      COSTS_N_INSNS (6),            /* fp_add */
+      COSTS_N_INSNS (7),            /* fp_mult_sf */
+      COSTS_N_INSNS (8),            /* fp_mult_df */
+      COSTS_N_INSNS (23),           /* fp_div_sf */
+      COSTS_N_INSNS (36),           /* fp_div_df */
+      COSTS_N_INSNS (3),            /* int_mult_si */
+      COSTS_N_INSNS (8),            /* int_mult_di */
+      COSTS_N_INSNS (69),           /* int_div_si */
+      COSTS_N_INSNS (69),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* SB1 */
+      /* These costs are the same as the SB-1A below.  */
+      COSTS_N_INSNS (4),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (4),            /* fp_mult_df */
+      COSTS_N_INSNS (24),           /* fp_div_sf */
+      COSTS_N_INSNS (32),           /* fp_div_df */
+      COSTS_N_INSNS (3),            /* int_mult_si */
+      COSTS_N_INSNS (4),            /* int_mult_di */
+      COSTS_N_INSNS (36),           /* int_div_si */
+      COSTS_N_INSNS (68),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* SB1-A */
+      /* These costs are the same as the SB-1 above.  */
+      COSTS_N_INSNS (4),            /* fp_add */
+      COSTS_N_INSNS (4),            /* fp_mult_sf */
+      COSTS_N_INSNS (4),            /* fp_mult_df */
+      COSTS_N_INSNS (24),           /* fp_div_sf */
+      COSTS_N_INSNS (32),           /* fp_div_df */
+      COSTS_N_INSNS (3),            /* int_mult_si */
+      COSTS_N_INSNS (4),            /* int_mult_di */
+      COSTS_N_INSNS (36),           /* int_div_si */
+      COSTS_N_INSNS (68),           /* int_div_di */
+                       1,           /* branch_cost */
+                       4            /* memory_latency */
+    },
+    { /* SR71000 */
+      DEFAULT_COSTS
+    },
+  };
+
 \f
 /* Nonzero if -march should decide the default value of MASK_SOFT_FLOAT.  */
 #ifndef MIPS_MARCH_CONTROLS_SOFT_FLOAT
@@ -772,9 +1172,7 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #define TARGET_MACHINE_DEPENDENT_REORG mips_reorg
 
 #undef TARGET_ASM_FILE_START
-#undef TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_START mips_file_start
-#define TARGET_ASM_FILE_END mips_file_end
 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 
@@ -816,6 +1214,9 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #undef TARGET_ARG_PARTIAL_BYTES
 #define TARGET_ARG_PARTIAL_BYTES mips_arg_partial_bytes
 
+#undef TARGET_MODE_REP_EXTENDED
+#define TARGET_MODE_REP_EXTENDED mips_mode_rep_extended
+
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P mips_vector_mode_supported_p
 
@@ -830,19 +1231,68 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM mips_cannot_force_const_mem
 
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO mips_encode_section_info
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE mips_attribute_table
+
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry
+
+#undef TARGET_MIN_ANCHOR_OFFSET
+#define TARGET_MIN_ANCHOR_OFFSET -32768
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET 32767
+#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
+#define TARGET_USE_BLOCKS_FOR_CONSTANT_P mips_use_blocks_for_constant_p
+#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
+#define TARGET_USE_ANCHORS_FOR_SYMBOL_P mips_use_anchors_for_symbol_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
+/* Return true if SYMBOL_REF X is associated with a global symbol
+   (in the STB_GLOBAL sense).  */
+
+static bool
+mips_global_symbol_p (rtx x)
+{
+  tree decl;
+
+  decl = SYMBOL_REF_DECL (x);
+  if (!decl)
+    return !SYMBOL_REF_LOCAL_P (x);
+
+  /* Weakref symbols are not TREE_PUBLIC, but their targets are global
+     or weak symbols.  Relocations in the object file will be against
+     the target symbol, so it's that symbol's binding that matters here.  */
+  return DECL_P (decl) && (TREE_PUBLIC (decl) || DECL_WEAK (decl));
+}
+
+/* Return true if SYMBOL_REF X binds locally.  */
+
+static bool
+mips_symbol_binds_local_p (rtx x)
+{
+  return (SYMBOL_REF_DECL (x)
+         ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
+         : SYMBOL_REF_LOCAL_P (x));
+}
+
 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
 
 static enum mips_symbol_type
 mips_classify_symbol (rtx x)
 {
+  if (TARGET_RTP_PIC)
+    return SYMBOL_GOT_DISP;
+
   if (GET_CODE (x) == LABEL_REF)
     {
       if (TARGET_MIPS16)
        return SYMBOL_CONSTANT_POOL;
-      if (TARGET_ABICALLS)
-       return SYMBOL_GOT_LOCAL;
+      if (TARGET_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
+       return SYMBOL_GOT_PAGE_OFST;
       return SYMBOL_GENERAL;
     }
 
@@ -856,96 +1306,73 @@ mips_classify_symbol (rtx x)
       if (TARGET_MIPS16)
        return SYMBOL_CONSTANT_POOL;
 
-      if (TARGET_ABICALLS)
-       return SYMBOL_GOT_LOCAL;
-
       if (GET_MODE_SIZE (get_pool_mode (x)) <= mips_section_threshold)
        return SYMBOL_SMALL_DATA;
-
-      return SYMBOL_GENERAL;
     }
 
-  if (SYMBOL_REF_SMALL_P (x))
+  /* Do not use small-data accesses for weak symbols; they may end up
+     being zero.  */
+  if (SYMBOL_REF_SMALL_P (x)
+      && !SYMBOL_REF_WEAK (x))
     return SYMBOL_SMALL_DATA;
 
   if (TARGET_ABICALLS)
     {
-      if (SYMBOL_REF_DECL (x) == 0)
-       return SYMBOL_REF_LOCAL_P (x) ? SYMBOL_GOT_LOCAL : SYMBOL_GOT_GLOBAL;
+      /* Don't use GOT accesses for locally-binding symbols; we can use
+        %hi and %lo instead.  */
+      if (TARGET_ABSOLUTE_ABICALLS && mips_symbol_binds_local_p (x))
+       return SYMBOL_GENERAL;
 
       /* There are three cases to consider:
 
-            - o32 PIC (either with or without explicit relocs)
-            - n32/n64 PIC without explicit relocs
-            - n32/n64 PIC with explicit relocs
+           - o32 PIC (either with or without explicit relocs)
+           - n32/n64 PIC without explicit relocs
+           - n32/n64 PIC with explicit relocs
 
-         In the first case, both local and global accesses will use an
-         R_MIPS_GOT16 relocation.  We must correctly predict which of
-         the two semantics (local or global) the assembler and linker
-         will apply.  The choice doesn't depend on the symbol's
-         visibility, so we deliberately ignore decl_visibility and
-         binds_local_p here.
+        In the first case, both local and global accesses will use an
+        R_MIPS_GOT16 relocation.  We must correctly predict which of
+        the two semantics (local or global) the assembler and linker
+        will apply.  The choice depends on the symbol's binding rather
+        than its visibility.
 
-         In the second case, the assembler will not use R_MIPS_GOT16
-         relocations, but it chooses between local and global accesses
-         in the same way as for o32 PIC.
+        In the second case, the assembler will not use R_MIPS_GOT16
+        relocations, but it chooses between local and global accesses
+        in the same way as for o32 PIC.
 
-         In the third case we have more freedom since both forms of
-         access will work for any kind of symbol.  However, there seems
-         little point in doing things differently.  */
-      if (DECL_P (SYMBOL_REF_DECL (x)) && TREE_PUBLIC (SYMBOL_REF_DECL (x)))
-       return SYMBOL_GOT_GLOBAL;
+        In the third case we have more freedom since both forms of
+        access will work for any kind of symbol.  However, there seems
+        little point in doing things differently.  */
+      if (mips_global_symbol_p (x))
+       return SYMBOL_GOT_DISP;
 
-      return SYMBOL_GOT_LOCAL;
+      return SYMBOL_GOT_PAGE_OFST;
     }
 
   return SYMBOL_GENERAL;
 }
 
-
-/* Split X into a base and a constant offset, storing them in *BASE
-   and *OFFSET respectively.  */
-
-static void
-mips_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
-{
-  *offset = 0;
-
-  if (GET_CODE (x) == CONST)
-    x = XEXP (x, 0);
-
-  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
-    {
-      *offset += INTVAL (XEXP (x, 1));
-      x = XEXP (x, 0);
-    }
-  *base = x;
-}
-
-
-/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
-   to the same object as SYMBOL.  */
+/* Returns true if OFFSET is within the range [0, ALIGN), where ALIGN
+   is the alignment (in bytes) of SYMBOL_REF X.  */
 
 static bool
-mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
+mips_offset_within_alignment_p (rtx x, HOST_WIDE_INT offset)
 {
-  if (GET_CODE (symbol) != SYMBOL_REF)
-    return false;
+  /* If for some reason we can't get the alignment for the
+     symbol, initializing this to one means we won't accept any
+     offset.  */
+  HOST_WIDE_INT align = 1;
+  tree t;
 
-  if (CONSTANT_POOL_ADDRESS_P (symbol)
-      && offset >= 0
-      && offset < (int) GET_MODE_SIZE (get_pool_mode (symbol)))
-    return true;
+  /* Get the alignment of the symbol we're referring to.  */
+  t = SYMBOL_REF_DECL (x);
+  if (t)
+    align = DECL_ALIGN_UNIT (t);
 
-  if (SYMBOL_REF_DECL (symbol) != 0
-      && offset >= 0
-      && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
+  if (offset >= 0 && offset < align)
     return true;
-
   return false;
 }
 
-
 /* Return true if X is a symbolic constant that can be calculated in
    the same way as a bare symbol.  If it is, store the type of the
    symbol in *SYMBOL_TYPE.  */
@@ -953,11 +1380,14 @@ mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
 bool
 mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
 {
-  HOST_WIDE_INT offset;
+  rtx offset;
 
-  mips_split_const (x, &x, &offset);
+  split_const (x, &x, &offset);
   if (UNSPEC_ADDRESS_P (x))
-    *symbol_type = UNSPEC_ADDRESS_TYPE (x);
+    {
+      *symbol_type = UNSPEC_ADDRESS_TYPE (x);
+      x = UNSPEC_ADDRESS (x);
+    }
   else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
     {
       *symbol_type = mips_classify_symbol (x);
@@ -967,7 +1397,7 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
   else
     return false;
 
-  if (offset == 0)
+  if (offset == const0_rtx)
     return true;
 
   /* Check whether a nonzero offset is valid for the underlying
@@ -983,7 +1413,7 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
         sign-extended.  In this case we can't allow an arbitrary offset
         in case the 32-bit value X + OFFSET has a different sign from X.  */
       if (Pmode == DImode && !ABI_HAS_64BIT_SYMBOLS)
-       return mips_offset_within_object_p (x, offset);
+       return offset_within_block_p (x, INTVAL (offset));
 
       /* In other cases the relocations can handle any offset.  */
       return true;
@@ -999,49 +1429,46 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
 
     case SYMBOL_SMALL_DATA:
       /* Make sure that the offset refers to something within the
-        underlying object.  This should guarantee that the final
+        same object block.  This should guarantee that the final
         PC- or GP-relative offset is within the 16-bit limit.  */
-      return mips_offset_within_object_p (x, offset);
+      return offset_within_block_p (x, INTVAL (offset));
 
-    case SYMBOL_GOT_LOCAL:
+    case SYMBOL_GOT_PAGE_OFST:
     case SYMBOL_GOTOFF_PAGE:
-      /* The linker should provide enough local GOT entries for a
-        16-bit offset.  Larger offsets may lead to GOT overflow.  */
-      return SMALL_OPERAND (offset);
+      /* If the symbol is global, the GOT entry will contain the symbol's
+        address, and we will apply a 16-bit offset after loading it.
+        If the symbol is local, the linker should provide enough local
+        GOT entries for a 16-bit offset, but larger offsets may lead
+        to GOT overflow.  */
+      return SMALL_INT (offset);
 
-    case SYMBOL_GOT_GLOBAL:
-    case SYMBOL_GOTOFF_GLOBAL:
+    case SYMBOL_TPREL:
+    case SYMBOL_DTPREL:
+      /* There is no carry between the HI and LO REL relocations, so the
+        offset is only valid if we know it won't lead to such a carry.  */
+      return mips_offset_within_alignment_p (x, INTVAL (offset));
+
+    case SYMBOL_GOT_DISP:
+    case SYMBOL_GOTOFF_DISP:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
     case SYMBOL_TLSGD:
     case SYMBOL_TLSLDM:
-    case SYMBOL_DTPREL:
-    case SYMBOL_TPREL:
     case SYMBOL_GOTTPREL:
     case SYMBOL_TLS:
+    case SYMBOL_HALF:
       return false;
     }
   gcc_unreachable ();
 }
 
 
-/* Return true if X is a symbolic constant whose value is not split
-   into separate relocations.  */
-
-bool
-mips_atomic_symbolic_constant_p (rtx x)
-{
-  enum mips_symbol_type type;
-  return mips_symbolic_constant_p (x, &type) && !mips_split_p[type];
-}
-
-
 /* This function is used to implement REG_MODE_OK_FOR_BASE_P.  */
 
 int
 mips_regno_mode_ok_for_base_p (int regno, enum machine_mode mode, int strict)
 {
-  if (regno >= FIRST_PSEUDO_REGISTER)
+  if (!HARD_REGISTER_NUM_P (regno))
     {
       if (!strict)
        return true;
@@ -1109,28 +1536,27 @@ mips_symbolic_address_p (enum mips_symbol_type symbol_type,
       /* PC-relative addressing is only available for lw and ld.  */
       return GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8;
 
-    case SYMBOL_GOT_LOCAL:
+    case SYMBOL_GOT_PAGE_OFST:
       return true;
 
-    case SYMBOL_GOT_GLOBAL:
+    case SYMBOL_GOT_DISP:
       /* The address will have to be loaded from the GOT first.  */
       return false;
 
+    case SYMBOL_GOTOFF_PAGE:
+    case SYMBOL_GOTOFF_DISP:
+    case SYMBOL_GOTOFF_CALL:
+    case SYMBOL_GOTOFF_LOADGP:
+    case SYMBOL_TLS:
     case SYMBOL_TLSGD:
     case SYMBOL_TLSLDM:
     case SYMBOL_DTPREL:
-    case SYMBOL_TPREL:
     case SYMBOL_GOTTPREL:
-    case SYMBOL_TLS:
-      return false;
-
-    case SYMBOL_GOTOFF_PAGE:
-    case SYMBOL_GOTOFF_GLOBAL:
-    case SYMBOL_GOTOFF_CALL:
-    case SYMBOL_GOTOFF_LOADGP:
+    case SYMBOL_TPREL:
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
+    case SYMBOL_HALF:
       return true;
     }
   gcc_unreachable ();
@@ -1210,10 +1636,41 @@ mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
 static bool
 mips_cannot_force_const_mem (rtx x)
 {
-  if (! TARGET_HAVE_TLS)
-    return false;
+  rtx base, offset;
+
+  if (!TARGET_MIPS16)
+    {
+      /* As an optimization, reject constants that mips_legitimize_move
+        can expand inline.
 
-  return for_each_rtx (&x, &mips_tls_symbol_ref_1, 0);
+        Suppose we have a multi-instruction sequence that loads constant C
+        into register R.  If R does not get allocated a hard register, and
+        R is used in an operand that allows both registers and memory
+        references, reload will consider forcing C into memory and using
+        one of the instruction's memory alternatives.  Returning false
+        here will force it to use an input reload instead.  */
+      if (GET_CODE (x) == CONST_INT)
+       return true;
+
+      split_const (x, &base, &offset);
+      if (symbolic_operand (base, VOIDmode) && SMALL_INT (offset))
+       return true;
+    }
+
+  if (TARGET_HAVE_TLS && for_each_rtx (&x, &mips_tls_symbol_ref_1, 0))
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  MIPS16 uses per-function
+   constant pools, but normal-mode code doesn't need to.  */
+
+static bool
+mips_use_blocks_for_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                               rtx x ATTRIBUTE_UNUSED)
+{
+  return !TARGET_MIPS16;
 }
 \f
 /* Return the number of instructions needed to load a symbol of the
@@ -1246,6 +1703,7 @@ mips_symbol_insns (enum mips_symbol_type type)
       return (ABI_HAS_64BIT_SYMBOLS ? 6 : 2);
 
     case SYMBOL_SMALL_DATA:
+    case SYMBOL_HALF:
       return 1;
 
     case SYMBOL_CONSTANT_POOL:
@@ -1253,8 +1711,8 @@ mips_symbol_insns (enum mips_symbol_type type)
         extended instruction.  */
       return 2;
 
-    case SYMBOL_GOT_LOCAL:
-    case SYMBOL_GOT_GLOBAL:
+    case SYMBOL_GOT_PAGE_OFST:
+    case SYMBOL_GOT_DISP:
       /* Unless -funit-at-a-time is in effect, we can't be sure whether
         the local/global classification is accurate.  See override_options
         for details.
@@ -1278,7 +1736,7 @@ mips_symbol_insns (enum mips_symbol_type type)
       return 3;
 
     case SYMBOL_GOTOFF_PAGE:
-    case SYMBOL_GOTOFF_GLOBAL:
+    case SYMBOL_GOTOFF_DISP:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
     case SYMBOL_64_HIGH:
@@ -1383,7 +1841,7 @@ mips_const_insns (rtx x)
 {
   struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
   enum mips_symbol_type symbol_type;
-  HOST_WIDE_INT offset;
+  rtx offset;
 
   switch (GET_CODE (x))
     {
@@ -1424,16 +1882,16 @@ mips_const_insns (rtx x)
       /* Otherwise try splitting the constant into a base and offset.
         16-bit offsets can be added using an extra addiu.  Larger offsets
         must be calculated separately and then added to the base.  */
-      mips_split_const (x, &x, &offset);
+      split_const (x, &x, &offset);
       if (offset != 0)
        {
          int n = mips_const_insns (x);
          if (n != 0)
            {
-             if (SMALL_OPERAND (offset))
+             if (SMALL_INT (offset))
                return n + 1;
              else
-               return n + 1 + mips_build_integer (codes, offset);
+               return n + 1 + mips_build_integer (codes, INTVAL (offset));
            }
        }
       return 0;
@@ -1513,15 +1971,20 @@ mips_force_temporary (rtx dest, rtx value)
 /* Return a LO_SUM expression for ADDR.  TEMP is as for mips_force_temporary
    and is used to load the high part into a register.  */
 
-static rtx
+rtx
 mips_split_symbol (rtx temp, rtx addr)
 {
   rtx high;
 
-  if (TARGET_MIPS16)
-    high = mips16_gp_pseudo_reg ();
-  else
+  if (!TARGET_MIPS16)
     high = mips_force_temporary (temp, gen_rtx_HIGH (Pmode, copy_rtx (addr)));
+  else if (no_new_pseudos)
+    {
+      emit_insn (gen_load_const_gp (copy_rtx (temp)));
+      high = temp;
+    }
+  else
+    high = mips16_gp_pseudo_reg ();
   return gen_rtx_LO_SUM (Pmode, high, addr);
 }
 
@@ -1532,13 +1995,14 @@ mips_split_symbol (rtx temp, rtx addr)
 rtx
 mips_unspec_address (rtx address, enum mips_symbol_type symbol_type)
 {
-  rtx base;
-  HOST_WIDE_INT offset;
+  rtx base, offset;
 
-  mips_split_const (address, &base, &offset);
+  split_const (address, &base, &offset);
   base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base),
                         UNSPEC_ADDRESS_FIRST + symbol_type);
-  return plus_constant (gen_rtx_CONST (Pmode, base), offset);
+  if (offset != const0_rtx)
+    base = gen_rtx_PLUS (Pmode, base, offset);
+  return gen_rtx_CONST (Pmode, base);
 }
 
 
@@ -1640,6 +2104,11 @@ mips_legitimize_tls_address (rtx loc)
   v1 = gen_rtx_REG (Pmode, GP_RETURN + 1);
 
   model = SYMBOL_REF_TLS_MODEL (loc);
+  /* Only TARGET_ABICALLS code can have more than one module; other
+     code must be be static and should not use a GOT.  All TLS models
+     reduce to local exec in this situation.  */
+  if (!TARGET_ABICALLS)
+    model = TLS_MODEL_LOCAL_EXEC;
 
   switch (model)
     {
@@ -1682,7 +2151,6 @@ mips_legitimize_tls_address (rtx loc)
       break;
 
     case TLS_MODEL_LOCAL_EXEC:
-
       if (Pmode == DImode)
        emit_insn (gen_tls_get_tp_di (v1));
       else
@@ -1843,10 +2311,10 @@ mips_build_integer (struct mips_integer_op *codes,
 }
 
 
-/* Move VALUE into register DEST.  */
+/* Load VALUE into DEST, using TEMP as a temporary register if need be.  */
 
-static void
-mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
+void
+mips_move_integer (rtx dest, rtx temp, unsigned HOST_WIDE_INT value)
 {
   struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
   enum machine_mode mode;
@@ -1862,7 +2330,10 @@ mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
   for (i = 1; i < cost; i++)
     {
       if (no_new_pseudos)
-       emit_move_insn (dest, x), x = dest;
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, temp, x));
+         x = temp;
+       }
       else
        x = force_reg (mode, x);
       x = gen_rtx_fmt_ee (codes[i].code, mode, x, GEN_INT (codes[i].value));
@@ -1879,45 +2350,38 @@ mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
 static void
 mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
 {
-  rtx base;
-  HOST_WIDE_INT offset;
-  enum mips_symbol_type symbol_type;
+  rtx base, offset;
 
-  /* Split moves of big integers into smaller pieces.  In mips16 code,
-     it's better to force the constant into memory instead.  */
-  if (GET_CODE (src) == CONST_INT && !TARGET_MIPS16)
+  /* Split moves of big integers into smaller pieces.  */
+  if (splittable_const_int_operand (src, mode))
     {
-      mips_move_integer (dest, INTVAL (src));
+      mips_move_integer (dest, dest, INTVAL (src));
       return;
     }
 
-  if (mips_tls_operand_p (src))
+  /* Split moves of symbolic constants into high/low pairs.  */
+  if (splittable_symbolic_operand (src, mode))
     {
-      emit_move_insn (dest, mips_legitimize_tls_address (src));
+      emit_insn (gen_rtx_SET (VOIDmode, dest, mips_split_symbol (dest, src)));
       return;
     }
 
-  /* See if the symbol can be split.  For mips16, this is often worse than
-     forcing it in the constant pool since it needs the single-register form
-     of addiu or daddiu.  */
-  if (!TARGET_MIPS16
-      && mips_symbolic_constant_p (src, &symbol_type)
-      && mips_split_p[symbol_type])
+  if (mips_tls_operand_p (src))
     {
-      emit_move_insn (dest, mips_split_symbol (dest, src));
+      emit_move_insn (dest, mips_legitimize_tls_address (src));
       return;
     }
 
   /* If we have (const (plus symbol offset)), load the symbol first
      and then add in the offset.  This is usually better than forcing
      the constant into memory, at least in non-mips16 code.  */
-  mips_split_const (src, &base, &offset);
+  split_const (src, &base, &offset);
   if (!TARGET_MIPS16
-      && offset != 0
-      && (!no_new_pseudos || SMALL_OPERAND (offset)))
+      && offset != const0_rtx
+      && (!no_new_pseudos || SMALL_INT (offset)))
     {
       base = mips_force_temporary (dest, base);
-      emit_move_insn (dest, mips_add_offset (0, base, offset));
+      emit_move_insn (dest, mips_add_offset (0, base, INTVAL (offset)));
       return;
     }
 
@@ -2085,75 +2549,78 @@ static bool
 mips_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
   enum machine_mode mode = GET_MODE (x);
+  bool float_mode_p = FLOAT_MODE_P (mode);
 
   switch (code)
     {
     case CONST_INT:
-      if (!TARGET_MIPS16)
-        {
-          /* Always return 0, since we don't have different sized
-             instructions, hence different costs according to Richard
-             Kenner */
-          *total = 0;
-          return true;
-        }
-
-      /* A number between 1 and 8 inclusive is efficient for a shift.
-         Otherwise, we will need an extended instruction.  */
-      if ((outer_code) == ASHIFT || (outer_code) == ASHIFTRT
-          || (outer_code) == LSHIFTRT)
+      if (TARGET_MIPS16)
         {
-          if (INTVAL (x) >= 1 && INTVAL (x) <= 8)
-            *total = 0;
-          else
-            *total = COSTS_N_INSNS (1);
-          return true;
-        }
+         /* A number between 1 and 8 inclusive is efficient for a shift.
+            Otherwise, we will need an extended instruction.  */
+         if ((outer_code) == ASHIFT || (outer_code) == ASHIFTRT
+             || (outer_code) == LSHIFTRT)
+           {
+             if (INTVAL (x) >= 1 && INTVAL (x) <= 8)
+               *total = 0;
+             else
+               *total = COSTS_N_INSNS (1);
+             return true;
+           }
 
-      /* We can use cmpi for an xor with an unsigned 16 bit value.  */
-      if ((outer_code) == XOR
-          && INTVAL (x) >= 0 && INTVAL (x) < 0x10000)
-        {
-          *total = 0;
-          return true;
-        }
+         /* We can use cmpi for an xor with an unsigned 16-bit value.  */
+         if ((outer_code) == XOR
+             && INTVAL (x) >= 0 && INTVAL (x) < 0x10000)
+           {
+             *total = 0;
+             return true;
+           }
 
-      /* We may be able to use slt or sltu for a comparison with a
-         signed 16 bit value.  (The boundary conditions aren't quite
-         right, but this is just a heuristic anyhow.)  */
-      if (((outer_code) == LT || (outer_code) == LE
-           || (outer_code) == GE || (outer_code) == GT
-           || (outer_code) == LTU || (outer_code) == LEU
-           || (outer_code) == GEU || (outer_code) == GTU)
-          && INTVAL (x) >= -0x8000 && INTVAL (x) < 0x8000)
-        {
-          *total = 0;
-          return true;
-        }
+         /* We may be able to use slt or sltu for a comparison with a
+            signed 16-bit value.  (The boundary conditions aren't quite
+            right, but this is just a heuristic anyhow.)  */
+         if (((outer_code) == LT || (outer_code) == LE
+              || (outer_code) == GE || (outer_code) == GT
+              || (outer_code) == LTU || (outer_code) == LEU
+              || (outer_code) == GEU || (outer_code) == GTU)
+             && INTVAL (x) >= -0x8000 && INTVAL (x) < 0x8000)
+           {
+             *total = 0;
+             return true;
+           }
 
-      /* Equality comparisons with 0 are cheap.  */
-      if (((outer_code) == EQ || (outer_code) == NE)
-          && INTVAL (x) == 0)
-        {
-          *total = 0;
-          return true;
-        }
+         /* Equality comparisons with 0 are cheap.  */
+         if (((outer_code) == EQ || (outer_code) == NE)
+             && INTVAL (x) == 0)
+           {
+             *total = 0;
+             return true;
+           }
 
-      /* Constants in the range 0...255 can be loaded with an unextended
-        instruction.  They are therefore as cheap as a register move.
+         /* Constants in the range 0...255 can be loaded with an unextended
+            instruction.  They are therefore as cheap as a register move.
 
-        Given the choice between "li R1,0...255" and "move R1,R2"
-        (where R2 is a known constant), it is usually better to use "li",
-        since we do not want to unnecessarily extend the lifetime of R2.  */
-      if (outer_code == SET
-         && INTVAL (x) >= 0
-         && INTVAL (x) < 256)
+            Given the choice between "li R1,0...255" and "move R1,R2"
+            (where R2 is a known constant), it is usually better to use "li",
+            since we do not want to unnecessarily extend the lifetime
+            of R2.  */
+         if (outer_code == SET
+             && INTVAL (x) >= 0
+             && INTVAL (x) < 256)
+           {
+             *total = 0;
+             return true;
+           }
+       }
+      else
        {
+         /* These can be used anywhere. */
          *total = 0;
          return true;
        }
 
-      /* Otherwise fall through to the handling below.  */
+      /* Otherwise fall through to the handling below because
+        we'll need to construct the constant.  */
 
     case CONST:
     case SYMBOL_REF:
@@ -2173,15 +2640,15 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
 
     case MEM:
       {
-        /* If the address is legitimate, return the number of
-           instructions it needs, otherwise use the default handling.  */
-        int n = mips_address_insns (XEXP (x, 0), GET_MODE (x));
-        if (n > 0)
-          {
-            *total = COSTS_N_INSNS (1 + n);
-            return true;
-          }
-        return false;
+       /* If the address is legitimate, return the number of
+          instructions it needs, otherwise use the default handling.  */
+       int n = mips_address_insns (XEXP (x, 0), GET_MODE (x));
+       if (n > 0)
+         {
+           *total = COSTS_N_INSNS (n + 1);
+           return true;
+         }
+       return false;
       }
 
     case FFS:
@@ -2214,7 +2681,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
       return false;
 
     case ABS:
-      if (mode == SFmode || mode == DFmode)
+      if (float_mode_p)
         *total = COSTS_N_INSNS (1);
       else
         *total = COSTS_N_INSNS (4);
@@ -2226,19 +2693,13 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
 
     case PLUS:
     case MINUS:
-      if (mode == SFmode || mode == DFmode)
-        {
-          if (TUNE_MIPS3000 || TUNE_MIPS3900)
-            *total = COSTS_N_INSNS (2);
-          else if (TUNE_MIPS6000)
-            *total = COSTS_N_INSNS (3);
-         else if (TUNE_SB1)
-           *total = COSTS_N_INSNS (4);
-          else
-            *total = COSTS_N_INSNS (6);
-          return true;
-        }
-      if (mode == DImode && !TARGET_64BIT)
+      if (float_mode_p)
+       {
+         *total = mips_cost->fp_add;
+         return true;
+       }
+
+      else if (mode == DImode && !TARGET_64BIT)
         {
           *total = COSTS_N_INSNS (4);
           return true;
@@ -2248,119 +2709,50 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
     case NEG:
       if (mode == DImode && !TARGET_64BIT)
         {
-          *total = 4;
+          *total = COSTS_N_INSNS (4);
           return true;
         }
       return false;
 
     case MULT:
       if (mode == SFmode)
-        {
-          if (TUNE_MIPS3000
-              || TUNE_MIPS3900
-              || TUNE_MIPS5000
-             || TUNE_SB1)
-            *total = COSTS_N_INSNS (4);
-          else if (TUNE_MIPS6000
-                   || TUNE_MIPS5400
-                   || TUNE_MIPS5500)
-            *total = COSTS_N_INSNS (5);
-          else
-            *total = COSTS_N_INSNS (7);
-          return true;
-        }
+       *total = mips_cost->fp_mult_sf;
 
-      if (mode == DFmode)
-        {
-          if (TUNE_SB1)
-           *total = COSTS_N_INSNS (4);
-          else if (TUNE_MIPS3000
-              || TUNE_MIPS3900
-              || TUNE_MIPS5000)
-            *total = COSTS_N_INSNS (5);
-          else if (TUNE_MIPS6000
-                   || TUNE_MIPS5400
-                   || TUNE_MIPS5500)
-            *total = COSTS_N_INSNS (6);
-          else
-            *total = COSTS_N_INSNS (8);
-          return true;
-        }
+      else if (mode == DFmode)
+       *total = mips_cost->fp_mult_df;
+
+      else if (mode == SImode)
+       *total = mips_cost->int_mult_si;
 
-      if (TUNE_MIPS3000)
-        *total = COSTS_N_INSNS (12);
-      else if (TUNE_MIPS3900)
-        *total = COSTS_N_INSNS (2);
-      else if (TUNE_MIPS4130)
-       *total = COSTS_N_INSNS (mode == DImode ? 6 : 4);
-      else if (TUNE_MIPS5400 || TUNE_SB1)
-        *total = COSTS_N_INSNS (mode == DImode ? 4 : 3);
-      else if (TUNE_MIPS5500 || TUNE_MIPS7000)
-        *total = COSTS_N_INSNS (mode == DImode ? 9 : 5);
-      else if (TUNE_MIPS9000)
-        *total = COSTS_N_INSNS (mode == DImode ? 8 : 3);
-      else if (TUNE_MIPS6000)
-        *total = COSTS_N_INSNS (17);
-      else if (TUNE_MIPS5000)
-        *total = COSTS_N_INSNS (5);
       else
-        *total = COSTS_N_INSNS (10);
+       *total = mips_cost->int_mult_di;
+
       return true;
 
     case DIV:
     case MOD:
-      if (mode == SFmode)
-        {
-          if (TUNE_MIPS3000
-              || TUNE_MIPS3900)
-            *total = COSTS_N_INSNS (12);
-          else if (TUNE_MIPS6000)
-            *total = COSTS_N_INSNS (15);
-         else if (TUNE_SB1)
-           *total = COSTS_N_INSNS (24);
-          else if (TUNE_MIPS5400 || TUNE_MIPS5500)
-            *total = COSTS_N_INSNS (30);
-          else
-            *total = COSTS_N_INSNS (23);
-          return true;
-        }
+      if (float_mode_p)
+       {
+         if (mode == SFmode)
+           *total = mips_cost->fp_div_sf;
+         else
+           *total = mips_cost->fp_div_df;
 
-      if (mode == DFmode)
-        {
-          if (TUNE_MIPS3000
-              || TUNE_MIPS3900)
-            *total = COSTS_N_INSNS (19);
-          else if (TUNE_MIPS5400 || TUNE_MIPS5500)
-            *total = COSTS_N_INSNS (59);
-          else if (TUNE_MIPS6000)
-            *total = COSTS_N_INSNS (16);
-         else if (TUNE_SB1)
-           *total = COSTS_N_INSNS (32);
-          else
-            *total = COSTS_N_INSNS (36);
-          return true;
-        }
+         return true;
+       }
       /* Fall through.  */
 
     case UDIV:
     case UMOD:
-      if (TUNE_MIPS3000
-          || TUNE_MIPS3900)
-        *total = COSTS_N_INSNS (35);
-      else if (TUNE_MIPS6000)
-        *total = COSTS_N_INSNS (38);
-      else if (TUNE_MIPS5000)
-        *total = COSTS_N_INSNS (36);
-      else if (TUNE_SB1)
-       *total = COSTS_N_INSNS ((mode == SImode) ? 36 : 68);
-      else if (TUNE_MIPS5400 || TUNE_MIPS5500)
-        *total = COSTS_N_INSNS ((mode == SImode) ? 42 : 74);
+      if (mode == DImode)
+        *total = mips_cost->int_div_di;
       else
-        *total = COSTS_N_INSNS (69);
+       *total = mips_cost->int_div_si;
+
       return true;
 
     case SIGN_EXTEND:
-      /* A sign extend from SImode to DImode in 64 bit mode is often
+      /* A sign extend from SImode to DImode in 64-bit mode is often
          zero instructions, because the result can often be used
          directly by another instruction; we'll call it one.  */
       if (TARGET_64BIT && mode == DImode
@@ -2378,6 +2770,15 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
         *total = COSTS_N_INSNS (1);
       return true;
 
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+    case SQRT:
+      *total = mips_cost->fp_add;
+      return true;
+
     default:
       return false;
     }
@@ -2415,8 +2816,8 @@ mips_subword (rtx op, int high_p)
     {
       if (FP_REG_P (REGNO (op)))
        return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op));
-      if (REGNO (op) == HI_REGNUM)
-       return gen_rtx_REG (word_mode, high_p ? HI_REGNUM : LO_REGNUM);
+      if (ACC_HI_REG_P (REGNO (op)))
+       return gen_rtx_REG (word_mode, high_p ? REGNO (op) : REGNO (op) + 1);
     }
 
   if (MEM_P (op))
@@ -2472,15 +2873,35 @@ mips_split_64bit_move (rtx dest, rtx src)
   if (FP_REG_RTX_P (dest))
     {
       /* Loading an FPR from memory or from GPRs.  */
-      emit_insn (gen_load_df_low (copy_rtx (dest), mips_subword (src, 0)));
-      emit_insn (gen_load_df_high (dest, mips_subword (src, 1),
-                                  copy_rtx (dest)));
+      if (ISA_HAS_MXHC1)
+       {
+         dest = gen_lowpart (DFmode, dest);
+         emit_insn (gen_load_df_low (dest, mips_subword (src, 0)));
+         emit_insn (gen_mthc1 (dest, mips_subword (src, 1),
+                               copy_rtx (dest)));
+       }
+      else
+       {
+         emit_insn (gen_load_df_low (copy_rtx (dest),
+                                     mips_subword (src, 0)));
+         emit_insn (gen_load_df_high (dest, mips_subword (src, 1),
+                                      copy_rtx (dest)));
+       }
     }
   else if (FP_REG_RTX_P (src))
     {
       /* Storing an FPR into memory or GPRs.  */
-      emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
-      emit_insn (gen_store_df_high (mips_subword (dest, 1), src));
+      if (ISA_HAS_MXHC1)
+       {
+         src = gen_lowpart (DFmode, src);
+         emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
+         emit_insn (gen_mfhc1 (mips_subword (dest, 1), src));
+       }
+      else
+       {
+         emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
+         emit_insn (gen_store_df_high (mips_subword (dest, 1), src));
+       }
     }
   else
     {
@@ -2530,6 +2951,14 @@ mips_output_move (rtx dest, rtx src)
          if (MD_REG_P (REGNO (dest)))
            return "mt%0\t%z1";
 
+         if (DSP_ACC_REG_P (REGNO (dest)))
+           {
+             static char retval[] = "mt__\t%z1,%q0";
+             retval[2] = reg_names[REGNO (dest)][4];
+             retval[3] = reg_names[REGNO (dest)][5];
+             return retval;
+           }
+
          if (FP_REG_P (REGNO (dest)))
            return (dbl_p ? "dmtc1\t%z1,%0" : "mtc1\t%z1,%0");
 
@@ -2548,6 +2977,14 @@ mips_output_move (rtx dest, rtx src)
     {
       if (src_code == REG)
        {
+         if (DSP_ACC_REG_P (REGNO (src)))
+           {
+             static char retval[] = "mf__\t%0,%q1";
+             retval[2] = reg_names[REGNO (src)][4];
+             retval[3] = reg_names[REGNO (src)][5];
+             return retval;
+           }
+
          if (ST_REG_P (REGNO (src)) && ISA_HAS_8CC)
            return "lui\t%0,0x3f80\n\tmovf\t%0,%.,%1";
 
@@ -2569,7 +3006,7 @@ mips_output_move (rtx dest, rtx src)
       if (src_code == CONST_INT)
        {
          /* Don't use the X format, because that will give out of
-            range numbers for 64 bit hosts and 32 bit targets.  */
+            range numbers for 64-bit hosts and 32-bit targets.  */
          if (!TARGET_MIPS16)
            return "li\t%0,%1\t\t\t# %X1";
 
@@ -2688,6 +3125,50 @@ mips_relational_operand_ok_p (enum rtx_code code, rtx cmp1)
     }
 }
 
+/* Canonicalize LE or LEU comparisons into LT comparisons when
+   possible to avoid extra instructions or inverting the
+   comparison.  */
+
+static bool
+mips_canonicalize_comparison (enum rtx_code *code, rtx *cmp1,
+                             enum machine_mode mode)
+{
+  HOST_WIDE_INT original, plus_one;
+
+  if (GET_CODE (*cmp1) != CONST_INT)
+    return false;
+
+  original = INTVAL (*cmp1);
+  plus_one = trunc_int_for_mode ((unsigned HOST_WIDE_INT) original + 1, mode);
+
+  switch (*code)
+    {
+    case LE:
+      if (original < plus_one)
+       {
+         *code = LT;
+         *cmp1 = force_reg (mode, GEN_INT (plus_one));
+         return true;
+       }
+      break;
+
+    case LEU:
+      if (plus_one != 0)
+       {
+         *code = LTU;
+         *cmp1 = force_reg (mode, GEN_INT (plus_one));
+         return true;
+       }
+      break;
+
+    default:
+      return false;
+   }
+
+  return false;
+
+}
+
 /* Compare CMP0 and CMP1 using relational operator CODE and store the
    result in TARGET.  CMP0 and TARGET are register_operands that have
    the same integer mode.  If INVERT_PTR is nonnull, it's OK to set
@@ -2698,11 +3179,14 @@ mips_emit_int_relational (enum rtx_code code, bool *invert_ptr,
                          rtx target, rtx cmp0, rtx cmp1)
 {
   /* First see if there is a MIPS instruction that can do this operation
-     with CMP1 in its current form.  If not, try doing the same for the
+     with CMP1 in its current form. If not, try to canonicalize the
+     comparison to LT. If that fails, try doing the same for the
      inverse operation.  If that also fails, force CMP1 into a register
      and try again.  */
   if (mips_relational_operand_ok_p (code, cmp1))
     mips_emit_binary (code, target, cmp0, cmp1);
+  else if (mips_canonicalize_comparison (&code, &cmp1, GET_MODE (target)))
+    mips_emit_binary (code, target, cmp0, cmp1);
   else
     {
       enum rtx_code inv_code = reverse_condition (code);
@@ -2742,6 +3226,27 @@ mips_zero_if_equal (rtx cmp0, rtx cmp1)
                       cmp0, cmp1, 0, 0, OPTAB_DIRECT);
 }
 
+/* Convert *CODE into a code that can be used in a floating-point
+   scc instruction (c.<cond>.<fmt>).  Return true if the values of
+   the condition code registers will be inverted, with 0 indicating
+   that the condition holds.  */
+
+static bool
+mips_reverse_fp_cond_p (enum rtx_code *code)
+{
+  switch (*code)
+    {
+    case NE:
+    case LTGT:
+    case ORDERED:
+      *code = reverse_condition_maybe_unordered (*code);
+      return true;
+
+    default:
+      return false;
+    }
+}
+
 /* Convert a comparison into something that can be used in a branch or
    conditional move.  cmp_operands[0] and cmp_operands[1] are the values
    being compared and *CODE is the code used to compare them.
@@ -2799,22 +3304,8 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
 
         Set CMP_CODE to the code of the comparison instruction and
         *CODE to the code that the branch or move should use.  */
-      switch (*code)
-       {
-       case NE:
-       case UNGE:
-       case UNGT:
-       case LTGT:
-       case ORDERED:
-         cmp_code = reverse_condition_maybe_unordered (*code);
-         *code = EQ;
-         break;
-
-       default:
-         cmp_code = *code;
-         *code = NE;
-         break;
-       }
+      cmp_code = *code;
+      *code = mips_reverse_fp_cond_p (&cmp_code) ? EQ : NE;
       *op0 = (ISA_HAS_8CC
              ? gen_reg_rtx (CCmode)
              : gen_rtx_REG (CCmode, FPSW_REGNUM));
@@ -2853,15 +3344,35 @@ mips_emit_scc (enum rtx_code code, rtx target)
 void
 gen_conditional_branch (rtx *operands, enum rtx_code code)
 {
-  rtx op0, op1, target;
+  rtx op0, op1, condition;
 
   mips_emit_compare (&code, &op0, &op1, TARGET_MIPS16);
-  target = gen_rtx_IF_THEN_ELSE (VOIDmode,
-                                gen_rtx_fmt_ee (code, GET_MODE (op0),
-                                                op0, op1),
-                                gen_rtx_LABEL_REF (VOIDmode, operands[0]),
-                                pc_rtx);
-  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, target));
+  condition = gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+  emit_jump_insn (gen_condjump (condition, operands[0]));
+}
+
+/* Implement:
+
+   (set temp (COND:CCV2 CMP_OP0 CMP_OP1))
+   (set DEST (unspec [TRUE_SRC FALSE_SRC temp] UNSPEC_MOVE_TF_PS))  */
+
+void
+mips_expand_vcondv2sf (rtx dest, rtx true_src, rtx false_src,
+                      enum rtx_code cond, rtx cmp_op0, rtx cmp_op1)
+{
+  rtx cmp_result;
+  bool reversed_p;
+
+  reversed_p = mips_reverse_fp_cond_p (&cond);
+  cmp_result = gen_reg_rtx (CCV2mode);
+  emit_insn (gen_scc_ps (cmp_result,
+                        gen_rtx_fmt_ee (cond, VOIDmode, cmp_op0, cmp_op1)));
+  if (reversed_p)
+    emit_insn (gen_mips_cond_move_tf_ps (dest, false_src, true_src,
+                                        cmp_result));
+  else
+    emit_insn (gen_mips_cond_move_tf_ps (dest, true_src, false_src,
+                                        cmp_result));
 }
 
 /* Emit the common code for conditional moves.  OPERANDS is the array
@@ -2923,6 +3434,16 @@ mips_gen_conditional_trap (rtx *operands)
                              operands[1]));
 }
 \f
+/* Return true if calls to X can use R_MIPS_CALL* relocations.  */
+
+static bool
+mips_ok_for_lazy_binding_p (rtx x)
+{
+  return (TARGET_USE_GOT
+         && GET_CODE (x) == SYMBOL_REF
+         && !mips_symbol_binds_local_p (x));
+}
+
 /* Load function address ADDR into register DEST.  SIBCALL_P is true
    if the address is needed for a sibling call.  */
 
@@ -2931,11 +3452,11 @@ mips_load_call_address (rtx dest, rtx addr, int sibcall_p)
 {
   /* If we're generating PIC, and this call is to a global function,
      try to allow its address to be resolved lazily.  This isn't
-     possible for NewABI sibcalls since the value of $gp on entry
+     possible if TARGET_CALL_SAVED_GP since the value of $gp on entry
      to the stub would be our caller's gp, not ours.  */
   if (TARGET_EXPLICIT_RELOCS
-      && !(sibcall_p && TARGET_NEWABI)
-      && global_got_operand (addr, VOIDmode))
+      && !(sibcall_p && TARGET_CALL_SAVED_GP)
+      && mips_ok_for_lazy_binding_p (addr))
     {
       rtx high, lo_sum_symbol;
 
@@ -3000,7 +3521,7 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
   insn = emit_call_insn (pattern);
 
   /* Lazy-binding stubs require $gp to be valid on entry.  */
-  if (global_got_operand (orig_addr, VOIDmode))
+  if (mips_ok_for_lazy_binding_p (orig_addr))
     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
 }
 
@@ -3037,7 +3558,7 @@ mips_emit_fcc_reload (rtx dest, rtx src, rtx scratch)
     src = gen_rtx_REG (SFmode, true_regnum (src));
 
   fp1 = gen_rtx_REG (SFmode, REGNO (scratch));
-  fp2 = gen_rtx_REG (SFmode, REGNO (scratch) + FP_INC);
+  fp2 = gen_rtx_REG (SFmode, REGNO (scratch) + MAX_FPRS_PER_FMT);
 
   emit_move_insn (copy_rtx (fp1), src);
   emit_move_insn (copy_rtx (fp2), CONST0_RTX (SFmode));
@@ -3381,7 +3902,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   if (mips_abi != ABI_EABI || !info.fpr_p)
     cum->num_gprs = info.reg_offset + info.reg_words;
   else if (info.reg_words > 0)
-    cum->num_fprs += FP_INC;
+    cum->num_fprs += MAX_FPRS_PER_FMT;
 
   if (info.stack_words > 0)
     cum->stack_words = info.stack_offset + info.stack_words;
@@ -3423,8 +3944,8 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && host_integerp (TYPE_SIZE_UNIT (type), 1)
       && named)
     {
-      /* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
-        structure contains a double in its entirety, then that 64 bit
+      /* The Irix 6 n32/n64 ABIs say that if any 64-bit chunk of the
+        structure contains a double in its entirety, then that 64-bit
         chunk is passed in a floating point register.  */
       tree field;
 
@@ -3440,7 +3961,7 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
       if (field != 0)
        {
          /* Now handle the special case by returning a PARALLEL
-            indicating where each 64 bit chunk goes.  INFO.REG_WORDS
+            indicating where each 64-bit chunk goes.  INFO.REG_WORDS
             chunks are passed in registers.  */
          unsigned int i;
          HOST_WIDE_INT bitpos;
@@ -3493,21 +4014,33 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
       inner = GET_MODE_INNER (mode);
       reg = FP_ARG_FIRST + info.reg_offset;
-      real = gen_rtx_EXPR_LIST (VOIDmode,
-                               gen_rtx_REG (inner, reg),
-                               const0_rtx);
-      imag = gen_rtx_EXPR_LIST (VOIDmode,
-                               gen_rtx_REG (inner, reg + info.reg_words / 2),
-                               GEN_INT (GET_MODE_SIZE (inner)));
-      return gen_rtx_PARALLEL (mode, gen_rtvec (2, real, imag));
+      if (info.reg_words * UNITS_PER_WORD == GET_MODE_SIZE (inner))
+       {
+         /* Real part in registers, imaginary part on stack.  */
+         gcc_assert (info.stack_words == info.reg_words);
+         return gen_rtx_REG (inner, reg);
+       }
+      else
+       {
+         gcc_assert (info.stack_words == 0);
+         real = gen_rtx_EXPR_LIST (VOIDmode,
+                                   gen_rtx_REG (inner, reg),
+                                   const0_rtx);
+         imag = gen_rtx_EXPR_LIST (VOIDmode,
+                                   gen_rtx_REG (inner,
+                                                reg + info.reg_words / 2),
+                                   GEN_INT (GET_MODE_SIZE (inner)));
+         return gen_rtx_PARALLEL (mode, gen_rtvec (2, real, imag));
+       }
     }
 
   if (!info.fpr_p)
     return gen_rtx_REG (mode, GP_ARG_FIRST + info.reg_offset);
-  else if (info.reg_offset == 1)
-    /* This code handles the special o32 case in which the second word
-       of the argument structure is passed in floating-point registers.  */
-    return gen_rtx_REG (mode, FP_ARG_FIRST + FP_INC);
+  else if (mips_abi == ABI_32 && TARGET_DOUBLE_FLOAT && info.reg_offset > 0)
+    /* In o32, the second argument is always passed in $f14
+       for TARGET_DOUBLE_FLOAT, regardless of whether the
+       first argument was a word or doubleword.  */
+    return gen_rtx_REG (mode, FP_ARG_FIRST + 2);
   else
     return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset);
 }
@@ -3598,7 +4131,8 @@ mips_pad_reg_upward (enum machine_mode mode, tree type)
 \f
 static void
 mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                            tree type, int *pretend_size, int no_rtl)
+                            tree type, int *pretend_size ATTRIBUTE_UNUSED,
+                            int no_rtl)
 {
   CUMULATIVE_ARGS local_cum;
   int gp_saved, fp_saved;
@@ -3622,18 +4156,9 @@ mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        {
          rtx ptr, mem;
 
-         ptr = virtual_incoming_args_rtx;
-         switch (mips_abi)
-           {
-           case ABI_32:
-           case ABI_O64:
-             ptr = plus_constant (ptr, local_cum.num_gprs * UNITS_PER_WORD);
-             break;
-
-           case ABI_EABI:
-             ptr = plus_constant (ptr, -gp_saved * UNITS_PER_WORD);
-             break;
-           }
+         ptr = plus_constant (virtual_incoming_args_rtx,
+                              REG_PARM_STACK_SPACE (cfun->decl)
+                              - gp_saved * UNITS_PER_WORD);
          mem = gen_rtx_MEM (BLKmode, ptr);
          set_mem_alias_set (mem, get_varargs_alias_set ());
 
@@ -3656,7 +4181,8 @@ mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
          mode = TARGET_SINGLE_FLOAT ? SFmode : DFmode;
 
-         for (i = local_cum.num_fprs; i < MAX_ARGS_IN_REGISTERS; i += FP_INC)
+         for (i = local_cum.num_fprs; i < MAX_ARGS_IN_REGISTERS;
+              i += MAX_FPRS_PER_FMT)
            {
              rtx ptr, mem;
 
@@ -3668,14 +4194,9 @@ mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            }
        }
     }
-  if (TARGET_OLDABI)
-    {
-      /* No need for pretend arguments: the register parameter area was
-        allocated by the caller.  */
-      *pretend_size = 0;
-      return;
-    }
-  *pretend_size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_FPREG);
+  if (REG_PARM_STACK_SPACE (cfun->decl) == 0)
+    cfun->machine->varargs_size = (gp_saved * UNITS_PER_WORD
+                                  + fp_saved * UNITS_PER_FPREG);
 }
 
 /* Create the va_list data type.
@@ -3755,101 +4276,84 @@ mips_build_builtin_va_list (void)
 void
 mips_va_start (tree valist, rtx nextarg)
 {
-  const CUMULATIVE_ARGS *cum = &current_function_args_info;
-
-  /* ARG_POINTER_REGNUM is initialized to STACK_POINTER_BOUNDARY, but
-     since the stack is aligned for a pair of argument-passing slots,
-     and the beginning of a variable argument list may be an odd slot,
-     we have to decrease its alignment.  */
-  if (cfun && cfun->emit->regno_pointer_align)
-    while (((current_function_pretend_args_size * BITS_PER_UNIT)
-           & (REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) - 1)) != 0)
-      REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) /= 2;
-
-  if (mips_abi == ABI_EABI)
+  if (EABI_FLOAT_VARARGS_P)
     {
+      const CUMULATIVE_ARGS *cum;
+      tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
+      tree ovfl, gtop, ftop, goff, foff;
+      tree t;
       int gpr_save_area_size;
+      int fpr_save_area_size;
+      int fpr_offset;
 
+      cum = &current_function_args_info;
       gpr_save_area_size
        = (MAX_ARGS_IN_REGISTERS - cum->num_gprs) * UNITS_PER_WORD;
+      fpr_save_area_size
+       = (MAX_ARGS_IN_REGISTERS - cum->num_fprs) * UNITS_PER_FPREG;
 
-      if (EABI_FLOAT_VARARGS_P)
-       {
-         tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
-         tree ovfl, gtop, ftop, goff, foff;
-         tree t;
-         int fpr_offset;
-         int fpr_save_area_size;
-
-         f_ovfl = TYPE_FIELDS (va_list_type_node);
-         f_gtop = TREE_CHAIN (f_ovfl);
-         f_ftop = TREE_CHAIN (f_gtop);
-         f_goff = TREE_CHAIN (f_ftop);
-         f_foff = TREE_CHAIN (f_goff);
-
-         ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
-                       NULL_TREE);
-         gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
-                       NULL_TREE);
-         ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
-                       NULL_TREE);
-         goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
-                       NULL_TREE);
-         foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
-                       NULL_TREE);
-
-         /* Emit code to initialize OVFL, which points to the next varargs
-            stack argument.  CUM->STACK_WORDS gives the number of stack
-            words used by named arguments.  */
-         t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
-         if (cum->stack_words > 0)
-           t = build (PLUS_EXPR, TREE_TYPE (ovfl), t,
-                      build_int_cst (NULL_TREE,
-                                     cum->stack_words * UNITS_PER_WORD));
-         t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
-         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-         /* Emit code to initialize GTOP, the top of the GPR save area.  */
-         t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx);
-         t = build (MODIFY_EXPR, TREE_TYPE (gtop), gtop, t);
-         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-         /* Emit code to initialize FTOP, the top of the FPR save area.
-            This address is gpr_save_area_bytes below GTOP, rounded
-            down to the next fp-aligned boundary.  */
-         t = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx);
-         fpr_offset = gpr_save_area_size + UNITS_PER_FPVALUE - 1;
-         fpr_offset &= ~(UNITS_PER_FPVALUE - 1);
-         if (fpr_offset)
-           t = build (PLUS_EXPR, TREE_TYPE (ftop), t,
-                      build_int_cst (NULL_TREE, -fpr_offset));
-         t = build (MODIFY_EXPR, TREE_TYPE (ftop), ftop, t);
-         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-         /* Emit code to initialize GOFF, the offset from GTOP of the
-            next GPR argument.  */
-         t = build (MODIFY_EXPR, TREE_TYPE (goff), goff,
-                    build_int_cst (NULL_TREE, gpr_save_area_size));
-         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-         /* Likewise emit code to initialize FOFF, the offset from FTOP
-            of the next FPR argument.  */
-         fpr_save_area_size
-           = (MAX_ARGS_IN_REGISTERS - cum->num_fprs) * UNITS_PER_FPREG;
-         t = build (MODIFY_EXPR, TREE_TYPE (foff), foff,
-                    build_int_cst (NULL_TREE, fpr_save_area_size));
-         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-       }
-      else
-       {
-         /* Everything is in the GPR save area, or in the overflow
-            area which is contiguous with it.  */
-         nextarg = plus_constant (nextarg, -gpr_save_area_size);
-         std_expand_builtin_va_start (valist, nextarg);
-       }
+      f_ovfl = TYPE_FIELDS (va_list_type_node);
+      f_gtop = TREE_CHAIN (f_ovfl);
+      f_ftop = TREE_CHAIN (f_gtop);
+      f_goff = TREE_CHAIN (f_ftop);
+      f_foff = TREE_CHAIN (f_goff);
+
+      ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
+                    NULL_TREE);
+      gtop = build3 (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
+                    NULL_TREE);
+      ftop = build3 (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
+                    NULL_TREE);
+      goff = build3 (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
+                    NULL_TREE);
+      foff = build3 (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
+                    NULL_TREE);
+
+      /* Emit code to initialize OVFL, which points to the next varargs
+        stack argument.  CUM->STACK_WORDS gives the number of stack
+        words used by named arguments.  */
+      t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
+      if (cum->stack_words > 0)
+       t = build2 (PLUS_EXPR, TREE_TYPE (ovfl), t,
+                   build_int_cst (NULL_TREE,
+                                  cum->stack_words * UNITS_PER_WORD));
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovfl), ovfl, t);
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* Emit code to initialize GTOP, the top of the GPR save area.  */
+      t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx);
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (gtop), gtop, t);
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* Emit code to initialize FTOP, the top of the FPR save area.
+        This address is gpr_save_area_bytes below GTOP, rounded
+        down to the next fp-aligned boundary.  */
+      t = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx);
+      fpr_offset = gpr_save_area_size + UNITS_PER_FPVALUE - 1;
+      fpr_offset &= ~(UNITS_PER_FPVALUE - 1);
+      if (fpr_offset)
+       t = build2 (PLUS_EXPR, TREE_TYPE (ftop), t,
+                   build_int_cst (NULL_TREE, -fpr_offset));
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ftop), ftop, t);
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* Emit code to initialize GOFF, the offset from GTOP of the
+        next GPR argument.  */
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (goff), goff,
+                 build_int_cst (NULL_TREE, gpr_save_area_size));
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* Likewise emit code to initialize FOFF, the offset from FTOP
+        of the next FPR argument.  */
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (foff), foff,
+                 build_int_cst (NULL_TREE, fpr_save_area_size));
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
   else
-    std_expand_builtin_va_start (valist, nextarg);
+    {
+      nextarg = plus_constant (nextarg, -cfun->machine->varargs_size);
+      std_expand_builtin_va_start (valist, nextarg);
+    }
 }
 \f
 /* Implement va_arg.  */
@@ -3916,16 +4420,16 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 
         [1] and [9] can sometimes be optimized away.  */
 
-      ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
-                   NULL_TREE);
+      ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
+                    NULL_TREE);
 
       if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
          && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
        {
-         top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
-                      NULL_TREE);
-         off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
-                      NULL_TREE);
+         top = build3 (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
+                       NULL_TREE);
+         off = build3 (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
+                       NULL_TREE);
 
          /* When floating-point registers are saved to the stack,
             each one will take up UNITS_PER_HWFPVALUE bytes, regardless
@@ -3953,42 +4457,42 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
        }
       else
        {
-         top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
-                      NULL_TREE);
-         off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
-                      NULL_TREE);
+         top = build3 (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
+                       NULL_TREE);
+         off = build3 (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
+                       NULL_TREE);
          if (rsize > UNITS_PER_WORD)
            {
              /* [1] Emit code for: off &= -rsize.      */
-             t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
-                        build_int_cst (NULL_TREE, -rsize));
-             t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
+             t = build2 (BIT_AND_EXPR, TREE_TYPE (off), off,
+                         build_int_cst (NULL_TREE, -rsize));
+             t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (off), off, t);
              gimplify_and_add (t, pre_p);
            }
          osize = rsize;
        }
 
       /* [2] Emit code to branch if off == 0.  */
-      t = build (NE_EXPR, boolean_type_node, off,
-                build_int_cst (TREE_TYPE (off), 0));
-      addr = build (COND_EXPR, ptr_type_node, t, NULL, NULL);
+      t = build2 (NE_EXPR, boolean_type_node, off,
+                 build_int_cst (TREE_TYPE (off), 0));
+      addr = build3 (COND_EXPR, ptr_type_node, t, NULL_TREE, NULL_TREE);
 
       /* [5] Emit code for: off -= rsize.  We do this as a form of
         post-increment not available to C.  Also widen for the
         coming pointer arithmetic.  */
       t = fold_convert (TREE_TYPE (off), build_int_cst (NULL_TREE, rsize));
-      t = build (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t);
+      t = build2 (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t);
       t = fold_convert (sizetype, t);
       t = fold_convert (TREE_TYPE (top), t);
 
       /* [4] Emit code for: addr_rtx = top - off.  On big endian machines,
         the argument has RSIZE - SIZE bytes of leading padding.  */
-      t = build (MINUS_EXPR, TREE_TYPE (top), top, t);
+      t = build2 (MINUS_EXPR, TREE_TYPE (top), top, t);
       if (BYTES_BIG_ENDIAN && rsize > size)
        {
          u = fold_convert (TREE_TYPE (t), build_int_cst (NULL_TREE,
                                                          rsize - size));
-         t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
+         t = build2 (PLUS_EXPR, TREE_TYPE (t), t, u);
        }
       COND_EXPR_THEN (addr) = t;
 
@@ -3997,11 +4501,11 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
          /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize.  */
          u = fold_convert (TREE_TYPE (ovfl),
                            build_int_cst (NULL_TREE, osize - 1));
-         t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
+         t = build2 (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
          u = fold_convert (TREE_TYPE (ovfl),
                            build_int_cst (NULL_TREE, -osize));
-         t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
-         align = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
+         t = build2 (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
+         align = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovfl), ovfl, t);
        }
       else
        align = NULL;
@@ -4011,25 +4515,25 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
         the argument has OSIZE - SIZE bytes of leading padding.  */
       u = fold_convert (TREE_TYPE (ovfl),
                        build_int_cst (NULL_TREE, osize));
-      t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
+      t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
       if (BYTES_BIG_ENDIAN && osize > size)
        {
          u = fold_convert (TREE_TYPE (t),
                            build_int_cst (NULL_TREE, osize - size));
-         t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
+         t = build2 (PLUS_EXPR, TREE_TYPE (t), t, u);
        }
 
       /* String [9] and [10,11] together.  */
       if (align)
-       t = build (COMPOUND_EXPR, TREE_TYPE (t), align, t);
+       t = build2 (COMPOUND_EXPR, TREE_TYPE (t), align, t);
       COND_EXPR_ELSE (addr) = t;
 
       addr = fold_convert (build_pointer_type (type), addr);
-      addr = build_fold_indirect_ref (addr);
+      addr = build_va_arg_indirect_ref (addr);
     }
 
   if (indirect)
-    addr = build_fold_indirect_ref (addr);
+    addr = build_va_arg_indirect_ref (addr);
 
   return addr;
 }
@@ -4045,7 +4549,7 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
    left-side instructions (lwl, swl, ldl, sdl).
 
    *RIGHT is a QImode reference to the opposite end of the field and
-   can be used in the parterning right-side instruction.  */
+   can be used in the patterning right-side instruction.  */
 
 static bool
 mips_get_unaligned_mem (rtx *op, unsigned int width, int bitpos,
@@ -4143,13 +4647,15 @@ bool
 mips_expand_unaligned_store (rtx dest, rtx src, unsigned int width, int bitpos)
 {
   rtx left, right;
+  enum machine_mode mode;
 
   if (!mips_get_unaligned_mem (&dest, width, bitpos, &left, &right))
     return false;
 
-  src = gen_lowpart (mode_for_size (width, MODE_INT, 0), src);
+  mode = mode_for_size (width, MODE_INT, 0);
+  src = gen_lowpart (mode, src);
 
-  if (GET_MODE (src) == DImode)
+  if (mode == DImode)
     {
       emit_insn (gen_mov_sdl (dest, src, left));
       emit_insn (gen_mov_sdr (copy_rtx (dest), copy_rtx (src), right));
@@ -4161,7 +4667,53 @@ mips_expand_unaligned_store (rtx dest, rtx src, unsigned int width, int bitpos)
     }
   return true;
 }
-\f
+
+/* Return true if X is a MEM with the same size as MODE.  */
+
+bool
+mips_mem_fits_mode_p (enum machine_mode mode, rtx x)
+{
+  rtx size;
+
+  if (!MEM_P (x))
+    return false;
+
+  size = MEM_SIZE (x);
+  return size && INTVAL (size) == GET_MODE_SIZE (mode);
+}
+
+/* Return true if (zero_extract OP SIZE POSITION) can be used as the
+   source of an "ext" instruction or the destination of an "ins"
+   instruction.  OP must be a register operand and the following
+   conditions must hold:
+
+     0 <= POSITION < GET_MODE_BITSIZE (GET_MODE (op))
+     0 < SIZE <= GET_MODE_BITSIZE (GET_MODE (op))
+     0 < POSITION + SIZE <= GET_MODE_BITSIZE (GET_MODE (op))
+
+   Also reject lengths equal to a word as they are better handled
+   by the move patterns.  */
+
+bool
+mips_use_ins_ext_p (rtx op, rtx size, rtx position)
+{
+  HOST_WIDE_INT len, pos;
+
+  if (!ISA_HAS_EXT_INS
+      || !register_operand (op, VOIDmode)
+      || GET_MODE_BITSIZE (GET_MODE (op)) > BITS_PER_WORD)
+    return false;
+
+  len = INTVAL (size);
+  pos = INTVAL (position);
+
+  if (len <= 0 || len >= GET_MODE_BITSIZE (GET_MODE (op))
+      || pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (op)))
+    return false;
+
+  return true;
+}
+
 /* Set up globals to generate code for the ISA or processor
    described by INFO.  */
 
@@ -4212,21 +4764,13 @@ mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
       return true;
 
     case OPT_march_:
-      mips_arch_string = arg;
-      return mips_parse_cpu (arg) != 0;
-
     case OPT_mtune_:
-      mips_tune_string = arg;
       return mips_parse_cpu (arg) != 0;
 
     case OPT_mips:
       mips_isa_info = mips_parse_cpu (ACONCAT (("mips", arg, NULL)));
       return mips_isa_info != 0;
 
-    case OPT_mflush_func_:
-      mips_cache_flush_func = arg;
-      return true;
-
     case OPT_mno_flush_func:
       mips_cache_flush_func = NULL;
       return true;
@@ -4245,6 +4789,10 @@ override_options (void)
   int i, start, regno;
   enum machine_mode mode;
 
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
   mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE;
 
   /* The following code determines the architecture and register size.
@@ -4285,6 +4833,12 @@ override_options (void)
   if (mips_tune_info == 0)
     mips_set_tune (mips_arch_info);
 
+  /* Set cost structure for the processor.  */
+  if (optimize_size)
+    mips_cost = &mips_rtx_cost_optimize_size;
+  else
+    mips_cost = &mips_rtx_cost_data[mips_tune];
+
   if ((target_flags_explicit & MASK_64BIT) != 0)
     {
       /* The user specified the size of the integer registers.  Make sure
@@ -4313,8 +4867,10 @@ override_options (void)
         only one right answer here.  */
       if (TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_FLOAT64)
        error ("unsupported combination: %s", "-mgp64 -mfp32 -mdouble-float");
-      else if (!TARGET_64BIT && TARGET_FLOAT64)
-       error ("unsupported combination: %s", "-mgp32 -mfp64");
+      else if (!TARGET_64BIT && TARGET_FLOAT64
+              && !(ISA_HAS_MXHC1 && mips_abi == ABI_32))
+       error ("-mgp32 and -mfp64 can only be combined if the target"
+              " supports the mfhc1 and mthc1 instructions");
       else if (TARGET_SINGLE_FLOAT && TARGET_FLOAT64)
        error ("unsupported combination: %s", "-mfp64 -msingle-float");
     }
@@ -4396,17 +4952,23 @@ override_options (void)
       target_flags &= ~MASK_ABICALLS;
     }
 
-  /* -fpic (-KPIC) is the default when TARGET_ABICALLS is defined.  We need
-     to set flag_pic so that the LEGITIMATE_PIC_OPERAND_P macro will work.  */
-  /* ??? -non_shared turns off pic code generation, but this is not
-     implemented.  */
   if (TARGET_ABICALLS)
     {
+      /* We need to set flag_pic for executables as well as DSOs
+        because we may reference symbols that are not defined in
+        the final executable.  (MIPS does not use things like
+        copy relocs, for example.)
+
+        Also, there is a body of code that uses __PIC__ to distinguish
+        between -mabicalls and -mno-abicalls code.  */
       flag_pic = 1;
       if (mips_section_threshold > 0)
-       warning (0, "-G is incompatible with PIC code which is the default");
+       warning (0, "%<-G%> is incompatible with %<-mabicalls%>");
     }
 
+  if (TARGET_VXWORKS_RTP && mips_section_threshold > 0)
+    warning (0, "-G and -mrtp are incompatible");
+
   /* mips_split_addresses is a half-way house between explicit
      relocations and the traditional assembler macros.  It can
      split absolute 32-bit symbolic constants into a high/lo_sum
@@ -4487,6 +5049,13 @@ override_options (void)
   if (TARGET_PAIRED_SINGLE_FLOAT && !ISA_MIPS64)
     error ("-mips3d/-mpaired-single must be used with -mips64");
 
+  /* If TARGET_DSPR2, enable MASK_DSP.  */
+  if (TARGET_DSPR2)
+    target_flags |= MASK_DSP;
+
+  if (TARGET_MIPS16 && TARGET_DSP)
+    error ("-mips16 and -mdsp cannot be used together");
+
   mips_print_operand_punct['?'] = 1;
   mips_print_operand_punct['#'] = 1;
   mips_print_operand_punct['/'] = 1;
@@ -4508,25 +5077,6 @@ override_options (void)
   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['t'] = T_REG;
-  mips_char_to_class['f'] = (TARGET_HARD_FLOAT ? FP_REGS : NO_REGS);
-  mips_char_to_class['h'] = HI_REG;
-  mips_char_to_class['l'] = LO_REG;
-  mips_char_to_class['x'] = MD_REGS;
-  mips_char_to_class['b'] = ALL_REGS;
-  mips_char_to_class['c'] = (TARGET_ABICALLS ? PIC_FN_ADDR_REG :
-                            TARGET_MIPS16 ? M16_NA_REGS :
-                            GR_REGS);
-  mips_char_to_class['e'] = LEA_REGS;
-  mips_char_to_class['j'] = PIC_FN_ADDR_REG;
-  mips_char_to_class['v'] = V1_REG;
-  mips_char_to_class['y'] = GR_REGS;
-  mips_char_to_class['z'] = ST_REGS;
-  mips_char_to_class['B'] = COP0_REGS;
-  mips_char_to_class['C'] = COP2_REGS;
-  mips_char_to_class['D'] = COP3_REGS;
-
   /* Set up array to map GCC register number to debug register number.
      Ignore the special purpose register numbers.  */
 
@@ -4580,21 +5130,28 @@ override_options (void)
            temp = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
 
          else if (FP_REG_P (regno))
-           temp = ((regno % FP_INC) == 0)
+           temp = ((((regno % MAX_FPRS_PER_FMT) == 0)
+                    || (MIN_FPRS_PER_FMT == 1
+                        && size <= UNITS_PER_FPREG))
                    && (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT
                          || class == MODE_VECTOR_FLOAT)
                         && size <= UNITS_PER_FPVALUE)
                        /* Allow integer modes that fit into a single
                           register.  We need to put integers into FPRs
-                          when using instructions like cvt and trunc.  */
-                       || (class == MODE_INT && size <= UNITS_PER_FPREG)
+                          when using instructions like cvt and trunc.
+                          We can't allow sizes smaller than a word,
+                          the FPU has no appropriate load/store
+                          instructions for those.  */
+                       || (class == MODE_INT
+                           && size >= MIN_UNITS_PER_WORD
+                           && size <= UNITS_PER_FPREG)
                        /* Allow TFmode for CCmode reloads.  */
-                       || (ISA_HAS_8CC && mode == TFmode));
+                       || (ISA_HAS_8CC && mode == TFmode)));
 
-         else if (MD_REG_P (regno))
+          else if (ACC_REG_P (regno))
            temp = (INTEGRAL_MODE_P (mode)
                    && (size <= UNITS_PER_WORD
-                       || (regno == MD_REG_FIRST
+                       || (ACC_HI_REG_P (regno)
                            && size == 2 * UNITS_PER_WORD)));
 
          else if (ALL_COP_REG_P (regno))
@@ -4667,26 +5224,26 @@ override_options (void)
         then lowered by mips_rewrite_small_data.  */
       mips_lo_relocs[SYMBOL_SMALL_DATA] = "%gp_rel(";
 
-      mips_split_p[SYMBOL_GOT_LOCAL] = true;
+      mips_split_p[SYMBOL_GOT_PAGE_OFST] = true;
       if (TARGET_NEWABI)
        {
          mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got_page(";
-         mips_lo_relocs[SYMBOL_GOT_LOCAL] = "%got_ofst(";
+         mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%got_ofst(";
        }
       else
        {
          mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got(";
-         mips_lo_relocs[SYMBOL_GOT_LOCAL] = "%lo(";
+         mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%lo(";
        }
 
       if (TARGET_XGOT)
        {
          /* The HIGH and LO_SUM are matched by special .md patterns.  */
-         mips_split_p[SYMBOL_GOT_GLOBAL] = true;
+         mips_split_p[SYMBOL_GOT_DISP] = true;
 
-         mips_split_p[SYMBOL_GOTOFF_GLOBAL] = true;
-         mips_hi_relocs[SYMBOL_GOTOFF_GLOBAL] = "%got_hi(";
-         mips_lo_relocs[SYMBOL_GOTOFF_GLOBAL] = "%got_lo(";
+         mips_split_p[SYMBOL_GOTOFF_DISP] = true;
+         mips_hi_relocs[SYMBOL_GOTOFF_DISP] = "%got_hi(";
+         mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_lo(";
 
          mips_split_p[SYMBOL_GOTOFF_CALL] = true;
          mips_hi_relocs[SYMBOL_GOTOFF_CALL] = "%call_hi(";
@@ -4695,9 +5252,9 @@ override_options (void)
       else
        {
          if (TARGET_NEWABI)
-           mips_lo_relocs[SYMBOL_GOTOFF_GLOBAL] = "%got_disp(";
+           mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_disp(";
          else
-           mips_lo_relocs[SYMBOL_GOTOFF_GLOBAL] = "%got(";
+           mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got(";
          mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call16(";
        }
     }
@@ -4720,6 +5277,8 @@ override_options (void)
   mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
   mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
 
+  mips_lo_relocs[SYMBOL_HALF] = "%half(";
+
   /* We don't have a thread pointer access instruction on MIPS16, or
      appropriate TLS relocations.  */
   if (TARGET_MIPS16)
@@ -4743,6 +5302,13 @@ override_options (void)
 void
 mips_conditional_register_usage (void)
 {
+  if (!TARGET_DSP)
+    {
+      int regno;
+
+      for (regno = DSP_ACC_REG_FIRST; regno <= DSP_ACC_REG_LAST; regno++)
+       fixed_regs[regno] = call_used_regs[regno] = 1;
+    }
   if (!TARGET_HARD_FLOAT)
     {
       int regno;
@@ -4887,6 +5453,7 @@ mips_debugger_offset (rtx addr, HOST_WIDE_INT offset)
    'Y'  for a CONST_INT X, print mips_fp_conditions[X]
    'Z'  print the operand and a comma for ISA_HAS_8CC, otherwise print nothing
    'R'  print the reloc associated with LO_SUM
+   'q'  print DSP accumulator registers
 
    The punctuation characters are:
 
@@ -5137,6 +5704,22 @@ print_operand (FILE *file, rtx op, int letter)
        }
     }
 
+  else if (letter == 'q')
+    {
+      int regnum;
+
+      if (code != REG)
+       fatal_insn ("PRINT_OPERAND, invalid insn for %%q", op);
+
+      regnum = REGNO (op);
+      if (MD_REG_P (regnum))
+       fprintf (file, "$ac0");
+      else if (DSP_ACC_REG_P (regnum))
+       fprintf (file, "$ac%c", reg_names[regnum][3]);
+      else
+       fatal_insn ("PRINT_OPERAND, invalid insn for %%q", op);
+    }
+
   else if (code == REG || code == SUBREG)
     {
       register int regnum;
@@ -5199,16 +5782,15 @@ print_operand_reloc (FILE *file, rtx op, const char **relocs)
 {
   enum mips_symbol_type symbol_type;
   const char *p;
-  rtx base;
-  HOST_WIDE_INT offset;
+  rtx base, offset;
 
   if (!mips_symbolic_constant_p (op, &symbol_type) || relocs[symbol_type] == 0)
     fatal_insn ("PRINT_OPERAND, invalid operand for relocation", op);
 
   /* If OP uses an UNSPEC address, we want to print the inner symbol.  */
-  mips_split_const (op, &base, &offset);
+  split_const (op, &base, &offset);
   if (UNSPEC_ADDRESS_P (base))
-    op = plus_constant (UNSPEC_ADDRESS (base), offset);
+    op = plus_constant (UNSPEC_ADDRESS (base), INTVAL (offset));
 
   fputs (relocs[symbol_type], file);
   output_addr_const (file, op);
@@ -5257,48 +5839,38 @@ print_operand_address (FILE *file, rtx x)
    the -G limit but declared by the user to be in a section other
    than .sbss or .sdata.  */
 
-int
-mips_output_external (FILE *file ATTRIBUTE_UNUSED, tree decl, const char *name)
-{
-  register struct extern_list *p;
-
-  if (!TARGET_EXPLICIT_RELOCS && mips_in_small_data_p (decl))
-    {
-      p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
-      p->next = extern_head;
-      p->name = name;
-      p->size = int_size_in_bytes (TREE_TYPE (decl));
-      extern_head = p;
-    }
-
-  if (TARGET_IRIX && mips_abi == ABI_32 && TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
-      p->next = extern_head;
-      p->name = name;
-      p->size = -1;
-      extern_head = p;
-    }
-
-  return 0;
-}
-
-#if TARGET_IRIX
-static void
-irix_output_external_libcall (rtx fun)
+void
+mips_output_external (FILE *file, tree decl, const char *name)
 {
-  register struct extern_list *p;
+  default_elf_asm_output_external (file, decl, name);
 
-  if (mips_abi == ABI_32)
+  /* We output the name if and only if TREE_SYMBOL_REFERENCED is
+     set in order to avoid putting out names that are never really
+     used. */
+  if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
     {
-      p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
-      p->next = extern_head;
-      p->name = XSTR (fun, 0);
-      p->size = -1;
-      extern_head = p;
+      if (!TARGET_EXPLICIT_RELOCS && mips_in_small_data_p (decl))
+       {
+         fputs ("\t.extern\t", file);
+         assemble_name (file, name);
+         fprintf (file, ", " HOST_WIDE_INT_PRINT_DEC "\n",
+                  int_size_in_bytes (TREE_TYPE (decl)));
+       }
+      else if (TARGET_IRIX
+              && mips_abi == ABI_32
+              && TREE_CODE (decl) == FUNCTION_DECL)
+       {
+         /* In IRIX 5 or IRIX 6 for the O32 ABI, we must output a
+            `.global name .text' directive for every used but
+            undefined function.  If we don't, the linker may perform
+            an optimization (skipping over the insns that set $gp)
+            when it is unsafe.  */
+         fputs ("\t.globl ", file);
+         assemble_name (file, name);
+         fputs (" .text\n", file);
+       }
     }
 }
-#endif
 \f
 /* Emit a new filename to a stream.  If we are smuggling stabs, try to
    put out a MIPS ECOFF file and a stab.  */
@@ -5408,7 +5980,7 @@ mips_file_start (void)
        default:
          gcc_unreachable ();
        }
-      /* Note - we use fprintf directly rather than called named_section()
+      /* Note - we use fprintf directly rather than calling switch_to_section
         because in this way we can avoid creating an allocated section.  We
         do not want this section to take up any space in the running
         executable.  */
@@ -5416,8 +5988,9 @@ mips_file_start (void)
 
       /* There is no ELF header flag to distinguish long32 forms of the
         EABI from long64 forms.  Emit a special section to help tools
-        such as GDB.  */
-      if (mips_abi == ABI_EABI)
+        such as GDB.  Do the same for o64, which is sometimes used with
+        -mlong64.  */
+      if (mips_abi == ABI_EABI || mips_abi == ABI_O64)
        fprintf (asm_out_file, "\t.section .gcc_compiled_long%d\n",
                 TARGET_LONG64 ? 64 : 32);
 
@@ -5427,7 +6000,6 @@ mips_file_start (void)
 
   /* Generate the pseudo ops that System V.4 wants.  */
   if (TARGET_ABICALLS)
-    /* ??? but do not want this (or want pic0) if -non-shared? */
     fprintf (asm_out_file, "\t.abicalls\n");
 
   if (TARGET_MIPS16)
@@ -5450,9 +6022,9 @@ mips_output_aligned_bss (FILE *stream, tree decl, const char *name,
   extern tree last_assemble_variable_decl;
 
   if (mips_in_small_data_p (decl))
-    named_section (0, ".sbss", 0);
+    switch_to_section (get_named_section (NULL, ".sbss", 0));
   else
-    bss_section ();
+    switch_to_section (bss_section);
   ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT));
   last_assemble_variable_decl = decl;
   ASM_DECLARE_OBJECT_NAME (stream, name, decl);
@@ -5460,50 +6032,6 @@ mips_output_aligned_bss (FILE *stream, tree decl, const char *name,
 }
 #endif
 \f
-/* Implement TARGET_ASM_FILE_END.  When using assembler macros, emit
-   .externs for any small-data variables that turned out to be external.  */
-
-static void
-mips_file_end (void)
-{
-  tree name_tree;
-  struct extern_list *p;
-
-  if (extern_head)
-    {
-      fputs ("\n", asm_out_file);
-
-      for (p = extern_head; p != 0; p = p->next)
-       {
-         name_tree = get_identifier (p->name);
-
-         /* Positively ensure only one .extern for any given symbol.  */
-         if (!TREE_ASM_WRITTEN (name_tree)
-             && TREE_SYMBOL_REFERENCED (name_tree))
-           {
-             TREE_ASM_WRITTEN (name_tree) = 1;
-             /* In IRIX 5 or IRIX 6 for the O32 ABI, we must output a
-                `.global name .text' directive for every used but
-                undefined function.  If we don't, the linker may perform
-                an optimization (skipping over the insns that set $gp)
-                when it is unsafe.  */
-             if (TARGET_IRIX && mips_abi == ABI_32 && p->size == -1)
-               {
-                 fputs ("\t.globl ", asm_out_file);
-                 assemble_name (asm_out_file, p->name);
-                 fputs (" .text\n", asm_out_file);
-               }
-             else
-               {
-                 fputs ("\t.extern\t", asm_out_file);
-                 assemble_name (asm_out_file, p->name);
-                 fprintf (asm_out_file, ", %d\n", p->size);
-               }
-           }
-       }
-    }
-}
-
 /* Implement ASM_OUTPUT_ALIGNED_DECL_COMMON.  This is usually the same as the
    elfos.h version, but we also need to handle -muninit-const-in-rodata.  */
 
@@ -5521,7 +6049,7 @@ mips_output_aligned_decl_common (FILE *stream, tree decl, const char *name,
       if (TREE_PUBLIC (decl) && DECL_NAME (decl))
        targetm.asm_out.globalize_label (stream, name);
 
-      readonly_data_section ();
+      switch_to_section (readonly_data_section);
       ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT));
       mips_declare_object (stream, name, "",
                           ":\n\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED "\n",
@@ -5606,7 +6134,7 @@ mips_declare_object_name (FILE *stream, const char *name,
       ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
     }
 
-  mips_declare_object (stream, name, "", ":\n", 0);
+  mips_declare_object (stream, name, "", ":\n");
 }
 
 /* Implement ASM_FINISH_DECLARE_OBJECT.  This is generic ELF stuff.  */
@@ -5727,8 +6255,8 @@ mips_global_pointer (void)
 {
   unsigned int regno;
 
-  /* $gp is always available in non-abicalls code.  */
-  if (!TARGET_ABICALLS)
+  /* $gp is always available unless we're using a GOT.  */
+  if (!TARGET_USE_GOT)
     return GLOBAL_POINTER_REGNUM;
 
   /* We must always provide $gp when it is used implicitly.  */
@@ -5765,7 +6293,7 @@ mips_global_pointer (void)
 
   /* We need a global pointer, but perhaps we can use a call-clobbered
      register instead of $gp.  */
-  if (TARGET_NEWABI && current_function_is_leaf)
+  if (TARGET_CALL_SAVED_GP && current_function_is_leaf)
     for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
       if (!regs_ever_live[regno]
          && call_used_regs[regno]
@@ -5782,15 +6310,24 @@ mips_global_pointer (void)
 static bool
 mips_save_reg_p (unsigned int regno)
 {
-  /* We only need to save $gp for NewABI PIC.  */
+  /* We only need to save $gp if TARGET_CALL_SAVED_GP and only then
+     if we have not chosen a call-clobbered substitute.  */
   if (regno == GLOBAL_POINTER_REGNUM)
-    return (TARGET_ABICALLS && TARGET_NEWABI
-           && cfun->machine->global_pointer == regno);
+    return TARGET_CALL_SAVED_GP && cfun->machine->global_pointer == regno;
 
   /* Check call-saved registers.  */
   if (regs_ever_live[regno] && !call_used_regs[regno])
     return true;
 
+ /* Save both registers in an FPR pair if either one is used.  This is
+    needed for the case when MIN_FPRS_PER_FMT == 1, which allows the odd
+    register to be used without the even register.  */
+ if (FP_REG_P (regno)
+     && MAX_FPRS_PER_FMT == 2 
+     && regs_ever_live[regno + 1]
+     && !call_used_regs[regno + 1])
+   return true;
+
   /* We need to save the old frame pointer before setting up a new one.  */
   if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
     return true;
@@ -5830,7 +6367,7 @@ mips_save_reg_p (unsigned int regno)
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.  SIZE is the size (in bytes) of the local variables.
 
-   Mips stack frames look like:
+   MIPS stack frames look like:
 
              Before call                       After call
         +-----------------------+      +-----------------------+
@@ -5943,25 +6480,24 @@ compute_frame_size (HOST_WIDE_INT size)
     }
 
   /* This loop must iterate over the same space as its companion in
-     save_restore_insns.  */
-  for (regno = (FP_REG_LAST - FP_INC + 1);
+     mips_for_each_saved_reg.  */
+  for (regno = (FP_REG_LAST - MAX_FPRS_PER_FMT + 1);
        regno >= FP_REG_FIRST;
-       regno -= FP_INC)
+       regno -= MAX_FPRS_PER_FMT)
     {
       if (mips_save_reg_p (regno))
        {
-         fp_reg_size += FP_INC * UNITS_PER_FPREG;
-         fmask |= ((1 << FP_INC) - 1) << (regno - FP_REG_FIRST);
+         fp_reg_size += MAX_FPRS_PER_FMT * UNITS_PER_FPREG;
+         fmask |= ((1 << MAX_FPRS_PER_FMT) - 1) << (regno - FP_REG_FIRST);
        }
     }
 
   gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
   total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size);
 
-  /* Add in space reserved on the stack by the callee for storing arguments
-     passed in registers.  */
-  if (!TARGET_OLDABI)
-    total_size += MIPS_STACK_ALIGN (current_function_pretend_args_size);
+  /* Add in the space required for saving incoming register arguments.  */
+  total_size += current_function_pretend_args_size;
+  total_size += MIPS_STACK_ALIGN (cfun->machine->varargs_size);
 
   /* Save other computed information.  */
   cfun->machine->frame.total_size = total_size;
@@ -5974,7 +6510,8 @@ compute_frame_size (HOST_WIDE_INT size)
   cfun->machine->frame.fmask = fmask;
   cfun->machine->frame.initialized = reload_completed;
   cfun->machine->frame.num_gp = gp_reg_size / UNITS_PER_WORD;
-  cfun->machine->frame.num_fp = fp_reg_size / (FP_INC * UNITS_PER_FPREG);
+  cfun->machine->frame.num_fp = (fp_reg_size
+                                / (MAX_FPRS_PER_FMT * UNITS_PER_FPREG));
 
   if (mask)
     {
@@ -5997,7 +6534,7 @@ compute_frame_size (HOST_WIDE_INT size)
 
       offset = (args_size + cprestore_size + var_size
                + gp_reg_rounded + fp_reg_size
-               - FP_INC * UNITS_PER_FPREG);
+               - MAX_FPRS_PER_FMT * UNITS_PER_FPREG);
       cfun->machine->frame.fp_sp_offset = offset;
       cfun->machine->frame.fp_save_offset = offset - total_size;
     }
@@ -6030,9 +6567,8 @@ mips_initial_elimination_offset (int from, int to)
       break;
 
     case ARG_POINTER_REGNUM:
-      offset = cfun->machine->frame.total_size;
-      if (TARGET_NEWABI)
-       offset -= current_function_pretend_args_size;
+      offset = (cfun->machine->frame.total_size
+               - current_function_pretend_args_size);
       break;
 
     default:
@@ -6066,7 +6602,7 @@ mips_save_restore_reg (enum machine_mode mode, int regno,
 {
   rtx mem;
 
-  mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset));
+  mem = gen_frame_mem (mode, plus_constant (stack_pointer_rtx, offset));
 
   fn (gen_rtx_REG (mode, regno), mem);
 }
@@ -6087,7 +6623,7 @@ mips_for_each_saved_reg (HOST_WIDE_INT sp_offset, mips_save_restore_fn fn)
 
   /* Save registers starting from high to low.  The debuggers prefer at least
      the return register be stored at func+4, and also it allows us not to
-     need a nop in the epilog if at least one register is reloaded in
+     need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
@@ -6101,9 +6637,9 @@ mips_for_each_saved_reg (HOST_WIDE_INT sp_offset, mips_save_restore_fn fn)
      compute_frame_size.  */
   offset = cfun->machine->frame.fp_sp_offset - sp_offset;
   fpr_mode = (TARGET_SINGLE_FLOAT ? SFmode : DFmode);
-  for (regno = (FP_REG_LAST - FP_INC + 1);
+  for (regno = (FP_REG_LAST - MAX_FPRS_PER_FMT + 1);
        regno >= FP_REG_FIRST;
-       regno -= FP_INC)
+       regno -= MAX_FPRS_PER_FMT)
     if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
       {
        mips_save_restore_reg (fpr_mode, regno, offset, fn);
@@ -6125,22 +6661,66 @@ mips_output_cplocal (void)
     output_asm_insn (".cplocal %+", 0);
 }
 
+/* Return the style of GP load sequence that is being used for the
+   current function.  */
+
+enum mips_loadgp_style
+mips_current_loadgp_style (void)
+{
+  if (!TARGET_USE_GOT || cfun->machine->global_pointer == 0)
+    return LOADGP_NONE;
+
+  if (TARGET_RTP_PIC)
+    return LOADGP_RTP;
+
+  if (TARGET_ABSOLUTE_ABICALLS)
+    return LOADGP_ABSOLUTE;
+
+  return TARGET_NEWABI ? LOADGP_NEWABI : LOADGP_OLDABI;
+}
+
+/* The __gnu_local_gp symbol.  */
+
+static GTY(()) rtx mips_gnu_local_gp;
+
 /* If we're generating n32 or n64 abicalls, emit instructions
    to set up the global pointer.  */
 
 static void
 mips_emit_loadgp (void)
 {
-  if (TARGET_ABICALLS && TARGET_NEWABI && cfun->machine->global_pointer > 0)
+  rtx addr, offset, incoming_address, base, index;
+
+  switch (mips_current_loadgp_style ())
     {
-      rtx addr, offset, incoming_address;
+    case LOADGP_ABSOLUTE:
+      if (mips_gnu_local_gp == NULL)
+       {
+         mips_gnu_local_gp = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
+         SYMBOL_REF_FLAGS (mips_gnu_local_gp) |= SYMBOL_FLAG_LOCAL;
+       }
+      emit_insn (gen_loadgp_absolute (mips_gnu_local_gp));
+      break;
 
+    case LOADGP_NEWABI:
       addr = XEXP (DECL_RTL (current_function_decl), 0);
       offset = mips_unspec_address (addr, SYMBOL_GOTOFF_LOADGP);
       incoming_address = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
-      emit_insn (gen_loadgp (offset, incoming_address));
+      emit_insn (gen_loadgp_newabi (offset, incoming_address));
+      if (!TARGET_EXPLICIT_RELOCS)
+       emit_insn (gen_loadgp_blockage ());
+      break;
+
+    case LOADGP_RTP:
+      base = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (VXWORKS_GOTT_BASE));
+      index = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (VXWORKS_GOTT_INDEX));
+      emit_insn (gen_loadgp_rtp (base, index));
       if (!TARGET_EXPLICIT_RELOCS)
        emit_insn (gen_loadgp_blockage ());
+      break;
+
+    default:
+      break;
     }
 }
 
@@ -6158,8 +6738,8 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 #endif
 
   /* In mips16 mode, we may need to generate a 32 bit to handle
-     floating point arguments.  The linker will arrange for any 32 bit
-     functions to call this stub, which will then jump to the 16 bit
+     floating point arguments.  The linker will arrange for any 32-bit
+     functions to call this stub, which will then jump to the 16-bit
      function proper.  */
   if (TARGET_MIPS16 && !TARGET_SOFT_FLOAT
       && current_function_args_info.fp_code != 0)
@@ -6220,7 +6800,7 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
         HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs.  */
     }
 
-  if (TARGET_ABICALLS && !TARGET_NEWABI && cfun->machine->global_pointer > 0)
+  if (mips_current_loadgp_style () == LOADGP_OLDABI)
     {
       /* Handle the initialization of $gp for SVR4 PIC.  */
       if (!cfun->machine->all_noreorder_p)
@@ -6384,22 +6964,35 @@ mips_expand_prologue (void)
       if (TARGET_MIPS16 && cfun->machine->frame.args_size != 0)
        {
          rtx offset = GEN_INT (cfun->machine->frame.args_size);
-         RTX_FRAME_RELATED_P
-           (emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      offset))) = 1;
+         if (SMALL_OPERAND (cfun->machine->frame.args_size))
+           RTX_FRAME_RELATED_P
+             (emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
+                                        stack_pointer_rtx,
+                                        offset))) = 1;
+         else
+           {
+             emit_move_insn (MIPS_PROLOGUE_TEMP (Pmode), offset);
+             emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+             emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
+                                       hard_frame_pointer_rtx,
+                                       MIPS_PROLOGUE_TEMP (Pmode)));
+             mips_set_frame_expr
+               (gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
+                             plus_constant (stack_pointer_rtx,
+                                            cfun->machine->frame.args_size)));
+           }
        }
       else
        RTX_FRAME_RELATED_P (emit_move_insn (hard_frame_pointer_rtx,
                                             stack_pointer_rtx)) = 1;
     }
 
+  mips_emit_loadgp ();
+
   /* If generating o32/o64 abicalls, save $gp on the stack.  */
-  if (TARGET_ABICALLS && !TARGET_NEWABI && !current_function_is_leaf)
+  if (TARGET_ABICALLS && TARGET_OLDABI && !current_function_is_leaf)
     emit_insn (gen_cprestore (GEN_INT (current_function_outgoing_args_size)));
 
-  mips_emit_loadgp ();
-
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  */
 
@@ -6531,10 +7124,10 @@ mips_expand_epilogue (int sibcall_p)
   if (target != stack_pointer_rtx)
     emit_move_insn (stack_pointer_rtx, target);
 
-  /* If we're using addressing macros for n32/n64 abicalls, $gp is
-     implicitly used by all SYMBOL_REFs.  We must emit a blockage
-     insn before restoring it.  */
-  if (TARGET_ABICALLS && TARGET_NEWABI && !TARGET_EXPLICIT_RELOCS)
+  /* If we're using addressing macros, $gp is implicitly used by all
+     SYMBOL_REFs.  We must emit a blockage insn before restoring $gp
+     from the stack.  */
+  if (TARGET_CALL_SAVED_GP && !TARGET_EXPLICIT_RELOCS)
     emit_insn (gen_blockage ());
 
   /* Restore the registers.  */
@@ -6623,14 +7216,13 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   /* Pretend to be a post-reload pass while generating rtl.  */
   no_new_pseudos = 1;
   reload_completed = 1;
-  reset_block_changes ();
 
-  /* Pick a global pointer for -mabicalls.  Use $15 rather than $28
-     for TARGET_NEWABI since the latter is a call-saved register.  */
-  if (TARGET_ABICALLS)
+  /* Pick a global pointer.  Use a call-clobbered register if
+     TARGET_CALL_SAVED_GP, so that we can use a sibcall.  */
+  if (TARGET_USE_GOT)
     cfun->machine->global_pointer
       = REGNO (pic_offset_table_rtx)
-      = TARGET_NEWABI ? 15 : GLOBAL_POINTER_REGNUM;
+      = TARGET_CALL_SAVED_GP ? 15 : GLOBAL_POINTER_REGNUM;
 
   /* Set up the global pointer for n32 or n64 abicalls.  */
   mips_emit_loadgp ();
@@ -6676,24 +7268,27 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   /* Jump to the target function.  Use a sibcall if direct jumps are
      allowed, otherwise load the address into a register first.  */
   fnaddr = XEXP (DECL_RTL (function), 0);
-  if (TARGET_MIPS16 || TARGET_ABICALLS || TARGET_LONG_CALLS)
+  if (TARGET_MIPS16 || TARGET_USE_GOT || TARGET_LONG_CALLS)
     {
       /* This is messy.  gas treats "la $25,foo" as part of a call
         sequence and may allow a global "foo" to be lazily bound.
         The general move patterns therefore reject this combination.
 
-        In this context, lazy binding would actually be OK for o32 and o64,
-        but it's still wrong for n32 and n64; see mips_load_call_address.
-        We must therefore load the address via a temporary register if
-        mips_dangerous_for_la25_p.
+        In this context, lazy binding would actually be OK
+        for TARGET_CALL_CLOBBERED_GP, but it's still wrong for
+        TARGET_CALL_SAVED_GP; see mips_load_call_address.
+        We must therefore load the address via a temporary
+        register if mips_dangerous_for_la25_p.
 
         If we jump to the temporary register rather than $25, the assembler
         can use the move insn to fill the jump's delay slot.  */
-      if (TARGET_ABICALLS && !mips_dangerous_for_la25_p (fnaddr))
+      if (TARGET_USE_PIC_FN_ADDR_REG
+         && !mips_dangerous_for_la25_p (fnaddr))
        temp1 = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
       mips_load_call_address (temp1, fnaddr, true);
 
-      if (TARGET_ABICALLS && REGNO (temp1) != PIC_FUNCTION_ADDR_REGNUM)
+      if (TARGET_USE_PIC_FN_ADDR_REG
+         && REGNO (temp1) != PIC_FUNCTION_ADDR_REGNUM)
        emit_move_insn (gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM), temp1);
       emit_jump_insn (gen_indirect_jump (temp1));
     }
@@ -6706,7 +7301,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   /* Run just enough of rest_of_compilation.  This sequence was
      "borrowed" from alpha.c.  */
   insn = get_insns ();
-  insn_locators_initialize ();
+  insn_locators_alloc ();
   split_all_insns_noflow ();
   if (TARGET_MIPS16)
     mips16_lay_out_constants ();
@@ -6745,7 +7340,7 @@ symbolic_expression_p (rtx x)
 /* Choose the section to use for the constant rtx expression X that has
    mode MODE.  */
 
-static void
+static section *
 mips_select_rtx_section (enum machine_mode mode, rtx x,
                         unsigned HOST_WIDE_INT align)
 {
@@ -6754,13 +7349,13 @@ mips_select_rtx_section (enum machine_mode mode, rtx x,
       /* 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.  */
-      function_section (current_function_decl);
+      return function_section (current_function_decl);
     }
   else if (TARGET_EMBEDDED_DATA)
     {
       /* For embedded applications, always put constants in read-only data,
         in order to reduce RAM usage.  */
-      mergeable_constant_section (mode, align, 0);
+      return mergeable_constant_section (mode, align, 0);
     }
   else
     {
@@ -6770,11 +7365,11 @@ mips_select_rtx_section (enum machine_mode mode, rtx x,
 
       if (GET_MODE_SIZE (mode) <= (unsigned) mips_section_threshold
          && mips_section_threshold > 0)
-       named_section (0, ".sdata", 0);
+       return get_named_section (NULL, ".sdata", 0);
       else if (flag_pic && symbolic_expression_p (x))
-       named_section (0, ".data.rel.ro", 3);
+       return get_named_section (NULL, ".data.rel.ro", 3);
       else
-       mergeable_constant_section (mode, align, 0);
+       return mergeable_constant_section (mode, align, 0);
     }
 }
 
@@ -6786,36 +7381,36 @@ mips_select_rtx_section (enum machine_mode mode, rtx x,
    cases by selecting a normal data section instead of a read-only one.
    The logic apes that in default_function_rodata_section.  */
 
-static void
+static section *
 mips_function_rodata_section (tree decl)
 {
   if (!TARGET_ABICALLS || TARGET_GPWORD)
-    default_function_rodata_section (decl);
-  else if (decl && DECL_SECTION_NAME (decl))
+    return default_function_rodata_section (decl);
+
+  if (decl && DECL_SECTION_NAME (decl))
     {
       const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
       if (DECL_ONE_ONLY (decl) && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
        {
          char *rname = ASTRDUP (name);
          rname[14] = 'd';
-         named_section_real (rname, SECTION_LINKONCE | SECTION_WRITE, decl);
+         return get_section (rname, SECTION_LINKONCE | SECTION_WRITE, decl);
        }
       else if (flag_function_sections && flag_data_sections
               && strncmp (name, ".text.", 6) == 0)
        {
          char *rname = ASTRDUP (name);
          memcpy (rname + 1, "data", 4);
-         named_section_flags (rname, SECTION_WRITE);
+         return get_section (rname, SECTION_WRITE, decl);
        }
-      else
-       data_section ();
     }
-  else
-    data_section ();
+  return data_section;
 }
 
-/* Implement TARGET_IN_SMALL_DATA_P.  Return true if it would be safe to
-   access DECL using %gp_rel(...)($gp).  */
+/* Implement TARGET_IN_SMALL_DATA_P.  This function controls whether
+   locally-defined objects go in a small data section.  It also controls
+   the setting of the SYMBOL_REF_SMALL_P flag, which in turn helps
+   mips_classify_symbol decide when to use %gp_rel(...)($gp) accesses.  */
 
 static bool
 mips_in_small_data_p (tree decl)
@@ -6825,9 +7420,9 @@ mips_in_small_data_p (tree decl)
   if (TREE_CODE (decl) == STRING_CST || TREE_CODE (decl) == FUNCTION_DECL)
     return false;
 
-  /* We don't yet generate small-data references for -mabicalls.  See related
-     -G handling in override_options.  */
-  if (TARGET_ABICALLS)
+  /* We don't yet generate small-data references for -mabicalls or
+     VxWorks RTP code.  See the related -G handling in override_options.  */
+  if (TARGET_ABICALLS || TARGET_VXWORKS_RTP)
     return false;
 
   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
@@ -6860,6 +7455,25 @@ mips_in_small_data_p (tree decl)
   size = int_size_in_bytes (TREE_TYPE (decl));
   return (size > 0 && size <= mips_section_threshold);
 }
+
+/* Implement TARGET_USE_ANCHORS_FOR_SYMBOL_P.  We don't want to use
+   anchors for small data: the GP register acts as an anchor in that
+   case.  We also don't want to use them for PC-relative accesses,
+   where the PC acts as an anchor.  */
+
+static bool
+mips_use_anchors_for_symbol_p (rtx symbol)
+{
+  switch (mips_classify_symbol (symbol))
+    {
+    case SYMBOL_CONSTANT_POOL:
+    case SYMBOL_SMALL_DATA:
+      return false;
+
+    default:
+      return true;
+    }
+}
 \f
 /* See whether VALTYPE is a record whose fields should be returned in
    floating-point registers.  If so, return the number of fields and
@@ -6937,7 +7551,7 @@ mips_return_fpr_pair (enum machine_mode mode,
 {
   int inc;
 
-  inc = (TARGET_NEWABI ? 2 : FP_INC);
+  inc = (TARGET_NEWABI ? 2 : MAX_FPRS_PER_FMT);
   return gen_rtx_PARALLEL
     (mode,
      gen_rtvec (2,
@@ -7038,10 +7652,10 @@ mips_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
       int size;
 
       /* ??? How should SCmode be handled?  */
-      if (type == NULL_TREE || mode == DImode || mode == DFmode)
+      if (mode == DImode || mode == DFmode)
        return 0;
 
-      size = int_size_in_bytes (type);
+      size = type ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
       return size == -1 || size > UNITS_PER_WORD;
     }
   else
@@ -7075,7 +7689,7 @@ mips_cannot_change_mode_class (enum machine_mode from,
             registers, the first register always holds the low word.
             We therefore can't allow FPRs to change between single-word
             and multi-word modes.  */
-         if (FP_INC > 1 && reg_classes_intersect_p (FP_REGS, class))
+         if (MAX_FPRS_PER_FMT > 1 && reg_classes_intersect_p (FP_REGS, class))
            return true;
        }
       else
@@ -7083,20 +7697,34 @@ mips_cannot_change_mode_class (enum machine_mode from,
          /* LO_REGNO == HI_REGNO + 1, so if a multi-word value is stored
             in LO and HI, the high word always comes first.  We therefore
             can't allow values stored in HI to change between single-word
-            and multi-word modes.  */
-         if (reg_classes_intersect_p (HI_REG, class))
+            and multi-word modes.
+            This rule applies to both the original HI/LO pair and the new
+            DSP accumulators.  */
+         if (reg_classes_intersect_p (ACC_REGS, class))
            return true;
        }
     }
+
+  /* gcc assumes that each word of a multiword register can be accessed
+     individually using SUBREGs.  This is not true for floating-point
+     registers if they are bigger than a word.  */
+  if (UNITS_PER_FPREG > UNITS_PER_WORD
+      && GET_MODE_SIZE (from) > UNITS_PER_WORD
+      && GET_MODE_SIZE (to) < UNITS_PER_FPREG
+      && reg_classes_intersect_p (FP_REGS, class))
+    return true;
+
   /* Loading a 32-bit value into a 64-bit floating-point register
      will not sign-extend the value, despite what LOAD_EXTEND_OP says.
      We can't allow 64-bit float registers to change from SImode to
      to a wider mode.  */
-  if (TARGET_FLOAT64
+  if (TARGET_64BIT
+      && TARGET_FLOAT64
       && from == SImode
       && GET_MODE_SIZE (to) >= UNITS_PER_WORD
       && reg_classes_intersect_p (FP_REGS, class))
     return true;
+
   return false;
 }
 
@@ -7107,13 +7735,10 @@ mips_cannot_change_mode_class (enum machine_mode from,
 bool
 mips_dangerous_for_la25_p (rtx x)
 {
-  HOST_WIDE_INT offset;
-
-  if (TARGET_EXPLICIT_RELOCS)
-    return false;
-
-  mips_split_const (x, &x, &offset);
-  return global_got_operand (x, VOIDmode);
+  return (!TARGET_EXPLICIT_RELOCS
+         && TARGET_USE_GOT
+         && GET_CODE (x) == SYMBOL_REF
+         && mips_global_symbol_p (x));
 }
 
 /* Implement PREFERRED_RELOAD_CLASS.  */
@@ -7165,8 +7790,10 @@ mips_secondary_reload_class (enum reg_class class,
     }
 
   /* Copying from HI or LO to anywhere other than a general register
-     requires a general register.  */
-  if (class == HI_REG || class == LO_REG || class == MD_REGS)
+     requires a general register.
+     This rule applies to both the original HI/LO pair and the new
+     DSP accumulators.  */
+  if (reg_class_subset_p (class, ACC_REGS))
     {
       if (TARGET_MIPS16 && in_p)
        {
@@ -7175,7 +7802,7 @@ mips_secondary_reload_class (enum reg_class class,
        }
       return gp_reg_p ? NO_REGS : gr_regs;
     }
-  if (MD_REG_P (regno))
+  if (ACC_REG_P (regno))
     {
       if (TARGET_MIPS16 && ! in_p)
        {
@@ -7256,14 +7883,17 @@ mips_secondary_reload_class (enum reg_class class,
 
 /* Implement CLASS_MAX_NREGS.
 
-   Usually all registers are word-sized.  The only supported exception
-   is -mgp64 -msingle-float, which has 64-bit words but 32-bit float
-   registers.  A word-based calculation is correct even in that case,
-   since -msingle-float disallows multi-FPR values.
+   - UNITS_PER_FPREG controls the number of registers needed by FP_REGS.
 
-   The FP status registers are an exception to this rule.  They are always
-   4 bytes wide as they only hold condition code modes, and CCmode is always
-   considered to be 4 bytes wide.  */
+   - ST_REGS are always hold CCmode values, and CCmode values are
+     considered to be 4 bytes wide.
+
+   All other register classes are covered by UNITS_PER_WORD.  Note that
+   this is true even for unions of integer and float registers when the
+   latter are smaller than the former.  The only supported combination
+   in which case this occurs is -mgp64 -msingle-float, which has 64-bit
+   words but 32-bit float registers.  A word-based calculation is correct
+   in that case since -msingle-float disallows multi-FPR values.  */
 
 int
 mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,
@@ -7271,6 +7901,8 @@ mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,
 {
   if (class == ST_REGS)
     return (GET_MODE_SIZE (mode) + 3) / 4;
+  else if (class == FP_REGS)
+    return (GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG;
   else
     return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 }
@@ -7286,10 +7918,18 @@ mips_valid_pointer_mode (enum machine_mode mode)
 static bool
 mips_vector_mode_supported_p (enum machine_mode mode)
 {
-  if (mode == V2SFmode && TARGET_PAIRED_SINGLE_FLOAT)
-    return true;
-  else
-    return false;
+  switch (mode)
+    {
+    case V2SFmode:
+      return TARGET_PAIRED_SINGLE_FLOAT;
+
+    case V2HImode:
+    case V4QImode:
+      return TARGET_DSP;
+
+    default:
+      return false;
+    }
 }
 \f
 /* If we can access small data directly (using gp-relative relocation
@@ -7304,19 +7944,13 @@ mips16_gp_pseudo_reg (void)
 {
   if (cfun->machine->mips16_gp_pseudo_rtx == NULL_RTX)
     {
-      rtx unspec;
       rtx insn, scan;
 
       cfun->machine->mips16_gp_pseudo_rtx = gen_reg_rtx (Pmode);
 
       /* We want to initialize this to a value which gcc will believe
          is constant.  */
-      start_sequence ();
-      unspec = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx), UNSPEC_GP);
-      emit_move_insn (cfun->machine->mips16_gp_pseudo_rtx,
-                     gen_rtx_CONST (Pmode, unspec));
-      insn = get_insns ();
-      end_sequence ();
+      insn = gen_load_const_gp (cfun->machine->mips16_gp_pseudo_rtx);
 
       push_topmost_sequence ();
       /* We need to emit the initialization after the FUNCTION_BEG
@@ -7347,7 +7981,7 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
   int gparg, fparg;
   unsigned int f;
 
-  /* This code only works for the original 32 bit ABI and the O64 ABI.  */
+  /* This code only works for the original 32-bit ABI and the O64 ABI.  */
   gcc_assert (TARGET_OLDABI);
 
   if (from_fp_p)
@@ -7395,9 +8029,9 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
 }
 
 /* Build a mips16 function stub.  This is used for functions which
-   take arguments in the floating point registers.  It is 32 bit code
+   take arguments in the floating point registers.  It is 32-bit code
    that moves the floating point args into the general registers, and
-   then jumps to the 16 bit code.  */
+   then jumps to the 16-bit code.  */
 
 static void
 build_mips16_function_stub (FILE *file)
@@ -7430,7 +8064,7 @@ build_mips16_function_stub (FILE *file)
   fprintf (file, ")\n");
 
   fprintf (file, "\t.set\tnomips16\n");
-  function_section (stubdecl);
+  switch_to_section (function_section (stubdecl));
   ASM_OUTPUT_ALIGN (file, floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT));
 
   /* ??? If FUNCTION_NAME_ALREADY_DECLARED is defined, then we are
@@ -7475,7 +8109,7 @@ build_mips16_function_stub (FILE *file)
 
   fprintf (file, "\t.set\tmips16\n");
 
-  function_section (current_function_decl);
+  switch_to_section (function_section (current_function_decl));
 }
 
 /* We keep a list of functions for which we have already built stubs
@@ -7492,11 +8126,11 @@ static struct mips16_stub *mips16_stubs;
 
 /* Build a call stub for a mips16 call.  A stub is needed if we are
    passing any floating point values which should go into the floating
-   point registers.  If we are, and the call turns out to be to a 32
-   bit function, the stub will be used to move the values into the
-   floating point registers before calling the 32 bit function.  The
-   linker will magically adjust the function call to either the 16 bit
-   function or the 32 bit stub, depending upon where the function call
+   point registers.  If we are, and the call turns out to be to a
+   32-bit function, the stub will be used to move the values into the
+   floating point registers before calling the 32-bit function.  The
+   linker will magically adjust the function call to either the 16-bit
+   function or the 32-bit stub, depending upon where the function call
    is actually defined.
 
    Similarly, we need a stub if the return value might come back in a
@@ -7616,7 +8250,7 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
     {
       /* Build a special purpose stub.  When the linker sees a
         function call in mips16 code, it will check where the target
-        is defined.  If the target is a 32 bit call, the linker will
+        is defined.  If the target is a 32-bit call, the linker will
         search for the section defined here.  It can tell which
         symbol this section is associated with by looking at the
         relocation information (the name is unreliable, since this
@@ -7675,7 +8309,7 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
        }
 
       /* We build the stub code by hand.  That's the only way we can
-        do it, since we can't generate 32 bit code during a 16 bit
+        do it, since we can't generate 32-bit code during a 16-bit
         compilation.  */
 
       /* We don't want the assembler to insert any nops here.  */
@@ -8534,7 +9168,7 @@ mips_reorg (void)
   else if (TARGET_EXPLICIT_RELOCS)
     {
       if (mips_flag_delayed_branch)
-       dbr_schedule (get_insns (), dump_file);
+       dbr_schedule (get_insns ());
       mips_avoid_hazards ();
       if (TUNE_MIPS4130 && TARGET_VR4130_ALIGN)
        vr4130_align_insns ();
@@ -8654,7 +9288,7 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
        }
       else if (to == FP_REGS)
        return 4;
-      else if (to == HI_REG || to == LO_REG || to == MD_REGS)
+      else if (reg_class_subset_p (to, ACC_REGS))
        {
          if (TARGET_MIPS16)
            return 12;
@@ -8665,7 +9299,7 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
        {
          return 5;
        }
-    }  /* GR_REG_CLASS_P (from) */
+    }
   else if (from == FP_REGS)
     {
       if (GR_REG_CLASS_P (to))
@@ -8674,8 +9308,8 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
        return 2;
       else if (to == ST_REGS)
        return 8;
-    }  /* from == FP_REGS */
-  else if (from == HI_REG || from == LO_REG || from == MD_REGS)
+    }
+  else if (reg_class_subset_p (from, ACC_REGS))
     {
       if (GR_REG_CLASS_P (to))
        {
@@ -8684,15 +9318,16 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
          else
            return 6;
        }
-    }  /* from == HI_REG, etc.  */
+    }
   else if (from == ST_REGS && GR_REG_CLASS_P (to))
     return 4;
   else if (COP_REG_CLASS_P (from))
     {
       return 5;
-    }  /* COP_REG_CLASS_P (from) */
+    }
 
-  /* Fall through.  */
+  /* Fall through.
+     ??? What cases are these? Shouldn't we return 2 here?  */
 
   return 12;
 }
@@ -8762,217 +9397,126 @@ mips_output_load_label (void)
     }
 }
 
+/* Return the assembly code for INSN, which has the operands given by
+   OPERANDS, and which branches to OPERANDS[1] if some condition is true.
+   BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[1]
+   is in range of a direct branch.  BRANCH_IF_FALSE is an inverted
+   version of BRANCH_IF_TRUE.  */
 
-/* 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
-   nonzero the comparison takes two operands; OPERANDS[3] will be the
-   second operand.
-
-   If INVERTED_P is nonzero we are to branch if the condition does
-   not hold.  If FLOAT_P is nonzero 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.  */
 const char *
-mips_output_conditional_branch (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]);
-  /* Nonzero if the opcode for the comparison needs a `z' indicating
-     that it is a comparison 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 *const comp = (float_p ? "%F0" : "%C0");
-  /* The operand-printing string for the inverted comparison.  */
-  const char *const inverted_comp = (float_p ? "%W0" : "%N0");
-
-  /* The MIPS processors (for levels of the ISA at least two), have
-     "likely" variants of each branch instruction.  These instructions
-     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 nonzero.  Thus, we change the CODE here to
-        reflect the simpler comparison operation.  */
-      switch (code)
-       {
-       case GTU:
-         code = NE;
-         break;
+mips_output_conditional_branch (rtx insn, rtx *operands,
+                               const char *branch_if_true,
+                               const char *branch_if_false)
+{
+  unsigned int length;
+  rtx taken, not_taken;
 
-       case LEU:
-         code = EQ;
-         break;
+  length = get_attr_length (insn);
+  if (length <= 8)
+    {
+      /* Just a simple conditional branch.  */
+      mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
+      return branch_if_true;
+    }
 
-       case GEU:
-         /* A condition which will always be true.  */
-         code = EQ;
-         op1 = "%.";
-         break;
+  /* Generate a reversed branch around a direct jump.  This fallback does
+     not use branch-likely instructions.  */
+  mips_branch_likely = false;
+  not_taken = gen_label_rtx ();
+  taken = operands[1];
 
-       case LTU:
-         /* A condition which will always be false.  */
-         code = NE;
-         op1 = "%.";
-         break;
+  /* Generate the reversed branch to NOT_TAKEN.  */
+  operands[1] = not_taken;
+  output_asm_insn (branch_if_false, operands);
 
-       default:
-         /* Not a special case.  */
-         break;
+  /* If INSN has a delay slot, we must provide delay slots for both the
+     branch to NOT_TAKEN and the conditional jump.  We must also ensure
+     that INSN's delay slot is executed in the appropriate cases.  */
+  if (final_sequence)
+    {
+      /* This first delay slot will always be executed, so use INSN's
+        delay slot if is not annulled.  */
+      if (!INSN_ANNULLED_BRANCH_P (insn))
+       {
+         final_scan_insn (XVECEXP (final_sequence, 0, 1),
+                          asm_out_file, optimize, 1, NULL);
+         INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
        }
+      else
+       output_asm_insn ("nop", 0);
+      fprintf (asm_out_file, "\n");
     }
 
-  /* 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';
+  /* Output the unconditional branch to TAKEN.  */
+  if (length <= 16)
+    output_asm_insn ("j\t%0%/", &taken);
+  else
+    {
+      output_asm_insn (mips_output_load_label (), &taken);
+      output_asm_insn ("jr\t%@%]%/", 0);
+    }
 
-  switch (length)
+  /* Now deal with its delay slot; see above.  */
+  if (final_sequence)
     {
-    case 4:
-    case 8:
-      /* Just a simple conditional branch.  */
-      if (float_p)
-       sprintf (buffer, "%%*b%s%%?\t%%Z2%%1%%/",
-                inverted_p ? inverted_comp : comp);
+      /* This delay slot will only be executed if the branch is taken.
+        Use INSN's delay slot if is annulled.  */
+      if (INSN_ANNULLED_BRANCH_P (insn))
+       {
+         final_scan_insn (XVECEXP (final_sequence, 0, 1),
+                          asm_out_file, optimize, 1, NULL);
+         INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
+       }
       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:
-    case 24:
-    case 28:
-      {
-       /* Generate a reversed conditional branch around ` j'
-          instruction:
-
-               .set noreorder
-               .set nomacro
-               bc    l
-               delay_slot or #nop
-               j     target
-               #nop
-            l:
-               .set macro
-               .set reorder
-
-          If the original branch was a likely branch, the delay slot
-          must be executed only if the branch is taken, so generate:
-
-               .set noreorder
-               .set nomacro
-               bc    l
-               #nop
-               j     target
-               delay slot or #nop
-            l:
-               .set macro
-               .set reorder
-
-          When generating PIC, instead of:
-
-               j     target
-
-          we emit:
-
-               .set noat
-               la    $at, target
-               jr    $at
-               .set at
-       */
-
-        rtx orig_target;
-       rtx target = gen_label_rtx ();
-
-        orig_target = operands[1];
-        operands[1] = target;
-       /* Generate the reversed comparison.  This takes four
-          bytes.  */
-       if (float_p)
-         sprintf (buffer, "%%*b%s\t%%Z2%%1",
-                  inverted_p ? comp : inverted_comp);
-       else
-         sprintf (buffer, "%%*b%s%s\t%s%s,%%1",
-                  inverted_p ? comp : inverted_comp,
-                  need_z_p ? "z" : "",
-                  op1,
-                  op2);
-        output_asm_insn (buffer, operands);
-
-        if (length != 16 && length != 28 && ! mips_branch_likely)
-          {
-            /* Output delay slot instruction.  */
-            rtx insn = final_sequence;
-            final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
-                             optimize, 1, NULL);
-            INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
-          }
-       else
-         output_asm_insn ("%#", 0);
+       output_asm_insn ("nop", 0);
+      fprintf (asm_out_file, "\n");
+    }
 
-       if (length <= 16)
-         output_asm_insn ("j\t%0", &orig_target);
-       else
-         {
-           output_asm_insn (mips_output_load_label (), &orig_target);
-           output_asm_insn ("jr\t%@%]", 0);
-         }
+  /* Output NOT_TAKEN.  */
+  (*targetm.asm_out.internal_label) (asm_out_file, "L",
+                                    CODE_LABEL_NUMBER (not_taken));
+  return "";
+}
 
-        if (length != 16 && length != 28 && mips_branch_likely)
-          {
-            /* Output delay slot instruction.  */
-            rtx insn = final_sequence;
-            final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
-                             optimize, 1, NULL);
-            INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
-          }
-       else
-         output_asm_insn ("%#", 0);
+/* Return the assembly code for INSN, which branches to OPERANDS[1]
+   if some ordered condition is true.  The condition is given by
+   OPERANDS[0] if !INVERTED_P, otherwise it is the inverse of
+   OPERANDS[0].  OPERANDS[2] is the comparison's first operand;
+   its second is always zero.  */
 
-        (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                   CODE_LABEL_NUMBER (target));
+const char *
+mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
+{
+  const char *branch[2];
 
-        return "";
-      }
+  /* Make BRANCH[1] branch to OPERANDS[1] when the condition is true.
+     Make BRANCH[0] branch on the inverse condition.  */
+  switch (GET_CODE (operands[0]))
+    {
+      /* These cases are equivalent to comparisons against zero.  */
+    case LEU:
+      inverted_p = !inverted_p;
+      /* Fall through.  */
+    case GTU:
+      branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%1");
+      branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%1");
+      break;
+
+      /* These cases are always true or always false.  */
+    case LTU:
+      inverted_p = !inverted_p;
+      /* Fall through.  */
+    case GEU:
+      branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%1");
+      branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%1");
+      break;
 
     default:
-      gcc_unreachable ();
+      branch[!inverted_p] = MIPS_BRANCH ("b%C0z", "%2,%1");
+      branch[inverted_p] = MIPS_BRANCH ("b%N0z", "%2,%1");
+      break;
     }
-
-  /* NOTREACHED */
-  return 0;
+  return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
 }
 \f
 /* Used to output div or ddiv instruction DIVISION, which has the operands
@@ -9348,7 +9892,7 @@ vr4130_true_reg_dependence_p (rtx insn)
 static bool
 vr4130_swap_insns_p (rtx insn1, rtx insn2)
 {
-  rtx dep;
+  dep_link_t dep;
 
   /* Check for the following case:
 
@@ -9358,11 +9902,11 @@ vr4130_swap_insns_p (rtx insn1, rtx insn2)
 
      If INSN1 is the last instruction blocking X, it would better to
      choose (INSN1, X) over (INSN2, INSN1).  */
-  for (dep = INSN_DEPEND (insn1); dep != 0; dep = XEXP (dep, 1))
-    if (REG_NOTE_KIND (dep) == REG_DEP_ANTI
-       && INSN_PRIORITY (XEXP (dep, 0)) > INSN_PRIORITY (insn2)
-       && recog_memoized (XEXP (dep, 0)) >= 0
-       && get_attr_vr4130_class (XEXP (dep, 0)) == VR4130_CLASS_ALU)
+  FOR_EACH_DEP_LINK (dep, INSN_FORW_DEPS (insn1))
+    if (DEP_LINK_KIND (dep) == REG_DEP_ANTI
+       && INSN_PRIORITY (DEP_LINK_CON (dep)) > INSN_PRIORITY (insn2)
+       && recog_memoized (DEP_LINK_CON (dep)) >= 0
+       && get_attr_vr4130_class (DEP_LINK_CON (dep)) == VR4130_CLASS_ALU)
       return false;
 
   if (vr4130_last_insn != 0
@@ -9488,6 +10032,9 @@ mips_issue_rate (void)
 {
   switch (mips_tune)
     {
+    case PROCESSOR_74KC:
+    case PROCESSOR_74KF:
+    case PROCESSOR_74KX:
     case PROCESSOR_R4130:
     case PROCESSOR_R5400:
     case PROCESSOR_R5500:
@@ -9496,6 +10043,7 @@ mips_issue_rate (void)
       return 2;
 
     case PROCESSOR_SB1:
+    case PROCESSOR_SB1A:
       /* This is actually 4, but we get better performance if we claim 3.
         This is partly because of unwanted speculative code motion with the
         larger number, and partly because in most common cases we can't
@@ -9514,11 +10062,25 @@ static int
 mips_multipass_dfa_lookahead (void)
 {
   /* Can schedule up to 4 of the 6 function units in any one cycle.  */
-  if (mips_tune == PROCESSOR_SB1)
+  if (TUNE_SB1)
     return 4;
 
   return 0;
 }
+
+/* Implements a store data bypass check.  We need this because the cprestore
+   pattern is type store, but defined using an UNSPEC.  This UNSPEC causes the
+   default routine to abort.  We just return false for that case.  */
+/* ??? Should try to give a better result here than assuming false.  */
+
+int
+mips_store_data_bypass_p (rtx out_insn, rtx in_insn)
+{
+  if (GET_CODE (PATTERN (in_insn)) == UNSPEC_VOLATILE)
+    return false;
+
+  return ! store_data_bypass_p (out_insn, in_insn);
+}
 \f
 /* Given that we have an rtx of the form (prefetch ... WRITE LOCALITY),
    return the first operand of the associated "pref" or "prefx" insn.  */
@@ -9629,9 +10191,6 @@ struct builtin_description
   CMP_4S_BUILTINS (c, COND),                                           \
   CMP_4S_BUILTINS (cabs, COND)
 
-/* __builtin_mips_abs_ps() maps to the standard absM2 pattern.  */
-#define CODE_FOR_mips_abs_ps CODE_FOR_absv2sf2
-
 static const struct builtin_description mips_bdesc[] =
 {
   DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
@@ -9676,6 +10235,174 @@ static const struct builtin_description sb1_bdesc[] =
   DIRECT_BUILTIN (sqrt_ps, MIPS_V2SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT)
 };
 
+/* Builtin functions for DSP ASE.  */
+
+#define CODE_FOR_mips_addq_ph CODE_FOR_addv2hi3
+#define CODE_FOR_mips_addu_qb CODE_FOR_addv4qi3
+#define CODE_FOR_mips_subq_ph CODE_FOR_subv2hi3
+#define CODE_FOR_mips_subu_qb CODE_FOR_subv4qi3
+#define CODE_FOR_mips_mul_ph CODE_FOR_mulv2hi3
+
+/* Define a MIPS_BUILTIN_DIRECT_NO_TARGET function for instruction
+   CODE_FOR_mips_<INSN>.  FUNCTION_TYPE and TARGET_FLAGS are
+   builtin_description fields.  */
+#define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, TARGET_FLAGS)    \
+  { CODE_FOR_mips_ ## INSN, 0, "__builtin_mips_" #INSN,                        \
+    MIPS_BUILTIN_DIRECT_NO_TARGET, FUNCTION_TYPE, TARGET_FLAGS }
+
+/* Define __builtin_mips_bposge<VALUE>.  <VALUE> is 32 for the MIPS32 DSP
+   branch instruction.  TARGET_FLAGS is a builtin_description field.  */
+#define BPOSGE_BUILTIN(VALUE, TARGET_FLAGS)                            \
+  { CODE_FOR_mips_bposge, 0, "__builtin_mips_bposge" #VALUE,           \
+    MIPS_BUILTIN_BPOSGE ## VALUE, MIPS_SI_FTYPE_VOID, TARGET_FLAGS }
+
+static const struct builtin_description dsp_bdesc[] =
+{
+  DIRECT_BUILTIN (addq_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (addq_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (addq_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (addu_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (addu_s_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (subq_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (subq_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (subq_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (subu_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (subu_s_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (addsc, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (addwc, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (modsub, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (raddu_w_qb, MIPS_SI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (absq_s_ph, MIPS_V2HI_FTYPE_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (absq_s_w, MIPS_SI_FTYPE_SI, MASK_DSP),
+  DIRECT_BUILTIN (precrq_qb_ph, MIPS_V4QI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (precrq_ph_w, MIPS_V2HI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (precrq_rs_ph_w, MIPS_V2HI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (precrqu_s_qb_ph, MIPS_V4QI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (preceq_w_phl, MIPS_SI_FTYPE_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (preceq_w_phr, MIPS_SI_FTYPE_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (precequ_ph_qbl, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (precequ_ph_qbr, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (precequ_ph_qbla, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (precequ_ph_qbra, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (preceu_ph_qbl, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (preceu_ph_qbr, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (preceu_ph_qbla, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (preceu_ph_qbra, MIPS_V2HI_FTYPE_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (shll_qb, MIPS_V4QI_FTYPE_V4QI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shll_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shll_s_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shll_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shrl_qb, MIPS_V4QI_FTYPE_V4QI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shra_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shra_r_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shra_r_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (muleu_s_ph_qbl, MIPS_V2HI_FTYPE_V4QI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (muleu_s_ph_qbr, MIPS_V2HI_FTYPE_V4QI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (mulq_rs_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (muleq_s_w_phl, MIPS_SI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (muleq_s_w_phr, MIPS_SI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (bitrev, MIPS_SI_FTYPE_SI, MASK_DSP),
+  DIRECT_BUILTIN (insv, MIPS_SI_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (repl_qb, MIPS_V4QI_FTYPE_SI, MASK_DSP),
+  DIRECT_BUILTIN (repl_ph, MIPS_V2HI_FTYPE_SI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (cmpu_eq_qb, MIPS_VOID_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (cmpu_lt_qb, MIPS_VOID_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (cmpu_le_qb, MIPS_VOID_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (cmpgu_eq_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (cmpgu_lt_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (cmpgu_le_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (cmp_eq_ph, MIPS_VOID_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (cmp_lt_ph, MIPS_VOID_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (cmp_le_ph, MIPS_VOID_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (pick_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (pick_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (packrl_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP),
+  DIRECT_NO_TARGET_BUILTIN (wrdsp, MIPS_VOID_FTYPE_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (rddsp, MIPS_SI_FTYPE_SI, MASK_DSP),
+  DIRECT_BUILTIN (lbux, MIPS_SI_FTYPE_PTR_SI, MASK_DSP),
+  DIRECT_BUILTIN (lhx, MIPS_SI_FTYPE_PTR_SI, MASK_DSP),
+  DIRECT_BUILTIN (lwx, MIPS_SI_FTYPE_PTR_SI, MASK_DSP),
+  BPOSGE_BUILTIN (32, MASK_DSP),
+
+  /* The following are for the MIPS DSP ASE REV 2.  */
+  DIRECT_BUILTIN (absq_s_qb, MIPS_V4QI_FTYPE_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (addu_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (addu_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (adduh_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (adduh_r_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (append, MIPS_SI_FTYPE_SI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (balign, MIPS_SI_FTYPE_SI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (cmpgdu_eq_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (cmpgdu_lt_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (cmpgdu_le_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (mul_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (mul_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (mulq_rs_w, MIPS_SI_FTYPE_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (mulq_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (mulq_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (precr_qb_ph, MIPS_V4QI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (precr_sra_ph_w, MIPS_V2HI_FTYPE_SI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (precr_sra_r_ph_w, MIPS_V2HI_FTYPE_SI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (prepend, MIPS_SI_FTYPE_SI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (shra_qb, MIPS_V4QI_FTYPE_V4QI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (shra_r_qb, MIPS_V4QI_FTYPE_V4QI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (shrl_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (subu_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (subu_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (subuh_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (subuh_r_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSPR2),
+  DIRECT_BUILTIN (addqh_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (addqh_r_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (addqh_w, MIPS_SI_FTYPE_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (addqh_r_w, MIPS_SI_FTYPE_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (subqh_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (subqh_r_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (subqh_w, MIPS_SI_FTYPE_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (subqh_r_w, MIPS_SI_FTYPE_SI_SI, MASK_DSPR2)
+};
+
+static const struct builtin_description dsp_32only_bdesc[] =
+{
+  DIRECT_BUILTIN (dpau_h_qbl, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (dpau_h_qbr, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (dpsu_h_qbl, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (dpsu_h_qbr, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP),
+  DIRECT_BUILTIN (dpaq_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (dpsq_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (mulsaq_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (dpaq_sa_l_w, MIPS_DI_FTYPE_DI_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (dpsq_sa_l_w, MIPS_DI_FTYPE_DI_SI_SI, MASK_DSP),
+  DIRECT_BUILTIN (maq_s_w_phl, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (maq_s_w_phr, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (maq_sa_w_phl, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (maq_sa_w_phr, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP),
+  DIRECT_BUILTIN (extr_w, MIPS_SI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (extr_r_w, MIPS_SI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (extr_rs_w, MIPS_SI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (extr_s_h, MIPS_SI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (extp, MIPS_SI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (extpdp, MIPS_SI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (shilo, MIPS_DI_FTYPE_DI_SI, MASK_DSP),
+  DIRECT_BUILTIN (mthlip, MIPS_DI_FTYPE_DI_SI, MASK_DSP),
+
+  /* The following are for the MIPS DSP ASE REV 2.  */
+  DIRECT_BUILTIN (dpa_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (dps_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (madd, MIPS_DI_FTYPE_DI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (maddu, MIPS_DI_FTYPE_DI_USI_USI, MASK_DSPR2),
+  DIRECT_BUILTIN (msub, MIPS_DI_FTYPE_DI_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (msubu, MIPS_DI_FTYPE_DI_USI_USI, MASK_DSPR2),
+  DIRECT_BUILTIN (mulsa_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (mult, MIPS_DI_FTYPE_SI_SI, MASK_DSPR2),
+  DIRECT_BUILTIN (multu, MIPS_DI_FTYPE_USI_USI, MASK_DSPR2),
+  DIRECT_BUILTIN (dpax_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (dpsx_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (dpaqx_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (dpaqx_sa_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (dpsqx_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2),
+  DIRECT_BUILTIN (dpsqx_sa_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSPR2)
+};
+
 /* This helps provide a mapping from builtin function codes to bdesc
    arrays.  */
 
@@ -9688,33 +10415,46 @@ struct bdesc_map
   unsigned int size;
 
   /* The target processor that supports these builtin functions.
-     PROCESSOR_DEFAULT means we enable them for all processors.  */
+     PROCESSOR_MAX means we enable them for all processors.  */
   enum processor_type proc;
+
+  /* If the target has these flags, this builtin function table
+     will not be supported.  */
+  int unsupported_target_flags;
 };
 
 static const struct bdesc_map bdesc_arrays[] =
 {
-  { mips_bdesc, ARRAY_SIZE (mips_bdesc), PROCESSOR_DEFAULT },
-  { sb1_bdesc, ARRAY_SIZE (sb1_bdesc), PROCESSOR_SB1 }
+  { mips_bdesc, ARRAY_SIZE (mips_bdesc), PROCESSOR_MAX, 0 },
+  { sb1_bdesc, ARRAY_SIZE (sb1_bdesc), PROCESSOR_SB1, 0 },
+  { dsp_bdesc, ARRAY_SIZE (dsp_bdesc), PROCESSOR_MAX, 0 },
+  { dsp_32only_bdesc, ARRAY_SIZE (dsp_32only_bdesc), PROCESSOR_MAX,
+    MASK_64BIT }
 };
 
-/* Take the head of argument list *ARGLIST and convert it into a form
-   suitable for input operand OP of instruction ICODE.  Return the value
-   and point *ARGLIST at the next element of the list.  */
+/* Take the argument ARGNUM of the arglist of EXP and convert it into a form
+   suitable for input operand OP of instruction ICODE.  Return the value.  */
 
 static rtx
 mips_prepare_builtin_arg (enum insn_code icode,
-                         unsigned int op, tree *arglist)
+                         unsigned int op, tree exp, unsigned int argnum)
 {
   rtx value;
   enum machine_mode mode;
 
-  value = expand_expr (TREE_VALUE (*arglist), NULL_RTX, VOIDmode, 0);
+  value = expand_normal (CALL_EXPR_ARG (exp, argnum));
   mode = insn_data[icode].operand[op].mode;
   if (!insn_data[icode].operand[op].predicate (value, mode))
-    value = copy_to_mode_reg (mode, value);
+    {
+      value = copy_to_mode_reg (mode, value);
+      /* Check the predicate again.  */
+      if (!insn_data[icode].operand[op].predicate (value, mode))
+       {
+         error ("invalid argument to builtin function");
+         return const0_rtx;
+       }
+    }
 
-  *arglist = TREE_CHAIN (*arglist);
   return value;
 }
 
@@ -9742,13 +10482,12 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 {
   enum insn_code icode;
   enum mips_builtin_type type;
-  tree fndecl, arglist;
+  tree fndecl;
   unsigned int fcode;
   const struct builtin_description *bdesc;
   const struct bdesc_map *m;
 
-  fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  arglist = TREE_OPERAND (exp, 1);
+  fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   fcode = DECL_FUNCTION_CODE (fndecl);
 
   bdesc = NULL;
@@ -9769,12 +10508,15 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   switch (type)
     {
     case MIPS_BUILTIN_DIRECT:
-      return mips_expand_builtin_direct (icode, target, arglist);
+      return mips_expand_builtin_direct (icode, target, exp, true);
+
+    case MIPS_BUILTIN_DIRECT_NO_TARGET:
+      return mips_expand_builtin_direct (icode, target, exp, false);
 
     case MIPS_BUILTIN_MOVT:
     case MIPS_BUILTIN_MOVF:
       return mips_expand_builtin_movtf (type, icode, bdesc[fcode].cond,
-                                       target, arglist);
+                                       target, exp);
 
     case MIPS_BUILTIN_CMP_ANY:
     case MIPS_BUILTIN_CMP_ALL:
@@ -9782,7 +10524,10 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     case MIPS_BUILTIN_CMP_LOWER:
     case MIPS_BUILTIN_CMP_SINGLE:
       return mips_expand_builtin_compare (type, icode, bdesc[fcode].cond,
-                                         target, arglist);
+                                         target, exp);
+
+    case MIPS_BUILTIN_BPOSGE32:
+      return mips_expand_builtin_bposge (type, target);
 
     default:
       return 0;
@@ -9798,70 +10543,249 @@ mips_init_builtins (void)
   const struct bdesc_map *m;
   tree types[(int) MIPS_MAX_FTYPE_MAX];
   tree V2SF_type_node;
+  tree V2HI_type_node;
+  tree V4QI_type_node;
   unsigned int offset;
 
-  /* We have only builtins for -mpaired-single and -mips3d.  */
-  if (!TARGET_PAIRED_SINGLE_FLOAT)
+  /* We have only builtins for -mpaired-single, -mips3d and -mdsp.  */
+  if (!TARGET_PAIRED_SINGLE_FLOAT && !TARGET_DSP)
     return;
 
-  V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode);
-
-  types[MIPS_V2SF_FTYPE_V2SF]
-    = build_function_type_list (V2SF_type_node, V2SF_type_node, NULL_TREE);
-
-  types[MIPS_V2SF_FTYPE_V2SF_V2SF]
-    = build_function_type_list (V2SF_type_node,
-                               V2SF_type_node, V2SF_type_node, NULL_TREE);
-
-  types[MIPS_V2SF_FTYPE_V2SF_V2SF_INT]
-    = build_function_type_list (V2SF_type_node,
-                               V2SF_type_node, V2SF_type_node,
-                               integer_type_node, NULL_TREE);
+  if (TARGET_PAIRED_SINGLE_FLOAT)
+    {
+      V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode);
 
-  types[MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF]
-    = build_function_type_list (V2SF_type_node,
-                               V2SF_type_node, V2SF_type_node,
-                               V2SF_type_node, V2SF_type_node, NULL_TREE);
+      types[MIPS_V2SF_FTYPE_V2SF]
+       = build_function_type_list (V2SF_type_node, V2SF_type_node, NULL_TREE);
 
-  types[MIPS_V2SF_FTYPE_SF_SF]
-    = build_function_type_list (V2SF_type_node,
-                               float_type_node, float_type_node, NULL_TREE);
+      types[MIPS_V2SF_FTYPE_V2SF_V2SF]
+       = build_function_type_list (V2SF_type_node,
+                                   V2SF_type_node, V2SF_type_node, NULL_TREE);
 
-  types[MIPS_INT_FTYPE_V2SF_V2SF]
-    = build_function_type_list (integer_type_node,
-                               V2SF_type_node, V2SF_type_node, NULL_TREE);
+      types[MIPS_V2SF_FTYPE_V2SF_V2SF_INT]
+       = build_function_type_list (V2SF_type_node,
+                                   V2SF_type_node, V2SF_type_node,
+                                   integer_type_node, NULL_TREE);
 
-  types[MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF]
-    = build_function_type_list (integer_type_node,
-                               V2SF_type_node, V2SF_type_node,
-                               V2SF_type_node, V2SF_type_node, NULL_TREE);
+      types[MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF]
+       = build_function_type_list (V2SF_type_node,
+                                   V2SF_type_node, V2SF_type_node,
+                                   V2SF_type_node, V2SF_type_node, NULL_TREE);
 
-  types[MIPS_INT_FTYPE_SF_SF]
-    = build_function_type_list (integer_type_node,
-                               float_type_node, float_type_node, NULL_TREE);
+      types[MIPS_V2SF_FTYPE_SF_SF]
+       = build_function_type_list (V2SF_type_node,
+                                   float_type_node, float_type_node, NULL_TREE);
 
-  types[MIPS_INT_FTYPE_DF_DF]
-    = build_function_type_list (integer_type_node,
-                               double_type_node, double_type_node, NULL_TREE);
+      types[MIPS_INT_FTYPE_V2SF_V2SF]
+       = build_function_type_list (integer_type_node,
+                                   V2SF_type_node, V2SF_type_node, NULL_TREE);
 
-  types[MIPS_SF_FTYPE_V2SF]
-    = build_function_type_list (float_type_node, V2SF_type_node, NULL_TREE);
+      types[MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF]
+       = build_function_type_list (integer_type_node,
+                                   V2SF_type_node, V2SF_type_node,
+                                   V2SF_type_node, V2SF_type_node, NULL_TREE);
 
-  types[MIPS_SF_FTYPE_SF]
-    = build_function_type_list (float_type_node,
-                               float_type_node, NULL_TREE);
+      types[MIPS_INT_FTYPE_SF_SF]
+       = build_function_type_list (integer_type_node,
+                                   float_type_node, float_type_node, NULL_TREE);
 
-  types[MIPS_SF_FTYPE_SF_SF]
-    = build_function_type_list (float_type_node,
-                               float_type_node, float_type_node, NULL_TREE);
+      types[MIPS_INT_FTYPE_DF_DF]
+       = build_function_type_list (integer_type_node,
+                                   double_type_node, double_type_node, NULL_TREE);
 
-  types[MIPS_DF_FTYPE_DF]
-    = build_function_type_list (double_type_node,
-                               double_type_node, NULL_TREE);
+      types[MIPS_SF_FTYPE_V2SF]
+       = build_function_type_list (float_type_node, V2SF_type_node, NULL_TREE);
+
+      types[MIPS_SF_FTYPE_SF]
+       = build_function_type_list (float_type_node,
+                                   float_type_node, NULL_TREE);
+
+      types[MIPS_SF_FTYPE_SF_SF]
+       = build_function_type_list (float_type_node,
+                                   float_type_node, float_type_node, NULL_TREE);
+
+      types[MIPS_DF_FTYPE_DF]
+       = build_function_type_list (double_type_node,
+                                   double_type_node, NULL_TREE);
+
+      types[MIPS_DF_FTYPE_DF_DF]
+       = build_function_type_list (double_type_node,
+                                   double_type_node, double_type_node, NULL_TREE);
+    }
+
+  if (TARGET_DSP)
+    {
+      V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
+      V4QI_type_node = build_vector_type_for_mode (intQI_type_node, V4QImode);
+
+      types[MIPS_V2HI_FTYPE_V2HI_V2HI]
+       = build_function_type_list (V2HI_type_node,
+                                   V2HI_type_node, V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_SI_SI]
+       = build_function_type_list (intSI_type_node,
+                                   intSI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V4QI_FTYPE_V4QI_V4QI]
+       = build_function_type_list (V4QI_type_node,
+                                   V4QI_type_node, V4QI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_V4QI]
+       = build_function_type_list (intSI_type_node,
+                                   V4QI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V2HI_FTYPE_V2HI]
+       = build_function_type_list (V2HI_type_node,
+                                   V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_SI]
+       = build_function_type_list (intSI_type_node,
+                                   intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V4QI_FTYPE_V2HI_V2HI]
+       = build_function_type_list (V4QI_type_node,
+                                   V2HI_type_node, V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V2HI_FTYPE_SI_SI]
+       = build_function_type_list (V2HI_type_node,
+                                   intSI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_V2HI]
+       = build_function_type_list (intSI_type_node,
+                                   V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V2HI_FTYPE_V4QI]
+       = build_function_type_list (V2HI_type_node,
+                                   V4QI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V4QI_FTYPE_V4QI_SI]
+       = build_function_type_list (V4QI_type_node,
+                                   V4QI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V2HI_FTYPE_V2HI_SI]
+       = build_function_type_list (V2HI_type_node,
+                                   V2HI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V2HI_FTYPE_V4QI_V2HI]
+       = build_function_type_list (V2HI_type_node,
+                                   V4QI_type_node, V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_V2HI_V2HI]
+       = build_function_type_list (intSI_type_node,
+                                   V2HI_type_node, V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_DI_FTYPE_DI_V4QI_V4QI]
+       = build_function_type_list (intDI_type_node,
+                                   intDI_type_node, V4QI_type_node, V4QI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_DI_FTYPE_DI_V2HI_V2HI]
+       = build_function_type_list (intDI_type_node,
+                                   intDI_type_node, V2HI_type_node, V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_DI_FTYPE_DI_SI_SI]
+       = build_function_type_list (intDI_type_node,
+                                   intDI_type_node, intSI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V4QI_FTYPE_SI]
+       = build_function_type_list (V4QI_type_node,
+                                   intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_V2HI_FTYPE_SI]
+       = build_function_type_list (V2HI_type_node,
+                                   intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_VOID_FTYPE_V4QI_V4QI]
+       = build_function_type_list (void_type_node,
+                                   V4QI_type_node, V4QI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_V4QI_V4QI]
+       = build_function_type_list (intSI_type_node,
+                                   V4QI_type_node, V4QI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_VOID_FTYPE_V2HI_V2HI]
+       = build_function_type_list (void_type_node,
+                                   V2HI_type_node, V2HI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_DI_SI]
+       = build_function_type_list (intSI_type_node,
+                                   intDI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_DI_FTYPE_DI_SI]
+       = build_function_type_list (intDI_type_node,
+                                   intDI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_VOID_FTYPE_SI_SI]
+       = build_function_type_list (void_type_node,
+                                   intSI_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_PTR_SI]
+       = build_function_type_list (intSI_type_node,
+                                   ptr_type_node, intSI_type_node,
+                                   NULL_TREE);
+
+      types[MIPS_SI_FTYPE_VOID]
+       = build_function_type (intSI_type_node, void_list_node);
+
+      if (TARGET_DSPR2)
+       {
+         types[MIPS_V4QI_FTYPE_V4QI]
+           = build_function_type_list (V4QI_type_node,
+                                       V4QI_type_node,
+                                       NULL_TREE);
+
+         types[MIPS_SI_FTYPE_SI_SI_SI]
+           = build_function_type_list (intSI_type_node,
+                                       intSI_type_node, intSI_type_node,
+                                       intSI_type_node, NULL_TREE);
+
+         types[MIPS_DI_FTYPE_DI_USI_USI]
+           = build_function_type_list (intDI_type_node,
+                                       intDI_type_node,
+                                       unsigned_intSI_type_node,
+                                       unsigned_intSI_type_node, NULL_TREE);
+
+         types[MIPS_DI_FTYPE_SI_SI]
+           = build_function_type_list (intDI_type_node,
+                                       intSI_type_node, intSI_type_node,
+                                       NULL_TREE);
+
+         types[MIPS_DI_FTYPE_USI_USI]
+           = build_function_type_list (intDI_type_node,
+                                       unsigned_intSI_type_node,
+                                       unsigned_intSI_type_node, NULL_TREE);
+
+         types[MIPS_V2HI_FTYPE_SI_SI_SI]
+           = build_function_type_list (V2HI_type_node,
+                                       intSI_type_node, intSI_type_node,
+                                       intSI_type_node, NULL_TREE);
 
-  types[MIPS_DF_FTYPE_DF_DF]
-    = build_function_type_list (double_type_node,
-                               double_type_node, double_type_node, NULL_TREE);
+       }
+    }
 
   /* Iterate through all of the bdesc arrays, initializing all of the
      builtin functions.  */
@@ -9869,42 +10793,54 @@ mips_init_builtins (void)
   offset = 0;
   for (m = bdesc_arrays; m < &bdesc_arrays[ARRAY_SIZE (bdesc_arrays)]; m++)
     {
-      if (m->proc == PROCESSOR_DEFAULT || (m->proc == mips_arch))
+      if ((m->proc == PROCESSOR_MAX || (m->proc == mips_arch))
+         && (m->unsupported_target_flags & target_flags) == 0)
        for (d = m->bdesc; d < &m->bdesc[m->size]; d++)
          if ((d->target_flags & target_flags) == d->target_flags)
-           lang_hooks.builtin_function (d->name, types[d->function_type],
-                                        d - m->bdesc + offset,
-                                        BUILT_IN_MD, NULL, NULL);
+           add_builtin_function (d->name, types[d->function_type],
+                                 d - m->bdesc + offset,
+                                 BUILT_IN_MD, NULL, NULL);
       offset += m->size;
     }
 }
 
 /* Expand a MIPS_BUILTIN_DIRECT function.  ICODE is the code of the
-   .md pattern and ARGLIST is the list of function arguments.  TARGET,
-   if nonnull, suggests a good place to put the result.  */
+   .md pattern and CALL is the function expr with arguments.  TARGET,
+   if nonnull, suggests a good place to put the result.
+   HAS_TARGET indicates the function must return something.  */
 
 static rtx
-mips_expand_builtin_direct (enum insn_code icode, rtx target, tree arglist)
+mips_expand_builtin_direct (enum insn_code icode, rtx target, tree exp,
+                           bool has_target)
 {
   rtx ops[MAX_RECOG_OPERANDS];
-  int i;
+  int i = 0;
+  int j = 0;
 
-  target = mips_prepare_builtin_target (icode, 0, target);
-  for (i = 1; i < insn_data[icode].n_operands; i++)
-    ops[i] = mips_prepare_builtin_arg (icode, i, &arglist);
+  if (has_target)
+    {
+      /* We save target to ops[0].  */
+      ops[0] = mips_prepare_builtin_target (icode, 0, target);
+      i = 1;
+    }
 
-  switch (insn_data[icode].n_operands)
+  /* We need to test if the arglist is not zero.  Some instructions have extra
+     clobber registers.  */
+  for (; i < insn_data[icode].n_operands && i <= call_expr_nargs (exp); i++, j++)
+    ops[i] = mips_prepare_builtin_arg (icode, i, exp, j);
+
+  switch (i)
     {
     case 2:
-      emit_insn (GEN_FCN (icode) (target, ops[1]));
+      emit_insn (GEN_FCN (icode) (ops[0], ops[1]));
       break;
 
     case 3:
-      emit_insn (GEN_FCN (icode) (target, ops[1], ops[2]));
+      emit_insn (GEN_FCN (icode) (ops[0], ops[1], ops[2]));
       break;
 
     case 4:
-      emit_insn (GEN_FCN (icode) (target, ops[1], ops[2], ops[3]));
+      emit_insn (GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3]));
       break;
 
     default:
@@ -9914,7 +10850,7 @@ mips_expand_builtin_direct (enum insn_code icode, rtx target, tree arglist)
 }
 
 /* Expand a __builtin_mips_movt_*_ps() or __builtin_mips_movf_*_ps()
-   function (TYPE says which).  ARGLIST is the list of arguments to the
+   function (TYPE says which).  EXP is the tree for the function
    function, ICODE is the instruction that should be used to compare
    the first two arguments, and COND is the condition it should test.
    TARGET, if nonnull, suggests a good place to put the result.  */
@@ -9922,63 +10858,90 @@ mips_expand_builtin_direct (enum insn_code icode, rtx target, tree arglist)
 static rtx
 mips_expand_builtin_movtf (enum mips_builtin_type type,
                           enum insn_code icode, enum mips_fp_condition cond,
-                          rtx target, tree arglist)
+                          rtx target, tree exp)
 {
   rtx cmp_result, op0, op1;
 
   cmp_result = mips_prepare_builtin_target (icode, 0, 0);
-  op0 = mips_prepare_builtin_arg (icode, 1, &arglist);
-  op1 = mips_prepare_builtin_arg (icode, 2, &arglist);
+  op0 = mips_prepare_builtin_arg (icode, 1, exp, 0);
+  op1 = mips_prepare_builtin_arg (icode, 2, exp, 1);
   emit_insn (GEN_FCN (icode) (cmp_result, op0, op1, GEN_INT (cond)));
 
   icode = CODE_FOR_mips_cond_move_tf_ps;
   target = mips_prepare_builtin_target (icode, 0, target);
   if (type == MIPS_BUILTIN_MOVT)
     {
-      op1 = mips_prepare_builtin_arg (icode, 2, &arglist);
-      op0 = mips_prepare_builtin_arg (icode, 1, &arglist);
+      op1 = mips_prepare_builtin_arg (icode, 2, exp, 2);
+      op0 = mips_prepare_builtin_arg (icode, 1, exp, 3);
     }
   else
     {
-      op0 = mips_prepare_builtin_arg (icode, 1, &arglist);
-      op1 = mips_prepare_builtin_arg (icode, 2, &arglist);
+      op0 = mips_prepare_builtin_arg (icode, 1, exp, 2);
+      op1 = mips_prepare_builtin_arg (icode, 2, exp, 3);
     }
   emit_insn (gen_mips_cond_move_tf_ps (target, op0, op1, cmp_result));
   return target;
 }
 
+/* Move VALUE_IF_TRUE into TARGET if CONDITION is true; move VALUE_IF_FALSE
+   into TARGET otherwise.  Return TARGET.  */
+
+static rtx
+mips_builtin_branch_and_move (rtx condition, rtx target,
+                             rtx value_if_true, rtx value_if_false)
+{
+  rtx true_label, done_label;
+
+  true_label = gen_label_rtx ();
+  done_label = gen_label_rtx ();
+
+  /* First assume that CONDITION is false.  */
+  emit_move_insn (target, value_if_false);
+
+  /* Branch to TRUE_LABEL if CONDITION is true and DONE_LABEL otherwise.  */
+  emit_jump_insn (gen_condjump (condition, true_label));
+  emit_jump_insn (gen_jump (done_label));
+  emit_barrier ();
+
+  /* Fix TARGET if CONDITION is true.  */
+  emit_label (true_label);
+  emit_move_insn (target, value_if_true);
+
+  emit_label (done_label);
+  return target;
+}
+
 /* Expand a comparison builtin of type BUILTIN_TYPE.  ICODE is the code
    of the comparison instruction and COND is the condition it should test.
-   ARGLIST is the list of function arguments and TARGET, if nonnull,
+   EXP is the function call and arguments and TARGET, if nonnull,
    suggests a good place to put the boolean result.  */
 
 static rtx
 mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
                             enum insn_code icode, enum mips_fp_condition cond,
-                            rtx target, tree arglist)
+                            rtx target, tree exp)
 {
-  rtx label1, label2, if_then_else;
-  rtx pat, cmp_result, ops[MAX_RECOG_OPERANDS];
-  rtx target_if_equal, target_if_unequal;
-  int cmp_value, i;
+  rtx offset, condition, cmp_result, ops[MAX_RECOG_OPERANDS];
+  int i;
+  int j = 0;
 
   if (target == 0 || GET_MODE (target) != SImode)
     target = gen_reg_rtx (SImode);
 
   /* Prepare the operands to the comparison.  */
   cmp_result = mips_prepare_builtin_target (icode, 0, 0);
-  for (i = 1; i < insn_data[icode].n_operands - 1; i++)
-    ops[i] = mips_prepare_builtin_arg (icode, i, &arglist);
+  for (i = 1; i < insn_data[icode].n_operands - 1; i++, j++)
+    ops[i] = mips_prepare_builtin_arg (icode, i, exp, j);
 
   switch (insn_data[icode].n_operands)
     {
     case 4:
-      pat = GEN_FCN (icode) (cmp_result, ops[1], ops[2], GEN_INT (cond));
+      emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2], GEN_INT (cond)));
       break;
 
     case 6:
-      pat = GEN_FCN (icode) (cmp_result, ops[1], ops[2],
-                            ops[3], ops[4], GEN_INT (cond));
+      emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2],
+                                 ops[3], ops[4], GEN_INT (cond)));
       break;
 
     default:
@@ -9987,52 +10950,87 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
 
   /* If the comparison sets more than one register, we define the result
      to be 0 if all registers are false and -1 if all registers are true.
-     The value of the complete result is indeterminate otherwise.  It is
-     possible to test individual registers using SUBREGs.
-
-     Set up CMP_RESULT, CMP_VALUE, TARGET_IF_EQUAL and TARGET_IF_UNEQUAL so
-     that the result should be TARGET_IF_EQUAL if (EQ CMP_RESULT CMP_VALUE)
-     and TARGET_IF_UNEQUAL otherwise.  */
-  if (builtin_type == MIPS_BUILTIN_CMP_ALL)
+     The value of the complete result is indeterminate otherwise.  */
+  switch (builtin_type)
     {
-      cmp_value = -1;
-      target_if_equal = const1_rtx;
-      target_if_unequal = const0_rtx;
+    case MIPS_BUILTIN_CMP_ALL:
+      condition = gen_rtx_NE (VOIDmode, cmp_result, constm1_rtx);
+      return mips_builtin_branch_and_move (condition, target,
+                                          const0_rtx, const1_rtx);
+
+    case MIPS_BUILTIN_CMP_UPPER:
+    case MIPS_BUILTIN_CMP_LOWER:
+      offset = GEN_INT (builtin_type == MIPS_BUILTIN_CMP_UPPER);
+      condition = gen_single_cc (cmp_result, offset);
+      return mips_builtin_branch_and_move (condition, target,
+                                          const1_rtx, const0_rtx);
+
+    default:
+      condition = gen_rtx_NE (VOIDmode, cmp_result, const0_rtx);
+      return mips_builtin_branch_and_move (condition, target,
+                                          const1_rtx, const0_rtx);
     }
+}
+
+/* Expand a bposge builtin of type BUILTIN_TYPE.  TARGET, if nonnull,
+   suggests a good place to put the boolean result.  */
+
+static rtx
+mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
+{
+  rtx condition, cmp_result;
+  int cmp_value;
+
+  if (target == 0 || GET_MODE (target) != SImode)
+    target = gen_reg_rtx (SImode);
+
+  cmp_result = gen_rtx_REG (CCDSPmode, CCDSP_PO_REGNUM);
+
+  if (builtin_type == MIPS_BUILTIN_BPOSGE32)
+    cmp_value = 32;
   else
+    gcc_assert (0);
+
+  condition = gen_rtx_GE (VOIDmode, cmp_result, GEN_INT (cmp_value));
+  return mips_builtin_branch_and_move (condition, target,
+                                      const1_rtx, const0_rtx);
+}
+\f
+/* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL.
+   FIRST is true if this is the first time handling this decl.  */
+
+static void
+mips_encode_section_info (tree decl, rtx rtl, int first)
+{
+  default_encode_section_info (decl, rtl, first);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
     {
-      cmp_value = 0;
-      target_if_equal = const0_rtx;
-      target_if_unequal = const1_rtx;
-      if (builtin_type == MIPS_BUILTIN_CMP_UPPER)
-       cmp_result = simplify_gen_subreg (CCmode, cmp_result, CCV2mode, 4);
-      else if (builtin_type == MIPS_BUILTIN_CMP_LOWER)
-       cmp_result = simplify_gen_subreg (CCmode, cmp_result, CCV2mode, 0);
-    }
-
-  /* First assume that CMP_RESULT == CMP_VALUE.  */
-  emit_move_insn (target, target_if_equal);
-
-  /* Branch to LABEL1 if CMP_RESULT != CMP_VALUE.  */
-  emit_insn (pat);
-  label1 = gen_label_rtx ();
-  label2 = gen_label_rtx ();
-  if_then_else
-    = gen_rtx_IF_THEN_ELSE (VOIDmode,
-                           gen_rtx_fmt_ee (NE, GET_MODE (cmp_result),
-                                           cmp_result, GEN_INT (cmp_value)),
-                           gen_rtx_LABEL_REF (VOIDmode, label1), pc_rtx);
-  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_then_else));
-  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
-                              gen_rtx_LABEL_REF (VOIDmode, label2)));
-  emit_barrier ();
-  emit_label (label1);
+      rtx symbol = XEXP (rtl, 0);
+      SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
+    }
+}
 
-  /* Fix TARGET for CMP_RESULT != CMP_VALUE.  */
-  emit_move_insn (target, target_if_unequal);
-  emit_label (label2);
+/* Implement TARGET_EXTRA_LIVE_ON_ENTRY.  Some code models use the incoming
+   value of PIC_FUNCTION_ADDR_REGNUM to set up the global pointer.  */
 
-  return target;
+static void
+mips_extra_live_on_entry (bitmap regs)
+{
+  if (TARGET_USE_GOT && !TARGET_ABSOLUTE_ABICALLS)
+    bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
+}
+
+/* SImode values are represented as sign-extended to DImode.  */
+
+int
+mips_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
+{
+  if (TARGET_64BIT && mode == SImode && mode_rep == DImode)
+    return SIGN_EXTEND;
+
+  return UNKNOWN;
 }
 \f
 #include "gt-mips.h"