OSDN Git Service

2005-12-02 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 6ca6daf..733b9c6 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"
@@ -150,6 +150,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 +191,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 +218,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.  */
@@ -362,13 +398,15 @@ 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);
 
 /* Structure to be filled in by compute_frame_size with register
    save masks, and offsets for the current function.  */
@@ -397,6 +435,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;
 
@@ -549,6 +591,9 @@ 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
@@ -637,11 +682,21 @@ 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
@@ -701,6 +756,7 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 
   /* MIPS64 */
   { "5kc", PROCESSOR_5KC, 64 },
+  { "5kf", PROCESSOR_5KF, 64 },
   { "20kc", PROCESSOR_20KC, 64 },
   { "sb1", PROCESSOR_SB1, 64 },
   { "sr71000", PROCESSOR_SR71000, 64 },
@@ -708,6 +764,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
@@ -829,6 +1154,12 @@ 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
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
@@ -2084,75 +2415,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:
@@ -2172,15 +2506,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:
@@ -2213,7 +2547,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);
@@ -2225,19 +2559,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;
@@ -2247,115 +2575,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:
@@ -2377,6 +2636,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;
     }
@@ -2414,8 +2682,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))
@@ -2529,6 +2797,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");
 
@@ -2547,6 +2823,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";
 
@@ -2687,6 +2971,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
@@ -2697,11 +3025,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);
@@ -3595,7 +3926,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;
@@ -3619,18 +3951,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 ());
 
@@ -3665,14 +3988,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.
@@ -3752,101 +4070,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.  */
@@ -3913,16 +4214,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
@@ -3950,42 +4251,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;
 
@@ -3994,11 +4295,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;
@@ -4008,25 +4309,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;
 }
@@ -4306,6 +4607,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
@@ -4508,6 +4812,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;
@@ -4547,6 +4854,8 @@ override_options (void)
   mips_char_to_class['B'] = COP0_REGS;
   mips_char_to_class['C'] = COP2_REGS;
   mips_char_to_class['D'] = COP3_REGS;
+  mips_char_to_class['A'] = DSP_ACC_REGS;
+  mips_char_to_class['a'] = ACC_REGS;
 
   /* Set up array to map GCC register number to debug register number.
      Ignore the special purpose register numbers.  */
@@ -4612,10 +4921,10 @@ override_options (void)
                        /* 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))
@@ -4764,6 +5073,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;
@@ -4908,6 +5224,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:
 
@@ -5158,6 +5475,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;
@@ -5851,7 +6184,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
         +-----------------------+      +-----------------------+
@@ -5979,10 +6312,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;
@@ -6051,9 +6383,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:
@@ -6405,10 +6736,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,
@@ -7104,8 +7448,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;
        }
     }
@@ -7186,8 +7532,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)
        {
@@ -7196,7 +7544,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)
        {
@@ -7307,10 +7655,18 @@ mips_valid_pointer_mode (enum machine_mode mode)
 static bool
 mips_vector_mode_supported_p (enum machine_mode mode)
 {
-  if (mode == V2SFmode && TARGET_PAIRED_SINGLE_FLOAT)
-    return true;
-  else
-    return false;
+  switch (mode)
+    {
+    case V2SFmode:
+      return TARGET_PAIRED_SINGLE_FLOAT;
+
+    case V2HImode:
+    case V4QImode:
+      return TARGET_DSP;
+
+    default:
+      return false;
+    }
 }
 \f
 /* If we can access small data directly (using gp-relative relocation
@@ -8675,7 +9031,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;
@@ -8686,7 +9042,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))
@@ -8695,8 +9051,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))
        {
@@ -8705,15 +9061,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;
 }
@@ -9697,6 +10054,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.  */
 
@@ -9709,14 +10176,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
@@ -9733,7 +10201,15 @@ mips_prepare_builtin_arg (enum insn_code icode,
   value = expand_expr (TREE_VALUE (*arglist), NULL_RTX, VOIDmode, 0);
   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;
@@ -9790,7 +10266,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:
@@ -9805,6 +10284,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;
     }
@@ -9819,70 +10301,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.  */
@@ -9890,7 +10516,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],
@@ -9902,30 +10528,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:
@@ -10055,5 +10691,75 @@ 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;
+    }
+}
 \f
 #include "gt-mips.h"