Add -Wshadow to the gcc command line options used when compiling the binutils.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index a84468a7c783761105bf545c5925114f71eebffa..ff2ffc6f9a2843d6deb07be753d0d2d987b1a72f 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
    Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
@@ -10,7 +10,7 @@
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -89,7 +89,7 @@ static char *mips_regmask_frag;
 #endif
 
 #define ZERO 0
-#define AT  1
+#define ATREG 1
 #define TREG 24
 #define PIC_CALL_REG 25
 #define KT0 26
@@ -101,6 +101,8 @@ static char *mips_regmask_frag;
 
 #define ILLEGAL_REG (32)
 
+#define AT  mips_opts.at
+
 /* Allow override of standard little-endian ECOFF format.  */
 
 #ifndef ECOFF_LITTLE_FORMAT
@@ -193,6 +195,7 @@ struct mips_set_options
   int ase_mdmx;
   int ase_smartmips;
   int ase_dsp;
+  int ase_dspr2;
   int ase_mt;
   /* Whether we are assembling for the mips16 processor.  0 if we are
      not, 1 if we are, and -1 if the value has not been initialized.
@@ -202,9 +205,11 @@ struct mips_set_options
   /* Non-zero if we should not reorder instructions.  Changed by `.set
      reorder' and `.set noreorder'.  */
   int noreorder;
-  /* Non-zero if we should not permit the $at ($1) register to be used
-     in instructions.  Changed by `.set at' and `.set noat'.  */
-  int noat;
+  /* Non-zero if we should not permit the register designated "assembler
+     temporary" to be used in instructions.  The value is the register
+     number, normally $at ($1).  Changed by `.set at=REG', `.set noat'
+     (same as `.set at=$0') and `.set at' (same as `.set at=$1').  */
+  unsigned int at;
   /* Non-zero if we should warn when a macro instruction expands into
      more than one machine instruction.  Changed by `.set nomacro' and
      `.set macro'.  */
@@ -230,21 +235,41 @@ struct mips_set_options
   int arch;
   /* True if ".set sym32" is in effect.  */
   bfd_boolean sym32;
+  /* True if floating-point operations are not allowed.  Changed by .set
+     softfloat or .set hardfloat, by command line options -msoft-float or
+     -mhard-float.  The default is false.  */
+  bfd_boolean soft_float;
+
+  /* True if only single-precision floating-point operations are allowed.
+     Changed by .set singlefloat or .set doublefloat, command-line options
+     -msingle-float or -mdouble-float.  The default is false.  */
+  bfd_boolean single_float;
 };
 
+/* This is the struct we use to hold the current set of options.  Note
+   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
+   -1 to indicate that they have not been initialized.  */
+
 /* True if -mgp32 was passed.  */
 static int file_mips_gp32 = -1;
 
 /* True if -mfp32 was passed.  */
 static int file_mips_fp32 = -1;
 
-/* This is the struct we use to hold the current set of options.  Note
-   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
-   -1 to indicate that they have not been initialized.  */
+/* 1 if -msoft-float, 0 if -mhard-float.  The default is 0.  */
+static int file_mips_soft_float = 0;
+
+/* 1 if -msingle-float, 0 if -mdouble-float.  The default is 0.   */
+static int file_mips_single_float = 0;
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, -1, 0, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
+  /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
+  /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
+  /* mips16 */ -1, /* noreorder */ 0, /* at */ ATREG,
+  /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
+  /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
+  /* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -260,6 +285,23 @@ static int file_mips_isa = ISA_UNKNOWN;
    command line (e.g., by -march).  */
 static int file_ase_mips16;
 
+#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32              \
+                             || mips_opts.isa == ISA_MIPS32R2          \
+                             || mips_opts.isa == ISA_MIPS64            \
+                             || mips_opts.isa == ISA_MIPS64R2)
+
+/* True if we want to create R_MIPS_JALR for jalr $25.  */
+#ifdef TE_IRIX
+#define MIPS_JALR_HINT_P(EXPR) HAVE_NEWABI
+#else
+/* As a GNU extension, we use R_MIPS_JALR for o32 too.  However,
+   because there's no place for any addend, the only acceptable
+   expression is a bare symbol.  */
+#define MIPS_JALR_HINT_P(EXPR) \
+  (!HAVE_IN_PLACE_ADDENDS \
+   || ((EXPR)->X_op == O_symbol && (EXPR)->X_add_number == 0))
+#endif
+
 /* True if -mips3d was passed or implied by arguments passed on the
    command line (e.g., by -march).  */
 static int file_ase_mips3d;
@@ -284,6 +326,13 @@ static int file_ase_dsp;
 
 #define ISA_SUPPORTS_DSP64_ASE (mips_opts.isa == ISA_MIPS64R2)
 
+/* True if -mdspr2 was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_dspr2;
+
+#define ISA_SUPPORTS_DSPR2_ASE (mips_opts.isa == ISA_MIPS32R2          \
+                               || mips_opts.isa == ISA_MIPS64R2)
+
 /* True if -mmt was passed or implied by arguments passed on the
    command line (e.g., by -march).  */
 static int file_ase_mt;
@@ -407,6 +456,14 @@ static int mips_32bitmode = 0;
 /* True if CPU has a ror instruction.  */
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
+/* True if CPU has seq/sne and seqi/snei instructions.  */
+#define CPU_HAS_SEQ(CPU)       ((CPU) == CPU_OCTEON)
+
+/* True if CPU does not implement the all the coprocessor insns.  For these
+   CPUs only those COP insns are accepted that are explicitly marked to be
+   available on the CPU.  ISA membership for COP insns is ignored.  */
+#define NO_ISA_COP(CPU)                ((CPU) == CPU_OCTEON)
+
 /* True if mflo and mfhi can be immediately followed by instructions
    which write to the HI and LO registers.
 
@@ -427,6 +484,8 @@ static int mips_32bitmode = 0;
    || mips_opts.arch == CPU_R4010                     \
    || mips_opts.arch == CPU_R10000                    \
    || mips_opts.arch == CPU_R12000                    \
+   || mips_opts.arch == CPU_R14000                    \
+   || mips_opts.arch == CPU_R16000                    \
    || mips_opts.arch == CPU_RM7000                    \
    || mips_opts.arch == CPU_VR5500                    \
    )
@@ -464,7 +523,16 @@ static int mips_32bitmode = 0;
 
 /* Is this a mfhi or mflo instruction?  */
 #define MF_HILO_INSN(PINFO) \
-          ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+  ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+
+/* Returns true for a (non floating-point) coprocessor instruction.  Reading
+   or writing the condition code is only possible on the coprocessors and
+   these insns are not marked with INSN_COP.  Thus for these insns use the
+   condition-code flags.  */
+#define COP_INSN(PINFO)                                                        \
+  (PINFO != INSN_MACRO                                                 \
+   && ((PINFO) & (FP_S | FP_D)) == 0                                   \
+   && ((PINFO) & (INSN_COP | INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)))
 
 /* MIPS PIC level.  */
 
@@ -494,7 +562,7 @@ static int mips_any_noreorder;
    an mfhi/mflo instruction is read in the next two instructions.  */
 static int mips_7000_hilo_fix;
 
-/* The size of the small data section.  */
+/* The size of objects in the small data section.  */
 static unsigned int g_switch_value = 8;
 /* Whether the -G option was used.  */
 static int g_switch_seen = 0;
@@ -704,6 +772,9 @@ static int mips_fix_vr4120;
 /* ...likewise -mfix-vr4130.  */
 static int mips_fix_vr4130;
 
+/* ...likewise -mfix-24k.  */
+static int mips_fix_24k;
+
 /* We don't relax branches by default, since this causes us to expand
    `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
    fail to compute the offset before expanding the macro to the most
@@ -1011,6 +1082,8 @@ static void s_cpsetup (int);
 static void s_cplocal (int);
 static void s_cprestore (int);
 static void s_cpreturn (int);
+static void s_dtprelword (int);
+static void s_dtpreldword (int);
 static void s_gpvalue (int);
 static void s_gpword (int);
 static void s_gpdword (int);
@@ -1047,6 +1120,7 @@ struct mips_cpu_info
 #define MIPS_CPU_ASE_MT                0x0008  /* CPU implements MT ASE */
 #define MIPS_CPU_ASE_MIPS3D    0x0010  /* CPU implements MIPS-3D ASE */
 #define MIPS_CPU_ASE_MDMX      0x0020  /* CPU implements MDMX ASE */
+#define MIPS_CPU_ASE_DSPR2     0x0040  /* CPU implements DSP R2 ASE */
 
 static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
 static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
@@ -1067,8 +1141,7 @@ static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
    The following pseudo-ops from the Kane and Heinrich MIPS book are
    not MIPS CPU specific, but are also not specific to the object file
    format.  This file is probably the best place to define them, but
-   they are not currently supported: .asm0, .endr, .lab, .repeat,
-   .struct.  */
+   they are not currently supported: .asm0, .endr, .lab, .struct.  */
 
 static const pseudo_typeS mips_pseudo_table[] =
 {
@@ -1084,6 +1157,8 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cplocal", s_cplocal, 0},
   {"cprestore", s_cprestore, 0},
   {"cpreturn", s_cpreturn, 0},
+  {"dtprelword", s_dtprelword, 0},
+  {"dtpreldword", s_dtpreldword, 0},
   {"gpvalue", s_gpvalue, 0},
   {"gpword", s_gpword, 0},
   {"gpdword", s_gpdword, 0},
@@ -1092,7 +1167,7 @@ static const pseudo_typeS mips_pseudo_table[] =
 
   /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
-  {"asciiz", stringer, 1},
+  {"asciiz", stringer, 8 + 1},
   {"bss", s_change_sec, 'b'},
   {"err", s_err, 0},
   {"half", s_cons, 1},
@@ -1163,8 +1238,8 @@ struct insn_label_list
   symbolS *label;
 };
 
-static struct insn_label_list *insn_labels;
 static struct insn_label_list *free_insn_labels;
+#define label_list tc_segment_info_data.labels
 
 static void mips_clear_insn_labels (void);
 
@@ -1172,12 +1247,19 @@ static inline void
 mips_clear_insn_labels (void)
 {
   register struct insn_label_list **pl;
+  segment_info_type *si;
 
-  for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
-    ;
-  *pl = insn_labels;
-  insn_labels = NULL;
+  if (now_seg)
+    {
+      for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
+       ;
+      
+      si = seg_info (now_seg);
+      *pl = si->label_list;
+      si->label_list = NULL;
+    }
 }
+
 \f
 static char *expr_end;
 
@@ -1282,6 +1364,18 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
   insn->mips16_absolute_jump_p = 0;
 }
 
+/* Record the current MIPS16 mode in now_seg.  */
+
+static void
+mips_record_mips16_mode (void)
+{
+  segment_info_type *si;
+
+  si = seg_info (now_seg);
+  if (si->tc_segment_info_data.mips16 != mips_opts.mips16)
+    si->tc_segment_info_data.mips16 = mips_opts.mips16;
+}
+
 /* Install INSN at the location specified by its "frag" and "where" fields.  */
 
 static void
@@ -1304,6 +1398,7 @@ install_insn (const struct mips_cl_insn *insn)
        }
       md_number_to_chars (f, insn->insn_opcode, 2);
     }
+  mips_record_mips16_mode ();
 }
 
 /* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly
@@ -1701,7 +1796,7 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   if (reg >= 0)
     *s = e;
   else if (types & RWARN)
-    as_warn ("Unrecognized register name `%s'", *s);
+    as_warn (_("Unrecognized register name `%s'"), *s);
 
   *e = save_c;
   if (regnop)
@@ -1709,13 +1804,84 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   return reg >= 0;
 }
 
+/* Return TRUE if opcode MO is valid on the currently selected ISA and
+   architecture.  If EXPANSIONP is TRUE then this check is done while
+   expanding a macro.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
+
+static bfd_boolean
+is_opcode_valid (const struct mips_opcode *mo, bfd_boolean expansionp)
+{
+  int isa = mips_opts.isa;
+  int fp_s, fp_d;
+
+  if (mips_opts.ase_mdmx)
+    isa |= INSN_MDMX;
+  if (mips_opts.ase_dsp)
+    isa |= INSN_DSP;
+  if (mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
+    isa |= INSN_DSP64;
+  if (mips_opts.ase_dspr2)
+    isa |= INSN_DSPR2;
+  if (mips_opts.ase_mt)
+    isa |= INSN_MT;
+  if (mips_opts.ase_mips3d)
+    isa |= INSN_MIPS3D;
+  if (mips_opts.ase_smartmips)
+    isa |= INSN_SMARTMIPS;
+
+  /* For user code we don't check for mips_opts.mips16 since we want
+     to allow jalx if -mips16 was specified on the command line.  */
+  if (expansionp ? mips_opts.mips16 : file_ase_mips16)
+    isa |= INSN_MIPS16;
+
+  /* Don't accept instructions based on the ISA if the CPU does not implement
+     all the coprocessor insns. */
+  if (NO_ISA_COP (mips_opts.arch)
+      && COP_INSN (mo->pinfo))
+    isa = 0;
+
+  if (!OPCODE_IS_MEMBER (mo, isa, mips_opts.arch))
+    return FALSE;
+
+  /* Check whether the instruction or macro requires single-precision or
+     double-precision floating-point support.  Note that this information is
+     stored differently in the opcode table for insns and macros.  */
+  if (mo->pinfo == INSN_MACRO)
+    {
+      fp_s = mo->pinfo2 & INSN2_M_FP_S;
+      fp_d = mo->pinfo2 & INSN2_M_FP_D;
+    }
+  else
+    {
+      fp_s = mo->pinfo & FP_S;
+      fp_d = mo->pinfo & FP_D;
+    }
+
+  if (fp_d && (mips_opts.soft_float || mips_opts.single_float))
+    return FALSE;
+
+  if (fp_s && mips_opts.soft_float)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return TRUE if the MIPS16 opcode MO is valid on the currently
+   selected ISA and architecture.  */
+
+static bfd_boolean
+is_opcode_valid_16 (const struct mips_opcode *mo)
+{
+  return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
+}
+
 /* This function is called once, at assembler startup time.  It should set up
    all the tables, etc. that the MD part of the assembler will need.  */
 
 void
 md_begin (void)
 {
-  register const char *retval = NULL;
+  const char *retval = NULL;
   int i = 0;
   int broken = 0;
 
@@ -1799,17 +1965,17 @@ md_begin (void)
      helps us detect invalid uses of them.  */
   for (i = 0; reg_names[i].name; i++) 
     symbol_table_insert (symbol_new (reg_names[i].name, reg_section,
-                                    reg_names[i].num, // & RNUM_MASK,
+                                    reg_names[i].num, /* & RNUM_MASK, */
                                     &zero_address_frag));
   if (HAVE_NEWABI)
     for (i = 0; reg_names_n32n64[i].name; i++) 
       symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section,
-                                      reg_names_n32n64[i].num, // & RNUM_MASK,
+                                      reg_names_n32n64[i].num, /* & RNUM_MASK, */
                                       &zero_address_frag));
   else
     for (i = 0; reg_names_o32[i].name; i++) 
       symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section,
-                                      reg_names_o32[i].num, // & RNUM_MASK,
+                                      reg_names_o32[i].num, /* & RNUM_MASK, */
                                       &zero_address_frag));
 
   mips_no_prev_insn ();
@@ -1826,13 +1992,13 @@ md_begin (void)
   bfd_set_gp_size (stdoutput, g_switch_value);
 
 #ifdef OBJ_ELF
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+  if (IS_ELF)
     {
       /* On a native system other than VxWorks, sections must be aligned
         to 16 byte boundaries.  When configured for an embedded ELF
         target, we don't bother.  */
-      if (strcmp (TARGET_OS, "elf") != 0
-         && strcmp (TARGET_OS, "vxworks") != 0)
+      if (strncmp (TARGET_OS, "elf", 3) != 0
+         && strncmp (TARGET_OS, "vxworks", 7) != 0)
        {
          (void) bfd_set_section_alignment (stdoutput, text_section, 4);
          (void) bfd_set_section_alignment (stdoutput, data_section, 4);
@@ -1854,7 +2020,7 @@ md_begin (void)
           running program can access it.  However, we don't load it
           if we are configured for an embedded target */
        flags = SEC_READONLY | SEC_DATA;
-       if (strcmp (TARGET_OS, "elf") != 0)
+       if (strncmp (TARGET_OS, "elf", 3) != 0)
          flags |= SEC_ALLOC | SEC_LOAD;
 
        if (mips_abi != N64_ABI)
@@ -1899,7 +2065,7 @@ md_begin (void)
                                          SEC_HAS_CONTENTS | SEC_READONLY);
            (void) bfd_set_section_alignment (stdoutput, sec, 2);
          }
-       else if (OUTPUT_FLAVOR == bfd_target_elf_flavour && mips_flag_pdr)
+       else if (mips_flag_pdr)
          {
            pdr_seg = subseg_new (".pdr", (subsegT) 0);
            (void) bfd_set_section_flags (stdoutput, pdr_seg,
@@ -1979,6 +2145,46 @@ md_assemble (char *str)
     }
 }
 
+/* Convenience functions for abstracting away the differences between
+   MIPS16 and non-MIPS16 relocations.  */
+
+static inline bfd_boolean
+mips16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  switch (reloc)
+    {
+    case BFD_RELOC_MIPS16_JMP:
+    case BFD_RELOC_MIPS16_GPREL:
+    case BFD_RELOC_MIPS16_GOT16:
+    case BFD_RELOC_MIPS16_CALL16:
+    case BFD_RELOC_MIPS16_HI16_S:
+    case BFD_RELOC_MIPS16_HI16:
+    case BFD_RELOC_MIPS16_LO16:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
+static inline bfd_boolean
+got16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16;
+}
+
+static inline bfd_boolean
+hi16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S;
+}
+
+static inline bfd_boolean
+lo16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16;
+}
+
 /* Return true if the given relocation might need a matching %lo().
    This is only "might" because SVR4 R_MIPS_GOT16 relocations only
    need a matching %lo() when applied to local symbols.  */
@@ -1987,11 +2193,19 @@ static inline bfd_boolean
 reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
 {
   return (HAVE_IN_PLACE_ADDENDS
-         && (reloc == BFD_RELOC_HI16_S
-             || reloc == BFD_RELOC_MIPS16_HI16_S
+         && (hi16_reloc_p (reloc)
              /* VxWorks R_MIPS_GOT16 relocs never need a matching %lo();
                 all GOT16 relocations evaluate to "G".  */
-             || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC)));
+             || (got16_reloc_p (reloc) && mips_pic != VXWORKS_PIC)));
+}
+
+/* Return the type of %lo() reloc needed by RELOC, given that
+   reloc_needs_lo_p.  */
+
+static inline bfd_reloc_code_real_type
+matching_lo_reloc (bfd_reloc_code_real_type reloc)
+{
+  return mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16 : BFD_RELOC_LO16;
 }
 
 /* Return true if the given fixup is followed by a matching R_MIPS_LO16
@@ -2001,8 +2215,7 @@ static inline bfd_boolean
 fixup_has_matching_lo_p (fixS *fixp)
 {
   return (fixp->fx_next != NULL
-         && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
-            || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
+         && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
          && fixp->fx_addsy == fixp->fx_next->fx_addsy
          && fixp->fx_offset == fixp->fx_next->fx_offset);
 }
@@ -2012,22 +2225,22 @@ fixup_has_matching_lo_p (fixS *fixp)
 
 static int
 insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
-              enum mips_regclass class)
+              enum mips_regclass regclass)
 {
-  if (class == MIPS16_REG)
+  if (regclass == MIPS16_REG)
     {
-      assert (mips_opts.mips16);
+      gas_assert (mips_opts.mips16);
       reg = mips16_to_32_reg_map[reg];
-      class = MIPS_GR_REG;
+      regclass = MIPS_GR_REG;
     }
 
   /* Don't report on general register ZERO, since it never changes.  */
-  if (class == MIPS_GR_REG && reg == ZERO)
+  if (regclass == MIPS_GR_REG && reg == ZERO)
     return 0;
 
-  if (class == MIPS_FP_REG)
+  if (regclass == MIPS_FP_REG)
     {
-      assert (! mips_opts.mips16);
+      gas_assert (! mips_opts.mips16);
       /* If we are called with either $f0 or $f1, we must check $f0.
         This is not optimal, because it will introduce an unnecessary
         NOP between "lwc1 $f0" and "swc1 $f1".  To fix this we would
@@ -2110,12 +2323,13 @@ reg_needs_delay (unsigned int reg)
 static void
 mips_move_labels (void)
 {
+  segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l;
   valueT val;
 
-  for (l = insn_labels; l != NULL; l = l->next)
+  for (l = si->label_list; l != NULL; l = l->next)
     {
-      assert (S_GET_SEGMENT (l->label) == now_seg);
+      gas_assert (S_GET_SEGMENT (l->label) == now_seg);
       symbol_set_frag (l->label, frag_now);
       val = (valueT) frag_now_fix ();
       /* mips16 text labels are stored as odd.  */
@@ -2125,6 +2339,28 @@ mips_move_labels (void)
     }
 }
 
+static bfd_boolean
+s_is_linkonce (symbolS *sym, segT from_seg)
+{
+  bfd_boolean linkonce = FALSE;
+  segT symseg = S_GET_SEGMENT (sym);
+
+  if (symseg != from_seg && !S_IS_LOCAL (sym))
+    {
+      if ((bfd_get_section_flags (stdoutput, symseg) & SEC_LINK_ONCE))
+       linkonce = TRUE;
+#ifdef OBJ_ELF
+      /* The GNU toolchain uses an extension for ELF: a section
+        beginning with the magic string .gnu.linkonce is a
+        linkonce section.  */
+      if (strncmp (segment_name (symseg), ".gnu.linkonce",
+                  sizeof ".gnu.linkonce" - 1) == 0)
+       linkonce = TRUE;
+#endif
+    }
+  return linkonce;
+}
+
 /* Mark instruction labels in mips16 mode.  This permits the linker to
    handle them specially, such as generating jalx instructions when
    needed.  We also make them odd for the duration of the assembly, in
@@ -2136,21 +2372,29 @@ mips_move_labels (void)
 static void
 mips16_mark_labels (void)
 {
-  if (mips_opts.mips16)
-    {
-      struct insn_label_list *l;
-      valueT val;
+  segment_info_type *si = seg_info (now_seg);
+  struct insn_label_list *l;
 
-      for (l = insn_labels; l != NULL; l = l->next)
-       {
-#ifdef OBJ_ELF
-         if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
-           S_SET_OTHER (l->label, STO_MIPS16);
+  if (!mips_opts.mips16)
+    return;
+
+  for (l = si->label_list; l != NULL; l = l->next)
+   {
+      symbolS *label = l->label;
+
+#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
+      if (IS_ELF)
+       S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
 #endif
-         val = S_GET_VALUE (l->label);
-         if ((val & 1) == 0)
-           S_SET_VALUE (l->label, val + 1);
-       }
+      if ((S_GET_VALUE (label) & 1) == 0
+       /* Don't adjust the address if the label is global or weak, or
+          in a link-once section, since we'll be emitting symbol reloc
+          references to it which will be patched up by the linker, and
+          the final value of the symbol may or may not be MIPS16.  */
+         && ! S_IS_WEAK (label)
+         && ! S_IS_EXTERNAL (label)
+         && ! s_is_linkonce (label, now_seg))
+       S_SET_VALUE (label, S_GET_VALUE (label) | 1);
     }
 }
 
@@ -2175,7 +2419,7 @@ relax_close_frag (void)
 static void
 relax_start (symbolS *symbol)
 {
-  assert (mips_relax.sequence == 0);
+  gas_assert (mips_relax.sequence == 0);
   mips_relax.sequence = 1;
   mips_relax.symbol = symbol;
 }
@@ -2186,7 +2430,7 @@ relax_start (symbolS *symbol)
 static void
 relax_switch (void)
 {
-  assert (mips_relax.sequence == 1);
+  gas_assert (mips_relax.sequence == 1);
   mips_relax.sequence = 2;
 }
 
@@ -2195,7 +2439,7 @@ relax_switch (void)
 static void
 relax_end (void)
 {
-  assert (mips_relax.sequence == 2);
+  gas_assert (mips_relax.sequence == 2);
   relax_close_frag ();
   mips_relax.sequence = 0;
 }
@@ -2222,6 +2466,9 @@ classify_vr4120_insn (const char *name)
   return NUM_FIX_VR4120_CLASSES;
 }
 
+#define INSN_ERET  0x42000018
+#define INSN_DERET 0x4200001f
+
 /* Return the number of instructions that must separate INSN1 and INSN2,
    where INSN1 is the earlier instruction.  Return the worst-case value
    for any INSN2 if INSN2 is null.  */
@@ -2259,6 +2506,24 @@ insns_between (const struct mips_cl_insn *insn1,
       && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
     return 2;
 
+  /* If we're working around 24K errata, one instruction is required
+     if an ERET or DERET is followed by a branch instruction.  */
+  if (mips_fix_24k)
+    {
+      if (insn1->insn_opcode == INSN_ERET
+         || insn1->insn_opcode == INSN_DERET)
+       {
+         if (insn2 == NULL
+             || insn2->insn_opcode == INSN_ERET
+             || insn2->insn_opcode == INSN_DERET
+             || (insn2->insn_mo->pinfo
+                 & (INSN_UNCOND_BRANCH_DELAY
+                    | INSN_COND_BRANCH_DELAY
+                    | INSN_COND_BRANCH_LIKELY)) != 0)
+           return 1;
+       }
+    }
+
   /* If working around VR4120 errata, check for combinations that need
      a single intervening instruction.  */
   if (mips_fix_vr4120)
@@ -2347,10 +2612,10 @@ insns_between (const struct mips_cl_insn *insn1,
 
 /* Return the number of nops that would be needed to work around the
    VR4130 mflo/mfhi errata if instruction INSN immediately followed
-   the MAX_VR4130_NOPS instructions described by HISTORY.  */
+   the MAX_VR4130_NOPS instructions described by HIST.  */
 
 static int
-nops_for_vr4130 (const struct mips_cl_insn *history,
+nops_for_vr4130 (const struct mips_cl_insn *hist,
                 const struct mips_cl_insn *insn)
 {
   int i, j, reg;
@@ -2365,13 +2630,13 @@ nops_for_vr4130 (const struct mips_cl_insn *history,
 
   /* Search for the first MFLO or MFHI.  */
   for (i = 0; i < MAX_VR4130_NOPS; i++)
-    if (!history[i].noreorder_p && MF_HILO_INSN (history[i].insn_mo->pinfo))
+    if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
       {
        /* Extract the destination register.  */
        if (mips_opts.mips16)
-         reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, history[i])];
+         reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, hist[i])];
        else
-         reg = EXTRACT_OPERAND (RD, history[i]);
+         reg = EXTRACT_OPERAND (RD, hist[i]);
 
        /* No nops are needed if INSN reads that register.  */
        if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
@@ -2379,7 +2644,7 @@ nops_for_vr4130 (const struct mips_cl_insn *history,
 
        /* ...or if any of the intervening instructions do.  */
        for (j = 0; j < i; j++)
-         if (insn_uses_reg (&history[j], reg, MIPS_GR_REG))
+         if (insn_uses_reg (&hist[j], reg, MIPS_GR_REG))
            return 0;
 
        return MAX_VR4130_NOPS - i;
@@ -2388,28 +2653,27 @@ nops_for_vr4130 (const struct mips_cl_insn *history,
 }
 
 /* Return the number of nops that would be needed if instruction INSN
-   immediately followed the MAX_NOPS instructions given by HISTORY,
-   where HISTORY[0] is the most recent instruction.  If INSN is null,
+   immediately followed the MAX_NOPS instructions given by HIST,
+   where HIST[0] is the most recent instruction.  If INSN is null,
    return the worse-case number of nops for any instruction.  */
 
 static int
-nops_for_insn (const struct mips_cl_insn *history,
+nops_for_insn (const struct mips_cl_insn *hist,
               const struct mips_cl_insn *insn)
 {
   int i, nops, tmp_nops;
 
   nops = 0;
   for (i = 0; i < MAX_DELAY_NOPS; i++)
-    if (!history[i].noreorder_p)
-      {
-       tmp_nops = insns_between (history + i, insn) - i;
-       if (tmp_nops > nops)
-         nops = tmp_nops;
-      }
+    {
+      tmp_nops = insns_between (hist + i, insn) - i;
+      if (tmp_nops > nops)
+       nops = tmp_nops;
+    }
 
   if (mips_fix_vr4130)
     {
-      tmp_nops = nops_for_vr4130 (history, insn);
+      tmp_nops = nops_for_vr4130 (hist, insn);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
@@ -2418,20 +2682,20 @@ nops_for_insn (const struct mips_cl_insn *history,
 }
 
 /* The variable arguments provide NUM_INSNS extra instructions that
-   might be added to HISTORY.  Return the largest number of nops that
+   might be added to HIST.  Return the largest number of nops that
    would be needed after the extended sequence.  */
 
 static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
+nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
 {
   va_list args;
   struct mips_cl_insn buffer[MAX_NOPS];
   struct mips_cl_insn *cursor;
   int nops;
 
-  va_start (args, history);
+  va_start (args, hist);
   cursor = buffer + num_insns;
-  memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
+  memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
   while (cursor > buffer)
     *--cursor = *va_arg (args, const struct mips_cl_insn *);
 
@@ -2444,23 +2708,23 @@ nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
    worst-case delay for the branch target.  */
 
 static int
-nops_for_insn_or_target (const struct mips_cl_insn *history,
+nops_for_insn_or_target (const struct mips_cl_insn *hist,
                         const struct mips_cl_insn *insn)
 {
   int nops, tmp_nops;
 
-  nops = nops_for_insn (history, insn);
+  nops = nops_for_insn (hist, insn);
   if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
                              | INSN_COND_BRANCH_DELAY
                              | INSN_COND_BRANCH_LIKELY))
     {
-      tmp_nops = nops_for_sequence (2, history, insn, NOP_INSN);
+      tmp_nops = nops_for_sequence (2, hist, insn, NOP_INSN);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
   else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
     {
-      tmp_nops = nops_for_sequence (1, history, insn);
+      tmp_nops = nops_for_sequence (1, hist, insn);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
@@ -2475,9 +2739,10 @@ static void
 append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             bfd_reloc_code_real_type *reloc_type)
 {
-  register unsigned long prev_pinfo, pinfo;
+  unsigned long prev_pinfo, pinfo;
   relax_stateT prev_insn_frag_type = 0;
   bfd_boolean relaxed_branch = FALSE;
+  segment_info_type *si = seg_info (now_seg);
 
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
@@ -2535,7 +2800,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
     {
       /* Work out how many nops in prev_nop_frag are needed by IP.  */
       int nops = nops_for_insn_or_target (history, ip);
-      assert (nops <= prev_nop_frag_holds);
+      gas_assert (nops <= prev_nop_frag_holds);
 
       /* Enforce NOPS as a minimum.  */
       if (nops > prev_nop_frag_required)
@@ -2581,7 +2846,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
         .set noat if we use $at for PIC computations.  If it turns
         out that the branch was out-of-range, we'll get an error.  */
       && !mips_opts.warn_about_macros
-      && !(mips_opts.noat && mips_pic != NO_PIC)
+      && (mips_opts.at || mips_pic == NO_PIC)
       && !mips_opts.mips16)
     {
       relaxed_branch = TRUE;
@@ -2602,7 +2867,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   else if (*reloc_type > BFD_RELOC_UNUSED)
     {
       /* We need to set up a variant frag.  */
-      assert (mips_opts.mips16 && address_expr != NULL);
+      gas_assert (mips_opts.mips16 && address_expr != NULL);
       add_relaxed_insn (ip, 4, 0,
                        RELAX_MIPS16_ENCODE
                        (*reloc_type - BFD_RELOC_UNUSED,
@@ -2734,12 +2999,26 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              break;
 
          howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
+         if (howto == NULL)
+           {
+             /* To reproduce this failure try assembling gas/testsuites/
+                gas/mips/mips16-intermix.s with a mips-ecoff targeted
+                assembler.  */
+             as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]);
+             howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
+           }
+         
          ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
                                     bfd_get_reloc_size (howto),
                                     address_expr,
                                     reloc_type[0] == BFD_RELOC_16_PCREL_S2,
                                     reloc_type[0]);
 
+         /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
+         if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
+             && ip->fixp[0]->fx_addsy)
+           *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
+
          /* These relocations can have an addend that won't fit in
             4 octets for 64bit assembly.  */
          if (HAVE_64BIT_GPRS
@@ -2747,8 +3026,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              && (reloc_type[0] == BFD_RELOC_16
                  || reloc_type[0] == BFD_RELOC_32
                  || reloc_type[0] == BFD_RELOC_MIPS_JMP
-                 || reloc_type[0] == BFD_RELOC_HI16_S
-                 || reloc_type[0] == BFD_RELOC_LO16
                  || reloc_type[0] == BFD_RELOC_GPREL16
                  || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
                  || reloc_type[0] == BFD_RELOC_GPREL32
@@ -2761,8 +3038,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                  || reloc_type[0] == BFD_RELOC_MIPS_REL16
                  || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
                  || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
-                 || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
-                 || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
+                 || hi16_reloc_p (reloc_type[0])
+                 || lo16_reloc_p (reloc_type[0])))
            ip->fixp[0]->fx_no_overflow = 1;
 
          if (mips_relax.sequence)
@@ -2894,7 +3171,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                 whether there is a label on this instruction.  If
                 there are any branches to anything other than a
                 label, users must use .set noreorder.  */
-             || insn_labels != NULL
+             || si->label_list != NULL
              /* If the previous instruction is in a variant frag
                 other than this branch's one, we cannot do the swap.
                 This does not apply to the mips16, which uses variant
@@ -2996,15 +3273,16 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              || (mips_opts.mips16 && history[0].fixp[0])
              /* If the previous instruction is a sync, sync.l, or
                 sync.p, we can not swap.  */
-             || (prev_pinfo & INSN_SYNC))
+             || (prev_pinfo & INSN_SYNC)
+             /* If the previous instruction is an ERET or
+                DERET, avoid the swap.  */
+              || (history[0].insn_opcode == INSN_ERET)
+              || (history[0].insn_opcode == INSN_DERET))
            {
              if (mips_opts.mips16
                  && (pinfo & INSN_UNCOND_BRANCH_DELAY)
                  && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31))
-                 && (mips_opts.isa == ISA_MIPS32
-                     || mips_opts.isa == ISA_MIPS32R2
-                     || mips_opts.isa == ISA_MIPS64
-                     || mips_opts.isa == ISA_MIPS64R2))
+                 && ISA_SUPPORTS_MIPS16E)
                {
                  /* Convert MIPS16 jr/jalr into a "compact" jump.  */
                  ip->insn_opcode |= 0x0080;
@@ -3058,7 +3336,9 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
          /* If that was an unconditional branch, forget the previous
             insn information.  */
          if (pinfo & INSN_UNCOND_BRANCH_DELAY)
-           mips_no_prev_insn ();
+           {
+             mips_no_prev_insn ();
+           }
        }
       else if (pinfo & INSN_COND_BRANCH_LIKELY)
        {
@@ -3161,6 +3441,7 @@ start_noreorder (void)
 static void
 end_noreorder (void)
 {
+
   mips_opts.noreorder--;
   if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
     {
@@ -3228,7 +3509,7 @@ macro_end (void)
             warning now.  */
          const char *msg = macro_warning (subtype);
          if (msg != 0)
-           as_warn (msg);
+           as_warn ("%s", msg);
        }
       else
        {
@@ -3283,23 +3564,21 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
   r[1] = BFD_RELOC_UNUSED;
   r[2] = BFD_RELOC_UNUSED;
   mo = (struct mips_opcode *) hash_find (op_hash, name);
-  assert (mo);
-  assert (strcmp (name, mo->name) == 0);
-
-  /* Search until we get a match for NAME.  It is assumed here that
-     macros will never generate MDMX, MIPS-3D, DSP or MT instructions.  */
-  while (strcmp (fmt, mo->args) != 0
-        || mo->pinfo == INSN_MACRO
-        || !OPCODE_IS_MEMBER (mo,
-                              (mips_opts.isa
-                               | (mips_opts.mips16 ? INSN_MIPS16 : 0)
-                               | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
-                              mips_opts.arch)
-        || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0))
+  gas_assert (mo);
+  gas_assert (strcmp (name, mo->name) == 0);
+
+  while (1)
     {
+      /* Search until we get a match for NAME.  It is assumed here that
+        macros will never generate MDMX, MIPS-3D, or MT instructions.  */
+      if (strcmp (fmt, mo->args) == 0
+         && mo->pinfo != INSN_MACRO
+         && is_opcode_valid (mo, TRUE))
+       break;
+
       ++mo;
-      assert (mo->name);
-      assert (strcmp (name, mo->name) == 0);
+      gas_assert (mo->name);
+      gas_assert (strcmp (name, mo->name) == 0);
     }
 
   create_insn (&insn, mo);
@@ -3342,11 +3621,19 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
              continue;
 
+           case 'Q':
+             INSERT_OPERAND (SEQI, insn, va_arg (args, int));
+             continue;
+
            default:
              internalError ();
            }
          continue;
 
+       case '2':
+         INSERT_OPERAND (BP, insn, va_arg (args, int));
+         continue;
+
        case 't':
        case 'w':
        case 'E':
@@ -3416,7 +3703,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
        case 'j':
        case 'o':
          macro_read_relocs (&args, r);
-         assert (*r == BFD_RELOC_GPREL16
+         gas_assert (*r == BFD_RELOC_GPREL16
                  || *r == BFD_RELOC_MIPS_LITERAL
                  || *r == BFD_RELOC_MIPS_HIGHER
                  || *r == BFD_RELOC_HI16_S
@@ -3432,7 +3719,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case 'u':
          macro_read_relocs (&args, r);
-         assert (ep != NULL
+         gas_assert (ep != NULL
                  && (ep->X_op == O_constant
                      || (ep->X_op == O_symbol
                          && (*r == BFD_RELOC_MIPS_HIGHEST
@@ -3444,7 +3731,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
          continue;
 
        case 'p':
-         assert (ep != NULL);
+         gas_assert (ep != NULL);
 
          /*
           * This allows macro() to pass an immediate expression for
@@ -3469,7 +3756,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
          continue;
 
        case 'a':
-         assert (ep != NULL);
+         gas_assert (ep != NULL);
          *r = BFD_RELOC_MIPS_JMP;
          continue;
 
@@ -3487,7 +3774,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
       break;
     }
   va_end (args);
-  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
   append_insn (&insn, ep, r);
 }
@@ -3502,14 +3789,14 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
   mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
-  assert (mo);
-  assert (strcmp (name, mo->name) == 0);
+  gas_assert (mo);
+  gas_assert (strcmp (name, mo->name) == 0);
 
   while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
     {
       ++mo;
-      assert (mo->name);
-      assert (strcmp (name, mo->name) == 0);
+      gas_assert (mo->name);
+      gas_assert (strcmp (name, mo->name) == 0);
     }
 
   create_insn (&insn, mo);
@@ -3583,7 +3870,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
        case 'p':
        case 'q':
          {
-           assert (ep != NULL);
+           gas_assert (ep != NULL);
 
            if (ep->X_op != O_constant)
              *r = (int) BFD_RELOC_UNUSED + c;
@@ -3606,7 +3893,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
       break;
     }
 
-  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
   append_insn (&insn, ep, r);
 }
@@ -3647,13 +3934,13 @@ macro_build_jalr (expressionS *ep)
 {
   char *f = NULL;
 
-  if (HAVE_NEWABI)
+  if (MIPS_JALR_HINT_P (ep))
     {
       frag_grow (8);
       f = frag_more (0);
     }
   macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
-  if (HAVE_NEWABI)
+  if (MIPS_JALR_HINT_P (ep))
     fix_new_exp (frag_now, f - frag_now->fr_literal,
                 4, ep, FALSE, BFD_RELOC_MIPS_JALR);
 }
@@ -3672,23 +3959,23 @@ macro_build_lui (expressionS *ep, int regnum)
   const char *name = "lui";
   const char *fmt = "t,u";
 
-  assert (! mips_opts.mips16);
+  gas_assert (! mips_opts.mips16);
 
   high_expr = *ep;
 
   if (high_expr.X_op == O_constant)
     {
-      /* we can compute the instruction now without a relocation entry */
+      /* We can compute the instruction now without a relocation entry.  */
       high_expr.X_add_number = ((high_expr.X_add_number + 0x8000)
                                >> 16) & 0xffff;
       *r = BFD_RELOC_UNUSED;
     }
   else
     {
-      assert (ep->X_op == O_symbol);
+      gas_assert (ep->X_op == O_symbol);
       /* _gp_disp is a special case, used from s_cpload.
         __gnu_local_gp is used if mips_no_shared.  */
-      assert (mips_pic == NO_PIC
+      gas_assert (mips_pic == NO_PIC
              || (! HAVE_NEWABI
                  && strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
              || (! mips_in_shared
@@ -3698,8 +3985,8 @@ macro_build_lui (expressionS *ep, int regnum)
     }
 
   mo = hash_find (op_hash, name);
-  assert (strcmp (name, mo->name) == 0);
-  assert (strcmp (fmt, mo->args) == 0);
+  gas_assert (strcmp (name, mo->name) == 0);
+  gas_assert (strcmp (fmt, mo->args) == 0);
   create_insn (&insn, mo);
 
   insn.insn_opcode = insn.insn_mo->match;
@@ -3720,7 +4007,7 @@ static void
 macro_build_ldst_constoffset (expressionS *ep, const char *op,
                              int treg, int breg, int dbl)
 {
-  assert (ep->X_op == O_constant);
+  gas_assert (ep->X_op == O_constant);
 
   /* Sign-extending 32-bit constants makes their handling easier.  */
   if (!dbl)
@@ -3746,7 +4033,7 @@ macro_build_ldst_constoffset (expressionS *ep, const char *op,
       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
       macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
-      if (mips_opts.noat)
+      if (!mips_opts.at)
        as_bad (_("Macro used $at after \".set noat\""));
     }
 }
@@ -3873,7 +4160,7 @@ load_register (int reg, expressionS *ep, int dbl)
 
   if (ep->X_op != O_big)
     {
-      assert (ep->X_op == O_constant);
+      gas_assert (ep->X_op == O_constant);
 
       /* Sign-extending 32-bit constants makes their handling easier.  */
       if (!dbl)
@@ -3927,7 +4214,7 @@ load_register (int reg, expressionS *ep, int dbl)
     }
   else
     {
-      assert (ep->X_add_number > 2);
+      gas_assert (ep->X_add_number > 2);
       if (ep->X_add_number == 3)
        generic_bignum[3] = 0;
       else if (ep->X_add_number > 4)
@@ -4157,7 +4444,7 @@ load_address (int reg, expressionS *ep, int *used_at)
              relax_switch ();
            }
 
-         if (*used_at == 0 && !mips_opts.noat)
+         if (*used_at == 0 && mips_opts.at)
            {
              macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
              macro_build (ep, "lui", "t,u", AT, BFD_RELOC_HI16_S);
@@ -4346,7 +4633,7 @@ load_address (int reg, expressionS *ep, int *used_at)
   else
     abort ();
 
-  if (mips_opts.noat && *used_at == 1)
+  if (!mips_opts.at && *used_at == 1)
     as_bad (_("Macro used $at after \".set noat\""));
 }
 
@@ -4455,8 +4742,8 @@ add_got_offset_hilo (int dest, expressionS *local, int tmp)
 static void
 macro (struct mips_cl_insn *ip)
 {
-  register int treg, sreg, dreg, breg;
-  int tempreg;
+  unsigned int treg, sreg, dreg, breg;
+  unsigned int tempreg;
   int mask;
   int used_at = 0;
   expressionS expr1;
@@ -4474,7 +4761,7 @@ macro (struct mips_cl_insn *ip)
   bfd_reloc_code_real_type r;
   int hold_mips_optimize;
 
-  assert (! mips_opts.mips16);
+  gas_assert (! mips_opts.mips16);
 
   treg = (ip->insn_opcode >> 16) & 0x1f;
   dreg = (ip->insn_opcode >> 11) & 0x1f;
@@ -4575,6 +4862,22 @@ macro (struct mips_cl_insn *ip)
       macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
       break;
 
+    case M_BALIGN:
+      switch (imm_expr.X_add_number)
+       {
+       case 0:
+         macro_build (NULL, "nop", "");
+         break;
+       case 2:
+         macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
+         break;
+       default:
+         macro_build (NULL, "balign", "t,s,2", treg, sreg,
+                      (int)imm_expr.X_add_number);
+         break;
+       }
+      break;
+
     case M_BEQ_I:
       s = "beq";
       goto beq_i;
@@ -4989,8 +5292,8 @@ macro (struct mips_cl_insn *ip)
            s = "dinsm";
            fmt = "t,r,+A,+F";
          }
-       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos,
-                    pos + size - 1);
+       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
+                    (int) (pos + size - 1));
       }
       break;
 
@@ -5203,7 +5506,7 @@ macro (struct mips_cl_insn *ip)
          break;
        }
 
-      if (!mips_opts.noat && (treg == breg))
+      if (mips_opts.at && (treg == breg))
        {
          tempreg = AT;
          used_at = 1;
@@ -5262,7 +5565,7 @@ macro (struct mips_cl_insn *ip)
                  relax_switch ();
                }
 
-             if (used_at == 0 && !mips_opts.noat)
+             if (used_at == 0 && mips_opts.at)
                {
                  macro_build (&offset_expr, "lui", "t,u",
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
@@ -5451,8 +5754,6 @@ macro (struct mips_cl_insn *ip)
                }
              else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
                {
-                 int dreg;
-
                  /* If we are going to add in a base register, and the
                     target register and the base register are the same,
                     then we are using AT as a temporary register.  Since
@@ -5464,7 +5765,7 @@ macro (struct mips_cl_insn *ip)
                    dreg = tempreg;
                  else
                    {
-                     assert (tempreg == AT);
+                     gas_assert (tempreg == AT);
                      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                                   treg, AT, breg);
                      dreg = treg;
@@ -5592,8 +5893,6 @@ macro (struct mips_cl_insn *ip)
            }
          else
            {
-             int dreg;
-
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -5605,7 +5904,7 @@ macro (struct mips_cl_insn *ip)
                dreg = tempreg;
              else
                {
-                 assert (tempreg == AT);
+                 gas_assert (tempreg == AT);
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
@@ -5648,7 +5947,7 @@ macro (struct mips_cl_insn *ip)
                {
                  /* We must add in the base register now, as in the
                     external symbol case.  */
-                 assert (tempreg == AT);
+                 gas_assert (tempreg == AT);
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
@@ -5731,8 +6030,6 @@ macro (struct mips_cl_insn *ip)
            }
          else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
            {
-             int dreg;
-
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -5744,7 +6041,7 @@ macro (struct mips_cl_insn *ip)
                dreg = tempreg;
              else
                {
-                 assert (tempreg == AT);
+                 gas_assert (tempreg == AT);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  dreg = treg;
@@ -5781,6 +6078,43 @@ macro (struct mips_cl_insn *ip)
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
       break;
 
+    case M_MSGSND:
+      {
+       unsigned long temp = (treg << 16) | (0x01);
+       macro_build (NULL, "c2", "C", temp);
+      }
+      /* AT is not used, just return */
+      return;
+
+    case M_MSGLD:
+      {
+       unsigned long temp = (0x02);
+       macro_build (NULL, "c2", "C", temp);
+      }
+      /* AT is not used, just return */
+      return;
+
+    case M_MSGLD_T:
+      {
+       unsigned long temp = (treg << 16) | (0x02);
+       macro_build (NULL, "c2", "C", temp);
+      }
+      /* AT is not used, just return */
+      return;
+
+    case M_MSGWAIT:
+      macro_build (NULL, "c2", "C", 3);
+      /* AT is not used, just return */
+      return;
+
+    case M_MSGWAIT_T:
+      {
+       unsigned long temp = (treg << 16) | 0x03;
+       macro_build (NULL, "c2", "C", temp);
+      }
+      /* AT is not used, just return */
+      return;
+
     case M_J_A:
       /* The j instruction may not be used in PIC code, since it
         requires an absolute address.  We convert it to a b
@@ -6018,11 +6352,6 @@ macro (struct mips_cl_insn *ip)
       lr = 1;
       goto ld;
     case M_LDC1_AB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       s = "ldc1";
       /* Itbl support may require additional care here.  */
       coproc = 1;
@@ -6109,11 +6438,6 @@ macro (struct mips_cl_insn *ip)
       s = "cache";
       goto st;
     case M_SDC1_AB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       s = "sdc1";
       coproc = 1;
       /* Itbl support may require additional care here.  */
@@ -6137,6 +6461,15 @@ macro (struct mips_cl_insn *ip)
       tempreg = AT;
       used_at = 1;
     ld_st:
+      if (coproc
+         && NO_ISA_COP (mips_opts.arch)
+         && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
+       {
+         as_bad (_("opcode not supported on this processor: %s"),
+                 mips_cpu_info_from_arch (mips_opts.arch)->name);
+         break;
+       }
+
       /* Itbl support may require additional care here.  */
       if (mask == M_LWC1_AB
          || mask == M_SWC1_AB
@@ -6259,7 +6592,7 @@ macro (struct mips_cl_insn *ip)
                  relax_switch ();
                }
 
-             if (used_at == 0 && !mips_opts.noat)
+             if (used_at == 0 && mips_opts.at)
                {
                  macro_build (&offset_expr, "lui", "t,u", tempreg,
                               BFD_RELOC_MIPS_HIGHEST);
@@ -6358,7 +6691,7 @@ macro (struct mips_cl_insn *ip)
             16 bits, because we have no way to load the upper 16 bits
             (actually, we could handle them for the subset of cases
             in which we are not using $at).  */
-         assert (offset_expr.X_op == O_symbol);
+         gas_assert (offset_expr.X_op == O_symbol);
          if (HAVE_NEWABI)
            {
              macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
@@ -6408,7 +6741,7 @@ macro (struct mips_cl_insn *ip)
             16 bits, because we have no way to load the upper 16 bits
             (actually, we could handle them for the subset of cases
             in which we are not using $at).  */
-         assert (offset_expr.X_op == O_symbol);
+         gas_assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
@@ -6447,7 +6780,7 @@ macro (struct mips_cl_insn *ip)
             Otherwise, for local symbols, we want:
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
-         assert (offset_expr.X_op == O_symbol);
+         gas_assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
@@ -6500,7 +6833,7 @@ macro (struct mips_cl_insn *ip)
        }
       else
        {
-         assert (offset_expr.X_op == O_symbol
+         gas_assert (offset_expr.X_op == O_symbol
                  && strcmp (segment_name (S_GET_SEGMENT
                                           (offset_expr.X_add_symbol)),
                             ".lit4") == 0
@@ -6542,7 +6875,7 @@ macro (struct mips_cl_insn *ip)
                    move_register (lreg, 0);
                  else
                    {
-                     assert (offset_expr.X_op == O_constant);
+                     gas_assert (offset_expr.X_op == O_constant);
                      load_register (lreg, &offset_expr, 0);
                    }
                }
@@ -6597,7 +6930,7 @@ macro (struct mips_cl_insn *ip)
          load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
          if (HAVE_64BIT_FPRS)
            {
-             assert (HAVE_64BIT_GPRS);
+             gas_assert (HAVE_64BIT_GPRS);
              macro_build (NULL, "dmtc1", "t,S", AT, treg);
            }
          else
@@ -6607,7 +6940,7 @@ macro (struct mips_cl_insn *ip)
                macro_build (NULL, "mtc1", "t,G", 0, treg);
              else
                {
-                 assert (offset_expr.X_op == O_constant);
+                 gas_assert (offset_expr.X_op == O_constant);
                  load_register (AT, &offset_expr, 0);
                  macro_build (NULL, "mtc1", "t,G", AT, treg);
                }
@@ -6615,7 +6948,7 @@ macro (struct mips_cl_insn *ip)
          break;
        }
 
-      assert (offset_expr.X_op == O_symbol
+      gas_assert (offset_expr.X_op == O_symbol
              && offset_expr.X_add_number == 0);
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
@@ -6632,7 +6965,7 @@ macro (struct mips_cl_insn *ip)
        }
       else
        {
-         assert (strcmp (s, RDATA_SECTION_NAME) == 0);
+         gas_assert (strcmp (s, RDATA_SECTION_NAME) == 0);
          used_at = 1;
          if (mips_pic != NO_PIC)
            macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
@@ -6655,16 +6988,11 @@ macro (struct mips_cl_insn *ip)
        }
 
     case M_L_DOB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
     dob:
-      assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (mips_opts.isa == ISA_MIPS1);
       macro_build (&offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg, r, breg);
       /* FIXME: A possible overflow which I don't know how to deal
@@ -6686,11 +7014,6 @@ macro (struct mips_cl_insn *ip)
        * But, the resulting address is the same after relocation so why
        * generate the extra instruction?
        */
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       /* Itbl support may require additional care here.  */
       coproc = 1;
       if (mips_opts.isa != ISA_MIPS1)
@@ -6704,12 +7027,6 @@ macro (struct mips_cl_insn *ip)
       goto ldd_std;
 
     case M_S_DAB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
-
       if (mips_opts.isa != ISA_MIPS1)
        {
          s = "sdc1";
@@ -6986,7 +7303,7 @@ macro (struct mips_cl_insn *ip)
     case M_SD_OB:
       s = "sw";
     sd_ob:
-      assert (HAVE_32BIT_ADDRESSES);
+      gas_assert (HAVE_32BIT_ADDRESSES);
       macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
       offset_expr.X_add_number += 4;
       macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
@@ -7021,6 +7338,14 @@ macro (struct mips_cl_insn *ip)
     case M_COP3:
       s = "c3";
     copz:
+      if (NO_ISA_COP (mips_opts.arch)
+         && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
+       {
+         as_bad (_("opcode not supported on this processor: %s"),
+                 mips_cpu_info_from_arch (mips_opts.arch)->name);
+         break;
+       }
+
       /* For now we just do C (same as Cz).  The parameter will be
          stored in insn_opcode by mips_ip.  */
       macro_build (NULL, s, "C", ip->insn_opcode);
@@ -7052,15 +7377,15 @@ macro (struct mips_cl_insn *ip)
       macro2 (ip);
       break;
     }
-  if (mips_opts.noat && used_at)
+  if (!mips_opts.at && used_at)
     as_bad (_("Macro used $at after \".set noat\""));
 }
 
 static void
 macro2 (struct mips_cl_insn *ip)
 {
-  register int treg, sreg, dreg, breg;
-  int tempreg;
+  unsigned int treg, sreg, dreg, breg;
+  unsigned int tempreg;
   int mask;
   int used_at;
   expressionS expr1;
@@ -7219,7 +7544,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_DROL_I:
       {
        unsigned int rot;
-       char *l, *r;
+       char *l;
+       char *rr;
 
        if (imm_expr.X_op != O_constant)
          as_bad (_("Improper rotate count"));
@@ -7239,11 +7565,11 @@ macro2 (struct mips_cl_insn *ip)
            break;
          }
        l = (rot < 0x20) ? "dsll" : "dsll32";
-       r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
+       rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rot &= 0x1f;
        used_at = 1;
        macro_build (NULL, l, "d,w,<", AT, sreg, rot);
-       macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build (NULL, rr, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
       break;
@@ -7301,7 +7627,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_DROR_I:
       {
        unsigned int rot;
-       char *l, *r;
+       char *l;
+       char *rr;
 
        if (imm_expr.X_op != O_constant)
          as_bad (_("Improper rotate count"));
@@ -7319,11 +7646,11 @@ macro2 (struct mips_cl_insn *ip)
            macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
            break;
          }
-       r = (rot < 0x20) ? "dsrl" : "dsrl32";
+       rr = (rot < 0x20) ? "dsrl" : "dsrl32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        rot &= 0x1f;
        used_at = 1;
-       macro_build (NULL, r, "d,w,<", AT, sreg, rot);
+       macro_build (NULL, rr, "d,w,<", AT, sreg, rot);
        macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
@@ -7354,12 +7681,7 @@ macro2 (struct mips_cl_insn *ip)
       break;
 
     case M_S_DOB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
-      assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (mips_opts.isa == ISA_MIPS1);
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when storing to memory.  */
       macro_build (&offset_expr, "swc1", "T,o(b)",
@@ -7394,6 +7716,14 @@ macro2 (struct mips_cl_insn *ip)
          move_register (dreg, 0);
          break;
        }
+      if (CPU_HAS_SEQ (mips_opts.arch)
+         && -512 <= imm_expr.X_add_number
+         && imm_expr.X_add_number < 512)
+       {
+         macro_build (NULL, "seqi", "t,r,+Q", dreg, sreg,
+                      (int) imm_expr.X_add_number);
+         break;
+       }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
@@ -7408,6 +7738,13 @@ macro2 (struct mips_cl_insn *ip)
          macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
        }
+      else if (CPU_HAS_SEQ (mips_opts.arch))
+       {
+         used_at = 1;
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, "seq", "d,v,t", dreg, sreg, AT);
+         break;
+       }
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
@@ -7541,6 +7878,14 @@ macro2 (struct mips_cl_insn *ip)
                       dreg, 0, BFD_RELOC_LO16);
          break;
        }
+      if (CPU_HAS_SEQ (mips_opts.arch)
+         && -512 <= imm_expr.X_add_number
+         && imm_expr.X_add_number < 512)
+       {
+         macro_build (NULL, "snei", "t,r,+Q", dreg, sreg,
+                      (int) imm_expr.X_add_number);
+         break;
+       }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
@@ -7555,6 +7900,13 @@ macro2 (struct mips_cl_insn *ip)
          macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
        }
+      else if (CPU_HAS_SEQ (mips_opts.arch))
+       {
+         used_at = 1;
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, "sne", "d,v,t", dreg, sreg, AT);
+         break;
+       }
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
@@ -7623,7 +7975,7 @@ macro2 (struct mips_cl_insn *ip)
 
     case M_TRUNCWS:
     case M_TRUNCWD:
-      assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (mips_opts.isa == ISA_MIPS1);
       used_at = 1;
       sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
       dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
@@ -7843,7 +8195,7 @@ macro2 (struct mips_cl_insn *ip)
       as_bad (_("Macro %s not implemented yet"), ip->insn_mo->name);
       break;
     }
-  if (mips_opts.noat && used_at)
+  if (!mips_opts.at && used_at)
     as_bad (_("Macro used $at after \".set noat\""));
 }
 
@@ -8121,6 +8473,14 @@ validate_mips_insn (const struct mips_opcode *opc)
          case 't': USE_BITS (OP_MASK_RT,       OP_SH_RT);      break;
          case 'T': USE_BITS (OP_MASK_RT,       OP_SH_RT);
                    USE_BITS (OP_MASK_SEL,      OP_SH_SEL);     break;
+         case 'x': USE_BITS (OP_MASK_BBITIND,  OP_SH_BBITIND); break;
+         case 'X': USE_BITS (OP_MASK_BBITIND,  OP_SH_BBITIND); break;
+         case 'p': USE_BITS (OP_MASK_CINSPOS,  OP_SH_CINSPOS); break;
+         case 'P': USE_BITS (OP_MASK_CINSPOS,  OP_SH_CINSPOS); break;
+         case 'Q': USE_BITS (OP_MASK_SEQI,     OP_SH_SEQI);    break;
+         case 's': USE_BITS (OP_MASK_CINSLM1,  OP_SH_CINSLM1); break;
+         case 'S': USE_BITS (OP_MASK_CINSLM1,  OP_SH_CINSLM1); break;
+
          default:
            as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
                    c, opc->name, opc->args);
@@ -8182,6 +8542,8 @@ validate_mips_insn (const struct mips_opcode *opc)
       case '%': USE_BITS (OP_MASK_VECALIGN,    OP_SH_VECALIGN); break;
       case '[': break;
       case ']': break;
+      case '1':        USE_BITS (OP_MASK_SHAMT,        OP_SH_SHAMT);   break;
+      case '2': USE_BITS (OP_MASK_BP,          OP_SH_BP);      break;
       case '3': USE_BITS (OP_MASK_SA3,         OP_SH_SA3);     break;
       case '4': USE_BITS (OP_MASK_SA4,         OP_SH_SA4);     break;
       case '5': USE_BITS (OP_MASK_IMM8,        OP_SH_IMM8);    break;
@@ -8329,7 +8691,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
       /* If we did not find a '.', then we can quit now.  */
       if (*s != '.')
        {
-         insn_error = "unrecognized opcode";
+         insn_error = _("unrecognized opcode");
          return;
        }
 
@@ -8337,7 +8699,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
       *s++ = '\0';
       if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
        {
-         insn_error = "unrecognized opcode";
+         insn_error = _("unrecognized opcode");
          return;
        }
     }
@@ -8347,32 +8709,9 @@ mips_ip (char *str, struct mips_cl_insn *ip)
     {
       bfd_boolean ok;
 
-      assert (strcmp (insn->name, str) == 0);
-
-      if (OPCODE_IS_MEMBER (insn,
-                           (mips_opts.isa
-                            /* We don't check for mips_opts.mips16 here since
-                               we want to allow jalx if -mips16 was specified
-                               on the command line.  */
-                            | (file_ase_mips16 ? INSN_MIPS16 : 0)
-                            | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
-                            | (mips_opts.ase_dsp ? INSN_DSP : 0)
-                            | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
-                               ? INSN_DSP64 : 0)
-                            | (mips_opts.ase_mt ? INSN_MT : 0)
-                            | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)
-                            | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
-                           mips_opts.arch))
-       ok = TRUE;
-      else
-       ok = FALSE;
-
-      if (insn->pinfo != INSN_MACRO)
-       {
-         if (mips_opts.arch == CPU_R4650 && (insn->pinfo & FP_D) != 0)
-           ok = FALSE;
-       }
+      gas_assert (strcmp (insn->name, str) == 0);
 
+      ok = is_opcode_valid (insn, FALSE);
       if (! ok)
        {
          if (insn + 1 < &mips_opcodes[NUMOPCODES]
@@ -8401,6 +8740,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
       create_insn (ip, insn);
       insn_error = NULL;
       argnum = 1;
+      lastregno = 0xffffffff;
       for (args = insn->args;; ++args)
        {
          int is_mdmx;
@@ -8414,6 +8754,20 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                return;
              break;
 
+           case '2': /* dsp 2-bit unsigned immediate in bit 11 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned long) imm_expr.X_add_number != 1
+                 && (unsigned long) imm_expr.X_add_number != 3)
+               {
+                 as_bad (_("BALIGN immediate not 1 or 3 (%lu)"),
+                         (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (BP, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
            case '3': /* dsp 3-bit unsigned immediate in bit 21 */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
@@ -8651,7 +9005,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                 we must have a left paren.  */
              /* This is dependent on the next operand specifier
                 is a base register specification.  */
-             assert (args[1] == 'b' || args[1] == '5'
+             gas_assert (args[1] == 'b' || args[1] == '5'
                      || args[1] == '-' || args[1] == '4');
              if (*s == '\0')
                return;
@@ -8828,6 +9182,116 @@ do_msbd:
                    as_bad (_("Invalid coprocessor 0 register number"));
                  break;
 
+               case 'x':
+                 /* bbit[01] and bbit[01]32 bit index.  Give error if index
+                    is not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number > 31)
+                   {
+                     as_bad (_("Improper bit index (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'X':
+                 /* bbit[01] bit index when bbit is used but we generate
+                    bbit[01]32 because the index is over 32.  Move to the
+                    next candidate if index is not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number < 32
+                     || (unsigned) imm_expr.X_add_number > 63)
+                   break;
+                 INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number - 32);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'p':
+                 /* cins, cins32, exts and exts32 position field.  Give error
+                    if it's not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number > 31)
+                   {
+                     as_bad (_("Improper position (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 /* Make the pos explicit to simplify +S.  */
+                 lastpos = imm_expr.X_add_number + 32;
+                 INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'P':
+                 /* cins, cins32, exts and exts32 position field.  Move to
+                    the next candidate if it's not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number < 32
+                     || (unsigned) imm_expr.X_add_number > 63)
+                   break;
+                 lastpos = imm_expr.X_add_number;
+                 INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number - 32);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 's':
+                 /* cins and exts length-minus-one field.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned long) imm_expr.X_add_number > 31)
+                   {
+                     as_bad (_("Improper size (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'S':
+                 /* cins32/exts32 and cins/exts aliasing cint32/exts32
+                    length-minus-one field.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((long) imm_expr.X_add_number < 0
+                     || (unsigned long) imm_expr.X_add_number + lastpos > 63)
+                   {
+                     as_bad (_("Improper size (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'Q':
+                 /* seqi/snei immediate field.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((long) imm_expr.X_add_number < -512
+                     || (long) imm_expr.X_add_number >= 512)
+                   {
+                     as_bad (_("Improper immediate (%ld)"),
+                              (long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (SEQI, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
                default:
                  as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
                    *args, insn->name, insn->args);
@@ -8866,6 +9330,7 @@ do_msbd:
 
            case 'k':           /* cache code */
            case 'h':           /* prefx code */
+           case '1':           /* sync type */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
@@ -8874,8 +9339,10 @@ do_msbd:
                         (unsigned long) imm_expr.X_add_number);
              if (*args == 'k')
                INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
-             else
+             else if (*args == 'h')
                INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
+             else
+               INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
@@ -8988,8 +9455,14 @@ do_msbd:
              else
                {
                  ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
-                 if (regno == AT && ! mips_opts.noat)
-                   as_warn ("Used $at without \".set noat\"");
+                 if (regno == AT && mips_opts.at)
+                   {
+                     if (mips_opts.at == ATREG)
+                       as_warn (_("used $at without \".set noat\""));
+                     else
+                       as_warn (_("used $%u with \".set at=$%u\""),
+                                regno, mips_opts.at);
+                   }
                }
              if (ok)
                {
@@ -9009,6 +9482,19 @@ do_msbd:
                  if (c == 'z' && regno != 0)
                    break;
 
+                 if (c == 's' && !strncmp (ip->insn_mo->name, "jalr", 4))
+                   {
+                     if (regno == lastregno)
+                       {
+                         insn_error = _("source and destination must be different");
+                         continue;
+                       }
+                     if (regno == 31 && lastregno == 0xffffffff)
+                       {
+                         insn_error = _("a destination register must be supplied");
+                         continue;
+                       }
+                   }
        /* Now that we have assembled one operand, we use the args string
         * to figure out where it goes in the instruction.  */
                  switch (c)
@@ -9074,7 +9560,7 @@ do_msbd:
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
-               as_warn ("Improper align amount (%ld), using low bits",
+               as_warn (_("Improper align amount (%ld), using low bits"),
                         (long) imm_expr.X_add_number);
              INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
@@ -9165,15 +9651,15 @@ do_msbd:
                          check_absolute_expr (ip, &imm_expr);
                          s = expr_end;
                          if (imm_expr.X_add_number > max_el)
-                           as_bad(_("Bad element selector %ld"),
-                                  (long) imm_expr.X_add_number);
+                           as_bad (_("Bad element selector %ld"),
+                                   (long) imm_expr.X_add_number);
                          imm_expr.X_add_number &= max_el;
                          ip->insn_opcode |= (imm_expr.X_add_number
                                              << (OP_SH_VSEL +
                                                  (is_qh ? 2 : 1)));
                          imm_expr.X_op = O_absent;
                          if (*s != ']')
-                           as_warn(_("Expecting ']' found '%s'"), s);
+                           as_warn (_("Expecting ']' found '%s'"), s);
                          else
                            s++;
                        }
@@ -9284,7 +9770,7 @@ do_msbd:
                    length = f64 ? 8 : 4;
                  }
 
-               assert (length == (unsigned) (f64 ? 8 : 4));
+               gas_assert (length == (unsigned) (f64 ? 8 : 4));
 
                if (*args == 'f'
                    || (*args == 'l'
@@ -9382,20 +9868,19 @@ do_msbd:
                        newname = RDATA_SECTION_NAME;
                        break;
                      case 'l':
-                       assert (g_switch_value >= 4);
+                       gas_assert (g_switch_value >= 4);
                        newname = ".lit4";
                        break;
                      }
                    new_seg = subseg_new (newname, (subsegT) 0);
-                   if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+                   if (IS_ELF)
                      bfd_set_section_flags (stdoutput, new_seg,
                                             (SEC_ALLOC
                                              | SEC_LOAD
                                              | SEC_READONLY
                                              | SEC_DATA));
                    frag_align (*args == 'l' ? 2 : 3, 0, 0);
-                   if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-                       && strcmp (TARGET_OS, "elf") != 0)
+                   if (IS_ELF && strncmp (TARGET_OS, "elf", 3) != 0)
                      record_alignment (new_seg, 4);
                    else
                      record_alignment (new_seg, *args == 'l' ? 2 : 3);
@@ -9522,13 +10007,13 @@ do_msbd:
                   || strcmp(str + strlen(str) - 5, "any2f") == 0
                   || strcmp(str + strlen(str) - 5, "any2t") == 0)
                  && (regno & 1) != 0)
-               as_warn(_("Condition code register should be even for %s, was %d"),
-                       str, regno);
+               as_warn (_("Condition code register should be even for %s, was %d"),
+                        str, regno);
              if ((strcmp(str + strlen(str) - 5, "any4f") == 0
                   || strcmp(str + strlen(str) - 5, "any4t") == 0)
                  && (regno & 3) != 0)
-               as_warn(_("Condition code register should be 0 or 4 for %s, was %d"),
-                       str, regno);
+               as_warn (_("Condition code register should be 0 or 4 for %s, was %d"),
+                        str, regno);
              if (*args == 'N')
                INSERT_OPERAND (BCC, *ip, regno);
              else
@@ -9608,7 +10093,7 @@ do_msbd:
          continue;
        }
       if (save_c)
-       *(--s) = save_c;
+       *(--argsStart) = save_c;
       insn_error = _("illegal operands");
       return;
     }
@@ -9686,13 +10171,9 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
     {
       bfd_boolean ok;
 
-      assert (strcmp (insn->name, str) == 0);
-
-      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch))
-       ok = TRUE;
-      else
-       ok = FALSE;
+      gas_assert (strcmp (insn->name, str) == 0);
 
+      ok = is_opcode_valid_16 (insn);
       if (! ok)
        {
          if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
@@ -9746,6 +10227,8 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  /* Stuff the immediate value in now, if we can.  */
                  if (imm_expr.X_op == O_constant
                      && *imm_reloc > BFD_RELOC_UNUSED
+                     && *imm_reloc != BFD_RELOC_MIPS16_GOT16
+                     && *imm_reloc != BFD_RELOC_MIPS16_CALL16
                      && insn->pinfo != INSN_MACRO)
                    {
                      valueT tmp;
@@ -9883,8 +10366,14 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
 
                case 'X':
                case 'Y':
-                 if (regno == AT && ! mips_opts.noat)
-                   as_warn (_("used $at without \".set noat\""));
+                 if (regno == AT && mips_opts.at)
+                   {
+                     if (mips_opts.at == ATREG)
+                       as_warn (_("used $at without \".set noat\""));
+                     else
+                       as_warn (_("used $%u with \".set at=$%u\""),
+                                regno, mips_opts.at);
+                   }
                  break;
 
                default:
@@ -10108,7 +10597,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              {
                int opcode = 0;
                int framesz = 0, seen_framesz = 0;
-               int args = 0, statics = 0, sregs = 0;
+               int nargs = 0, statics = 0, sregs = 0;
 
                while (*s != '\0')
                  {
@@ -10161,9 +10650,9 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                      {
                        if (reg1 >= 4 && reg1 <= 7)
                          {
-                           if (c == 'm' && !seen_framesz)
+                           if (!seen_framesz)
                                /* args $a0-$a3 */
-                               args |= 1 << (reg1 - 4);
+                               nargs |= 1 << (reg1 - 4);
                            else
                                /* statics $a0-$a3 */
                                statics |= 1 << (reg1 - 4);
@@ -10189,9 +10678,9 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  }
 
                /* Encode args/statics combination.  */
-               if (args & statics)
+               if (nargs & statics)
                  as_bad (_("arg/static registers overlap"));
-               else if (args == 0xf)
+               else if (nargs == 0xf)
                  /* All $a0-$a3 are args.  */
                  opcode |= MIPS16_ALL_ARGS << 16;
                else if (statics == 0xf)
@@ -10202,12 +10691,12 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                    int narg = 0, nstat = 0;
 
                    /* Count arg registers.  */
-                   while (args & 0x1)
+                   while (nargs & 0x1)
                      {
-                       args >>= 1;
+                       nargs >>= 1;
                        narg++;
                      }
-                   if (args != 0)
+                   if (nargs != 0)
                      as_bad (_("invalid arg register list"));
 
                    /* Count static registers.  */
@@ -10373,7 +10862,7 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
              unsigned long *insn, bfd_boolean *use_extend,
              unsigned short *extend)
 {
-  register const struct mips16_immed_operand *op;
+  const struct mips16_immed_operand *op;
   int mintiny, maxtiny;
   bfd_boolean needext;
 
@@ -10381,7 +10870,7 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
   while (op->type != type)
     {
       ++op;
-      assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+      gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
     }
 
   if (op->unsp)
@@ -10509,6 +10998,8 @@ static const struct percent_op_match mips16_percent_op[] =
 {
   {"%lo", BFD_RELOC_MIPS16_LO16},
   {"%gprel", BFD_RELOC_MIPS16_GPREL},
+  {"%got", BFD_RELOC_MIPS16_GOT16},
+  {"%call16", BFD_RELOC_MIPS16_CALL16},
   {"%hi", BFD_RELOC_MIPS16_HI16_S}
 };
 
@@ -10549,7 +11040,7 @@ parse_relocation (char **str, bfd_reloc_code_real_type *reloc)
           If not, issue an error and fall back on something safe.  */
        if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc))
          {
-           as_bad ("relocation %s isn't supported by the current ABI",
+           as_bad (_("relocation %s isn't supported by the current ABI"),
                    percent_op[i].str);
            *reloc = BFD_RELOC_UNUSED;
          }
@@ -10605,7 +11096,7 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
       crux_depth--;
 
   if (crux_depth > 0)
-    as_bad ("unclosed '('");
+    as_bad (_("unclosed '('"));
 
   expr_end = str;
 
@@ -10645,58 +11136,10 @@ my_getExpression (expressionS *ep, char *str)
     S_SET_VALUE (ep->X_add_symbol, val + 1);
 }
 
-/* Turn a string in input_line_pointer into a floating point constant
-   of type TYPE, and store the appropriate bytes in *LITP.  The number
-   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
-   returned, or NULL on OK.  */
-
 char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizeP = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizeP = prec * 2;
-
-  if (! target_big_endian)
-    {
-      for (i = prec - 1; i >= 0; i--)
-       {
-         md_number_to_chars (litP, words[i], 2);
-         litP += 2;
-       }
-    }
-  else
-    {
-      for (i = 0; i < prec; i++)
-       {
-         md_number_to_chars (litP, words[i], 2);
-         litP += 2;
-       }
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litP, sizeP, target_big_endian);
 }
 
 void
@@ -10733,160 +11176,184 @@ static int support_64bit_objects(void)
 
 const char *md_shortopts = "O::g::G:";
 
+enum options
+  {
+    OPTION_MARCH = OPTION_MD_BASE,
+    OPTION_MTUNE,
+    OPTION_MIPS1,
+    OPTION_MIPS2,
+    OPTION_MIPS3,
+    OPTION_MIPS4,
+    OPTION_MIPS5,
+    OPTION_MIPS32,
+    OPTION_MIPS64,
+    OPTION_MIPS32R2,
+    OPTION_MIPS64R2,
+    OPTION_MIPS16,
+    OPTION_NO_MIPS16,
+    OPTION_MIPS3D,
+    OPTION_NO_MIPS3D,
+    OPTION_MDMX,
+    OPTION_NO_MDMX,
+    OPTION_DSP,
+    OPTION_NO_DSP,
+    OPTION_MT,
+    OPTION_NO_MT,
+    OPTION_SMARTMIPS,
+    OPTION_NO_SMARTMIPS,
+    OPTION_DSPR2,
+    OPTION_NO_DSPR2,
+    OPTION_COMPAT_ARCH_BASE,
+    OPTION_M4650,
+    OPTION_NO_M4650,
+    OPTION_M4010,
+    OPTION_NO_M4010,
+    OPTION_M4100,
+    OPTION_NO_M4100,
+    OPTION_M3900,
+    OPTION_NO_M3900,
+    OPTION_M7000_HILO_FIX,
+    OPTION_MNO_7000_HILO_FIX, 
+    OPTION_FIX_24K,
+    OPTION_NO_FIX_24K,
+    OPTION_FIX_VR4120,
+    OPTION_NO_FIX_VR4120,
+    OPTION_FIX_VR4130,
+    OPTION_NO_FIX_VR4130,
+    OPTION_TRAP,
+    OPTION_BREAK,
+    OPTION_EB,
+    OPTION_EL,
+    OPTION_FP32,
+    OPTION_GP32,
+    OPTION_CONSTRUCT_FLOATS,
+    OPTION_NO_CONSTRUCT_FLOATS,
+    OPTION_FP64,
+    OPTION_GP64,
+    OPTION_RELAX_BRANCH,
+    OPTION_NO_RELAX_BRANCH,
+    OPTION_MSHARED,
+    OPTION_MNO_SHARED,
+    OPTION_MSYM32,
+    OPTION_MNO_SYM32,
+    OPTION_SOFT_FLOAT,
+    OPTION_HARD_FLOAT,
+    OPTION_SINGLE_FLOAT,
+    OPTION_DOUBLE_FLOAT,
+    OPTION_32,
+#ifdef OBJ_ELF
+    OPTION_CALL_SHARED,
+    OPTION_CALL_NONPIC,
+    OPTION_NON_SHARED,
+    OPTION_XGOT,
+    OPTION_MABI,
+    OPTION_N32,
+    OPTION_64,
+    OPTION_MDEBUG,
+    OPTION_NO_MDEBUG,
+    OPTION_PDR,
+    OPTION_NO_PDR,
+    OPTION_MVXWORKS_PIC,
+#endif /* OBJ_ELF */
+    OPTION_END_OF_ENUM    
+  };
+  
 struct option md_longopts[] =
 {
   /* Options which specify architecture.  */
-#define OPTION_ARCH_BASE    (OPTION_MD_BASE)
-#define OPTION_MARCH (OPTION_ARCH_BASE + 0)
   {"march", required_argument, NULL, OPTION_MARCH},
-#define OPTION_MTUNE (OPTION_ARCH_BASE + 1)
   {"mtune", required_argument, NULL, OPTION_MTUNE},
-#define OPTION_MIPS1 (OPTION_ARCH_BASE + 2)
   {"mips0", no_argument, NULL, OPTION_MIPS1},
   {"mips1", no_argument, NULL, OPTION_MIPS1},
-#define OPTION_MIPS2 (OPTION_ARCH_BASE + 3)
   {"mips2", no_argument, NULL, OPTION_MIPS2},
-#define OPTION_MIPS3 (OPTION_ARCH_BASE + 4)
   {"mips3", no_argument, NULL, OPTION_MIPS3},
-#define OPTION_MIPS4 (OPTION_ARCH_BASE + 5)
   {"mips4", no_argument, NULL, OPTION_MIPS4},
-#define OPTION_MIPS5 (OPTION_ARCH_BASE + 6)
   {"mips5", no_argument, NULL, OPTION_MIPS5},
-#define OPTION_MIPS32 (OPTION_ARCH_BASE + 7)
   {"mips32", no_argument, NULL, OPTION_MIPS32},
-#define OPTION_MIPS64 (OPTION_ARCH_BASE + 8)
   {"mips64", no_argument, NULL, OPTION_MIPS64},
-#define OPTION_MIPS32R2 (OPTION_ARCH_BASE + 9)
   {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
-#define OPTION_MIPS64R2 (OPTION_ARCH_BASE + 10)
   {"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
 
   /* Options which specify Application Specific Extensions (ASEs).  */
-#define OPTION_ASE_BASE (OPTION_ARCH_BASE + 11)
-#define OPTION_MIPS16 (OPTION_ASE_BASE + 0)
   {"mips16", no_argument, NULL, OPTION_MIPS16},
-#define OPTION_NO_MIPS16 (OPTION_ASE_BASE + 1)
   {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-#define OPTION_MIPS3D (OPTION_ASE_BASE + 2)
   {"mips3d", no_argument, NULL, OPTION_MIPS3D},
-#define OPTION_NO_MIPS3D (OPTION_ASE_BASE + 3)
   {"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
-#define OPTION_MDMX (OPTION_ASE_BASE + 4)
   {"mdmx", no_argument, NULL, OPTION_MDMX},
-#define OPTION_NO_MDMX (OPTION_ASE_BASE + 5)
   {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
-#define OPTION_DSP (OPTION_ASE_BASE + 6)
   {"mdsp", no_argument, NULL, OPTION_DSP},
-#define OPTION_NO_DSP (OPTION_ASE_BASE + 7)
   {"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
-#define OPTION_MT (OPTION_ASE_BASE + 8)
   {"mmt", no_argument, NULL, OPTION_MT},
-#define OPTION_NO_MT (OPTION_ASE_BASE + 9)
   {"mno-mt", no_argument, NULL, OPTION_NO_MT},
-#define OPTION_SMARTMIPS (OPTION_ASE_BASE + 10)
   {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
-#define OPTION_NO_SMARTMIPS (OPTION_ASE_BASE + 11)
   {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
+  {"mdspr2", no_argument, NULL, OPTION_DSPR2},
+  {"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
 
   /* Old-style architecture options.  Don't add more of these.  */
-#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 12)
-#define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0)
   {"m4650", no_argument, NULL, OPTION_M4650},
-#define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1)
   {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
-#define OPTION_M4010 (OPTION_COMPAT_ARCH_BASE + 2)
   {"m4010", no_argument, NULL, OPTION_M4010},
-#define OPTION_NO_M4010 (OPTION_COMPAT_ARCH_BASE + 3)
   {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
-#define OPTION_M4100 (OPTION_COMPAT_ARCH_BASE + 4)
   {"m4100", no_argument, NULL, OPTION_M4100},
-#define OPTION_NO_M4100 (OPTION_COMPAT_ARCH_BASE + 5)
   {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
-#define OPTION_M3900 (OPTION_COMPAT_ARCH_BASE + 6)
   {"m3900", no_argument, NULL, OPTION_M3900},
-#define OPTION_NO_M3900 (OPTION_COMPAT_ARCH_BASE + 7)
   {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
 
   /* Options which enable bug fixes.  */
-#define OPTION_FIX_BASE    (OPTION_COMPAT_ARCH_BASE + 8)
-#define OPTION_M7000_HILO_FIX (OPTION_FIX_BASE + 0)
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
-#define OPTION_MNO_7000_HILO_FIX (OPTION_FIX_BASE + 1)
   {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
-#define OPTION_FIX_VR4120 (OPTION_FIX_BASE + 2)
-#define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
   {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
   {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
-#define OPTION_FIX_VR4130 (OPTION_FIX_BASE + 4)
-#define OPTION_NO_FIX_VR4130 (OPTION_FIX_BASE + 5)
   {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
   {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
+  {"mfix-24k",    no_argument, NULL, OPTION_FIX_24K},
+  {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
 
   /* Miscellaneous options.  */
-#define OPTION_MISC_BASE (OPTION_FIX_BASE + 6)
-#define OPTION_TRAP (OPTION_MISC_BASE + 0)
   {"trap", no_argument, NULL, OPTION_TRAP},
   {"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MISC_BASE + 1)
   {"break", no_argument, NULL, OPTION_BREAK},
   {"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MISC_BASE + 2)
   {"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MISC_BASE + 3)
   {"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_FP32 (OPTION_MISC_BASE + 4)
   {"mfp32", no_argument, NULL, OPTION_FP32},
-#define OPTION_GP32 (OPTION_MISC_BASE + 5)
   {"mgp32", no_argument, NULL, OPTION_GP32},
-#define OPTION_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 6)
   {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
-#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 7)
   {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
-#define OPTION_FP64 (OPTION_MISC_BASE + 8)
   {"mfp64", no_argument, NULL, OPTION_FP64},
-#define OPTION_GP64 (OPTION_MISC_BASE + 9)
   {"mgp64", no_argument, NULL, OPTION_GP64},
-#define OPTION_RELAX_BRANCH (OPTION_MISC_BASE + 10)
-#define OPTION_NO_RELAX_BRANCH (OPTION_MISC_BASE + 11)
   {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
   {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
-#define OPTION_MSHARED (OPTION_MISC_BASE + 12)
-#define OPTION_MNO_SHARED (OPTION_MISC_BASE + 13)
   {"mshared", no_argument, NULL, OPTION_MSHARED},
   {"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
-#define OPTION_MSYM32 (OPTION_MISC_BASE + 14)
-#define OPTION_MNO_SYM32 (OPTION_MISC_BASE + 15)
   {"msym32", no_argument, NULL, OPTION_MSYM32},
   {"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
-
+  {"msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT},
+  {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
+  {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
+  {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
+
+  /* Strictly speaking this next option is ELF specific,
+     but we allow it for other ports as well in order to
+     make testing easier.  */
+  {"32",          no_argument, NULL, OPTION_32},
+  
   /* ELF-specific options.  */
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MISC_BASE + 16)
-#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
-#define OPTION_NON_SHARED  (OPTION_ELF_BASE + 1)
+  {"call_nonpic", no_argument, NULL, OPTION_CALL_NONPIC},
   {"non_shared",  no_argument, NULL, OPTION_NON_SHARED},
-#define OPTION_XGOT        (OPTION_ELF_BASE + 2)
   {"xgot",        no_argument, NULL, OPTION_XGOT},
-#define OPTION_MABI        (OPTION_ELF_BASE + 3)
   {"mabi", required_argument, NULL, OPTION_MABI},
-#define OPTION_32         (OPTION_ELF_BASE + 4)
-  {"32",          no_argument, NULL, OPTION_32},
-#define OPTION_N32        (OPTION_ELF_BASE + 5)
   {"n32",         no_argument, NULL, OPTION_N32},
-#define OPTION_64          (OPTION_ELF_BASE + 6)
   {"64",          no_argument, NULL, OPTION_64},
-#define OPTION_MDEBUG      (OPTION_ELF_BASE + 7)
   {"mdebug", no_argument, NULL, OPTION_MDEBUG},
-#define OPTION_NO_MDEBUG   (OPTION_ELF_BASE + 8)
   {"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
-#define OPTION_PDR        (OPTION_ELF_BASE + 9)
   {"mpdr", no_argument, NULL, OPTION_PDR},
-#define OPTION_NO_PDR     (OPTION_ELF_BASE + 10)
   {"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
-#define OPTION_MVXWORKS_PIC (OPTION_ELF_BASE + 11)
   {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
 #endif /* OBJ_ELF */
 
@@ -10941,7 +11408,11 @@ md_parse_option (int c, char *arg)
       break;
 
     case 'O':
-      if (arg && arg[1] == '0')
+      if (arg == NULL)
+       mips_optimize = 1;
+      else if (arg[0] == '0')
+       mips_optimize = 0;
+      else if (arg[0] == '1')
        mips_optimize = 1;
       else
        mips_optimize = 2;
@@ -10952,11 +11423,6 @@ md_parse_option (int c, char *arg)
        mips_debug = 2;
       else
        mips_debug = atoi (arg);
-      /* When the MIPS assembler sees -g or -g2, it does not do
-         optimizations which limit full symbolic debugging.  We take
-         that to be equivalent to -O0.  */
-      if (mips_debug == 2)
-       mips_optimize = 1;
       break;
 
     case OPTION_MIPS1:
@@ -11045,9 +11511,21 @@ md_parse_option (int c, char *arg)
 
     case OPTION_DSP:
       mips_opts.ase_dsp = 1;
+      mips_opts.ase_dspr2 = 0;
       break;
 
     case OPTION_NO_DSP:
+      mips_opts.ase_dsp = 0;
+      mips_opts.ase_dspr2 = 0;
+      break;
+
+    case OPTION_DSPR2:
+      mips_opts.ase_dspr2 = 1;
+      mips_opts.ase_dsp = 1;
+      break;
+
+    case OPTION_NO_DSPR2:
+      mips_opts.ase_dspr2 = 0;
       mips_opts.ase_dsp = 0;
       break;
 
@@ -11085,6 +11563,14 @@ md_parse_option (int c, char *arg)
       mips_opts.ase_smartmips = 0;
       break;
 
+    case OPTION_FIX_24K:
+      mips_fix_24k = 1;
+      break;
+
+    case OPTION_NO_FIX_24K:
+      mips_fix_24k = 0;
+      break;
+
     case OPTION_FIX_VR4120:
       mips_fix_vr4120 = 1;
       break;
@@ -11130,7 +11616,7 @@ md_parse_option (int c, char *arg)
         select SVR4_PIC, and -non_shared to select no PIC.  This is
         intended to be compatible with Irix 5.  */
     case OPTION_CALL_SHARED:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-call_shared is supported only for ELF format"));
          return 0;
@@ -11139,8 +11625,18 @@ md_parse_option (int c, char *arg)
       mips_abicalls = TRUE;
       break;
 
+    case OPTION_CALL_NONPIC:
+      if (!IS_ELF)
+       {
+         as_bad (_("-call_nonpic is supported only for ELF format"));
+         return 0;
+       }
+      mips_pic = NO_PIC;
+      mips_abicalls = TRUE;
+      break;
+
     case OPTION_NON_SHARED:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-non_shared is supported only for ELF format"));
          return 0;
@@ -11162,20 +11658,18 @@ md_parse_option (int c, char *arg)
       g_switch_seen = 1;
       break;
 
-#ifdef OBJ_ELF
       /* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
         and -mabi=64.  */
     case OPTION_32:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
-       {
-         as_bad (_("-32 is supported for ELF format only"));
-         return 0;
-       }
-      mips_abi = O32_ABI;
+      if (IS_ELF)
+       mips_abi = O32_ABI;
+      /* We silently ignore -32 for non-ELF targets.  This greatly
+        simplifies the construction of the MIPS GAS test cases.  */
       break;
 
+#ifdef OBJ_ELF
     case OPTION_N32:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-n32 is supported for ELF format only"));
          return 0;
@@ -11184,13 +11678,13 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_64:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-64 is supported for ELF format only"));
          return 0;
        }
       mips_abi = N64_ABI;
-      if (! support_64bit_objects())
+      if (!support_64bit_objects())
        as_fatal (_("No compiled in support for 64 bit object file format"));
       break;
 #endif /* OBJ_ELF */
@@ -11211,9 +11705,25 @@ md_parse_option (int c, char *arg)
       file_mips_fp32 = 0;
       break;
 
+    case OPTION_SINGLE_FLOAT:
+      file_mips_single_float = 1;
+      break;
+
+    case OPTION_DOUBLE_FLOAT:
+      file_mips_single_float = 0;
+      break;
+
+    case OPTION_SOFT_FLOAT:
+      file_mips_soft_float = 1;
+      break;
+
+    case OPTION_HARD_FLOAT:
+      file_mips_soft_float = 0;
+      break;
+
 #ifdef OBJ_ELF
     case OPTION_MABI:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-mabi is supported for ELF format only"));
          return 0;
@@ -11351,7 +11861,7 @@ mips_after_parse_args (void)
     arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
 
   if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (arch_info->isa))
-    as_bad ("-march=%s is not compatible with the selected ABI",
+    as_bad (_("-march=%s is not compatible with the selected ABI"),
            arch_info->name);
 
   mips_set_architecture (arch_info);
@@ -11454,20 +11964,29 @@ mips_after_parse_args (void)
   if (mips_opts.ase_smartmips == -1)
     mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
   if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
-      as_warn ("%s ISA does not support SmartMIPS"
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support SmartMIPS")
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   if (mips_opts.ase_dsp == -1)
     mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
   if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
-      as_warn ("%s ISA does not support DSP ASE", 
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support DSP ASE"), 
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
+
+  if (mips_opts.ase_dspr2 == -1)
+    {
+      mips_opts.ase_dspr2 = (arch_info->flags & MIPS_CPU_ASE_DSPR2) ? 1 : 0;
+      mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
+    }
+  if (mips_opts.ase_dspr2 && !ISA_SUPPORTS_DSPR2_ASE)
+    as_warn (_("%s ISA does not support DSP R2 ASE"),
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   if (mips_opts.ase_mt == -1)
     mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
   if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
-      as_warn ("%s ISA does not support MT ASE", 
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support MT ASE"),
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   file_mips_isa = mips_opts.isa;
   file_ase_mips16 = mips_opts.mips16;
@@ -11475,9 +11994,12 @@ mips_after_parse_args (void)
   file_ase_mdmx = mips_opts.ase_mdmx;
   file_ase_smartmips = mips_opts.ase_smartmips;
   file_ase_dsp = mips_opts.ase_dsp;
+  file_ase_dspr2 = mips_opts.ase_dspr2;
   file_ase_mt = mips_opts.ase_mt;
   mips_opts.gp32 = file_mips_gp32;
   mips_opts.fp32 = file_mips_fp32;
+  mips_opts.soft_float = file_mips_soft_float;
+  mips_opts.single_float = file_mips_single_float;
 
   if (mips_flag_mdebug < 0)
     {
@@ -11509,6 +12031,10 @@ md_pcrel_from (fixS *fixP)
       /* Return the address of the delay slot.  */
       return addr + 4;
     default:
+      /* We have no relocation type for PC relative MIPS16 instructions.  */
+      if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("PC relative MIPS16 instruction references a different section"));
       return addr;
     }
 }
@@ -11583,6 +12109,7 @@ void
 mips_frob_file (void)
 {
   struct mips_hi_fixup *l;
+  bfd_reloc_code_real_type looking_for_rtype = BFD_RELOC_UNUSED;
 
   for (l = mips_hi_fixup_list; l != NULL; l = l->next)
     {
@@ -11590,11 +12117,11 @@ mips_frob_file (void)
       bfd_boolean matched_lo_p;
       fixS **hi_pos, **lo_pos, **pos;
 
-      assert (reloc_needs_lo_p (l->fixp->fx_r_type));
+      gas_assert (reloc_needs_lo_p (l->fixp->fx_r_type));
 
       /* If a GOT16 relocation turns out to be against a global symbol,
         there isn't supposed to be a matching LO.  */
-      if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
+      if (got16_reloc_p (l->fixp->fx_r_type)
          && !pic_need_relax (l->fixp->fx_addsy, l->seg))
        continue;
 
@@ -11612,13 +12139,14 @@ mips_frob_file (void)
       hi_pos = NULL;
       lo_pos = NULL;
       matched_lo_p = FALSE;
+      looking_for_rtype = matching_lo_reloc (l->fixp->fx_r_type);
+
       for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
        {
          if (*pos == l->fixp)
            hi_pos = pos;
 
-         if (((*pos)->fx_r_type == BFD_RELOC_LO16
-              || (*pos)->fx_r_type == BFD_RELOC_MIPS16_LO16)
+         if ((*pos)->fx_r_type == looking_for_rtype
              && (*pos)->fx_addsy == l->fixp->fx_addsy
              && (*pos)->fx_offset >= l->fixp->fx_offset
              && (lo_pos == NULL
@@ -11664,8 +12192,8 @@ mips_force_relocation (fixS *fixp)
   if (HAVE_NEWABI
       && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
       && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
-         || fixp->fx_r_type == BFD_RELOC_HI16_S
-         || fixp->fx_r_type == BFD_RELOC_LO16))
+         || hi16_reloc_p (fixp->fx_r_type)
+         || lo16_reloc_p (fixp->fx_r_type)))
     return 1;
 
   return 0;
@@ -11685,17 +12213,18 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   if (! howto)
     return;
 
-  assert (fixP->fx_size == 4
+  gas_assert (fixP->fx_size == 4
          || fixP->fx_r_type == BFD_RELOC_16
          || fixP->fx_r_type == BFD_RELOC_64
          || fixP->fx_r_type == BFD_RELOC_CTOR
          || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
          || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);
+         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+         || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
 
   buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
 
-  assert (! fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
+  gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
 
   /* Don't treat parts of a composite relocation as done.  There are two
      reasons for this:
@@ -11707,13 +12236,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
         constants.  The easiest way of dealing with the pathological
         exceptions is to generate a relocation against STN_UNDEF and
         leave everything up to the linker.  */
-  if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel && fixP->fx_tcbit == 0)
+  if (fixP->fx_addsy == NULL && !fixP->fx_pcrel && fixP->fx_tcbit == 0)
     fixP->fx_done = 1;
 
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_MIPS_TLS_GD:
     case BFD_RELOC_MIPS_TLS_LDM:
+    case BFD_RELOC_MIPS_TLS_DTPREL32:
+    case BFD_RELOC_MIPS_TLS_DTPREL64:
     case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
     case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
     case BFD_RELOC_MIPS_TLS_GOTTPREL:
@@ -11750,16 +12281,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
     case BFD_RELOC_MIPS16_GPREL:
+    case BFD_RELOC_MIPS16_GOT16:
+    case BFD_RELOC_MIPS16_CALL16:
     case BFD_RELOC_MIPS16_HI16:
     case BFD_RELOC_MIPS16_HI16_S:
-      /* Nothing needed to do. The value comes from the reloc entry */
-      break;
-
     case BFD_RELOC_MIPS16_JMP:
-      /* We currently always generate a reloc against a symbol, which
-         means that we don't want an addend even if the symbol is
-         defined.  */
-      *valP = 0;
+      /* Nothing needed to do.  The value comes from the reloc entry.  */
       break;
 
     case BFD_RELOC_64:
@@ -11787,18 +12314,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
-      /* If we are deleting this reloc entry, we must fill in the
-        value now.  This can happen if we have a .word which is not
-        resolved when it appears but is later defined.   */
-      if (fixP->fx_done)
-       md_number_to_chars ((char *) buf, *valP, 4);
-      break;
-
     case BFD_RELOC_16:
       /* If we are deleting this reloc entry, we must fill in the
-         value now.  */
+        value now.  This can happen if we have a .word which is not
+        resolved when it appears but is later defined.  */
       if (fixP->fx_done)
-       md_number_to_chars ((char *) buf, *valP, 2);
+       md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
       break;
 
     case BFD_RELOC_LO16:
@@ -11823,15 +12344,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("Branch to misaligned address (%lx)"), (long) *valP);
 
-      /*
-       * We need to save the bits in the instruction since fixup_segment()
-       * might be deleting the relocation entry (i.e., a branch within
-       * the current segment).
-       */
+      /* We need to save the bits in the instruction since fixup_segment()
+        might be deleting the relocation entry (i.e., a branch within
+        the current segment).  */
       if (! fixP->fx_done)
        break;
 
-      /* update old instruction data */
+      /* Update old instruction data.  */
       if (target_big_endian)
        insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
       else
@@ -11908,18 +12427,26 @@ get_symbol (void)
   return p;
 }
 
-/* Align the current frag to a given power of two.  The MIPS assembler
-   also automatically adjusts any preceding label.  */
+/* Align the current frag to a given power of two.  If a particular
+   fill byte should be used, FILL points to an integer that contains
+   that byte, otherwise FILL is null.
+
+   The MIPS assembler also automatically adjusts any preceding
+   label.  */
 
 static void
-mips_align (int to, int fill, symbolS *label)
+mips_align (int to, int *fill, symbolS *label)
 {
   mips_emit_delays ();
-  frag_align (to, fill, 0);
+  mips_record_mips16_mode ();
+  if (fill == NULL && subseg_text_p (now_seg))
+    frag_align_code (to, 0);
+  else
+    frag_align (to, fill ? *fill : 0, 0);
   record_alignment (now_seg, to);
   if (label != NULL)
     {
-      assert (S_GET_SEGMENT (label) == now_seg);
+      gas_assert (S_GET_SEGMENT (label) == now_seg);
       symbol_set_frag (label, frag_now);
       S_SET_VALUE (label, (valueT) frag_now_fix ());
     }
@@ -11931,21 +12458,16 @@ mips_align (int to, int fill, symbolS *label)
 static void
 s_align (int x ATTRIBUTE_UNUSED)
 {
-  register int temp;
-  register long temp_fill;
-  long max_alignment = 15;
+  int temp, fill_value, *fill_ptr;
+  long max_alignment = 28;
 
-  /*
-
-    o  Note that the assembler pulls down any immediately preceding label
+  /* o Note that the assembler pulls down any immediately preceding label
        to the aligned address.
-     It's not documented but auto alignment is reinstated by
+     o It's not documented but auto alignment is reinstated by
        a .align pseudo instruction.
-     Note also that after auto alignment is turned off the mips assembler
+     o Note also that after auto alignment is turned off the mips assembler
        issues an error on attempt to assemble an improperly aligned data item.
-       We don't.
-
-    */
+       We don't.  */
 
   temp = get_absolute_expression ();
   if (temp > max_alignment)
@@ -11958,15 +12480,18 @@ s_align (int x ATTRIBUTE_UNUSED)
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
-      temp_fill = get_absolute_expression ();
+      fill_value = get_absolute_expression ();
+      fill_ptr = &fill_value;
     }
   else
-    temp_fill = 0;
+    fill_ptr = 0;
   if (temp)
     {
+      segment_info_type *si = seg_info (now_seg);
+      struct insn_label_list *l = si->label_list;
+      /* Auto alignment should be switched on by next section change.  */
       auto_align = 1;
-      mips_align (temp, (int) temp_fill,
-                 insn_labels != NULL ? insn_labels->label : NULL);
+      mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
     }
   else
     {
@@ -11988,10 +12513,12 @@ s_change_sec (int sec)
      as it would not be appropriate to use it in the section changing
      functions in read.c, since obj-elf.c intercepts those.  FIXME:
      This should be cleaner, somehow.  */
-  obj_elf_section_change_hook ();
+  if (IS_ELF)
+    obj_elf_section_change_hook ();
 #endif
 
   mips_emit_delays ();
+
   switch (sec)
     {
     case 't':
@@ -12008,12 +12535,12 @@ s_change_sec (int sec)
     case 'r':
       seg = subseg_new (RDATA_SECTION_NAME,
                        (subsegT) get_absolute_expression ());
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+      if (IS_ELF)
        {
          bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
                                                  | SEC_READONLY | SEC_RELOC
                                                  | SEC_DATA));
-         if (strcmp (TARGET_OS, "elf") != 0)
+         if (strncmp (TARGET_OS, "elf", 3) != 0)
            record_alignment (seg, 4);
        }
       demand_empty_rest_of_line ();
@@ -12021,11 +12548,11 @@ s_change_sec (int sec)
 
     case 's':
       seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+      if (IS_ELF)
        {
          bfd_set_section_flags (stdoutput, seg,
                                 SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
-         if (strcmp (TARGET_OS, "elf") != 0)
+         if (strncmp (TARGET_OS, "elf", 3) != 0)
            record_alignment (seg, 4);
        }
       demand_empty_rest_of_line ();
@@ -12047,7 +12574,7 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
   int section_entry_size;
   int section_alignment;
 
-  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+  if (!IS_ELF)
     return;
 
   section_name = input_line_pointer;
@@ -12119,9 +12646,11 @@ mips_enable_auto_align (void)
 static void
 s_cons (int log_size)
 {
+  segment_info_type *si = seg_info (now_seg);
+  struct insn_label_list *l = si->label_list;
   symbolS *label;
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (log_size > 0 && auto_align)
     mips_align (log_size, 0, label);
@@ -12132,9 +12661,11 @@ s_cons (int log_size)
 static void
 s_float_cons (int type)
 {
+  segment_info_type *si = seg_info (now_seg);
+  struct insn_label_list *l = si->label_list;
   symbolS *label;
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  label = l != NULL ? l->label : NULL;
 
   mips_emit_delays ();
 
@@ -12287,13 +12818,20 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
       if (!mips_opts.noreorder)
        start_noreorder ();
     }
+  else if (strncmp (name, "at=", 3) == 0)
+    {
+      char *s = name + 3;
+
+      if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &mips_opts.at))
+       as_bad (_("Unrecognized register name `%s'"), s);
+    }
   else if (strcmp (name, "at") == 0)
     {
-      mips_opts.noat = 0;
+      mips_opts.at = ATREG;
     }
   else if (strcmp (name, "noat") == 0)
     {
-      mips_opts.noat = 1;
+      mips_opts.at = ZERO;
     }
   else if (strcmp (name, "macro") == 0)
     {
@@ -12328,7 +12866,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "gp=64") == 0)
     {
       if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
-       as_warn ("%s isa does not support 64-bit registers",
+       as_warn (_("%s isa does not support 64-bit registers"),
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.gp32 = 0;
     }
@@ -12339,10 +12877,18 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "fp=64") == 0)
     {
       if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       as_warn ("%s isa does not support 64-bit floating point registers",
+       as_warn (_("%s isa does not support 64-bit floating point registers"),
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.fp32 = 0;
     }
+  else if (strcmp (name, "softfloat") == 0)
+    mips_opts.soft_float = 1;
+  else if (strcmp (name, "hardfloat") == 0)
+    mips_opts.soft_float = 0;
+  else if (strcmp (name, "singlefloat") == 0)
+    mips_opts.single_float = 1;
+  else if (strcmp (name, "doublefloat") == 0)
+    mips_opts.single_float = 0;
   else if (strcmp (name, "mips16") == 0
           || strcmp (name, "MIPS-16") == 0)
     mips_opts.mips16 = 1;
@@ -12352,7 +12898,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "smartmips") == 0)
     {
       if (!ISA_SUPPORTS_SMARTMIPS)
-       as_warn ("%s ISA does not support SmartMIPS ASE"
+       as_warn (_("%s ISA does not support SmartMIPS ASE")
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_smartmips = 1;
     }
@@ -12369,16 +12915,33 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "dsp") == 0)
     {
       if (!ISA_SUPPORTS_DSP_ASE)
-       as_warn ("%s ISA does not support DSP ASE"
+       as_warn (_("%s ISA does not support DSP ASE")
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_dsp = 1;
+      mips_opts.ase_dspr2 = 0;
     }
   else if (strcmp (name, "nodsp") == 0)
-    mips_opts.ase_dsp = 0;
+    {
+      mips_opts.ase_dsp = 0;
+      mips_opts.ase_dspr2 = 0;
+    }
+  else if (strcmp (name, "dspr2") == 0)
+    {
+      if (!ISA_SUPPORTS_DSPR2_ASE)
+       as_warn (_("%s ISA does not support DSP R2 ASE"),
+                mips_cpu_info_from_isa (mips_opts.isa)->name);
+      mips_opts.ase_dspr2 = 1;
+      mips_opts.ase_dsp = 1;
+    }
+  else if (strcmp (name, "nodspr2") == 0)
+    {
+      mips_opts.ase_dspr2 = 0;
+      mips_opts.ase_dsp = 0;
+    }
   else if (strcmp (name, "mt") == 0)
     {
       if (!ISA_SUPPORTS_MT_ASE)
-       as_warn ("%s ISA does not support MT ASE"
+       as_warn (_("%s ISA does not support MT ASE")
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_mt = 1;
     }
@@ -12492,6 +13055,14 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.sym32 = TRUE;
   else if (strcmp (name, "nosym32") == 0)
     mips_opts.sym32 = FALSE;
+  else if (strchr (name, ','))
+    {
+      /* Generic ".set" directive; use the generic handler.  */
+      *input_line_pointer = ch;
+      input_line_pointer = name;
+      s_set (0);
+      return;
+    }
   else
     {
       as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
@@ -12599,8 +13170,7 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
 
    The -mno-shared option replaces the last three instructions with
        lui     $gp,%hi(_gp)
-       addiu   $gp,$gp,%lo(_gp)
-   */
+       addiu   $gp,$gp,%lo(_gp)  */
 
 static void
 s_cpsetup (int ignore ATTRIBUTE_UNUSED)
@@ -12702,7 +13272,7 @@ static void
 s_cplocal (int ignore ATTRIBUTE_UNUSED)
 {
   /* If we are not generating SVR4 PIC code, or if this is not NewABI code,
-   .cplocal is ignored.  */
+     .cplocal is ignored.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
     {
       s_ignore (0);
@@ -12751,8 +13321,8 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
      ld                $gp, offset($sp)
 
    If a register $reg2 was given there, it results in:
-     daddu     $gp, $reg2, $0
- */
+     daddu     $gp, $reg2, $0  */
+
 static void
 s_cpreturn (int ignore ATTRIBUTE_UNUSED)
 {
@@ -12784,6 +13354,52 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .dtprelword and .dtpreldword pseudo-ops.  They generate
+   a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
+   use in DWARF debug information.  */
+
+static void
+s_dtprel_internal (size_t bytes)
+{
+  expressionS ex;
+  char *p;
+
+  expression (&ex);
+
+  if (ex.X_op != O_symbol)
+    {
+      as_bad (_("Unsupported use of %s"), (bytes == 8
+                                          ? ".dtpreldword"
+                                          : ".dtprelword"));
+      ignore_rest_of_line ();
+    }
+
+  p = frag_more (bytes);
+  md_number_to_chars (p, 0, bytes);
+  fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
+              (bytes == 8
+               ? BFD_RELOC_MIPS_TLS_DTPREL64
+               : BFD_RELOC_MIPS_TLS_DTPREL32));
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle .dtprelword.  */
+
+static void
+s_dtprelword (int ignore ATTRIBUTE_UNUSED)
+{
+  s_dtprel_internal (4);
+}
+
+/* Handle .dtpreldword.  */
+
+static void
+s_dtpreldword (int ignore ATTRIBUTE_UNUSED)
+{
+  s_dtprel_internal (8);
+}
+
 /* Handle the .gpvalue pseudo-op.  This is used when generating NewABI PIC
    code.  It sets the offset to use in gp_rel relocations.  */
 
@@ -12809,6 +13425,8 @@ s_gpvalue (int ignore ATTRIBUTE_UNUSED)
 static void
 s_gpword (int ignore ATTRIBUTE_UNUSED)
 {
+  segment_info_type *si;
+  struct insn_label_list *l;
   symbolS *label;
   expressionS ex;
   char *p;
@@ -12820,7 +13438,9 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  si = seg_info (now_seg);
+  l = si->label_list;
+  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (auto_align)
     mips_align (2, 0, label);
@@ -12845,6 +13465,8 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
 static void
 s_gpdword (int ignore ATTRIBUTE_UNUSED)
 {
+  segment_info_type *si;
+  struct insn_label_list *l;
   symbolS *label;
   expressionS ex;
   char *p;
@@ -12856,7 +13478,9 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  si = seg_info (now_seg);
+  l = si->label_list;
+  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (auto_align)
     mips_align (3, 0, label);
@@ -12938,8 +13562,7 @@ s_mips_stab (int type)
   s_stab (type);
 }
 
-/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.
- */
+/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */
 
 static void
 s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
@@ -12961,7 +13584,7 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
     {
       if (S_IS_DEFINED (symbolP))
        {
-         as_bad ("ignoring attempt to redefine symbol %s",
+         as_bad (_("ignoring attempt to redefine symbol %s"),
                  S_GET_NAME (symbolP));
          ignore_rest_of_line ();
          return;
@@ -12976,7 +13599,7 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
       expression (&exp);
       if (exp.X_op != O_symbol)
        {
-         as_bad ("bad .weakext directive");
+         as_bad (_("bad .weakext directive"));
          ignore_rest_of_line ();
          return;
        }
@@ -13012,16 +13635,17 @@ md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
 
-#ifdef OBJ_ELF
-  /* We don't need to align ELF sections to the full alignment.
-     However, Irix 5 may prefer that we align them at least to a 16
-     byte boundary.  We don't bother to align the sections if we are
-     targeted for an embedded system.  */
-  if (strcmp (TARGET_OS, "elf") == 0)
-    return addr;
-  if (align > 4)
-    align = 4;
-#endif
+  if (IS_ELF)
+    {
+      /* We don't need to align ELF sections to the full alignment.
+        However, Irix 5 may prefer that we align them at least to a 16
+        byte boundary.  We don't bother to align the sections if we
+        are targeted for an embedded system.  */
+      if (strncmp (TARGET_OS, "elf", 3) == 0)
+        return addr;
+      if (align > 4)
+        align = 4;
+    }
 
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
@@ -13082,11 +13706,13 @@ nopic_need_relax (symbolS *sym, int before_relaxing)
          const char *segname;
 
          segname = segment_name (S_GET_SEGMENT (sym));
-         assert (strcmp (segname, ".lit8") != 0
+         gas_assert (strcmp (segname, ".lit8") != 0
                  && strcmp (segname, ".lit4") != 0);
          change = (strcmp (segname, ".sdata") != 0
                    && strcmp (segname, ".sbss") != 0
                    && strncmp (segname, ".sdata.", 7) != 0
+                   && strncmp (segname, ".sbss.", 6) != 0
+                   && strncmp (segname, ".gnu.linkonce.sb.", 17) != 0
                    && strncmp (segname, ".gnu.linkonce.s.", 16) != 0);
        }
       return change;
@@ -13103,48 +13729,32 @@ static bfd_boolean
 pic_need_relax (symbolS *sym, asection *segtype)
 {
   asection *symsec;
-  bfd_boolean linkonce;
 
   /* Handle the case of a symbol equated to another symbol.  */
   while (symbol_equated_reloc_p (sym))
     {
       symbolS *n;
 
-      /* It's possible to get a loop here in a badly written
-        program.  */
+      /* It's possible to get a loop here in a badly written program.  */
       n = symbol_get_value_expression (sym)->X_add_symbol;
       if (n == sym)
        break;
       sym = n;
     }
 
-  symsec = S_GET_SEGMENT (sym);
-
-  /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
-  linkonce = FALSE;
-  if (symsec != segtype && ! S_IS_LOCAL (sym))
-    {
-      if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
-         != 0)
-       linkonce = TRUE;
+  if (symbol_section_p (sym))
+    return TRUE;
 
-      /* The GNU toolchain uses an extension for ELF: a section
-        beginning with the magic string .gnu.linkonce is a linkonce
-        section.  */
-      if (strncmp (segment_name (symsec), ".gnu.linkonce",
-                  sizeof ".gnu.linkonce" - 1) == 0)
-       linkonce = TRUE;
-    }
+  symsec = S_GET_SEGMENT (sym);
 
   /* This must duplicate the test in adjust_reloc_syms.  */
   return (symsec != &bfd_und_section
          && symsec != &bfd_abs_section
-         && ! bfd_is_com_section (symsec)
-         && !linkonce
+         && !bfd_is_com_section (symsec)
+         && !s_is_linkonce (sym, segtype)
 #ifdef OBJ_ELF
          /* A global or weak symbol is treated as external.  */
-         && (OUTPUT_FLAVOR != bfd_target_elf_flavour
-             || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
+         && (!IS_ELF || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
 #endif
          );
 }
@@ -13157,7 +13767,7 @@ static int
 mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
 {
   int type;
-  register const struct mips16_immed_operand *op;
+  const struct mips16_immed_operand *op;
   offsetT val;
   int mintiny, maxtiny;
   segT symsec;
@@ -13173,7 +13783,7 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
   while (op->type != type)
     {
       ++op;
-      assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+      gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
     }
 
   if (op->unsp)
@@ -13460,11 +14070,6 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
 int
 mips_fix_adjustable (fixS *fixp)
 {
-  /* Don't adjust MIPS16 jump relocations, so we don't have to worry
-     about the format of the offset in the .o file. */
-  if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
-    return 0;
-
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
@@ -13486,19 +14091,61 @@ mips_fix_adjustable (fixS *fixp)
      placed anywhere.  Rather than break backwards compatibility by changing
      this, it seems better not to force the issue, and instead keep the
      original symbol.  This will work with either linker behavior.  */
-  if ((fixp->fx_r_type == BFD_RELOC_LO16
-       || fixp->fx_r_type == BFD_RELOC_MIPS16_LO16
+  if ((lo16_reloc_p (fixp->fx_r_type)
        || reloc_needs_lo_p (fixp->fx_r_type))
       && HAVE_IN_PLACE_ADDENDS
       && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
     return 0;
 
+  /* There is no place to store an in-place offset for JALR relocations.  */
+  if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+    return 0;
+
 #ifdef OBJ_ELF
-  /* Don't adjust relocations against mips16 symbols, so that the linker
-     can find them if it needs to set up a stub.  */
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
-      && fixp->fx_subsy == NULL)
+  /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
+     to a floating-point stub.  The same is true for non-R_MIPS16_26
+     relocations against MIPS16 functions; in this case, the stub becomes
+     the function's canonical address.
+
+     Floating-point stubs are stored in unique .mips16.call.* or
+     .mips16.fn.* sections.  If a stub T for function F is in section S,
+     the first relocation in section S must be against F; this is how the
+     linker determines the target function.  All relocations that might
+     resolve to T must also be against F.  We therefore have the following
+     restrictions, which are given in an intentionally-redundant way:
+
+       1. We cannot reduce R_MIPS16_26 relocations against non-MIPS16
+         symbols.
+
+       2. We cannot reduce a stub's relocations against non-MIPS16 symbols
+         if that stub might be used.
+
+       3. We cannot reduce non-R_MIPS16_26 relocations against MIPS16
+         symbols.
+
+       4. We cannot reduce a stub's relocations against MIPS16 symbols if
+         that stub might be used.
+
+     There is a further restriction:
+
+       5. We cannot reduce R_MIPS16_26 relocations against MIPS16 symbols
+         on targets with in-place addends; the relocation field cannot
+         encode the low bit.
+
+     For simplicity, we deal with (3)-(5) by not reducing _any_ relocation
+     against a MIPS16 symbol.
+
+     We deal with (1)-(2) by saying that, if there's a R_MIPS16_26
+     relocation against some symbol R, no relocation against R may be
+     reduced.  (Note that this deals with (2) as well as (1) because
+     relocations against global symbols will never be reduced on ELF
+     targets.)  This approach is a little simpler than trying to detect
+     stub sections, and gives the "all or nothing" per-symbol consistency
+     that we have for MIPS16 symbols.  */
+  if (IS_ELF
+      && fixp->fx_subsy == NULL
+      && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
+         || *symbol_get_tc (fixp->fx_addsy)))
     return 0;
 #endif
 
@@ -13523,12 +14170,12 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 
   if (fixp->fx_pcrel)
     {
-      assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
+      gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
 
       /* At this point, fx_addnumber is "symbol offset - pcrel address".
         Relocations want only the symbol offset.  */
       reloc->addend = fixp->fx_addnumber + reloc->address;
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          /* A gruesome hack which is a result of the gruesome gas
             reloc handling.  What's worse, for COFF (as opposed to
@@ -13627,7 +14274,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          exp.X_add_number = fragp->fr_offset;
 
          fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                             4, &exp, 1, BFD_RELOC_16_PCREL_S2);
+                             4, &exp, TRUE, BFD_RELOC_16_PCREL_S2);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -13653,20 +14300,20 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                  /* bc[0-3][tf]l? and bc1any[24][ft] instructions can
                     have the condition reversed by tweaking a single
                     bit, and their opcodes all have 0x4???????.  */
-                 assert ((insn & 0xf1000000) == 0x41000000);
+                 gas_assert ((insn & 0xf1000000) == 0x41000000);
                  insn ^= 0x00010000;
                  break;
 
                case 0:
                  /* bltz       0x04000000      bgez    0x04010000
-                    bltzal     0x04100000      bgezal  0x04110000 */
-                 assert ((insn & 0xfc0e0000) == 0x04000000);
+                    bltzal     0x04100000      bgezal  0x04110000  */
+                 gas_assert ((insn & 0xfc0e0000) == 0x04000000);
                  insn ^= 0x00010000;
                  break;
 
                case 1:
                  /* beq        0x10000000      bne     0x14000000
-                    blez       0x18000000      bgtz    0x1c000000 */
+                    blez       0x18000000      bgtz    0x1c000000  */
                  insn ^= 0x04000000;
                  break;
 
@@ -13678,10 +14325,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          if (RELAX_BRANCH_LINK (fragp->fr_subtype))
            {
              /* Clear the and-link bit.  */
-             assert ((insn & 0xfc1c0000) == 0x04100000);
+             gas_assert ((insn & 0xfc1c0000) == 0x04100000);
 
-             /* bltzal 0x04100000      bgezal  0x04110000
-               bltzall 0x04120000     bgezall  0x04130000 */
+             /* bltzal         0x04100000      bgezal  0x04110000
+                bltzall        0x04120000      bgezall 0x04130000  */
              insn &= ~0x00100000;
            }
 
@@ -13706,7 +14353,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          md_number_to_chars ((char *) buf, insn, 4);
          buf += 4;
 
-         /* Nop */
+         /* nop */
          md_number_to_chars ((char *) buf, 0, 4);
          buf += 4;
 
@@ -13744,7 +14391,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              exp.X_add_number = fragp->fr_offset;
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, 0, BFD_RELOC_MIPS_JMP);
+                                 4, &exp, FALSE, BFD_RELOC_MIPS_JMP);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -13766,7 +14413,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                }
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, 0, BFD_RELOC_MIPS_GOT16);
+                                 4, &exp, FALSE, BFD_RELOC_MIPS_GOT16);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -13784,7 +14431,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, 0, BFD_RELOC_LO16);
+                                 4, &exp, FALSE, BFD_RELOC_LO16);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -13802,7 +14449,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
            }
        }
 
-      assert (buf == (bfd_byte *)fragp->fr_literal
+      gas_assert (buf == (bfd_byte *)fragp->fr_literal
              + fragp->fr_fix + fragp->fr_var);
 
       fragp->fr_fix += fragp->fr_var;
@@ -13813,7 +14460,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
   if (RELAX_MIPS16_P (fragp->fr_subtype))
     {
       int type;
-      register const struct mips16_immed_operand *op;
+      const struct mips16_immed_operand *op;
       bfd_boolean small, ext;
       offsetT val;
       bfd_byte *buf;
@@ -13914,7 +14561,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
        {
          const char *msg = macro_warning (fragp->fr_subtype);
          if (msg != 0)
-           as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+           as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
        }
 
       /* Go through all the fixups for the first sequence.  Disable them
@@ -13967,14 +14614,14 @@ mips_frob_file_after_relocs (void)
   asymbol **syms;
   unsigned int count, i;
 
-  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+  if (!IS_ELF)
     return;
 
   syms = bfd_get_outsymbols (stdoutput);
   count = bfd_get_symcount (stdoutput);
   for (i = 0; i < count; i++, syms++)
     {
-      if (elf_symbol (*syms)->internal_elf_sym.st_other == STO_MIPS16
+      if (ELF_ST_IS_MIPS16 (elf_symbol (*syms)->internal_elf_sym.st_other)
          && ((*syms)->value & 1) != 0)
        {
          (*syms)->value &= ~1;
@@ -13995,6 +14642,7 @@ mips_frob_file_after_relocs (void)
 void
 mips_define_label (symbolS *sym)
 {
+  segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l;
 
   if (free_insn_labels == NULL)
@@ -14006,8 +14654,8 @@ mips_define_label (symbolS *sym)
     }
 
   l->label = sym;
-  l->next = insn_labels;
-  insn_labels = l;
+  l->next = si->label_list;
+  si->label_list = l;
 
 #ifdef OBJ_ELF
   dwarf2_emit_label (sym);
@@ -14069,6 +14717,7 @@ mips_elf_final_processing (void)
   /* Set MIPS ELF flags for ASEs.  */
   /* We may need to define a new flag for DSP ASE, and set this flag when
      file_ase_dsp is true.  */
+  /* Same for DSP R2.  */
   /* We may need to define a new flag for MT ASE, and set this flag when
      file_ase_mt is true.  */
   if (file_ase_mips16)
@@ -14125,36 +14774,40 @@ static procS cur_proc;
 static procS *cur_proc_ptr;
 static int numprocs;
 
-/* Fill in an rs_align_code fragment.  */
+/* Implement NOP_OPCODE.  We encode a MIPS16 nop as "1" and a normal
+   nop as "0".  */
+
+char
+mips_nop_opcode (void)
+{
+  return seg_info (now_seg)->tc_segment_info_data.mips16;
+}
+
+/* Fill in an rs_align_code fragment.  This only needs to do something
+   for MIPS16 code, where 0 is not a nop.  */
 
 void
 mips_handle_align (fragS *fragp)
 {
+  char *p;
+
   if (fragp->fr_type != rs_align_code)
     return;
 
-  if (mips_opts.mips16)
+  p = fragp->fr_literal + fragp->fr_fix;
+  if (*p)
     {
-      static const unsigned char be_nop[] = { 0x65, 0x00 };
-      static const unsigned char le_nop[] = { 0x00, 0x65 };
-
       int bytes;
-      char *p;
 
       bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
-      p = fragp->fr_literal + fragp->fr_fix;
-
       if (bytes & 1)
        {
          *p++ = 0;
          fragp->fr_fix++;
        }
-
-      memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
+      md_number_to_chars (p, mips16_nop_insn.insn_opcode, 2);
       fragp->fr_var = 2;
     }
-
-  /* For mips32, a nop is a zero, which we trivially get by doing nothing.  */
 }
 
 static void
@@ -14165,7 +14818,7 @@ md_obj_begin (void)
 static void
 md_obj_end (void)
 {
-  /* check for premature end, nesting errors, etc */
+  /* Check for premature end, nesting errors, etc.  */
   if (cur_proc_ptr)
     as_warn (_("missing .end at end of assembly"));
 }
@@ -14294,7 +14947,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
 
   if (p != NULL)
     {
-      assert (S_GET_NAME (p));
+      gas_assert (S_GET_NAME (p));
       if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
        as_warn (_(".end symbol does not match .ent symbol."));
 
@@ -14322,8 +14975,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
     }
 
   /* Generate a .pdr section.  */
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING
-      && mips_flag_pdr)
+  if (IS_ELF && !ECOFF_DEBUGGING && mips_flag_pdr)
     {
       segT saved_seg = now_seg;
       subsegT saved_subseg = now_subseg;
@@ -14337,7 +14989,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
       md_flush_pending_output ();
 #endif
 
-      assert (pdr_seg);
+      gas_assert (pdr_seg);
       subseg_set (pdr_seg, 0);
 
       /* Write the symbol.  */
@@ -14417,7 +15069,7 @@ static void
 s_mips_frame (int ignore ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_ELF
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+  if (IS_ELF && !ECOFF_DEBUGGING)
     {
       long val;
 
@@ -14460,7 +15112,7 @@ static void
 s_mips_mask (int reg_type)
 {
 #ifdef OBJ_ELF
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+  if (IS_ELF && !ECOFF_DEBUGGING)
     {
       long mask, off;
 
@@ -14538,11 +15190,16 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "r4600",          0,                       ISA_MIPS3,      CPU_R4600 },
   { "orion",          0,                       ISA_MIPS3,      CPU_R4600 },
   { "r4650",          0,                       ISA_MIPS3,      CPU_R4650 },
+  /* ST Microelectronics Loongson 2E and 2F cores */
+  { "loongson2e",     0,                       ISA_MIPS3,   CPU_LOONGSON_2E },
+  { "loongson2f",     0,                       ISA_MIPS3,   CPU_LOONGSON_2F },
 
   /* MIPS IV */
   { "r8000",          0,                       ISA_MIPS4,      CPU_R8000 },
   { "r10000",         0,                       ISA_MIPS4,      CPU_R10000 },
   { "r12000",         0,                       ISA_MIPS4,      CPU_R12000 },
+  { "r14000",         0,                       ISA_MIPS4,      CPU_R14000 },
+  { "r16000",         0,                       ISA_MIPS4,      CPU_R16000 },
   { "vr5000",         0,                       ISA_MIPS4,      CPU_R5000 },
   { "vr5400",         0,                       ISA_MIPS4,      CPU_VR5400 },
   { "vr5500",         0,                       ISA_MIPS4,      CPU_VR5500 },
@@ -14567,31 +15224,81 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "4ksd",           MIPS_CPU_ASE_SMARTMIPS,  ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "m4k",            0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "m4kp",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24k",            0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "24kc",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kf2_1",        0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "24kf",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kf1_1",        0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* Deprecated forms of the above.  */
+  { "24kfx",          0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "24kx",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  /* 24ke is a 24k with DSP ASE, other ASEs are optional.  */
-  { "24ke",           MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 24KE is a 24K with DSP ASE, other ASEs are optional.  */
   { "24kec",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kef2_1",       MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "24kef",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kef1_1",       MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* Deprecated forms of the above.  */
+  { "24kefx",         MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "24kex",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  /* 34k is a 24k with MT ASE, other ASEs are optional.  */
-  { "34kc",           MIPS_CPU_ASE_MT,         ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "34kf",           MIPS_CPU_ASE_MT,         ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "34kx",           MIPS_CPU_ASE_MT,         ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 34K is a 24K with DSP and MT ASE, other ASEs are optional.  */
+  { "34kc",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kf2_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kf",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kf1_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* Deprecated forms of the above.  */
+  { "34kfx",          MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 74K with DSP and DSPR2 ASE, other ASEs are optional.  */
+  { "74kc",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kf2_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kf",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kf1_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kf3_2",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* Deprecated forms of the above.  */
+  { "74kfx",          MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 1004K cores are multiprocessor versions of the 34K.  */
+  { "1004kc",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kf2_1",      MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kf",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kf1_1",      MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
 
   /* MIPS 64 */
   { "5kc",            0,                       ISA_MIPS64,     CPU_MIPS64 },
   { "5kf",            0,                       ISA_MIPS64,     CPU_MIPS64 },
   { "20kc",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
-
-  /* MIPS 64 Release 2 */
-  { "25kf",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64R2,   CPU_MIPS64R2 },
+  { "25kf",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
 
   /* Broadcom SB-1 CPU core */
   { "sb1",            MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
                                                ISA_MIPS64,     CPU_SB1 },
+  /* Broadcom SB-1A CPU core */
+  { "sb1a",           MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
+                                               ISA_MIPS64,     CPU_SB1 },
+
+  /* MIPS 64 Release 2 */
+
+  /* Cavium Networks Octeon CPU core */
+  { "octeon",        0,      ISA_MIPS64R2,   CPU_OCTEON },
+
+  /* RMI Xlr */
+  { "xlr",           0,      ISA_MIPS64,     CPU_XLR },
 
   /* End marker */
   { NULL, 0, 0, 0 }
@@ -14693,7 +15400,7 @@ mips_parse_cpu (const char *option, const char *cpu_string)
     if (mips_matching_cpu_name_p (p->name, cpu_string))
       return p;
 
-  as_bad ("Bad value (%s) for %s", cpu_string, option);
+  as_bad (_("Bad value (%s) for %s"), cpu_string, option);
   return 0;
 }
 
@@ -14806,28 +15513,39 @@ MIPS options:\n\
 -mdsp                  generate DSP instructions\n\
 -mno-dsp               do not generate DSP instructions\n"));
   fprintf (stream, _("\
+-mdspr2                        generate DSP R2 instructions\n\
+-mno-dspr2             do not generate DSP R2 instructions\n"));
+  fprintf (stream, _("\
 -mmt                   generate MT instructions\n\
 -mno-mt                        do not generate MT instructions\n"));
   fprintf (stream, _("\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
+-mfix-24k              insert a nop after ERET and DERET instructions\n\
 -mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
 -mfp32                 use 32-bit FPRs, regardless of the chosen ISA\n\
--mno-shared            optimize output for executables\n\
 -msym32                        assume all symbols have 32-bit values\n\
 -O0                    remove unneeded NOPs, do not swap branches\n\
 -O                     remove unneeded NOPs and swap branches\n\
---[no-]construct-floats [dis]allow floating point values to be constructed\n\
 --trap, --no-break     trap exception on div by 0 and mult overflow\n\
 --break, --no-trap     break exception on div by 0 and mult overflow\n"));
+  fprintf (stream, _("\
+-mhard-float           allow floating-point instructions\n\
+-msoft-float           do not allow floating-point instructions\n\
+-msingle-float         only allow 32-bit floating-point operations\n\
+-mdouble-float         allow 32-bit and 64-bit floating-point operations\n\
+--[no-]construct-floats [dis]allow floating point values to be constructed\n"
+                    ));
 #ifdef OBJ_ELF
   fprintf (stream, _("\
 -KPIC, -call_shared    generate SVR4 position independent code\n\
--non_shared            do not generate position independent code\n\
+-call_nonpic           generate non-PIC code that can operate with DSOs\n\
+-mvxworks-pic          generate VxWorks position independent code\n\
+-non_shared            do not generate code that can operate with DSOs\n\
 -xgot                  assume a 32 bit GOT\n\
 -mpdr, -mno-pdr                enable/disable creation of .pdr sections\n\
 -mshared, -mno-shared   disable/enable .cpload optimization for\n\
-                        non-shared code\n\
+                        position dependent (non shared) code\n\
 -mabi=ABI              create ABI conformant object file for:\n"));
 
   first = 1;
@@ -14848,9 +15566,9 @@ MIPS options:\n\
 }
 
 enum dwarf2_format
-mips_dwarf2_format (void)
+mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
 {
-  if (mips_abi == N64_ABI)
+  if (HAVE_64BIT_SYMBOLS)
     {
 #ifdef TE_IRIX
       return dwarf2_format_64bit_irix;
@@ -14865,7 +15583,7 @@ mips_dwarf2_format (void)
 int
 mips_dwarf2_addr_size (void)
 {
-  if (mips_abi == N64_ABI)
+  if (HAVE_64BIT_OBJECTS)
     return 8;
   else
     return 4;
This page took 0.087543 seconds and 4 git commands to generate.