gas/
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 42626ab630b91f5c3a03c7fda90af7bbff54c07d..345d6d0df4ca298f9c29a0315042590f5547c90a 100644 (file)
@@ -1,6 +1,7 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   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
@@ -89,7 +90,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 +102,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
@@ -153,6 +156,9 @@ struct mips_cl_insn
 
   /* True for mips16 instructions that jump to an absolute address.  */
   unsigned int mips16_absolute_jump_p : 1;
+
+  /* True if this instruction is complete.  */
+  unsigned int complete_p : 1;
 };
 
 /* The ABI to use.  */
@@ -203,9 +209,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'.  */
@@ -231,21 +239,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, -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.
@@ -257,8 +285,7 @@ unsigned long mips_cprmask[4];
 /* MIPS ISA we are using for this output file.  */
 static int file_mips_isa = ISA_UNKNOWN;
 
-/* True if -mips16 was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
+/* True if any MIPS16 code was produced.  */
 static int file_ase_mips16;
 
 #define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32              \
@@ -266,6 +293,18 @@ static int file_ase_mips16;
                              || 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;
@@ -420,6 +459,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.
 
@@ -440,6 +487,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                    \
    )
@@ -477,7 +526,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.  */
 
@@ -696,7 +754,8 @@ static const unsigned int mips16_to_32_reg_map[] =
 
 /* Classifies the kind of instructions we're interested in when
    implementing -mfix-vr4120.  */
-enum fix_vr4120_class {
+enum fix_vr4120_class
+{
   FIX_VR4120_MACC,
   FIX_VR4120_DMACC,
   FIX_VR4120_MULT,
@@ -706,6 +765,15 @@ enum fix_vr4120_class {
   NUM_FIX_VR4120_CLASSES
 };
 
+/* ...likewise -mfix-loongson2f-jump.  */
+static bfd_boolean mips_fix_loongson2f_jump;
+
+/* ...likewise -mfix-loongson2f-nop.  */
+static bfd_boolean mips_fix_loongson2f_nop;
+
+/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed.  */
+static bfd_boolean mips_fix_loongson2f;
+
 /* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
    there must be at least one other instruction between an instruction
    of type X and an instruction of type Y.  */
@@ -717,6 +785,12 @@ static int mips_fix_vr4120;
 /* ...likewise -mfix-vr4130.  */
 static int mips_fix_vr4130;
 
+/* ...likewise -mfix-24k.  */
+static int mips_fix_24k;
+
+/* ...likewise -mfix-cn63xxp1 */
+static bfd_boolean mips_fix_cn63xxp1;
+
 /* 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
@@ -847,18 +921,20 @@ static int mips_relax_branch;
 
 
    but it's not clear that it would actually improve performance.  */
-#define RELAX_BRANCH_ENCODE(uncond, likely, link, toofar) \
-  ((relax_substateT) \
-   (0xc0000000 \
-    | ((toofar) ? 1 : 0) \
-    | ((link) ? 2 : 0) \
-    | ((likely) ? 4 : 0) \
-    | ((uncond) ? 8 : 0)))
+#define RELAX_BRANCH_ENCODE(at, uncond, likely, link, toofar)  \
+  ((relax_substateT)                                           \
+   (0xc0000000                                                 \
+    | ((at) & 0x1f)                                            \
+    | ((toofar) ? 0x20 : 0)                                    \
+    | ((link) ? 0x40 : 0)                                      \
+    | ((likely) ? 0x80 : 0)                                    \
+    | ((uncond) ? 0x100 : 0)))
 #define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
-#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
-#define RELAX_BRANCH_LIKELY(i) (((i) & 4) != 0)
-#define RELAX_BRANCH_LINK(i) (((i) & 2) != 0)
-#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0)
+#define RELAX_BRANCH_UNCOND(i) (((i) & 0x100) != 0)
+#define RELAX_BRANCH_LIKELY(i) (((i) & 0x80) != 0)
+#define RELAX_BRANCH_LINK(i) (((i) & 0x40) != 0)
+#define RELAX_BRANCH_TOOFAR(i) (((i) & 0x20) != 0)
+#define RELAX_BRANCH_AT(i) ((i) & 0x1f)
 
 /* For mips16 code, we use an entirely different form of relaxation.
    mips16 supports two versions of most instructions which take
@@ -990,18 +1066,16 @@ static struct {
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static void append_insn
-  (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
+  (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
 static void mips_no_prev_insn (void);
+static void macro_build (expressionS *, const char *, const char *, ...);
 static void mips16_macro_build
-  (expressionS *, const char *, const char *, va_list);
+  (expressionS *, const char *, const char *, va_list *);
 static void load_register (int, expressionS *, int);
 static void macro_start (void);
 static void macro_end (void);
 static void macro (struct mips_cl_insn * ip);
 static void mips16_macro (struct mips_cl_insn * ip);
-#ifdef LOSING_COMPILER
-static void macro2 (struct mips_cl_insn * ip);
-#endif
 static void mips_ip (char *str, struct mips_cl_insn * ip);
 static void mips16_ip (char *str, struct mips_cl_insn * ip);
 static void mips16_immed
@@ -1109,7 +1183,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},
@@ -1118,6 +1192,9 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"origin", s_org, 0},
   {"repeat", s_rept, 0},
 
+  /* For MIPS this is non-standard, but we define it for consistency.  */
+  {"sbss", s_change_sec, 'B'},
+
   /* These pseudo-ops are defined in read.c, but must be overridden
      here for one reason or another.  */
   {"align", s_align, 0},
@@ -1162,6 +1239,15 @@ static const pseudo_typeS mips_nonecoff_pseudo_table[] =
   { NULL, NULL, 0 },
 };
 
+/* Export the ABI address size for use by TC_ADDRESS_BYTES for the
+   purpose of the `.dc.a' internal pseudo-op.  */
+
+int
+mips_address_bytes (void)
+{
+  return HAVE_64BIT_ADDRESSES ? 8 : 4;
+}
+
 extern void pop_insert (const pseudo_typeS *);
 
 void
@@ -1181,7 +1267,7 @@ struct insn_label_list
 };
 
 static struct insn_label_list *free_insn_labels;
-#define label_list tc_segment_info_data
+#define label_list tc_segment_info_data.labels
 
 static void mips_clear_insn_labels (void);
 
@@ -1232,6 +1318,14 @@ static segT pdr_seg;
 
 /* The default target format to use.  */
 
+#if defined (TE_FreeBSD)
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX "trad" ENDIAN "mips-freebsd"
+#elif defined (TE_TMIPS)
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX "trad" ENDIAN "mips"
+#else
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX ENDIAN "mips"
+#endif
+
 const char *
 mips_target_format (void)
 {
@@ -1248,28 +1342,17 @@ mips_target_format (void)
                ? "elf32-bigmips-vxworks"
                : "elf32-littlemips-vxworks");
 #endif
-#ifdef TE_TMIPS
-      /* This is traditional mips.  */
-      return (target_big_endian
-             ? (HAVE_64BIT_OBJECTS
-                ? "elf64-tradbigmips"
-                : (HAVE_NEWABI
-                   ? "elf32-ntradbigmips" : "elf32-tradbigmips"))
-             : (HAVE_64BIT_OBJECTS
-                ? "elf64-tradlittlemips"
-                : (HAVE_NEWABI
-                   ? "elf32-ntradlittlemips" : "elf32-tradlittlemips")));
-#else
       return (target_big_endian
              ? (HAVE_64BIT_OBJECTS
-                ? "elf64-bigmips"
+                ? ELF_TARGET ("elf64-", "big")
                 : (HAVE_NEWABI
-                   ? "elf32-nbigmips" : "elf32-bigmips"))
+                   ? ELF_TARGET ("elf32-n", "big")
+                   : ELF_TARGET ("elf32-", "big")))
              : (HAVE_64BIT_OBJECTS
-                ? "elf64-littlemips"
+                ? ELF_TARGET ("elf64-", "little")
                 : (HAVE_NEWABI
-                   ? "elf32-nlittlemips" : "elf32-littlemips")));
-#endif
+                   ? ELF_TARGET ("elf32-n", "little")
+                   : ELF_TARGET ("elf32-", "little"))));
     default:
       abort ();
       return NULL;
@@ -1304,6 +1387,19 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
   insn->fixed_p = (mips_opts.noreorder > 0);
   insn->noreorder_p = (mips_opts.noreorder > 0);
   insn->mips16_absolute_jump_p = 0;
+  insn->complete_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.  */
@@ -1328,6 +1424,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
@@ -1725,7 +1822,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)
@@ -1733,6 +1830,71 @@ 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.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
+
+static bfd_boolean
+is_opcode_valid (const struct mips_opcode *mo)
+{
+  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;
+
+  /* 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.  */
 
@@ -1776,6 +1938,8 @@ md_begin (void)
              if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
                {
                  create_insn (&nop_insn, mips_opcodes + i);
+                 if (mips_fix_loongson2f_nop)
+                   nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
                  nop_insn.fixed_p = 1;
                }
            }
@@ -1823,17 +1987,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 ();
@@ -1855,8 +2019,8 @@ md_begin (void)
       /* 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);
@@ -1878,7 +2042,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)
@@ -1947,6 +2111,7 @@ md_begin (void)
 void
 md_mips_end (void)
 {
+  mips_emit_delays ();
   if (! ECOFF_DEBUGGING)
     md_obj_end ();
 }
@@ -2003,6 +2168,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.  */
@@ -2011,11 +2216,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
@@ -2025,84 +2238,11 @@ 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);
 }
 
-/* See whether instruction IP reads register REG.  CLASS is the type
-   of register.  */
-
-static int
-insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
-              enum mips_regclass class)
-{
-  if (class == MIPS16_REG)
-    {
-      assert (mips_opts.mips16);
-      reg = mips16_to_32_reg_map[reg];
-      class = MIPS_GR_REG;
-    }
-
-  /* Don't report on general register ZERO, since it never changes.  */
-  if (class == MIPS_GR_REG && reg == ZERO)
-    return 0;
-
-  if (class == MIPS_FP_REG)
-    {
-      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
-        need to distinguish reading both $f0 and $f1 or just one of
-        them.  Note that we don't have to check the other way,
-        because there is no instruction that sets both $f0 and $f1
-        and requires a delay.  */
-      if ((ip->insn_mo->pinfo & INSN_READ_FPR_S)
-         && ((EXTRACT_OPERAND (FS, *ip) & ~(unsigned) 1)
-             == (reg &~ (unsigned) 1)))
-       return 1;
-      if ((ip->insn_mo->pinfo & INSN_READ_FPR_T)
-         && ((EXTRACT_OPERAND (FT, *ip) & ~(unsigned) 1)
-             == (reg &~ (unsigned) 1)))
-       return 1;
-    }
-  else if (! mips_opts.mips16)
-    {
-      if ((ip->insn_mo->pinfo & INSN_READ_GPR_S)
-         && EXTRACT_OPERAND (RS, *ip) == reg)
-       return 1;
-      if ((ip->insn_mo->pinfo & INSN_READ_GPR_T)
-         && EXTRACT_OPERAND (RT, *ip) == reg)
-       return 1;
-    }
-  else
-    {
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_X)
-         && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)] == reg)
-       return 1;
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Y)
-         && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)] == reg)
-       return 1;
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Z)
-         && (mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]
-             == reg))
-       return 1;
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_T) && reg == TREG)
-       return 1;
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_SP) && reg == SP)
-       return 1;
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_31) && reg == RA)
-       return 1;
-      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_GPR_X)
-         && MIPS16_EXTRACT_OPERAND (REGR32, *ip) == reg)
-       return 1;
-    }
-
-  return 0;
-}
-
 /* This function returns true if modifying a register requires a
    delay.  */
 
@@ -2140,7 +2280,7 @@ mips_move_labels (void)
 
   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.  */
@@ -2195,7 +2335,7 @@ mips16_mark_labels (void)
 
 #if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
       if (IS_ELF)
-       S_SET_OTHER (label, STO_MIPS16);
+       S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
 #endif
       if ((S_GET_VALUE (label) & 1) == 0
        /* Don't adjust the address if the label is global or weak, or
@@ -2230,7 +2370,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;
 }
@@ -2241,7 +2381,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;
 }
 
@@ -2250,11 +2390,154 @@ 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;
 }
 
+/* Return the mask of core registers that IP reads.  */
+
+static unsigned int
+gpr_read_mask (const struct mips_cl_insn *ip)
+{
+  unsigned long pinfo, pinfo2;
+  unsigned int mask;
+
+  mask = 0;
+  pinfo = ip->insn_mo->pinfo;
+  pinfo2 = ip->insn_mo->pinfo2;
+  if (mips_opts.mips16)
+    {
+      if (pinfo & MIPS16_INSN_READ_X)
+       mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
+      if (pinfo & MIPS16_INSN_READ_Y)
+       mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
+      if (pinfo & MIPS16_INSN_READ_T)
+       mask |= 1 << TREG;
+      if (pinfo & MIPS16_INSN_READ_SP)
+       mask |= 1 << SP;
+      if (pinfo & MIPS16_INSN_READ_31)
+       mask |= 1 << RA;
+      if (pinfo & MIPS16_INSN_READ_Z)
+       mask |= 1 << (mips16_to_32_reg_map
+                     [MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]);
+      if (pinfo & MIPS16_INSN_READ_GPR_X)
+       mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
+    }
+  else
+    {
+      if (pinfo2 & INSN2_READ_GPR_D)
+       mask |= 1 << EXTRACT_OPERAND (RD, *ip);
+      if (pinfo & INSN_READ_GPR_T)
+       mask |= 1 << EXTRACT_OPERAND (RT, *ip);
+      if (pinfo & INSN_READ_GPR_S)
+       mask |= 1 << EXTRACT_OPERAND (RS, *ip);
+      if (pinfo2 & INSN2_READ_GPR_Z)
+       mask |= 1 << EXTRACT_OPERAND (RZ, *ip);
+    }
+  return mask & ~0;
+}
+
+/* Return the mask of core registers that IP writes.  */
+
+static unsigned int
+gpr_write_mask (const struct mips_cl_insn *ip)
+{
+  unsigned long pinfo, pinfo2;
+  unsigned int mask;
+
+  mask = 0;
+  pinfo = ip->insn_mo->pinfo;
+  pinfo2 = ip->insn_mo->pinfo2;
+  if (mips_opts.mips16)
+    {
+      if (pinfo & MIPS16_INSN_WRITE_X)
+       mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
+      if (pinfo & MIPS16_INSN_WRITE_Y)
+       mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
+      if (pinfo & MIPS16_INSN_WRITE_Z)
+       mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RZ, *ip)];
+      if (pinfo & MIPS16_INSN_WRITE_T)
+       mask |= 1 << TREG;
+      if (pinfo & MIPS16_INSN_WRITE_SP)
+       mask |= 1 << SP;
+      if (pinfo & MIPS16_INSN_WRITE_31)
+       mask |= 1 << RA;
+      if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
+       mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
+    }
+  else
+    {
+      if (pinfo & INSN_WRITE_GPR_D)
+       mask |= 1 << EXTRACT_OPERAND (RD, *ip);
+      if (pinfo & INSN_WRITE_GPR_T)
+       mask |= 1 << EXTRACT_OPERAND (RT, *ip);
+      if (pinfo & INSN_WRITE_GPR_31)
+       mask |= 1 << RA;
+      if (pinfo2 & INSN2_WRITE_GPR_Z)
+       mask |= 1 << EXTRACT_OPERAND (RZ, *ip);
+    }
+  return mask & ~0;
+}
+
+/* Return the mask of floating-point registers that IP reads.  */
+
+static unsigned int
+fpr_read_mask (const struct mips_cl_insn *ip)
+{
+  unsigned long pinfo, pinfo2;
+  unsigned int mask;
+
+  mask = 0;
+  pinfo = ip->insn_mo->pinfo;
+  pinfo2 = ip->insn_mo->pinfo2;
+  if (!mips_opts.mips16)
+    {
+      if (pinfo & INSN_READ_FPR_S)
+       mask |= 1 << EXTRACT_OPERAND (FS, *ip);
+      if (pinfo & INSN_READ_FPR_T)
+       mask |= 1 << EXTRACT_OPERAND (FT, *ip);
+      if (pinfo & INSN_READ_FPR_R)
+       mask |= 1 << EXTRACT_OPERAND (FR, *ip);
+      if (pinfo2 & INSN2_READ_FPR_Z)
+       mask |= 1 << EXTRACT_OPERAND (FZ, *ip);
+    }
+  /* Conservatively treat all operands to an FP_D instruction are doubles.
+     (This is overly pessimistic for things like cvt.d.s.)  */
+  if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+    mask |= mask << 1;
+  return mask;
+}
+
+/* Return the mask of floating-point registers that IP writes.  */
+
+static unsigned int
+fpr_write_mask (const struct mips_cl_insn *ip)
+{
+  unsigned long pinfo, pinfo2;
+  unsigned int mask;
+
+  mask = 0;
+  pinfo = ip->insn_mo->pinfo;
+  pinfo2 = ip->insn_mo->pinfo2;
+  if (!mips_opts.mips16)
+    {
+      if (pinfo & INSN_WRITE_FPR_D)
+       mask |= 1 << EXTRACT_OPERAND (FD, *ip);
+      if (pinfo & INSN_WRITE_FPR_S)
+       mask |= 1 << EXTRACT_OPERAND (FS, *ip);
+      if (pinfo & INSN_WRITE_FPR_T)
+       mask |= 1 << EXTRACT_OPERAND (FT, *ip);
+      if (pinfo2 & INSN2_WRITE_FPR_Z)
+       mask |= 1 << EXTRACT_OPERAND (FZ, *ip);
+    }
+  /* Conservatively treat all operands to an FP_D instruction are doubles.
+     (This is overly pessimistic for things like cvt.s.d.)  */
+  if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+    mask |= mask << 1;
+  return mask;
+}
+
 /* Classify an instruction according to the FIX_VR4120_* enumeration.
    Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
    by VR4120 errata.  */
@@ -2277,6 +2560,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.  */
@@ -2286,16 +2572,17 @@ insns_between (const struct mips_cl_insn *insn1,
               const struct mips_cl_insn *insn2)
 {
   unsigned long pinfo1, pinfo2;
+  unsigned int mask;
 
   /* This function needs to know which pinfo flags are set for INSN2
      and which registers INSN2 uses.  The former is stored in PINFO2 and
-     the latter is tested via INSN2_USES_REG.  If INSN2 is null, PINFO2
-     will have every flag set and INSN2_USES_REG will always return true.  */
+     the latter is tested via INSN2_USES_GPR.  If INSN2 is null, PINFO2
+     will have every flag set and INSN2_USES_GPR will always return true.  */
   pinfo1 = insn1->insn_mo->pinfo;
   pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
 
-#define INSN2_USES_REG(REG, CLASS) \
-   (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
+#define INSN2_USES_GPR(REG) \
+  (insn2 == NULL || (gpr_read_mask (insn2) & (1U << (REG))) != 0)
 
   /* For most targets, write-after-read dependencies on the HI and LO
      registers must be separated by at least two instructions.  */
@@ -2311,9 +2598,27 @@ insns_between (const struct mips_cl_insn *insn1,
      between an mfhi or mflo and any instruction that uses the result.  */
   if (mips_7000_hilo_fix
       && MF_HILO_INSN (pinfo1)
-      && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
+      && INSN2_USES_GPR (EXTRACT_OPERAND (RD, *insn1)))
     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)
@@ -2340,7 +2645,7 @@ insns_between (const struct mips_cl_insn *insn1,
          || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
        {
          know (pinfo1 & INSN_WRITE_GPR_T);
-         if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
+         if (INSN2_USES_GPR (EXTRACT_OPERAND (RT, *insn1)))
            return 1;
        }
 
@@ -2358,14 +2663,10 @@ insns_between (const struct mips_cl_insn *insn1,
          /* Handle cases where INSN1 writes to a known general coprocessor
             register.  There must be a one instruction delay before INSN2
             if INSN2 reads that register, otherwise no delay is needed.  */
-         if (pinfo1 & INSN_WRITE_FPR_T)
-           {
-             if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
-               return 1;
-           }
-         else if (pinfo1 & INSN_WRITE_FPR_S)
+         mask = fpr_write_mask (insn1);
+         if (mask != 0)
            {
-             if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
+             if (!insn2 || (mask & fpr_read_mask (insn2)) != 0)
                return 1;
            }
          else
@@ -2395,20 +2696,22 @@ insns_between (const struct mips_cl_insn *insn1,
        return 1;
     }
 
-#undef INSN2_USES_REG
+#undef INSN2_USES_GPR
 
   return 0;
 }
 
 /* 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.  Ignore hazards
+   that are contained within the first IGNORE instructions of HIST.  */
 
 static int
-nops_for_vr4130 (const struct mips_cl_insn *history,
+nops_for_vr4130 (int ignore, const struct mips_cl_insn *hist,
                 const struct mips_cl_insn *insn)
 {
-  int i, j, reg;
+  int i, j;
+  unsigned int mask;
 
   /* Check if the instruction writes to HI or LO.  MTHI and MTLO
      are not affected by the errata.  */
@@ -2420,126 +2723,458 @@ 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])];
-       else
-         reg = EXTRACT_OPERAND (RD, history[i]);
+       mask = gpr_write_mask (&hist[i]);
 
        /* No nops are needed if INSN reads that register.  */
-       if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
+       if (insn != NULL && (gpr_read_mask (insn) & mask) != 0)
          return 0;
 
        /* ...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 (gpr_read_mask (&hist[j]) & mask)
            return 0;
 
-       return MAX_VR4130_NOPS - i;
+       if (i >= ignore)
+         return MAX_VR4130_NOPS - i;
       }
   return 0;
 }
 
-/* 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,
-   return the worse-case number of nops for any instruction.  */
+#define BASE_REG_EQ(INSN1, INSN2)      \
+  ((((INSN1) >> OP_SH_RS) & OP_MASK_RS) \
+      == (((INSN2) >> OP_SH_RS) & OP_MASK_RS))
+
+/* Return the minimum alignment for this store instruction.  */
 
 static int
-nops_for_insn (const struct mips_cl_insn *history,
-              const struct mips_cl_insn *insn)
+fix_24k_align_to (const struct mips_opcode *mo)
 {
-  int i, nops, tmp_nops;
+  if (strcmp (mo->name, "sh") == 0)
+    return 2;
 
-  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;
-      }
+  if (strcmp (mo->name, "swc1") == 0
+      || strcmp (mo->name, "swc2") == 0
+      || strcmp (mo->name, "sw") == 0
+      || strcmp (mo->name, "sc") == 0
+      || strcmp (mo->name, "s.s") == 0)
+    return 4;
 
-  if (mips_fix_vr4130)
-    {
-      tmp_nops = nops_for_vr4130 (history, insn);
-      if (tmp_nops > nops)
-       nops = tmp_nops;
-    }
+  if (strcmp (mo->name, "sdc1") == 0
+      || strcmp (mo->name, "sdc2") == 0
+      || strcmp (mo->name, "s.d") == 0)
+    return 8;
 
-  return nops;
+  /* sb, swl, swr */
+  return 1;
 }
 
-/* The variable arguments provide NUM_INSNS extra instructions that
-   might be added to HISTORY.  Return the largest number of nops that
-   would be needed after the extended sequence.  */
+struct fix_24k_store_info
+  {
+    /* Immediate offset, if any, for this store instruction.  */
+    short off;
+    /* Alignment required by this store instruction.  */
+    int align_to;
+    /* True for register offsets.  */
+    int register_offset;
+  };
+
+/* Comparison function used by qsort.  */
 
 static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
+fix_24k_sort (const void *a, const void *b)
 {
-  va_list args;
-  struct mips_cl_insn buffer[MAX_NOPS];
-  struct mips_cl_insn *cursor;
-  int nops;
-
-  va_start (args, history);
-  cursor = buffer + num_insns;
-  memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
-  while (cursor > buffer)
-    *--cursor = *va_arg (args, const struct mips_cl_insn *);
+  const struct fix_24k_store_info *pos1 = a;
+  const struct fix_24k_store_info *pos2 = b;
 
-  nops = nops_for_insn (buffer, NULL);
-  va_end (args);
-  return nops;
+  return (pos1->off - pos2->off);
 }
 
-/* Like nops_for_insn, but if INSN is a branch, take into account the
-   worst-case delay for the branch target.  */
+/* INSN is a store instruction.  Try to record the store information
+   in STINFO.  Return false if the information isn't known.  */
+
+static bfd_boolean
+fix_24k_record_store_info (struct fix_24k_store_info *stinfo,
+                          const struct mips_cl_insn *insn)
+{
+  /* The instruction must have a known offset.  */
+  if (!insn->complete_p || !strstr (insn->insn_mo->args, "o("))
+    return FALSE;
 
+  stinfo->off = (insn->insn_opcode >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE;
+  stinfo->align_to = fix_24k_align_to (insn->insn_mo);
+  return TRUE;
+}
+
+/* Return the number of nops that would be needed to work around the 24k
+   "lost data on stores during refill" errata if instruction INSN
+   immediately followed the 2 instructions described by HIST.
+   Ignore hazards that are contained within the first IGNORE
+   instructions of HIST.
+
+   Problem: The FSB (fetch store buffer) acts as an intermediate buffer
+   for the data cache refills and store data. The following describes
+   the scenario where the store data could be lost.
+
+   * A data cache miss, due to either a load or a store, causing fill
+     data to be supplied by the memory subsystem
+   * The first three doublewords of fill data are returned and written
+     into the cache
+   * A sequence of four stores occurs in consecutive cycles around the
+     final doubleword of the fill:
+   * Store A
+   * Store B
+   * Store C
+   * Zero, One or more instructions
+   * Store D
+
+   The four stores A-D must be to different doublewords of the line that
+   is being filled. The fourth instruction in the sequence above permits
+   the fill of the final doubleword to be transferred from the FSB into
+   the cache. In the sequence above, the stores may be either integer
+   (sb, sh, sw, swr, swl, sc) or coprocessor (swc1/swc2, sdc1/sdc2,
+   swxc1, sdxc1, suxc1) stores, as long as the four stores are to
+   different doublewords on the line. If the floating point unit is
+   running in 1:2 mode, it is not possible to create the sequence above
+   using only floating point store instructions.
+
+   In this case, the cache line being filled is incorrectly marked
+   invalid, thereby losing the data from any store to the line that
+   occurs between the original miss and the completion of the five
+   cycle sequence shown above.
+
+   The workarounds are:
+
+   * Run the data cache in write-through mode.
+   * Insert a non-store instruction between
+     Store A and Store B or Store B and Store C.  */
+  
 static int
-nops_for_insn_or_target (const struct mips_cl_insn *history,
-                        const struct mips_cl_insn *insn)
+nops_for_24k (int ignore, const struct mips_cl_insn *hist,
+             const struct mips_cl_insn *insn)
 {
-  int nops, tmp_nops;
+  struct fix_24k_store_info pos[3];
+  int align, i, base_offset;
 
-  nops = nops_for_insn (history, 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);
-      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);
-      if (tmp_nops > nops)
-       nops = tmp_nops;
-    }
-  return nops;
-}
+  if (ignore >= 2)
+    return 0;
 
-/* Output an instruction.  IP is the instruction information.
-   ADDRESS_EXPR is an operand of the instruction to be used with
-   RELOC_TYPE.  */
+  /* If the previous instruction wasn't a store, there's nothing to
+     worry about.  */
+  if ((hist[0].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
+    return 0;
 
-static void
-append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
-            bfd_reloc_code_real_type *reloc_type)
-{
-  unsigned long prev_pinfo, pinfo;
-  relax_stateT prev_insn_frag_type = 0;
+  /* If the instructions after the previous one are unknown, we have
+     to assume the worst.  */
+  if (!insn)
+    return 1;
+
+  /* Check whether we are dealing with three consecutive stores.  */
+  if ((insn->insn_mo->pinfo & INSN_STORE_MEMORY) == 0
+      || (hist[1].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
+    return 0;
+
+  /* If we don't know the relationship between the store addresses,
+     assume the worst.  */
+  if (!BASE_REG_EQ (insn->insn_opcode, hist[0].insn_opcode)
+      || !BASE_REG_EQ (insn->insn_opcode, hist[1].insn_opcode))
+    return 1;
+
+  if (!fix_24k_record_store_info (&pos[0], insn)
+      || !fix_24k_record_store_info (&pos[1], &hist[0])
+      || !fix_24k_record_store_info (&pos[2], &hist[1]))
+    return 1;
+
+  qsort (&pos, 3, sizeof (struct fix_24k_store_info), fix_24k_sort);
+
+  /* Pick a value of ALIGN and X such that all offsets are adjusted by
+     X bytes and such that the base register + X is known to be aligned
+     to align bytes.  */
+
+  if (((insn->insn_opcode >> OP_SH_RS) & OP_MASK_RS) == SP)
+    align = 8;
+  else
+    {
+      align = pos[0].align_to;
+      base_offset = pos[0].off;
+      for (i = 1; i < 3; i++)
+       if (align < pos[i].align_to)
+         {
+           align = pos[i].align_to;
+           base_offset = pos[i].off;
+         }
+      for (i = 0; i < 3; i++)
+       pos[i].off -= base_offset;
+    }
+
+  pos[0].off &= ~align + 1;
+  pos[1].off &= ~align + 1;
+  pos[2].off &= ~align + 1;
+
+  /* If any two stores write to the same chunk, they also write to the
+     same doubleword.  The offsets are still sorted at this point.  */
+  if (pos[0].off == pos[1].off || pos[1].off == pos[2].off)
+    return 0;
+
+  /* A range of at least 9 bytes is needed for the stores to be in
+     non-overlapping doublewords.  */
+  if (pos[2].off - pos[0].off <= 8)
+    return 0;
+
+  if (pos[2].off - pos[1].off >= 24
+      || pos[1].off - pos[0].off >= 24
+      || pos[2].off - pos[0].off >= 32)
+    return 0;
+
+  return 1;
+}
+
+/* Return the number of nops that would be needed if instruction INSN
+   immediately followed the MAX_NOPS instructions given by HIST,
+   where HIST[0] is the most recent instruction.  Ignore hazards
+   between INSN and the first IGNORE instructions in HIST.
+
+   If INSN is null, return the worse-case number of nops for any
+   instruction.  */
+
+static int
+nops_for_insn (int ignore, const struct mips_cl_insn *hist,
+              const struct mips_cl_insn *insn)
+{
+  int i, nops, tmp_nops;
+
+  nops = 0;
+  for (i = ignore; i < MAX_DELAY_NOPS; i++)
+    {
+      tmp_nops = insns_between (hist + i, insn) - i;
+      if (tmp_nops > nops)
+       nops = tmp_nops;
+    }
+
+  if (mips_fix_vr4130)
+    {
+      tmp_nops = nops_for_vr4130 (ignore, hist, insn);
+      if (tmp_nops > nops)
+       nops = tmp_nops;
+    }
+
+  if (mips_fix_24k)
+    {
+      tmp_nops = nops_for_24k (ignore, hist, insn);
+      if (tmp_nops > nops)
+       nops = tmp_nops;
+    }
+
+  return nops;
+}
+
+/* The variable arguments provide NUM_INSNS extra instructions that
+   might be added to HIST.  Return the largest number of nops that
+   would be needed after the extended sequence, ignoring hazards
+   in the first IGNORE instructions.  */
+
+static int
+nops_for_sequence (int num_insns, int ignore,
+                  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, hist);
+  cursor = buffer + num_insns;
+  memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
+  while (cursor > buffer)
+    *--cursor = *va_arg (args, const struct mips_cl_insn *);
+
+  nops = nops_for_insn (ignore, buffer, NULL);
+  va_end (args);
+  return nops;
+}
+
+/* Like nops_for_insn, but if INSN is a branch, take into account the
+   worst-case delay for the branch target.  */
+
+static int
+nops_for_insn_or_target (int ignore, const struct mips_cl_insn *hist,
+                        const struct mips_cl_insn *insn)
+{
+  int nops, tmp_nops;
+
+  nops = nops_for_insn (ignore, 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, ignore ? ignore + 2 : 0,
+                                   hist, insn, NOP_INSN);
+      if (tmp_nops > nops)
+       nops = tmp_nops;
+    }
+  else if (mips_opts.mips16
+          && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
+                                      | MIPS16_INSN_COND_BRANCH)))
+    {
+      tmp_nops = nops_for_sequence (1, ignore ? ignore + 1 : 0, hist, insn);
+      if (tmp_nops > nops)
+       nops = tmp_nops;
+    }
+  return nops;
+}
+
+/* Fix NOP issue: Replace nops by "or at,at,zero".  */
+
+static void
+fix_loongson2f_nop (struct mips_cl_insn * ip)
+{
+  if (strcmp (ip->insn_mo->name, "nop") == 0)
+    ip->insn_opcode = LOONGSON2F_NOP_INSN;
+}
+
+/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
+                   jr target pc &= 'hffff_ffff_cfff_ffff.  */
+
+static void
+fix_loongson2f_jump (struct mips_cl_insn * ip)
+{
+  if (strcmp (ip->insn_mo->name, "j") == 0
+      || strcmp (ip->insn_mo->name, "jr") == 0
+      || strcmp (ip->insn_mo->name, "jalr") == 0)
+    {
+      int sreg;
+      expressionS ep;
+
+      if (! mips_opts.at)
+        return;
+
+      sreg = EXTRACT_OPERAND (RS, *ip);
+      if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
+        return;
+
+      ep.X_op = O_constant;
+      ep.X_add_number = 0xcfff0000;
+      macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16);
+      ep.X_add_number = 0xffff;
+      macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16);
+      macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG);
+    }
+}
+
+static void
+fix_loongson2f (struct mips_cl_insn * ip)
+{
+  if (mips_fix_loongson2f_nop)
+    fix_loongson2f_nop (ip);
+
+  if (mips_fix_loongson2f_jump)
+    fix_loongson2f_jump (ip);
+}
+
+/* Output an instruction.  IP is the instruction information.
+   ADDRESS_EXPR is an operand of the instruction to be used with
+   RELOC_TYPE.  */
+
+static void
+append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
+            bfd_reloc_code_real_type *reloc_type)
+{
+  unsigned long prev_pinfo, pinfo;
+  unsigned long prev_pinfo2, pinfo2;
+  relax_stateT prev_insn_frag_type = 0;
   bfd_boolean relaxed_branch = FALSE;
   segment_info_type *si = seg_info (now_seg);
 
+  if (mips_fix_loongson2f)
+    fix_loongson2f (ip);
+
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
 
+  file_ase_mips16 |= mips_opts.mips16;
+
   prev_pinfo = history[0].insn_mo->pinfo;
+  prev_pinfo2 = history[0].insn_mo->pinfo2;
   pinfo = ip->insn_mo->pinfo;
+  pinfo2 = ip->insn_mo->pinfo2;
+
+  if (address_expr == NULL)
+    ip->complete_p = 1;
+  else if (*reloc_type <= BFD_RELOC_UNUSED
+          && address_expr->X_op == O_constant)
+    {
+      unsigned int tmp;
+
+      ip->complete_p = 1;
+      switch (*reloc_type)
+       {
+       case BFD_RELOC_32:
+         ip->insn_opcode |= address_expr->X_add_number;
+         break;
+
+       case BFD_RELOC_MIPS_HIGHEST:
+         tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
+         ip->insn_opcode |= tmp & 0xffff;
+         break;
+
+       case BFD_RELOC_MIPS_HIGHER:
+         tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
+         ip->insn_opcode |= tmp & 0xffff;
+         break;
+
+       case BFD_RELOC_HI16_S:
+         tmp = (address_expr->X_add_number + 0x8000) >> 16;
+         ip->insn_opcode |= tmp & 0xffff;
+         break;
+
+       case BFD_RELOC_HI16:
+         ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
+         break;
+
+       case BFD_RELOC_UNUSED:
+       case BFD_RELOC_LO16:
+       case BFD_RELOC_MIPS_GOT_DISP:
+         ip->insn_opcode |= address_expr->X_add_number & 0xffff;
+         break;
+
+       case BFD_RELOC_MIPS_JMP:
+         if ((address_expr->X_add_number & 3) != 0)
+           as_bad (_("jump to misaligned address (0x%lx)"),
+                   (unsigned long) address_expr->X_add_number);
+         ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
+         ip->complete_p = 0;
+         break;
+
+       case BFD_RELOC_MIPS16_JMP:
+         if ((address_expr->X_add_number & 3) != 0)
+           as_bad (_("jump to misaligned address (0x%lx)"),
+                   (unsigned long) address_expr->X_add_number);
+         ip->insn_opcode |=
+           (((address_expr->X_add_number & 0x7c0000) << 3)
+              | ((address_expr->X_add_number & 0xf800000) >> 7)
+              | ((address_expr->X_add_number & 0x3fffc) >> 2));
+         ip->complete_p = 0;
+         break;
+
+       case BFD_RELOC_16_PCREL_S2:
+         if ((address_expr->X_add_number & 3) != 0)
+           as_bad (_("branch to misaligned address (0x%lx)"),
+                   (unsigned long) address_expr->X_add_number);
+         if (mips_relax_branch)
+           goto need_reloc;
+         if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
+           as_bad (_("branch address range overflow (0x%lx)"),
+                   (unsigned long) address_expr->X_add_number);
+         ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
+         ip->complete_p = 0;
+         break;
+
+       default:
+         internalError ();
+       }       
+    }
 
   if (mips_relax.sequence != 2 && !mips_opts.noreorder)
     {
@@ -2551,8 +3186,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
         benefit hand written assembly code, and does not seem worth
         it.  */
       int nops = (mips_optimize == 0
-                 ? nops_for_insn (history, NULL)
-                 : nops_for_insn_or_target (history, ip));
+                 ? nops_for_insn (0, history, NULL)
+                 : nops_for_insn_or_target (0, history, ip));
       if (nops > 0)
        {
          fragS *old_frag;
@@ -2589,9 +3224,13 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
     }
   else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
     {
-      /* 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);
+      int nops;
+
+      /* Work out how many nops in prev_nop_frag are needed by IP,
+        ignoring hazards generated by the first prev_nop_frag_since
+        instructions.  */
+      nops = nops_for_insn_or_target (prev_nop_frag_since, history, ip);
+      gas_assert (nops <= prev_nop_frag_holds);
 
       /* Enforce NOPS as a minimum.  */
       if (nops > prev_nop_frag_required)
@@ -2637,7 +3276,9 @@ 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)
+      /* Don't relax BPOSGE32/64 as they have no complementing branches.  */
+      && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP))
       && !mips_opts.mips16)
     {
       relaxed_branch = TRUE;
@@ -2647,7 +3288,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                              : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
                              : 0)), 4,
                        RELAX_BRANCH_ENCODE
-                       (pinfo & INSN_UNCOND_BRANCH_DELAY,
+                       (AT,
+                        pinfo & INSN_UNCOND_BRANCH_DELAY,
                         pinfo & INSN_COND_BRANCH_LIKELY,
                         pinfo & INSN_WRITE_GPR_31,
                         0),
@@ -2658,7 +3300,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,
@@ -2709,75 +3351,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
 
   if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
     {
-      if (address_expr->X_op == O_constant)
-       {
-         unsigned int tmp;
-
-         switch (*reloc_type)
-           {
-           case BFD_RELOC_32:
-             ip->insn_opcode |= address_expr->X_add_number;
-             break;
-
-           case BFD_RELOC_MIPS_HIGHEST:
-             tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
-             ip->insn_opcode |= tmp & 0xffff;
-             break;
-
-           case BFD_RELOC_MIPS_HIGHER:
-             tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
-             ip->insn_opcode |= tmp & 0xffff;
-             break;
-
-           case BFD_RELOC_HI16_S:
-             tmp = (address_expr->X_add_number + 0x8000) >> 16;
-             ip->insn_opcode |= tmp & 0xffff;
-             break;
-
-           case BFD_RELOC_HI16:
-             ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
-             break;
-
-           case BFD_RELOC_UNUSED:
-           case BFD_RELOC_LO16:
-           case BFD_RELOC_MIPS_GOT_DISP:
-             ip->insn_opcode |= address_expr->X_add_number & 0xffff;
-             break;
-
-           case BFD_RELOC_MIPS_JMP:
-             if ((address_expr->X_add_number & 3) != 0)
-               as_bad (_("jump to misaligned address (0x%lx)"),
-                       (unsigned long) address_expr->X_add_number);
-             ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
-             break;
-
-           case BFD_RELOC_MIPS16_JMP:
-             if ((address_expr->X_add_number & 3) != 0)
-               as_bad (_("jump to misaligned address (0x%lx)"),
-                       (unsigned long) address_expr->X_add_number);
-             ip->insn_opcode |=
-               (((address_expr->X_add_number & 0x7c0000) << 3)
-                | ((address_expr->X_add_number & 0xf800000) >> 7)
-                | ((address_expr->X_add_number & 0x3fffc) >> 2));
-             break;
-
-           case BFD_RELOC_16_PCREL_S2:
-             if ((address_expr->X_add_number & 3) != 0)
-               as_bad (_("branch to misaligned address (0x%lx)"),
-                       (unsigned long) address_expr->X_add_number);
-             if (mips_relax_branch)
-               goto need_reloc;
-             if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
-               as_bad (_("branch address range overflow (0x%lx)"),
-                       (unsigned long) address_expr->X_add_number);
-             ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
-             break;
-
-           default:
-             internalError ();
-           }
-       }
-      else if (*reloc_type < BFD_RELOC_UNUSED)
+      if (!ip->complete_p
+          && *reloc_type < BFD_RELOC_UNUSED)
        need_reloc:
        {
          reloc_howto_type *howto;
@@ -2790,6 +3365,15 @@ 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,
@@ -2808,8 +3392,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
@@ -2822,8 +3404,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)
@@ -2870,55 +3452,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   install_insn (ip);
 
   /* Update the register mask information.  */
-  if (! mips_opts.mips16)
-    {
-      if (pinfo & INSN_WRITE_GPR_D)
-       mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
-      if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
-       mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
-      if (pinfo & INSN_READ_GPR_S)
-       mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
-      if (pinfo & INSN_WRITE_GPR_31)
-       mips_gprmask |= 1 << RA;
-      if (pinfo & INSN_WRITE_FPR_D)
-       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FD, *ip);
-      if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
-       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FS, *ip);
-      if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
-       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FT, *ip);
-      if ((pinfo & INSN_READ_FPR_R) != 0)
-       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FR, *ip);
-      if (pinfo & INSN_COP)
-       {
-         /* We don't keep enough information to sort these cases out.
-            The itbl support does keep this information however, although
-            we currently don't support itbl fprmats as part of the cop
-            instruction.  May want to add this support in the future.  */
-       }
-      /* Never set the bit for $0, which is always zero.  */
-      mips_gprmask &= ~1 << 0;
-    }
-  else
-    {
-      if (pinfo & (MIPS16_INSN_WRITE_X | MIPS16_INSN_READ_X))
-       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
-      if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
-       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
-      if (pinfo & MIPS16_INSN_WRITE_Z)
-       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
-      if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
-       mips_gprmask |= 1 << TREG;
-      if (pinfo & (MIPS16_INSN_WRITE_SP | MIPS16_INSN_READ_SP))
-       mips_gprmask |= 1 << SP;
-      if (pinfo & (MIPS16_INSN_WRITE_31 | MIPS16_INSN_READ_31))
-       mips_gprmask |= 1 << RA;
-      if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
-       mips_gprmask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
-      if (pinfo & MIPS16_INSN_READ_Z)
-       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip);
-      if (pinfo & MIPS16_INSN_READ_GPR_X)
-       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
-    }
+  mips_gprmask |= gpr_read_mask (ip) | gpr_write_mask (ip);
+  mips_cprmask[1] |= fpr_read_mask (ip) | fpr_write_mask (ip);
 
   if (mips_relax.sequence != 2 && !mips_opts.noreorder)
     {
@@ -2964,83 +3499,23 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                  && prev_insn_frag_type == rs_machine_dependent)
              /* Check for conflicts between the branch and the instructions
                 before the candidate delay slot.  */
-             || nops_for_insn (history + 1, ip) > 0
+             || nops_for_insn (0, history + 1, ip) > 0
              /* Check for conflicts between the swapped sequence and the
                 target of the branch.  */
-             || nops_for_sequence (2, history + 1, ip, history) > 0
+             || nops_for_sequence (2, 0, history + 1, ip, history) > 0
              /* We do not swap with a trap instruction, since it
                 complicates trap handlers to have the trap
                 instruction be in a delay slot.  */
              || (prev_pinfo & INSN_TRAP)
              /* If the branch reads a register that the previous
                 instruction sets, we can not swap.  */
-             || (! mips_opts.mips16
-                 && (prev_pinfo & INSN_WRITE_GPR_T)
-                 && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
-                                   MIPS_GR_REG))
-             || (! mips_opts.mips16
-                 && (prev_pinfo & INSN_WRITE_GPR_D)
-                 && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
-                                   MIPS_GR_REG))
-             || (mips_opts.mips16
-                 && (((prev_pinfo & MIPS16_INSN_WRITE_X)
-                      && (insn_uses_reg
-                          (ip, MIPS16_EXTRACT_OPERAND (RX, history[0]),
-                           MIPS16_REG)))
-                     || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
-                         && (insn_uses_reg
-                             (ip, MIPS16_EXTRACT_OPERAND (RY, history[0]),
-                              MIPS16_REG)))
-                     || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
-                         && (insn_uses_reg
-                             (ip, MIPS16_EXTRACT_OPERAND (RZ, history[0]),
-                              MIPS16_REG)))
-                     || ((prev_pinfo & MIPS16_INSN_WRITE_T)
-                         && insn_uses_reg (ip, TREG, MIPS_GR_REG))
-                     || ((prev_pinfo & MIPS16_INSN_WRITE_31)
-                         && insn_uses_reg (ip, RA, MIPS_GR_REG))
-                     || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
-                         && insn_uses_reg (ip,
-                                           MIPS16OP_EXTRACT_REG32R
-                                             (history[0].insn_opcode),
-                                           MIPS_GR_REG))))
+             || (gpr_read_mask (ip) & gpr_write_mask (&history[0])) != 0
              /* If the branch writes a register that the previous
-                instruction sets, we can not swap (we know that
-                branches write only to RD or to $31).  */
-             || (! mips_opts.mips16
-                 && (prev_pinfo & INSN_WRITE_GPR_T)
-                 && (((pinfo & INSN_WRITE_GPR_D)
-                      && (EXTRACT_OPERAND (RT, history[0])
-                          == EXTRACT_OPERAND (RD, *ip)))
-                     || ((pinfo & INSN_WRITE_GPR_31)
-                         && EXTRACT_OPERAND (RT, history[0]) == RA)))
-             || (! mips_opts.mips16
-                 && (prev_pinfo & INSN_WRITE_GPR_D)
-                 && (((pinfo & INSN_WRITE_GPR_D)
-                      && (EXTRACT_OPERAND (RD, history[0])
-                          == EXTRACT_OPERAND (RD, *ip)))
-                     || ((pinfo & INSN_WRITE_GPR_31)
-                         && EXTRACT_OPERAND (RD, history[0]) == RA)))
-             || (mips_opts.mips16
-                 && (pinfo & MIPS16_INSN_WRITE_31)
-                 && ((prev_pinfo & MIPS16_INSN_WRITE_31)
-                     || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
-                         && (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
-                             == RA))))
+                instruction sets, we can not swap.  */
+             || (gpr_write_mask (ip) & gpr_write_mask (&history[0])) != 0
              /* If the branch writes a register that the previous
-                instruction reads, we can not swap (we know that
-                branches only write to RD or to $31).  */
-             || (! mips_opts.mips16
-                 && (pinfo & INSN_WRITE_GPR_D)
-                 && insn_uses_reg (&history[0],
-                                   EXTRACT_OPERAND (RD, *ip),
-                                   MIPS_GR_REG))
-             || (! mips_opts.mips16
-                 && (pinfo & INSN_WRITE_GPR_31)
-                 && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
-             || (mips_opts.mips16
-                 && (pinfo & MIPS16_INSN_WRITE_31)
-                 && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
+                instruction reads, we can not swap.  */
+             || (gpr_write_mask (ip) & gpr_read_mask (&history[0])) != 0
              /* If one instruction sets a condition code and the
                  other one uses a condition code, we can not swap.  */
              || ((pinfo & INSN_READ_COND_CODE)
@@ -3057,7 +3532,11 @@ 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)
@@ -3116,7 +3595,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)
        {
@@ -3156,7 +3637,7 @@ mips_emit_delays (void)
 {
   if (! mips_opts.noreorder)
     {
-      int nops = nops_for_insn (history, NULL);
+      int nops = nops_for_insn (0, history, NULL);
       if (nops > 0)
        {
          while (nops-- > 0)
@@ -3184,7 +3665,7 @@ start_noreorder (void)
       /* Insert any nops that might be needed between the .set noreorder
         block and the previous instructions.  We will later remove any
         nops that turn out not to be needed.  */
-      nops = nops_for_insn (history, NULL);
+      nops = nops_for_insn (0, history, NULL);
       if (nops > 0)
        {
          if (mips_optimize != 0)
@@ -3219,6 +3700,7 @@ start_noreorder (void)
 static void
 end_noreorder (void)
 {
+
   mips_opts.noreorder--;
   if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
     {
@@ -3286,7 +3768,7 @@ macro_end (void)
             warning now.  */
          const char *msg = macro_warning (subtype);
          if (msg != 0)
-           as_warn (msg);
+           as_warn ("%s", msg);
        }
       else
        {
@@ -3332,7 +3814,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
   if (mips_opts.mips16)
     {
-      mips16_macro_build (ep, name, fmt, args);
+      mips16_macro_build (ep, name, fmt, &args);
       va_end (args);
       return;
     }
@@ -3341,8 +3823,8 @@ 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);
+  gas_assert (mo);
+  gas_assert (strcmp (name, mo->name) == 0);
 
   while (1)
     {
@@ -3350,21 +3832,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
         macros will never generate MDMX, MIPS-3D, or MT instructions.  */
       if (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_dsp ? INSN_DSP : 0)
-                               | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
-                                  ? INSN_DSP64 : 0)
-                               | (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
-                               | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
-                              mips_opts.arch)
-         && (mips_opts.arch != CPU_R4650 || (mo->pinfo & FP_D) == 0))
+         && is_opcode_valid (mo))
        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);
@@ -3407,6 +3880,10 @@ 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 ();
            }
@@ -3483,37 +3960,33 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case 'i':
        case 'j':
+         macro_read_relocs (&args, r);
+         gas_assert (*r == BFD_RELOC_GPREL16
+                     || *r == BFD_RELOC_MIPS_HIGHER
+                     || *r == BFD_RELOC_HI16_S
+                     || *r == BFD_RELOC_LO16
+                     || *r == BFD_RELOC_MIPS_GOT_OFST);
+         continue;
+
        case 'o':
          macro_read_relocs (&args, r);
-         assert (*r == BFD_RELOC_GPREL16
-                 || *r == BFD_RELOC_MIPS_LITERAL
-                 || *r == BFD_RELOC_MIPS_HIGHER
-                 || *r == BFD_RELOC_HI16_S
-                 || *r == BFD_RELOC_LO16
-                 || *r == BFD_RELOC_MIPS_GOT16
-                 || *r == BFD_RELOC_MIPS_CALL16
-                 || *r == BFD_RELOC_MIPS_GOT_DISP
-                 || *r == BFD_RELOC_MIPS_GOT_PAGE
-                 || *r == BFD_RELOC_MIPS_GOT_OFST
-                 || *r == BFD_RELOC_MIPS_GOT_LO16
-                 || *r == BFD_RELOC_MIPS_CALL_LO16);
          continue;
 
        case 'u':
          macro_read_relocs (&args, r);
-         assert (ep != NULL
-                 && (ep->X_op == O_constant
-                     || (ep->X_op == O_symbol
-                         && (*r == BFD_RELOC_MIPS_HIGHEST
-                             || *r == BFD_RELOC_HI16_S
-                             || *r == BFD_RELOC_HI16
-                             || *r == BFD_RELOC_GPREL16
-                             || *r == BFD_RELOC_MIPS_GOT_HI16
-                             || *r == BFD_RELOC_MIPS_CALL_HI16))));
+         gas_assert (ep != NULL
+                     && (ep->X_op == O_constant
+                         || (ep->X_op == O_symbol
+                             && (*r == BFD_RELOC_MIPS_HIGHEST
+                                 || *r == BFD_RELOC_HI16_S
+                                 || *r == BFD_RELOC_HI16
+                                 || *r == BFD_RELOC_GPREL16
+                                 || *r == BFD_RELOC_MIPS_GOT_HI16
+                                 || *r == BFD_RELOC_MIPS_CALL_HI16))));
          continue;
 
        case 'p':
-         assert (ep != NULL);
+         gas_assert (ep != NULL);
 
          /*
           * This allows macro() to pass an immediate expression for
@@ -3538,7 +4011,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;
 
@@ -3556,14 +4029,14 @@ 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);
 }
 
 static void
 mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
-                   va_list args)
+                   va_list *args)
 {
   struct mips_opcode *mo;
   struct mips_cl_insn insn;
@@ -3571,14 +4044,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);
@@ -3599,20 +4072,20 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
 
        case 'y':
        case 'w':
-         MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (RY, insn, va_arg (*args, int));
          continue;
 
        case 'x':
        case 'v':
-         MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (RX, insn, va_arg (*args, int));
          continue;
 
        case 'z':
-         MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (RZ, insn, va_arg (*args, int));
          continue;
 
        case 'Z':
-         MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (*args, int));
          continue;
 
        case '0':
@@ -3622,14 +4095,14 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
          continue;
 
        case 'X':
-         MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
          continue;
 
        case 'Y':
          {
            int regno;
 
-           regno = va_arg (args, int);
+           regno = va_arg (*args, int);
            regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
            MIPS16_INSERT_OPERAND (REG32R, insn, regno);
          }
@@ -3652,7 +4125,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;
@@ -3668,14 +4141,14 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
          continue;
 
        case '6':
-         MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (*args, int));
          continue;
        }
 
       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);
 }
@@ -3716,13 +4189,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);
 }
@@ -3741,7 +4214,7 @@ 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;
 
@@ -3754,10 +4227,10 @@ macro_build_lui (expressionS *ep, int regnum)
     }
   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
@@ -3767,8 +4240,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;
@@ -3789,7 +4262,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)
@@ -3815,7 +4288,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\""));
     }
 }
@@ -3942,7 +4415,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)
@@ -3996,7 +4469,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)
@@ -4226,7 +4699,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);
@@ -4415,7 +4888,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\""));
 }
 
@@ -4524,8 +4997,8 @@ add_got_offset_hilo (int dest, expressionS *local, int tmp)
 static void
 macro (struct mips_cl_insn *ip)
 {
-  int treg, sreg, dreg, breg;
-  int tempreg;
+  unsigned int treg, sreg, dreg, breg;
+  unsigned int tempreg;
   int mask;
   int used_at = 0;
   expressionS expr1;
@@ -4543,11 +5016,11 @@ 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;
-  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
+  treg = EXTRACT_OPERAND (RT, *ip);
+  dreg = EXTRACT_OPERAND (RD, *ip);
+  sreg = breg = EXTRACT_OPERAND (RS, *ip);
   mask = ip->insn_mo->mask;
 
   expr1.X_op = O_constant;
@@ -4570,7 +5043,7 @@ macro (struct mips_cl_insn *ip)
       expr1.X_add_number = 8;
       macro_build (&expr1, "bgez", "s,p", sreg);
       if (dreg == sreg)
-       macro_build (NULL, "nop", "", 0);
+       macro_build (NULL, "nop", "");
       else
        move_register (dreg, sreg);
       macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
@@ -4655,7 +5128,7 @@ macro (struct mips_cl_insn *ip)
          break;
        default:
          macro_build (NULL, "balign", "t,s,2", treg, sreg,
-                      (int)imm_expr.X_add_number);
+                      (int) imm_expr.X_add_number);
          break;
        }
       break;
@@ -4676,7 +5149,7 @@ macro (struct mips_cl_insn *ip)
     beq_i:
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build (&offset_expr, s, "s,t,p", sreg, 0);
+         macro_build (&offset_expr, s, "s,t,p", sreg, ZERO);
          break;
        }
       used_at = 1;
@@ -4699,13 +5172,13 @@ macro (struct mips_cl_insn *ip)
        }
       used_at = 1;
       macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
-      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
       break;
 
     case M_BGTL_I:
       likely = 1;
     case M_BGT_I:
-      /* check for > max integer */
+      /* Check for > max integer.  */
       maxnum = 0x7fffffff;
       if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
        {
@@ -4719,11 +5192,11 @@ macro (struct mips_cl_insn *ip)
          && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
        {
        do_false:
-         /* result is always false */
+         /* Result is always false.  */
          if (! likely)
-           macro_build (NULL, "nop", "", 0);
+           macro_build (NULL, "nop", "");
          else
-           macro_build (&offset_expr, "bnel", "s,t,p", 0, 0);
+           macro_build (&offset_expr, "bnel", "s,t,p", ZERO, ZERO);
          break;
        }
       if (imm_expr.X_op != O_constant)
@@ -4765,7 +5238,7 @@ macro (struct mips_cl_insn *ip)
        }
       used_at = 1;
       set_at (sreg, 0);
-      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
       break;
 
     case M_BGEUL:
@@ -4776,12 +5249,12 @@ macro (struct mips_cl_insn *ip)
       if (sreg == 0)
        {
          macro_build (&offset_expr, likely ? "beql" : "beq",
-                      "s,t,p", 0, treg);
+                      "s,t,p", ZERO, treg);
          break;
        }
       used_at = 1;
       macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
-      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
       break;
 
     case M_BGTUL_I:
@@ -4790,7 +5263,7 @@ macro (struct mips_cl_insn *ip)
       if (sreg == 0
          || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
-             && imm_expr.X_add_number == (offsetT) 0xffffffff))
+             && imm_expr.X_add_number == -1))
        goto do_false;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
@@ -4805,12 +5278,12 @@ macro (struct mips_cl_insn *ip)
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build (&offset_expr, likely ? "bnel" : "bne",
-                      "s,t,p", sreg, 0);
+                      "s,t,p", sreg, ZERO);
          break;
        }
       used_at = 1;
       set_at (sreg, 1);
-      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
       break;
 
     case M_BGTL:
@@ -4828,7 +5301,7 @@ macro (struct mips_cl_insn *ip)
        }
       used_at = 1;
       macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
-      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
       break;
 
     case M_BGTUL:
@@ -4837,14 +5310,14 @@ macro (struct mips_cl_insn *ip)
       if (treg == 0)
        {
          macro_build (&offset_expr, likely ? "bnel" : "bne",
-                      "s,t,p", sreg, 0);
+                      "s,t,p", sreg, ZERO);
          break;
        }
       if (sreg == 0)
        goto do_false;
       used_at = 1;
       macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
-      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
       break;
 
     case M_BLEL:
@@ -4862,7 +5335,7 @@ macro (struct mips_cl_insn *ip)
        }
       used_at = 1;
       macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
-      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
       break;
 
     case M_BLEL_I:
@@ -4900,7 +5373,7 @@ macro (struct mips_cl_insn *ip)
        }
       used_at = 1;
       set_at (sreg, 0);
-      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
       break;
 
     case M_BLEUL:
@@ -4909,14 +5382,14 @@ macro (struct mips_cl_insn *ip)
       if (treg == 0)
        {
          macro_build (&offset_expr, likely ? "beql" : "beq",
-                      "s,t,p", sreg, 0);
+                      "s,t,p", sreg, ZERO);
          break;
        }
       if (sreg == 0)
        goto do_true;
       used_at = 1;
       macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
-      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
       break;
 
     case M_BLEUL_I:
@@ -4925,7 +5398,7 @@ macro (struct mips_cl_insn *ip)
       if (sreg == 0
          || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
-             && imm_expr.X_add_number == (offsetT) 0xffffffff))
+             && imm_expr.X_add_number == -1))
        goto do_true;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
@@ -4940,12 +5413,12 @@ macro (struct mips_cl_insn *ip)
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build (&offset_expr, likely ? "beql" : "beq",
-                      "s,t,p", sreg, 0);
+                      "s,t,p", sreg, ZERO);
          break;
        }
       used_at = 1;
       set_at (sreg, 1);
-      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
       break;
 
     case M_BLTL:
@@ -4963,7 +5436,7 @@ macro (struct mips_cl_insn *ip)
        }
       used_at = 1;
       macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
-      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
       break;
 
     case M_BLTUL:
@@ -4974,40 +5447,40 @@ macro (struct mips_cl_insn *ip)
       if (sreg == 0)
        {
          macro_build (&offset_expr, likely ? "bnel" : "bne",
-                      "s,t,p", 0, treg);
+                      "s,t,p", ZERO, treg);
          break;
        }
       used_at = 1;
       macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
-      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
       break;
 
     case M_DEXT:
       {
-       unsigned long pos;
-       unsigned long size;
+       /* Use unsigned arithmetic.  */
+       addressT pos;
+       addressT size;
 
-        if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
+       if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
          {
            as_bad (_("Unsupported large constant"));
            pos = size = 1;
          }
        else
          {
-           pos = (unsigned long) imm_expr.X_add_number;
-           size = (unsigned long) imm2_expr.X_add_number;
+           pos = imm_expr.X_add_number;
+           size = imm2_expr.X_add_number;
          }
 
        if (pos > 63)
          {
-           as_bad (_("Improper position (%lu)"), pos);
+           as_bad (_("Improper position (%lu)"), (unsigned long) pos);
            pos = 1;
          }
-        if (size == 0 || size > 64
-           || (pos + size - 1) > 63)
+       if (size == 0 || size > 64 || (pos + size - 1) > 63)
          {
            as_bad (_("Improper extract size (%lu, position %lu)"),
-                   size, pos);
+                   (unsigned long) size, (unsigned long) pos);
            size = 1;
          }
 
@@ -5026,36 +5499,37 @@ macro (struct mips_cl_insn *ip)
            s = "dextm";
            fmt = "t,r,+A,+G";
          }
-       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos, size - 1);
+       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
+                    (int) (size - 1));
       }
       break;
 
     case M_DINS:
       {
-       unsigned long pos;
-       unsigned long size;
+       /* Use unsigned arithmetic.  */
+       addressT pos;
+       addressT size;
 
-        if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
+       if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
          {
            as_bad (_("Unsupported large constant"));
            pos = size = 1;
          }
        else
          {
-           pos = (unsigned long) imm_expr.X_add_number;
-           size = (unsigned long) imm2_expr.X_add_number;
+           pos = imm_expr.X_add_number;
+           size = imm2_expr.X_add_number;
          }
 
        if (pos > 63)
          {
-           as_bad (_("Improper position (%lu)"), pos);
+           as_bad (_("Improper position (%lu)"), (unsigned long) pos);
            pos = 1;
          }
-        if (size == 0 || size > 64
-           || (pos + size - 1) > 63)
+       if (size == 0 || size > 64 || (pos + size - 1) > 63)
          {
            as_bad (_("Improper insert size (%lu, position %lu)"),
-                   size, pos);
+                   (unsigned long) size, (unsigned long) pos);
            size = 1;
          }
 
@@ -5074,8 +5548,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;
 
@@ -5093,7 +5567,7 @@ macro (struct mips_cl_insn *ip)
        {
          as_warn (_("Divide by zero."));
          if (mips_trap)
-           macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
+           macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
          else
            macro_build (NULL, "break", "c", 7);
          break;
@@ -5102,13 +5576,13 @@ macro (struct mips_cl_insn *ip)
       start_noreorder ();
       if (mips_trap)
        {
-         macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+         macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
          macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
        }
       else
        {
          expr1.X_add_number = 8;
-         macro_build (&expr1, "bne", "s,t,p", treg, 0);
+         macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
          macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
          macro_build (NULL, "break", "c", 7);
        }
@@ -5139,7 +5613,7 @@ macro (struct mips_cl_insn *ip)
        {
          expr1.X_add_number = 8;
          macro_build (&expr1, "bne", "s,t,p", sreg, AT);
-         macro_build (NULL, "nop", "", 0);
+         macro_build (NULL, "nop", "");
 
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
@@ -5190,7 +5664,7 @@ macro (struct mips_cl_insn *ip)
        {
          as_warn (_("Divide by zero."));
          if (mips_trap)
-           macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
+           macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
          else
            macro_build (NULL, "break", "c", 7);
          break;
@@ -5200,7 +5674,7 @@ macro (struct mips_cl_insn *ip)
          if (strcmp (s2, "mflo") == 0)
            move_register (dreg, sreg);
          else
-           move_register (dreg, 0);
+           move_register (dreg, ZERO);
          break;
        }
       if (imm_expr.X_op == O_constant
@@ -5212,7 +5686,7 @@ macro (struct mips_cl_insn *ip)
              macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
            }
          else
-           move_register (dreg, 0);
+           move_register (dreg, ZERO);
          break;
        }
 
@@ -5241,7 +5715,7 @@ macro (struct mips_cl_insn *ip)
       start_noreorder ();
       if (mips_trap)
        {
-         macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+         macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
          macro_build (NULL, s, "z,s,t", sreg, treg);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
@@ -5250,7 +5724,7 @@ macro (struct mips_cl_insn *ip)
       else
        {
          expr1.X_add_number = 8;
-         macro_build (&expr1, "bne", "s,t,p", treg, 0);
+         macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
          macro_build (NULL, s, "z,s,t", sreg, treg);
 
          /* We want to close the noreorder block as soon as possible, so
@@ -5276,7 +5750,7 @@ macro (struct mips_cl_insn *ip)
       if (dbl && HAVE_32BIT_GPRS)
        as_warn (_("dla used to load 32-bit register"));
 
-      if (! dbl && HAVE_64BIT_OBJECTS)
+      if (!dbl && HAVE_64BIT_OBJECTS)
        as_warn (_("la used to load 64-bit address"));
 
       if (offset_expr.X_op == O_constant
@@ -5288,7 +5762,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;
@@ -5301,7 +5775,7 @@ macro (struct mips_cl_insn *ip)
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
-         as_bad (_("expression too complex"));
+         as_bad (_("Expression too complex"));
          offset_expr.X_op = O_constant;
        }
 
@@ -5347,7 +5821,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);
@@ -5389,7 +5863,7 @@ macro (struct mips_cl_insn *ip)
                  relax_switch ();
                }
              if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
-               as_bad (_("offset too large"));
+               as_bad (_("Offset too large"));
              macro_build_lui (&offset_expr, tempreg);
              macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                           tempreg, tempreg, BFD_RELOC_LO16);
@@ -5536,8 +6010,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
@@ -5549,7 +6021,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;
@@ -5677,8 +6149,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
@@ -5690,7 +6160,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);
@@ -5733,7 +6203,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);
@@ -5816,8 +6286,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
@@ -5829,7 +6297,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;
@@ -5866,6 +6334,38 @@ 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);
+      }
+      break;
+
+    case M_MSGLD:
+      {
+       unsigned long temp = (0x02);
+       macro_build (NULL, "c2", "C", temp);
+      }
+      break;
+
+    case M_MSGLD_T:
+      {
+       unsigned long temp = (treg << 16) | (0x02);
+       macro_build (NULL, "c2", "C", temp);
+      }
+      break;
+
+    case M_MSGWAIT:
+      macro_build (NULL, "c2", "C", 3);
+      break;
+
+    case M_MSGWAIT_T:
+      {
+       unsigned long temp = (treg << 16) | 0x03;
+       macro_build (NULL, "c2", "C", temp);
+      }
+      break;
+
     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
@@ -5897,18 +6397,20 @@ macro (struct mips_cl_insn *ip)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
                {
-                 if (! mips_frame_reg_valid)
+                 if (!mips_frame_reg_valid)
                    {
                      as_warn (_("No .frame pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_frame_reg_valid = 1;
                    }
-                 if (! mips_cprestore_valid)
+                 if (!mips_cprestore_valid)
                    {
                      as_warn (_("No .cprestore pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_cprestore_valid = 1;
                    }
+                 if (mips_opts.noreorder)
+                   macro_build (NULL, "nop", "");
                  expr1.X_add_number = mips_cprestore_offset;
                  macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
                                                mips_gp_register,
@@ -5955,7 +6457,7 @@ macro (struct mips_cl_insn *ip)
             GOT_DISP.  */
          if (HAVE_NEWABI)
            {
-             if (! mips_big_got)
+             if (!mips_big_got)
                {
                  relax_start (offset_expr.X_add_symbol);
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
@@ -5992,7 +6494,7 @@ macro (struct mips_cl_insn *ip)
          else
            {
              relax_start (offset_expr.X_add_symbol);
-             if (! mips_big_got)
+             if (!mips_big_got)
                {
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
@@ -6030,13 +6532,13 @@ macro (struct mips_cl_insn *ip)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
                {
-                 if (! mips_frame_reg_valid)
+                 if (!mips_frame_reg_valid)
                    {
                      as_warn (_("No .frame pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_frame_reg_valid = 1;
                    }
-                 if (! mips_cprestore_valid)
+                 if (!mips_cprestore_valid)
                    {
                      as_warn (_("No .cprestore pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
@@ -6103,11 +6605,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;
@@ -6193,12 +6690,10 @@ macro (struct mips_cl_insn *ip)
     case M_CACHE_AB:
       s = "cache";
       goto st;
+    case M_PREF_AB:
+      s = "pref";
+      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.  */
@@ -6222,6 +6717,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
@@ -6230,7 +6734,7 @@ macro (struct mips_cl_insn *ip)
          || mask == M_L_DAB
          || mask == M_S_DAB)
        fmt = "T,o(b)";
-      else if (mask == M_CACHE_AB)
+      else if (mask == M_CACHE_AB || mask == M_PREF_AB)
        fmt = "k,o(b)";
       else if (coproc)
        fmt = "E,o(b)";
@@ -6240,7 +6744,7 @@ macro (struct mips_cl_insn *ip)
       if (offset_expr.X_op != O_constant
          && offset_expr.X_op != O_symbol)
        {
-         as_bad (_("expression too complex"));
+         as_bad (_("Expression too complex"));
          offset_expr.X_op = O_constant;
        }
 
@@ -6257,14 +6761,19 @@ macro (struct mips_cl_insn *ip)
         is in non PIC code.  */
       if (offset_expr.X_op == O_constant)
        {
-         expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
-                               & ~(bfd_vma) 0xffff);
+         expr1.X_add_number = offset_expr.X_add_number;
          normalize_address_expr (&expr1);
-         load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
-         if (breg != 0)
-           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                        tempreg, tempreg, breg);
-         macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+         if (!IS_SEXT_16BIT_NUM (expr1.X_add_number))
+           {
+             expr1.X_add_number = ((expr1.X_add_number + 0x8000)
+                                   & ~(bfd_vma) 0xffff);
+             load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
+             if (breg != 0)
+               macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                            tempreg, tempreg, breg);
+             breg = tempreg;
+           }
+         macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
        }
       else if (mips_pic == NO_PIC)
        {
@@ -6344,7 +6853,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);
@@ -6443,7 +6952,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,
@@ -6493,7 +7002,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
@@ -6532,7 +7041,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
@@ -6585,11 +7094,11 @@ macro (struct mips_cl_insn *ip)
        }
       else
        {
-         assert (offset_expr.X_op == O_symbol
-                 && strcmp (segment_name (S_GET_SEGMENT
-                                          (offset_expr.X_add_symbol)),
-                            ".lit4") == 0
-                 && offset_expr.X_add_number == 0);
+         gas_assert (offset_expr.X_op == O_symbol
+                     && strcmp (segment_name (S_GET_SEGMENT
+                                              (offset_expr.X_add_symbol)),
+                                ".lit4") == 0
+                     && offset_expr.X_add_number == 0);
          macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
                       BFD_RELOC_MIPS_LITERAL, mips_gp_register);
          break;
@@ -6627,7 +7136,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);
                    }
                }
@@ -6682,7 +7191,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
@@ -6692,7 +7201,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);
                }
@@ -6700,8 +7209,8 @@ macro (struct mips_cl_insn *ip)
          break;
        }
 
-      assert (offset_expr.X_op == O_symbol
-             && offset_expr.X_add_number == 0);
+      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)
        {
@@ -6717,7 +7226,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,
@@ -6740,16 +7249,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
@@ -6759,6 +7263,17 @@ macro (struct mips_cl_insn *ip)
                   target_big_endian ? treg : treg + 1, r, breg);
       break;
 
+    case M_S_DOB:
+      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)",
+                  target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
+      offset_expr.X_add_number += 4;
+      macro_build (&offset_expr, "swc1", "T,o(b)",
+                  target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
+      break;
+
     case M_L_DAB:
       /*
        * The MIPS assembler seems to check for X_add_number not
@@ -6771,11 +7286,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)
@@ -6789,12 +7299,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";
@@ -6832,7 +7336,7 @@ macro (struct mips_cl_insn *ip)
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
-         as_bad (_("expression too complex"));
+         as_bad (_("Expression too complex"));
          offset_expr.X_op = O_constant;
        }
 
@@ -6849,11 +7353,10 @@ macro (struct mips_cl_insn *ip)
         to adjust when loading from memory.  We set coproc if we must
         load $fn+1 first.  */
       /* Itbl support may require additional care here.  */
-      if (! target_big_endian)
+      if (!target_big_endian)
        coproc = 0;
 
-      if (mips_pic == NO_PIC
-         || offset_expr.X_op == O_constant)
+      if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
        {
          /* If this is a reference to a GP relative symbol, we want
               <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
@@ -6902,26 +7405,7 @@ macro (struct mips_cl_insn *ip)
 
              relax_switch ();
 
-             /* We just generated two relocs.  When tc_gen_reloc
-                handles this case, it will skip the first reloc and
-                handle the second.  The second reloc already has an
-                extra addend of 4, which we added above.  We must
-                subtract it out, and then subtract another 4 to make
-                the first reloc come out right.  The second reloc
-                will come out right because we are going to add 4 to
-                offset_expr when we build its instruction below.
-
-                If we have a symbol, then we don't want to include
-                the offset, because it will wind up being included
-                when we generate the reloc.  */
-
-             if (offset_expr.X_op == O_constant)
-               offset_expr.X_add_number -= 8;
-             else
-               {
-                 offset_expr.X_add_number = -4;
-                 offset_expr.X_op = O_constant;
-               }
+             offset_expr.X_add_number -= 4;
            }
          used_at = 1;
          macro_build_lui (&offset_expr, AT);
@@ -7066,15 +7550,21 @@ macro (struct mips_cl_insn *ip)
       break;
 
     case M_LD_OB:
-      s = "lw";
+      s = HAVE_64BIT_GPRS ? "ld" : "lw";
       goto sd_ob;
     case M_SD_OB:
-      s = "sw";
+      s = HAVE_64BIT_GPRS ? "sd" : "sw";
     sd_ob:
-      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);
+      macro_build (&offset_expr, s, "t,o(b)", treg,
+                  -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+                  breg);
+      if (!HAVE_64BIT_GPRS)
+       {
+         offset_expr.X_add_number += 4;
+         macro_build (&offset_expr, s, "t,o(b)", treg + 1,
+                      -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+                      breg);
+       }
       break;
 
    /* New code added to support COPZ instructions.
@@ -7106,6 +7596,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);
@@ -7115,66 +7613,6 @@ macro (struct mips_cl_insn *ip)
       move_register (dreg, sreg);
       break;
 
-#ifdef LOSING_COMPILER
-    default:
-      /* Try and see if this is a new itbl instruction.
-         This code builds table entries out of the macros in mip_opcodes.
-         FIXME: For now we just assemble the expression and pass it's
-         value along as a 32-bit immediate.
-         We may want to have the assembler assemble this value,
-         so that we gain the assembler's knowledge of delay slots,
-         symbols, etc.
-         Would it be more efficient to use mask (id) here? */
-      if (itbl_have_entries
-         && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
-       {
-         s = ip->insn_mo->name;
-         s2 = "cop3";
-         coproc = ITBL_DECODE_PNUM (immed_expr);;
-         macro_build (&immed_expr, s, "C");
-         break;
-       }
-      macro2 (ip);
-      break;
-    }
-  if (mips_opts.noat && used_at)
-    as_bad (_("Macro used $at after \".set noat\""));
-}
-
-static void
-macro2 (struct mips_cl_insn *ip)
-{
-  int treg, sreg, dreg, breg;
-  int tempreg;
-  int mask;
-  int used_at;
-  expressionS expr1;
-  const char *s;
-  const char *s2;
-  const char *fmt;
-  int likely = 0;
-  int dbl = 0;
-  int coproc = 0;
-  int lr = 0;
-  int imm = 0;
-  int off;
-  offsetT maxnum;
-  bfd_reloc_code_real_type r;
-
-  treg = (ip->insn_opcode >> 16) & 0x1f;
-  dreg = (ip->insn_opcode >> 11) & 0x1f;
-  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
-  mask = ip->insn_mo->mask;
-
-  expr1.X_op = O_constant;
-  expr1.X_op_symbol = NULL;
-  expr1.X_add_symbol = NULL;
-  expr1.X_add_number = 1;
-
-  switch (mask)
-    {
-#endif /* LOSING_COMPILER */
-
     case M_DMUL:
       dbl = 1;
     case M_MUL:
@@ -7218,7 +7656,7 @@ macro2 (struct mips_cl_insn *ip)
        {
          expr1.X_add_number = 8;
          macro_build (&expr1, "beq", "s,t,p", dreg, AT);
-         macro_build (NULL, "nop", "", 0);
+         macro_build (NULL, "nop", "");
          macro_build (NULL, "break", "c", 6);
        }
       end_noreorder ();
@@ -7244,12 +7682,12 @@ macro2 (struct mips_cl_insn *ip)
       macro_build (NULL, "mfhi", "d", AT);
       macro_build (NULL, "mflo", "d", dreg);
       if (mips_trap)
-       macro_build (NULL, "tne", "s,t,q", AT, 0, 6);
+       macro_build (NULL, "tne", "s,t,q", AT, ZERO, 6);
       else
        {
          expr1.X_add_number = 8;
-         macro_build (&expr1, "beq", "s,t,p", AT, 0);
-         macro_build (NULL, "nop", "", 0);
+         macro_build (&expr1, "beq", "s,t,p", AT, ZERO);
+         macro_build (NULL, "nop", "");
          macro_build (NULL, "break", "c", 6);
        }
       end_noreorder ();
@@ -7272,7 +7710,7 @@ macro2 (struct mips_cl_insn *ip)
          break;
        }
       used_at = 1;
-      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
       macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
       macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
@@ -7295,7 +7733,7 @@ macro2 (struct mips_cl_insn *ip)
          break;
        }
       used_at = 1;
-      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
       macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
       macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
@@ -7304,7 +7742,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"));
@@ -7324,11 +7763,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;
@@ -7364,7 +7803,7 @@ macro2 (struct mips_cl_insn *ip)
          break;
        }
       used_at = 1;
-      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
       macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
       macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
@@ -7377,7 +7816,7 @@ macro2 (struct mips_cl_insn *ip)
          break;
        }
       used_at = 1;
-      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
       macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
       macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
@@ -7386,7 +7825,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"));
@@ -7404,11 +7844,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);
       }
@@ -7438,22 +7878,6 @@ 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);
-      /* 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)",
-                  target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
-      offset_expr.X_add_number += 4;
-      macro_build (&offset_expr, "swc1", "T,o(b)",
-                  target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
-      break;
-
     case M_SEQ:
       if (sreg == 0)
        macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
@@ -7479,6 +7903,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)
@@ -7493,6 +7925,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);
@@ -7626,6 +8065,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)
@@ -7640,6 +8087,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);
@@ -7708,7 +8162,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 */
@@ -7742,11 +8196,11 @@ macro2 (struct mips_cl_insn *ip)
     ulh:
       used_at = 1;
       if (offset_expr.X_add_number >= 0x7fff)
-       as_bad (_("operand overflow"));
-      if (! target_big_endian)
+       as_bad (_("Operand overflow"));
+      if (!target_big_endian)
        ++offset_expr.X_add_number;
       macro_build (&offset_expr, s, "t,o(b)", AT, BFD_RELOC_LO16, breg);
-      if (! target_big_endian)
+      if (!target_big_endian)
        --offset_expr.X_add_number;
       else
        ++offset_expr.X_add_number;
@@ -7766,7 +8220,7 @@ macro2 (struct mips_cl_insn *ip)
       off = 3;
     ulw:
       if (offset_expr.X_add_number >= 0x8000 - off)
-       as_bad (_("operand overflow"));
+       as_bad (_("Operand overflow"));
       if (treg != breg)
        tempreg = treg;
       else
@@ -7774,16 +8228,16 @@ macro2 (struct mips_cl_insn *ip)
          used_at = 1;
          tempreg = AT;
        }
-      if (! target_big_endian)
+      if (!target_big_endian)
        offset_expr.X_add_number += off;
       macro_build (&offset_expr, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
-      if (! target_big_endian)
+      if (!target_big_endian)
        offset_expr.X_add_number -= off;
       else
        offset_expr.X_add_number += off;
       macro_build (&offset_expr, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
 
-      /* If necessary, move the result in tempreg the final destination.  */
+      /* If necessary, move the result in tempreg to the final destination.  */
       if (treg == tempreg)
         break;
       /* Protect second load's delay slot.  */
@@ -7805,12 +8259,12 @@ macro2 (struct mips_cl_insn *ip)
       load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = off;
       else
        expr1.X_add_number = 0;
       macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = 0;
       else
        expr1.X_add_number = off;
@@ -7839,7 +8293,7 @@ macro2 (struct mips_cl_insn *ip)
     case M_USH:
       used_at = 1;
       if (offset_expr.X_add_number >= 0x7fff)
-       as_bad (_("operand overflow"));
+       as_bad (_("Operand overflow"));
       if (target_big_endian)
        ++offset_expr.X_add_number;
       macro_build (&offset_expr, "sb", "t,o(b)", treg, BFD_RELOC_LO16, breg);
@@ -7862,11 +8316,11 @@ macro2 (struct mips_cl_insn *ip)
       off = 3;
     usw:
       if (offset_expr.X_add_number >= 0x8000 - off)
-       as_bad (_("operand overflow"));
-      if (! target_big_endian)
+       as_bad (_("Operand overflow"));
+      if (!target_big_endian)
        offset_expr.X_add_number += off;
       macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
-      if (! target_big_endian)
+      if (!target_big_endian)
        offset_expr.X_add_number -= off;
       else
        offset_expr.X_add_number += off;
@@ -7887,12 +8341,12 @@ macro2 (struct mips_cl_insn *ip)
       load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = off;
       else
        expr1.X_add_number = 0;
       macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = 0;
       else
        expr1.X_add_number = off;
@@ -7904,16 +8358,16 @@ macro2 (struct mips_cl_insn *ip)
       load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = 0;
       macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
       macro_build (NULL, "srl", "d,w,<", treg, treg, 8);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = 1;
       else
        expr1.X_add_number = 0;
       macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
-      if (! target_big_endian)
+      if (!target_big_endian)
        expr1.X_add_number = 0;
       else
        expr1.X_add_number = 1;
@@ -7928,7 +8382,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\""));
 }
 
@@ -8206,6 +8660,19 @@ 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;
+         case 'z': USE_BITS (OP_MASK_RZ,       OP_SH_RZ);      break;
+         case 'Z': USE_BITS (OP_MASK_FZ,       OP_SH_FZ);      break;
+         case 'a': USE_BITS (OP_MASK_OFFSET_A, OP_SH_OFFSET_A); break;
+         case 'b': USE_BITS (OP_MASK_OFFSET_B, OP_SH_OFFSET_B); break;
+         case 'c': USE_BITS (OP_MASK_OFFSET_C, OP_SH_OFFSET_C); break;
+
          default:
            as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
                    c, opc->name, opc->args);
@@ -8267,6 +8734,7 @@ 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;
@@ -8369,7 +8837,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   struct mips_opcode *insn;
   char *argsStart;
   unsigned int regno;
-  unsigned int lastregno = 0;
+  unsigned int lastregno;
   unsigned int lastpos = 0;
   unsigned int limlo, limhi;
   char *s_reset;
@@ -8415,7 +8883,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;
        }
 
@@ -8423,7 +8891,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;
        }
     }
@@ -8433,33 +8901,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_dspr2 ? INSN_DSPR2 : 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);
       if (! ok)
        {
          if (insn + 1 < &mips_opcodes[NUMOPCODES]
@@ -8488,6 +8932,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;
@@ -8501,7 +8946,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                return;
              break;
 
-           case '2': /* dsp 2-bit unsigned immediate in bit 11 */
+           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
@@ -8515,7 +8960,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '3': /* dsp 3-bit unsigned immediate in bit 21 */
+           case '3': /* DSP 3-bit unsigned immediate in bit 21.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_SA3)
@@ -8528,7 +8973,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '4': /* dsp 4-bit unsigned immediate in bit 21 */
+           case '4': /* DSP 4-bit unsigned immediate in bit 21.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_SA4)
@@ -8541,7 +8986,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '5': /* dsp 8-bit unsigned immediate in bit 16 */
+           case '5': /* DSP 8-bit unsigned immediate in bit 16.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_IMM8)
@@ -8554,7 +8999,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '6': /* dsp 5-bit unsigned immediate in bit 21 */
+           case '6': /* DSP 5-bit unsigned immediate in bit 21.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_RS)
@@ -8567,7 +9012,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '7': /* four dsp accumulators in bits 11,12 */ 
+           case '7': /* Four DSP accumulators in bits 11,12.  */
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                {
@@ -8580,7 +9025,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                as_bad (_("Invalid dsp acc register"));
              break;
 
-           case '8': /* dsp 6-bit unsigned immediate in bit 11 */
+           case '8': /* DSP 6-bit unsigned immediate in bit 11.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
@@ -8594,7 +9039,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '9': /* four dsp accumulators in bits 21,22 */
+           case '9': /* Four DSP accumulators in bits 21,22.  */
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                {
@@ -8607,7 +9052,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                as_bad (_("Invalid dsp acc register"));
              break;
 
-           case '0': /* dsp 6-bit signed immediate in bit 20 */
+           case '0': /* DSP 6-bit signed immediate in bit 20.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              min_range = -((OP_MASK_DSPSFT + 1) >> 1);
@@ -8624,7 +9069,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '\'': /* dsp 6-bit unsigned immediate in bit 16 */
+           case '\'': /* DSP 6-bit unsigned immediate in bit 16.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
@@ -8638,7 +9083,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case ':': /* dsp 7-bit signed immediate in bit 19 */
+           case ':': /* DSP 7-bit signed immediate in bit 19.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
@@ -8655,7 +9100,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '@': /* dsp 10-bit signed immediate in bit 16 */
+           case '@': /* DSP 10-bit signed immediate in bit 16.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              min_range = -((OP_MASK_IMM10 + 1) >> 1);
@@ -8694,7 +9139,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case '*': /* four dsp accumulators in bits 18,19 */ 
+           case '*': /* Four DSP accumulators in bits 18,19.  */
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                {
@@ -8707,7 +9152,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                as_bad (_("Invalid dsp/smartmips acc register"));
              break;
 
-           case '&': /* four dsp accumulators in bits 13,14 */ 
+           case '&': /* Four DSP accumulators in bits 13,14.  */
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                {
@@ -8752,12 +9197,11 @@ 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'
-                     || args[1] == '-' || args[1] == '4');
+             gas_assert (args[1] == 'b');
              if (*s == '\0')
                return;
 
-           case ')':           /* these must match exactly */
+           case ')':           /* These must match exactly.  */
            case '[':
            case ']':
              if (*s++ == *args)
@@ -8786,7 +9230,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                                 imm->desc ? imm->desc : ip->insn_mo->name,
                                 (unsigned long) imm_expr.X_add_number,
                                 (unsigned long) imm_expr.X_add_number);
-                             imm_expr.X_add_number &= imm->mask;
+                       imm_expr.X_add_number &= imm->mask;
                      }
                    ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
                                        << imm->shift);
@@ -8794,7 +9238,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                    s = expr_end;
                  }
                  continue;
-                 
+
                case 'A':               /* ins/ext position, becomes LSB.  */
                  limlo = 0;
                  limhi = 31;
@@ -8803,7 +9247,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  limlo = 32;
                  limhi = 63;
                  goto do_lsb;
-do_lsb:
+               do_lsb:
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned long) imm_expr.X_add_number < limlo
@@ -8827,7 +9271,7 @@ do_lsb:
                  limlo = 33;
                  limhi = 64;
                  goto do_msb;
-do_msb:
+               do_msb:
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  /* Check for negative input so that small negative numbers
@@ -8851,87 +9295,278 @@ do_msb:
                  s = expr_end;
                  continue;
 
-               case 'C':               /* ext size, becomes MSBD.  */
-                 limlo = 1;
-                 limhi = 32;
-                 goto do_msbd;
-               case 'G':
-                 limlo = 33;
-                 limhi = 64;
-                 goto do_msbd;
-               case 'H':
-                 limlo = 33;
-                 limhi = 64;
-                 goto do_msbd;
-do_msbd:
+               case 'C':               /* ext size, becomes MSBD.  */
+                 limlo = 1;
+                 limhi = 32;
+                 goto do_msbd;
+               case 'G':
+                 limlo = 33;
+                 limhi = 64;
+                 goto do_msbd;
+               case 'H':
+                 limlo = 33;
+                 limhi = 64;
+                 goto do_msbd;
+               do_msbd:
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 /* Check for negative input so that small negative numbers
+                    will not succeed incorrectly.  The checks against
+                    (pos+size) transitively check "size" itself,
+                    assuming that "pos" is reasonable.  */
+                 if ((long) imm_expr.X_add_number < 0
+                     || ((unsigned long) imm_expr.X_add_number
+                         + lastpos) < limlo
+                     || ((unsigned long) imm_expr.X_add_number
+                         + lastpos) > limhi)
+                   {
+                     as_bad (_("Improper extract size (%lu, position %lu)"),
+                             (unsigned long) imm_expr.X_add_number,
+                             (unsigned long) lastpos);
+                     imm_expr.X_add_number = limlo - lastpos;
+                   }
+                 INSERT_OPERAND (EXTMSBD, *ip, imm_expr.X_add_number - 1);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'D':
+                 /* +D is for disassembly only; never match.  */
+                 break;
+
+               case 'I':
+                 /* "+I" is like "I", except that imm2_expr is used.  */
+                 my_getExpression (&imm2_expr, s);
+                 if (imm2_expr.X_op != O_big
+                     && imm2_expr.X_op != O_constant)
+                 insn_error = _("absolute expression required");
+                 if (HAVE_32BIT_GPRS)
+                   normalize_constant_expr (&imm2_expr);
+                 s = expr_end;
+                 continue;
+
+               case 'T': /* Coprocessor register.  */
+                 /* +T is for disassembly only; never match.  */
+                 break;
+
+               case 't': /* Coprocessor register number.  */
+                 if (s[0] == '$' && ISDIGIT (s[1]))
+                   {
+                     ++s;
+                     regno = 0;
+                     do
+                       {
+                         regno *= 10;
+                         regno += *s - '0';
+                         ++s;
+                       }
+                     while (ISDIGIT (*s));
+                     if (regno > 31)
+                       as_bad (_("Invalid register number (%d)"), regno);
+                     else
+                       {
+                         INSERT_OPERAND (RT, *ip, regno);
+                         continue;
+                       }
+                   }
+                 else
+                   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;
+
+               case 'a': /* 8-bit signed offset in bit 6 */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 min_range = -((OP_MASK_OFFSET_A + 1) >> 1);
+                 max_range = ((OP_MASK_OFFSET_A + 1) >> 1) - 1;
+                 if (imm_expr.X_add_number < min_range
+                     || imm_expr.X_add_number > max_range)
+                   {
+                     as_bad (_("Offset not in range %ld..%ld (%ld)"),
+                             (long) min_range, (long) max_range,
+                             (long) imm_expr.X_add_number);
+                   }
+                 INSERT_OPERAND (OFFSET_A, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'b': /* 8-bit signed offset in bit 3 */
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
-                 /* Check for negative input so that small negative numbers
-                    will not succeed incorrectly.  The checks against
-                    (pos+size) transitively check "size" itself,
-                    assuming that "pos" is reasonable.  */
-                 if ((long) imm_expr.X_add_number < 0
-                     || ((unsigned long) imm_expr.X_add_number
-                         + lastpos) < limlo
-                     || ((unsigned long) imm_expr.X_add_number
-                         + lastpos) > limhi)
+                 min_range = -((OP_MASK_OFFSET_B + 1) >> 1);
+                 max_range = ((OP_MASK_OFFSET_B + 1) >> 1) - 1;
+                 if (imm_expr.X_add_number < min_range
+                     || imm_expr.X_add_number > max_range)
                    {
-                     as_bad (_("Improper extract size (%lu, position %lu)"),
-                             (unsigned long) imm_expr.X_add_number,
-                             (unsigned long) lastpos);
-                     imm_expr.X_add_number = limlo - lastpos;
+                     as_bad (_("Offset not in range %ld..%ld (%ld)"),
+                             (long) min_range, (long) max_range,
+                             (long) imm_expr.X_add_number);
                    }
-                 INSERT_OPERAND (EXTMSBD, *ip, imm_expr.X_add_number - 1);
+                 INSERT_OPERAND (OFFSET_B, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  continue;
 
-               case 'D':
-                 /* +D is for disassembly only; never match.  */
-                 break;
-
-               case 'I':
-                 /* "+I" is like "I", except that imm2_expr is used.  */
-                 my_getExpression (&imm2_expr, s);
-                 if (imm2_expr.X_op != O_big
-                     && imm2_expr.X_op != O_constant)
-                 insn_error = _("absolute expression required");
-                 if (HAVE_32BIT_GPRS)
-                   normalize_constant_expr (&imm2_expr);
+               case 'c': /* 9-bit signed offset in bit 6 */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 min_range = -((OP_MASK_OFFSET_C + 1) >> 1);
+                 max_range = ((OP_MASK_OFFSET_C + 1) >> 1) - 1;
+                 /* We check the offset range before adjusted.  */
+                 min_range <<= 4;
+                 max_range <<= 4;
+                 if (imm_expr.X_add_number < min_range
+                     || imm_expr.X_add_number > max_range)
+                   {
+                     as_bad (_("Offset not in range %ld..%ld (%ld)"),
+                             (long) min_range, (long) max_range,
+                             (long) imm_expr.X_add_number);
+                   }
+                 if (imm_expr.X_add_number & 0xf)
+                   {
+                     as_bad (_("Offset not 16 bytes alignment (%ld)"),
+                             (long) imm_expr.X_add_number);
+                   }
+                 /* Right shift 4 bits to adjust the offset operand.  */
+                 INSERT_OPERAND (OFFSET_C, *ip, imm_expr.X_add_number >> 4);
+                 imm_expr.X_op = O_absent;
                  s = expr_end;
                  continue;
 
-               case 'T': /* Coprocessor register.  */
-                 /* +T is for disassembly only; never match.  */
-                 break;
-
-               case 't': /* Coprocessor register number.  */
-                 if (s[0] == '$' && ISDIGIT (s[1]))
+               case 'z':
+                 if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
+                   break;
+                 if (regno == AT && mips_opts.at)
                    {
-                     ++s;
-                     regno = 0;
-                     do
-                       {
-                         regno *= 10;
-                         regno += *s - '0';
-                         ++s;
-                       }
-                     while (ISDIGIT (*s));
-                     if (regno > 31)
-                       as_bad (_("Invalid register number (%d)"), regno);
+                     if (mips_opts.at == ATREG)
+                       as_warn (_("used $at without \".set noat\""));
                      else
-                       {
-                         INSERT_OPERAND (RT, *ip, regno);
-                         continue;
-                       }
+                       as_warn (_("used $%u with \".set at=$%u\""),
+                                regno, mips_opts.at);
                    }
-                 else
-                   as_bad (_("Invalid coprocessor 0 register number"));
-                 break;
+                 INSERT_OPERAND (RZ, *ip, regno);
+                 continue;
+
+               case 'Z':
+                 if (!reg_lookup (&s, RTYPE_FPU, &regno))
+                   break;
+                 INSERT_OPERAND (FZ, *ip, regno);
+                 continue;
 
                default:
-                 as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
-                   *args, insn->name, insn->args);
+                 as_bad (_("Internal error: bad mips opcode "
+                           "(unknown extension operand type `+%c'): %s %s"),
+                         *args, insn->name, insn->args);
                  /* Further processing is fruitless.  */
                  return;
                }
@@ -8965,8 +9600,9 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'k':           /* cache code */
-           case 'h':           /* prefx code */
+           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)
@@ -8974,14 +9610,35 @@ do_msbd:
                         ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
              if (*args == 'k')
-               INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
-             else
+               {
+                 if (mips_fix_cn63xxp1 && strcmp ("pref", insn->name) == 0)
+                   switch (imm_expr.X_add_number)
+                     {
+                     case 5:
+                     case 25:
+                     case 26:
+                     case 27:
+                     case 28:
+                     case 29:
+                     case 30:
+                     case 31:  /* These are ok.  */
+                       break;
+
+                     default:  /* The rest must be changed to 28.  */
+                       imm_expr.X_add_number = 28;
+                       break;
+                     }
+                 INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
+               }
+             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;
 
-           case 'c':           /* break code */
+           case 'c':           /* BREAK code.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE)
@@ -8993,7 +9650,7 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'q':           /* lower break code */
+           case 'q':           /* Lower BREAK code.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE2)
@@ -9005,7 +9662,7 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'B':           /* 20-bit syscall/break code.  */
+           case 'B':           /* 20-bit SYSCALL/BREAK code.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
@@ -9017,7 +9674,7 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'C':           /* Coprocessor code */
+           case 'C':           /* Coprocessor code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_COPZ)
@@ -9031,7 +9688,7 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'J':           /* 19-bit wait code.  */
+           case 'J':           /* 19-bit WAIT code.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
@@ -9070,27 +9727,33 @@ do_msbd:
              else
                break;
 
-           case 'b':           /* base register */
-           case 'd':           /* destination register */
-           case 's':           /* source register */
-           case 't':           /* target register */
-           case 'r':           /* both target and source */
-           case 'v':           /* both dest and source */
-           case 'w':           /* both dest and target */
-           case 'E':           /* coprocessor target register */
-           case 'K':           /* 'rdhwr' destination register */
-           case 'x':           /* ignore register name */
-           case 'z':           /* must be zero register */
-           case 'U':           /* destination register (clo/clz).  */
-           case 'g':           /* coprocessor destination register */
-             s_reset = s;            
+           case 'b':           /* Base register.  */
+           case 'd':           /* Destination register.  */
+           case 's':           /* Source register.  */
+           case 't':           /* Target register.  */
+           case 'r':           /* Both target and source.  */
+           case 'v':           /* Both dest and source.  */
+           case 'w':           /* Both dest and target.  */
+           case 'E':           /* Coprocessor target register.  */
+           case 'K':           /* RDHWR destination register.  */
+           case 'x':           /* Ignore register name.  */
+           case 'z':           /* Must be zero register.  */
+           case 'U':           /* Destination register (CLO/CLZ).  */
+           case 'g':           /* Coprocessor destination register.  */
+             s_reset = s;
              if (*args == 'E' || *args == 'K')
                ok = reg_lookup (&s, RTYPE_NUM, &regno);
              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)
                {
@@ -9110,8 +9773,23 @@ do_msbd:
                  if (c == 'z' && regno != 0)
                    break;
 
-       /* Now that we have assembled one operand, we use the args string
-        * to figure out where it goes in the instruction.  */
+                 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)
                    {
                    case 'r':
@@ -9121,7 +9799,6 @@ do_msbd:
                      INSERT_OPERAND (RS, *ip, regno);
                      break;
                    case 'd':
-                   case 'G':
                    case 'K':
                    case 'g':
                      INSERT_OPERAND (RD, *ip, regno);
@@ -9150,11 +9827,6 @@ do_msbd:
                         is $0.  This only matches $0, and is checked
                         outside the switch.  */
                      break;
-                   case 'D':
-                     /* Itbl operand; not yet implemented. FIXME ?? */
-                     break;
-                     /* What about all other operands like 'i', which
-                        can be specified in the opcode table? */
                    }
                  lastregno = regno;
                  continue;
@@ -9175,7 +9847,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;
@@ -9205,10 +9877,10 @@ do_msbd:
            case 'Y':           /* MDMX source register.  */
            case 'Z':           /* MDMX target register.  */
              is_mdmx = 1;
-           case 'D':           /* floating point destination register */
-           case 'S':           /* floating point source register */
-           case 'T':           /* floating point target register */
-           case 'R':           /* floating point source register */
+           case 'D':           /* Floating point destination register.  */
+           case 'S':           /* Floating point source register.  */
+           case 'T':           /* Floating point target register.  */
+           case 'R':           /* Floating point source register.  */
            case 'V':
            case 'W':
              rtype = RTYPE_FPU;
@@ -9226,7 +9898,7 @@ do_msbd:
                {
                  if ((regno & 1) != 0
                      && HAVE_32BIT_FPRS
-                     && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
+                     && !mips_oddfpreg_ok (ip->insn_mo, argnum))
                    as_warn (_("Float register should be even, was %d"),
                             regno);
 
@@ -9266,15 +9938,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++;
                        }
@@ -9287,7 +9959,7 @@ do_msbd:
                            ip->insn_opcode |= (MDMX_FMTSEL_VEC_OB <<
                                                OP_SH_VSEL);
                        }
-                      /* Fall through */
+                      /* Fall through */
                    case 'W':
                    case 'T':
                    case 'Z':
@@ -9385,7 +10057,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'
@@ -9394,35 +10066,35 @@ do_msbd:
                            || (temp[2] == 0 && temp[3] == 0))))
                  {
                    imm_expr.X_op = O_constant;
-                   if (! target_big_endian)
+                   if (!target_big_endian)
                      imm_expr.X_add_number = bfd_getl32 (temp);
                    else
                      imm_expr.X_add_number = bfd_getb32 (temp);
                  }
                else if (length > 4
-                        && ! mips_disable_float_construction
+                        && !mips_disable_float_construction
                         /* Constants can only be constructed in GPRs and
                            copied to FPRs if the GPRs are at least as wide
                            as the FPRs.  Force the constant into memory if
                            we are using 64-bit FPRs but the GPRs are only
                            32 bits wide.  */
                         && (using_gprs
-                            || ! (HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
+                            || !(HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
                         && ((temp[0] == 0 && temp[1] == 0)
                             || (temp[2] == 0 && temp[3] == 0))
                         && ((temp[4] == 0 && temp[5] == 0)
                             || (temp[6] == 0 && temp[7] == 0)))
                  {
                    /* The value is simple enough to load with a couple of
-                       instructions.  If using 32-bit registers, set
-                       imm_expr to the high order 32 bits and offset_expr to
-                       the low order 32 bits.  Otherwise, set imm_expr to
-                       the entire 64 bit constant.  */
+                      instructions.  If using 32-bit registers, set
+                      imm_expr to the high order 32 bits and offset_expr to
+                      the low order 32 bits.  Otherwise, set imm_expr to
+                      the entire 64 bit constant.  */
                    if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
                      {
                        imm_expr.X_op = O_constant;
                        offset_expr.X_op = O_constant;
-                       if (! target_big_endian)
+                       if (!target_big_endian)
                          {
                            imm_expr.X_add_number = bfd_getl32 (temp + 4);
                            offset_expr.X_add_number = bfd_getl32 (temp);
@@ -9438,7 +10110,7 @@ do_msbd:
                    else if (sizeof (imm_expr.X_add_number) > 4)
                      {
                        imm_expr.X_op = O_constant;
-                       if (! target_big_endian)
+                       if (!target_big_endian)
                          imm_expr.X_add_number = bfd_getl64 (temp);
                        else
                          imm_expr.X_add_number = bfd_getb64 (temp);
@@ -9447,7 +10119,7 @@ do_msbd:
                      {
                        imm_expr.X_op = O_big;
                        imm_expr.X_add_number = 4;
-                       if (! target_big_endian)
+                       if (!target_big_endian)
                          {
                            generic_bignum[0] = bfd_getl16 (temp);
                            generic_bignum[1] = bfd_getl16 (temp + 2);
@@ -9483,7 +10155,7 @@ do_msbd:
                        newname = RDATA_SECTION_NAME;
                        break;
                      case 'l':
-                       assert (g_switch_value >= 4);
+                       gas_assert (g_switch_value >= 4);
                        newname = ".lit4";
                        break;
                      }
@@ -9495,7 +10167,7 @@ do_msbd:
                                              | SEC_READONLY
                                              | SEC_DATA));
                    frag_align (*args == 'l' ? 2 : 3, 0, 0);
-                   if (IS_ELF && 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);
@@ -9505,9 +10177,7 @@ do_msbd:
                    /* Set the argument to the current address in the
                       section.  */
                    offset_expr.X_op = O_symbol;
-                   offset_expr.X_add_symbol =
-                     symbol_new ("L0\001", now_seg,
-                                 (valueT) frag_now_fix (), frag_now);
+                   offset_expr.X_add_symbol = symbol_temp_new_now ();
                    offset_expr.X_add_number = 0;
 
                    /* Put the floating point number into the section.  */
@@ -9520,8 +10190,8 @@ do_msbd:
              }
              continue;
 
-           case 'i':           /* 16 bit unsigned immediate */
-           case 'j':           /* 16 bit signed immediate */
+           case 'i':           /* 16-bit unsigned immediate.  */
+           case 'j':           /* 16-bit signed immediate.  */
              *imm_reloc = BFD_RELOC_LO16;
              if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
                {
@@ -9561,13 +10231,17 @@ do_msbd:
                        break;
                      if (imm_expr.X_op == O_constant
                          || imm_expr.X_op == O_big)
-                       as_bad (_("expression out of range"));
+                       as_bad (_("Expression out of range"));
                    }
                }
              s = expr_end;
              continue;
 
-           case 'o':           /* 16 bit offset */
+           case 'o':           /* 16-bit offset.  */
+             offset_reloc[0] = BFD_RELOC_LO16;
+             offset_reloc[1] = BFD_RELOC_UNUSED;
+             offset_reloc[2] = BFD_RELOC_UNUSED;
+
              /* Check whether there is only a single bracketed expression
                 left.  If so, it must be the base register and the
                 constant must be zero.  */
@@ -9590,45 +10264,48 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'p':           /* pc relative offset */
+           case 'p':           /* PC-relative offset.  */
              *offset_reloc = BFD_RELOC_16_PCREL_S2;
              my_getExpression (&offset_expr, s);
              s = expr_end;
              continue;
 
-           case 'u':           /* upper 16 bits */
+           case 'u':           /* Upper 16 bits.  */
              if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
                  && imm_expr.X_op == O_constant
                  && (imm_expr.X_add_number < 0
                      || imm_expr.X_add_number >= 0x10000))
-               as_bad (_("lui expression not in range 0..65535"));
+               as_bad (_("lui expression (%lu) not in range 0..65535"),
+                       (unsigned long) imm_expr.X_add_number);
              s = expr_end;
              continue;
 
-           case 'a':           /* 26 bit address */
+           case 'a':           /* 26-bit address.  */
              my_getExpression (&offset_expr, s);
              s = expr_end;
              *offset_reloc = BFD_RELOC_MIPS_JMP;
              continue;
 
-           case 'N':           /* 3 bit branch condition code */
-           case 'M':           /* 3 bit compare condition code */
+           case 'N':           /* 3-bit branch condition code.  */
+           case 'M':           /* 3-bit compare condition code.  */
              rtype = RTYPE_CCC;
-             if (ip->insn_mo->pinfo & (FP_D| FP_S))
+             if (ip->insn_mo->pinfo & (FP_D | FP_S))
                rtype |= RTYPE_FCC;
              if (!reg_lookup (&s, rtype, &regno))
                break;
-             if ((strcmp(str + strlen(str) - 3, ".ps") == 0
-                  || strcmp(str + strlen(str) - 5, "any2f") == 0
-                  || strcmp(str + strlen(str) - 5, "any2t") == 0)
+             if ((strcmp (str + strlen (str) - 3, ".ps") == 0
+                  || 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);
-             if ((strcmp(str + strlen(str) - 5, "any4f") == 0
-                  || strcmp(str + strlen(str) - 5, "any4t") == 0)
+               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
@@ -9653,7 +10330,7 @@ do_msbd:
                c = 8; /* Invalid sel value.  */
 
              if (c > 7)
-               as_bad (_("invalid coprocessor sub-selection value (0-7)"));
+               as_bad (_("Invalid coprocessor sub-selection value (0-7)"));
              ip->insn_opcode |= c;
              continue;
 
@@ -9693,7 +10370,7 @@ do_msbd:
              continue;
 
            default:
-             as_bad (_("bad char = '%c'\n"), *args);
+             as_bad (_("Bad char = '%c'\n"), *args);
              internalError ();
            }
          break;
@@ -9704,12 +10381,12 @@ do_msbd:
        {
          ++insn;
          s = argsStart;
-         insn_error = _("illegal operands");
+         insn_error = _("Illegal operands");
          continue;
        }
       if (save_c)
-       *(--s) = save_c;
-      insn_error = _("illegal operands");
+       *(--argsStart) = save_c;
+      insn_error = _("Illegal operands");
       return;
     }
 }
@@ -9786,13 +10463,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]
@@ -9846,6 +10519,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;
@@ -9983,8 +10658,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:
@@ -10208,7 +10889,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')
                  {
@@ -10263,7 +10944,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                          {
                            if (!seen_framesz)
                                /* args $a0-$a3 */
-                               args |= 1 << (reg1 - 4);
+                               nargs |= 1 << (reg1 - 4);
                            else
                                /* statics $a0-$a3 */
                                statics |= 1 << (reg1 - 4);
@@ -10289,9 +10970,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)
@@ -10302,12 +10983,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.  */
@@ -10481,7 +11162,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)
@@ -10609,6 +11290,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}
 };
 
@@ -10649,7 +11332,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;
          }
@@ -10705,7 +11388,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;
 
@@ -10723,80 +11406,18 @@ static void
 my_getExpression (expressionS *ep, char *str)
 {
   char *save_in;
-  valueT val;
 
   save_in = input_line_pointer;
   input_line_pointer = str;
   expression (ep);
   expr_end = input_line_pointer;
   input_line_pointer = save_in;
-
-  /* If we are in mips16 mode, and this is an expression based on `.',
-     then we bump the value of the symbol by 1 since that is how other
-     text symbols are handled.  We don't bother to handle complex
-     expressions, just `.' plus or minus a constant.  */
-  if (mips_opts.mips16
-      && ep->X_op == O_symbol
-      && strcmp (S_GET_NAME (ep->X_add_symbol), FAKE_LABEL_NAME) == 0
-      && S_GET_SEGMENT (ep->X_add_symbol) == now_seg
-      && symbol_get_frag (ep->X_add_symbol) == frag_now
-      && symbol_constant_p (ep->X_add_symbol)
-      && (val = S_GET_VALUE (ep->X_add_symbol)) == frag_now_fix ())
-    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
@@ -10816,14 +11437,8 @@ static int support_64bit_objects(void)
 
   list = bfd_target_list ();
   for (l = list; *l != NULL; l++)
-#ifdef TE_TMIPS
-    /* This is traditional mips */
-    if (strcmp (*l, "elf64-tradbigmips") == 0
-       || strcmp (*l, "elf64-tradlittlemips") == 0)
-#else
-    if (strcmp (*l, "elf64-bigmips") == 0
-       || strcmp (*l, "elf64-littlemips") == 0)
-#endif
+    if (strcmp (*l, ELF_TARGET ("elf64-", "big")) == 0
+       || strcmp (*l, ELF_TARGET ("elf64-", "little")) == 0)
       break;
   yes = (*l != NULL);
   free (list);
@@ -10833,164 +11448,196 @@ 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_LOONGSON2F_JUMP,
+    OPTION_NO_FIX_LOONGSON2F_JUMP,
+    OPTION_FIX_LOONGSON2F_NOP,
+    OPTION_NO_FIX_LOONGSON2F_NOP,
+    OPTION_FIX_VR4120,
+    OPTION_NO_FIX_VR4120,
+    OPTION_FIX_VR4130,
+    OPTION_NO_FIX_VR4130,
+    OPTION_FIX_CN63XXP1,
+    OPTION_NO_FIX_CN63XXP1,
+    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},
-#define OPTION_DSPR2 (OPTION_ASE_BASE + 12)
   {"mdspr2", no_argument, NULL, OPTION_DSPR2},
-#define OPTION_NO_DSPR2 (OPTION_ASE_BASE + 13)
   {"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 + 14)
-#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-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
+  {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
+  {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
+  {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
   {"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},
+  {"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
+  {"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
 
   /* 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 */
 
@@ -11045,7 +11692,11 @@ md_parse_option (int c, char *arg)
       break;
 
     case 'O':
-      if (arg && arg[0] == '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;
@@ -11196,6 +11847,30 @@ 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_LOONGSON2F_JUMP:
+      mips_fix_loongson2f_jump = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON2F_JUMP:
+      mips_fix_loongson2f_jump = FALSE;
+      break;
+
+    case OPTION_FIX_LOONGSON2F_NOP:
+      mips_fix_loongson2f_nop = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON2F_NOP:
+      mips_fix_loongson2f_nop = FALSE;
+      break;
+
     case OPTION_FIX_VR4120:
       mips_fix_vr4120 = 1;
       break;
@@ -11212,6 +11887,14 @@ md_parse_option (int c, char *arg)
       mips_fix_vr4130 = 0;
       break;
 
+    case OPTION_FIX_CN63XXP1:
+      mips_fix_cn63xxp1 = TRUE;
+      break;
+
+    case OPTION_NO_FIX_CN63XXP1:
+      mips_fix_cn63xxp1 = FALSE;
+      break;
+
     case OPTION_RELAX_BRANCH:
       mips_relax_branch = 1;
       break;
@@ -11250,6 +11933,16 @@ 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 (!IS_ELF)
        {
@@ -11273,18 +11966,16 @@ 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 (!IS_ELF)
-       {
-         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 (!IS_ELF)
        {
@@ -11322,6 +12013,22 @@ 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 (!IS_ELF)
@@ -11386,6 +12093,8 @@ md_parse_option (int c, char *arg)
       return 0;
     }
 
+    mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump;
+
   return 1;
 }
 \f
@@ -11462,7 +12171,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);
@@ -11565,14 +12274,14 @@ 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)
     {
@@ -11580,17 +12289,16 @@ mips_after_parse_args (void)
       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);
+    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;
   file_ase_mips3d = mips_opts.ase_mips3d;
   file_ase_mdmx = mips_opts.ase_mdmx;
   file_ase_smartmips = mips_opts.ase_smartmips;
@@ -11599,6 +12307,8 @@ mips_after_parse_args (void)
   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)
     {
@@ -11708,6 +12418,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)
     {
@@ -11715,11 +12426,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;
 
@@ -11737,14 +12448,15 @@ 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)
-             && (*pos)->fx_addsy == l->fixp->fx_addsy
+         if ((*pos)->fx_r_type == looking_for_rtype
+             && symbol_same_p ((*pos)->fx_addsy, l->fixp->fx_addsy)
              && (*pos)->fx_offset >= l->fixp->fx_offset
              && (lo_pos == NULL
                  || (*pos)->fx_offset < (*lo_pos)->fx_offset
@@ -11789,8 +12501,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;
@@ -11810,18 +12522,18 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   if (! howto)
     return;
 
-  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_MIPS_TLS_DTPREL64);
+  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_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:
@@ -11878,6 +12590,8 @@ 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:
     case BFD_RELOC_MIPS16_JMP:
@@ -12022,18 +12736,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 ());
     }
@@ -12045,9 +12767,8 @@ mips_align (int to, int fill, symbolS *label)
 static void
 s_align (int x ATTRIBUTE_UNUSED)
 {
-  int temp;
-  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
        to the aligned address.
@@ -12068,17 +12789,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, l != NULL ? l->label : NULL);
+      mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
     }
   else
     {
@@ -12105,6 +12827,7 @@ s_change_sec (int sec)
 #endif
 
   mips_emit_delays ();
+
   switch (sec)
     {
     case 't':
@@ -12126,7 +12849,7 @@ s_change_sec (int sec)
          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 ();
@@ -12138,7 +12861,18 @@ s_change_sec (int sec)
        {
          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 ();
+      break;
+
+    case 'B':
+      seg = subseg_new (".sbss", (subsegT) get_absolute_expression ());
+      if (IS_ELF)
+       {
+         bfd_set_section_flags (stdoutput, seg, SEC_ALLOC);
+         if (strncmp (TARGET_OS, "elf", 3) != 0)
            record_alignment (seg, 4);
        }
       demand_empty_rest_of_line ();
@@ -12196,6 +12930,8 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
     section_alignment = get_absolute_expression ();
   else
     section_alignment = 0;
+  /* FIXME: really ignore?  */
+  (void) section_alignment;
 
   section_name = xstrdup (section_name);
 
@@ -12240,8 +12976,8 @@ s_cons (int log_size)
   mips_emit_delays ();
   if (log_size > 0 && auto_align)
     mips_align (log_size, 0, label);
-  mips_clear_insn_labels ();
   cons (1 << log_size);
+  mips_clear_insn_labels ();
 }
 
 static void
@@ -12263,9 +12999,8 @@ s_float_cons (int type)
        mips_align (2, 0, label);
     }
 
-  mips_clear_insn_labels ();
-
   float_cons (type);
+  mips_clear_insn_labels ();
 }
 
 /* Handle .globl.  We need to override it because on Irix 5 you are
@@ -12404,13 +13139,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)
     {
@@ -12445,7 +13187,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;
     }
@@ -12456,10 +13198,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;
@@ -12469,7 +13219,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;
     }
@@ -12486,7 +13236,7 @@ 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;
@@ -12499,7 +13249,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "dspr2") == 0)
     {
       if (!ISA_SUPPORTS_DSPR2_ASE)
-       as_warn ("%s ISA does not support DSP R2 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;
@@ -12512,7 +13262,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   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;
     }
@@ -13015,9 +13765,9 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
   mips_emit_delays ();
   if (auto_align)
     mips_align (2, 0, label);
-  mips_clear_insn_labels ();
 
   expression (&ex);
+  mips_clear_insn_labels ();
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
@@ -13055,9 +13805,9 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
   mips_emit_delays ();
   if (auto_align)
     mips_align (3, 0, label);
-  mips_clear_insn_labels ();
 
   expression (&ex);
+  mips_clear_insn_labels ();
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
@@ -13155,7 +13905,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;
@@ -13170,7 +13920,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;
        }
@@ -13212,7 +13962,7 @@ md_section_align (asection *seg, valueT addr)
         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)
+      if (strncmp (TARGET_OS, "elf", 3) == 0)
         return addr;
       if (align > 4)
         align = 4;
@@ -13277,7 +14027,7 @@ 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
@@ -13354,7 +14104,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)
@@ -13565,7 +14315,8 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update)
 
   if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
     fragp->fr_subtype
-      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_UNCOND (fragp->fr_subtype),
+      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype),
+                            RELAX_BRANCH_UNCOND (fragp->fr_subtype),
                             RELAX_BRANCH_LIKELY (fragp->fr_subtype),
                             RELAX_BRANCH_LINK (fragp->fr_subtype),
                             toofar);
@@ -13662,13 +14413,20 @@ 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.
+     Likewise an in-range offset of PC-relative relocations may overflow
+     the in-place relocatable field if recalculated against the start
+     address of the symbol's containing section.  */
+  if (HAVE_IN_PLACE_ADDENDS
+      && (fixp->fx_pcrel || fixp->fx_r_type == BFD_RELOC_MIPS_JALR))
+    return 0;
+
 #ifdef OBJ_ELF
   /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
      to a floating-point stub.  The same is true for non-R_MIPS16_26
@@ -13712,7 +14470,7 @@ mips_fix_adjustable (fixS *fixp)
      that we have for MIPS16 symbols.  */
   if (IS_ELF
       && fixp->fx_subsy == NULL
-      && (S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
+      && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
          || *symbol_get_tc (fixp->fx_addsy)))
     return 0;
 #endif
@@ -13738,7 +14496,7 @@ 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.  */
@@ -13854,7 +14612,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          int i;
 
          as_warn_where (fragp->fr_file, fragp->fr_line,
-                        _("relaxed out-of-range branch into a jump"));
+                        _("Relaxed out-of-range branch into a jump"));
 
          if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
            goto uncond;
@@ -13868,14 +14626,14 @@ 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);
+                 gas_assert ((insn & 0xfc0e0000) == 0x04000000);
                  insn ^= 0x00010000;
                  break;
 
@@ -13893,7 +14651,7 @@ 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  */
@@ -13968,8 +14726,11 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
            }
          else
            {
+             unsigned long at = RELAX_BRANCH_AT (fragp->fr_subtype);
+
              /* lw/ld $at, <sym>($gp)  R_MIPS_GOT16 */
-             insn = HAVE_64BIT_ADDRESSES ? 0xdf810000 : 0x8f810000;
+             insn = HAVE_64BIT_ADDRESSES ? 0xdf800000 : 0x8f800000;
+             insn |= at << OP_SH_RT;
              exp.X_op = O_symbol;
              exp.X_add_symbol = fragp->fr_symbol;
              exp.X_add_number = fragp->fr_offset;
@@ -13996,7 +14757,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                }
 
              /* d/addiu $at, $at, <sym>  R_MIPS_LO16 */
-             insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
+             insn = HAVE_64BIT_ADDRESSES ? 0x64000000 : 0x24000000;
+             insn |= at << OP_SH_RS | at << OP_SH_RT;
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
                                  4, &exp, FALSE, BFD_RELOC_LO16);
@@ -14008,16 +14770,17 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
 
              /* j(al)r $at.  */
              if (RELAX_BRANCH_LINK (fragp->fr_subtype))
-               insn = 0x0020f809;
+               insn = 0x0000f809;
              else
-               insn = 0x00200008;
+               insn = 0x00000008;
+             insn |= at << OP_SH_RS;
 
              md_number_to_chars ((char *) buf, insn, 4);
              buf += 4;
            }
        }
 
-      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;
@@ -14052,8 +14815,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          ext = FALSE;
        }
 
-      resolve_symbol_value (fragp->fr_symbol);
-      val = S_GET_VALUE (fragp->fr_symbol);
+      val = resolve_symbol_value (fragp->fr_symbol);
       if (op->pcrel)
        {
          addressT addr;
@@ -14129,7 +14891,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
@@ -14189,7 +14951,7 @@ mips_frob_file_after_relocs (void)
   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;
@@ -14203,12 +14965,14 @@ mips_frob_file_after_relocs (void)
 
 #endif
 
-/* This function is called whenever a label is defined.  It is used
-   when handling branch delays; if a branch has a label, we assume we
-   can not move it.  */
+/* This function is called whenever a label is defined, including fake
+   labels instantiated off the dot special symbol.  It is used when
+   handling branch delays; if a branch has a label, we assume we cannot
+   move it.  This also bumps the value of the symbol by 1 in compressed
+   code.  */
 
 void
-mips_define_label (symbolS *sym)
+mips_record_label (symbolS *sym)
 {
   segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l;
@@ -14224,7 +14988,15 @@ mips_define_label (symbolS *sym)
   l->label = sym;
   l->next = si->label_list;
   si->label_list = l;
+}
 
+/* This function is called as tc_frob_label() whenever a label is defined
+   and adds a DWARF-2 record we only want for true labels.  */
+
+void
+mips_define_label (symbolS *sym)
+{
+  mips_record_label (sym);
 #ifdef OBJ_ELF
   dwarf2_emit_label (sym);
 #endif
@@ -14342,36 +15114,53 @@ 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;
+  int bytes, size, excess;
+  valueT opcode;
+
   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++;
-       }
+      opcode = mips16_nop_insn.insn_opcode;
+      size = 2;
+    }
+  else
+    {
+      opcode = nop_insn.insn_opcode;
+      size = 4;
+    }
 
-      memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
-      fragp->fr_var = 2;
+  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+  excess = bytes % size;
+  if (excess != 0)
+    {
+      /* If we're not inserting a whole number of instructions,
+        pad the end of the fixed part of the frag with zeros.  */
+      memset (p, 0, excess);
+      p += excess;
+      fragp->fr_fix += excess;
     }
 
-  /* For mips32, a nop is a zero, which we trivially get by doing nothing.  */
+  md_number_to_chars (p, opcode, size);
+  fragp->fr_var = size;
 }
 
 static void
@@ -14511,7 +15300,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."));
 
@@ -14543,17 +15332,14 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
     {
       segT saved_seg = now_seg;
       subsegT saved_subseg = now_subseg;
-      valueT dot;
       expressionS exp;
       char *fragp;
 
-      dot = frag_now_fix ();
-
 #ifdef md_flush_pending_output
       md_flush_pending_output ();
 #endif
 
-      assert (pdr_seg);
+      gas_assert (pdr_seg);
       subseg_set (pdr_seg, 0);
 
       /* Write the symbol.  */
@@ -14611,8 +15397,6 @@ s_mips_ent (int aent)
 
       cur_proc_ptr->func_sym = symbolP;
 
-      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
-
       ++numprocs;
 
       if (debug_type == DEBUG_STABS)
@@ -14620,6 +15404,8 @@ s_mips_ent (int aent)
                                 S_GET_NAME (symbolP));
     }
 
+  symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
   demand_empty_rest_of_line ();
 }
 
@@ -14754,11 +15540,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 },
@@ -14828,6 +15619,15 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
                                                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 },
@@ -14835,14 +15635,22 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "20kc",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
   { "25kf",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
 
-  /* MIPS 64 Release 2 */
-
   /* 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 },
+  
+  { "loongson3a",     0,                       ISA_MIPS64,     CPU_LOONGSON_3A },
+
+  /* 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 }
@@ -14944,7 +15752,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;
 }
 
@@ -15063,21 +15871,32 @@ MIPS options:\n\
 -mmt                   generate MT instructions\n\
 -mno-mt                        do not generate MT instructions\n"));
   fprintf (stream, _("\
+-mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
+-mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
 -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\
+-mfix-cn63xxp1         work around CN63XXP1 PREF errata\n\
 -mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
 -mfp32                 use 32-bit FPRs, regardless of the chosen ISA\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\
+-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 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\
@@ -15101,25 +15920,21 @@ MIPS options:\n\
 #endif
 }
 
+#ifdef TE_IRIX
 enum dwarf2_format
-mips_dwarf2_format (void)
+mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
 {
-  if (mips_abi == N64_ABI)
-    {
-#ifdef TE_IRIX
-      return dwarf2_format_64bit_irix;
-#else
-      return dwarf2_format_64bit;
-#endif
-    }
+  if (HAVE_64BIT_SYMBOLS)
+    return dwarf2_format_64bit_irix;
   else
     return dwarf2_format_32bit;
 }
+#endif
 
 int
 mips_dwarf2_addr_size (void)
 {
-  if (mips_abi == N64_ABI)
+  if (HAVE_64BIT_OBJECTS)
     return 8;
   else
     return 4;
This page took 0.112485 seconds and 4 git commands to generate.