OSDN Git Service

* doc/md.texi: Update documentation of MIPS constraints.
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 594d5c1..aed07e5 100644 (file)
@@ -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,35 @@ 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,
+
   /* The last type.  */
   MIPS_MAX_FTYPE_MAX
 };
@@ -162,6 +192,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 +219,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.  */
@@ -292,9 +329,9 @@ 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 int mips_fpr_return_fields (tree, tree *);
 static bool mips_return_in_msb (tree);
@@ -357,19 +394,21 @@ static bool mips_callee_copies (CUMULATIVE_ARGS *, enum machine_mode mode,
 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_scalar_mode_supported_p (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_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);
 
 /* Structure to be filled in by compute_frame_size with register
    save masks, and offsets for the current function.  */
@@ -398,6 +437,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;
 
@@ -550,21 +593,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;
 
@@ -644,11 +684,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
@@ -696,13 +743,19 @@ 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 },
+  { "24k", PROCESSOR_24K, 33 },
+  { "24kc", PROCESSOR_24K, 33 },  /* 24K  no FPU */
+  { "24kf", PROCESSOR_24K, 33 },  /* 24K 1:2 FPU */
+  { "24kx", PROCESSOR_24KX, 33 }, /* 24K 1:1 FPU */
 
   /* MIPS64 */
   { "5kc", PROCESSOR_5KC, 64 },
+  { "5kf", PROCESSOR_5KF, 64 },
   { "20kc", PROCESSOR_20KC, 64 },
   { "sb1", PROCESSOR_SB1, 64 },
   { "sr71000", PROCESSOR_SR71000, 64 },
@@ -710,6 +763,275 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
   /* 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_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
+    },
+    { /* 24k */
+      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 */
+    },
+    { /* 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 */
+      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
@@ -820,9 +1142,6 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P mips_vector_mode_supported_p
 
-#undef TARGET_SCALAR_MODE_SUPPORTED_P
-#define TARGET_SCALAR_MODE_SUPPORTED_P mips_scalar_mode_supported_p
-
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS mips_init_builtins
 #undef TARGET_EXPAND_BUILTIN
@@ -834,6 +1153,18 @@ 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
+/* With -mabicalls (which is the default on GNU/Linux),
+   PIC_FUNCTION_ADDR_REGNUM is live on function entry and is to
+   initialize $28, which is PIC_OFFSET_TABLE_REGNUM.  */
+#define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
@@ -1698,7 +2029,7 @@ mips_legitimize_tls_address (rtx loc)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return dest;
@@ -2089,75 +2420,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:
@@ -2177,15 +2511,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:
@@ -2218,7 +2552,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);
@@ -2230,19 +2564,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;
@@ -2252,115 +2580,46 @@ 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:
@@ -2382,6 +2641,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;
     }
@@ -2419,8 +2687,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))
@@ -2534,6 +2802,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");
 
@@ -2552,6 +2828,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";
 
@@ -2692,6 +2976,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
@@ -2702,11 +3030,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);
@@ -2806,8 +3137,6 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
       switch (*code)
        {
        case NE:
-       case UNGE:
-       case UNGT:
        case LTGT:
        case ORDERED:
          cmp_code = reverse_condition_maybe_unordered (*code);
@@ -3602,7 +3931,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;
@@ -3626,18 +3956,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 ());
 
@@ -3672,14 +3993,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.
@@ -3759,101 +4075,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 (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 = build2 (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 = build2 (PLUS_EXPR, TREE_TYPE (ftop), t,
+                   build_int_cst (NULL_TREE, -fpr_offset));
+      t = build2 (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 = build2 (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.  */
+      t = build2 (MODIFY_EXPR, 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.  */
@@ -3920,16 +4219,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
@@ -3957,42 +4256,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 (MODIFY_EXPR, 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;
 
@@ -4001,11 +4300,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 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
        }
       else
        align = NULL;
@@ -4015,25 +4314,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;
 }
@@ -4049,7 +4348,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,
@@ -4165,7 +4464,39 @@ mips_expand_unaligned_store (rtx dest, rtx src, unsigned int width, int bitpos)
     }
   return true;
 }
-\f
+
+/* 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.  */
 
@@ -4216,21 +4547,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;
@@ -4289,6 +4612,9 @@ override_options (void)
   if (mips_tune_info == 0)
     mips_set_tune (mips_arch_info);
 
+  /* Set cost structure for the processor.  */
+  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
@@ -4336,25 +4662,12 @@ override_options (void)
 
   if ((target_flags_explicit & MASK_LONG64) == 0)
     {
-      if (TARGET_INT64)
-       target_flags |= MASK_LONG64;
-      /* If no type size setting options (-mlong64,-mint64,-mlong32)
-        were used, then set the type sizes.  In the EABI in 64 bit mode,
-        longs and pointers are 64 bits.  Likewise for the SGI Irix6 N64
-        ABI.  */
-      else if ((mips_abi == ABI_EABI && TARGET_64BIT) || mips_abi == ABI_64)
+      if ((mips_abi == ABI_EABI && TARGET_64BIT) || mips_abi == ABI_64)
        target_flags |= MASK_LONG64;
       else
        target_flags &= ~MASK_LONG64;
     }
 
-  /* Deprecate -mint64. Remove after 4.0 branches.  */
-  if (TARGET_INT64)
-    warning ("-mint64 is a deprecated option");
-
-  if (TARGET_INT64 && !TARGET_LONG64)
-    error ("unsupported combination: %s", "-mint64 -mlong32");
-
   if (MIPS_MARCH_CONTROLS_SOFT_FLOAT
       && (target_flags_explicit & MASK_SOFT_FLOAT) == 0)
     {
@@ -4404,7 +4717,7 @@ override_options (void)
        target_flags &= ~MASK_BRANCHLIKELY;
     }
   if (TARGET_BRANCHLIKELY && !ISA_HAS_BRANCHLIKELY)
-    warning ("generation of Branch Likely instructions enabled, but not supported by architecture");
+    warning (0, "generation of Branch Likely instructions enabled, but not supported by architecture");
 
   /* The effect of -mabicalls isn't defined for the EABI.  */
   if (mips_abi == ABI_EABI && TARGET_ABICALLS)
@@ -4421,7 +4734,7 @@ override_options (void)
     {
       flag_pic = 1;
       if (mips_section_threshold > 0)
-       warning ("-G is incompatible with PIC code which is the default");
+       warning (0, "-G is incompatible with PIC code which is the default");
     }
 
   /* mips_split_addresses is a half-way house between explicit
@@ -4504,6 +4817,9 @@ override_options (void)
   if (TARGET_PAIRED_SINGLE_FLOAT && !ISA_MIPS64)
     error ("-mips3d/-mpaired-single must be used with -mips64");
 
+  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;
@@ -4525,25 +4841,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.  */
 
@@ -4603,15 +4900,20 @@ override_options (void)
                         && 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));
 
-         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))
@@ -4760,6 +5062,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;
@@ -4904,6 +5213,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:
 
@@ -5154,6 +5464,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;
@@ -5425,7 +5751,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.  */
@@ -5467,9 +5793,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);
@@ -5538,7 +5864,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",
@@ -5623,7 +5949,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.  */
@@ -5847,7 +6173,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
         +-----------------------+      +-----------------------+
@@ -5975,10 +6301,9 @@ compute_frame_size (HOST_WIDE_INT size)
   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;
@@ -6047,9 +6372,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:
@@ -6276,8 +6600,18 @@ mips_set_frame_expr (rtx frame_pattern)
 static rtx
 mips_frame_set (rtx mem, rtx reg)
 {
-  rtx set = gen_rtx_SET (VOIDmode, mem, reg);
+  rtx set;
+
+  /* If we're saving the return address register and the dwarf return
+     address column differs from the hard register number, adjust the
+     note reg to refer to the former.  */
+  if (REGNO (reg) == GP_REG_FIRST + 31
+      && DWARF_FRAME_RETURN_COLUMN != GP_REG_FIRST + 31)
+    reg = gen_rtx_REG (GET_MODE (reg), DWARF_FRAME_RETURN_COLUMN);
+
+  set = gen_rtx_SET (VOIDmode, mem, reg);
   RTX_FRAME_RELATED_P (set) = 1;
+
   return set;
 }
 
@@ -6391,10 +6725,23 @@ 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,
@@ -6719,7 +7066,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     mips16_lay_out_constants ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
-  final (insn, file, 1, 0);
+  final (insn, file, 1);
   final_end_function ();
 
   /* Clean up the vars set above.  Note that final_end_function resets
@@ -6752,7 +7099,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)
 {
@@ -6761,13 +7108,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
     {
@@ -6777,11 +7124,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);
     }
 }
 
@@ -6793,32 +7140,30 @@ 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
@@ -7090,8 +7435,10 @@ 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;
        }
     }
@@ -7172,8 +7519,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)
        {
@@ -7182,7 +7531,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)
        {
@@ -7288,52 +7637,24 @@ mips_valid_pointer_mode (enum machine_mode mode)
   return (mode == SImode || (TARGET_64BIT && mode == DImode));
 }
 
-/* Define this so that we can deal with a testcase like:
-
-   char foo __attribute__ ((mode (SI)));
-
-   then compiled with -mabi=64 and -mint64. We have no
-   32-bit type at that point and so the default case
-   always fails.  */
+/* Target hook for vector_mode_supported_p.  */
 
 static bool
-mips_scalar_mode_supported_p (enum machine_mode mode)
+mips_vector_mode_supported_p (enum machine_mode mode)
 {
   switch (mode)
     {
-    case QImode:
-    case HImode:
-    case SImode:
-    case DImode:
-      return true;
+    case V2SFmode:
+      return TARGET_PAIRED_SINGLE_FLOAT;
 
-      /* Handled via optabs.c.  */
-    case TImode:
-      return TARGET_64BIT;
-
-    case SFmode:
-    case DFmode:
-      return true;
-
-      /* LONG_DOUBLE_TYPE_SIZE is 128 for TARGET_NEWABI only.  */
-    case TFmode:
-      return TARGET_NEWABI;
+    case V2HImode:
+    case V4QImode:
+      return TARGET_DSP;
 
     default:
       return false;
     }
 }
-
-
-/* Target hook for vector_mode_supported_p.  */
-static bool
-mips_vector_mode_supported_p (enum machine_mode mode)
-{
-  if (mode == V2SFmode && TARGET_PAIRED_SINGLE_FLOAT)
-    return true;
-  else
-    return false;
-}
 \f
 /* If we can access small data directly (using gp-relative relocation
    operators) return the small data pointer, otherwise return null.
@@ -7473,7 +7794,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
@@ -7518,7 +7839,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
@@ -7978,11 +8299,7 @@ dump_constants (struct mips16_constant *constants, rtx insn)
   emit_barrier_after (insn);
 }
 
-/* Return the length of instruction INSN.
-
-   ??? MIPS16 switch tables go in .text, but we don't define
-   JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
-   compute their lengths correctly.  */
+/* Return the length of instruction INSN.  */
 
 static int
 mips16_insn_length (rtx insn)
@@ -8581,7 +8898,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 ();
@@ -8701,7 +9018,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;
@@ -8712,7 +9029,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))
@@ -8721,8 +9038,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))
        {
@@ -8731,15 +9048,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;
 }
@@ -8983,7 +9301,7 @@ mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p,
             /* Output delay slot instruction.  */
             rtx insn = final_sequence;
             final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
-                             optimize, 0, 1, NULL);
+                             optimize, 1, NULL);
             INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
           }
        else
@@ -9002,7 +9320,7 @@ mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p,
             /* Output delay slot instruction.  */
             rtx insn = final_sequence;
             final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
-                             optimize, 0, 1, NULL);
+                             optimize, 1, NULL);
             INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
           }
        else
@@ -9209,7 +9527,7 @@ mips_parse_cpu (const char *cpu_string)
   for (s = cpu_string; *s != 0; s++)
     if (ISUPPER (*s))
       {
-       warning ("the cpu name must be lower case");
+       warning (0, "the cpu name must be lower case");
        break;
       }
 
@@ -9723,6 +10041,116 @@ 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 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 (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 (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_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),
+  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)
+};
+
 /* This helps provide a mapping from builtin function codes to bdesc
    arrays.  */
 
@@ -9735,14 +10163,15 @@ 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;
 };
 
 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 },
+  { sb1_bdesc, ARRAY_SIZE (sb1_bdesc), PROCESSOR_SB1 },
+  { dsp_bdesc, ARRAY_SIZE (dsp_bdesc), PROCESSOR_MAX }
 };
 
 /* Take the head of argument list *ARGLIST and convert it into a form
@@ -9756,10 +10185,18 @@ mips_prepare_builtin_arg (enum insn_code icode,
   rtx value;
   enum machine_mode mode;
 
-  value = expand_expr (TREE_VALUE (*arglist), NULL_RTX, VOIDmode, 0);
+  value = expand_normal (TREE_VALUE (*arglist));
   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;
@@ -9816,7 +10253,10 @@ 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, arglist, true);
+
+    case MIPS_BUILTIN_DIRECT_NO_TARGET:
+      return mips_expand_builtin_direct (icode, target, arglist, false);
 
     case MIPS_BUILTIN_MOVT:
     case MIPS_BUILTIN_MOVF:
@@ -9831,6 +10271,9 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return mips_expand_builtin_compare (type, icode, bdesc[fcode].cond,
                                          target, arglist);
 
+    case MIPS_BUILTIN_BPOSGE32:
+      return mips_expand_builtin_bposge (type, target);
+
     default:
       return 0;
     }
@@ -9845,70 +10288,214 @@ 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);
-
-  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);
+  if (TARGET_PAIRED_SINGLE_FLOAT)
+    {
+      V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode);
 
-  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]
+       = build_function_type_list (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]
+       = build_function_type_list (V2SF_type_node,
+                                   V2SF_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_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_SF_SF]
-    = build_function_type_list (integer_type_node,
-                               float_type_node, float_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_DF_DF]
-    = build_function_type_list (integer_type_node,
-                               double_type_node, double_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_SF_FTYPE_V2SF]
-    = build_function_type_list (float_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_SF_FTYPE_SF]
-    = build_function_type_list (float_type_node,
-                               float_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_SF]
-    = build_function_type_list (float_type_node,
-                               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_DF_FTYPE_DF]
-    = build_function_type_list (double_type_node,
-                               double_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_DF]
-    = build_function_type_list (double_type_node,
-                               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);
+    }
 
   /* Iterate through all of the bdesc arrays, initializing all of the
      builtin functions.  */
@@ -9916,7 +10503,7 @@ 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))
        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],
@@ -9928,30 +10515,40 @@ mips_init_builtins (void)
 
 /* 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.  */
+   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 arglist,
+                           bool has_target)
 {
   rtx ops[MAX_RECOG_OPERANDS];
-  int i;
+  int i = 0;
 
-  target = mips_prepare_builtin_target (icode, 0, target);
-  for (i = 1; i < insn_data[icode].n_operands; i++)
+  if (has_target)
+    {
+      /* We save target to ops[0].  */
+      ops[0] = mips_prepare_builtin_target (icode, 0, target);
+      i = 1;
+    }
+
+  /* We need to test if arglist is not zero.  Some instructions have extra
+     clobber registers.  */
+  for (; i < insn_data[icode].n_operands && arglist != 0; i++)
     ops[i] = mips_prepare_builtin_arg (icode, i, &arglist);
 
-  switch (insn_data[icode].n_operands)
+  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:
@@ -10081,5 +10678,86 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
 
   return target;
 }
+
+/* Expand a bposge builtin of type BUILTIN_TYPE.  TARGET, if nonnull,
+   suggests a good place to put the boolean result.
+
+   The sequence we want is
+
+       li      target, 0
+       bposge* label1
+       j       label2
+   label1:
+       li      target, 1
+   label2:  */
+
+static rtx
+mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
+{
+  rtx label1, label2, if_then_else;
+  rtx 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);
+
+  /* Move 0 to target */
+  emit_move_insn (target, const0_rtx);
+
+  /* Generate two labels */
+  label1 = gen_label_rtx ();
+  label2 = gen_label_rtx ();
+
+  /* Generate if_then_else */
+  if_then_else
+    = gen_rtx_IF_THEN_ELSE (VOIDmode,
+                           gen_rtx_fmt_ee (GE, CCDSPmode,
+                                           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);
+  emit_move_insn (target, const1_rtx);
+  emit_label (label2);
+
+  return target;
+}
+\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))))
+    {
+      rtx symbol = XEXP (rtl, 0);
+      SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
+    }
+}
+
+/* Implement TARGET_EXTRA_LIVE_ON_ENTRY.  TARGET_ABICALLS makes
+   PIC_FUNCTION_ADDR_REGNUM live on entry to a function.  */
+
+static void
+mips_extra_live_on_entry (bitmap regs)
+{
+  if (!TARGET_ABICALLS)
+    bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
+}
+
 \f
 #include "gt-mips.h"