gas/
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index bf26235b84a82f01bc79e4c4dff245548620926c..345d6d0df4ca298f9c29a0315042590f5547c90a 100644 (file)
@@ -156,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.  */
@@ -282,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              \
@@ -919,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
@@ -1072,9 +1076,6 @@ 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
@@ -1238,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
@@ -1308,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)
 {
@@ -1324,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;
@@ -1380,6 +1387,7 @@ 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.  */
@@ -2103,6 +2111,7 @@ md_begin (void)
 void
 md_mips_end (void)
 {
+  mips_emit_delays ();
   if (! ECOFF_DEBUGGING)
     md_obj_end ();
 }
@@ -2234,78 +2243,6 @@ fixup_has_matching_lo_p (fixS *fixp)
          && 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 regclass)
-{
-  if (regclass == MIPS16_REG)
-    {
-      gas_assert (mips_opts.mips16);
-      reg = mips16_to_32_reg_map[reg];
-      regclass = MIPS_GR_REG;
-    }
-
-  /* Don't report on general register ZERO, since it never changes.  */
-  if (regclass == MIPS_GR_REG && reg == ZERO)
-    return 0;
-
-  if (regclass == MIPS_FP_REG)
-    {
-      gas_assert (! mips_opts.mips16);
-      /* If we are called with either $f0 or $f1, we must check $f0.
-        This is not optimal, because it will introduce an unnecessary
-        NOP between "lwc1 $f0" and "swc1 $f1".  To fix this we would
-        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.  */
 
@@ -2458,6 +2395,149 @@ relax_end (void)
   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.  */
@@ -2492,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.  */
@@ -2517,7 +2598,7 @@ 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
@@ -2564,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;
        }
 
@@ -2582,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)
+         mask = fpr_write_mask (insn1);
+         if (mask != 0)
            {
-             if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
-               return 1;
-           }
-         else if (pinfo1 & INSN_WRITE_FPR_S)
-           {
-             if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
+             if (!insn2 || (mask & fpr_read_mask (insn2)) != 0)
                return 1;
            }
          else
@@ -2619,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 HIST.  */
+   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 *hist,
+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.  */
@@ -2647,38 +2726,227 @@ nops_for_vr4130 (const struct mips_cl_insn *hist,
     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, hist[i])];
-       else
-         reg = EXTRACT_OPERAND (RD, hist[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 (&hist[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;
 }
 
+#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
+fix_24k_align_to (const struct mips_opcode *mo)
+{
+  if (strcmp (mo->name, "sh") == 0)
+    return 2;
+
+  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 (strcmp (mo->name, "sdc1") == 0
+      || strcmp (mo->name, "sdc2") == 0
+      || strcmp (mo->name, "s.d") == 0)
+    return 8;
+
+  /* sb, swl, swr */
+  return 1;
+}
+
+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
+fix_24k_sort (const void *a, const void *b)
+{
+  const struct fix_24k_store_info *pos1 = a;
+  const struct fix_24k_store_info *pos2 = b;
+
+  return (pos1->off - pos2->off);
+}
+
+/* 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_24k (int ignore, const struct mips_cl_insn *hist,
+             const struct mips_cl_insn *insn)
+{
+  struct fix_24k_store_info pos[3];
+  int align, i, base_offset;
+
+  if (ignore >= 2)
+    return 0;
+
+  /* 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;
+
+  /* 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.  If INSN is null,
-   return the worse-case number of nops for any instruction.  */
+   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 (const struct mips_cl_insn *hist,
+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 = 0; i < MAX_DELAY_NOPS; i++)
+  for (i = ignore; i < MAX_DELAY_NOPS; i++)
     {
       tmp_nops = insns_between (hist + i, insn) - i;
       if (tmp_nops > nops)
@@ -2687,7 +2955,14 @@ nops_for_insn (const struct mips_cl_insn *hist,
 
   if (mips_fix_vr4130)
     {
-      tmp_nops = nops_for_vr4130 (hist, insn);
+      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;
     }
@@ -2697,10 +2972,12 @@ nops_for_insn (const struct mips_cl_insn *hist,
 
 /* 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.  */
+   would be needed after the extended sequence, ignoring hazards
+   in the first IGNORE instructions.  */
 
 static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
+nops_for_sequence (int num_insns, int ignore,
+                  const struct mips_cl_insn *hist, ...)
 {
   va_list args;
   struct mips_cl_insn buffer[MAX_NOPS];
@@ -2713,7 +2990,7 @@ nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
   while (cursor > buffer)
     *--cursor = *va_arg (args, const struct mips_cl_insn *);
 
-  nops = nops_for_insn (buffer, NULL);
+  nops = nops_for_insn (ignore, buffer, NULL);
   va_end (args);
   return nops;
 }
@@ -2722,17 +2999,18 @@ nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
    worst-case delay for the branch target.  */
 
 static int
-nops_for_insn_or_target (const struct mips_cl_insn *hist,
+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 (hist, insn);
+  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, hist, insn, NOP_INSN);
+      tmp_nops = nops_for_sequence (2, ignore ? ignore + 2 : 0,
+                                   hist, insn, NOP_INSN);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
@@ -2740,7 +3018,7 @@ nops_for_insn_or_target (const struct mips_cl_insn *hist,
           && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
                                       | MIPS16_INSN_COND_BRANCH)))
     {
-      tmp_nops = nops_for_sequence (1, hist, insn);
+      tmp_nops = nops_for_sequence (1, ignore ? ignore + 1 : 0, hist, insn);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
@@ -2804,6 +3082,7 @@ 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);
@@ -2814,8 +3093,88 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   /* 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)
     {
@@ -2827,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;
@@ -2865,8 +3224,12 @@ 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);
+      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.  */
@@ -2914,6 +3277,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
         out that the branch was out-of-range, we'll get an error.  */
       && !mips_opts.warn_about_macros
       && (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;
@@ -2923,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),
@@ -2985,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;
@@ -3153,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)
     {
@@ -3247,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)
@@ -3445,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)
@@ -3473,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)
@@ -3768,33 +3960,29 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case 'i':
        case 'j':
-       case 'o':
          macro_read_relocs (&args, r);
          gas_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);
+                     || *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);
          continue;
 
        case 'u':
          macro_read_relocs (&args, r);
          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))));
+                     && (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':
@@ -4830,9 +5018,9 @@ macro (struct mips_cl_insn *ip)
 
   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;
@@ -4855,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);
@@ -4940,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;
@@ -4961,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;
@@ -4984,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)
        {
@@ -5004,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)
@@ -5050,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:
@@ -5061,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:
@@ -5075,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"));
@@ -5090,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:
@@ -5113,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:
@@ -5122,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:
@@ -5147,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:
@@ -5185,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:
@@ -5194,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:
@@ -5210,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"));
@@ -5225,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:
@@ -5248,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:
@@ -5259,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;
          }
 
@@ -5311,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;
          }
 
@@ -5378,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;
@@ -5387,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);
        }
@@ -5424,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.  */
@@ -5475,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;
@@ -5485,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
@@ -5497,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;
        }
 
@@ -5526,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.  */
@@ -5535,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
@@ -5561,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
@@ -5586,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;
        }
 
@@ -5674,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);
@@ -6150,37 +6339,32 @@ macro (struct mips_cl_insn *ip)
        unsigned long temp = (treg << 16) | (0x01);
        macro_build (NULL, "c2", "C", temp);
       }
-      /* AT is not used, just return */
-      return;
+      break;
 
     case M_MSGLD:
       {
        unsigned long temp = (0x02);
        macro_build (NULL, "c2", "C", temp);
       }
-      /* AT is not used, just return */
-      return;
+      break;
 
     case M_MSGLD_T:
       {
        unsigned long temp = (treg << 16) | (0x02);
        macro_build (NULL, "c2", "C", temp);
       }
-      /* AT is not used, just return */
-      return;
+      break;
 
     case M_MSGWAIT:
       macro_build (NULL, "c2", "C", 3);
-      /* AT is not used, just return */
-      return;
+      break;
 
     case M_MSGWAIT_T:
       {
        unsigned long temp = (treg << 16) | 0x03;
        macro_build (NULL, "c2", "C", temp);
       }
-      /* AT is not used, just return */
-      return;
+      break;
 
     case M_J_A:
       /* The j instruction may not be used in PIC code, since it
@@ -6213,13 +6397,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.  */
@@ -6273,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)",
@@ -6310,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,
@@ -6348,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.  */
@@ -6506,6 +6690,9 @@ 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:
       s = "sdc1";
       coproc = 1;
@@ -6534,7 +6721,7 @@ macro (struct mips_cl_insn *ip)
          && 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"),
+         as_bad (_("Opcode not supported on this processor: %s"),
                  mips_cpu_info_from_arch (mips_opts.arch)->name);
          break;
        }
@@ -6547,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)";
@@ -6557,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;
        }
 
@@ -6574,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)
        {
@@ -6903,10 +7095,10 @@ macro (struct mips_cl_insn *ip)
       else
        {
          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);
+                     && 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;
@@ -7018,7 +7210,7 @@ macro (struct mips_cl_insn *ip)
        }
 
       gas_assert (offset_expr.X_op == O_symbol
-             && offset_expr.X_add_number == 0);
+                 && offset_expr.X_add_number == 0);
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
        {
@@ -7071,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
@@ -7133,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;
        }
 
@@ -7150,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)
@@ -7203,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);
@@ -7372,12 +7555,15 @@ macro (struct mips_cl_insn *ip)
     case M_SD_OB:
       s = HAVE_64BIT_GPRS ? "sd" : "sw";
     sd_ob:
-      macro_build (&offset_expr, s, "t,o(b)", treg, 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,
-                      BFD_RELOC_LO16, breg);
+                      -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+                      breg);
        }
       break;
 
@@ -7427,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.at && used_at)
-    as_bad (_("Macro used $at after \".set noat\""));
-}
-
-static void
-macro2 (struct mips_cl_insn *ip)
-{
-  unsigned int treg, sreg, dreg, breg;
-  unsigned 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:
@@ -7530,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 ();
@@ -7556,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 ();
@@ -7584,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);
@@ -7607,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);
@@ -7677,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);
@@ -7690,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);
@@ -7752,17 +7878,6 @@ macro2 (struct mips_cl_insn *ip)
       }
       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_SEQ:
       if (sreg == 0)
        macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
@@ -8081,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;
@@ -8105,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
@@ -8113,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.  */
@@ -8144,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;
@@ -8178,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);
@@ -8201,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;
@@ -8226,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;
@@ -8243,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;
@@ -8552,6 +8667,11 @@ validate_mips_insn (const struct mips_opcode *opc)
          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"),
@@ -8717,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;
@@ -8763,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;
        }
 
@@ -8771,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;
        }
     }
@@ -8826,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
@@ -8840,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)
@@ -8853,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)
@@ -8866,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)
@@ -8879,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)
@@ -8892,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')
                {
@@ -8905,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)
@@ -8919,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')
                {
@@ -8932,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);
@@ -8949,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)
@@ -8963,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);
@@ -8980,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);
@@ -9019,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')
                {
@@ -9032,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')
                {
@@ -9077,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.  */
-             gas_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)
@@ -9111,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);
@@ -9119,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;
@@ -9128,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
@@ -9152,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
@@ -9188,7 +9307,7 @@ do_msb:
                  limlo = 33;
                  limhi = 64;
                  goto do_msbd;
-do_msbd:
+               do_msbd:
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  /* Check for negative input so that small negative numbers
@@ -9364,9 +9483,90 @@ do_msbd:
                  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);
+                 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 (_("Offset not in range %ld..%ld (%ld)"),
+                             (long) min_range, (long) max_range,
+                             (long) imm_expr.X_add_number);
+                   }
+                 INSERT_OPERAND (OFFSET_B, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               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 'z':
+                 if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
+                   break;
+                 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);
+                   }
+                 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;
                }
@@ -9400,9 +9600,9 @@ do_msbd:
              s = expr_end;
              continue;
 
-           case 'k':           /* cache code */
-           case 'h':           /* prefx code */
-           case '1':           /* sync type */
+           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)
@@ -9438,7 +9638,7 @@ do_msbd:
              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)
@@ -9450,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)
@@ -9462,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)
@@ -9474,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)
@@ -9488,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)
@@ -9527,20 +9727,20 @@ 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
@@ -9549,9 +9749,9 @@ do_msbd:
                  if (regno == AT && mips_opts.at)
                    {
                      if (mips_opts.at == ATREG)
-                       as_warn (_("used $at without \".set noat\""));
+                       as_warn (_("Used $at without \".set noat\""));
                      else
-                       as_warn (_("used $%u with \".set at=$%u\""),
+                       as_warn (_("Used $%u with \".set at=$%u\""),
                                 regno, mips_opts.at);
                    }
                }
@@ -9576,18 +9776,20 @@ do_msbd:
                  if (c == 's' && !strncmp (ip->insn_mo->name, "jalr", 4))
                    {
                      if (regno == lastregno)
-                       {
-                         insn_error = _("source and destination must be different");
+                       {
+                         insn_error
+                           = _("Source and destination must be different");
                          continue;
-                       }
+                       }
                      if (regno == 31 && lastregno == 0xffffffff)
-                       {
-                         insn_error = _("a destination register must be supplied");
+                       {
+                         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.  */
+                 /* 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':
@@ -9597,7 +9799,6 @@ do_msbd:
                      INSERT_OPERAND (RS, *ip, regno);
                      break;
                    case 'd':
-                   case 'G':
                    case 'K':
                    case 'g':
                      INSERT_OPERAND (RD, *ip, regno);
@@ -9626,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;
@@ -9681,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;
@@ -9702,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);
 
@@ -9763,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':
@@ -9870,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);
@@ -9914,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);
@@ -9923,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);
@@ -9994,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)
                {
@@ -10035,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.  */
@@ -10064,44 +10264,47 @@ 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"),
+               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)
+             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"),
+               as_warn (_("Condition code register should be 0 or 4 for %s, "
+                          "was %d"),
                         str, regno);
              if (*args == 'N')
                INSERT_OPERAND (BCC, *ip, regno);
@@ -10127,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;
 
@@ -10167,7 +10370,7 @@ do_msbd:
              continue;
 
            default:
-             as_bad (_("bad char = '%c'\n"), *args);
+             as_bad (_("Bad char = '%c'\n"), *args);
              internalError ();
            }
          break;
@@ -10178,12 +10381,12 @@ do_msbd:
        {
          ++insn;
          s = argsStart;
-         insn_error = _("illegal operands");
+         insn_error = _("Illegal operands");
          continue;
        }
       if (save_c)
        *(--argsStart) = save_c;
-      insn_error = _("illegal operands");
+      insn_error = _("Illegal operands");
       return;
     }
 }
@@ -11203,26 +11406,12 @@ 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);
 }
 
 char *
@@ -11248,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);
@@ -12116,7 +12299,6 @@ mips_after_parse_args (void)
             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;
@@ -12341,13 +12523,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     return;
 
   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);
+             || 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);
 
@@ -12794,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
@@ -12817,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
@@ -13584,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)
     {
@@ -13624,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)
     {
@@ -14134,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);
@@ -14237,8 +14419,12 @@ mips_fix_adjustable (fixS *fixp)
       && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
     return 0;
 
-  /* There is no place to store an in-place offset for JALR relocations.  */
-  if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+  /* 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
@@ -14426,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;
@@ -14540,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;
@@ -14568,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);
@@ -14580,9 +14770,10 @@ 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;
@@ -14624,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;
@@ -14775,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;
@@ -14796,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
@@ -15441,6 +15641,8 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   /* 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 */
 
This page took 0.072346 seconds and 4 git commands to generate.