OSDN Git Service

2006-06-12 Fred Fish <fnf@specifix.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index f5b2a08..d879402 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for MIPS code generation.
    Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by A. Lichnewsky, lich@inria.inria.fr.
    Changes by Michael Meissner, meissner@osf.org.
    64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
@@ -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)                                    \
@@ -71,13 +72,6 @@ Boston, MA 02111-1307, USA.  */
 #define UNSPEC_ADDRESS_TYPE(X) \
   ((enum mips_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST))
 
-/* True if X is (const (unspec [(const_int 0)] UNSPEC_GP)).  This is used
-   to initialize the mips16 gp pseudo register.  */
-#define CONST_GP_P(X) \
-  (GET_CODE (X) == CONST                       \
-   && GET_CODE (XEXP (X, 0)) == UNSPEC         \
-   && XINT (XEXP (X, 0), 1) == UNSPEC_GP)
-
 /* The maximum distance between the top of the stack frame and the
    value $sp has when we save & restore registers.
 
@@ -86,10 +80,8 @@ Boston, MA 02111-1307, USA.  */
    allocate and deallocate the top part of the frame.
 
    The value in the !mips16 case must be a SMALL_OPERAND and must
-   preserve the maximum stack alignment.  It could really be 0x7ff0,
-   but SGI's assemblers implement daddiu $sp,$sp,-0x7ff0 as a
-   multi-instruction addu sequence.  Use 0x7fe0 to work around this.  */
-#define MIPS_MAX_FIRST_STACK_STEP (TARGET_MIPS16 ? 0x100 : 0x7fe0)
+   preserve the maximum stack alignment.  */
+#define MIPS_MAX_FIRST_STACK_STEP (TARGET_MIPS16 ? 0x100 : 0x7ff0)
 
 /* True if INSN is a mips.md pattern or asm statement.  */
 #define USEFUL_INSN_P(INSN)                                            \
@@ -141,6 +133,129 @@ enum mips_address_type {
   ADDRESS_SYMBOLIC
 };
 
+/* Classifies the prototype of a builtin function.  */
+enum mips_function_type
+{
+  MIPS_V2SF_FTYPE_V2SF,
+  MIPS_V2SF_FTYPE_V2SF_V2SF,
+  MIPS_V2SF_FTYPE_V2SF_V2SF_INT,
+  MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF,
+  MIPS_V2SF_FTYPE_SF_SF,
+  MIPS_INT_FTYPE_V2SF_V2SF,
+  MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF,
+  MIPS_INT_FTYPE_SF_SF,
+  MIPS_INT_FTYPE_DF_DF,
+  MIPS_SF_FTYPE_V2SF,
+  MIPS_SF_FTYPE_SF,
+  MIPS_SF_FTYPE_SF_SF,
+  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
+};
+
+/* Specifies how a builtin function should be converted into rtl.  */
+enum mips_builtin_type
+{
+  /* The builtin corresponds directly to an .md pattern.  The return
+     value is mapped to operand 0 and the arguments are mapped to
+     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
+     operands for the movt.ps or movf.ps instruction (in assembly order).  */
+  MIPS_BUILTIN_MOVF,
+  MIPS_BUILTIN_MOVT,
+
+  /* The builtin corresponds to a V2SF comparison instruction.  Operand 0
+     of this instruction is the result of the comparison, which has mode
+     CCV2 or CCV4.  The function arguments are mapped to operands 1 and
+     above.  The function's return value is an SImode boolean that is
+     true under the following conditions:
+
+     MIPS_BUILTIN_CMP_ANY: one of the registers is true
+     MIPS_BUILTIN_CMP_ALL: all of the registers are true
+     MIPS_BUILTIN_CMP_LOWER: the first register is true
+     MIPS_BUILTIN_CMP_UPPER: the second register is true.  */
+  MIPS_BUILTIN_CMP_ANY,
+  MIPS_BUILTIN_CMP_ALL,
+  MIPS_BUILTIN_CMP_UPPER,
+  MIPS_BUILTIN_CMP_LOWER,
+
+  /* As above, but the instruction only sets a single $fcc register.  */
+  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.  */
+#define MIPS_FP_CONDITIONS(MACRO) \
+  MACRO (f),   \
+  MACRO (un),  \
+  MACRO (eq),  \
+  MACRO (ueq), \
+  MACRO (olt), \
+  MACRO (ult), \
+  MACRO (ole), \
+  MACRO (ule), \
+  MACRO (sf),  \
+  MACRO (ngle),        \
+  MACRO (seq), \
+  MACRO (ngl), \
+  MACRO (lt),  \
+  MACRO (nge), \
+  MACRO (le),  \
+  MACRO (ngt)
+
+/* Enumerates the codes above as MIPS_FP_COND_<X>.  */
+#define DECLARE_MIPS_COND(X) MIPS_FP_COND_ ## X
+enum mips_fp_condition {
+  MIPS_FP_CONDITIONS (DECLARE_MIPS_COND)
+};
+
+/* Index X provides the string representation of MIPS_FP_COND_<X>.  */
+#define STRINGIFY(X) #X
+static const char *const mips_fp_conditions[] = {
+  MIPS_FP_CONDITIONS (STRINGIFY)
+};
+
 /* A function to save or store a register.  The first argument is the
    register and the second is the stack slot.  */
 typedef void (*mips_save_restore_fn) (rtx, rtx);
@@ -154,23 +269,22 @@ struct mips_sim;
 static enum mips_symbol_type mips_classify_symbol (rtx);
 static void mips_split_const (rtx, rtx *, HOST_WIDE_INT *);
 static bool mips_offset_within_object_p (rtx, HOST_WIDE_INT);
-static bool mips_symbolic_constant_p (rtx, enum mips_symbol_type *);
 static bool mips_valid_base_register_p (rtx, enum machine_mode, int);
 static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode);
 static bool mips_classify_address (struct mips_address_info *, rtx,
                                   enum machine_mode, int);
+static bool mips_cannot_force_const_mem (rtx);
+static bool mips_use_blocks_for_constant_p (enum machine_mode, rtx);
 static int mips_symbol_insns (enum mips_symbol_type);
 static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
 static rtx mips_force_temporary (rtx, rtx);
-static rtx mips_split_symbol (rtx, rtx);
 static rtx mips_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
-static rtx mips_add_offset (rtx, HOST_WIDE_INT);
+static rtx mips_add_offset (rtx, rtx, HOST_WIDE_INT);
 static unsigned int mips_build_shift (struct mips_integer_op *, HOST_WIDE_INT);
 static unsigned int mips_build_lower (struct mips_integer_op *,
                                      unsigned HOST_WIDE_INT);
 static unsigned int mips_build_integer (struct mips_integer_op *,
                                        unsigned HOST_WIDE_INT);
-static void mips_move_integer (rtx, unsigned HOST_WIDE_INT);
 static void mips_legitimize_const_move (enum machine_mode, rtx, rtx);
 static int m16_check_op (rtx, int, int, int);
 static bool mips_rtx_costs (rtx, int, int, int *);
@@ -186,13 +300,16 @@ static void mips_arg_info (const CUMULATIVE_ARGS *, enum machine_mode,
 static bool mips_get_unaligned_mem (rtx *, unsigned int, int, rtx *, rtx *);
 static void mips_set_architecture (const struct mips_cpu_info *);
 static void mips_set_tune (const struct mips_cpu_info *);
+static bool mips_handle_option (size_t, const char *, int);
 static struct machine_function *mips_init_machine_status (void);
 static void print_operand_reloc (FILE *, rtx, const char **);
-static bool mips_assemble_integer (rtx, unsigned int, int);
+#if TARGET_IRIX
+static void irix_output_external_libcall (rtx);
+#endif
 static void mips_file_start (void);
 static void mips_file_end (void);
 static bool mips_rewrite_small_data_p (rtx);
-static int small_data_pattern_1 (rtx *, void *);
+static int mips_small_data_pattern_1 (rtx *, void *);
 static int mips_rewrite_small_data_1 (rtx *, void *);
 static bool mips_function_has_gp_insn (void);
 static unsigned int mips_global_pointer        (void);
@@ -211,11 +328,11 @@ static void mips_restore_reg (rtx, rtx);
 static void mips_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                  HOST_WIDE_INT, tree);
 static int symbolic_expression_p (rtx);
-static void mips_select_rtx_section (enum machine_mode, rtx,
-                                    unsigned HOST_WIDE_INT);
-static void mips_select_section (tree, int, unsigned HOST_WIDE_INT)
-                                 ATTRIBUTE_UNUSED;
+static section *mips_select_rtx_section (enum machine_mode, rtx,
+                                        unsigned HOST_WIDE_INT);
+static section *mips_function_rodata_section (tree);
 static bool mips_in_small_data_p (tree);
+static bool mips_use_anchors_for_symbol_p (rtx);
 static int mips_fpr_return_fields (tree, tree *);
 static bool mips_return_in_msb (tree);
 static rtx mips_return_fpr_pair (enum machine_mode mode,
@@ -249,7 +366,7 @@ static void mips_avoid_hazards (void);
 static void mips_reorg (void);
 static bool mips_strict_matching_cpu_name_p (const char *, const char *);
 static bool mips_matching_cpu_name_p (const char *, const char *);
-static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
+static const struct mips_cpu_info *mips_parse_cpu (const char *);
 static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
 static bool mips_return_in_memory (tree, tree);
 static bool mips_strict_argument_naming (CUMULATIVE_ARGS *);
@@ -272,19 +389,27 @@ static tree mips_build_builtin_va_list (void);
 static tree mips_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 static bool mips_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode mode,
                                    tree, bool);
-
-#if TARGET_IRIX
-static void irix_asm_named_section_1 (const char *, unsigned int,
-                                     unsigned int);
-static void irix_asm_named_section (const char *, unsigned int);
-static int irix_section_align_entry_eq (const void *, const void *);
-static hashval_t irix_section_align_entry_hash (const void *);
-static void irix_file_start (void);
-static int irix_section_align_1 (void **, void *);
-static void copy_file_data (FILE *, FILE *);
-static void irix_file_end (void);
-static unsigned int irix_section_type_flags (tree, const char *, int);
-#endif
+static bool mips_callee_copies (CUMULATIVE_ARGS *, enum machine_mode mode,
+                               tree, bool);
+static int mips_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode mode,
+                                  tree, bool);
+static bool mips_valid_pointer_mode (enum machine_mode);
+static bool mips_vector_mode_supported_p (enum machine_mode);
+static rtx mips_prepare_builtin_arg (enum insn_code, unsigned int, tree *);
+static rtx mips_prepare_builtin_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, bool);
+static rtx mips_expand_builtin_movtf (enum mips_builtin_type,
+                                     enum insn_code, enum mips_fp_condition,
+                                     rtx, tree);
+static rtx mips_expand_builtin_compare (enum mips_builtin_type,
+                                       enum insn_code, enum mips_fp_condition,
+                                       rtx, tree);
+static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx);
+static void mips_encode_section_info (tree, rtx, int);
+static void mips_extra_live_on_entry (bitmap);
+static int mips_mode_rep_extended (enum machine_mode, enum machine_mode);
 
 /* Structure to be filled in by compute_frame_size with register
    save masks, and offsets for the current function.  */
@@ -313,6 +438,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;
 
@@ -338,14 +467,15 @@ struct mips_arg_info
      would have been if we hadn't run out of registers.  */
   bool fpr_p;
 
-  /* The argument's size, in bytes.  */
-  unsigned int num_bytes;
-
   /* The number of words passed in registers, rounded up.  */
   unsigned int reg_words;
 
-  /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
-     or MAX_ARGS_IN_REGISTERS if the argument is passed entirely
+  /* For EABI, the offset of the first register from GP_ARG_FIRST or
+     FP_ARG_FIRST.  For other ABIs, the offset of the first register from
+     the start of the ABI's argument structure (see the CUMULATIVE_ARGS
+     comment for details).
+
+     The value is MAX_ARGS_IN_REGISTERS if the argument is passed entirely
      on the stack.  */
   unsigned int reg_offset;
 
@@ -462,13 +592,10 @@ const struct mips_cpu_info *mips_tune_info;
 int mips_isa;
 
 /* Which ABI to use.  */
-int mips_abi;
+int mips_abi = MIPS_ABI_DEFAULT;
 
-/* Strings to hold which cpu and instruction set architecture to use.  */
-const char *mips_arch_string;   /* for -march=<xxx> */
-const char *mips_tune_string;   /* for -mtune=<xxx> */
-const char *mips_isa_string;   /* for -mips{1,2,3,4} */
-const char *mips_abi_string;   /* for -mabi={32,n32,64,eabi} */
+/* 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
@@ -476,7 +603,8 @@ const char *mips_abi_string;        /* for -mabi={32,n32,64,eabi} */
    should arrange to call mips32 hard floating point code.  */
 int mips16_hard_float;
 
-const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
+/* The architecture selected by -mipsN.  */
+static const struct mips_cpu_info *mips_isa_info;
 
 /* If TRUE, we split addresses into their high and low parts in the RTL.  */
 int mips_split_addresses;
@@ -501,7 +629,7 @@ static GTY (()) int mips_output_filename_first_time = 1;
 
 /* mips_split_p[X] is true if symbols of type X can be split by
    mips_split_symbol().  */
-static bool mips_split_p[NUM_SYMBOL_TYPES];
+bool mips_split_p[NUM_SYMBOL_TYPES];
 
 /* mips_lo_relocs[X] is the relocation to use when a symbol of type X
    appears in a LO_SUM.  It can be null if such LO_SUMs aren't valid or
@@ -514,7 +642,7 @@ static const char *mips_hi_relocs[NUM_SYMBOL_TYPES];
 /* Map hard register number to register class */
 const enum reg_class mips_regno_to_class[] =
 {
-  LEA_REGS,    LEA_REGS,       M16_NA_REGS,    M16_NA_REGS,
+  LEA_REGS,    LEA_REGS,       M16_NA_REGS,    V1_REG,
   M16_REGS,    M16_REGS,       M16_REGS,       M16_REGS,
   LEA_REGS,    LEA_REGS,       LEA_REGS,       LEA_REGS,
   LEA_REGS,    LEA_REGS,       LEA_REGS,       LEA_REGS,
@@ -557,11 +685,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
@@ -609,13 +744,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 },
@@ -623,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
@@ -634,8 +1044,8 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
 #undef TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
-#undef TARGET_ASM_INTEGER
-#define TARGET_ASM_INTEGER mips_assemble_integer
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
 
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE mips_output_function_prologue
@@ -643,6 +1053,8 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #define TARGET_ASM_FUNCTION_EPILOGUE mips_output_function_epilogue
 #undef TARGET_ASM_SELECT_RTX_SECTION
 #define TARGET_ASM_SELECT_RTX_SECTION mips_select_rtx_section
+#undef TARGET_ASM_FUNCTION_RODATA_SECTION
+#define TARGET_ASM_FUNCTION_RODATA_SECTION mips_function_rodata_section
 
 #undef TARGET_SCHED_REORDER
 #define TARGET_SCHED_REORDER mips_sched_reorder
@@ -656,6 +1068,17 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
   mips_multipass_dfa_lookahead
 
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS            \
+  (TARGET_DEFAULT                              \
+   | TARGET_CPU_DEFAULT                                \
+   | TARGET_ENDIAN_DEFAULT                     \
+   | TARGET_FP_EXCEPTIONS_DEFAULT              \
+   | MASK_CHECK_ZERO_DIV                       \
+   | MASK_FUSED_MADD)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION mips_handle_option
+
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL mips_function_ok_for_sibcall
 
@@ -674,21 +1097,11 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 
 #undef TARGET_ASM_FILE_START
 #undef TARGET_ASM_FILE_END
-#if TARGET_IRIX
-#define TARGET_ASM_FILE_START irix_file_start
-#define TARGET_ASM_FILE_END irix_file_end
-#else
 #define TARGET_ASM_FILE_START mips_file_start
 #define TARGET_ASM_FILE_END mips_file_end
-#endif
 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 
-#if TARGET_IRIX
-#undef TARGET_SECTION_TYPE_FLAGS
-#define TARGET_SECTION_TYPE_FLAGS irix_section_type_flags
-#endif
-
 #undef TARGET_INIT_LIBFUNCS
 #define TARGET_INIT_LIBFUNCS mips_init_libfuncs
 
@@ -722,6 +1135,45 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
 #undef TARGET_PASS_BY_REFERENCE
 #define TARGET_PASS_BY_REFERENCE mips_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES mips_callee_copies
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES mips_arg_partial_bytes
+
+#undef TARGET_MODE_REP_EXTENDED
+#define TARGET_MODE_REP_EXTENDED mips_mode_rep_extended
+
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P mips_vector_mode_supported_p
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS mips_init_builtins
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN mips_expand_builtin
+
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM mips_cannot_force_const_mem
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO mips_encode_section_info
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE mips_attribute_table
+
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry
+
+#undef TARGET_MIN_ANCHOR_OFFSET
+#define TARGET_MIN_ANCHOR_OFFSET -32768
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET 32767
+#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
+#define TARGET_USE_BLOCKS_FOR_CONSTANT_P mips_use_blocks_for_constant_p
+#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
+#define TARGET_USE_ANCHORS_FOR_SYMBOL_P mips_use_anchors_for_symbol_p
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
@@ -734,26 +1186,23 @@ mips_classify_symbol (rtx x)
     {
       if (TARGET_MIPS16)
        return SYMBOL_CONSTANT_POOL;
-      if (TARGET_ABICALLS)
+      if (TARGET_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
        return SYMBOL_GOT_LOCAL;
       return SYMBOL_GENERAL;
     }
 
-  if (GET_CODE (x) != SYMBOL_REF)
-    abort ();
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+  if (SYMBOL_REF_TLS_MODEL (x))
+    return SYMBOL_TLS;
 
   if (CONSTANT_POOL_ADDRESS_P (x))
     {
       if (TARGET_MIPS16)
        return SYMBOL_CONSTANT_POOL;
 
-      if (TARGET_ABICALLS)
-       return SYMBOL_GOT_LOCAL;
-
       if (GET_MODE_SIZE (get_pool_mode (x)) <= mips_section_threshold)
        return SYMBOL_SMALL_DATA;
-
-      return SYMBOL_GENERAL;
     }
 
   if (SYMBOL_REF_SMALL_P (x))
@@ -762,32 +1211,43 @@ mips_classify_symbol (rtx x)
   if (TARGET_ABICALLS)
     {
       if (SYMBOL_REF_DECL (x) == 0)
-       return SYMBOL_REF_LOCAL_P (x) ? SYMBOL_GOT_LOCAL : SYMBOL_GOT_GLOBAL;
-
-      /* There are three cases to consider:
-
-            - o32 PIC (either with or without explicit relocs)
-            - n32/n64 PIC without explicit relocs
-            - n32/n64 PIC with explicit relocs
-
-         In the first case, both local and global accesses will use an
-         R_MIPS_GOT16 relocation.  We must correctly predict which of
-         the two semantics (local or global) the assembler and linker
-         will apply.  The choice doesn't depend on the symbol's
-         visibility, so we deliberately ignore decl_visibility and
-         binds_local_p here.
-
-         In the second case, the assembler will not use R_MIPS_GOT16
-         relocations, but it chooses between local and global accesses
-         in the same way as for o32 PIC.
-
-         In the third case we have more freedom since both forms of
-         access will work for any kind of symbol.  However, there seems
-         little point in doing things differently.  */
-      if (DECL_P (SYMBOL_REF_DECL (x)) && TREE_PUBLIC (SYMBOL_REF_DECL (x)))
-       return SYMBOL_GOT_GLOBAL;
+       {
+         if (!SYMBOL_REF_LOCAL_P (x))
+           return SYMBOL_GOT_GLOBAL;
+       }
+      else
+       {
+         /* Don't use GOT accesses for locally-binding symbols if
+            TARGET_ABSOLUTE_ABICALLS.  Otherwise, there are three
+            cases to consider:
+
+               - o32 PIC (either with or without explicit relocs)
+               - n32/n64 PIC without explicit relocs
+               - n32/n64 PIC with explicit relocs
+
+            In the first case, both local and global accesses will use an
+            R_MIPS_GOT16 relocation.  We must correctly predict which of
+            the two semantics (local or global) the assembler and linker
+            will apply.  The choice doesn't depend on the symbol's
+            visibility, so we deliberately ignore decl_visibility and
+            binds_local_p here.
+
+            In the second case, the assembler will not use R_MIPS_GOT16
+            relocations, but it chooses between local and global accesses
+            in the same way as for o32 PIC.
+
+            In the third case we have more freedom since both forms of
+            access will work for any kind of symbol.  However, there seems
+            little point in doing things differently.  */
+         if (DECL_P (SYMBOL_REF_DECL (x))
+             && TREE_PUBLIC (SYMBOL_REF_DECL (x))
+             && !(TARGET_ABSOLUTE_ABICALLS
+                  && targetm.binds_local_p (SYMBOL_REF_DECL (x))))
+           return SYMBOL_GOT_GLOBAL;
+       }
 
-      return SYMBOL_GOT_LOCAL;
+      if (!TARGET_ABSOLUTE_ABICALLS)
+       return SYMBOL_GOT_LOCAL;
     }
 
   return SYMBOL_GENERAL;
@@ -815,7 +1275,7 @@ mips_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
 
 
 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
-   to the same object as SYMBOL.  */
+   to the same object as SYMBOL, or to the same object_block.  */
 
 static bool
 mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
@@ -833,6 +1293,13 @@ mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
       && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
     return true;
 
+  if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol)
+      && SYMBOL_REF_BLOCK (symbol)
+      && SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0
+      && ((unsigned HOST_WIDE_INT) offset + SYMBOL_REF_BLOCK_OFFSET (symbol)
+         < (unsigned HOST_WIDE_INT) SYMBOL_REF_BLOCK (symbol)->size))
+    return true;
+
   return false;
 }
 
@@ -841,7 +1308,7 @@ mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
    the same way as a bare symbol.  If it is, store the type of the
    symbol in *SYMBOL_TYPE.  */
 
-static bool
+bool
 mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
 {
   HOST_WIDE_INT offset;
@@ -850,7 +1317,11 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
   if (UNSPEC_ADDRESS_P (x))
     *symbol_type = UNSPEC_ADDRESS_TYPE (x);
   else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
-    *symbol_type = mips_classify_symbol (x);
+    {
+      *symbol_type = mips_classify_symbol (x);
+      if (*symbol_type == SYMBOL_TLS)
+       return false;
+    }
   else
     return false;
 
@@ -900,9 +1371,15 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
     case SYMBOL_GOTOFF_GLOBAL:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
+    case SYMBOL_TLSGD:
+    case SYMBOL_TLSLDM:
+    case SYMBOL_DTPREL:
+    case SYMBOL_TPREL:
+    case SYMBOL_GOTTPREL:
+    case SYMBOL_TLS:
       return false;
     }
-  abort ();
+  gcc_unreachable ();
 }
 
 
@@ -955,7 +1432,7 @@ mips_valid_base_register_p (rtx x, enum machine_mode mode, int strict)
   if (!strict && GET_CODE (x) == SUBREG)
     x = SUBREG_REG (x);
 
-  return (GET_CODE (x) == REG
+  return (REG_P (x)
          && mips_regno_mode_ok_for_base_p (REGNO (x), mode, strict));
 }
 
@@ -990,12 +1467,18 @@ mips_symbolic_address_p (enum mips_symbol_type symbol_type,
     case SYMBOL_GOTOFF_GLOBAL:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
+    case SYMBOL_TLS:
+    case SYMBOL_TLSGD:
+    case SYMBOL_TLSLDM:
+    case SYMBOL_DTPREL:
+    case SYMBOL_GOTTPREL:
+    case SYMBOL_TPREL:
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
       return true;
     }
-  abort ();
+  gcc_unreachable ();
 }
 
 
@@ -1050,6 +1533,65 @@ mips_classify_address (struct mips_address_info *info, rtx x,
       return false;
     }
 }
+
+/* Return true if X is a thread-local symbol.  */
+
+static bool
+mips_tls_operand_p (rtx x)
+{
+  return GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+/* Return true if X can not be forced into a constant pool.  */
+
+static int
+mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  return mips_tls_operand_p (*x);
+}
+
+/* Return true if X can not be forced into a constant pool.  */
+
+static bool
+mips_cannot_force_const_mem (rtx x)
+{
+  rtx base;
+  HOST_WIDE_INT offset;
+
+  if (!TARGET_MIPS16)
+    {
+      /* As an optimization, reject constants that mips_legitimize_move
+        can expand inline.
+
+        Suppose we have a multi-instruction sequence that loads constant C
+        into register R.  If R does not get allocated a hard register, and
+        R is used in an operand that allows both registers and memory
+        references, reload will consider forcing C into memory and using
+        one of the instruction's memory alternatives.  Returning false
+        here will force it to use an input reload instead.  */
+      if (GET_CODE (x) == CONST_INT)
+       return true;
+
+      mips_split_const (x, &base, &offset);
+      if (symbolic_operand (base, VOIDmode) && SMALL_OPERAND (offset))
+       return true;
+    }
+
+  if (TARGET_HAVE_TLS && for_each_rtx (&x, &mips_tls_symbol_ref_1, 0))
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  MIPS16 uses per-function
+   constant pools, but normal-mode code doesn't need to.  */
+
+static bool
+mips_use_blocks_for_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                               rtx x ATTRIBUTE_UNUSED)
+{
+  return !TARGET_MIPS16;
+}
 \f
 /* Return the number of instructions needed to load a symbol of the
    given type into a register.  If valid in an address, the same number
@@ -1119,12 +1661,32 @@ mips_symbol_insns (enum mips_symbol_type type)
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
+    case SYMBOL_TLSGD:
+    case SYMBOL_TLSLDM:
+    case SYMBOL_DTPREL:
+    case SYMBOL_GOTTPREL:
+    case SYMBOL_TPREL:
       /* Check whether the offset is a 16- or 32-bit value.  */
       return mips_split_p[type] ? 2 : 1;
+
+    case SYMBOL_TLS:
+      /* We don't treat a bare TLS symbol as a constant.  */
+      return 0;
     }
-  abort ();
+  gcc_unreachable ();
 }
 
+/* Return true if X is a legitimate $sp-based address for mode MDOE.  */
+
+bool
+mips_stack_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+         && addr.type == ADDRESS_REG
+         && addr.reg == stack_pointer_rtx);
+}
 
 /* Return true if a value at OFFSET bytes from BASE can be accessed
    using an unextended mips16 instruction.  MODE is the mode of the
@@ -1225,6 +1787,7 @@ mips_const_insns (rtx x)
       return mips_build_integer (codes, INTVAL (x));
 
     case CONST_DOUBLE:
+    case CONST_VECTOR:
       return (!TARGET_MIPS16 && x == CONST0_RTX (GET_MODE (x)) ? 1 : 0);
 
     case CONST:
@@ -1268,9 +1831,7 @@ mips_const_insns (rtx x)
 int
 mips_fetch_insns (rtx x)
 {
-  if (GET_CODE (x) != MEM)
-    abort ();
-
+  gcc_assert (MEM_P (x));
   return mips_address_insns (XEXP (x, 0), GET_MODE (x));
 }
 
@@ -1284,382 +1845,18 @@ mips_idiv_insns (void)
 
   count = 1;
   if (TARGET_CHECK_ZERO_DIV)
-    count += 2;
-  if (TARGET_FIX_R4000 || TARGET_FIX_R4400)
-    count++;
-  return count;
-}
-
-
-/* Return truth value of whether OP can be used as an operands
-   where a register or 16 bit unsigned integer is needed.  */
-
-int
-uns_arith_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))
-    return 1;
-
-  return register_operand (op, mode);
-}
-
-
-/* True if OP can be treated as a signed 16-bit constant.  */
-
-int
-const_arith_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return GET_CODE (op) == CONST_INT && SMALL_INT (op);
-}
-
-
-/* Return true if OP is a register operand or a signed 16-bit constant.  */
-
-int
-arith_operand (rtx op, enum machine_mode mode)
-{
-  return const_arith_operand (op, mode) || register_operand (op, mode);
-}
-
-/* Return true if OP can be used as the second argument to an LE operation.  */
-
-int
-sle_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return GET_CODE (op) == CONST_INT && SMALL_OPERAND (INTVAL (op) + 1);
-}
-
-/* Likewise LEU.  */
-
-int
-sleu_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && INTVAL (op) + 1 != 0
-         && SMALL_OPERAND (INTVAL (op) + 1));
-}
-
-/* Return truth value of whether OP is an integer which fits in 16 bits.  */
-
-int
-small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
-}
-
-/* Return truth value of whether OP is a register or the constant 0.
-   Do not accept 0 in mips16 mode since $0 is not one of the core 8
-   registers.  */
-
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  switch (GET_CODE (op))
-    {
-    case CONST_INT:
-      if (TARGET_MIPS16)
-       return 0;
-      return INTVAL (op) == 0;
-
-    case CONST_DOUBLE:
-      if (TARGET_MIPS16)
-       return 0;
-      return op == CONST0_RTX (mode);
-
-    default:
-      return register_operand (op, mode);
-    }
-}
-
-/* Accept a register or the floating point constant 1 in the
-   appropriate mode.  */
-
-int
-reg_or_const_float_1_operand (rtx op, enum machine_mode mode)
-{
-  return const_float_1_operand (op, mode) || register_operand (op, mode);
-}
-
-/* Accept the floating point constant 1 in the appropriate mode.  */
-
-int
-const_float_1_operand (rtx op, enum machine_mode mode)
-{
-  REAL_VALUE_TYPE d;
-
-  if (GET_CODE (op) != CONST_DOUBLE
-      || mode != GET_MODE (op)
-      || (mode != DFmode && mode != SFmode))
-    return 0;
-
-  REAL_VALUE_FROM_CONST_DOUBLE (d, op);
-
-  return REAL_VALUES_EQUAL (d, dconst1);
-}
-
-/* Return true if OP is either the HI or LO register.  */
-
-int
-hilo_operand (rtx op, enum machine_mode mode)
-{
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && REG_P (op) && MD_REG_P (REGNO (op)));
-}
-
-/* Return true if OP is an extension operator.  */
-
-int
-extend_operator (rtx op, enum machine_mode mode)
-{
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND));
-}
-
-/* Return true if X is the right hand side of a "macc" or "msac" instruction.
-   This predicate is intended for use in peephole optimizations.  */
-
-int
-macc_msac_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (ISA_HAS_MACC && GET_CODE (x) == PLUS && REG_P (XEXP (x, 1)))
-    x = XEXP (x, 0);
-  else if (ISA_HAS_MSAC && GET_CODE (x) == MINUS && REG_P (XEXP (x, 0)))
-    x = XEXP (x, 1);
-  else
-    return false;
-
-  return GET_CODE (x) == MULT && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1));
-}
-
-/* Return nonzero if the code of this rtx pattern is EQ or NE.  */
-
-int
-equality_op (rtx op, enum machine_mode mode)
-{
-  if (mode != GET_MODE (op))
-    return 0;
-
-  return GET_CODE (op) == EQ || GET_CODE (op) == NE;
-}
-
-/* Return nonzero if the code is a relational operations (EQ, LE, etc.) */
-
-int
-cmp_op (rtx op, enum machine_mode mode)
-{
-  if (mode != GET_MODE (op))
-    return 0;
-
-  return COMPARISON_P (op);
-}
-
-/* Return nonzero if the code is a relational operation suitable for a
-   conditional trap instruction (only EQ, NE, LT, LTU, GE, GEU).
-   We need this in the insn that expands `trap_if' in order to prevent
-   combine from erroneously altering the condition.  */
-
-int
-trap_cmp_op (rtx op, enum machine_mode mode)
-{
-  if (mode != GET_MODE (op))
-    return 0;
-
-  switch (GET_CODE (op))
-    {
-    case EQ:
-    case NE:
-    case LT:
-    case LTU:
-    case GE:
-    case GEU:
-      return 1;
-
-    default:
-      return 0;
-    }
-}
-
-/* Return nonzero if the operand is either the PC or a label_ref.  */
-
-int
-pc_or_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (op == pc_rtx)
-    return 1;
-
-  if (GET_CODE (op) == LABEL_REF)
-    return 1;
-
-  return 0;
-}
-
-/* Test for a valid call address.  */
-
-int
-call_insn_operand (rtx op, enum machine_mode mode)
-{
-  enum mips_symbol_type symbol_type;
-
-  if (mips_symbolic_constant_p (op, &symbol_type))
-    switch (symbol_type)
-      {
-      case SYMBOL_GENERAL:
-       /* If -mlong-calls, force all calls to use register addressing.  */
-       return !TARGET_LONG_CALLS;
-
-      case SYMBOL_GOT_GLOBAL:
-       /* Without explicit relocs, there is no special syntax for
-          loading the address of a call destination into a register.
-          Using "la $25,foo; jal $25" would prevent the lazy binding
-          of "foo", so keep the address of global symbols with the
-          jal macro.  */
-       return !TARGET_EXPLICIT_RELOCS;
-
-      default:
-       return false;
-      }
-  return register_operand (op, mode);
-}
-
-
-/* Return nonzero if OP is valid as a source operand for a move
-   instruction.  */
-
-int
-move_operand (rtx op, enum machine_mode mode)
-{
-  enum mips_symbol_type symbol_type;
-
-  if (!general_operand (op, mode))
-    return false;
-
-  switch (GET_CODE (op))
     {
-    case CONST_INT:
-      /* When generating mips16 code, LEGITIMATE_CONSTANT_P rejects
-        CONST_INTs that can't be loaded using simple insns.  */
-      if (TARGET_MIPS16)
-       return true;
-
-      /* When generating 32-bit code, allow DImode move_operands to
-        match arbitrary constants.  We split them after reload.  */
-      if (!TARGET_64BIT && mode == DImode)
-       return true;
-
-      /* Otherwise check whether the constant can be loaded in a single
-        instruction.  */
-      return LUI_INT (op) || SMALL_INT (op) || SMALL_INT_UNSIGNED (op);
-
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      if (CONST_GP_P (op))
-       return true;
-
-      return (mips_symbolic_constant_p (op, &symbol_type)
-             && !mips_split_p[symbol_type]);
-
-    default:
-      return true;
+      if (GENERATE_DIVIDE_TRAPS)
+        count++;
+      else
+        count += 2;
     }
-}
-
-
-/* Accept any operand that can appear in a mips16 constant table
-   instruction.  We can't use any of the standard operand functions
-   because for these instructions we accept values that are not
-   accepted by LEGITIMATE_CONSTANT, such as arbitrary SYMBOL_REFs.  */
-
-int
-consttable_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return CONSTANT_P (op);
-}
-
-/* Return 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
-   possibly with an offset.  */
-
-int
-symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum mips_symbol_type symbol_type;
-
-  return mips_symbolic_constant_p (op, &symbol_type);
-}
-
 
-/* Return true if OP is a symbolic constant of type SYMBOL_GENERAL.  */
-
-int
-general_symbolic_operand (rtx op, enum machine_mode mode)
-{
-  enum mips_symbol_type symbol_type;
-
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && mips_symbolic_constant_p (op, &symbol_type)
-         && symbol_type == SYMBOL_GENERAL);
-}
-
-
-/* Return true if we're generating PIC and OP is a global symbol.  */
-
-int
-global_got_operand (rtx op, enum machine_mode mode)
-{
-  enum mips_symbol_type symbol_type;
-
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && mips_symbolic_constant_p (op, &symbol_type)
-         && symbol_type == SYMBOL_GOT_GLOBAL);
-}
-
-
-/* Likewise for local symbols.  */
-
-int
-local_got_operand (rtx op, enum machine_mode mode)
-{
-  enum mips_symbol_type symbol_type;
-
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && mips_symbolic_constant_p (op, &symbol_type)
-         && symbol_type == SYMBOL_GOT_LOCAL);
-}
-
-
-/* Return true if OP is a memory reference that uses the stack pointer
-   as a base register.  */
-
-int
-stack_operand (rtx op, enum machine_mode mode)
-{
-  struct mips_address_info addr;
-
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && GET_CODE (op) == MEM
-         && mips_classify_address (&addr, XEXP (op, 0), GET_MODE (op), false)
-         && addr.type == ADDRESS_REG
-         && addr.reg == stack_pointer_rtx);
-}
-
-/* Helper function for DFA schedulers.  Return true if OP is a floating
-   point register.  */
-
-int
-fp_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return REG_P (op) && FP_REG_P (REGNO (op));
-}
-
-/* Helper function for DFA schedulers.  Return true if OP is a LO reg.  */
-
-int
-lo_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return REG_P (op) && REGNO (op) == LO_REGNUM;
+  if (TARGET_FIX_R4000 || TARGET_FIX_R4400)
+    count++;
+  return count;
 }
 \f
-
 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS.  It
    returns a nonzero value if X is a legitimate address for a memory
    operand of the indicated MODE.  STRICT is nonzero if this function
@@ -1693,7 +1890,7 @@ mips_force_temporary (rtx dest, rtx value)
 /* Return a LO_SUM expression for ADDR.  TEMP is as for mips_force_temporary
    and is used to load the high part into a register.  */
 
-static rtx
+rtx
 mips_split_symbol (rtx temp, rtx addr)
 {
   rtx high;
@@ -1712,50 +1909,173 @@ mips_split_symbol (rtx temp, rtx addr)
 rtx
 mips_unspec_address (rtx address, enum mips_symbol_type symbol_type)
 {
-  rtx base;
-  HOST_WIDE_INT offset;
+  rtx base;
+  HOST_WIDE_INT offset;
+
+  mips_split_const (address, &base, &offset);
+  base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base),
+                        UNSPEC_ADDRESS_FIRST + symbol_type);
+  return plus_constant (gen_rtx_CONST (Pmode, base), offset);
+}
+
+
+/* If mips_unspec_address (ADDR, SYMBOL_TYPE) is a 32-bit value, add the
+   high part to BASE and return the result.  Just return BASE otherwise.
+   TEMP is available as a temporary register if needed.
+
+   The returned expression can be used as the first operand to a LO_SUM.  */
+
+static rtx
+mips_unspec_offset_high (rtx temp, rtx base, rtx addr,
+                        enum mips_symbol_type symbol_type)
+{
+  if (mips_split_p[symbol_type])
+    {
+      addr = gen_rtx_HIGH (Pmode, mips_unspec_address (addr, symbol_type));
+      addr = mips_force_temporary (temp, addr);
+      return mips_force_temporary (temp, gen_rtx_PLUS (Pmode, addr, base));
+    }
+  return base;
+}
+
+
+/* Return a legitimate address for REG + OFFSET.  TEMP is as for
+   mips_force_temporary; it is only needed when OFFSET is not a
+   SMALL_OPERAND.  */
+
+static rtx
+mips_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
+{
+  if (!SMALL_OPERAND (offset))
+    {
+      rtx high;
+      if (TARGET_MIPS16)
+       {
+         /* Load the full offset into a register so that we can use
+            an unextended instruction for the address itself.  */
+         high = GEN_INT (offset);
+         offset = 0;
+       }
+      else
+       {
+         /* Leave OFFSET as a 16-bit offset and put the excess in HIGH.  */
+         high = GEN_INT (CONST_HIGH_PART (offset));
+         offset = CONST_LOW_PART (offset);
+       }
+      high = mips_force_temporary (temp, high);
+      reg = mips_force_temporary (temp, gen_rtx_PLUS (Pmode, high, reg));
+    }
+  return plus_constant (reg, offset);
+}
+
+/* Emit a call to __tls_get_addr.  SYM is the TLS symbol we are
+   referencing, and TYPE is the symbol type to use (either global
+   dynamic or local dynamic).  V0 is an RTX for the return value
+   location.  The entire insn sequence is returned.  */
+
+static GTY(()) rtx mips_tls_symbol;
+
+static rtx
+mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
+{
+  rtx insn, loc, tga, a0;
 
-  mips_split_const (address, &base, &offset);
-  base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base),
-                        UNSPEC_ADDRESS_FIRST + symbol_type);
-  return plus_constant (gen_rtx_CONST (Pmode, base), offset);
-}
+  a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
 
+  if (!mips_tls_symbol)
+    mips_tls_symbol = init_one_libfunc ("__tls_get_addr");
 
-/* If mips_unspec_address (ADDR, SYMBOL_TYPE) is a 32-bit value, add the
-   high part to BASE and return the result.  Just return BASE otherwise.
-   TEMP is available as a temporary register if needed.
+  loc = mips_unspec_address (sym, type);
 
-   The returned expression can be used as the first operand to a LO_SUM.  */
+  start_sequence ();
+
+  emit_insn (gen_rtx_SET (Pmode, a0,
+                         gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
+  tga = gen_rtx_MEM (Pmode, mips_tls_symbol);
+  insn = emit_call_insn (gen_call_value (v0, tga, const0_rtx, const0_rtx));
+  CONST_OR_PURE_CALL_P (insn) = 1;
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), v0);
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
+  insn = get_insns ();
+
+  end_sequence ();
+
+  return insn;
+}
+
+/* Generate the code to access LOC, a thread local SYMBOL_REF.  The
+   return value will be a valid address and move_operand (either a REG
+   or a LO_SUM).  */
 
 static rtx
-mips_unspec_offset_high (rtx temp, rtx base, rtx addr,
-                        enum mips_symbol_type symbol_type)
+mips_legitimize_tls_address (rtx loc)
 {
-  if (mips_split_p[symbol_type])
+  rtx dest, insn, v0, v1, tmp1, tmp2, eqv;
+  enum tls_model model;
+
+  v0 = gen_rtx_REG (Pmode, GP_RETURN);
+  v1 = gen_rtx_REG (Pmode, GP_RETURN + 1);
+
+  model = SYMBOL_REF_TLS_MODEL (loc);
+
+  switch (model)
     {
-      addr = gen_rtx_HIGH (Pmode, mips_unspec_address (addr, symbol_type));
-      addr = mips_force_temporary (temp, addr);
-      return mips_force_temporary (temp, gen_rtx_PLUS (Pmode, addr, base));
-    }
-  return base;
-}
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      insn = mips_call_tls_get_addr (loc, SYMBOL_TLSGD, v0);
+      dest = gen_reg_rtx (Pmode);
+      emit_libcall_block (insn, dest, v0, loc);
+      break;
 
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      insn = mips_call_tls_get_addr (loc, SYMBOL_TLSLDM, v0);
+      tmp1 = gen_reg_rtx (Pmode);
 
-/* Return a legitimate address for REG + OFFSET.  This function will
-   create a temporary register if OFFSET is not a SMALL_OPERAND.  */
+      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+        share the LDM result with other LD model accesses.  */
+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+                           UNSPEC_TLS_LDM);
+      emit_libcall_block (insn, tmp1, v0, eqv);
 
-static rtx
-mips_add_offset (rtx reg, HOST_WIDE_INT offset)
-{
-  if (!SMALL_OPERAND (offset))
-    reg = expand_simple_binop (GET_MODE (reg), PLUS,
-                              GEN_INT (CONST_HIGH_PART (offset)),
-                              reg, NULL, 0, OPTAB_WIDEN);
+      tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
+      dest = gen_rtx_LO_SUM (Pmode, tmp2,
+                            mips_unspec_address (loc, SYMBOL_DTPREL));
+      break;
 
-  return plus_constant (reg, CONST_LOW_PART (offset));
-}
+    case TLS_MODEL_INITIAL_EXEC:
+      tmp1 = gen_reg_rtx (Pmode);
+      tmp2 = mips_unspec_address (loc, SYMBOL_GOTTPREL);
+      if (Pmode == DImode)
+       {
+         emit_insn (gen_tls_get_tp_di (v1));
+         emit_insn (gen_load_gotdi (tmp1, pic_offset_table_rtx, tmp2));
+       }
+      else
+       {
+         emit_insn (gen_tls_get_tp_si (v1));
+         emit_insn (gen_load_gotsi (tmp1, pic_offset_table_rtx, tmp2));
+       }
+      dest = gen_reg_rtx (Pmode);
+      emit_insn (gen_add3_insn (dest, tmp1, v1));
+      break;
+
+    case TLS_MODEL_LOCAL_EXEC:
+
+      if (Pmode == DImode)
+       emit_insn (gen_tls_get_tp_di (v1));
+      else
+       emit_insn (gen_tls_get_tp_si (v1));
+
+      tmp1 = mips_unspec_offset_high (NULL, v1, loc, SYMBOL_TPREL);
+      dest = gen_rtx_LO_SUM (Pmode, tmp1,
+                            mips_unspec_address (loc, SYMBOL_TPREL));
+      break;
 
+    default:
+      gcc_unreachable ();
+    }
+
+  return dest;
+}
 
 /* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can
    be legitimized in a way that the generic machinery might not expect,
@@ -1767,6 +2087,12 @@ mips_legitimize_address (rtx *xloc, enum machine_mode mode)
 {
   enum mips_symbol_type symbol_type;
 
+  if (mips_tls_operand_p (*xloc))
+    {
+      *xloc = mips_legitimize_tls_address (*xloc);
+      return true;
+    }
+
   /* See if the address can split into a high part and a LO_SUM.  */
   if (mips_symbolic_constant_p (*xloc, &symbol_type)
       && mips_symbolic_address_p (symbol_type, mode)
@@ -1784,7 +2110,7 @@ mips_legitimize_address (rtx *xloc, enum machine_mode mode)
       reg = XEXP (*xloc, 0);
       if (!mips_valid_base_register_p (reg, mode, 0))
        reg = copy_to_mode_reg (Pmode, reg);
-      *xloc = mips_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
+      *xloc = mips_add_offset (0, reg, INTVAL (XEXP (*xloc, 1)));
       return true;
     }
 
@@ -1856,7 +2182,7 @@ mips_build_integer (struct mips_integer_op *codes,
       || LUI_OPERAND (value))
     {
       /* The value can be loaded with a single instruction.  */
-      codes[0].code = NIL;
+      codes[0].code = UNKNOWN;
       codes[0].value = value;
       return 1;
     }
@@ -1894,10 +2220,10 @@ mips_build_integer (struct mips_integer_op *codes,
 }
 
 
-/* Move VALUE into register DEST.  */
+/* Load VALUE into DEST, using TEMP as a temporary register if need be.  */
 
-static void
-mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
+void
+mips_move_integer (rtx dest, rtx temp, unsigned HOST_WIDE_INT value)
 {
   struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
   enum machine_mode mode;
@@ -1913,7 +2239,10 @@ mips_move_integer (rtx dest, unsigned HOST_WIDE_INT value)
   for (i = 1; i < cost; i++)
     {
       if (no_new_pseudos)
-       emit_move_insn (dest, x), x = dest;
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, temp, x));
+         x = temp;
+       }
       else
        x = force_reg (mode, x);
       x = gen_rtx_fmt_ee (codes[i].code, mode, x, GEN_INT (codes[i].value));
@@ -1932,24 +2261,24 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
 {
   rtx base;
   HOST_WIDE_INT offset;
-  enum mips_symbol_type symbol_type;
 
-  /* Split moves of big integers into smaller pieces.  In mips16 code,
-     it's better to force the constant into memory instead.  */
-  if (GET_CODE (src) == CONST_INT && !TARGET_MIPS16)
+  /* Split moves of big integers into smaller pieces.  */
+  if (splittable_const_int_operand (src, mode))
     {
-      mips_move_integer (dest, INTVAL (src));
+      mips_move_integer (dest, dest, INTVAL (src));
       return;
     }
 
-  /* See if the symbol can be split.  For mips16, this is often worse than
-     forcing it in the constant pool since it needs the single-register form
-     of addiu or daddiu.  */
-  if (!TARGET_MIPS16
-      && mips_symbolic_constant_p (src, &symbol_type)
-      && mips_split_p[symbol_type])
+  /* Split moves of symbolic constants into high/low pairs.  */
+  if (splittable_symbolic_operand (src, mode))
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, dest, mips_split_symbol (dest, src)));
+      return;
+    }
+
+  if (mips_tls_operand_p (src))
     {
-      emit_move_insn (dest, mips_split_symbol (dest, src));
+      emit_move_insn (dest, mips_legitimize_tls_address (src));
       return;
     }
 
@@ -1962,7 +2291,7 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
       && (!no_new_pseudos || SMALL_OPERAND (offset)))
     {
       base = mips_force_temporary (dest, base);
-      emit_move_insn (dest, mips_add_offset (base, offset));
+      emit_move_insn (dest, mips_add_offset (0, base, offset));
       return;
     }
 
@@ -2130,75 +2459,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 unnessarily 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:
@@ -2218,15 +2550,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:
@@ -2259,7 +2591,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);
@@ -2271,19 +2603,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;
@@ -2293,115 +2619,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:
@@ -2423,6 +2680,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;
     }
@@ -2456,15 +2722,15 @@ mips_subword (rtx op, int high_p)
   else
     byte = 0;
 
-  if (GET_CODE (op) == REG)
+  if (REG_P (op))
     {
       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 (GET_CODE (op) == MEM)
+  if (MEM_P (op))
     return mips_rewrite_small_data (adjust_address (op, word_mode, byte));
 
   return simplify_gen_subreg (word_mode, op, mode, byte);
@@ -2487,9 +2753,9 @@ mips_split_64bit_move_p (rtx dest, rtx src)
      ldc1 and sdc1 on MIPS II and above.  */
   if (mips_isa > 1)
     {
-      if (FP_REG_RTX_P (dest) && GET_CODE (src) == MEM)
+      if (FP_REG_RTX_P (dest) && MEM_P (src))
        return false;
-      if (FP_REG_RTX_P (src) && GET_CODE (dest) == MEM)
+      if (FP_REG_RTX_P (src) && MEM_P (dest))
        return false;
     }
   return true;
@@ -2534,7 +2800,7 @@ mips_split_64bit_move (rtx dest, rtx src)
       rtx low_dest;
 
       low_dest = mips_subword (dest, 0);
-      if (GET_CODE (low_dest) == REG
+      if (REG_P (low_dest)
          && reg_overlap_mentioned_p (low_dest, src))
        {
          emit_move_insn (mips_subword (dest, 1), mips_subword (src, 1));
@@ -2575,6 +2841,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");
 
@@ -2593,6 +2867,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";
 
@@ -2637,7 +2919,12 @@ mips_output_move (rtx dest, rtx src)
   if (src_code == REG && FP_REG_P (REGNO (src)))
     {
       if (dest_code == REG && FP_REG_P (REGNO (dest)))
-       return (dbl_p ? "mov.d\t%0,%1" : "mov.s\t%0,%1");
+       {
+         if (GET_MODE (dest) == V2SFmode)
+           return "mov.ps\t%0,%1";
+         else
+           return (dbl_p ? "mov.d\t%0,%1" : "mov.s\t%0,%1");
+       }
 
       if (dest_code == MEM)
        return (dbl_p ? "sdc1\t%1,%0" : "swc1\t%1,%0");
@@ -2663,28 +2950,29 @@ mips_output_move (rtx dest, rtx src)
       retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (src));
       return retval;
     }
-  abort ();
+  gcc_unreachable ();
 }
 \f
-/* Return an rtx for the gp save slot.  Valid only when using o32 or
+/* Restore $gp from its save slot.  Valid only when using o32 or
    o64 abicalls.  */
 
-rtx
-mips_gp_save_slot (void)
+void
+mips_restore_gp (void)
 {
-  rtx loc;
+  rtx address, slot;
 
-  if (!TARGET_ABICALLS || TARGET_NEWABI)
-    abort ();
+  gcc_assert (TARGET_ABICALLS && TARGET_OLDABI);
 
-  if (frame_pointer_needed)
-    loc = hard_frame_pointer_rtx;
-  else
-    loc = stack_pointer_rtx;
-  loc = plus_constant (loc, current_function_outgoing_args_size);
-  loc = gen_rtx_MEM (Pmode, loc);
-  RTX_UNCHANGING_P (loc) = 1;
-  return loc;
+  address = mips_add_offset (pic_offset_table_rtx,
+                            frame_pointer_needed
+                            ? hard_frame_pointer_rtx
+                            : stack_pointer_rtx,
+                            current_function_outgoing_args_size);
+  slot = gen_rtx_MEM (Pmode, address);
+
+  emit_move_insn (pic_offset_table_rtx, slot);
+  if (!TARGET_EXPLICIT_RELOCS)
+    emit_insn (gen_blockage ());
 }
 \f
 /* Emit an instruction of the form (set TARGET (CODE OP0 OP1)).  */
@@ -2723,10 +3011,54 @@ mips_relational_operand_ok_p (enum rtx_code code, rtx cmp1)
       return sleu_operand (cmp1, VOIDmode);
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
+/* 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
@@ -2737,11 +3069,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);
@@ -2781,6 +3116,27 @@ mips_zero_if_equal (rtx cmp0, rtx cmp1)
                       cmp0, cmp1, 0, 0, OPTAB_DIRECT);
 }
 
+/* Convert *CODE into a code that can be used in a floating-point
+   scc instruction (c.<cond>.<fmt>).  Return true if the values of
+   the condition code registers will be inverted, with 0 indicating
+   that the condition holds.  */
+
+static bool
+mips_reverse_fp_cond_p (enum rtx_code *code)
+{
+  switch (*code)
+    {
+    case NE:
+    case LTGT:
+    case ORDERED:
+      *code = reverse_condition_maybe_unordered (*code);
+      return true;
+
+    default:
+      return false;
+    }
+}
+
 /* Convert a comparison into something that can be used in a branch or
    conditional move.  cmp_operands[0] and cmp_operands[1] are the values
    being compared and *CODE is the code used to compare them.
@@ -2838,22 +3194,8 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
 
         Set CMP_CODE to the code of the comparison instruction and
         *CODE to the code that the branch or move should use.  */
-      switch (*code)
-       {
-       case NE:
-       case UNGE:
-       case UNGT:
-       case LTGT:
-       case ORDERED:
-         cmp_code = reverse_condition_maybe_unordered (*code);
-         *code = EQ;
-         break;
-
-       default:
-         cmp_code = *code;
-         *code = NE;
-         break;
-       }
+      cmp_code = *code;
+      *code = mips_reverse_fp_cond_p (&cmp_code) ? EQ : NE;
       *op0 = (ISA_HAS_8CC
              ? gen_reg_rtx (CCmode)
              : gen_rtx_REG (CCmode, FPSW_REGNUM));
@@ -2892,15 +3234,35 @@ mips_emit_scc (enum rtx_code code, rtx target)
 void
 gen_conditional_branch (rtx *operands, enum rtx_code code)
 {
-  rtx op0, op1, target;
+  rtx op0, op1, condition;
 
   mips_emit_compare (&code, &op0, &op1, TARGET_MIPS16);
-  target = gen_rtx_IF_THEN_ELSE (VOIDmode,
-                                gen_rtx_fmt_ee (code, GET_MODE (op0),
-                                                op0, op1),
-                                gen_rtx_LABEL_REF (VOIDmode, operands[0]),
-                                pc_rtx);
-  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, target));
+  condition = gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+  emit_jump_insn (gen_condjump (condition, operands[0]));
+}
+
+/* Implement:
+
+   (set temp (COND:CCV2 CMP_OP0 CMP_OP1))
+   (set DEST (unspec [TRUE_SRC FALSE_SRC temp] UNSPEC_MOVE_TF_PS))  */
+
+void
+mips_expand_vcondv2sf (rtx dest, rtx true_src, rtx false_src,
+                      enum rtx_code cond, rtx cmp_op0, rtx cmp_op1)
+{
+  rtx cmp_result;
+  bool reversed_p;
+
+  reversed_p = mips_reverse_fp_cond_p (&cond);
+  cmp_result = gen_reg_rtx (CCV2mode);
+  emit_insn (gen_scc_ps (cmp_result,
+                        gen_rtx_fmt_ee (cond, VOIDmode, cmp_op0, cmp_op1)));
+  if (reversed_p)
+    emit_insn (gen_mips_cond_move_tf_ps (dest, false_src, true_src,
+                                        cmp_result));
+  else
+    emit_insn (gen_mips_cond_move_tf_ps (dest, true_src, false_src,
+                                        cmp_result));
 }
 
 /* Emit the common code for conditional moves.  OPERANDS is the array
@@ -2916,7 +3278,8 @@ gen_conditional_move (rtx *operands)
   mips_emit_compare (&code, &op0, &op1, true);
   emit_insn (gen_rtx_SET (VOIDmode, operands[0],
                          gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
-                                               gen_rtx_fmt_ee (code, VOIDmode,
+                                               gen_rtx_fmt_ee (code,
+                                                               GET_MODE (op0),
                                                                op0, op1),
                                                operands[2], operands[3])));
 }
@@ -2944,20 +3307,20 @@ mips_gen_conditional_trap (rtx *operands)
     }
   if (cmp_code == GET_CODE (operands[0]))
     {
-      op0 = force_reg (mode, cmp_operands[0]);
+      op0 = cmp_operands[0];
       op1 = cmp_operands[1];
     }
   else
     {
-      op0 = force_reg (mode, cmp_operands[1]);
+      op0 = cmp_operands[1];
       op1 = cmp_operands[0];
     }
-  if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
+  op0 = force_reg (mode, op0);
+  if (!arith_operand (op1, mode))
     op1 = force_reg (mode, op1);
 
   emit_insn (gen_rtx_TRAP_IF (VOIDmode,
-                             gen_rtx_fmt_ee (cmp_code, GET_MODE (operands[0]),
-                                             op0, op1),
+                             gen_rtx_fmt_ee (cmp_code, mode, op0, op1),
                              operands[1]));
 }
 \f
@@ -3052,18 +3415,6 @@ mips_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
   return TARGET_SIBCALLS;
 }
 \f
-/* Return true if operand OP is a condition code register.
-   Only for use during or after reload.  */
-
-int
-fcc_register_operand (rtx op, enum machine_mode mode)
-{
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && (reload_in_progress || reload_completed)
-         && (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
-         && ST_REG_P (true_regnum (op)));
-}
-
 /* Emit code to move general operand SRC into condition-code
    register DEST.  SCRATCH is a scratch TFmode float register.
    The sequence is:
@@ -3081,9 +3432,9 @@ mips_emit_fcc_reload (rtx dest, rtx src, rtx scratch)
   rtx fp1, fp2;
 
   /* Change the source to SFmode.  */
-  if (GET_CODE (src) == MEM)
+  if (MEM_P (src))
     src = adjust_address (src, SFmode, 0);
-  else if (GET_CODE (src) == REG || GET_CODE (src) == SUBREG)
+  else if (REG_P (src) || GET_CODE (src) == SUBREG)
     src = gen_rtx_REG (SFmode, true_regnum (src));
 
   fp1 = gen_rtx_REG (SFmode, REGNO (scratch));
@@ -3101,26 +3452,14 @@ mips_emit_fcc_reload (rtx dest, rtx src, rtx scratch)
 void
 mips_set_return_address (rtx address, rtx scratch)
 {
-  HOST_WIDE_INT gp_offset;
+  rtx slot_address;
 
   compute_frame_size (get_frame_size ());
-  if (((cfun->machine->frame.mask >> 31) & 1) == 0)
-    abort ();
-  gp_offset = cfun->machine->frame.gp_sp_offset;
-
-  /* Reduce SP + GP_OFSET to a legitimate address and put it in SCRATCH.  */
-  if (gp_offset < 32768)
-    scratch = plus_constant (stack_pointer_rtx, gp_offset);
-  else
-    {
-      emit_move_insn (scratch, GEN_INT (gp_offset));
-      if (Pmode == DImode)
-       emit_insn (gen_adddi3 (scratch, scratch, stack_pointer_rtx));
-      else
-       emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
-    }
+  gcc_assert ((cfun->machine->frame.mask >> 31) & 1);
+  slot_address = mips_add_offset (scratch, stack_pointer_rtx,
+                                 cfun->machine->frame.gp_sp_offset);
 
-  emit_move_insn (gen_rtx_MEM (GET_MODE (address), scratch), address);
+  emit_move_insn (gen_rtx_MEM (GET_MODE (address), slot_address), address);
 }
 \f
 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
@@ -3163,7 +3502,7 @@ mips_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
        {
          rtx part = adjust_address (src, BLKmode, offset);
          if (!mips_expand_unaligned_load (regs[i], part, bits, 0))
-           abort ();
+           gcc_unreachable ();
        }
     }
 
@@ -3175,7 +3514,7 @@ mips_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
       {
        rtx part = adjust_address (dest, BLKmode, offset);
        if (!mips_expand_unaligned_store (part, regs[i], bits, 0))
-         abort ();
+         gcc_unreachable ();
       }
 
   /* Mop up any left-over bytes.  */
@@ -3317,53 +3656,85 @@ static void
 mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
               tree type, int named, struct mips_arg_info *info)
 {
-  bool even_reg_p;
-  unsigned int num_words, max_regs;
+  bool doubleword_aligned_p;
+  unsigned int num_bytes, num_words, max_regs;
 
-  /* Decide whether this argument should go in a floating-point register,
-     assuming one is free.  Later code checks for availability.  */
+  /* Work out the size of the argument.  */
+  num_bytes = type ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+  num_words = (num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
-  info->fpr_p = (GET_MODE_CLASS (mode) == MODE_FLOAT
-                && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE);
+  /* Decide whether it should go in a floating-point register, assuming
+     one is free.  Later code checks for availability.
 
-  if (info->fpr_p)
-    switch (mips_abi)
-      {
-      case ABI_32:
-      case ABI_O64:
-       info->fpr_p = (!cum->gp_reg_found
-                      && cum->arg_number < 2
-                      && (type == 0 || FLOAT_TYPE_P (type)));
-       break;
+     The checks against UNITS_PER_FPVALUE handle the soft-float and
+     single-float cases.  */
+  switch (mips_abi)
+    {
+    case ABI_EABI:
+      /* The EABI conventions have traditionally been defined in terms
+        of TYPE_MODE, regardless of the actual type.  */
+      info->fpr_p = ((GET_MODE_CLASS (mode) == MODE_FLOAT
+                     || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+                    && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE);
+      break;
 
-      case ABI_N32:
-      case ABI_64:
-       info->fpr_p = (named && (type == 0 || FLOAT_TYPE_P (type)));
-       break;
-      }
+    case ABI_32:
+    case ABI_O64:
+      /* Only leading floating-point scalars are passed in
+        floating-point registers.  We also handle vector floats the same
+        say, which is OK because they are not covered by the standard ABI.  */
+      info->fpr_p = (!cum->gp_reg_found
+                    && cum->arg_number < 2
+                    && (type == 0 || SCALAR_FLOAT_TYPE_P (type)
+                        || VECTOR_FLOAT_TYPE_P (type))
+                    && (GET_MODE_CLASS (mode) == MODE_FLOAT
+                        || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+                    && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE);
+      break;
 
-  /* Now decide whether the argument must go in an even-numbered register.  */
+    case ABI_N32:
+    case ABI_64:
+      /* Scalar and complex floating-point types are passed in
+        floating-point registers.  */
+      info->fpr_p = (named
+                    && (type == 0 || FLOAT_TYPE_P (type))
+                    && (GET_MODE_CLASS (mode) == MODE_FLOAT
+                        || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+                        || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+                    && GET_MODE_UNIT_SIZE (mode) <= UNITS_PER_FPVALUE);
+
+      /* ??? According to the ABI documentation, the real and imaginary
+        parts of complex floats should be passed in individual registers.
+        The real and imaginary parts of stack arguments are supposed
+        to be contiguous and there should be an extra word of padding
+        at the end.
+
+        This has two problems.  First, it makes it impossible to use a
+        single "void *" va_list type, since register and stack arguments
+        are passed differently.  (At the time of writing, MIPSpro cannot
+        handle complex float varargs correctly.)  Second, it's unclear
+        what should happen when there is only one register free.
+
+        For now, we assume that named complex floats should go into FPRs
+        if there are two FPRs free, otherwise they should be passed in the
+        same way as a struct containing two floats.  */
+      if (info->fpr_p
+         && GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+         && GET_MODE_UNIT_SIZE (mode) < UNITS_PER_FPVALUE)
+       {
+         if (cum->num_gprs >= MAX_ARGS_IN_REGISTERS - 1)
+           info->fpr_p = false;
+         else
+           num_words = 2;
+       }
+      break;
 
-  even_reg_p = false;
-  if (info->fpr_p)
-    {
-      /* Under the O64 ABI, the second float argument goes in $f13 if it
-        is a double, but $f14 if it is a single.  Otherwise, on a
-        32-bit double-float machine, each FP argument must start in a
-        new register pair.  */
-      even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_HWFPVALUE
-                   || (mips_abi == ABI_O64 && mode == SFmode)
-                   || FP_INC > 1);
+    default:
+      gcc_unreachable ();
     }
-  else if (!TARGET_64BIT || LONG_DOUBLE_TYPE_SIZE == 128)
-    {
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         || GET_MODE_CLASS (mode) == MODE_FLOAT)
-       even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
 
-      else if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD)
-       even_reg_p = true;
-    }
+  /* See whether the argument has doubleword alignment.  */
+  doubleword_aligned_p = FUNCTION_ARG_BOUNDARY (mode, type) > BITS_PER_WORD;
 
   /* Set REG_OFFSET to the register count we're interested in.
      The EABI allocates the floating-point registers separately,
@@ -3372,20 +3743,15 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
                      ? cum->num_fprs
                      : cum->num_gprs);
 
-  if (even_reg_p)
+  /* Advance to an even register if the argument is doubleword-aligned.  */
+  if (doubleword_aligned_p)
     info->reg_offset += info->reg_offset & 1;
 
-  /* The alignment applied to registers is also applied to stack arguments.  */
+  /* Work out the offset of a stack argument.  */
   info->stack_offset = cum->stack_words;
-  if (even_reg_p)
+  if (doubleword_aligned_p)
     info->stack_offset += info->stack_offset & 1;
 
-  if (mode == BLKmode)
-    info->num_bytes = int_size_in_bytes (type);
-  else
-    info->num_bytes = GET_MODE_SIZE (mode);
-
-  num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
   max_regs = MAX_ARGS_IN_REGISTERS - info->reg_offset;
 
   /* Partition the argument between registers and stack.  */
@@ -3515,26 +3881,69 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
        }
     }
 
-  if (info.fpr_p)
-    return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset);
-  else
+  /* Handle the n32/n64 conventions for passing complex floating-point
+     arguments in FPR pairs.  The real part goes in the lower register
+     and the imaginary part goes in the upper register.  */
+  if (TARGET_NEWABI
+      && info.fpr_p
+      && GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+    {
+      rtx real, imag;
+      enum machine_mode inner;
+      int reg;
+
+      inner = GET_MODE_INNER (mode);
+      reg = FP_ARG_FIRST + info.reg_offset;
+      real = gen_rtx_EXPR_LIST (VOIDmode,
+                               gen_rtx_REG (inner, reg),
+                               const0_rtx);
+      imag = gen_rtx_EXPR_LIST (VOIDmode,
+                               gen_rtx_REG (inner, reg + info.reg_words / 2),
+                               GEN_INT (GET_MODE_SIZE (inner)));
+      return gen_rtx_PARALLEL (mode, gen_rtvec (2, real, imag));
+    }
+
+  if (!info.fpr_p)
     return gen_rtx_REG (mode, GP_ARG_FIRST + info.reg_offset);
+  else if (info.reg_offset == 1)
+    /* This code handles the special o32 case in which the second word
+       of the argument structure is passed in floating-point registers.  */
+    return gen_rtx_REG (mode, FP_ARG_FIRST + FP_INC);
+  else
+    return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset);
 }
 
 
-/* Implement FUNCTION_ARG_PARTIAL_NREGS.  */
+/* Implement TARGET_ARG_PARTIAL_BYTES.  */
 
-int
-function_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
-                           enum machine_mode mode, tree type, int named)
+static int
+mips_arg_partial_bytes (CUMULATIVE_ARGS *cum,
+                       enum machine_mode mode, tree type, bool named)
 {
   struct mips_arg_info info;
 
   mips_arg_info (cum, mode, type, named, &info);
-  return info.stack_words > 0 ? info.reg_words : 0;
+  return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
 }
 
 
+/* Implement FUNCTION_ARG_BOUNDARY.  Every parameter gets at least
+   PARM_BOUNDARY bits of alignment, but will be given anything up
+   to STACK_BOUNDARY bits if the type requires it.  */
+
+int
+function_arg_boundary (enum machine_mode mode, tree type)
+{
+  unsigned int alignment;
+
+  alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
+  if (alignment < PARM_BOUNDARY)
+    alignment = PARM_BOUNDARY;
+  if (alignment > STACK_BOUNDARY)
+    alignment = STACK_BOUNDARY;
+  return alignment;
+}
+
 /* Return true if FUNCTION_ARG_PADDING (MODE, TYPE) should return
    upward rather than downward.  In other words, return true if the
    first byte of the stack slot has useful data, false if the last
@@ -3590,7 +3999,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;
@@ -3614,18 +4024,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 ());
 
@@ -3660,14 +4061,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.
@@ -3712,7 +4108,7 @@ mips_build_builtin_va_list (void)
                          unsigned_char_type_node);
       /* Explicitly pad to the size of a pointer, so that -Wpadded won't
         warn on every user file.  */
-      index = build_int_2 (GET_MODE_SIZE (ptr_mode) - 2 - 1, 0);
+      index = build_int_cst (NULL_TREE, GET_MODE_SIZE (ptr_mode) - 2 - 1);
       array = build_array_type (unsigned_char_type_node,
                                build_index_type (index));
       f_res = build_decl (FIELD_DECL, get_identifier ("__reserved"), array);
@@ -3734,7 +4130,7 @@ mips_build_builtin_va_list (void)
       layout_type (record);
       return record;
     }
-  else if (TARGET_IRIX && !TARGET_IRIX5)
+  else if (TARGET_IRIX && TARGET_IRIX6)
     /* On IRIX 6, this type is 'char *'.  */
     return build_pointer_type (char_type_node);
   else
@@ -3745,102 +4141,86 @@ mips_build_builtin_va_list (void)
 /* Implement va_start.  */
 
 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)
+mips_va_start (tree valist, rtx nextarg)
+{
+  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_2 (cum->stack_words * UNITS_PER_WORD, 0));
-         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_2 (-fpr_offset, -1));
-         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_2 (gpr_save_area_size, 0));
-         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_2 (fpr_save_area_size, 0));
-         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.  */
@@ -3907,16 +4287,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
@@ -3944,51 +4324,55 @@ 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_2 (-rsize, -1));
-             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 = lang_hooks.truthvalue_conversion (off);
-      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_2 (rsize, 0));
-      t = build (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t);
+      t = fold_convert (TREE_TYPE (off), build_int_cst (NULL_TREE, rsize));
+      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_2 (rsize - size, 0));
-         t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
+         u = fold_convert (TREE_TYPE (t), build_int_cst (NULL_TREE,
+                                                         rsize - size));
+         t = build2 (PLUS_EXPR, TREE_TYPE (t), t, u);
        }
       COND_EXPR_THEN (addr) = t;
 
       if (osize > UNITS_PER_WORD)
        {
          /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize.  */
-         u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize - 1, 0));
-         t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
-         u = fold_convert (TREE_TYPE (ovfl), build_int_2 (-osize, -1));
-         t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
-         align = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
+         u = fold_convert (TREE_TYPE (ovfl),
+                           build_int_cst (NULL_TREE, osize - 1));
+         t = build2 (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
+         u = fold_convert (TREE_TYPE (ovfl),
+                           build_int_cst (NULL_TREE, -osize));
+         t = build2 (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
+         align = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
        }
       else
        align = NULL;
@@ -3996,25 +4380,27 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
       /* [10, 11].     Emit code to store ovfl in addr_rtx, then
         post-increment ovfl by osize.  On big-endian machines,
         the argument has OSIZE - SIZE bytes of leading padding.  */
-      u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize, 0));
-      t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
+      u = fold_convert (TREE_TYPE (ovfl),
+                       build_int_cst (NULL_TREE, osize));
+      t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
       if (BYTES_BIG_ENDIAN && osize > size)
        {
-         u = fold_convert (TREE_TYPE (t), build_int_2 (osize - size, 0));
-         t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
+         u = fold_convert (TREE_TYPE (t),
+                           build_int_cst (NULL_TREE, osize - size));
+         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;
 }
@@ -4030,7 +4416,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,
@@ -4040,7 +4426,7 @@ mips_get_unaligned_mem (rtx *op, unsigned int width, int bitpos,
 
   /* Check that the operand really is a MEM.  Not all the extv and
      extzv predicates are checked.  */
-  if (GET_CODE (*op) != MEM)
+  if (!MEM_P (*op))
     return false;
 
   /* Check that the size is valid.  */
@@ -4146,7 +4532,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.  */
 
@@ -4174,6 +4592,44 @@ mips_set_tune (const struct mips_cpu_info *info)
     }
 }
 
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case OPT_mabi_:
+      if (strcmp (arg, "32") == 0)
+       mips_abi = ABI_32;
+      else if (strcmp (arg, "o64") == 0)
+       mips_abi = ABI_O64;
+      else if (strcmp (arg, "n32") == 0)
+       mips_abi = ABI_N32;
+      else if (strcmp (arg, "64") == 0)
+       mips_abi = ABI_64;
+      else if (strcmp (arg, "eabi") == 0)
+       mips_abi = ABI_EABI;
+      else
+       return false;
+      return true;
+
+    case OPT_march_:
+    case OPT_mtune_:
+      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_mno_flush_func:
+      mips_cache_flush_func = NULL;
+      return true;
+
+    default:
+      return true;
+    }
+}
 
 /* Set up the threshold for data to go into the small data area, instead
    of the normal data area, and detect any conflicts in the switches.  */
@@ -4186,57 +4642,28 @@ override_options (void)
 
   mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE;
 
-  /* Interpret -mabi.  */
-  mips_abi = MIPS_ABI_DEFAULT;
-  if (mips_abi_string != 0)
-    {
-      if (strcmp (mips_abi_string, "32") == 0)
-       mips_abi = ABI_32;
-      else if (strcmp (mips_abi_string, "o64") == 0)
-       mips_abi = ABI_O64;
-      else if (strcmp (mips_abi_string, "n32") == 0)
-       mips_abi = ABI_N32;
-      else if (strcmp (mips_abi_string, "64") == 0)
-       mips_abi = ABI_64;
-      else if (strcmp (mips_abi_string, "eabi") == 0)
-       mips_abi = ABI_EABI;
-      else
-       fatal_error ("bad value (%s) for -mabi= switch", mips_abi_string);
-    }
-
   /* The following code determines the architecture and register size.
      Similar code was added to GAS 2.14 (see tc-mips.c:md_after_parse_args()).
      The GAS and GCC code should be kept in sync as much as possible.  */
 
   if (mips_arch_string != 0)
-    mips_set_architecture (mips_parse_cpu ("-march", mips_arch_string));
+    mips_set_architecture (mips_parse_cpu (mips_arch_string));
 
-  if (mips_isa_string != 0)
+  if (mips_isa_info != 0)
     {
-      /* Handle -mipsN.  */
-      char *whole_isa_str = concat ("mips", mips_isa_string, NULL);
-      const struct mips_cpu_info *isa_info;
-
-      isa_info = mips_parse_cpu ("-mips option", whole_isa_str);
-      free (whole_isa_str);
-
-      /* -march takes precedence over -mipsN, since it is more descriptive.
-        There's no harm in specifying both as long as the ISA levels
-        are the same.  */
-      if (mips_arch_info != 0 && mips_isa != isa_info->isa)
-       error ("-mips%s conflicts with the other architecture options, "
-              "which specify a MIPS%d processor",
-              mips_isa_string, mips_isa);
-
-      /* Set architecture based on the given option.  */
-      mips_set_architecture (isa_info);
+      if (mips_arch_info == 0)
+       mips_set_architecture (mips_isa_info);
+      else if (mips_arch_info->isa != mips_isa_info->isa)
+       error ("-%s conflicts with the other architecture options, "
+              "which specify a %s processor",
+              mips_isa_info->name,
+              mips_cpu_info_from_isa (mips_arch_info->isa)->name);
     }
 
   if (mips_arch_info == 0)
     {
 #ifdef MIPS_CPU_STRING_DEFAULT
-      mips_set_architecture (mips_parse_cpu ("default CPU",
-                                            MIPS_CPU_STRING_DEFAULT));
+      mips_set_architecture (mips_parse_cpu (MIPS_CPU_STRING_DEFAULT));
 #else
       mips_set_architecture (mips_cpu_info_from_isa (MIPS_ISA_DEFAULT));
 #endif
@@ -4248,11 +4675,14 @@ override_options (void)
 
   /* Optimize for mips_arch, unless -mtune selects a different processor.  */
   if (mips_tune_string != 0)
-    mips_set_tune (mips_parse_cpu ("-mtune", mips_tune_string));
+    mips_set_tune (mips_parse_cpu (mips_tune_string));
 
   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
@@ -4300,10 +4730,6 @@ override_options (void)
 
   if ((target_flags_explicit & MASK_LONG64) == 0)
     {
-      /* If no type size setting options (-mlong64,-mint64,-mlong32)
-        were used, then set the type sizes.  In the EABI in 64 bit mode,
-        longs and pointers are 64 bits.  Likewise for the SGI Irix6 N64
-        ABI.  */
       if ((mips_abi == ABI_EABI && TARGET_64BIT) || mips_abi == ABI_64)
        target_flags |= MASK_LONG64;
       else
@@ -4333,58 +4759,6 @@ override_options (void)
   if (!TARGET_OLDABI)
     flag_pcc_struct_return = 0;
 
-#if defined(USE_COLLECT2)
-  /* For IRIX 5 or IRIX 6 with integrated O32 ABI support, USE_COLLECT2 is
-     always defined when GNU as is not in use, but collect2 is only used
-     for the O32 ABI, so override the toplev.c and target-def.h defaults
-     for flag_gnu_linker, TARGET_ASM_{CONSTRUCTOR, DESTRUCTOR} and
-     TARGET_HAVE_CTORS_DTORS.
-
-     Since the IRIX 5 and IRIX 6 O32 assemblers cannot handle named
-     sections, constructor/destructor handling depends on the ABI in use.
-
-     Since USE_COLLECT2 is defined, we only need to restore the non-collect2
-     defaults for the N32/N64 ABIs.  */
-  if (TARGET_IRIX && !TARGET_SGI_O32_AS)
-    {
-      targetm.have_ctors_dtors = true;
-      targetm.asm_out.constructor = default_named_section_asm_out_constructor;
-      targetm.asm_out.destructor = default_named_section_asm_out_destructor;
-    }
-#endif
-
-  /* Handle some quirks of the IRIX 5 and IRIX 6 O32 assemblers.  */
-
-  if (TARGET_SGI_O32_AS)
-    {
-      /* They don't recognize `.[248]byte'.  */
-      targetm.asm_out.unaligned_op.hi = "\t.align 0\n\t.half\t";
-      targetm.asm_out.unaligned_op.si = "\t.align 0\n\t.word\t";
-      /* The IRIX 6 O32 assembler gives an error for `align 0; .dword',
-        contrary to the documentation, so disable it.  */
-      targetm.asm_out.unaligned_op.di = NULL;
-
-      /* They cannot handle named sections.  */
-      targetm.have_named_sections = false;
-      /* Therefore, EH_FRAME_SECTION_NAME isn't defined and we must use
-        collect2.  */
-      targetm.terminate_dw2_eh_frame_info = true;
-      targetm.asm_out.eh_frame_section = collect2_eh_frame_section;
-
-      /* They cannot handle debug information.  */
-      if (write_symbols != NO_DEBUG)
-       {
-         /* Adapt wording to IRIX version: IRIX 5 only had a single ABI,
-            so -mabi=32 isn't usually specified.  */
-         if (TARGET_IRIX5)
-           inform ("-g is only supported using GNU as,");
-         else
-           inform ("-g is only supported using GNU as with -mabi=32,");
-         inform ("-g option disabled");
-         write_symbols = NO_DEBUG;
-       }
-    }
-
   if ((target_flags_explicit & MASK_BRANCHLIKELY) == 0)
     {
       /* If neither -mbranch-likely nor -mno-branch-likely was given
@@ -4411,7 +4785,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)
@@ -4420,31 +4794,20 @@ override_options (void)
       target_flags &= ~MASK_ABICALLS;
     }
 
-  /* -fpic (-KPIC) is the default when TARGET_ABICALLS is defined.  We need
-     to set flag_pic so that the LEGITIMATE_PIC_OPERAND_P macro will work.  */
-  /* ??? -non_shared turns off pic code generation, but this is not
-     implemented.  */
   if (TARGET_ABICALLS)
     {
+      /* We need to set flag_pic for executables as well as DSOs
+        because we may reference symbols that are not defined in
+        the final executable.  (MIPS does not use things like
+        copy relocs, for example.)
+
+        Also, there is a body of code that uses __PIC__ to distinguish
+        between -mabicalls and -mno-abicalls code.  */
       flag_pic = 1;
       if (mips_section_threshold > 0)
-       warning ("-G is incompatible with PIC code which is the default");
+       warning (0, "%<-G%> is incompatible with %<-mabicalls%>");
     }
 
-  /* The MIPS and SGI o32 assemblers expect small-data variables to
-     be declared before they are used.  Although we once had code to
-     do this, it was very invasive and fragile.  It no longer seems
-     worth the effort.  */
-  if (!TARGET_EXPLICIT_RELOCS && !TARGET_GAS)
-    mips_section_threshold = 0;
-
-  /* We switch to small data sections using ".section", which the native
-     o32 irix assemblers don't understand.  Disable -G accordingly.
-     We must do this regardless of command-line options since otherwise
-     the compiler would abort.  */
-  if (!targetm.have_named_sections)
-    mips_section_threshold = 0;
-
   /* mips_split_addresses is a half-way house between explicit
      relocations and the traditional assembler macros.  It can
      split absolute 32-bit symbolic constants into a high/lo_sum
@@ -4455,49 +4818,20 @@ override_options (void)
 
      Although this code should work for -O0, it has traditionally
      been treated as an optimization.  */
-  if (TARGET_GAS && !TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES
+  if (!TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES
       && optimize && !flag_pic
       && !ABI_HAS_64BIT_SYMBOLS)
     mips_split_addresses = 1;
   else
     mips_split_addresses = 0;
 
-  /* Explicit relocations for "old" ABIs are a GNU extension.  Unless
-     the user has said otherwise, assume that they are not available
-     with assemblers other than gas.  */
-  if (!TARGET_NEWABI && !TARGET_GAS
-      && (target_flags_explicit & MASK_EXPLICIT_RELOCS) == 0)
-    target_flags &= ~MASK_EXPLICIT_RELOCS;
-
-  /* Make -mabicalls -fno-unit-at-a-time imply -mno-explicit-relocs
-     unless the user says otherwise.
-
-     There are two problems here:
-
-       (1) The value of an R_MIPS_GOT16 relocation depends on whether
-          the symbol is local or global.  We therefore need to know
-          a symbol's binding before referring to it using %got().
-
-       (2) R_MIPS_CALL16 can only be applied to global symbols.
-
-     When not using -funit-at-a-time, a symbol's binding may change
-     after it has been used.  For example, the C++ front-end will
-     initially assume that the typeinfo for an incomplete type will be
-     comdat, on the basis that the type could be completed later in the
-     file.  But if the type never is completed, the typeinfo will become
-     local instead.  */
-  if (!flag_unit_at_a_time
-      && TARGET_ABICALLS
-      && (target_flags_explicit & MASK_EXPLICIT_RELOCS) == 0)
-    target_flags &= ~MASK_EXPLICIT_RELOCS;
-
   /* -mvr4130-align is a "speed over size" optimization: it usually produces
      faster code, but at the expense of more nops.  Enable it at -O3 and
      above.  */
   if (optimize > 2 && (target_flags_explicit & MASK_VR4130_ALIGN) == 0)
     target_flags |= MASK_VR4130_ALIGN;
 
-  /* When compiling for the mips16, we can not use floating point.  We
+  /* When compiling for the mips16, we cannot use floating point.  We
      record the original hard float value in mips16_hard_float.  */
   if (TARGET_MIPS16)
     {
@@ -4511,6 +4845,10 @@ override_options (void)
          increase register pressure.  */
       flag_schedule_insns = 0;
 
+      /* Don't do hot/cold partitioning.  The constant layout code expects
+        the whole function to be in a single section.  */
+      flag_reorder_blocks_and_partition = 0;
+
       /* Silently disable -mexplicit-relocs since it doesn't apply
         to mips16 code.  Even so, it would overly pedantic to warn
         about "-mips16 -mexplicit-relocs", especially given that
@@ -4530,6 +4868,29 @@ override_options (void)
   REAL_MODE_FORMAT (TFmode) = &MIPS_TFMODE_FORMAT;
 #endif
 
+  /* Make sure that the user didn't turn off paired single support when
+     MIPS-3D support is requested.  */
+  if (TARGET_MIPS3D && (target_flags_explicit & MASK_PAIRED_SINGLE_FLOAT)
+      && !TARGET_PAIRED_SINGLE_FLOAT)
+    error ("-mips3d requires -mpaired-single");
+
+  /* If TARGET_MIPS3D, enable MASK_PAIRED_SINGLE_FLOAT.  */
+  if (TARGET_MIPS3D)
+    target_flags |= MASK_PAIRED_SINGLE_FLOAT;
+
+  /* Make sure that when TARGET_PAIRED_SINGLE_FLOAT is true, TARGET_FLOAT64
+     and TARGET_HARD_FLOAT are both true.  */
+  if (TARGET_PAIRED_SINGLE_FLOAT && !(TARGET_FLOAT64 && TARGET_HARD_FLOAT))
+    error ("-mips3d/-mpaired-single must be used with -mfp64 -mhard-float");
+
+  /* Make sure that the ISA supports TARGET_PAIRED_SINGLE_FLOAT when it is
+     enabled.  */
+  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;
@@ -4551,24 +4912,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['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.  */
 
@@ -4599,7 +4942,17 @@ override_options (void)
        {
          register int temp;
 
-         if (mode == CCmode)
+         if (mode == CCV2mode)
+           temp = (ISA_HAS_8CC
+                   && ST_REG_P (regno)
+                   && (regno - ST_REG_FIRST) % 2 == 0);
+
+         else if (mode == CCV4mode)
+           temp = (ISA_HAS_8CC
+                   && ST_REG_P (regno)
+                   && (regno - ST_REG_FIRST) % 4 == 0);
+
+         else if (mode == CCmode)
            {
              if (! ISA_HAS_8CC)
                temp = (regno == FPSW_REGNUM);
@@ -4613,19 +4966,25 @@ override_options (void)
 
          else if (FP_REG_P (regno))
            temp = ((regno % FP_INC) == 0)
-                   && (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+                   && (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT
+                         || class == MODE_VECTOR_FLOAT)
                         && size <= UNITS_PER_FPVALUE)
                        /* Allow integer modes that fit into a single
                           register.  We need to put integers into FPRs
-                          when using instructions like cvt and trunc.  */
-                       || (class == MODE_INT && size <= UNITS_PER_FPREG)
+                          when using instructions like cvt and trunc.
+                          We can't allow sizes smaller than a word,
+                          the FPU has no appropriate load/store
+                          instructions for those.  */
+                       || (class == MODE_INT
+                           && size >= MIN_UNITS_PER_WORD
+                           && size <= UNITS_PER_FPREG)
                        /* Allow TFmode for CCmode reloads.  */
                        || (ISA_HAS_8CC && mode == TFmode));
 
-         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))
@@ -4740,6 +5099,22 @@ override_options (void)
       mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
     }
 
+  /* Thread-local relocation operators.  */
+  mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
+  mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
+  mips_split_p[SYMBOL_DTPREL] = 1;
+  mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+  mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+  mips_split_p[SYMBOL_TPREL] = 1;
+  mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+  mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+
+  /* We don't have a thread pointer access instruction on MIPS16, or
+     appropriate TLS relocations.  */
+  if (TARGET_MIPS16)
+    targetm.have_tls = false;
+
   /* Default to working around R4000 errata only if the processor
      was selected explicitly.  */
   if ((target_flags_explicit & MASK_FIX_R4000) == 0
@@ -4758,6 +5133,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;
@@ -4896,12 +5278,13 @@ mips_debugger_offset (rtx addr, HOST_WIDE_INT offset)
    'F'  print part of opcode for a floating-point branch condition.
    'N'  print part of opcode for a branch condition, inverted.
    'W'  print part of opcode for a floating-point branch condition, inverted.
-   'B'  print 'z' for EQ, 'n' for NE
-   'b'  print 'n' for EQ, 'z' for NE
-   'T'  print 'f' for EQ, 't' for NE
-   't'  print 't' for EQ, 'f' for NE
-   'Z'  print register and a comma, but print nothing for $fcc0
+   'T'  print 'f' for (eq:CC ...), 't' for (ne:CC ...),
+             'z' for (eq:?I ...), 'n' for (ne:?I ...).
+   't'  like 'T', but with the EQ/NE cases reversed
+   '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:
 
@@ -5036,14 +5419,14 @@ print_operand (FILE *file, rtx op, int letter)
 
        case '{':
          if (set_volatile++ == 0)
-           fprintf (file, "%s.set\tvolatile\n\t", TARGET_MIPS_AS ? "" : "#");
+           fputs ("#.set\tvolatile\n\t", file);
          break;
 
        case '}':
          if (set_volatile == 0)
            error ("internal error: %%} found without a %%{ in assembler pattern");
          else if (--set_volatile == 0)
-           fprintf (file, "\n\t%s.set\tnovolatile", (TARGET_MIPS_AS) ? "" : "#");
+           fputs ("\n\t#.set\tnovolatile", file);
 
          break;
 
@@ -5052,7 +5435,7 @@ print_operand (FILE *file, rtx op, int letter)
            if (align_labels_log > 0)
              ASM_OUTPUT_ALIGN (file, align_labels_log);
          }
-       break;
+         break;
 
        default:
          error ("PRINT_OPERAND: unknown punctuation '%c'", letter);
@@ -5133,19 +5516,39 @@ print_operand (FILE *file, rtx op, int letter)
   else if (letter == 'R')
     print_operand_reloc (file, op, mips_lo_relocs);
 
+  else if (letter == 'Y')
+    {
+      if (GET_CODE (op) == CONST_INT
+         && ((unsigned HOST_WIDE_INT) INTVAL (op)
+             < ARRAY_SIZE (mips_fp_conditions)))
+       fputs (mips_fp_conditions[INTVAL (op)], file);
+      else
+       output_operand_lossage ("invalid %%Y value");
+    }
+
   else if (letter == 'Z')
     {
-      register int regnum;
+      if (ISA_HAS_8CC)
+       {
+         print_operand (file, op, 0);
+         fputc (',', file);
+       }
+    }
+
+  else if (letter == 'q')
+    {
+      int regnum;
 
       if (code != REG)
-       abort ();
+       fatal_insn ("PRINT_OPERAND, invalid insn for %%q", op);
 
       regnum = REGNO (op);
-      if (! ST_REG_P (regnum))
-       abort ();
-
-      if (regnum != ST_REG_FIRST)
-       fprintf (file, "%s,", reg_names[regnum]);
+      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)
@@ -5188,14 +5591,11 @@ print_operand (FILE *file, rtx op, int letter)
   else if (letter == 'd' || letter == 'x' || letter == 'X')
     output_operand_lossage ("invalid use of %%d, %%x, or %%X");
 
-  else if (letter == 'B')
-    fputs (code == EQ ? "z" : "n", file);
-  else if (letter == 'b')
-    fputs (code == EQ ? "n" : "z", file);
-  else if (letter == 'T')
-    fputs (code == EQ ? "f" : "t", file);
-  else if (letter == 't')
-    fputs (code == EQ ? "t" : "f", file);
+  else if (letter == 'T' || letter == 't')
+    {
+      int truth = (code == NE) == (letter == 'T');
+      fputc ("zfnt"[truth * 2 + (GET_MODE (op) == CCmode)], file);
+    }
 
   else if (CONST_GP_P (op))
     fputs (reg_names[GLOBAL_POINTER_REGNUM], file);
@@ -5252,31 +5652,15 @@ print_operand_address (FILE *file, rtx x)
        return;
 
       case ADDRESS_CONST_INT:
+       output_addr_const (file, x);
+       fprintf (file, "(%s)", reg_names[0]);
+       return;
+
       case ADDRESS_SYMBOLIC:
        output_addr_const (file, x);
        return;
       }
-  abort ();
-}
-\f
-/* Target hook for assembling integer objects.  It appears that the Irix
-   6 assembler can't handle 64-bit decimal integers, so avoid printing
-   such an integer here.  */
-
-static bool
-mips_assemble_integer (rtx x, unsigned int size, int aligned_p)
-{
-  if ((TARGET_64BIT || TARGET_GAS) && size == 8 && aligned_p)
-    {
-      fputs ("\t.dword\t", asm_out_file);
-      if (HOST_BITS_PER_WIDE_INT < 64 || GET_CODE (x) != CONST_INT)
-       output_addr_const (asm_out_file, x);
-      else
-       print_operand (asm_out_file, x, 'X');
-      fputc ('\n', asm_out_file);
-      return true;
-    }
-  return default_assemble_integer (x, size, aligned_p);
+  gcc_unreachable ();
 }
 \f
 /* When using assembler macros, keep track of all of small-data externs
@@ -5314,7 +5698,7 @@ mips_output_external (FILE *file ATTRIBUTE_UNUSED, tree decl, const char *name)
 }
 
 #if TARGET_IRIX
-void
+static void
 irix_output_external_libcall (rtx fun)
 {
   register struct extern_list *p;
@@ -5336,7 +5720,6 @@ irix_output_external_libcall (rtx fun)
 void
 mips_output_filename (FILE *stream, const char *name)
 {
-  char ltext_label_name[100];
 
   /* If we are emitting DWARF-2, let dwarf2out handle the ".file"
      directives.  */
@@ -5345,50 +5728,26 @@ mips_output_filename (FILE *stream, const char *name)
   else if (mips_output_filename_first_time)
     {
       mips_output_filename_first_time = 0;
-      SET_FILE_NUMBER ();
+      num_source_filenames += 1;
       current_function_file = name;
-      ASM_OUTPUT_FILENAME (stream, num_source_filenames, name);
-      /* This tells mips-tfile that stabs will follow.  */
-      if (!TARGET_GAS && write_symbols == DBX_DEBUG)
-       fprintf (stream, "\t#@stabs\n");
+      fprintf (stream, "\t.file\t%d ", num_source_filenames);
+      output_quoted_string (stream, name);
+      putc ('\n', stream);
     }
 
+  /* If we are emitting stabs, let dbxout.c handle this (except for
+     the mips_output_filename_first_time case).  */
   else if (write_symbols == DBX_DEBUG)
-    {
-      ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
-      fprintf (stream, "%s", ASM_STABS_OP);
-      output_quoted_string (stream, name);
-      fprintf (stream, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
-    }
+    return;
 
   else if (name != current_function_file
           && strcmp (name, current_function_file) != 0)
     {
-      SET_FILE_NUMBER ();
+      num_source_filenames += 1;
       current_function_file = name;
-      ASM_OUTPUT_FILENAME (stream, num_source_filenames, name);
-    }
-}
-\f
-/* Emit a linenumber.  For encapsulated stabs, we need to put out a stab
-   as well as a .loc, since it is possible that MIPS ECOFF might not be
-   able to represent the location for inlines that come from a different
-   file.  */
-
-void
-mips_output_lineno (FILE *stream, int line)
-{
-  if (write_symbols == DBX_DEBUG)
-    {
-      ++sym_lineno;
-      fprintf (stream, "%sLM%d:\n%s%d,0,%d,%sLM%d\n",
-              LOCAL_LABEL_PREFIX, sym_lineno, ASM_STABN_OP, N_SLINE, line,
-              LOCAL_LABEL_PREFIX, sym_lineno);
-    }
-  else
-    {
-      fprintf (stream, "\n\t.loc\t%d %d\n", num_source_filenames, line);
-      LABEL_AFTER_LOC (stream);
+      fprintf (stream, "\t.file\t%d ", num_source_filenames);
+      output_quoted_string (stream, name);
+      putc ('\n', stream);
     }
 }
 \f
@@ -5410,56 +5769,20 @@ mips_output_ascii (FILE *stream, const char *string_param, size_t len,
     {
       register int c = string[i];
 
-      switch (c)
+      if (ISPRINT (c))
        {
-       case '\"':
-       case '\\':
-         putc ('\\', stream);
-         putc (c, stream);
-         cur_pos += 2;
-         break;
-
-       case TARGET_NEWLINE:
-         fputs ("\\n", stream);
-         if (i+1 < len
-             && (((c = string[i+1]) >= '\040' && c <= '~')
-                 || c == TARGET_TAB))
-           cur_pos = 32767;            /* break right here */
-         else
-           cur_pos += 2;
-         break;
-
-       case TARGET_TAB:
-         fputs ("\\t", stream);
-         cur_pos += 2;
-         break;
-
-       case TARGET_FF:
-         fputs ("\\f", stream);
-         cur_pos += 2;
-         break;
-
-       case TARGET_BS:
-         fputs ("\\b", stream);
-         cur_pos += 2;
-         break;
-
-       case TARGET_CR:
-         fputs ("\\r", stream);
-         cur_pos += 2;
-         break;
-
-       default:
-         if (c >= ' ' && c < 0177)
+         if (c == '\\' || c == '\"')
            {
-             putc (c, stream);
+             putc ('\\', stream);
              cur_pos++;
            }
-         else
-           {
-             fprintf (stream, "\\%03o", c);
-             cur_pos += 4;
-           }
+         putc (c, stream);
+         cur_pos++;
+       }
+      else
+       {
+         fprintf (stream, "\\%03o", c);
+         cur_pos += 4;
        }
 
       if (cur_pos > 72 && i+1 < len)
@@ -5478,17 +5801,8 @@ mips_file_start (void)
 {
   default_file_start ();
 
-  /* Versions of the MIPS assembler before 2.20 generate errors if a branch
-     inside of a .set noreorder section jumps to a label outside of the .set
-     noreorder section.  Revision 2.20 just set nobopt silently rather than
-     fixing the bug.  */
-
-  if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
-    fprintf (asm_out_file, "\t.set\tnobopt\n");
-
-  if (TARGET_GAS)
+  if (!TARGET_IRIX)
     {
-#if defined(OBJECT_FORMAT_ELF) && !TARGET_IRIX
       /* Generate a special section to describe the ABI switches used to
         produce the resultant binary.  This used to be done by the assembler
         setting bits in the ELF header's flags field, but we have run out of
@@ -5506,9 +5820,9 @@ mips_file_start (void)
        case ABI_O64:  abi_string = "abiO64"; break;
        case ABI_EABI: abi_string = TARGET_64BIT ? "eabi64" : "eabi32"; break;
        default:
-         abort ();
+         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.  */
@@ -5516,23 +5830,19 @@ mips_file_start (void)
 
       /* There is no ELF header flag to distinguish long32 forms of the
         EABI from long64 forms.  Emit a special section to help tools
-        such as GDB.  */
-      if (mips_abi == ABI_EABI)
+        such as GDB.  Do the same for o64, which is sometimes used with
+        -mlong64.  */
+      if (mips_abi == ABI_EABI || mips_abi == ABI_O64)
        fprintf (asm_out_file, "\t.section .gcc_compiled_long%d\n",
                 TARGET_LONG64 ? 64 : 32);
 
       /* Restore the default section.  */
       fprintf (asm_out_file, "\t.previous\n");
-#endif
     }
 
   /* Generate the pseudo ops that System V.4 wants.  */
-#ifndef ABICALLS_ASM_OP
-#define ABICALLS_ASM_OP "\t.abicalls"
-#endif
   if (TARGET_ABICALLS)
-    /* ??? but do not want this (or want pic0) if -non-shared? */
-    fprintf (asm_out_file, "%s\n", ABICALLS_ASM_OP);
+    fprintf (asm_out_file, "\t.abicalls\n");
 
   if (TARGET_MIPS16)
     fprintf (asm_out_file, "\t.set\tmips16\n");
@@ -5554,9 +5864,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);
@@ -5608,9 +5918,8 @@ mips_file_end (void)
     }
 }
 
-/* Implement ASM_OUTPUT_ALIGNED_DECL_COMMON.  This is usually the same as
-   the elfos.h version, but we also need to handle -muninit-const-in-rodata
-   and the limitations of the SGI o32 assembler.  */
+/* Implement ASM_OUTPUT_ALIGNED_DECL_COMMON.  This is usually the same as the
+   elfos.h version, but we also need to handle -muninit-const-in-rodata.  */
 
 void
 mips_output_aligned_decl_common (FILE *stream, tree decl, const char *name,
@@ -5626,16 +5935,15 @@ 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",
                           size);
     }
   else
-    /* The SGI o32 assembler doesn't accept an alignment.  */
     mips_declare_common_object (stream, name, "\n\t.comm\t",
-                               size, align, !TARGET_SGI_O32_AS);
+                               size, align, true);
 }
 
 /* Declare a common object of SIZE bytes using asm directive INIT_STRING.
@@ -5698,24 +6006,21 @@ void
 mips_declare_object_name (FILE *stream, const char *name,
                          tree decl ATTRIBUTE_UNUSED)
 {
-  if (!TARGET_SGI_O32_AS)
-    {
 #ifdef ASM_OUTPUT_TYPE_DIRECTIVE
-      ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
+  ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
 #endif
 
-      size_directive_output = 0;
-      if (!flag_inhibit_size_directive && DECL_SIZE (decl))
-       {
-         HOST_WIDE_INT size;
+  size_directive_output = 0;
+  if (!flag_inhibit_size_directive && DECL_SIZE (decl))
+    {
+      HOST_WIDE_INT size;
 
-         size_directive_output = 1;
-         size = int_size_in_bytes (TREE_TYPE (decl));
-         ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
-       }
+      size_directive_output = 1;
+      size = int_size_in_bytes (TREE_TYPE (decl));
+      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.  */
@@ -5726,8 +6031,7 @@ mips_finish_declare_object (FILE *stream, tree decl, int top_level, int at_end)
   const char *name;
 
   name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-  if (!TARGET_SGI_O32_AS
-      && !flag_inhibit_size_directive
+  if (!flag_inhibit_size_directive
       && DECL_SIZE (decl) != 0
       && !at_end && top_level
       && DECL_INITIAL (decl) == error_mark_node
@@ -5756,10 +6060,10 @@ mips_rewrite_small_data_p (rtx x)
 }
 
 
-/* A for_each_rtx callback for small_data_pattern.  */
+/* A for_each_rtx callback for mips_small_data_pattern_p.  */
 
 static int
-small_data_pattern_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
+mips_small_data_pattern_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (*loc) == LO_SUM)
     return -1;
@@ -5770,11 +6074,10 @@ small_data_pattern_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
 /* Return true if OP refers to small data symbols directly, not through
    a LO_SUM.  */
 
-int
-small_data_pattern (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+bool
+mips_small_data_pattern_p (rtx op)
 {
-  return (GET_CODE (op) != SEQUENCE
-         && for_each_rtx (&op, small_data_pattern_1, 0));
+  return for_each_rtx (&op, mips_small_data_pattern_1, 0);
 }
 \f
 /* A for_each_rtx callback, used by mips_rewrite_small_data.  */
@@ -5941,7 +6244,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
         +-----------------------+      +-----------------------+
@@ -6069,10 +6372,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;
@@ -6141,13 +6443,12 @@ 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:
-      abort ();
+      gcc_unreachable ();
     }
 
   if (TARGET_MIPS16 && to == HARD_FRAME_POINTER_REGNUM)
@@ -6178,8 +6479,6 @@ mips_save_restore_reg (enum machine_mode mode, int regno,
   rtx mem;
 
   mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset));
-  if (!current_function_calls_eh_return)
-    RTX_UNCHANGING_P (mem) = 1;
 
   fn (gen_rtx_REG (mode, regno), mem);
 }
@@ -6238,22 +6537,55 @@ mips_output_cplocal (void)
     output_asm_insn (".cplocal %+", 0);
 }
 
+/* Return the style of GP load sequence that is being used for the
+   current function.  */
+
+enum mips_loadgp_style
+mips_current_loadgp_style (void)
+{
+  if (!TARGET_ABICALLS || cfun->machine->global_pointer == 0)
+    return LOADGP_NONE;
+
+  if (TARGET_ABSOLUTE_ABICALLS)
+    return LOADGP_ABSOLUTE;
+
+  return TARGET_NEWABI ? LOADGP_NEWABI : LOADGP_OLDABI;
+}
+
+/* The __gnu_local_gp symbol.  */
+
+static GTY(()) rtx mips_gnu_local_gp;
+
 /* If we're generating n32 or n64 abicalls, emit instructions
    to set up the global pointer.  */
 
 static void
 mips_emit_loadgp (void)
 {
-  if (TARGET_ABICALLS && TARGET_NEWABI && cfun->machine->global_pointer > 0)
+  rtx addr, offset, incoming_address;
+
+  switch (mips_current_loadgp_style ())
     {
-      rtx addr, offset, incoming_address;
+    case LOADGP_ABSOLUTE:
+      if (mips_gnu_local_gp == NULL)
+       {
+         mips_gnu_local_gp = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
+         SYMBOL_REF_FLAGS (mips_gnu_local_gp) |= SYMBOL_FLAG_LOCAL;
+       }
+      emit_insn (gen_loadgp_noshared (mips_gnu_local_gp));
+      break;
 
+    case LOADGP_NEWABI:
       addr = XEXP (DECL_RTL (current_function_decl), 0);
       offset = mips_unspec_address (addr, SYMBOL_GOTOFF_LOADGP);
       incoming_address = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
       emit_insn (gen_loadgp (offset, incoming_address));
       if (!TARGET_EXPLICIT_RELOCS)
        emit_insn (gen_loadgp_blockage ());
+      break;
+
+    default:
+      break;
     }
 }
 
@@ -6265,15 +6597,9 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
   const char *fnname;
   HOST_WIDE_INT tsize = cfun->machine->frame.total_size;
 
-  /* ??? When is this really needed?  At least the GNU assembler does not
-     need the source filename more than once in the file, beyond what is
-     emitted by the debug information.  */
-  if (!TARGET_GAS)
-    ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
-
 #ifdef SDB_DEBUGGING_INFO
   if (debug_info_level != DINFO_LEVEL_TERSE && write_symbols == SDB_DEBUG)
-    ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl), 0);
+    SDB_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
 #endif
 
   /* In mips16 mode, we may need to generate a 32 bit to handle
@@ -6302,6 +6628,10 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       fputs (":\n", file);
     }
 
+  /* Stop mips_file_end from treating this function as external.  */
+  if (TARGET_IRIX && mips_abi == ABI_32)
+    TREE_ASM_WRITTEN (DECL_NAME (cfun->decl)) = 1;
+
   if (!flag_inhibit_size_directive)
     {
       /* .frame FRAMEREG, FRAMESIZE, RETREG */
@@ -6335,7 +6665,7 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
         HIGHEST_GP_SAVED == *FRAMEREG + FRAMESIZE + GPOFFSET => can find saved regs.  */
     }
 
-  if (TARGET_ABICALLS && !TARGET_NEWABI && cfun->machine->global_pointer > 0)
+  if (mips_current_loadgp_style () == LOADGP_OLDABI)
     {
       /* Handle the initialization of $gp for SVR4 PIC.  */
       if (!cfun->machine->all_noreorder_p)
@@ -6374,8 +6704,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;
 }
 
@@ -6461,9 +6801,7 @@ mips_expand_prologue (void)
                 from the stack pointer, so use the frame pointer as a
                 temporary.  We should always be using a frame pointer
                 in this case anyway.  */
-             if (!frame_pointer_needed)
-               abort ();
-
+             gcc_assert (frame_pointer_needed);
              emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
              emit_insn (gen_sub3_insn (hard_frame_pointer_rtx,
                                        hard_frame_pointer_rtx,
@@ -6491,22 +6829,35 @@ mips_expand_prologue (void)
       if (TARGET_MIPS16 && cfun->machine->frame.args_size != 0)
        {
          rtx offset = GEN_INT (cfun->machine->frame.args_size);
-         RTX_FRAME_RELATED_P
-           (emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      offset))) = 1;
+         if (SMALL_OPERAND (cfun->machine->frame.args_size))
+           RTX_FRAME_RELATED_P 
+             (emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
+                                        stack_pointer_rtx,
+                                        offset))) = 1;
+         else
+           {
+             emit_move_insn (MIPS_PROLOGUE_TEMP (Pmode), offset);
+             emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+             emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
+                                       hard_frame_pointer_rtx,
+                                       MIPS_PROLOGUE_TEMP (Pmode)));
+             mips_set_frame_expr
+               (gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
+                             plus_constant (stack_pointer_rtx, 
+                                            cfun->machine->frame.args_size)));
+           }
        }
       else
        RTX_FRAME_RELATED_P (emit_move_insn (hard_frame_pointer_rtx,
                                             stack_pointer_rtx)) = 1;
     }
 
+  mips_emit_loadgp ();
+
   /* If generating o32/o64 abicalls, save $gp on the stack.  */
   if (TARGET_ABICALLS && !TARGET_NEWABI && !current_function_is_leaf)
     emit_insn (gen_cprestore (GEN_INT (current_function_outgoing_args_size)));
 
-  mips_emit_loadgp ();
-
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  */
 
@@ -6773,25 +7124,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
       emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
 
       /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET.  */
-      if (SMALL_OPERAND (vcall_offset))
-       addr = gen_rtx_PLUS (Pmode, temp1, GEN_INT (vcall_offset));
-      else if (TARGET_MIPS16)
-       {
-         /* Load the full offset into a register so that we can use
-            an unextended instruction for the load itself.  */
-         emit_move_insn (temp2, GEN_INT (vcall_offset));
-         emit_insn (gen_add3_insn (temp1, temp1, temp2));
-         addr = temp1;
-       }
-      else
-       {
-         /* Load the high part of the offset into a register and
-            leave the low part for the address.  */
-         emit_move_insn (temp2, GEN_INT (CONST_HIGH_PART (vcall_offset)));
-         emit_insn (gen_add3_insn (temp1, temp1, temp2));
-         addr = gen_rtx_PLUS (Pmode, temp1,
-                              GEN_INT (CONST_LOW_PART (vcall_offset)));
-       }
+      addr = mips_add_offset (temp2, temp1, vcall_offset);
 
       /* Load the offset and add it to THIS.  */
       emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
@@ -6837,7 +7170,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
@@ -6870,7 +7203,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)
 {
@@ -6879,13 +7212,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
     {
@@ -6895,33 +7228,47 @@ 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))
-       {
-         if (targetm.have_named_sections)
-           named_section (0, ".data.rel.ro", 3);
-         else
-           data_section ();
-       }
+       return get_named_section (NULL, ".data.rel.ro", 3);
       else
-       mergeable_constant_section (mode, align, 0);
+       return mergeable_constant_section (mode, align, 0);
     }
 }
 
-/* Choose the section to use for DECL.  RELOC is true if its value contains
-   any relocatable expression.  */
+/* Implement TARGET_ASM_FUNCTION_RODATA_SECTION.
 
-static void
-mips_select_section (tree decl, int reloc,
-                    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+   The complication here is that, with the combination TARGET_ABICALLS
+   && !TARGET_GPWORD, jump tables will use absolute addresses, and should
+   therefore not be included in the read-only part of a DSO.  Handle such
+   cases by selecting a normal data section instead of a read-only one.
+   The logic apes that in default_function_rodata_section.  */
+
+static section *
+mips_function_rodata_section (tree decl)
 {
-  if (targetm.have_named_sections)
-    default_elf_select_section (decl, reloc, align);
-  else
-    /* The native irix o32 assembler doesn't support named sections.  */
-    default_select_section (decl, reloc, align);
-}
+  if (!TARGET_ABICALLS || TARGET_GPWORD)
+    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';
+         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);
+         return get_section (rname, SECTION_WRITE, decl);
+       }
+    }
+  return data_section;
+}
 
 /* Implement TARGET_IN_SMALL_DATA_P.  Return true if it would be safe to
    access DECL using %gp_rel(...)($gp).  */
@@ -6966,8 +7313,27 @@ mips_in_small_data_p (tree decl)
        return false;
     }
 
-  size = int_size_in_bytes (TREE_TYPE (decl));
-  return (size > 0 && size <= mips_section_threshold);
+  size = int_size_in_bytes (TREE_TYPE (decl));
+  return (size > 0 && size <= mips_section_threshold);
+}
+
+/* Implement TARGET_USE_ANCHORS_FOR_SYMBOL_P.  We don't want to use
+   anchors for small data: the GP register acts as an anchor in that
+   case.  We also don't want to use them for PC-relative accesses,
+   where the PC acts as an anchor.  */
+
+static bool
+mips_use_anchors_for_symbol_p (rtx symbol)
+{
+  switch (mips_classify_symbol (symbol))
+    {
+    case SYMBOL_CONSTANT_POOL:
+    case SYMBOL_SMALL_DATA:
+      return false;
+
+    default:
+      return true;
+    }
 }
 \f
 /* See whether VALTYPE is a record whose fields should be returned in
@@ -7105,9 +7471,17 @@ mips_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
              mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
            }
        }
+
+      /* For EABI, the class of return register depends entirely on MODE.
+        For example, "struct { some_type x; }" and "union { some_type x; }"
+        are returned in the same way as a bare "some_type" would be.
+        Other ABIs only use FPRs for scalar, complex or vector types.  */
+      if (mips_abi != ABI_EABI && !FLOAT_TYPE_P (valtype))
+       return gen_rtx_REG (mode, GP_RETURN);
     }
 
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+  if ((GET_MODE_CLASS (mode) == MODE_FLOAT
+       || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
       && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
     return gen_rtx_REG (mode, FP_RETURN);
 
@@ -7152,35 +7526,54 @@ mips_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
     }
 }
 
-/* Return the class of registers for which a mode change from FROM to TO
-   is invalid.
-
-   In little-endian mode, the hi-lo registers are numbered backwards,
-   so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
-   word as intended.
-
-   Similarly, when using paired floating-point registers, the first
-   register holds the low word, regardless of endianness.  So in big
-   endian mode, (subreg:SI (reg:DF $f0) 0) does not get the high word
-   as intended.
+static bool
+mips_callee_copies (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                   enum machine_mode mode ATTRIBUTE_UNUSED,
+                   tree type ATTRIBUTE_UNUSED, bool named)
+{
+  return mips_abi == ABI_EABI && named;
+}
 
-   Also, loading a 32-bit value into a 64-bit floating-point register
-   will not sign-extend the value, despite what LOAD_EXTEND_OP says.
-   We can't allow 64-bit float registers to change from a 32-bit
-   mode to a 64-bit mode.  */
+/* Return true if registers of class CLASS cannot change from mode FROM
+   to mode TO.  */
 
 bool
 mips_cannot_change_mode_class (enum machine_mode from,
                               enum machine_mode to, enum reg_class class)
 {
-  if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to))
+  if (MIN (GET_MODE_SIZE (from), GET_MODE_SIZE (to)) <= UNITS_PER_WORD
+      && MAX (GET_MODE_SIZE (from), GET_MODE_SIZE (to)) > UNITS_PER_WORD)
     {
       if (TARGET_BIG_ENDIAN)
-       return reg_classes_intersect_p (FP_REGS, class);
-      if (TARGET_FLOAT64)
-       return reg_classes_intersect_p (HI_AND_FP_REGS, class);
-      return reg_classes_intersect_p (HI_REG, class);
+       {
+         /* When a multi-word value is stored in paired floating-point
+            registers, the first register always holds the low word.
+            We therefore can't allow FPRs to change between single-word
+            and multi-word modes.  */
+         if (FP_INC > 1 && reg_classes_intersect_p (FP_REGS, class))
+           return true;
+       }
+      else
+       {
+         /* 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.
+            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;
+       }
     }
+  /* Loading a 32-bit value into a 64-bit floating-point register
+     will not sign-extend the value, despite what LOAD_EXTEND_OP says.
+     We can't allow 64-bit float registers to change from SImode to
+     to a wider mode.  */
+  if (TARGET_FLOAT64
+      && from == SImode
+      && GET_MODE_SIZE (to) >= UNITS_PER_WORD
+      && reg_classes_intersect_p (FP_REGS, class))
+    return true;
   return false;
 }
 
@@ -7236,7 +7629,7 @@ mips_secondary_reload_class (enum reg_class class,
   int regno = -1;
   int gp_reg_p;
 
-  if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+  if (REG_P (x)|| GET_CODE (x) == SUBREG)
     regno = true_regnum (x);
 
   gp_reg_p = TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno);
@@ -7249,8 +7642,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)
        {
@@ -7259,7 +7654,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,7 +7683,7 @@ mips_secondary_reload_class (enum reg_class class,
 
   if (class == FP_REGS)
     {
-      if (GET_CODE (x) == MEM)
+      if (MEM_P (x))
        {
          /* In this case we can use lwc1, swc1, ldc1 or sdc1.  */
          return NO_REGS;
@@ -7343,21 +7738,46 @@ mips_secondary_reload_class (enum reg_class class,
    Usually all registers are word-sized.  The only supported exception
    is -mgp64 -msingle-float, which has 64-bit words but 32-bit float
    registers.  A word-based calculation is correct even in that case,
-   since -msingle-float disallows multi-FPR values.  */
+   since -msingle-float disallows multi-FPR values.
+
+   The FP status registers are an exception to this rule.  They are always
+   4 bytes wide as they only hold condition code modes, and CCmode is always
+   considered to be 4 bytes wide.  */
 
 int
 mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,
                      enum machine_mode mode)
 {
-  return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (class == ST_REGS)
+    return (GET_MODE_SIZE (mode) + 3) / 4;
+  else
+    return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 }
 
-bool
+static bool
 mips_valid_pointer_mode (enum machine_mode mode)
 {
   return (mode == SImode || (TARGET_64BIT && mode == DImode));
 }
 
+/* Target hook for vector_mode_supported_p.  */
+
+static bool
+mips_vector_mode_supported_p (enum machine_mode mode)
+{
+  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
    operators) return the small data pointer, otherwise return null.
@@ -7375,7 +7795,6 @@ mips16_gp_pseudo_reg (void)
       rtx insn, scan;
 
       cfun->machine->mips16_gp_pseudo_rtx = gen_reg_rtx (Pmode);
-      RTX_UNCHANGING_P (cfun->machine->mips16_gp_pseudo_rtx) = 1;
 
       /* We want to initialize this to a value which gcc will believe
          is constant.  */
@@ -7390,7 +7809,7 @@ mips16_gp_pseudo_reg (void)
       /* We need to emit the initialization after the FUNCTION_BEG
          note, so that it will be integrated.  */
       for (scan = get_insns (); scan != NULL_RTX; scan = NEXT_INSN (scan))
-       if (GET_CODE (scan) == NOTE
+       if (NOTE_P (scan)
            && NOTE_LINE_NUMBER (scan) == NOTE_INSN_FUNCTION_BEG)
          break;
       if (scan == NULL_RTX)
@@ -7416,8 +7835,7 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
   unsigned int f;
 
   /* This code only works for the original 32 bit ABI and the O64 ABI.  */
-  if (!TARGET_OLDABI)
-    abort ();
+  gcc_assert (TARGET_OLDABI);
 
   if (from_fp_p)
     s = "mfc1";
@@ -7456,7 +7874,7 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
            }
        }
       else
-       abort ();
+       gcc_unreachable ();
 
       ++gparg;
       ++fparg;
@@ -7499,11 +7917,11 @@ 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
-     within a .ent, and we can not emit another .ent.  */
+     within a .ent, and we cannot emit another .ent.  */
   if (!FUNCTION_NAME_ALREADY_DECLARED)
     {
       fputs ("\t.ent\t", file);
@@ -7544,7 +7962,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
@@ -7613,13 +8031,12 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
 
   /* This code will only work for o32 and o64 abis.  The other ABI's
      require more sophisticated support.  */
-  if (!TARGET_OLDABI)
-    abort ();
+  gcc_assert (TARGET_OLDABI);
 
   /* We can only handle SFmode and DFmode floating point return
      values.  */
-  if (fpret && GET_MODE (retval) != SFmode && GET_MODE (retval) != DFmode)
-    abort ();
+  if (fpret)
+    gcc_assert (GET_MODE (retval) == SFmode || GET_MODE (retval) == DFmode);
 
   /* If we're calling via a function pointer, then we must always call
      via a stub.  There are magic stubs provided in libgcc.a for each
@@ -7652,8 +8069,6 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
       insn = emit_call_insn (insn);
 
       /* Put the register usage information on the CALL.  */
-      if (GET_CODE (insn) != CALL_INSN)
-       abort ();
       CALL_INSN_FUNCTION_USAGE (insn) =
        gen_rtx_EXPR_LIST (VOIDmode,
                           gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 2)),
@@ -7836,7 +8251,7 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
      Fortunately, this case is illegal, since it means that a function
      was declared in two different ways in a single compilation.  */
   if (fpret && ! l->fpret)
-    error ("can not handle inconsistent calls to `%s'", fnname);
+    error ("cannot handle inconsistent calls to %qs", fnname);
 
   /* If we are calling a stub which handles a floating point return
      value, we need to arrange to save $18 in the prologue.  We do
@@ -7854,9 +8269,6 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
        insn = gen_call_value_internal (retval, fn, arg_size);
       insn = emit_call_insn (insn);
 
-      if (GET_CODE (insn) != CALL_INSN)
-       abort ();
-
       CALL_INSN_FUNCTION_USAGE (insn) =
        gen_rtx_EXPR_LIST (VOIDmode,
                           gen_rtx_USE (VOIDmode, gen_rtx_REG (word_mode, 18)),
@@ -7976,7 +8388,7 @@ dump_constants_1 (enum machine_mode mode, rtx value, rtx insn)
       }
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -8010,16 +8422,12 @@ 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)
 {
-  if (GET_CODE (insn) == JUMP_INSN)
+  if (JUMP_P (insn))
     {
       rtx body = PATTERN (insn);
       if (GET_CODE (body) == ADDR_VEC)
@@ -8333,8 +8741,8 @@ vr4130_avoid_branch_rt_conflict (rtx insn)
 
   first = SEQ_BEGIN (insn);
   second = SEQ_END (insn);
-  if (GET_CODE (first) == JUMP_INSN
-      && GET_CODE (second) == INSN
+  if (JUMP_P (first)
+      && NONJUMP_INSN_P (second)
       && GET_CODE (PATTERN (first)) == SET
       && GET_CODE (SET_DEST (PATTERN (first))) == PC
       && GET_CODE (SET_SRC (PATTERN (first))) == IF_THEN_ELSE)
@@ -8409,7 +8817,7 @@ vr4130_align_insns (void)
               way, if the nop makes Y aligned, it will also align any labels
               between X and Y.  */
            if (state.insns_left != state.issue_rate
-               && GET_CODE (subinsn) != CALL_INSN)
+               && !CALL_P (subinsn))
              {
                if (subinsn == SEQ_BEGIN (insn) && aligned_p)
                  {
@@ -8448,7 +8856,7 @@ vr4130_align_insns (void)
             mips.md patern, the length is only an estimate.  Insert an
             8 byte alignment after it so that the following instructions
             can be handled correctly.  */
-         if (GET_CODE (SEQ_BEGIN (insn)) == INSN
+         if (NONJUMP_INSN_P (SEQ_BEGIN (insn))
              && (recog_memoized (insn) < 0 || length >= 8))
            {
              next = emit_insn_after (gen_align (GEN_INT (3)), insn);
@@ -8539,8 +8947,7 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
 
       case HAZARD_DELAY:
        set = single_set (insn);
-       if (set == 0)
-         abort ();
+       gcc_assert (set != 0);
        *delayed_reg = SET_DEST (set);
        break;
       }
@@ -8564,10 +8971,24 @@ mips_avoid_hazards (void)
   cfun->machine->ignore_hazard_length_p = true;
   shorten_branches (get_insns ());
 
-  /* The profiler code uses assembler macros.  -mfix-vr4120 relies on
-     assembler nop insertion.  */
-  cfun->machine->all_noreorder_p = (!current_function_profile
-                                   && !TARGET_FIX_VR4120);
+  cfun->machine->all_noreorder_p = true;
+
+  /* Profiled functions can't be all noreorder because the profiler
+     support uses assembler macros.  */
+  if (current_function_profile)
+    cfun->machine->all_noreorder_p = false;
+
+  /* Code compiled with -mfix-vr4120 can't be all noreorder because
+     we rely on the assembler to work around some errata.  */
+  if (TARGET_FIX_VR4120)
+    cfun->machine->all_noreorder_p = false;
+
+  /* The same is true for -mfix-vr4130 if we might generate mflo or
+     mfhi instructions.  Note that we avoid using mflo and mfhi if
+     the VR4130 macc and dmacc instructions are available instead;
+     see the *mfhilo_{si,di}_macc patterns.  */
+  if (TARGET_FIX_VR4130 && !ISA_HAS_MACCHI)
+    cfun->machine->all_noreorder_p = false;
 
   last_insn = 0;
   hilo_delay = 2;
@@ -8600,7 +9021,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 ();
@@ -8720,7 +9141,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;
@@ -8731,7 +9152,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))
@@ -8740,8 +9161,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))
        {
@@ -8750,15 +9171,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;
 }
@@ -8828,217 +9250,126 @@ mips_output_load_label (void)
     }
 }
 
+/* Return the assembly code for INSN, which has the operands given by
+   OPERANDS, and which branches to OPERANDS[1] if some condition is true.
+   BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[1]
+   is in range of a direct branch.  BRANCH_IF_FALSE is an inverted
+   version of BRANCH_IF_TRUE.  */
 
-/* Output assembly instructions to peform a conditional branch.
-
-   INSN is the branch instruction.  OPERANDS[0] is the condition.
-   OPERANDS[1] is the target of the branch.  OPERANDS[2] is the target
-   of the first operand to the condition.  If TWO_OPERANDS_P is
-   nonzero the comparison takes two operands; OPERANDS[3] will be the
-   second operand.
-
-   If INVERTED_P is nonzero we are to branch if the condition does
-   not hold.  If FLOAT_P is nonzero this is a floating-point comparison.
-
-   LENGTH is the length (in bytes) of the sequence we are to generate.
-   That tells us whether to generate a simple conditional branch, or a
-   reversed conditional branch around a `jr' instruction.  */
 const char *
-mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p,
-                               int float_p, int inverted_p, int length)
-{
-  static char buffer[200];
-  /* The kind of comparison we are doing.  */
-  enum rtx_code code = GET_CODE (operands[0]);
-  /* Nonzero if the opcode for the comparison needs a `z' indicating
-     that it is a comparison against zero.  */
-  int need_z_p;
-  /* A string to use in the assembly output to represent the first
-     operand.  */
-  const char *op1 = "%z2";
-  /* A string to use in the assembly output to represent the second
-     operand.  Use the hard-wired zero register if there's no second
-     operand.  */
-  const char *op2 = (two_operands_p ? ",%z3" : ",%.");
-  /* The operand-printing string for the comparison.  */
-  const char *const comp = (float_p ? "%F0" : "%C0");
-  /* The operand-printing string for the inverted comparison.  */
-  const char *const inverted_comp = (float_p ? "%W0" : "%N0");
-
-  /* The MIPS processors (for levels of the ISA at least two), have
-     "likely" variants of each branch instruction.  These instructions
-     annul the instruction in the delay slot if the branch is not
-     taken.  */
-  mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
-
-  if (!two_operands_p)
-    {
-      /* To compute whether than A > B, for example, we normally
-        subtract B from A and then look at the sign bit.  But, if we
-        are doing an unsigned comparison, and B is zero, we don't
-        have to do the subtraction.  Instead, we can just check to
-        see if A is nonzero.  Thus, we change the CODE here to
-        reflect the simpler comparison operation.  */
-      switch (code)
-       {
-       case GTU:
-         code = NE;
-         break;
+mips_output_conditional_branch (rtx insn, rtx *operands,
+                               const char *branch_if_true,
+                               const char *branch_if_false)
+{
+  unsigned int length;
+  rtx taken, not_taken;
 
-       case LEU:
-         code = EQ;
-         break;
+  length = get_attr_length (insn);
+  if (length <= 8)
+    {
+      /* Just a simple conditional branch.  */
+      mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
+      return branch_if_true;
+    }
 
-       case GEU:
-         /* A condition which will always be true.  */
-         code = EQ;
-         op1 = "%.";
-         break;
+  /* Generate a reversed branch around a direct jump.  This fallback does
+     not use branch-likely instructions.  */
+  mips_branch_likely = false;
+  not_taken = gen_label_rtx ();
+  taken = operands[1];
 
-       case LTU:
-         /* A condition which will always be false.  */
-         code = NE;
-         op1 = "%.";
-         break;
+  /* Generate the reversed branch to NOT_TAKEN.  */
+  operands[1] = not_taken;
+  output_asm_insn (branch_if_false, operands);
 
-       default:
-         /* Not a special case.  */
-         break;
+  /* If INSN has a delay slot, we must provide delay slots for both the
+     branch to NOT_TAKEN and the conditional jump.  We must also ensure
+     that INSN's delay slot is executed in the appropriate cases.  */
+  if (final_sequence)
+    {
+      /* This first delay slot will always be executed, so use INSN's
+        delay slot if is not annulled.  */
+      if (!INSN_ANNULLED_BRANCH_P (insn))
+       {
+         final_scan_insn (XVECEXP (final_sequence, 0, 1),
+                          asm_out_file, optimize, 1, NULL);
+         INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
        }
+      else
+       output_asm_insn ("nop", 0);
+      fprintf (asm_out_file, "\n");
     }
 
-  /* Relative comparisons are always done against zero.  But
-     equality comparisons are done between two operands, and therefore
-     do not require a `z' in the assembly language output.  */
-  need_z_p = (!float_p && code != EQ && code != NE);
-  /* For comparisons against zero, the zero is not provided
-     explicitly.  */
-  if (need_z_p)
-    op2 = "";
-
-  /* Begin by terminating the buffer.  That way we can always use
-     strcat to add to it.  */
-  buffer[0] = '\0';
+  /* Output the unconditional branch to TAKEN.  */
+  if (length <= 16)
+    output_asm_insn ("j\t%0%/", &taken);
+  else
+    {
+      output_asm_insn (mips_output_load_label (), &taken);
+      output_asm_insn ("jr\t%@%]%/", 0);
+    }
 
-  switch (length)
+  /* Now deal with its delay slot; see above.  */
+  if (final_sequence)
     {
-    case 4:
-    case 8:
-      /* Just a simple conditional branch.  */
-      if (float_p)
-       sprintf (buffer, "%%*b%s%%?\t%%Z2%%1%%/",
-                inverted_p ? inverted_comp : comp);
+      /* This delay slot will only be executed if the branch is taken.
+        Use INSN's delay slot if is annulled.  */
+      if (INSN_ANNULLED_BRANCH_P (insn))
+       {
+         final_scan_insn (XVECEXP (final_sequence, 0, 1),
+                          asm_out_file, optimize, 1, NULL);
+         INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
+       }
       else
-       sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1%%/",
-                inverted_p ? inverted_comp : comp,
-                need_z_p ? "z" : "",
-                op1,
-                op2);
-      return buffer;
-
-    case 12:
-    case 16:
-    case 24:
-    case 28:
-      {
-       /* Generate a reversed conditional branch around ` j'
-          instruction:
-
-               .set noreorder
-               .set nomacro
-               bc    l
-               delay_slot or #nop
-               j     target
-               #nop
-            l:
-               .set macro
-               .set reorder
-
-          If the original branch was a likely branch, the delay slot
-          must be executed only if the branch is taken, so generate:
-
-               .set noreorder
-               .set nomacro
-               bc    l
-               #nop
-               j     target
-               delay slot or #nop
-            l:
-               .set macro
-               .set reorder
-
-          When generating PIC, instead of:
-
-               j     target
-
-          we emit:
-
-               .set noat
-               la    $at, target
-               jr    $at
-               .set at
-       */
-
-        rtx orig_target;
-       rtx target = gen_label_rtx ();
-
-        orig_target = operands[1];
-        operands[1] = target;
-       /* Generate the reversed comparison.  This takes four
-          bytes.  */
-       if (float_p)
-         sprintf (buffer, "%%*b%s\t%%Z2%%1",
-                  inverted_p ? comp : inverted_comp);
-       else
-         sprintf (buffer, "%%*b%s%s\t%s%s,%%1",
-                  inverted_p ? comp : inverted_comp,
-                  need_z_p ? "z" : "",
-                  op1,
-                  op2);
-        output_asm_insn (buffer, operands);
-
-        if (length != 16 && length != 28 && ! mips_branch_likely)
-          {
-            /* Output delay slot instruction.  */
-            rtx insn = final_sequence;
-            final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
-                             optimize, 0, 1, NULL);
-            INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
-          }
-       else
-         output_asm_insn ("%#", 0);
+       output_asm_insn ("nop", 0);
+      fprintf (asm_out_file, "\n");
+    }
 
-       if (length <= 16)
-         output_asm_insn ("j\t%0", &orig_target);
-       else
-         {
-           output_asm_insn (mips_output_load_label (), &orig_target);
-           output_asm_insn ("jr\t%@%]", 0);
-         }
+  /* Output NOT_TAKEN.  */
+  (*targetm.asm_out.internal_label) (asm_out_file, "L",
+                                    CODE_LABEL_NUMBER (not_taken));
+  return "";
+}
 
-        if (length != 16 && length != 28 && mips_branch_likely)
-          {
-            /* Output delay slot instruction.  */
-            rtx insn = final_sequence;
-            final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
-                             optimize, 0, 1, NULL);
-            INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
-          }
-       else
-         output_asm_insn ("%#", 0);
+/* Return the assembly code for INSN, which branches to OPERANDS[1]
+   if some ordered condition is true.  The condition is given by
+   OPERANDS[0] if !INVERTED_P, otherwise it is the inverse of
+   OPERANDS[0].  OPERANDS[2] is the comparison's first operand;
+   its second is always zero.  */
+
+const char *
+mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
+{
+  const char *branch[2];
 
-        (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                   CODE_LABEL_NUMBER (target));
+  /* Make BRANCH[1] branch to OPERANDS[1] when the condition is true.
+     Make BRANCH[0] branch on the inverse condition.  */
+  switch (GET_CODE (operands[0]))
+    {
+      /* These cases are equivalent to comparisons against zero.  */
+    case LEU:
+      inverted_p = !inverted_p;
+      /* Fall through.  */
+    case GTU:
+      branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%1");
+      branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%1");
+      break;
 
-        return "";
-      }
+      /* These cases are always true or always false.  */
+    case LTU:
+      inverted_p = !inverted_p;
+      /* Fall through.  */
+    case GEU:
+      branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%1");
+      branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%1");
+      break;
 
     default:
-      abort ();
+      branch[!inverted_p] = MIPS_BRANCH ("b%C0z", "%2,%1");
+      branch[inverted_p] = MIPS_BRANCH ("b%N0z", "%2,%1");
+      break;
     }
-
-  /* NOTREACHED */
-  return 0;
+  return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
 }
 \f
 /* Used to output div or ddiv instruction DIVISION, which has the operands
@@ -9148,6 +9479,11 @@ mips_output_division (const char *division, rtx *operands)
          output_asm_insn (s, operands);
          s = "bnez\t%2,1f\n\tbreak\t7\n1:";
        }
+      else if (GENERATE_DIVIDE_TRAPS)
+        {
+         output_asm_insn (s, operands);
+         s = "teq\t%2,%.,7";
+        }
       else
        {
          output_asm_insn ("%(bne\t%2,%.,1f", operands);
@@ -9207,15 +9543,13 @@ mips_matching_cpu_name_p (const char *canonical, const char *given)
 }
 
 
-/* Parse an option that takes the name of a processor as its argument.
-   OPTION is the name of the option and CPU_STRING is the argument.
-   Return the corresponding processor enumeration if the CPU_STRING is
-   recognized, otherwise report an error and return null.
+/* Return the mips_cpu_info entry for the processor or ISA given
+   by CPU_STRING.  Return null if the string isn't recognized.
 
    A similar function exists in GAS.  */
 
 static const struct mips_cpu_info *
-mips_parse_cpu (const char *option, const char *cpu_string)
+mips_parse_cpu (const char *cpu_string)
 {
   const struct mips_cpu_info *p;
   const char *s;
@@ -9225,7 +9559,7 @@ mips_parse_cpu (const char *option, 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;
       }
 
@@ -9247,7 +9581,6 @@ mips_parse_cpu (const char *option, const char *cpu_string)
     if (mips_matching_cpu_name_p (p->name, cpu_string))
       return p;
 
-  error ("bad value (%s) for %s", cpu_string, option);
   return 0;
 }
 
@@ -9267,13 +9600,17 @@ mips_cpu_info_from_isa (int isa)
   return 0;
 }
 \f
-/* Implement HARD_REGNO_NREGS.  The size of FP registers are controlled
-   by UNITS_PER_FPREG.  All other registers are word sized.  */
+/* Implement HARD_REGNO_NREGS.  The size of FP registers is controlled
+   by UNITS_PER_FPREG.  The size of FP status registers is always 4, because
+   they only hold condition code modes, and CCmode is always considered to
+   be 4 bytes wide.  All other registers are word sized.  */
 
 unsigned int
 mips_hard_regno_nregs (int regno, enum machine_mode mode)
 {
-  if (! FP_REG_P (regno))
+  if (ST_REG_P (regno))
+    return ((GET_MODE_SIZE (mode) + 3) / 4);
+  else if (! FP_REG_P (regno))
     return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
   else
     return ((GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG);
@@ -9565,9 +9902,6 @@ mips_issue_rate (void)
     default:
       return 1;
     }
-
-  abort ();
-
 }
 
 /* Implements TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD.  This should
@@ -9583,226 +9917,859 @@ mips_multipass_dfa_lookahead (void)
   return 0;
 }
 \f
+/* Given that we have an rtx of the form (prefetch ... WRITE LOCALITY),
+   return the first operand of the associated "pref" or "prefx" insn.  */
 
-const char *
-mips_emit_prefetch (rtx *operands)
-{
-  int write = INTVAL (operands[1]);
-  int locality = INTVAL (operands[2]);
-  int indexed = GET_CODE (operands[3]) == REG;
-  int code;
-  char buffer[30];
-
-  if (locality <= 0)
-    code = (write ? 5 : 4);    /* store_streamed / load_streamed.  */
-  else if (locality <= 2)
-    code = (write ? 1 : 0);    /* store / load.  */
-  else
-    code = (write ? 7 : 6);    /* store_retained / load_retained.  */
+rtx
+mips_prefetch_cookie (rtx write, rtx locality)
+{
+  /* store_streamed / load_streamed.  */
+  if (INTVAL (locality) <= 0)
+    return GEN_INT (INTVAL (write) + 4);
 
-  sprintf (buffer, "%s\t%d,%%3(%%0)", indexed ? "prefx" : "pref", code);
-  output_asm_insn (buffer, operands);
-  return "";
+  /* store / load.  */
+  if (INTVAL (locality) <= 2)
+    return write;
+
+  /* store_retained / load_retained.  */
+  return GEN_INT (INTVAL (write) + 6);
 }
+\f
+/* MIPS builtin function support. */
 
+struct builtin_description
+{
+  /* The code of the main .md file instruction.  See mips_builtin_type
+     for more information.  */
+  enum insn_code icode;
 
-\f
-#if TARGET_IRIX
-/* Output assembly to switch to section NAME with attribute FLAGS.  */
+  /* The floating-point comparison code to use with ICODE, if any.  */
+  enum mips_fp_condition cond;
 
-static void
-irix_asm_named_section_1 (const char *name, unsigned int flags,
-                          unsigned int align)
-{
-  unsigned int sh_type, sh_flags, sh_entsize;
-
-  sh_flags = 0;
-  if (!(flags & SECTION_DEBUG))
-    sh_flags |= 2; /* SHF_ALLOC */
-  if (flags & SECTION_WRITE)
-    sh_flags |= 1; /* SHF_WRITE */
-  if (flags & SECTION_CODE)
-    sh_flags |= 4; /* SHF_EXECINSTR */
-  if (flags & SECTION_SMALL)
-    sh_flags |= 0x10000000; /* SHF_MIPS_GPREL */
-  if (strcmp (name, ".debug_frame") == 0)
-    sh_flags |= 0x08000000; /* SHF_MIPS_NOSTRIP */
-  if (flags & SECTION_DEBUG)
-    sh_type = 0x7000001e; /* SHT_MIPS_DWARF */
-  else if (flags & SECTION_BSS)
-    sh_type = 8; /* SHT_NOBITS */
-  else
-    sh_type = 1; /* SHT_PROGBITS */
+  /* The name of the builtin function.  */
+  const char *name;
 
-  if (flags & SECTION_CODE)
-    sh_entsize = 4;
-  else
-    sh_entsize = 0;
+  /* Specifies how the function should be expanded.  */
+  enum mips_builtin_type builtin_type;
 
-  fprintf (asm_out_file, "\t.section %s,%#x,%#x,%u,%u\n",
-          name, sh_type, sh_flags, sh_entsize, align);
-}
+  /* The function's prototype.  */
+  enum mips_function_type function_type;
 
-static void
-irix_asm_named_section (const char *name, unsigned int flags)
+  /* The target flags required for this function.  */
+  int target_flags;
+};
+
+/* Define a MIPS_BUILTIN_DIRECT function for instruction CODE_FOR_mips_<INSN>.
+   FUNCTION_TYPE and TARGET_FLAGS are builtin_description fields.  */
+#define DIRECT_BUILTIN(INSN, FUNCTION_TYPE, TARGET_FLAGS)              \
+  { CODE_FOR_mips_ ## INSN, 0, "__builtin_mips_" #INSN,                        \
+    MIPS_BUILTIN_DIRECT, FUNCTION_TYPE, TARGET_FLAGS }
+
+/* Define __builtin_mips_<INSN>_<COND>_{s,d}, both of which require
+   TARGET_FLAGS.  */
+#define CMP_SCALAR_BUILTINS(INSN, COND, TARGET_FLAGS)                  \
+  { CODE_FOR_mips_ ## INSN ## _cond_s, MIPS_FP_COND_ ## COND,          \
+    "__builtin_mips_" #INSN "_" #COND "_s",                            \
+    MIPS_BUILTIN_CMP_SINGLE, MIPS_INT_FTYPE_SF_SF, TARGET_FLAGS },     \
+  { CODE_FOR_mips_ ## INSN ## _cond_d, MIPS_FP_COND_ ## COND,          \
+    "__builtin_mips_" #INSN "_" #COND "_d",                            \
+    MIPS_BUILTIN_CMP_SINGLE, MIPS_INT_FTYPE_DF_DF, TARGET_FLAGS }
+
+/* Define __builtin_mips_{any,all,upper,lower}_<INSN>_<COND>_ps.
+   The lower and upper forms require TARGET_FLAGS while the any and all
+   forms require MASK_MIPS3D.  */
+#define CMP_PS_BUILTINS(INSN, COND, TARGET_FLAGS)                      \
+  { CODE_FOR_mips_ ## INSN ## _cond_ps, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_any_" #INSN "_" #COND "_ps",                       \
+    MIPS_BUILTIN_CMP_ANY, MIPS_INT_FTYPE_V2SF_V2SF, MASK_MIPS3D },     \
+  { CODE_FOR_mips_ ## INSN ## _cond_ps, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_all_" #INSN "_" #COND "_ps",                       \
+    MIPS_BUILTIN_CMP_ALL, MIPS_INT_FTYPE_V2SF_V2SF, MASK_MIPS3D },     \
+  { CODE_FOR_mips_ ## INSN ## _cond_ps, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_lower_" #INSN "_" #COND "_ps",                     \
+    MIPS_BUILTIN_CMP_LOWER, MIPS_INT_FTYPE_V2SF_V2SF, TARGET_FLAGS },  \
+  { CODE_FOR_mips_ ## INSN ## _cond_ps, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_upper_" #INSN "_" #COND "_ps",                     \
+    MIPS_BUILTIN_CMP_UPPER, MIPS_INT_FTYPE_V2SF_V2SF, TARGET_FLAGS }
+
+/* Define __builtin_mips_{any,all}_<INSN>_<COND>_4s.  The functions
+   require MASK_MIPS3D.  */
+#define CMP_4S_BUILTINS(INSN, COND)                                    \
+  { CODE_FOR_mips_ ## INSN ## _cond_4s, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_any_" #INSN "_" #COND "_4s",                       \
+    MIPS_BUILTIN_CMP_ANY, MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF,          \
+    MASK_MIPS3D },                                                     \
+  { CODE_FOR_mips_ ## INSN ## _cond_4s, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_all_" #INSN "_" #COND "_4s",                       \
+    MIPS_BUILTIN_CMP_ALL, MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF,          \
+    MASK_MIPS3D }
+
+/* Define __builtin_mips_mov{t,f}_<INSN>_<COND>_ps.  The comparison
+   instruction requires TARGET_FLAGS.  */
+#define MOVTF_BUILTINS(INSN, COND, TARGET_FLAGS)                       \
+  { CODE_FOR_mips_ ## INSN ## _cond_ps, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_movt_" #INSN "_" #COND "_ps",                      \
+    MIPS_BUILTIN_MOVT, MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF,            \
+    TARGET_FLAGS },                                                    \
+  { CODE_FOR_mips_ ## INSN ## _cond_ps, MIPS_FP_COND_ ## COND,         \
+    "__builtin_mips_movf_" #INSN "_" #COND "_ps",                      \
+    MIPS_BUILTIN_MOVF, MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF,            \
+    TARGET_FLAGS }
+
+/* Define all the builtins related to c.cond.fmt condition COND.  */
+#define CMP_BUILTINS(COND)                                             \
+  MOVTF_BUILTINS (c, COND, MASK_PAIRED_SINGLE_FLOAT),                  \
+  MOVTF_BUILTINS (cabs, COND, MASK_MIPS3D),                            \
+  CMP_SCALAR_BUILTINS (cabs, COND, MASK_MIPS3D),                       \
+  CMP_PS_BUILTINS (c, COND, MASK_PAIRED_SINGLE_FLOAT),                 \
+  CMP_PS_BUILTINS (cabs, COND, MASK_MIPS3D),                           \
+  CMP_4S_BUILTINS (c, COND),                                           \
+  CMP_4S_BUILTINS (cabs, COND)
+
+/* __builtin_mips_abs_ps() maps to the standard absM2 pattern.  */
+#define CODE_FOR_mips_abs_ps CODE_FOR_absv2sf2
+
+static const struct builtin_description mips_bdesc[] =
+{
+  DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (plu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (puu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (cvt_ps_s, MIPS_V2SF_FTYPE_SF_SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (cvt_s_pl, MIPS_SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (cvt_s_pu, MIPS_SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (abs_ps, MIPS_V2SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+
+  DIRECT_BUILTIN (alnv_ps, MIPS_V2SF_FTYPE_V2SF_V2SF_INT,
+                 MASK_PAIRED_SINGLE_FLOAT),
+  DIRECT_BUILTIN (addr_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (mulr_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (cvt_pw_ps, MIPS_V2SF_FTYPE_V2SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (cvt_ps_pw, MIPS_V2SF_FTYPE_V2SF, MASK_MIPS3D),
+
+  DIRECT_BUILTIN (recip1_s, MIPS_SF_FTYPE_SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (recip1_d, MIPS_DF_FTYPE_DF, MASK_MIPS3D),
+  DIRECT_BUILTIN (recip1_ps, MIPS_V2SF_FTYPE_V2SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (recip2_s, MIPS_SF_FTYPE_SF_SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (recip2_d, MIPS_DF_FTYPE_DF_DF, MASK_MIPS3D),
+  DIRECT_BUILTIN (recip2_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_MIPS3D),
+
+  DIRECT_BUILTIN (rsqrt1_s, MIPS_SF_FTYPE_SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (rsqrt1_d, MIPS_DF_FTYPE_DF, MASK_MIPS3D),
+  DIRECT_BUILTIN (rsqrt1_ps, MIPS_V2SF_FTYPE_V2SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (rsqrt2_s, MIPS_SF_FTYPE_SF_SF, MASK_MIPS3D),
+  DIRECT_BUILTIN (rsqrt2_d, MIPS_DF_FTYPE_DF_DF, MASK_MIPS3D),
+  DIRECT_BUILTIN (rsqrt2_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_MIPS3D),
+
+  MIPS_FP_CONDITIONS (CMP_BUILTINS)
+};
+
+/* Builtin functions for the SB-1 processor.  */
+
+#define CODE_FOR_mips_sqrt_ps CODE_FOR_sqrtv2sf2
+
+static const struct builtin_description sb1_bdesc[] =
 {
-  if (TARGET_SGI_O32_AS)
-    default_no_named_section (name, flags);
-  else if (mips_abi == ABI_32 && TARGET_GAS)
-    default_elf_asm_named_section (name, flags);
-  else
-    irix_asm_named_section_1 (name, flags, 0);
-}
+  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)
+};
 
-/* In addition to emitting a .align directive, record the maximum
-   alignment requested for the current section.  */
+/* This helps provide a mapping from builtin function codes to bdesc
+   arrays.  */
 
-struct irix_section_align_entry GTY (())
+struct bdesc_map
 {
-  const char *name;
-  unsigned int log;
-  unsigned int flags;
+  /* The builtin function table that this entry describes.  */
+  const struct builtin_description *bdesc;
+
+  /* The number of entries in the builtin function table.  */
+  unsigned int size;
+
+  /* The target processor that supports these builtin functions.
+     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_MAX },
+  { sb1_bdesc, ARRAY_SIZE (sb1_bdesc), PROCESSOR_SB1 },
+  { dsp_bdesc, ARRAY_SIZE (dsp_bdesc), PROCESSOR_MAX }
 };
 
-static htab_t irix_section_align_htab;
-static FILE *irix_orig_asm_out_file;
+/* Take the head of argument list *ARGLIST and convert it into a form
+   suitable for input operand OP of instruction ICODE.  Return the value
+   and point *ARGLIST at the next element of the list.  */
 
-static int
-irix_section_align_entry_eq (const void *p1, const void *p2)
+static rtx
+mips_prepare_builtin_arg (enum insn_code icode,
+                         unsigned int op, tree *arglist)
 {
-  const struct irix_section_align_entry *old = p1;
-  const char *new = p2;
+  rtx value;
+  enum machine_mode mode;
+
+  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);
+      /* Check the predicate again.  */
+      if (!insn_data[icode].operand[op].predicate (value, mode))
+       {
+         error ("invalid argument to builtin function");
+         return const0_rtx;
+       }
+    }
 
-  return strcmp (old->name, new) == 0;
+  *arglist = TREE_CHAIN (*arglist);
+  return value;
 }
 
-static hashval_t
-irix_section_align_entry_hash (const void *p)
+/* Return an rtx suitable for output operand OP of instruction ICODE.
+   If TARGET is non-null, try to use it where possible.  */
+
+static rtx
+mips_prepare_builtin_target (enum insn_code icode, unsigned int op, rtx target)
 {
-  const struct irix_section_align_entry *old = p;
-  return htab_hash_string (old->name);
+  enum machine_mode mode;
+
+  mode = insn_data[icode].operand[op].mode;
+  if (target == 0 || !insn_data[icode].operand[op].predicate (target, mode))
+    target = gen_reg_rtx (mode);
+
+  return target;
 }
 
-void
-irix_asm_output_align (FILE *file, unsigned int log)
+/* Expand builtin functions.  This is called from TARGET_EXPAND_BUILTIN.  */
+
+rtx
+mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+                    enum machine_mode mode ATTRIBUTE_UNUSED,
+                    int ignore ATTRIBUTE_UNUSED)
 {
-  const char *section = current_section_name ();
-  struct irix_section_align_entry **slot, *entry;
+  enum insn_code icode;
+  enum mips_builtin_type type;
+  tree fndecl, arglist;
+  unsigned int fcode;
+  const struct builtin_description *bdesc;
+  const struct bdesc_map *m;
 
-  if (mips_abi != ABI_32)
-    {
-      if (! section)
-       abort ();
+  fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  arglist = TREE_OPERAND (exp, 1);
+  fcode = DECL_FUNCTION_CODE (fndecl);
 
-      slot = (struct irix_section_align_entry **)
-       htab_find_slot_with_hash (irix_section_align_htab, section,
-                                 htab_hash_string (section), INSERT);
-      entry = *slot;
-      if (! entry)
+  bdesc = NULL;
+  for (m = bdesc_arrays; m < &bdesc_arrays[ARRAY_SIZE (bdesc_arrays)]; m++)
+    {
+      if (fcode < m->size)
        {
-         entry = (struct irix_section_align_entry *)
-           xmalloc (sizeof (struct irix_section_align_entry));
-         *slot = entry;
-         entry->name = section;
-         entry->log = log;
-         entry->flags = current_section_flags ();
+         bdesc = m->bdesc;
+         icode = bdesc[fcode].icode;
+         type = bdesc[fcode].builtin_type;
+         break;
        }
-      else if (entry->log < log)
-       entry->log = log;
+      fcode -= m->size;
     }
+  if (bdesc == NULL)
+    return 0;
+
+  switch (type)
+    {
+    case MIPS_BUILTIN_DIRECT:
+      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:
+      return mips_expand_builtin_movtf (type, icode, bdesc[fcode].cond,
+                                       target, arglist);
 
-  fprintf (file, "\t.align\t%u\n", log);
+    case MIPS_BUILTIN_CMP_ANY:
+    case MIPS_BUILTIN_CMP_ALL:
+    case MIPS_BUILTIN_CMP_UPPER:
+    case MIPS_BUILTIN_CMP_LOWER:
+    case MIPS_BUILTIN_CMP_SINGLE:
+      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;
+    }
 }
 
-/* The IRIX assembler does not record alignment from .align directives,
-   but takes it from the first .section directive seen.  Play file
-   switching games so that we can emit a .section directive at the
-   beginning of the file with the proper alignment attached.  */
+/* Init builtin functions.  This is called from TARGET_INIT_BUILTIN.  */
 
-static void
-irix_file_start (void)
+void
+mips_init_builtins (void)
+{
+  const struct builtin_description *d;
+  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, -mips3d and -mdsp.  */
+  if (!TARGET_PAIRED_SINGLE_FLOAT && !TARGET_DSP)
+    return;
+
+  if (TARGET_PAIRED_SINGLE_FLOAT)
+    {
+      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);
+
+      types[MIPS_V2SF_FTYPE_SF_SF]
+       = build_function_type_list (V2SF_type_node,
+                                   float_type_node, float_type_node, NULL_TREE);
+
+      types[MIPS_INT_FTYPE_V2SF_V2SF]
+       = build_function_type_list (integer_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_INT_FTYPE_SF_SF]
+       = build_function_type_list (integer_type_node,
+                                   float_type_node, float_type_node, NULL_TREE);
+
+      types[MIPS_INT_FTYPE_DF_DF]
+       = build_function_type_list (integer_type_node,
+                                   double_type_node, double_type_node, NULL_TREE);
+
+      types[MIPS_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.  */
+
+  offset = 0;
+  for (m = bdesc_arrays; m < &bdesc_arrays[ARRAY_SIZE (bdesc_arrays)]; m++)
+    {
+      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],
+                                        d - m->bdesc + offset,
+                                        BUILT_IN_MD, NULL, NULL);
+      offset += m->size;
+    }
+}
+
+/* Expand a MIPS_BUILTIN_DIRECT function.  ICODE is the code of the
+   .md pattern and ARGLIST is the list of function arguments.  TARGET,
+   if nonnull, suggests a good place to put the result.
+   HAS_TARGET indicates the function must return something.  */
+
+static rtx
+mips_expand_builtin_direct (enum insn_code icode, rtx target, tree arglist,
+                           bool has_target)
 {
-  mips_file_start ();
+  rtx ops[MAX_RECOG_OPERANDS];
+  int i = 0;
 
-  if (mips_abi == ABI_32)
-    return;
+  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 (i)
+    {
+    case 2:
+      emit_insn (GEN_FCN (icode) (ops[0], ops[1]));
+      break;
+
+    case 3:
+      emit_insn (GEN_FCN (icode) (ops[0], ops[1], ops[2]));
+      break;
 
-  irix_orig_asm_out_file = asm_out_file;
-  asm_out_file = tmpfile ();
+    case 4:
+      emit_insn (GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3]));
+      break;
 
-  irix_section_align_htab = htab_create (31, irix_section_align_entry_hash,
-                                        irix_section_align_entry_eq, NULL);
+    default:
+      gcc_unreachable ();
+    }
+  return target;
 }
 
-static int
-irix_section_align_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+/* Expand a __builtin_mips_movt_*_ps() or __builtin_mips_movf_*_ps()
+   function (TYPE says which).  ARGLIST is the list of arguments to the
+   function, ICODE is the instruction that should be used to compare
+   the first two arguments, and COND is the condition it should test.
+   TARGET, if nonnull, suggests a good place to put the result.  */
+
+static rtx
+mips_expand_builtin_movtf (enum mips_builtin_type type,
+                          enum insn_code icode, enum mips_fp_condition cond,
+                          rtx target, tree arglist)
 {
-  const struct irix_section_align_entry *entry
-    = *(const struct irix_section_align_entry **) slot;
+  rtx cmp_result, op0, op1;
+
+  cmp_result = mips_prepare_builtin_target (icode, 0, 0);
+  op0 = mips_prepare_builtin_arg (icode, 1, &arglist);
+  op1 = mips_prepare_builtin_arg (icode, 2, &arglist);
+  emit_insn (GEN_FCN (icode) (cmp_result, op0, op1, GEN_INT (cond)));
 
-  irix_asm_named_section_1 (entry->name, entry->flags, 1 << entry->log);
-  return 1;
+  icode = CODE_FOR_mips_cond_move_tf_ps;
+  target = mips_prepare_builtin_target (icode, 0, target);
+  if (type == MIPS_BUILTIN_MOVT)
+    {
+      op1 = mips_prepare_builtin_arg (icode, 2, &arglist);
+      op0 = mips_prepare_builtin_arg (icode, 1, &arglist);
+    }
+  else
+    {
+      op0 = mips_prepare_builtin_arg (icode, 1, &arglist);
+      op1 = mips_prepare_builtin_arg (icode, 2, &arglist);
+    }
+  emit_insn (gen_mips_cond_move_tf_ps (target, op0, op1, cmp_result));
+  return target;
 }
 
-static void
-copy_file_data (FILE *to, FILE *from)
+/* Move VALUE_IF_TRUE into TARGET if CONDITION is true; move VALUE_IF_FALSE
+   into TARGET otherwise.  Return TARGET.  */
+
+static rtx
+mips_builtin_branch_and_move (rtx condition, rtx target,
+                             rtx value_if_true, rtx value_if_false)
 {
-  char buffer[8192];
-  size_t len;
-  rewind (from);
-  if (ferror (from))
-    fatal_error ("can't rewind temp file: %m");
+  rtx true_label, done_label;
 
-  while ((len = fread (buffer, 1, sizeof (buffer), from)) > 0)
-    if (fwrite (buffer, 1, len, to) != len)
-      fatal_error ("can't write to output file: %m");
+  true_label = gen_label_rtx ();
+  done_label = gen_label_rtx ();
 
-  if (ferror (from))
-    fatal_error ("can't read from temp file: %m");
+  /* First assume that CONDITION is false.  */
+  emit_move_insn (target, value_if_false);
 
-  if (fclose (from))
-    fatal_error ("can't close temp file: %m");
+  /* Branch to TRUE_LABEL if CONDITION is true and DONE_LABEL otherwise.  */
+  emit_jump_insn (gen_condjump (condition, true_label));
+  emit_jump_insn (gen_jump (done_label));
+  emit_barrier ();
+
+  /* Fix TARGET if CONDITION is true.  */
+  emit_label (true_label);
+  emit_move_insn (target, value_if_true);
+
+  emit_label (done_label);
+  return target;
 }
 
-static void
-irix_file_end (void)
+/* Expand a comparison builtin of type BUILTIN_TYPE.  ICODE is the code
+   of the comparison instruction and COND is the condition it should test.
+   ARGLIST is the list of function arguments and TARGET, if nonnull,
+   suggests a good place to put the boolean result.  */
+
+static rtx
+mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
+                            enum insn_code icode, enum mips_fp_condition cond,
+                            rtx target, tree arglist)
 {
-  if (mips_abi != ABI_32)
+  rtx offset, condition, cmp_result, ops[MAX_RECOG_OPERANDS];
+  int i;
+
+  if (target == 0 || GET_MODE (target) != SImode)
+    target = gen_reg_rtx (SImode);
+
+  /* Prepare the operands to the comparison.  */
+  cmp_result = mips_prepare_builtin_target (icode, 0, 0);
+  for (i = 1; i < insn_data[icode].n_operands - 1; i++)
+    ops[i] = mips_prepare_builtin_arg (icode, i, &arglist);
+
+  switch (insn_data[icode].n_operands)
     {
-      /* Emit section directives with the proper alignment at the top of the
-        real output file.  */
-      FILE *temp = asm_out_file;
-      asm_out_file = irix_orig_asm_out_file;
-      htab_traverse (irix_section_align_htab, irix_section_align_1, NULL);
+    case 4:
+      emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2], GEN_INT (cond)));
+      break;
+
+    case 6:
+      emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2],
+                                 ops[3], ops[4], GEN_INT (cond)));
+      break;
 
-      /* Copy the data emitted to the temp file to the real output file.  */
-      copy_file_data (asm_out_file, temp);
+    default:
+      gcc_unreachable ();
     }
 
-  mips_file_end ();
+  /* If the comparison sets more than one register, we define the result
+     to be 0 if all registers are false and -1 if all registers are true.
+     The value of the complete result is indeterminate otherwise.  */
+  switch (builtin_type)
+    {
+    case MIPS_BUILTIN_CMP_ALL:
+      condition = gen_rtx_NE (VOIDmode, cmp_result, constm1_rtx);
+      return mips_builtin_branch_and_move (condition, target,
+                                          const0_rtx, const1_rtx);
+
+    case MIPS_BUILTIN_CMP_UPPER:
+    case MIPS_BUILTIN_CMP_LOWER:
+      offset = GEN_INT (builtin_type == MIPS_BUILTIN_CMP_UPPER);
+      condition = gen_single_cc (cmp_result, offset);
+      return mips_builtin_branch_and_move (condition, target,
+                                          const1_rtx, const0_rtx);
+
+    default:
+      condition = gen_rtx_NE (VOIDmode, cmp_result, const0_rtx);
+      return mips_builtin_branch_and_move (condition, target,
+                                          const1_rtx, const0_rtx);
+    }
 }
 
+/* Expand a bposge builtin of type BUILTIN_TYPE.  TARGET, if nonnull,
+   suggests a good place to put the boolean result.  */
+
+static rtx
+mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
+{
+  rtx condition, cmp_result;
+  int cmp_value;
 
-/* Implement TARGET_SECTION_TYPE_FLAGS.  Make sure that .sdata and
-   .sbss sections get the SECTION_SMALL flag: this isn't set by the
-   default code.  */
+  if (target == 0 || GET_MODE (target) != SImode)
+    target = gen_reg_rtx (SImode);
 
-static unsigned int
-irix_section_type_flags (tree decl, const char *section, int relocs_p)
+  cmp_result = gen_rtx_REG (CCDSPmode, CCDSP_PO_REGNUM);
+
+  if (builtin_type == MIPS_BUILTIN_BPOSGE32)
+    cmp_value = 32;
+  else
+    gcc_assert (0);
+
+  condition = gen_rtx_GE (VOIDmode, cmp_result, GEN_INT (cmp_value));
+  return mips_builtin_branch_and_move (condition, target,
+                                      const1_rtx, const0_rtx);
+}
+\f
+/* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL.
+   FIRST is true if this is the first time handling this decl.  */
+
+static void
+mips_encode_section_info (tree decl, rtx rtl, int first)
 {
-  unsigned int flags;
+  default_encode_section_info (decl, rtl, first);
 
-  flags = default_section_type_flags (decl, section, relocs_p);
+  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;
+    }
+}
 
-  if (strcmp (section, ".sdata") == 0
-      || strcmp (section, ".sbss") == 0
-      || strncmp (section, ".gnu.linkonce.s.", 16) == 0
-      || strncmp (section, ".gnu.linkonce.sb.", 17) == 0)
-    flags |= SECTION_SMALL;
+/* Implement TARGET_EXTRA_LIVE_ON_ENTRY.  PIC_FUNCTION_ADDR_REGNUM is live
+   on entry to a function when generating -mshared abicalls code.  */
 
-  return flags;
+static void
+mips_extra_live_on_entry (bitmap regs)
+{
+  if (TARGET_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
+    bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
 }
 
-#endif /* TARGET_IRIX */
+/* SImode values are represented as sign-extended to DImode.  */
+
+int
+mips_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
+{
+  if (TARGET_64BIT && mode == SImode && mode_rep == DImode)
+    return SIGN_EXTEND;
 
+  return UNKNOWN;
+}
+\f
 #include "gt-mips.h"