2013-09-12 Chao-ying Fu <Chao-ying.Fu@imgtec.com>
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 73b7b4e774c6d1c8c52b499ed483f294091b47ca..ff1c610d605d0aef54f876a8cabcc6677c8f5a4d 100644 (file)
@@ -630,7 +630,43 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
    but nothing is ideal around here.
  */
 
-static char *insn_error;
+/* Types of printf format used for instruction-related error messages.
+   "I" means int ("%d") and "S" means string ("%s"). */
+enum mips_insn_error_format {
+  ERR_FMT_PLAIN,
+  ERR_FMT_I,
+  ERR_FMT_SS,
+};
+
+/* Information about an error that was found while assembling the current
+   instruction.  */
+struct mips_insn_error {
+  /* We sometimes need to match an instruction against more than one
+     opcode table entry.  Errors found during this matching are reported
+     against a particular syntactic argument rather than against the
+     instruction as a whole.  We grade these messages so that errors
+     against argument N have a greater priority than an error against
+     any argument < N, since the former implies that arguments up to N
+     were acceptable and that the opcode entry was therefore a closer match.
+     If several matches report an error against the same argument,
+     we only use that error if it is the same in all cases.
+
+     min_argnum is the minimum argument number for which an error message
+     should be accepted.  It is 0 if MSG is against the instruction as
+     a whole.  */
+  int min_argnum;
+
+  /* The printf()-style message, including its format and arguments.  */
+  enum mips_insn_error_format format;
+  const char *msg;
+  union {
+    int i;
+    const char *ss[2];
+  } u;
+};
+
+/* The error that should be reported for the current instruction.  */
+static struct mips_insn_error insn_error;
 
 static int auto_align = 1;
 
@@ -690,7 +726,7 @@ static int mips_debug = 0;
 static struct mips_cl_insn history[1 + MAX_NOPS];
 
 /* Arrays of operands for each instruction.  */
-#define MAX_OPERANDS 5
+#define MAX_OPERANDS 6
 struct mips_operand_array {
   const struct mips_operand *operand[MAX_OPERANDS];
 };
@@ -1726,11 +1762,10 @@ mips_mark_labels (void)
 \f
 static char *expr_end;
 
-/* Expressions which appear in macro instructions.  These are set by
-   mips_ip and read by macro.  */
+/* An expression in a macro instruction.  This is set by mips_ip and
+   mips16_ip and when populated is always an O_constant.  */
 
 static expressionS imm_expr;
-static expressionS imm2_expr;
 
 /* The relocatable field in an instruction and the relocs associated
    with it.  These variables are used for instructions like LUI and
@@ -1850,10 +1885,10 @@ mips_check_isa_supports_ase (const struct mips_ase *ase)
       base = mips_opts.micromips ? "microMIPS" : "MIPS";
       size = ISA_HAS_64BIT_REGS (mips_opts.isa) ? 64 : 32;
       if (min_rev < 0)
-       as_warn (_("The %d-bit %s architecture does not support the"
+       as_warn (_("the %d-bit %s architecture does not support the"
                   " `%s' extension"), size, base, ase->name);
       else
-       as_warn (_("The `%s' extension requires %s%d revision %d or greater"),
+       as_warn (_("the `%s' extension requires %s%d revision %d or greater"),
                 ase->name, base, size, min_rev);
     }
   if ((ase->flags & FP64_ASES)
@@ -1861,7 +1896,7 @@ mips_check_isa_supports_ase (const struct mips_ase *ase)
       && (warned_fp32 & ase->flags) != ase->flags)
     {
       warned_fp32 |= ase->flags;
-      as_warn (_("The `%s' extension requires 64-bit FPRs"), ase->name);
+      as_warn (_("the `%s' extension requires 64-bit FPRs"), ase->name);
     }
 }
 
@@ -2157,6 +2192,111 @@ insert_into_history (unsigned int first, unsigned int n,
     }
 }
 
+/* Clear the error in insn_error.  */
+
+static void
+clear_insn_error (void)
+{
+  memset (&insn_error, 0, sizeof (insn_error));
+}
+
+/* Possibly record error message MSG for the current instruction.
+   If the error is about a particular argument, ARGNUM is the 1-based
+   number of that argument, otherwise it is 0.  FORMAT is the format
+   of MSG.  Return true if MSG was used, false if the current message
+   was kept.  */
+
+static bfd_boolean
+set_insn_error_format (int argnum, enum mips_insn_error_format format,
+                      const char *msg)
+{
+  if (argnum == 0)
+    {
+      /* Give priority to errors against specific arguments, and to
+        the first whole-instruction message.  */
+      if (insn_error.msg)
+       return FALSE;
+    }
+  else
+    {
+      /* Keep insn_error if it is against a later argument.  */
+      if (argnum < insn_error.min_argnum)
+       return FALSE;
+
+      /* If both errors are against the same argument but are different,
+        give up on reporting a specific error for this argument.
+        See the comment about mips_insn_error for details.  */
+      if (argnum == insn_error.min_argnum
+         && insn_error.msg
+         && strcmp (insn_error.msg, msg) != 0)
+       {
+         insn_error.msg = 0;
+         insn_error.min_argnum += 1;
+         return FALSE;
+       }
+    }
+  insn_error.min_argnum = argnum;
+  insn_error.format = format;
+  insn_error.msg = msg;
+  return TRUE;
+}
+
+/* Record an instruction error with no % format fields.  ARGNUM and MSG are
+   as for set_insn_error_format.  */
+
+static void
+set_insn_error (int argnum, const char *msg)
+{
+  set_insn_error_format (argnum, ERR_FMT_PLAIN, msg);
+}
+
+/* Record an instruction error with one %d field I.  ARGNUM and MSG are
+   as for set_insn_error_format.  */
+
+static void
+set_insn_error_i (int argnum, const char *msg, int i)
+{
+  if (set_insn_error_format (argnum, ERR_FMT_I, msg))
+    insn_error.u.i = i;
+}
+
+/* Record an instruction error with two %s fields S1 and S2.  ARGNUM and MSG
+   are as for set_insn_error_format.  */
+
+static void
+set_insn_error_ss (int argnum, const char *msg, const char *s1, const char *s2)
+{
+  if (set_insn_error_format (argnum, ERR_FMT_SS, msg))
+    {
+      insn_error.u.ss[0] = s1;
+      insn_error.u.ss[1] = s2;
+    }
+}
+
+/* Report the error in insn_error, which is against assembly code STR.  */
+
+static void
+report_insn_error (const char *str)
+{
+  const char *msg;
+
+  msg = ACONCAT ((insn_error.msg, " `%s'", NULL));
+  switch (insn_error.format)
+    {
+    case ERR_FMT_PLAIN:
+      as_bad (msg, str);
+      break;
+
+    case ERR_FMT_I:
+      as_bad (msg, insn_error.u.i, str);
+      break;
+
+    case ERR_FMT_SS:
+      as_bad (msg, insn_error.u.ss[0], insn_error.u.ss[1], str);
+      break;
+    }
+}
+
 /* Initialize vr4120_conflicts.  There is a bit of duplication here:
    the idea is to make it obvious at a glance that each errata is
    included.  */
@@ -2206,18 +2346,24 @@ struct regname {
   unsigned int num;
 };
 
-#define RTYPE_MASK     0x1ff00
-#define RTYPE_NUM      0x00100
-#define RTYPE_FPU      0x00200
-#define RTYPE_FCC      0x00400
-#define RTYPE_VEC      0x00800
-#define RTYPE_GP       0x01000
-#define RTYPE_CP0      0x02000
-#define RTYPE_PC       0x04000
-#define RTYPE_ACC      0x08000
-#define RTYPE_CCC      0x10000
-#define RNUM_MASK      0x000ff
-#define RWARN          0x80000
+#define RNUM_MASK      0x00000ff
+#define RTYPE_MASK     0x0efff00
+#define RTYPE_NUM      0x0000100
+#define RTYPE_FPU      0x0000200
+#define RTYPE_FCC      0x0000400
+#define RTYPE_VEC      0x0000800
+#define RTYPE_GP       0x0001000
+#define RTYPE_CP0      0x0002000
+#define RTYPE_PC       0x0004000
+#define RTYPE_ACC      0x0008000
+#define RTYPE_CCC      0x0010000
+#define RTYPE_VI       0x0020000
+#define RTYPE_VF       0x0040000
+#define RTYPE_R5900_I  0x0080000
+#define RTYPE_R5900_Q  0x0100000
+#define RTYPE_R5900_R  0x0200000
+#define RTYPE_R5900_ACC        0x0400000
+#define RWARN          0x8000000
 
 #define GENERIC_REGISTER_NUMBERS \
     {"$0",     RTYPE_NUM | 0},  \
@@ -2403,6 +2549,18 @@ struct regname {
     {"$v30",   RTYPE_VEC | 30}, \
     {"$v31",   RTYPE_VEC | 31}
 
+#define R5900_I_NAMES \
+    {"$I",     RTYPE_R5900_I | 0}
+
+#define R5900_Q_NAMES \
+    {"$Q",     RTYPE_R5900_Q | 0}
+
+#define R5900_R_NAMES \
+    {"$R",     RTYPE_R5900_R | 0}
+
+#define R5900_ACC_NAMES \
+    {"$ACC",   RTYPE_R5900_ACC | 0 }
+
 #define MIPS_DSP_ACCUMULATOR_NAMES \
     {"$ac0",   RTYPE_ACC | 0}, \
     {"$ac1",   RTYPE_ACC | 1}, \
@@ -2423,6 +2581,10 @@ static const struct regname reg_names[] = {
 
   MIPS16_SPECIAL_REGISTER_NAMES,
   MDMX_VECTOR_REGISTER_NAMES,
+  R5900_I_NAMES,
+  R5900_Q_NAMES,
+  R5900_R_NAMES,
+  R5900_ACC_NAMES,
   MIPS_DSP_ACCUMULATOR_NAMES,
   {0, 0}
 };
@@ -2450,24 +2612,14 @@ mips_prefer_vec_regno (unsigned int symval)
   return symval;
 }
 
-/* Return true if the string at *SPTR is a valid register name.  If so,
-   move *SPTR past the register and store the register's symbol value
-   in *SYMVAL.  This symbol value includes the register number
-   (RNUM_MASK) and register type (RTYPE_MASK).  */
+/* Return true if string [S, E) is a valid register name, storing its
+   symbol value in *SYMVAL_PTR if so.  */
 
 static bfd_boolean
-mips_parse_register (char **sptr, unsigned int *symval)
+mips_parse_register_1 (char *s, char *e, unsigned int *symval_ptr)
 {
-  symbolS *symbol;
-  char *s, *e;
   char save_c;
-
-  /* Find end of name.  */
-  s = e = *sptr;
-  if (is_name_beginner (*e))
-    ++e;
-  while (is_part_of_name (*e))
-    ++e;
+  symbolS *symbol;
 
   /* Terminate name.  */
   save_c = *e;
@@ -2480,8 +2632,63 @@ mips_parse_register (char **sptr, unsigned int *symval)
   if (!symbol || S_GET_SEGMENT (symbol) != reg_section)
     return FALSE;
 
+  *symval_ptr = S_GET_VALUE (symbol);
+  return TRUE;
+}
+
+/* Return true if the string at *SPTR is a valid register name.  Allow it
+   to have a VU0-style channel suffix of the form x?y?z?w? if CHANNELS_PTR
+   is nonnull.
+
+   When returning true, move *SPTR past the register, store the
+   register's symbol value in *SYMVAL_PTR and the channel mask in
+   *CHANNELS_PTR (if nonnull).  The symbol value includes the register
+   number (RNUM_MASK) and register type (RTYPE_MASK).  The channel mask
+   is a 4-bit value of the form XYZW and is 0 if no suffix was given.  */
+
+static bfd_boolean
+mips_parse_register (char **sptr, unsigned int *symval_ptr,
+                    unsigned int *channels_ptr)
+{
+  char *s, *e, *m;
+  const char *q;
+  unsigned int channels, symval, bit;
+
+  /* Find end of name.  */
+  s = e = *sptr;
+  if (is_name_beginner (*e))
+    ++e;
+  while (is_part_of_name (*e))
+    ++e;
+
+  channels = 0;
+  if (!mips_parse_register_1 (s, e, &symval))
+    {
+      if (!channels_ptr)
+       return FALSE;
+
+      /* Eat characters from the end of the string that are valid
+        channel suffixes.  The preceding register must be $ACC or
+        end with a digit, so there is no ambiguity.  */
+      bit = 1;
+      m = e;
+      for (q = "wzyx"; *q; q++, bit <<= 1)
+       if (m > s && m[-1] == *q)
+         {
+           --m;
+           channels |= bit;
+         }
+
+      if (channels == 0
+         || !mips_parse_register_1 (s, m, &symval)
+         || (symval & (RTYPE_VI | RTYPE_VF | RTYPE_R5900_ACC)) == 0)
+       return FALSE;
+    }
+
   *sptr = e;
-  *symval = S_GET_VALUE (symbol);
+  *symval_ptr = symval;
+  if (channels_ptr)
+    *channels_ptr = channels;
   return TRUE;
 }
 
@@ -2494,7 +2701,7 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
 {
   unsigned int regno;
 
-  if (mips_parse_register (s, &regno))
+  if (mips_parse_register (s, &regno, NULL))
     {
       if (types & RTYPE_VEC)
        regno = mips_prefer_vec_regno (regno);
@@ -2506,7 +2713,7 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   else
     {
       if (types & RWARN)
-       as_warn (_("Unrecognized register name `%s'"), *s);
+       as_warn (_("unrecognized register name `%s'"), *s);
       regno = ~0;
     }
   if (regnop)
@@ -2514,11 +2721,32 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   return regno <= RNUM_MASK;
 }
 
+/* Parse a VU0 "x?y?z?w?" channel mask at S and store the associated
+   mask in *CHANNELS.  Return a pointer to the first unconsumed character.  */
+
+static char *
+mips_parse_vu0_channels (char *s, unsigned int *channels)
+{
+  unsigned int i;
+
+  *channels = 0;
+  for (i = 0; i < 4; i++)
+    if (*s == "xyzw"[i])
+      {
+       *channels |= 1 << (3 - i);
+       ++s;
+      }
+  return s;
+}
+
 /* Token types for parsed operand lists.  */
 enum mips_operand_token_type {
   /* A plain register, e.g. $f2.  */
   OT_REG,
 
+  /* A 4-bit XYZW channel mask.  */
+  OT_CHANNELS,
+
   /* An element of a vector, e.g. $v0[1].  */
   OT_REG_ELEMENT,
 
@@ -2535,6 +2763,9 @@ enum mips_operand_token_type {
      before OT_REGs.  */
   OT_CHAR,
 
+  /* A doubled character, either "--" or "++".  */
+  OT_DOUBLE_CHAR,
+
   /* The end of the operand list.  */
   OT_END
 };
@@ -2549,6 +2780,9 @@ struct mips_operand_token
     /* The register symbol value for an OT_REG.  */
     unsigned int regno;
 
+    /* The 4-bit channel mask for an OT_CHANNEL_SUFFIX.  */
+    unsigned int channels;
+
     /* The register symbol value and index for an OT_REG_ELEMENT.  */
     struct {
       unsigned int regno;
@@ -2577,7 +2811,7 @@ struct mips_operand_token
       int length;
     } flt;
 
-    /* The character represented by an OT_CHAR.  */
+    /* The character represented by an OT_CHAR or OT_DOUBLE_CHAR.  */
     char ch;
   } u;
 };
@@ -2603,22 +2837,56 @@ static char *
 mips_parse_base_start (char *s)
 {
   struct mips_operand_token token;
-  unsigned int regno;
+  unsigned int regno, channels;
+  bfd_boolean decrement_p;
 
   if (*s != '(')
     return 0;
 
   ++s;
   SKIP_SPACE_TABS (s);
-  if (!mips_parse_register (&s, &regno))
+
+  /* Only match "--" as part of a base expression.  In other contexts "--X"
+     is a double negative.  */
+  decrement_p = (s[0] == '-' && s[1] == '-');
+  if (decrement_p)
+    {
+      s += 2;
+      SKIP_SPACE_TABS (s);
+    }
+
+  /* Allow a channel specifier because that leads to better error messages
+     than treating something like "$vf0x++" as an expression.  */
+  if (!mips_parse_register (&s, &regno, &channels))
     return 0;
 
   token.u.ch = '(';
   mips_add_token (&token, OT_CHAR);
 
+  if (decrement_p)
+    {
+      token.u.ch = '-';
+      mips_add_token (&token, OT_DOUBLE_CHAR);
+    }
+
   token.u.regno = regno;
   mips_add_token (&token, OT_REG);
 
+  if (channels)
+    {
+      token.u.channels = channels;
+      mips_add_token (&token, OT_CHANNELS);
+    }
+
+  /* For consistency, only match "++" as part of base expressions too.  */
+  SKIP_SPACE_TABS (s);
+  if (s[0] == '+' && s[1] == '+')
+    {
+      s += 2;
+      token.u.ch = '+';
+      mips_add_token (&token, OT_DOUBLE_CHAR);
+    }
+
   return s;
 }
 
@@ -2631,7 +2899,7 @@ static char *
 mips_parse_argument_token (char *s, char float_format)
 {
   char *end, *save_in, *err;
-  unsigned int regno1, regno2;
+  unsigned int regno1, regno2, channels;
   struct mips_operand_token token;
 
   /* First look for "($reg", since we want to treat that as an
@@ -2650,17 +2918,28 @@ mips_parse_argument_token (char *s, char float_format)
     }
 
   /* Handle tokens that start with a register.  */
-  if (mips_parse_register (&s, &regno1))
+  if (mips_parse_register (&s, &regno1, &channels))
     {
+      if (channels)
+       {
+         /* A register and a VU0 channel suffix.  */
+         token.u.regno = regno1;
+         mips_add_token (&token, OT_REG);
+
+         token.u.channels = channels;
+         mips_add_token (&token, OT_CHANNELS);
+         return s;
+       }
+
       SKIP_SPACE_TABS (s);
       if (*s == '-')
        {
          /* A register range.  */
          ++s;
          SKIP_SPACE_TABS (s);
-         if (!mips_parse_register (&s, &regno2))
+         if (!mips_parse_register (&s, &regno2, NULL))
            {
-             insn_error = _("Invalid register range");
+             set_insn_error (0, _("invalid register range"));
              return 0;
            }
 
@@ -2679,14 +2958,14 @@ mips_parse_argument_token (char *s, char float_format)
          my_getExpression (&element, s);
          if (element.X_op != O_constant)
            {
-             insn_error = _("Vector element must be constant");
+             set_insn_error (0, _("vector element must be constant"));
              return 0;
            }
          s = expr_end;
          SKIP_SPACE_TABS (s);
          if (*s != ']')
            {
-             insn_error = _("Missing `]'");
+             set_insn_error (0, _("missing `]'"));
              return 0;
            }
          ++s;
@@ -2714,7 +2993,7 @@ mips_parse_argument_token (char *s, char float_format)
       input_line_pointer = save_in;
       if (err && *err)
        {
-         insn_error = err;
+         set_insn_error (0, err);
          return 0;
        }
       if (s != end)
@@ -2897,6 +3176,8 @@ validate_mips_insn (const struct mips_opcode *opcode,
     }
   used_bits = 0;
   opno = 0;
+  if (opcode->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
+    used_bits = mips_insert_operand (&mips_vu0_channel_mask, used_bits, -1);
   for (s = opcode->args; *s; ++s)
     switch (*s)
       {
@@ -2905,6 +3186,10 @@ validate_mips_insn (const struct mips_opcode *opcode,
       case ')':
        break;
 
+      case '#':
+       s++;
+       break;
+
       default:
        if (!decode_operand)
          operand = decode_mips16_operand (*s, FALSE);
@@ -2918,9 +3203,9 @@ validate_mips_insn (const struct mips_opcode *opcode,
          }
        gas_assert (opno < MAX_OPERANDS);
        operands->operand[opno] = operand;
-       if (operand)
+       if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
          {
-           used_bits |= ((1 << operand->size) - 1) << operand->lsb;
+           used_bits = mips_insert_operand (operand, used_bits, -1);
            if (operand->type == OP_MDMX_IMM_REG)
              /* Bit 5 is the format selector (OB vs QH).  The opcode table
                 has separate entries for each format.  */
@@ -2996,7 +3281,7 @@ validate_micromips_insn (const struct mips_opcode *opc,
   length = micromips_insn_length (opc);
   if (length != 2 && length != 4)
     {
-      as_bad (_("Internal error: bad microMIPS opcode (incorrect length: %u): "
+      as_bad (_("internal error: bad microMIPS opcode (incorrect length: %u): "
                "%s %s"), length, opc->name, opc->args);
       return 0;
     }
@@ -3004,7 +3289,7 @@ validate_micromips_insn (const struct mips_opcode *opc,
   if ((length == 2 && (major & 7) != 1 && (major & 6) != 2)
       || (length == 4 && (major & 7) != 0 && (major & 4) != 4))
     {
-      as_bad (_("Internal error: bad microMIPS opcode "
+      as_bad (_("internal error: bad microMIPS opcode "
                "(opcode/length mismatch): %s %s"), opc->name, opc->args);
       return 0;
     }
@@ -3035,7 +3320,7 @@ md_begin (void)
     }
 
   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
-    as_warn (_("Could not set architecture and machine"));
+    as_warn (_("could not set architecture and machine"));
 
   op_hash = hash_new ();
 
@@ -3050,7 +3335,7 @@ md_begin (void)
          fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
                   mips_opcodes[i].name, retval);
          /* Probably a memory allocation problem?  Give up now.  */
-         as_fatal (_("Broken assembler.  No assembly attempted."));
+         as_fatal (_("broken assembler, no assembly attempted"));
        }
       do
        {
@@ -3141,7 +3426,7 @@ md_begin (void)
     }
 
   if (broken)
-    as_fatal (_("Broken assembler.  No assembly attempted."));
+    as_fatal (_("broken assembler, no assembly attempted"));
 
   /* We add all the general register names to the symbol table.  This
      helps us detect invalid uses of them.  */
@@ -3160,6 +3445,23 @@ md_begin (void)
                                       reg_names_o32[i].num, /* & RNUM_MASK, */
                                       &zero_address_frag));
 
+  for (i = 0; i < 32; i++)
+    {
+      char regname[7];
+
+      /* R5900 VU0 floating-point register.  */
+      regname[sizeof (rename) - 1] = 0;
+      snprintf (regname, sizeof (regname) - 1, "$vf%d", i);
+      symbol_table_insert (symbol_new (regname, reg_section,
+                                      RTYPE_VF | i, &zero_address_frag));
+
+      /* R5900 VU0 integer register.  */
+      snprintf (regname, sizeof (regname) - 1, "$vi%d", i);
+      symbol_table_insert (symbol_new (regname, reg_section,
+                                      RTYPE_VI | i, &zero_address_frag));
+
+    }
+
   obstack_init (&mips_operand_tokens);
 
   mips_no_prev_insn ();
@@ -3281,7 +3583,6 @@ md_assemble (char *str)
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
   imm_expr.X_op = O_absent;
-  imm2_expr.X_op = O_absent;
   offset_expr.X_op = O_absent;
   offset_reloc[0] = BFD_RELOC_UNUSED;
   offset_reloc[1] = BFD_RELOC_UNUSED;
@@ -3289,6 +3590,7 @@ md_assemble (char *str)
 
   mips_mark_labels ();
   mips_assembling_insn = TRUE;
+  clear_insn_error ();
 
   if (mips_opts.mips16)
     mips16_ip (str, &insn);
@@ -3299,8 +3601,8 @@ md_assemble (char *str)
            str, insn.insn_opcode));
     }
 
-  if (insn_error)
-    as_bad ("%s `%s'", insn_error, str);
+  if (insn_error.msg)
+    report_insn_error (str);
   else if (insn.insn_mo->pinfo == INSN_MACRO)
     {
       macro_start ();
@@ -3701,9 +4003,12 @@ operand_reg_mask (const struct mips_cl_insn *insn,
     case OP_REPEAT_DEST_REG:
     case OP_REPEAT_PREV_REG:
     case OP_PC:
+    case OP_VU0_SUFFIX:
+    case OP_VU0_MATCH_SUFFIX:
       abort ();
 
     case OP_REG:
+    case OP_OPTIONAL_REG:
       {
        const struct mips_reg_operand *reg_op;
 
@@ -3904,39 +4209,6 @@ mips_oddfpreg_ok (const struct mips_opcode *insn, int opnum)
   return FALSE;
 }
 
-/* Report that user-supplied argument ARGNUM for INSN was VAL, but should
-   have been in the range [MIN_VAL, MAX_VAL].  PRINT_HEX says whether
-   this operand is normally printed in hex or decimal.  */
-
-static void
-report_bad_range (struct mips_cl_insn *insn, int argnum,
-                 offsetT val, int min_val, int max_val,
-                 bfd_boolean print_hex)
-{
-  if (print_hex && val >= 0)
-    as_bad (_("Operand %d of `%s' must be in the range [0x%x, 0x%x],"
-             " was 0x%lx."),
-           argnum, insn->insn_mo->name, min_val, max_val, (unsigned long) val);
-  else if (print_hex)
-    as_bad (_("Operand %d of `%s' must be in the range [0x%x, 0x%x],"
-             " was %ld."),
-           argnum, insn->insn_mo->name, min_val, max_val, (unsigned long) val);
-  else
-    as_bad (_("Operand %d of `%s' must be in the range [%d, %d],"
-             " was %ld."),
-           argnum, insn->insn_mo->name, min_val, max_val, (unsigned long) val);
-}
-
-/* Report an invalid combination of position and size operands for a bitfield
-   operation.  POS and SIZE are the values that were given.  */
-
-static void
-report_bad_field (offsetT pos, offsetT size)
-{
-  as_bad (_("Invalid field specification (position %ld, size %ld)"),
-         (unsigned long) pos, (unsigned long) size);
-}
-
 /* Information about an instruction argument that we're trying to match.  */
 struct mips_arg_info
 {
@@ -3964,26 +4236,33 @@ struct mips_arg_info
      where it gives the lsb position.  */
   unsigned int last_op_int;
 
-  /* If true, match routines should silently reject invalid arguments.
-     If false, match routines can accept invalid arguments as long as
-     they report an appropriate error.  They still have the option of
-     silently rejecting arguments, in which case a generic "Invalid operands"
-     style of error will be used instead.  */
-  bfd_boolean soft_match;
-
-  /* If true, the OP_INT match routine should treat plain symbolic operands
-     as if a relocation operator like %lo(...) had been used.  This is only
-     ever true if the operand can be relocated.  */
-  bfd_boolean allow_nonconst;
-
-  /* When true, the OP_INT match routine should allow unsigned N-bit
-     arguments to be used where a signed N-bit operand is expected.  */
-  bfd_boolean lax_max;
+  /* If true, match routines should assume that no later instruction
+     alternative matches and should therefore be as accomodating as
+     possible.  Match routines should not report errors if something
+     is only invalid for !LAX_MATCH.  */
+  bfd_boolean lax_match;
 
   /* True if a reference to the current AT register was seen.  */
   bfd_boolean seen_at;
 };
 
+/* Record that the argument is out of range.  */
+
+static void
+match_out_of_range (struct mips_arg_info *arg)
+{
+  set_insn_error_i (arg->argnum, _("operand %d out of range"), arg->argnum);
+}
+
+/* Record that the argument isn't constant but needs to be.  */
+
+static void
+match_not_constant (struct mips_arg_info *arg)
+{
+  set_insn_error_i (arg->argnum, _("operand %d must be constant"),
+                   arg->argnum);
+}
+
 /* Try to match an OT_CHAR token for character CH.  Consume the token
    and return true on success, otherwise return false.  */
 
@@ -4008,37 +4287,38 @@ static bfd_boolean
 match_expression (struct mips_arg_info *arg, expressionS *value,
                  bfd_reloc_code_real_type *r)
 {
-  if (arg->token->type == OT_INTEGER)
+  /* If the next token is a '(' that was parsed as being part of a base
+     expression, assume we have an elided offset.  The later match will fail
+     if this turns out to be wrong.  */
+  if (arg->token->type == OT_CHAR && arg->token->u.ch == '(')
     {
-      *value = arg->token->u.integer.value;
-      memcpy (r, arg->token->u.integer.relocs, 3 * sizeof (*r));
-      ++arg->token;
+      value->X_op = O_constant;
+      value->X_add_number = 0;
+      r[0] = r[1] = r[2] = BFD_RELOC_UNUSED;
       return TRUE;
     }
 
-  /* Error-reporting is more consistent if we treat registers as O_register
-     rather than rejecting them outright.  "$1", "($1)" and "(($1))" are
-     then handled in the same way.  */
-  if (arg->token->type == OT_REG)
+  /* Reject register-based expressions such as "0+$2" and "(($2))".
+     For plain registers the default error seems more appropriate.  */
+  if (arg->token->type == OT_INTEGER
+      && arg->token->u.integer.value.X_op == O_register)
     {
-      value->X_add_number = arg->token->u.regno;
-      ++arg->token;
+      set_insn_error (arg->argnum, _("register value used as expression"));
+      return FALSE;
     }
-  else if (arg->token[0].type == OT_CHAR
-          && arg->token[0].u.ch == '('
-          && arg->token[1].type == OT_REG
-          && arg->token[2].type == OT_CHAR
-          && arg->token[2].u.ch == ')')
+
+  if (arg->token->type == OT_INTEGER)
     {
-      value->X_add_number = arg->token[1].u.regno;
-      arg->token += 3;
+      *value = arg->token->u.integer.value;
+      memcpy (r, arg->token->u.integer.relocs, 3 * sizeof (*r));
+      ++arg->token;
+      return TRUE;
     }
-  else
-    return FALSE;
 
-  value->X_op = O_register;
-  r[0] = r[1] = r[2] = BFD_RELOC_UNUSED;
-  return TRUE;
+  set_insn_error_i
+    (arg->argnum, _("operand %d must be an immediate expression"),
+     arg->argnum);
+  return FALSE;
 }
 
 /* Try to get a constant expression from the next tokens in ARG.  Consume
@@ -4047,7 +4327,7 @@ match_expression (struct mips_arg_info *arg, expressionS *value,
    error.  */
 
 static bfd_boolean
-match_const_int (struct mips_arg_info *arg, offsetT *value, offsetT fallback)
+match_const_int (struct mips_arg_info *arg, offsetT *value)
 {
   expressionS ex;
   bfd_reloc_code_real_type r[3];
@@ -4059,11 +4339,8 @@ match_const_int (struct mips_arg_info *arg, offsetT *value, offsetT fallback)
     *value = ex.X_add_number;
   else
     {
-      if (arg->soft_match)
-       return FALSE;
-      as_bad (_("Operand %d of `%s' must be constant"),
-             arg->argnum, arg->insn->insn_mo->name);
-      *value = fallback;
+      match_not_constant (arg);
+      return FALSE;
     }
   return TRUE;
 }
@@ -4113,6 +4390,24 @@ convert_reg_type (const struct mips_opcode *opcode,
 
     case OP_REG_HW:
       return RTYPE_NUM;
+
+    case OP_REG_VI:
+      return RTYPE_NUM | RTYPE_VI;
+
+    case OP_REG_VF:
+      return RTYPE_NUM | RTYPE_VF;
+
+    case OP_REG_R5900_I:
+      return RTYPE_R5900_I;
+
+    case OP_REG_R5900_Q:
+      return RTYPE_R5900_Q;
+
+    case OP_REG_R5900_R:
+      return RTYPE_R5900_R;
+
+    case OP_REG_R5900_ACC:
+      return RTYPE_R5900_ACC;
     }
   abort ();
 }
@@ -4130,7 +4425,7 @@ check_regno (struct mips_arg_info *arg,
       && (regno & 1) != 0
       && HAVE_32BIT_FPRS
       && !mips_oddfpreg_ok (arg->insn->insn_mo, arg->opnum))
-    as_warn (_("Float register should be even, was %d"), regno);
+    as_warn (_("float register should be even, was %d"), regno);
 
   if (type == OP_REG_CCC)
     {
@@ -4142,12 +4437,12 @@ check_regno (struct mips_arg_info *arg,
       if ((regno & 1) != 0
          && ((length >= 3 && strcmp (name + length - 3, ".ps") == 0)
              || (length >= 5 && strncmp (name + length - 5, "any2", 4) == 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"),
                 name, regno);
 
       if ((regno & 3) != 0
          && (length >= 5 && strncmp (name + length - 5, "any4", 4) == 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"),
                 name, regno);
     }
 }
@@ -4221,24 +4516,17 @@ match_int_operand (struct mips_arg_info *arg,
   unsigned int uval;
   int min_val, max_val, factor;
   offsetT sval;
-  bfd_boolean print_hex;
 
   operand = (const struct mips_int_operand *) operand_base;
   factor = 1 << operand->shift;
   min_val = mips_int_operand_min (operand);
   max_val = mips_int_operand_max (operand);
-  if (arg->lax_max)
-    max_val = ((1 << operand_base->size) - 1) << operand->shift;
 
-  if (arg->token->type == OT_CHAR && arg->token->u.ch == '(')
-    /* Assume we have an elided offset.  The later match will fail
-       if this turns out to be wrong.  */
-    sval = 0;
-  else if (operand_base->lsb == 0
-          && operand_base->size == 16
-          && operand->shift == 0
-          && operand->bias == 0
-          && (operand->max_val == 32767 || operand->max_val == 65535))
+  if (operand_base->lsb == 0
+      && operand_base->size == 16
+      && operand->shift == 0
+      && operand->bias == 0
+      && (operand->max_val == 32767 || operand->max_val == 65535))
     {
       /* The operand can be relocated.  */
       if (!match_expression (arg, &offset_expr, offset_reloc))
@@ -4252,9 +4540,9 @@ match_int_operand (struct mips_arg_info *arg,
 
       if (offset_expr.X_op != O_constant)
        {
-         /* If non-constant operands are allowed then leave them for
-            the caller to process, otherwise fail the match.  */
-         if (!arg->allow_nonconst)
+         /* Accept non-constant operands if no later alternative matches,
+            leaving it for the caller to process.  */
+         if (!arg->lax_match)
            return FALSE;
          offset_reloc[0] = BFD_RELOC_LO16;
          return TRUE;
@@ -4264,41 +4552,29 @@ match_int_operand (struct mips_arg_info *arg,
         ourselves.  */
       sval = offset_expr.X_add_number;
       offset_expr.X_op = O_absent;
+
+      /* For compatibility with older assemblers, we accept
+        0x8000-0xffff as signed 16-bit numbers when only
+        signed numbers are allowed.  */
+      if (sval > max_val)
+       {
+         max_val = ((1 << operand_base->size) - 1) << operand->shift;
+         if (!arg->lax_match && sval <= max_val)
+           return FALSE;
+       }
     }
   else
     {
-      if (!match_const_int (arg, &sval, min_val))
+      if (!match_const_int (arg, &sval))
        return FALSE;
     }
 
   arg->last_op_int = sval;
 
-  /* Check the range.  If there's a problem, record the lowest acceptable
-     value in arg->last_op_int in order to prevent an unhelpful error
-     from OP_MSB too.
-
-     Bit counts have traditionally been printed in hex by the disassembler
-     but printed as decimal in error messages.  Only resort to hex if
-     the operand is bigger than 6 bits.  */
-  print_hex = operand->print_hex && operand_base->size > 6;
-  if (sval < min_val || sval > max_val)
-    {
-      if (arg->soft_match)
-       return FALSE;
-      report_bad_range (arg->insn, arg->argnum, sval, min_val, max_val,
-                       print_hex);
-      arg->last_op_int = min_val;
-    }
-  else if (sval % factor)
+  if (sval < min_val || sval > max_val || sval % factor)
     {
-      if (arg->soft_match)
-       return FALSE;
-      as_bad (print_hex && sval >= 0
-             ? _("Operand %d of `%s' must be a factor of %d, was 0x%lx.")
-             : _("Operand %d of `%s' must be a factor of %d, was %ld."),
-             arg->argnum, arg->insn->insn_mo->name, factor,
-             (unsigned long) sval);
-      arg->last_op_int = min_val;
+      match_out_of_range (arg);
+      return FALSE;
     }
 
   uval = (unsigned int) sval >> operand->shift;
@@ -4343,7 +4619,7 @@ match_mapped_int_operand (struct mips_arg_info *arg,
   offsetT sval;
 
   operand = (const struct mips_mapped_int_operand *) operand_base;
-  if (!match_const_int (arg, &sval, operand->int_map[0]))
+  if (!match_const_int (arg, &sval))
     return FALSE;
 
   num_vals = 1 << operand_base->size;
@@ -4351,7 +4627,10 @@ match_mapped_int_operand (struct mips_arg_info *arg,
     if (operand->int_map[uval] == sval)
       break;
   if (uval == num_vals)
-    return FALSE;
+    {
+      match_out_of_range (arg);
+      return FALSE;
+    }
 
   insn_insert_operand (arg->insn, operand_base, uval);
   return TRUE;
@@ -4372,7 +4651,7 @@ match_msb_operand (struct mips_arg_info *arg,
   max_val = min_val + (1 << operand_base->size) - 1;
   max_high = operand->opsize;
 
-  if (!match_const_int (arg, &size, 1))
+  if (!match_const_int (arg, &size))
     return FALSE;
 
   high = size + arg->last_op_int;
@@ -4380,10 +4659,8 @@ match_msb_operand (struct mips_arg_info *arg,
 
   if (size < 0 || high > max_high || sval < min_val || sval > max_val)
     {
-      if (arg->soft_match)
-       return FALSE;
-      report_bad_field (arg->last_op_int, size);
-      sval = min_val;
+      match_out_of_range (arg);
+      return FALSE;
     }
   insn_insert_operand (arg->insn, operand_base, sval - min_val);
   return TRUE;
@@ -4465,7 +4742,7 @@ match_perf_reg_operand (struct mips_arg_info *arg,
 {
   offsetT sval;
 
-  if (!match_const_int (arg, &sval, 0))
+  if (!match_const_int (arg, &sval))
     return FALSE;
 
   if (sval != 0
@@ -4474,9 +4751,8 @@ match_perf_reg_operand (struct mips_arg_info *arg,
              && (strcmp (arg->insn->insn_mo->name, "mfps") == 0
                  || strcmp (arg->insn->insn_mo->name, "mtps") == 0))))
     {
-      if (arg->soft_match)
-       return FALSE;
-      as_bad (_("Invalid performance register (%ld)"), (unsigned long) sval);
+      set_insn_error (arg->argnum, _("invalid performance register"));
+      return FALSE;
     }
 
   insn_insert_operand (arg->insn, operand, sval);
@@ -4492,15 +4768,21 @@ match_addiusp_operand (struct mips_arg_info *arg,
   offsetT sval;
   unsigned int uval;
 
-  if (!match_const_int (arg, &sval, -256))
+  if (!match_const_int (arg, &sval))
     return FALSE;
 
   if (sval % 4)
-    return FALSE;
+    {
+      match_out_of_range (arg);
+      return FALSE;
+    }
 
   sval /= 4;
   if (!(sval >= -258 && sval <= 257) || (sval >= -2 && sval <= 1))
-    return FALSE;
+    {
+      match_out_of_range (arg);
+      return FALSE;
+    }
 
   uval = (unsigned int) sval;
   uval = ((uval >> 1) & ~0xff) | (uval & 0xff);
@@ -4644,9 +4926,7 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
   unsigned int opcode, args, statics, sregs;
   unsigned int num_frame_sizes, num_args, num_statics, num_sregs;
   offsetT frame_size;
-  const char *error;
 
-  error = 0;
   opcode = arg->insn->insn_opcode;
   frame_size = 0;
   num_frame_sizes = 0;
@@ -4660,7 +4940,7 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
       if (arg->token->type == OT_INTEGER)
        {
          /* Handle the frame size.  */
-         if (!match_const_int (arg, &frame_size, 0))
+         if (!match_const_int (arg, &frame_size))
            return FALSE;
          num_frame_sizes += 1;
        }
@@ -4754,25 +5034,27 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
 
   /* Encode frame size.  */
   if (num_frame_sizes == 0)
-    error = _("Missing frame size");
-  else if (num_frame_sizes > 1)
-    error = _("Frame size specified twice");
-  else if ((frame_size & 7) != 0 || frame_size < 0 || frame_size > 0xff * 8)
-    error = _("Invalid frame size");
-  else if (frame_size != 128 || (opcode >> 16) != 0)
+    {
+      set_insn_error (arg->argnum, _("missing frame size"));
+      return FALSE;
+    }
+  if (num_frame_sizes > 1)
+    {
+      set_insn_error (arg->argnum, _("frame size specified twice"));
+      return FALSE;
+    }
+  if ((frame_size & 7) != 0 || frame_size < 0 || frame_size > 0xff * 8)
+    {
+      set_insn_error (arg->argnum, _("invalid frame size"));
+      return FALSE;
+    }
+  if (frame_size != 128 || (opcode >> 16) != 0)
     {
       frame_size /= 8;
       opcode |= (((frame_size & 0xf0) << 16)
                 | (frame_size & 0x0f));
     }
 
-  if (error)
-    {
-      if (arg->soft_match)
-       return FALSE;
-      as_bad ("%s", error);
-    }
-
   /* Finally build the instruction.  */
   if ((opcode >> 16) != 0 || frame_size == 0)
     opcode |= MIPS16_EXTEND;
@@ -4801,10 +5083,9 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
       if ((opcode->membership & INSN_5400)
          && strcmp (opcode->name, "rzu.ob") == 0)
        {
-         if (arg->soft_match)
-           return FALSE;
-         as_bad (_("Operand %d of `%s' must be an immediate"),
-                 arg->argnum, opcode->name);
+         set_insn_error_i (arg->argnum, _("operand %d must be an immediate"),
+                           arg->argnum);
+         return FALSE;
        }
 
       /* Check whether this is a vector register or a broadcast of
@@ -4816,9 +5097,8 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
            return FALSE;
          if (arg->token->u.reg_element.index > (is_qh ? 3 : 7))
            {
-             if (arg->soft_match)
-               return FALSE;
-             as_bad (_("Invalid element selector"));
+             set_insn_error (arg->argnum, _("invalid element selector"));
+             return FALSE;
            }
          else
            uval |= arg->token->u.reg_element.index << (is_qh ? 2 : 1) << 5;
@@ -4830,10 +5110,9 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
              && (strcmp (opcode->name, "sll.ob") == 0
                  || strcmp (opcode->name, "srl.ob") == 0))
            {
-             if (arg->soft_match)
-               return FALSE;
-             as_bad (_("Operand %d of `%s' must be scalar"),
-                     arg->argnum, opcode->name);
+             set_insn_error_i (arg->argnum, _("operand %d must be scalar"),
+                               arg->argnum);
+             return FALSE;
            }
 
          if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
@@ -4850,13 +5129,12 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
     {
       offsetT sval;
 
-      if (!match_const_int (arg, &sval, 0))
+      if (!match_const_int (arg, &sval))
        return FALSE;
       if (sval < 0 || sval > 31)
        {
-         if (arg->soft_match)
-           return FALSE;
-         report_bad_range (arg->insn, arg->argnum, sval, 0, 31, FALSE);
+         match_out_of_range (arg);
+         return FALSE;
        }
       uval |= (sval & 31);
       if (is_qh)
@@ -4934,7 +5212,10 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm,
      The .lit4 and .lit8 sections are only used if permitted by the
      -G argument.  */
   if (arg->token->type != OT_FLOAT)
-    return FALSE;
+    {
+      set_insn_error (arg->argnum, _("floating-point expression required"));
+      return FALSE;
+    }
 
   gas_assert (arg->token->u.flt.length == length);
   data = arg->token->u.flt.data;
@@ -5029,7 +5310,7 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm,
   else
     record_alignment (new_seg, length == 4 ? 2 : 3);
   if (seg == now_seg)
-    as_bad (_("Can't use floating point insn in this section"));
+    as_bad (_("cannot use `%s' in this section"), arg->insn->insn_mo->name);
 
   /* Set the argument to the current address in the section.  */
   imm->X_op = O_absent;
@@ -5046,6 +5327,42 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm,
   return TRUE;
 }
 
+/* OP_VU0_SUFFIX and OP_VU0_MATCH_SUFFIX matcher; MATCH_P selects between
+   them.  */
+
+static bfd_boolean
+match_vu0_suffix_operand (struct mips_arg_info *arg,
+                         const struct mips_operand *operand,
+                         bfd_boolean match_p)
+{
+  unsigned int uval;
+
+  /* The operand can be an XYZW mask or a single 2-bit channel index
+     (with X being 0).  */
+  gas_assert (operand->size == 2 || operand->size == 4);
+
+  /* The suffix can be omitted when it is already part of the opcode.  */
+  if (arg->token->type != OT_CHANNELS)
+    return match_p;
+
+  uval = arg->token->u.channels;
+  if (operand->size == 2)
+    {
+      /* Check that a single bit is set and convert it into a 2-bit index.  */
+      if ((uval & -uval) != uval)
+       return FALSE;
+      uval = 4 - ffs (uval);
+    }
+
+  if (match_p && insn_extract_operand (arg->insn, operand) != uval)
+    return FALSE;
+
+  ++arg->token;
+  if (!match_p)
+    insn_insert_operand (arg->insn, operand, uval);
+  return TRUE;
+}
+
 /* S is the text seen for ARG.  Match it against OPERAND.  Return the end
    of the argument text if the match is successful, otherwise return null.  */
 
@@ -5065,6 +5382,7 @@ match_operand (struct mips_arg_info *arg,
       return match_msb_operand (arg, operand);
 
     case OP_REG:
+    case OP_OPTIONAL_REG:
       return match_reg_operand (arg, operand);
 
     case OP_REG_PAIR:
@@ -5102,6 +5420,12 @@ match_operand (struct mips_arg_info *arg,
 
     case OP_PC:
       return match_pc_operand (arg);
+
+    case OP_VU0_SUFFIX:
+      return match_vu0_suffix_operand (arg, operand, FALSE);
+
+    case OP_VU0_MATCH_SUFFIX:
+      return match_vu0_suffix_operand (arg, operand, TRUE);
     }
   abort ();
 }
@@ -5115,9 +5439,9 @@ check_completed_insn (struct mips_arg_info *arg)
   if (arg->seen_at)
     {
       if (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\""), AT, AT);
+       as_warn (_("used $%u with \".set at=$%u\""), AT, AT);
     }
 }
 
@@ -6082,7 +6406,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
           && micromips_insn_length (ip->insn_mo) != 2)
          || ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
              && micromips_insn_length (ip->insn_mo) != 4)))
-    as_warn (_("Wrong size instruction in a %u-bit branch delay slot"),
+    as_warn (_("wrong size instruction in a %u-bit branch delay slot"),
             (prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0 ? 16 : 32);
 
   if (address_expr == NULL)
@@ -6654,10 +6978,585 @@ end_noreorder (void)
     }
 }
 
-/* Set up global variables for the start of a new macro.  */
+/* Sign-extend 32-bit mode constants that have bit 31 set and all
+   higher bits unset.  */
 
 static void
-macro_start (void)
+normalize_constant_expr (expressionS *ex)
+{
+  if (ex->X_op == O_constant
+      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+                       - 0x80000000);
+}
+
+/* Sign-extend 32-bit mode address offsets that have bit 31 set and
+   all higher bits unset.  */
+
+static void
+normalize_address_expr (expressionS *ex)
+{
+  if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
+       || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
+      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+                       - 0x80000000);
+}
+
+/* Try to match TOKENS against OPCODE, storing the result in INSN.
+   Return true if the match was successful.
+
+   OPCODE_EXTRA is a value that should be ORed into the opcode
+   (used for VU0 channel suffixes, etc.).  MORE_ALTS is true if
+   there are more alternatives after OPCODE and SOFT_MATCH is
+   as for mips_arg_info.  */
+
+static bfd_boolean
+match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
+           struct mips_operand_token *tokens, unsigned int opcode_extra,
+           bfd_boolean lax_match, bfd_boolean complete_p)
+{
+  const char *args;
+  struct mips_arg_info arg;
+  const struct mips_operand *operand;
+  char c;
+
+  imm_expr.X_op = O_absent;
+  offset_expr.X_op = O_absent;
+  offset_reloc[0] = BFD_RELOC_UNUSED;
+  offset_reloc[1] = BFD_RELOC_UNUSED;
+  offset_reloc[2] = BFD_RELOC_UNUSED;
+
+  create_insn (insn, opcode);
+  /* When no opcode suffix is specified, assume ".xyzw". */
+  if ((opcode->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0 && opcode_extra == 0)
+    insn->insn_opcode |= 0xf << mips_vu0_channel_mask.lsb;
+  else
+    insn->insn_opcode |= opcode_extra;
+  memset (&arg, 0, sizeof (arg));
+  arg.insn = insn;
+  arg.token = tokens;
+  arg.argnum = 1;
+  arg.last_regno = ILLEGAL_REG;
+  arg.dest_regno = ILLEGAL_REG;
+  arg.lax_match = lax_match;
+  for (args = opcode->args;; ++args)
+    {
+      if (arg.token->type == OT_END)
+       {
+         /* Handle unary instructions in which only one operand is given.
+            The source is then the same as the destination.  */
+         if (arg.opnum == 1 && *args == ',')
+           {
+             operand = (mips_opts.micromips
+                        ? decode_micromips_operand (args + 1)
+                        : decode_mips_operand (args + 1));
+             if (operand && mips_optional_operand_p (operand))
+               {
+                 arg.token = tokens;
+                 arg.argnum = 1;
+                 continue;
+               }
+           }
+
+         /* Treat elided base registers as $0.  */
+         if (strcmp (args, "(b)") == 0)
+           args += 3;
+
+         if (args[0] == '+')
+           switch (args[1])
+             {
+             case 'K':
+             case 'N':
+               /* The register suffix is optional. */
+               args += 2;
+               break;
+             }
+
+         /* Fail the match if there were too few operands.  */
+         if (*args)
+           return FALSE;
+
+         /* Successful match.  */
+         if (!complete_p)
+           return TRUE;
+         clear_insn_error ();
+         if (arg.dest_regno == arg.last_regno
+             && strncmp (insn->insn_mo->name, "jalr", 4) == 0)
+           {
+             if (arg.opnum == 2)
+               set_insn_error
+                 (0, _("source and destination must be different"));
+             else if (arg.last_regno == 31)
+               set_insn_error
+                 (0, _("a destination register must be supplied"));
+           }
+         else if (arg.last_regno == 31
+                  && (strncmp (insn->insn_mo->name, "bltzal", 6) == 0
+                      || strncmp (insn->insn_mo->name, "bgezal", 6) == 0))
+           set_insn_error (0, _("the source register must not be $31"));
+         check_completed_insn (&arg);
+         return TRUE;
+       }
+
+      /* Fail the match if the line has too many operands.   */
+      if (*args == 0)
+       return FALSE;
+
+      /* Handle characters that need to match exactly.  */
+      if (*args == '(' || *args == ')' || *args == ',')
+       {
+         if (match_char (&arg, *args))
+           continue;
+         return FALSE;
+       }
+      if (*args == '#')
+       {
+         ++args;
+         if (arg.token->type == OT_DOUBLE_CHAR
+             && arg.token->u.ch == *args)
+           {
+             ++arg.token;
+             continue;
+           }
+         return FALSE;
+       }
+
+      /* Handle special macro operands.  Work out the properties of
+        other operands.  */
+      arg.opnum += 1;
+      switch (*args)
+       {
+       case '+':
+         switch (args[1])
+           {
+           case 'i':
+             *offset_reloc = BFD_RELOC_MIPS_JMP;
+             break;
+           }
+         break;
+
+       case 'I':
+         if (!match_const_int (&arg, &imm_expr.X_add_number))
+           return FALSE;
+         imm_expr.X_op = O_constant;
+         if (HAVE_32BIT_GPRS)
+           normalize_constant_expr (&imm_expr);
+         continue;
+
+       case 'A':
+         if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
+           {
+             /* Assume that the offset has been elided and that what
+                we saw was a base register.  The match will fail later
+                if that assumption turns out to be wrong.  */
+             offset_expr.X_op = O_constant;
+             offset_expr.X_add_number = 0;
+           }
+         else
+           {
+             if (!match_expression (&arg, &offset_expr, offset_reloc))
+               return FALSE;
+             normalize_address_expr (&offset_expr);
+           }
+         continue;
+
+       case 'F':
+         if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+                                    8, TRUE))
+           return FALSE;
+         continue;
+
+       case 'L':
+         if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+                                    8, FALSE))
+           return FALSE;
+         continue;
+
+       case 'f':
+         if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+                                    4, TRUE))
+           return FALSE;
+         continue;
+
+       case 'l':
+         if (!match_float_constant (&arg, &imm_expr, &offset_expr,
+                                    4, FALSE))
+           return FALSE;
+         continue;
+
+       case 'p':
+         *offset_reloc = BFD_RELOC_16_PCREL_S2;
+         break;
+
+       case 'a':
+         *offset_reloc = BFD_RELOC_MIPS_JMP;
+         break;
+
+       case 'm':
+         gas_assert (mips_opts.micromips);
+         c = args[1];
+         switch (c)
+           {
+           case 'D':
+           case 'E':
+             if (!forced_insn_length)
+               *offset_reloc = (int) BFD_RELOC_UNUSED + c;
+             else if (c == 'D')
+               *offset_reloc = BFD_RELOC_MICROMIPS_10_PCREL_S1;
+             else
+               *offset_reloc = BFD_RELOC_MICROMIPS_7_PCREL_S1;
+             break;
+           }
+         break;
+       }
+
+      operand = (mips_opts.micromips
+                ? decode_micromips_operand (args)
+                : decode_mips_operand (args));
+      if (!operand)
+       abort ();
+
+      /* Skip prefixes.  */
+      if (*args == '+' || *args == 'm')
+       args++;
+
+      if (mips_optional_operand_p (operand)
+         && args[1] == ','
+         && (arg.token[0].type != OT_REG
+             || arg.token[1].type == OT_END))
+       {
+         /* Assume that the register has been elided and is the
+            same as the first operand.  */
+         arg.token = tokens;
+         arg.argnum = 1;
+       }
+
+      if (!match_operand (&arg, operand))
+       return FALSE;
+    }
+}
+
+/* Like match_insn, but for MIPS16.  */
+
+static bfd_boolean
+match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
+                  struct mips_operand_token *tokens)
+{
+  const char *args;
+  const struct mips_operand *operand;
+  const struct mips_operand *ext_operand;
+  struct mips_arg_info arg;
+  int relax_char;
+
+  create_insn (insn, opcode);
+  imm_expr.X_op = O_absent;
+  offset_expr.X_op = O_absent;
+  offset_reloc[0] = BFD_RELOC_UNUSED;
+  offset_reloc[1] = BFD_RELOC_UNUSED;
+  offset_reloc[2] = BFD_RELOC_UNUSED;
+  relax_char = 0;
+
+  memset (&arg, 0, sizeof (arg));
+  arg.insn = insn;
+  arg.token = tokens;
+  arg.argnum = 1;
+  arg.last_regno = ILLEGAL_REG;
+  arg.dest_regno = ILLEGAL_REG;
+  relax_char = 0;
+  for (args = opcode->args;; ++args)
+    {
+      int c;
+
+      if (arg.token->type == OT_END)
+       {
+         offsetT value;
+
+         /* Handle unary instructions in which only one operand is given.
+            The source is then the same as the destination.  */
+         if (arg.opnum == 1 && *args == ',')
+           {
+             operand = decode_mips16_operand (args[1], FALSE);
+             if (operand && mips_optional_operand_p (operand))
+               {
+                 arg.token = tokens;
+                 arg.argnum = 1;
+                 continue;
+               }
+           }
+
+         /* Fail the match if there were too few operands.  */
+         if (*args)
+           return FALSE;
+
+         /* Successful match.  Stuff the immediate value in now, if
+            we can.  */
+         clear_insn_error ();
+         if (opcode->pinfo == INSN_MACRO)
+           {
+             gas_assert (relax_char == 0 || relax_char == 'p');
+             gas_assert (*offset_reloc == BFD_RELOC_UNUSED);
+           }
+         else if (relax_char
+                  && offset_expr.X_op == O_constant
+                  && calculate_reloc (*offset_reloc,
+                                      offset_expr.X_add_number,
+                                      &value))
+           {
+             mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
+                           forced_insn_length, &insn->insn_opcode);
+             offset_expr.X_op = O_absent;
+             *offset_reloc = BFD_RELOC_UNUSED;
+           }
+         else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
+           {
+             if (forced_insn_length == 2)
+               set_insn_error (0, _("invalid unextended operand value"));
+             forced_insn_length = 4;
+             insn->insn_opcode |= MIPS16_EXTEND;
+           }
+         else if (relax_char)
+           *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
+
+         check_completed_insn (&arg);
+         return TRUE;
+       }
+
+      /* Fail the match if the line has too many operands.   */
+      if (*args == 0)
+       return FALSE;
+
+      /* Handle characters that need to match exactly.  */
+      if (*args == '(' || *args == ')' || *args == ',')
+       {
+         if (match_char (&arg, *args))
+           continue;
+         return FALSE;
+       }
+
+      arg.opnum += 1;
+      c = *args;
+      switch (c)
+       {
+       case 'p':
+       case 'q':
+       case 'A':
+       case 'B':
+       case 'E':
+         relax_char = c;
+         break;
+
+       case 'I':
+         if (!match_const_int (&arg, &imm_expr.X_add_number))
+           return FALSE;
+         imm_expr.X_op = O_constant;
+         if (HAVE_32BIT_GPRS)
+           normalize_constant_expr (&imm_expr);
+         continue;
+
+       case 'a':
+       case 'i':
+         *offset_reloc = BFD_RELOC_MIPS16_JMP;
+         insn->insn_opcode <<= 16;
+         break;
+       }
+
+      operand = decode_mips16_operand (c, FALSE);
+      if (!operand)
+       abort ();
+
+      /* '6' is a special case.  It is used for BREAK and SDBBP,
+        whose operands are only meaningful to the software that decodes
+        them.  This means that there is no architectural reason why
+        they cannot be prefixed by EXTEND, but in practice,
+        exception handlers will only look at the instruction
+        itself.  We therefore allow '6' to be extended when
+        disassembling but not when assembling.  */
+      if (operand->type != OP_PCREL && c != '6')
+       {
+         ext_operand = decode_mips16_operand (c, TRUE);
+         if (operand != ext_operand)
+           {
+             if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
+               {
+                 offset_expr.X_op = O_constant;
+                 offset_expr.X_add_number = 0;
+                 relax_char = c;
+                 continue;
+               }
+
+             /* We need the OT_INTEGER check because some MIPS16
+                immediate variants are listed before the register ones.  */
+             if (arg.token->type != OT_INTEGER
+                 || !match_expression (&arg, &offset_expr, offset_reloc))
+               return FALSE;
+
+             /* '8' is used for SLTI(U) and has traditionally not
+                been allowed to take relocation operators.  */
+             if (offset_reloc[0] != BFD_RELOC_UNUSED
+                 && (ext_operand->size != 16 || c == '8'))
+               return FALSE;
+
+             relax_char = c;
+             continue;
+           }
+       }
+
+      if (mips_optional_operand_p (operand)
+         && args[1] == ','
+         && (arg.token[0].type != OT_REG
+             || arg.token[1].type == OT_END))
+       {
+         /* Assume that the register has been elided and is the
+            same as the first operand.  */
+         arg.token = tokens;
+         arg.argnum = 1;
+       }
+
+      if (!match_operand (&arg, operand))
+       return FALSE;
+    }
+}
+
+/* Record that the current instruction is invalid for the current ISA.  */
+
+static void
+match_invalid_for_isa (void)
+{
+  set_insn_error_ss
+    (0, _("opcode not supported on this processor: %s (%s)"),
+     mips_cpu_info_from_arch (mips_opts.arch)->name,
+     mips_cpu_info_from_isa (mips_opts.isa)->name);
+}
+
+/* Try to match TOKENS against a series of opcode entries, starting at FIRST.
+   Return true if a definite match or failure was found, storing any match
+   in INSN.  OPCODE_EXTRA is a value that should be ORed into the opcode
+   (to handle things like VU0 suffixes).  LAX_MATCH is true if we have already
+   tried and failed to match under normal conditions and now want to try a
+   more relaxed match.  */
+
+static bfd_boolean
+match_insns (struct mips_cl_insn *insn, const struct mips_opcode *first,
+            const struct mips_opcode *past, struct mips_operand_token *tokens,
+            int opcode_extra, bfd_boolean lax_match)
+{
+  const struct mips_opcode *opcode;
+  const struct mips_opcode *invalid_delay_slot;
+  bfd_boolean seen_valid_for_isa, seen_valid_for_size;
+
+  /* Search for a match, ignoring alternatives that don't satisfy the
+     current ISA or forced_length.  */
+  invalid_delay_slot = 0;
+  seen_valid_for_isa = FALSE;
+  seen_valid_for_size = FALSE;
+  opcode = first;
+  do
+    {
+      gas_assert (strcmp (opcode->name, first->name) == 0);
+      if (is_opcode_valid (opcode))
+       {
+         seen_valid_for_isa = TRUE;
+         if (is_size_valid (opcode))
+           {
+             bfd_boolean delay_slot_ok;
+
+             seen_valid_for_size = TRUE;
+             delay_slot_ok = is_delay_slot_valid (opcode);
+             if (match_insn (insn, opcode, tokens, opcode_extra,
+                             lax_match, delay_slot_ok))
+               {
+                 if (!delay_slot_ok)
+                   {
+                     if (!invalid_delay_slot)
+                       invalid_delay_slot = opcode;
+                   }
+                 else
+                   return TRUE;
+               }
+           }
+       }
+      ++opcode;
+    }
+  while (opcode < past && strcmp (opcode->name, first->name) == 0);
+
+  /* If the only matches we found had the wrong length for the delay slot,
+     pick the first such match.  We'll issue an appropriate warning later.  */
+  if (invalid_delay_slot)
+    {
+      if (match_insn (insn, invalid_delay_slot, tokens, opcode_extra,
+                     lax_match, TRUE))
+       return TRUE;
+      abort ();
+    }
+
+  /* Handle the case where we didn't try to match an instruction because
+     all the alternatives were incompatible with the current ISA.  */
+  if (!seen_valid_for_isa)
+    {
+      match_invalid_for_isa ();
+      return TRUE;
+    }
+
+  /* Handle the case where we didn't try to match an instruction because
+     all the alternatives were of the wrong size.  */
+  if (!seen_valid_for_size)
+    {
+      if (mips_opts.insn32)
+       set_insn_error (0, _("opcode not supported in the `insn32' mode"));
+      else
+       set_insn_error_i
+         (0, _("unrecognized %d-bit version of microMIPS opcode"),
+          8 * forced_insn_length);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Like match_insns, but for MIPS16.  */
+
+static bfd_boolean
+match_mips16_insns (struct mips_cl_insn *insn, const struct mips_opcode *first,
+                   struct mips_operand_token *tokens)
+{
+  const struct mips_opcode *opcode;
+  bfd_boolean seen_valid_for_isa;
+
+  /* Search for a match, ignoring alternatives that don't satisfy the
+     current ISA.  There are no separate entries for extended forms so
+     we deal with forced_length later.  */
+  seen_valid_for_isa = FALSE;
+  opcode = first;
+  do
+    {
+      gas_assert (strcmp (opcode->name, first->name) == 0);
+      if (is_opcode_valid_16 (opcode))
+       {
+         seen_valid_for_isa = TRUE;
+         if (match_mips16_insn (insn, opcode, tokens))
+           return TRUE;
+       }
+      ++opcode;
+    }
+  while (opcode < &mips16_opcodes[bfd_mips16_num_opcodes]
+        && strcmp (opcode->name, first->name) == 0);
+
+  /* Handle the case where we didn't try to match an instruction because
+     all the alternatives were incompatible with the current ISA.  */
+  if (!seen_valid_for_isa)
+    {
+      match_invalid_for_isa ();
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Set up global variables for the start of a new macro.  */
+
+static void
+macro_start (void)
 {
   memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
   memset (&mips_macro_warning.first_insn_sizes, 0,
@@ -6691,16 +7590,16 @@ static const char *
 macro_warning (relax_substateT subtype)
 {
   if (subtype & RELAX_DELAY_SLOT)
-    return _("Macro instruction expanded into multiple instructions"
+    return _("macro instruction expanded into multiple instructions"
             " in a branch delay slot");
   else if (subtype & RELAX_NOMACRO)
-    return _("Macro instruction expanded into multiple instructions");
+    return _("macro instruction expanded into multiple instructions");
   else if (subtype & (RELAX_DELAY_SLOT_SIZE_FIRST
                      | RELAX_DELAY_SLOT_SIZE_SECOND))
     return ((subtype & RELAX_DELAY_SLOT_16BIT)
-           ? _("Macro instruction expanded into a wrong size instruction"
+           ? _("macro instruction expanded into a wrong size instruction"
                " in a 16-bit branch delay slot")
-           : _("Macro instruction expanded into a wrong size instruction"
+           : _("macro instruction expanded into a wrong size instruction"
                " in a 32-bit branch delay slot"));
   else
     return 0;
@@ -7068,33 +7967,6 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
   append_insn (&insn, ep, r, TRUE);
 }
 
-/*
- * Sign-extend 32-bit mode constants that have bit 31 set and all
- * higher bits unset.
- */
-static void
-normalize_constant_expr (expressionS *ex)
-{
-  if (ex->X_op == O_constant
-      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
-    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
-                       - 0x80000000);
-}
-
-/*
- * Sign-extend 32-bit mode address offsets that have bit 31 set and
- * all higher bits unset.
- */
-static void
-normalize_address_expr (expressionS *ex)
-{
-  if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
-       || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
-      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
-    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
-                       - 0x80000000);
-}
-
 /*
  * Generate a "jalr" instruction with a relocation hint to the called
  * function.  This occurs in NewABI PIC code.
@@ -7188,7 +8060,7 @@ macro_build_ldst_constoffset (expressionS *ep, const char *op,
       macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
       if (!mips_opts.at)
-       as_bad (_("Macro used $at after \".set noat\""));
+       as_bad (_("macro used $at after \".set noat\""));
     }
 }
 
@@ -7199,8 +8071,7 @@ macro_build_ldst_constoffset (expressionS *ep, const char *op,
 static void
 set_at (int reg, int unsignedp)
 {
-  if (imm_expr.X_op == O_constant
-      && imm_expr.X_add_number >= -0x8000
+  if (imm_expr.X_add_number >= -0x8000
       && imm_expr.X_add_number < 0x8000)
     macro_build (&imm_expr, unsignedp ? "sltiu" : "slti", "t,r,j",
                 AT, reg, BFD_RELOC_LO16);
@@ -7337,7 +8208,7 @@ load_register (int reg, expressionS *ep, int dbl)
       char value[32];
 
       sprintf_vma (value, ep->X_add_number);
-      as_bad (_("Number (0x%s) larger than 32 bits"), value);
+      as_bad (_("number (0x%s) larger than 32 bits"), value);
       macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
       return;
     }
@@ -7357,7 +8228,7 @@ load_register (int reg, expressionS *ep, int dbl)
       if (ep->X_add_number == 3)
        generic_bignum[3] = 0;
       else if (ep->X_add_number > 4)
-       as_bad (_("Number larger than 64 bits"));
+       as_bad (_("number larger than 64 bits"));
       lo32.X_op = O_constant;
       lo32.X_add_number = generic_bignum[0] + (generic_bignum[1] << 16);
       hi32.X_op = O_constant;
@@ -7773,7 +8644,7 @@ load_address (int reg, expressionS *ep, int *used_at)
     abort ();
 
   if (!mips_opts.at && *used_at == 1)
-    as_bad (_("Macro used $at after \".set noat\""));
+    as_bad (_("macro used $at after \".set noat\""));
 }
 
 /* Move the contents of register SOURCE into register DEST.  */
@@ -8124,7 +8995,8 @@ small_offset_p (unsigned int range, unsigned int align, unsigned int offbits)
 static void
 macro (struct mips_cl_insn *ip, char *str)
 {
-  unsigned int treg, sreg, dreg, breg;
+  const struct mips_operand_array *operands;
+  unsigned int breg, i;
   unsigned int tempreg;
   int mask;
   int used_at = 0;
@@ -8147,12 +9019,17 @@ macro (struct mips_cl_insn *ip, char *str)
   int off;
   int hold_mips_optimize;
   unsigned int align;
+  unsigned int op[MAX_OPERANDS];
 
   gas_assert (! mips_opts.mips16);
 
-  treg = EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
-  dreg = EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
-  sreg = breg = EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
+  operands = insn_operands (ip);
+  for (i = 0; i < MAX_OPERANDS; i++)
+    if (operands->operand[i])
+      op[i] = insn_extract_operand (ip, operands->operand[i]);
+    else
+      op[i] = -1;
+
   mask = ip->insn_mo->mask;
 
   label_expr.X_op = O_constant;
@@ -8183,12 +9060,12 @@ macro (struct mips_cl_insn *ip, char *str)
        micromips_label_expr (&label_expr);
       else
        label_expr.X_add_number = 8;
-      macro_build (&label_expr, "bgez", "s,p", sreg);
-      if (dreg == sreg)
+      macro_build (&label_expr, "bgez", "s,p", op[1]);
+      if (op[0] == op[1])
        macro_build (NULL, "nop", "");
       else
-       move_register (dreg, sreg);
-      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
+       move_register (op[0], op[1]);
+      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", op[0], 0, op[1]);
       if (mips_opts.micromips)
        micromips_add_label ();
 
@@ -8209,11 +9086,11 @@ macro (struct mips_cl_insn *ip, char *str)
       s2 = "dadd";
       if (!mips_opts.micromips)
        goto do_addi;
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= -0x200
+      if (imm_expr.X_add_number >= -0x200
          && imm_expr.X_add_number < 0x200)
        {
-         macro_build (NULL, s, "t,r,.", treg, sreg, imm_expr.X_add_number);
+         macro_build (NULL, s, "t,r,.", op[0], op[1],
+                      (int) imm_expr.X_add_number);
          break;
        }
       goto do_addi_i;
@@ -8222,17 +9099,16 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "daddiu";
       s2 = "daddu";
     do_addi:
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= -0x8000
+      if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (&imm_expr, s, "t,r,j", treg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, s, "t,r,j", op[0], op[1], BFD_RELOC_LO16);
          break;
        }
     do_addi_i:
       used_at = 1;
       load_register (AT, &imm_expr, dbl);
-      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
+      macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
       break;
 
     case M_AND_I:
@@ -8251,24 +9127,23 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "xori";
       s2 = "xor";
     do_bit:
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= 0
+      if (imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
        {
          if (mask != M_NOR_I)
-           macro_build (&imm_expr, s, "t,r,i", treg, sreg, BFD_RELOC_LO16);
+           macro_build (&imm_expr, s, "t,r,i", op[0], op[1], BFD_RELOC_LO16);
          else
            {
              macro_build (&imm_expr, "ori", "t,r,i",
-                          treg, sreg, BFD_RELOC_LO16);
-             macro_build (NULL, "nor", "d,v,t", treg, treg, 0);
+                          op[0], op[1], BFD_RELOC_LO16);
+             macro_build (NULL, "nor", "d,v,t", op[0], op[0], 0);
            }
          break;
        }
 
       used_at = 1;
       load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
+      macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
       break;
 
     case M_BALIGN:
@@ -8278,11 +9153,11 @@ macro (struct mips_cl_insn *ip, char *str)
          macro_build (NULL, "nop", "");
          break;
        case 2:
-         macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
+         macro_build (NULL, "packrl.ph", "d,s,t", op[0], op[0], op[1]);
          break;
        case 1:
        case 3:
-         macro_build (NULL, "balign", "t,s,2", treg, sreg,
+         macro_build (NULL, "balign", "t,s,2", op[0], op[1],
                       (int) imm_expr.X_add_number);
          break;
        default:
@@ -8305,31 +9180,31 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BEQL_I:
     case M_BNE_I:
     case M_BNEL_I:
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
-       treg = 0;
+      if (imm_expr.X_add_number == 0)
+       op[1] = 0;
       else
        {
-         treg = AT;
+         op[1] = AT;
          used_at = 1;
-         load_register (treg, &imm_expr, HAVE_64BIT_GPRS);
+         load_register (op[1], &imm_expr, HAVE_64BIT_GPRS);
        }
       /* Fall through.  */
     case M_BEQL:
     case M_BNEL:
-      macro_build_branch_rsrt (mask, &offset_expr, sreg, treg);
+      macro_build_branch_rsrt (mask, &offset_expr, op[0], op[1]);
       break;
 
     case M_BGEL:
       likely = 1;
     case M_BGE:
-      if (treg == 0)
-       macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, sreg);
-      else if (sreg == 0)
-       macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, treg);
+      if (op[1] == 0)
+       macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, op[0]);
+      else if (op[0] == 0)
+       macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[1]);
       else
        {
          used_at = 1;
-         macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
+         macro_build (NULL, "slt", "d,v,t", AT, op[0], op[1]);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
                                   &offset_expr, AT, ZERO);
        }
@@ -8341,14 +9216,14 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLEZL:
     case M_BLTZL:
     case M_BLTZALL:
-      macro_build_branch_rs (mask, &offset_expr, sreg);
+      macro_build_branch_rs (mask, &offset_expr, op[0]);
       break;
 
     case M_BGTL_I:
       likely = 1;
     case M_BGT_I:
       /* Check for > max integer.  */
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number >= GPR_SMAX)
+      if (imm_expr.X_add_number >= GPR_SMAX)
        {
        do_false:
          /* Result is always false.  */
@@ -8358,36 +9233,34 @@ macro (struct mips_cl_insn *ip, char *str)
            macro_build_branch_rsrt (M_BNEL, &offset_expr, ZERO, ZERO);
          break;
        }
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BGE_I:
     case M_BGEL_I:
       if (mask == M_BGEL_I)
        likely = 1;
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+      if (imm_expr.X_add_number == 0)
        {
          macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ,
-                                &offset_expr, sreg);
+                                &offset_expr, op[0]);
          break;
        }
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+      if (imm_expr.X_add_number == 1)
        {
          macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ,
-                                &offset_expr, sreg);
+                                &offset_expr, op[0]);
          break;
        }
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number <= GPR_SMIN)
+      if (imm_expr.X_add_number <= GPR_SMIN)
        {
        do_true:
          /* result is always true */
-         as_warn (_("Branch %s is always true"), ip->insn_mo->name);
+         as_warn (_("branch %s is always true"), ip->insn_mo->name);
          macro_build (&offset_expr, "b", "p");
          break;
        }
       used_at = 1;
-      set_at (sreg, 0);
+      set_at (op[0], 0);
       macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
                               &offset_expr, AT, ZERO);
       break;
@@ -8395,15 +9268,15 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BGEUL:
       likely = 1;
     case M_BGEU:
-      if (treg == 0)
+      if (op[1] == 0)
        goto do_true;
-      else if (sreg == 0)
+      else if (op[0] == 0)
        macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
-                                &offset_expr, ZERO, treg);
+                                &offset_expr, ZERO, op[1]);
       else
        {
          used_at = 1;
-         macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
+         macro_build (NULL, "sltu", "d,v,t", AT, op[0], op[1]);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
                                   &offset_expr, AT, ZERO);
        }
@@ -8412,28 +9285,25 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BGTUL_I:
       likely = 1;
     case M_BGTU_I:
-      if (sreg == 0
+      if (op[0] == 0
          || (HAVE_32BIT_GPRS
-             && imm_expr.X_op == O_constant
              && imm_expr.X_add_number == -1))
        goto do_false;
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BGEU_I:
     case M_BGEUL_I:
       if (mask == M_BGEUL_I)
        likely = 1;
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+      if (imm_expr.X_add_number == 0)
        goto do_true;
-      else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+      else if (imm_expr.X_add_number == 1)
        macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
-                                &offset_expr, sreg, ZERO);
+                                &offset_expr, op[0], ZERO);
       else
        {
          used_at = 1;
-         set_at (sreg, 1);
+         set_at (op[0], 1);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
                                   &offset_expr, AT, ZERO);
        }
@@ -8442,14 +9312,14 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BGTL:
       likely = 1;
     case M_BGT:
-      if (treg == 0)
-       macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, sreg);
-      else if (sreg == 0)
-       macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, treg);
+      if (op[1] == 0)
+       macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, op[0]);
+      else if (op[0] == 0)
+       macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[1]);
       else
        {
          used_at = 1;
-         macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
+         macro_build (NULL, "slt", "d,v,t", AT, op[1], op[0]);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
                                   &offset_expr, AT, ZERO);
        }
@@ -8458,15 +9328,15 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BGTUL:
       likely = 1;
     case M_BGTU:
-      if (treg == 0)
+      if (op[1] == 0)
        macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
-                                &offset_expr, sreg, ZERO);
-      else if (sreg == 0)
+                                &offset_expr, op[0], ZERO);
+      else if (op[0] == 0)
        goto do_false;
       else
        {
          used_at = 1;
-         macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
+         macro_build (NULL, "sltu", "d,v,t", AT, op[1], op[0]);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
                                   &offset_expr, AT, ZERO);
        }
@@ -8475,14 +9345,14 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLEL:
       likely = 1;
     case M_BLE:
-      if (treg == 0)
-       macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, sreg);
-      else if (sreg == 0)
-       macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, treg);
+      if (op[1] == 0)
+       macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[0]);
+      else if (op[0] == 0)
+       macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, op[1]);
       else
        {
          used_at = 1;
-         macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
+         macro_build (NULL, "slt", "d,v,t", AT, op[1], op[0]);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
                                   &offset_expr, AT, ZERO);
        }
@@ -8491,24 +9361,22 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLEL_I:
       likely = 1;
     case M_BLE_I:
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number >= GPR_SMAX)
+      if (imm_expr.X_add_number >= GPR_SMAX)
        goto do_true;
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BLT_I:
     case M_BLTL_I:
       if (mask == M_BLTL_I)
        likely = 1;
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
-       macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, sreg);
-      else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
-       macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, sreg);
+      if (imm_expr.X_add_number == 0)
+       macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[0]);
+      else if (imm_expr.X_add_number == 1)
+       macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[0]);
       else
        {
          used_at = 1;
-         set_at (sreg, 0);
+         set_at (op[0], 0);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
                                   &offset_expr, AT, ZERO);
        }
@@ -8517,15 +9385,15 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLEUL:
       likely = 1;
     case M_BLEU:
-      if (treg == 0)
+      if (op[1] == 0)
        macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
-                                &offset_expr, sreg, ZERO);
-      else if (sreg == 0)
+                                &offset_expr, op[0], ZERO);
+      else if (op[0] == 0)
        goto do_true;
       else
        {
          used_at = 1;
-         macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
+         macro_build (NULL, "sltu", "d,v,t", AT, op[1], op[0]);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
                                   &offset_expr, AT, ZERO);
        }
@@ -8534,28 +9402,25 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLEUL_I:
       likely = 1;
     case M_BLEU_I:
-      if (sreg == 0
+      if (op[0] == 0
          || (HAVE_32BIT_GPRS
-             && imm_expr.X_op == O_constant
              && imm_expr.X_add_number == -1))
        goto do_true;
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BLTU_I:
     case M_BLTUL_I:
       if (mask == M_BLTUL_I)
        likely = 1;
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+      if (imm_expr.X_add_number == 0)
        goto do_false;
-      else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+      else if (imm_expr.X_add_number == 1)
        macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
-                                &offset_expr, sreg, ZERO);
+                                &offset_expr, op[0], ZERO);
       else
        {
          used_at = 1;
-         set_at (sreg, 1);
+         set_at (op[0], 1);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
                                   &offset_expr, AT, ZERO);
        }
@@ -8564,14 +9429,14 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLTL:
       likely = 1;
     case M_BLT:
-      if (treg == 0)
-       macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, sreg);
-      else if (sreg == 0)
-       macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, treg);
+      if (op[1] == 0)
+       macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[0]);
+      else if (op[0] == 0)
+       macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, op[1]);
       else
        {
          used_at = 1;
-         macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
+         macro_build (NULL, "slt", "d,v,t", AT, op[0], op[1]);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
                                   &offset_expr, AT, ZERO);
        }
@@ -8580,116 +9445,20 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_BLTUL:
       likely = 1;
     case M_BLTU:
-      if (treg == 0)
+      if (op[1] == 0)
        goto do_false;
-      else if (sreg == 0)
+      else if (op[0] == 0)
        macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
-                                &offset_expr, ZERO, treg);
+                                &offset_expr, ZERO, op[1]);
       else
        {
          used_at = 1;
-         macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
+         macro_build (NULL, "sltu", "d,v,t", AT, op[0], op[1]);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
                                   &offset_expr, AT, ZERO);
        }
       break;
 
-    case M_DEXT:
-      {
-       /* Use unsigned arithmetic.  */
-       addressT pos;
-       addressT size;
-
-       if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
-         {
-           as_bad (_("Unsupported large constant"));
-           pos = size = 1;
-         }
-       else
-         {
-           pos = imm_expr.X_add_number;
-           size = imm2_expr.X_add_number;
-         }
-
-       if (pos > 63)
-         {
-           report_bad_range (ip, 3, pos, 0, 63, FALSE);
-           pos = 1;
-         }
-       if (size == 0 || size > 64 || (pos + size - 1) > 63)
-         {
-           report_bad_field (pos, size);
-           size = 1;
-         }
-
-       if (size <= 32 && pos < 32)
-         {
-           s = "dext";
-           fmt = "t,r,+A,+C";
-         }
-       else if (size <= 32)
-         {
-           s = "dextu";
-           fmt = "t,r,+E,+H";
-         }
-       else
-         {
-           s = "dextm";
-           fmt = "t,r,+A,+G";
-         }
-       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
-                    (int) (size - 1));
-      }
-      break;
-
-    case M_DINS:
-      {
-       /* Use unsigned arithmetic.  */
-       addressT pos;
-       addressT size;
-
-       if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
-         {
-           as_bad (_("Unsupported large constant"));
-           pos = size = 1;
-         }
-       else
-         {
-           pos = imm_expr.X_add_number;
-           size = imm2_expr.X_add_number;
-         }
-
-       if (pos > 63)
-         {
-           report_bad_range (ip, 3, pos, 0, 63, FALSE);
-           pos = 1;
-         }
-       if (size == 0 || size > 64 || (pos + size - 1) > 63)
-         {
-           report_bad_field (pos, size);
-           size = 1;
-         }
-
-       if (pos < 32 && (pos + size - 1) < 32)
-         {
-           s = "dins";
-           fmt = "t,r,+A,+B";
-         }
-       else if (pos >= 32)
-         {
-           s = "dinsu";
-           fmt = "t,r,+E,+F";
-         }
-       else
-         {
-           s = "dinsm";
-           fmt = "t,r,+A,+F";
-         }
-       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
-                    (int) (pos + size - 1));
-      }
-      break;
-
     case M_DDIV_3:
       dbl = 1;
     case M_DIV_3:
@@ -8700,9 +9469,9 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_REM_3:
       s = "mfhi";
     do_div3:
-      if (treg == 0)
+      if (op[2] == 0)
        {
-         as_warn (_("Divide by zero."));
+         as_warn (_("divide by zero"));
          if (mips_trap)
            macro_build (NULL, "teq", TRAP_FMT, ZERO, ZERO, 7);
          else
@@ -8713,8 +9482,8 @@ macro (struct mips_cl_insn *ip, char *str)
       start_noreorder ();
       if (mips_trap)
        {
-         macro_build (NULL, "teq", TRAP_FMT, treg, ZERO, 7);
-         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+         macro_build (NULL, "teq", TRAP_FMT, op[2], ZERO, 7);
+         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", op[1], op[2]);
        }
       else
        {
@@ -8722,8 +9491,8 @@ macro (struct mips_cl_insn *ip, char *str)
            micromips_label_expr (&label_expr);
          else
            label_expr.X_add_number = 8;
-         macro_build (&label_expr, "bne", "s,t,p", treg, ZERO);
-         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+         macro_build (&label_expr, "bne", "s,t,p", op[2], ZERO);
+         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", op[1], op[2]);
          macro_build (NULL, "break", BRK_FMT, 7);
          if (mips_opts.micromips)
            micromips_add_label ();
@@ -8735,7 +9504,7 @@ macro (struct mips_cl_insn *ip, char *str)
        micromips_label_expr (&label_expr);
       else
        label_expr.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
-      macro_build (&label_expr, "bne", "s,t,p", treg, AT);
+      macro_build (&label_expr, "bne", "s,t,p", op[2], AT);
       if (dbl)
        {
          expr1.X_add_number = 1;
@@ -8749,7 +9518,7 @@ macro (struct mips_cl_insn *ip, char *str)
        }
       if (mips_trap)
        {
-         macro_build (NULL, "teq", TRAP_FMT, sreg, AT, 6);
+         macro_build (NULL, "teq", TRAP_FMT, op[1], AT, 6);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          end_noreorder ();
@@ -8760,7 +9529,7 @@ macro (struct mips_cl_insn *ip, char *str)
            micromips_label_expr (&label_expr);
          else
            label_expr.X_add_number = 8;
-         macro_build (&label_expr, "bne", "s,t,p", sreg, AT);
+         macro_build (&label_expr, "bne", "s,t,p", op[1], AT);
          macro_build (NULL, "nop", "");
 
          /* We want to close the noreorder block as soon as possible, so
@@ -8771,7 +9540,7 @@ macro (struct mips_cl_insn *ip, char *str)
        }
       if (mips_opts.micromips)
        micromips_add_label ();
-      macro_build (NULL, s, MFHL_FMT, dreg);
+      macro_build (NULL, s, MFHL_FMT, op[0]);
       break;
 
     case M_DIV_3I:
@@ -8810,40 +9579,36 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "ddivu";
       s2 = "mfhi";
     do_divi:
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+      if (imm_expr.X_add_number == 0)
        {
-         as_warn (_("Divide by zero."));
+         as_warn (_("divide by zero"));
          if (mips_trap)
            macro_build (NULL, "teq", TRAP_FMT, ZERO, ZERO, 7);
          else
            macro_build (NULL, "break", BRK_FMT, 7);
          break;
        }
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
+      if (imm_expr.X_add_number == 1)
        {
          if (strcmp (s2, "mflo") == 0)
-           move_register (dreg, sreg);
+           move_register (op[0], op[1]);
          else
-           move_register (dreg, ZERO);
+           move_register (op[0], ZERO);
          break;
        }
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number == -1
-         && s[strlen (s) - 1] != 'u')
+      if (imm_expr.X_add_number == -1 && s[strlen (s) - 1] != 'u')
        {
          if (strcmp (s2, "mflo") == 0)
-           {
-             macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
-           }
+           macro_build (NULL, dbl ? "dneg" : "neg", "d,w", op[0], op[1]);
          else
-           move_register (dreg, ZERO);
+           move_register (op[0], ZERO);
          break;
        }
 
       used_at = 1;
       load_register (AT, &imm_expr, dbl);
-      macro_build (NULL, s, "z,s,t", sreg, AT);
-      macro_build (NULL, s2, MFHL_FMT, dreg);
+      macro_build (NULL, s, "z,s,t", op[1], AT);
+      macro_build (NULL, s2, MFHL_FMT, op[0]);
       break;
 
     case M_DIVU_3:
@@ -8865,8 +9630,8 @@ macro (struct mips_cl_insn *ip, char *str)
       start_noreorder ();
       if (mips_trap)
        {
-         macro_build (NULL, "teq", TRAP_FMT, treg, ZERO, 7);
-         macro_build (NULL, s, "z,s,t", sreg, treg);
+         macro_build (NULL, "teq", TRAP_FMT, op[2], ZERO, 7);
+         macro_build (NULL, s, "z,s,t", op[1], op[2]);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          end_noreorder ();
@@ -8877,8 +9642,8 @@ macro (struct mips_cl_insn *ip, char *str)
            micromips_label_expr (&label_expr);
          else
            label_expr.X_add_number = 8;
-         macro_build (&label_expr, "bne", "s,t,p", treg, ZERO);
-         macro_build (NULL, s, "z,s,t", sreg, treg);
+         macro_build (&label_expr, "bne", "s,t,p", op[2], ZERO);
+         macro_build (NULL, s, "z,s,t", op[1], op[2]);
 
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
@@ -8887,7 +9652,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (mips_opts.micromips)
            micromips_add_label ();
        }
-      macro_build (NULL, s2, MFHL_FMT, dreg);
+      macro_build (NULL, s2, MFHL_FMT, op[0]);
       break;
 
     case M_DLCA_AB:
@@ -8902,6 +9667,7 @@ macro (struct mips_cl_insn *ip, char *str)
       /* Load the address of a symbol into a register.  If breg is not
         zero, we then add a base register to it.  */
 
+      breg = op[2];
       if (dbl && HAVE_32BIT_GPRS)
        as_warn (_("dla used to load 32-bit register"));
 
@@ -8910,25 +9676,23 @@ macro (struct mips_cl_insn *ip, char *str)
 
       if (small_offset_p (0, align, 16))
        {
-         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, breg,
+         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", op[0], breg,
                       -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
          break;
        }
 
-      if (mips_opts.at && (treg == breg))
+      if (mips_opts.at && (op[0] == breg))
        {
          tempreg = AT;
          used_at = 1;
        }
       else
-       {
-         tempreg = treg;
-       }
+       tempreg = op[0];
 
       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;
        }
 
@@ -9016,7 +9780,7 @@ macro (struct mips_cl_insn *ip, char *str)
                  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);
@@ -9107,13 +9871,13 @@ macro (struct mips_cl_insn *ip, char *str)
                 current AT (from the global offset table) and the
                 register into the register now, and pretend we were
                 not using a base register.  */
-             if (breg == treg)
+             if (breg == op[0])
                {
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              treg, AT, breg);
+                              op[0], AT, breg);
                  breg = 0;
-                 tempreg = treg;
+                 tempreg = op[0];
                }
              add_got_offset_hilo (tempreg, &offset_expr, AT);
              used_at = 1;
@@ -9163,6 +9927,8 @@ macro (struct mips_cl_insn *ip, char *str)
                }
              else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
                {
+                 unsigned int dreg;
+
                  /* If we are going to add in a base register, and the
                     target register and the base register are the same,
                     then we are using AT as a temporary register.  Since
@@ -9170,14 +9936,14 @@ macro (struct mips_cl_insn *ip, char *str)
                     current AT (from the global offset table) and the
                     register into the register now, and pretend we were
                     not using a base register.  */
-                 if (breg != treg)
+                 if (breg != op[0])
                    dreg = tempreg;
                  else
                    {
                      gas_assert (tempreg == AT);
                      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                                  treg, AT, breg);
-                     dreg = treg;
+                                  op[0], AT, breg);
+                     dreg = op[0];
                      add_breg_early = 1;
                    }
 
@@ -9198,9 +9964,9 @@ macro (struct mips_cl_insn *ip, char *str)
              if (add_breg_early)
                {
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              treg, tempreg, breg);
+                              op[0], tempreg, breg);
                  breg = 0;
-                 tempreg = treg;
+                 tempreg = op[0];
                }
              relax_end ();
            }
@@ -9302,6 +10068,8 @@ macro (struct mips_cl_insn *ip, char *str)
            }
          else
            {
+             unsigned int dreg;
+
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -9309,15 +10077,15 @@ macro (struct mips_cl_insn *ip, char *str)
                 current AT (from the global offset table) and the
                 register into the register now, and pretend we were
                 not using a base register.  */
-             if (breg != treg)
+             if (breg != op[0])
                dreg = tempreg;
              else
                {
                  gas_assert (tempreg == AT);
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              treg, AT, breg);
-                 dreg = treg;
+                              op[0], AT, breg);
+                 dreg = op[0];
                }
 
              load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
@@ -9351,15 +10119,15 @@ macro (struct mips_cl_insn *ip, char *str)
            }
          else
            {
-             if (breg == treg)
+             if (breg == op[0])
                {
                  /* We must add in the base register now, as in the
                     external symbol case.  */
                  gas_assert (tempreg == AT);
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              treg, AT, breg);
-                 tempreg = treg;
+                              op[0], AT, breg);
+                 tempreg = op[0];
                  /* We set breg to 0 because we have arranged to add
                     it in in both cases.  */
                  breg = 0;
@@ -9438,6 +10206,8 @@ macro (struct mips_cl_insn *ip, char *str)
            }
          else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
            {
+             unsigned int dreg;
+
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -9445,14 +10215,14 @@ macro (struct mips_cl_insn *ip, char *str)
                 current AT (from the global offset table) and the
                 register into the register now, and pretend we were
                 not using a base register.  */
-             if (breg != treg)
+             if (breg != op[0])
                dreg = tempreg;
              else
                {
                  gas_assert (tempreg == AT);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              treg, AT, breg);
-                 dreg = treg;
+                              op[0], AT, breg);
+                 dreg = op[0];
                  add_breg_early = 1;
                }
 
@@ -9473,9 +10243,9 @@ macro (struct mips_cl_insn *ip, char *str)
          if (add_breg_early)
            {
              macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          treg, tempreg, breg);
+                          op[0], tempreg, breg);
              breg = 0;
-             tempreg = treg;
+             tempreg = op[0];
            }
          relax_end ();
        }
@@ -9483,12 +10253,12 @@ macro (struct mips_cl_insn *ip, char *str)
        abort ();
 
       if (breg != 0)
-       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
+       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", op[0], tempreg, breg);
       break;
 
     case M_MSGSND:
       gas_assert (!mips_opts.micromips);
-      macro_build (NULL, "c2", "C", (treg << 16) | 0x01);
+      macro_build (NULL, "c2", "C", (op[0] << 16) | 0x01);
       break;
 
     case M_MSGLD:
@@ -9498,7 +10268,7 @@ macro (struct mips_cl_insn *ip, char *str)
 
     case M_MSGLD_T:
       gas_assert (!mips_opts.micromips);
-      macro_build (NULL, "c2", "C", (treg << 16) | 0x02);
+      macro_build (NULL, "c2", "C", (op[0] << 16) | 0x02);
       break;
 
     case M_MSGWAIT:
@@ -9508,7 +10278,7 @@ macro (struct mips_cl_insn *ip, char *str)
 
     case M_MSGWAIT_T:
       gas_assert (!mips_opts.micromips);
-      macro_build (NULL, "c2", "C", (treg << 16) | 0x03);
+      macro_build (NULL, "c2", "C", (op[0] << 16) | 0x03);
       break;
 
     case M_J_A:
@@ -9525,19 +10295,21 @@ macro (struct mips_cl_insn *ip, char *str)
         generating PIC code they expand to multi-instruction
         sequences.  Normally they are simple instructions.  */
     case M_JALS_1:
-      dreg = RA;
+      op[1] = op[0];
+      op[0] = RA;
       /* Fall through.  */
     case M_JALS_2:
       gas_assert (mips_opts.micromips);
       if (mips_opts.insn32)
        {
-         as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
+         as_bad (_("opcode not supported in the `insn32' mode `%s'"), str);
          break;
        }
       jals = 1;
       goto jal;
     case M_JAL_1:
-      dreg = RA;
+      op[1] = op[0];
+      op[0] = RA;
       /* Fall through.  */
     case M_JAL_2:
     jal:
@@ -9546,18 +10318,18 @@ macro (struct mips_cl_insn *ip, char *str)
          s = jals ? "jalrs" : "jalr";
          if (mips_opts.micromips
              && !mips_opts.insn32
-             && dreg == RA
+             && op[0] == RA
              && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
-           macro_build (NULL, s, "mj", sreg);
+           macro_build (NULL, s, "mj", op[1]);
          else
-           macro_build (NULL, s, JALR_FMT, dreg, sreg);
+           macro_build (NULL, s, JALR_FMT, op[0], op[1]);
        }
       else
        {
          int cprestore = (mips_pic == SVR4_PIC && !HAVE_NEWABI
                           && mips_cprestore_offset >= 0);
 
-         if (sreg != PIC_CALL_REG)
+         if (op[1] != PIC_CALL_REG)
            as_warn (_("MIPS PIC call to register other than $25"));
 
          s = ((mips_opts.micromips
@@ -9566,26 +10338,26 @@ macro (struct mips_cl_insn *ip, char *str)
               ? "jalrs" : "jalr");
          if (mips_opts.micromips
              && !mips_opts.insn32
-             && dreg == RA
+             && op[0] == RA
              && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
-           macro_build (NULL, s, "mj", sreg);
+           macro_build (NULL, s, "mj", op[1]);
          else
-           macro_build (NULL, s, JALR_FMT, dreg, sreg);
+           macro_build (NULL, s, JALR_FMT, op[0], op[1]);
          if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
            {
              if (mips_cprestore_offset < 0)
-               as_warn (_("No .cprestore pseudo-op used in PIC code"));
+               as_warn (_("no .cprestore pseudo-op used in PIC code"));
              else
                {
                  if (!mips_frame_reg_valid)
                    {
-                     as_warn (_("No .frame pseudo-op used in PIC code"));
+                     as_warn (_("no .frame pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_frame_reg_valid = 1;
                    }
                  if (!mips_cprestore_valid)
                    {
-                     as_warn (_("No .cprestore pseudo-op used in PIC code"));
+                     as_warn (_("no .cprestore pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_cprestore_valid = 1;
                    }
@@ -9606,7 +10378,7 @@ macro (struct mips_cl_insn *ip, char *str)
       gas_assert (mips_opts.micromips);
       if (mips_opts.insn32)
        {
-         as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
+         as_bad (_("opcode not supported in the `insn32' mode `%s'"), str);
          break;
        }
       jals = 1;
@@ -9718,18 +10490,18 @@ macro (struct mips_cl_insn *ip, char *str)
              macro_build_jalr (&offset_expr, mips_cprestore_offset >= 0);
 
              if (mips_cprestore_offset < 0)
-               as_warn (_("No .cprestore pseudo-op used in PIC code"));
+               as_warn (_("no .cprestore pseudo-op used in PIC code"));
              else
                {
                  if (!mips_frame_reg_valid)
                    {
-                     as_warn (_("No .frame pseudo-op used in PIC code"));
+                     as_warn (_("no .frame pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_frame_reg_valid = 1;
                    }
                  if (!mips_cprestore_valid)
                    {
-                     as_warn (_("No .cprestore pseudo-op used in PIC code"));
+                     as_warn (_("no .cprestore pseudo-op used in PIC code"));
                      /* Quiet this warning.  */
                      mips_cprestore_valid = 1;
                    }
@@ -9744,7 +10516,7 @@ macro (struct mips_cl_insn *ip, char *str)
            }
        }
       else if (mips_pic == VXWORKS_PIC)
-       as_bad (_("Non-PIC jump used in PIC library"));
+       as_bad (_("non-PIC jump used in PIC library"));
       else
        abort ();
 
@@ -9822,13 +10594,11 @@ macro (struct mips_cl_insn *ip, char *str)
       goto ld_st;
     case M_ACLR_AB:
       s = "aclr";
-      treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
       fmt = "\\,~(b)";
       offbits = 12;
       goto ld_st;
     case M_ASET_AB:
       s = "aset";
-      treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
       fmt = "\\,~(b)";
       offbits = 12;
       goto ld_st;
@@ -9904,7 +10674,7 @@ macro (struct mips_cl_insn *ip, char *str)
       goto ld_st;
     case M_LQC2_AB:
       s = "lqc2";
-      fmt = "E,o(b)";
+      fmt = "+7,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
@@ -9968,10 +10738,10 @@ macro (struct mips_cl_insn *ip, char *str)
 
     ld:
       /* We don't want to use $0 as tempreg.  */
-      if (breg == treg + lp || treg + lp == ZERO)
+      if (op[2] == op[0] + lp || op[0] + lp == ZERO)
        goto ld_st;
       else
-       tempreg = treg + lp;
+       tempreg = op[0] + lp;
       goto ld_noat;
 
     case M_SB_AB:
@@ -10068,7 +10838,7 @@ macro (struct mips_cl_insn *ip, char *str)
       goto ld_st;
     case M_SQC2_AB:
       s = "sqc2";
-      fmt = "E,o(b)";
+      fmt = "+7,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
@@ -10116,20 +10886,21 @@ macro (struct mips_cl_insn *ip, char *str)
     ld_st:
       tempreg = AT;
     ld_noat:
+      breg = op[2];
       if (small_offset_p (0, align, 16))
        {
          /* The first case exists for M_LD_AB and M_SD_AB, which are
             macros for o32 but which should act like normal instructions
             otherwise.  */
          if (offbits == 16)
-           macro_build (&offset_expr, s, fmt, treg, -1, offset_reloc[0],
+           macro_build (&offset_expr, s, fmt, op[0], -1, offset_reloc[0],
                         offset_reloc[1], offset_reloc[2], breg);
          else if (small_offset_p (0, align, offbits))
            {
              if (offbits == 0)
-               macro_build (NULL, s, fmt, treg, breg);
+               macro_build (NULL, s, fmt, op[0], breg);
              else
-               macro_build (NULL, s, fmt, treg,
+               macro_build (NULL, s, fmt, op[0],
                             (int) offset_expr.X_add_number, breg);
            }
          else
@@ -10140,9 +10911,9 @@ macro (struct mips_cl_insn *ip, char *str)
                           tempreg, breg, -1, offset_reloc[0],
                           offset_reloc[1], offset_reloc[2]);
              if (offbits == 0)
-               macro_build (NULL, s, fmt, treg, tempreg);
+               macro_build (NULL, s, fmt, op[0], tempreg);
              else
-               macro_build (NULL, s, fmt, treg, 0, tempreg);
+               macro_build (NULL, s, fmt, op[0], 0, tempreg);
            }
          break;
        }
@@ -10153,7 +10924,7 @@ macro (struct mips_cl_insn *ip, char *str)
       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;
        }
 
@@ -10163,7 +10934,7 @@ macro (struct mips_cl_insn *ip, char *str)
          char value [32];
 
          sprintf_vma (value, offset_expr.X_add_number);
-         as_bad (_("Number (0x%s) larger than 32 bits"), value);
+         as_bad (_("number (0x%s) larger than 32 bits"), value);
        }
 
       /* A constant expression in PIC code can be handled just as it
@@ -10183,12 +10954,12 @@ macro (struct mips_cl_insn *ip, char *str)
              if (offset_expr.X_add_number != 0)
                macro_build (&offset_expr, ADDRESS_ADDI_INSN,
                             "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
-             macro_build (NULL, s, fmt, treg, tempreg);
+             macro_build (NULL, s, fmt, op[0], tempreg);
            }
          else if (offbits == 16)
-           macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+           macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
          else
-           macro_build (NULL, s, fmt, treg,
+           macro_build (NULL, s, fmt, op[0],
                         (int) offset_expr.X_add_number, tempreg);
        }
       else if (offbits != 16)
@@ -10201,29 +10972,29 @@ macro (struct mips_cl_insn *ip, char *str)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
          if (offbits == 0)
-           macro_build (NULL, s, fmt, treg, tempreg);
+           macro_build (NULL, s, fmt, op[0], tempreg);
          else
-           macro_build (NULL, s, fmt, treg, 0, tempreg);
+           macro_build (NULL, s, fmt, op[0], 0, tempreg);
        }
       else if (mips_pic == NO_PIC)
        {
          /* If this is a reference to a GP relative symbol, and there
             is no base register, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
+              <op>     op[0],<sym>($gp)        (BFD_RELOC_GPREL16)
             Otherwise, if there is no base register, we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_LO16)
             If we have a constant, we need two instructions anyhow,
             so we always use the latter form.
 
             If we have a base register, and this is a reference to a
             GP relative symbol, we want
               addu     $tempreg,$breg,$gp
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_GPREL16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_GPREL16)
             Otherwise we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               addu     $tempreg,$tempreg,$breg
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_LO16)
             With a constant we always use the latter case.
 
             With 64bit address space and no base register and $at usable,
@@ -10233,7 +11004,7 @@ macro (struct mips_cl_insn *ip, char *str)
               daddiu   $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHER)
               dsll32   $tempreg,0
               daddu    $tempreg,$at
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_LO16)
             If we have a base register, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHEST)
               lui      $at,<sym>               (BFD_RELOC_HI16_S)
@@ -10241,7 +11012,7 @@ macro (struct mips_cl_insn *ip, char *str)
               daddu    $at,$breg
               dsll32   $tempreg,0
               daddu    $tempreg,$at
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_LO16)
 
             Without $at we can't generate the optimal path for superscalar
             processors here since this would require two temporary registers.
@@ -10250,7 +11021,7 @@ macro (struct mips_cl_insn *ip, char *str)
               dsll     $tempreg,16
               daddiu   $tempreg,<sym>          (BFD_RELOC_HI16_S)
               dsll     $tempreg,16
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_LO16)
             If we have a base register, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHEST)
               daddiu   $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHER)
@@ -10258,7 +11029,7 @@ macro (struct mips_cl_insn *ip, char *str)
               daddiu   $tempreg,<sym>          (BFD_RELOC_HI16_S)
               dsll     $tempreg,16
               daddu    $tempreg,$tempreg,$breg
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_LO16)
 
             For GP relative symbols in 64bit address space we can use
             the same sequence as in 32bit address space.  */
@@ -10270,14 +11041,14 @@ macro (struct mips_cl_insn *ip, char *str)
                  relax_start (offset_expr.X_add_symbol);
                  if (breg == 0)
                    {
-                     macro_build (&offset_expr, s, fmt, treg,
+                     macro_build (&offset_expr, s, fmt, op[0],
                                   BFD_RELOC_GPREL16, mips_gp_register);
                    }
                  else
                    {
                      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                                   tempreg, breg, mips_gp_register);
-                     macro_build (&offset_expr, s, fmt, treg,
+                     macro_build (&offset_expr, s, fmt, op[0],
                                   BFD_RELOC_GPREL16, tempreg);
                    }
                  relax_switch ();
@@ -10295,7 +11066,7 @@ macro (struct mips_cl_insn *ip, char *str)
                    macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
                  macro_build (NULL, "dsll32", SHFT_FMT, tempreg, tempreg, 0);
                  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
-                 macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
+                 macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_LO16,
                               tempreg);
                  used_at = 1;
                }
@@ -10312,7 +11083,7 @@ macro (struct mips_cl_insn *ip, char *str)
                  if (breg != 0)
                    macro_build (NULL, "daddu", "d,v,t",
                                 tempreg, tempreg, breg);
-                 macro_build (&offset_expr, s, fmt, treg,
+                 macro_build (&offset_expr, s, fmt, op[0],
                               BFD_RELOC_LO16, tempreg);
                }
 
@@ -10327,12 +11098,12 @@ macro (struct mips_cl_insn *ip, char *str)
                  && !nopic_need_relax (offset_expr.X_add_symbol, 1))
                {
                  relax_start (offset_expr.X_add_symbol);
-                 macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_GPREL16,
+                 macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_GPREL16,
                               mips_gp_register);
                  relax_switch ();
                }
              macro_build_lui (&offset_expr, tempreg);
-             macro_build (&offset_expr, s, fmt, treg,
+             macro_build (&offset_expr, s, fmt, op[0],
                           BFD_RELOC_LO16, tempreg);
              if (mips_relax.sequence)
                relax_end ();
@@ -10345,14 +11116,14 @@ macro (struct mips_cl_insn *ip, char *str)
                  relax_start (offset_expr.X_add_symbol);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               tempreg, breg, mips_gp_register);
-                 macro_build (&offset_expr, s, fmt, treg,
+                 macro_build (&offset_expr, s, fmt, op[0],
                               BFD_RELOC_GPREL16, tempreg);
                  relax_switch ();
                }
              macro_build_lui (&offset_expr, tempreg);
              macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                           tempreg, tempreg, breg);
-             macro_build (&offset_expr, s, fmt, treg,
+             macro_build (&offset_expr, s, fmt, op[0],
                           BFD_RELOC_LO16, tempreg);
              if (mips_relax.sequence)
                relax_end ();
@@ -10365,16 +11136,16 @@ macro (struct mips_cl_insn *ip, char *str)
          /* If this is a reference to an external symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
-              <op>     $treg,0($tempreg)
+              <op>     op[0],0($tempreg)
             Otherwise we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
-              <op>     $treg,0($tempreg)
+              <op>     op[0],0($tempreg)
 
             For NewABI, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)
 
             If there is a base register, we add it to $tempreg before
             the <op>.  If there is a constant, we stick it in the
@@ -10390,7 +11161,7 @@ macro (struct mips_cl_insn *ip, char *str)
              if (breg != 0)
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                             tempreg, tempreg, breg);
-             macro_build (&offset_expr, s, fmt, treg,
+             macro_build (&offset_expr, s, fmt, op[0],
                           BFD_RELOC_MIPS_GOT_OFST, tempreg);
              break;
            }
@@ -10410,7 +11181,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+         macro_build (&expr1, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
        }
       else if (mips_big_got && !HAVE_NEWABI)
        {
@@ -10420,12 +11191,12 @@ macro (struct mips_cl_insn *ip, char *str)
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
               addu     $tempreg,$tempreg,$gp
               lw       $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
-              <op>     $treg,0($tempreg)
+              <op>     op[0],0($tempreg)
             Otherwise we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
-              <op>     $treg,0($tempreg)
+              <op>     op[0],0($tempreg)
             If there is a base register, we add it to $tempreg before
             the <op>.  If there is a constant, we stick it in the
             <op> instruction.  We don't handle constants larger than
@@ -10459,7 +11230,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+         macro_build (&expr1, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
        }
       else if (mips_big_got && HAVE_NEWABI)
        {
@@ -10467,10 +11238,10 @@ macro (struct mips_cl_insn *ip, char *str)
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
               add      $tempreg,$tempreg,$gp
               lw       $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
-              <op>     $treg,<ofst>($tempreg)
+              <op>     op[0],<ofst>($tempreg)
             Otherwise, for local symbols, we want:
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
+              <op>     op[0],<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
          gas_assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
@@ -10487,7 +11258,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+         macro_build (&expr1, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
 
          relax_switch ();
          offset_expr.X_add_number = expr1.X_add_number;
@@ -10496,7 +11267,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (&offset_expr, s, fmt, treg,
+         macro_build (&offset_expr, s, fmt, op[0],
                       BFD_RELOC_MIPS_GOT_OFST, tempreg);
          relax_end ();
        }
@@ -10510,7 +11281,7 @@ macro (struct mips_cl_insn *ip, char *str)
       gas_assert (mips_opts.insn32);
       start_noreorder ();
       macro_build (NULL, "jr", "s", RA);
-      expr1.X_add_number = EXTRACT_OPERAND (1, IMMP, *ip) << 2;
+      expr1.X_add_number = op[0] << 2;
       macro_build (&expr1, "addiu", "t,r,j", SP, SP, BFD_RELOC_LO16);
       end_noreorder ();
       break;
@@ -10518,18 +11289,18 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_JRC:
       gas_assert (mips_opts.micromips);
       gas_assert (mips_opts.insn32);
-      macro_build (NULL, "jr", "s", sreg);
+      macro_build (NULL, "jr", "s", op[0]);
       if (mips_opts.noreorder)
        macro_build (NULL, "nop", "");
       break;
 
     case M_LI:
     case M_LI_S:
-      load_register (treg, &imm_expr, 0);
+      load_register (op[0], &imm_expr, 0);
       break;
 
     case M_DLI:
-      load_register (treg, &imm_expr, 1);
+      load_register (op[0], &imm_expr, 1);
       break;
 
     case M_LI_SS:
@@ -10537,17 +11308,18 @@ macro (struct mips_cl_insn *ip, char *str)
        {
          used_at = 1;
          load_register (AT, &imm_expr, 0);
-         macro_build (NULL, "mtc1", "t,G", AT, treg);
+         macro_build (NULL, "mtc1", "t,G", AT, op[0]);
          break;
        }
       else
        {
-         gas_assert (offset_expr.X_op == O_symbol
+         gas_assert (imm_expr.X_op == O_absent
+                     && offset_expr.X_op == O_symbol
                      && strcmp (segment_name (S_GET_SEGMENT
                                               (offset_expr.X_add_symbol)),
                                 ".lit4") == 0
                      && offset_expr.X_add_number == 0);
-         macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
+         macro_build (&offset_expr, "lwc1", "T,o(b)", op[0],
                       BFD_RELOC_MIPS_LITERAL, mips_gp_register);
          break;
        }
@@ -10557,23 +11329,23 @@ macro (struct mips_cl_insn *ip, char *str)
          wide, IMM_EXPR is the entire value.  Otherwise IMM_EXPR is the high
          order 32 bits of the value and the low order 32 bits are either
          zero or in OFFSET_EXPR.  */
-      if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
+      if (imm_expr.X_op == O_constant)
        {
          if (HAVE_64BIT_GPRS)
-           load_register (treg, &imm_expr, 1);
+           load_register (op[0], &imm_expr, 1);
          else
            {
              int hreg, lreg;
 
              if (target_big_endian)
                {
-                 hreg = treg;
-                 lreg = treg + 1;
+                 hreg = op[0];
+                 lreg = op[0] + 1;
                }
              else
                {
-                 hreg = treg + 1;
-                 lreg = treg;
+                 hreg = op[0] + 1;
+                 lreg = op[0];
                }
 
              if (hreg <= 31)
@@ -10591,6 +11363,7 @@ macro (struct mips_cl_insn *ip, char *str)
            }
          break;
        }
+      gas_assert (imm_expr.X_op == O_absent);
 
       /* We know that sym is in the .rdata section.  First we get the
         upper 16 bits of the address.  */
@@ -10610,19 +11383,21 @@ macro (struct mips_cl_insn *ip, char *str)
       if (HAVE_64BIT_GPRS)
        {
          used_at = 1;
-         macro_build (&offset_expr, "ld", "t,o(b)", treg, BFD_RELOC_LO16, AT);
+         macro_build (&offset_expr, "ld", "t,o(b)", op[0],
+                      BFD_RELOC_LO16, AT);
        }
       else
        {
          used_at = 1;
-         macro_build (&offset_expr, "lw", "t,o(b)", treg, BFD_RELOC_LO16, AT);
-         if (treg != RA)
+         macro_build (&offset_expr, "lw", "t,o(b)", op[0],
+                      BFD_RELOC_LO16, AT);
+         if (op[0] != RA)
            {
              /* FIXME: How in the world do we deal with the possible
                 overflow here?  */
              offset_expr.X_add_number += 4;
              macro_build (&offset_expr, "lw", "t,o(b)",
-                          treg + 1, BFD_RELOC_LO16, AT);
+                          op[0] + 1, BFD_RELOC_LO16, AT);
            }
        }
       break;
@@ -10633,36 +11408,37 @@ macro (struct mips_cl_insn *ip, char *str)
          bits wide as well.  Otherwise IMM_EXPR is the high order 32 bits of
          the value and the low order 32 bits are either zero or in
          OFFSET_EXPR.  */
-      if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
+      if (imm_expr.X_op == O_constant)
        {
          used_at = 1;
          load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
          if (HAVE_64BIT_FPRS)
            {
              gas_assert (HAVE_64BIT_GPRS);
-             macro_build (NULL, "dmtc1", "t,S", AT, treg);
+             macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
            }
          else
            {
-             macro_build (NULL, "mtc1", "t,G", AT, treg + 1);
+             macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
              if (offset_expr.X_op == O_absent)
-               macro_build (NULL, "mtc1", "t,G", 0, treg);
+               macro_build (NULL, "mtc1", "t,G", 0, op[0]);
              else
                {
                  gas_assert (offset_expr.X_op == O_constant);
                  load_register (AT, &offset_expr, 0);
-                 macro_build (NULL, "mtc1", "t,G", AT, treg);
+                 macro_build (NULL, "mtc1", "t,G", AT, op[0]);
                }
            }
          break;
        }
 
-      gas_assert (offset_expr.X_op == O_symbol
+      gas_assert (imm_expr.X_op == O_absent
+                 && offset_expr.X_op == O_symbol
                  && offset_expr.X_add_number == 0);
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
        {
-         breg = mips_gp_register;
+         op[2] = mips_gp_register;
          offset_reloc[0] = BFD_RELOC_MIPS_LITERAL;
          offset_reloc[1] = BFD_RELOC_UNUSED;
          offset_reloc[2] = BFD_RELOC_UNUSED;
@@ -10680,7 +11456,7 @@ macro (struct mips_cl_insn *ip, char *str)
              macro_build_lui (&offset_expr, AT);
            }
 
-         breg = AT;
+         op[2] = AT;
          offset_reloc[0] = BFD_RELOC_LO16;
          offset_reloc[1] = BFD_RELOC_UNUSED;
          offset_reloc[2] = BFD_RELOC_UNUSED;
@@ -10761,6 +11537,7 @@ macro (struct mips_cl_insn *ip, char *str)
       if (!target_big_endian)
        coproc = 0;
 
+      breg = op[2];
       if (small_offset_p (0, align, 16))
        {
          ep = &offset_expr;
@@ -10777,22 +11554,22 @@ macro (struct mips_cl_insn *ip, char *str)
              offset_reloc[1] = BFD_RELOC_UNUSED;
              offset_reloc[2] = BFD_RELOC_UNUSED;
            }
-         if (strcmp (s, "lw") == 0 && treg == breg)
+         if (strcmp (s, "lw") == 0 && op[0] == breg)
            {
              ep->X_add_number += 4;
-             macro_build (ep, s, fmt, treg + 1, -1, offset_reloc[0],
+             macro_build (ep, s, fmt, op[0] + 1, -1, offset_reloc[0],
                           offset_reloc[1], offset_reloc[2], breg);
              ep->X_add_number -= 4;
-             macro_build (ep, s, fmt, treg, -1, offset_reloc[0],
+             macro_build (ep, s, fmt, op[0], -1, offset_reloc[0],
                           offset_reloc[1], offset_reloc[2], breg);
            }
          else
            {
-             macro_build (ep, s, fmt, coproc ? treg + 1 : treg, -1,
+             macro_build (ep, s, fmt, coproc ? op[0] + 1 : op[0], -1,
                           offset_reloc[0], offset_reloc[1], offset_reloc[2],
                           breg);
              ep->X_add_number += 4;
-             macro_build (ep, s, fmt, coproc ? treg : treg + 1, -1,
+             macro_build (ep, s, fmt, coproc ? op[0] : op[0] + 1, -1,
                           offset_reloc[0], offset_reloc[1], offset_reloc[2],
                           breg);
            }
@@ -10802,7 +11579,7 @@ macro (struct mips_cl_insn *ip, char *str)
       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;
        }
 
@@ -10812,22 +11589,22 @@ macro (struct mips_cl_insn *ip, char *str)
          char value [32];
 
          sprintf_vma (value, offset_expr.X_add_number);
-         as_bad (_("Number (0x%s) larger than 32 bits"), value);
+         as_bad (_("number (0x%s) larger than 32 bits"), value);
        }
 
       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)
-              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
+              <op>     op[0],<sym>($gp)        (BFD_RELOC_GPREL16)
+              <op>     op[0]+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
             If we have a base register, we use this
               addu     $at,$breg,$gp
-              <op>     $treg,<sym>($at)        (BFD_RELOC_GPREL16)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
+              <op>     op[0],<sym>($at)        (BFD_RELOC_GPREL16)
+              <op>     op[0]+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
             If this is not a GP relative symbol, we want
               lui      $at,<sym>               (BFD_RELOC_HI16_S)
-              <op>     $treg,<sym>($at)        (BFD_RELOC_LO16)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($at)        (BFD_RELOC_LO16)
+              <op>     op[0]+1,<sym>+4($at)    (BFD_RELOC_LO16)
             If there is a base register, we add it to $at after the
             lui instruction.  If there is a constant, we always use
             the last case.  */
@@ -10849,7 +11626,7 @@ macro (struct mips_cl_insn *ip, char *str)
                }
 
              /* Itbl support may require additional care here.  */
-             macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+             macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
                           BFD_RELOC_GPREL16, tempreg);
              offset_expr.X_add_number += 4;
 
@@ -10858,7 +11635,7 @@ macro (struct mips_cl_insn *ip, char *str)
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
              /* Itbl support may require additional care here.  */
-             macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+             macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
                           BFD_RELOC_GPREL16, tempreg);
              mips_optimize = hold_mips_optimize;
 
@@ -10879,12 +11656,12 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
-         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
                       BFD_RELOC_LO16, AT);
          /* FIXME: How do we handle overflow here?  */
          offset_expr.X_add_number += 4;
          /* Itbl support may require additional care here.  */
-         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
                       BFD_RELOC_LO16, AT);
          if (mips_relax.sequence)
            relax_end ();
@@ -10894,13 +11671,13 @@ macro (struct mips_cl_insn *ip, char *str)
          /* If this is a reference to an external symbol, we want
               lw       $at,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
               nop
-              <op>     $treg,0($at)
-              <op>     $treg+1,4($at)
+              <op>     op[0],0($at)
+              <op>     op[0]+1,4($at)
             Otherwise we want
               lw       $at,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
               nop
-              <op>     $treg,<sym>($at)        (BFD_RELOC_LO16)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($at)        (BFD_RELOC_LO16)
+              <op>     op[0]+1,<sym>+4($at)    (BFD_RELOC_LO16)
             If there is a base register we add it to $at before the
             lwc1 instructions.  If there is a constant we include it
             in the lwc1 instructions.  */
@@ -10921,16 +11698,16 @@ macro (struct mips_cl_insn *ip, char *str)
 
          /* Itbl support may require additional care here.  */
          relax_start (offset_expr.X_add_symbol);
-         macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&expr1, s, fmt, coproc ? op[0] + 1 : op[0],
                       BFD_RELOC_LO16, AT);
          expr1.X_add_number += 4;
-         macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&expr1, s, fmt, coproc ? op[0] : op[0] + 1,
                       BFD_RELOC_LO16, AT);
          relax_switch ();
-         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
                       BFD_RELOC_LO16, AT);
          offset_expr.X_add_number += 4;
-         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
                       BFD_RELOC_LO16, AT);
          relax_end ();
 
@@ -10945,13 +11722,13 @@ macro (struct mips_cl_insn *ip, char *str)
               addu     $at,$at,$gp
               lw       $at,<sym>($at)          (BFD_RELOC_MIPS_GOT_LO16)
               nop
-              <op>     $treg,0($at)
-              <op>     $treg+1,4($at)
+              <op>     op[0],0($at)
+              <op>     op[0]+1,4($at)
             Otherwise we want
               lw       $at,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
               nop
-              <op>     $treg,<sym>($at)        (BFD_RELOC_LO16)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_LO16)
+              <op>     op[0],<sym>($at)        (BFD_RELOC_LO16)
+              <op>     op[0]+1,<sym>+4($at)    (BFD_RELOC_LO16)
             If there is a base register we add it to $at before the
             lwc1 instructions.  If there is a constant we include it
             in the lwc1 instructions.  */
@@ -10973,7 +11750,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
-         macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&expr1, s, fmt, coproc ? op[0] + 1 : op[0],
                       BFD_RELOC_LO16, AT);
          expr1.X_add_number += 4;
 
@@ -10982,7 +11759,7 @@ macro (struct mips_cl_insn *ip, char *str)
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
          /* Itbl support may require additional care here.  */
-         macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&expr1, s, fmt, coproc ? op[0] : op[0] + 1,
                       BFD_RELOC_LO16, AT);
          mips_optimize = hold_mips_optimize;
          expr1.X_add_number -= 4;
@@ -10997,7 +11774,7 @@ macro (struct mips_cl_insn *ip, char *str)
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
-         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&offset_expr, s, fmt, coproc ? op[0] + 1 : op[0],
                       BFD_RELOC_LO16, AT);
          offset_expr.X_add_number += 4;
 
@@ -11006,7 +11783,7 @@ macro (struct mips_cl_insn *ip, char *str)
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
          /* Itbl support may require additional care here.  */
-         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&offset_expr, s, fmt, coproc ? op[0] : op[0] + 1,
                       BFD_RELOC_LO16, AT);
          mips_optimize = hold_mips_optimize;
          relax_end ();
@@ -11063,31 +11840,28 @@ macro (struct mips_cl_insn *ip, char *str)
       break;
 
     case M_MOVE:
-      move_register (dreg, sreg);
+      move_register (op[0], op[1]);
       break;
 
     case M_MOVEP:
       gas_assert (mips_opts.micromips);
       gas_assert (mips_opts.insn32);
-      dreg = micromips_to_32_reg_h_map1[EXTRACT_OPERAND (1, MH, *ip)];
-      breg = micromips_to_32_reg_h_map2[EXTRACT_OPERAND (1, MH, *ip)];
-      sreg = micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
-      treg = micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
-      move_register (dreg, sreg);
-      move_register (breg, treg);
+      move_register (micromips_to_32_reg_h_map1[op[0]],
+                    micromips_to_32_reg_m_map[op[1]]);
+      move_register (micromips_to_32_reg_h_map2[op[0]],
+                    micromips_to_32_reg_n_map[op[2]]);
       break;
 
     case M_DMUL:
       dbl = 1;
     case M_MUL:
       if (mips_opts.arch == CPU_R5900)
-        {
-          macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", dreg, sreg, treg);
-        }
+       macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", op[0], op[1],
+                    op[2]);
       else
         {
-      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
-      macro_build (NULL, "mflo", MFHL_FMT, dreg);
+         macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", op[1], op[2]);
+         macro_build (NULL, "mflo", MFHL_FMT, op[0]);
         }
       break;
 
@@ -11099,8 +11873,8 @@ macro (struct mips_cl_insn *ip, char *str)
         anyway.  */
       used_at = 1;
       load_register (AT, &imm_expr, dbl);
-      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
-      macro_build (NULL, "mflo", MFHL_FMT, dreg);
+      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", op[1], AT);
+      macro_build (NULL, "mflo", MFHL_FMT, op[0]);
       break;
 
     case M_DMULO_I:
@@ -11117,26 +11891,27 @@ macro (struct mips_cl_insn *ip, char *str)
       used_at = 1;
       if (imm)
        load_register (AT, &imm_expr, dbl);
-      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
-      macro_build (NULL, "mflo", MFHL_FMT, dreg);
-      macro_build (NULL, dbl ? "dsra32" : "sra", SHFT_FMT, dreg, dreg, RA);
+      macro_build (NULL, dbl ? "dmult" : "mult", "s,t",
+                  op[1], imm ? AT : op[2]);
+      macro_build (NULL, "mflo", MFHL_FMT, op[0]);
+      macro_build (NULL, dbl ? "dsra32" : "sra", SHFT_FMT, op[0], op[0], 31);
       macro_build (NULL, "mfhi", MFHL_FMT, AT);
       if (mips_trap)
-       macro_build (NULL, "tne", TRAP_FMT, dreg, AT, 6);
+       macro_build (NULL, "tne", TRAP_FMT, op[0], AT, 6);
       else
        {
          if (mips_opts.micromips)
            micromips_label_expr (&label_expr);
          else
            label_expr.X_add_number = 8;
-         macro_build (&label_expr, "beq", "s,t,p", dreg, AT);
+         macro_build (&label_expr, "beq", "s,t,p", op[0], AT);
          macro_build (NULL, "nop", "");
          macro_build (NULL, "break", BRK_FMT, 6);
          if (mips_opts.micromips)
            micromips_add_label ();
        }
       end_noreorder ();
-      macro_build (NULL, "mflo", MFHL_FMT, dreg);
+      macro_build (NULL, "mflo", MFHL_FMT, op[0]);
       break;
 
     case M_DMULOU_I:
@@ -11154,9 +11929,9 @@ macro (struct mips_cl_insn *ip, char *str)
       if (imm)
        load_register (AT, &imm_expr, dbl);
       macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
-                  sreg, imm ? AT : treg);
+                  op[1], imm ? AT : op[2]);
       macro_build (NULL, "mfhi", MFHL_FMT, AT);
-      macro_build (NULL, "mflo", MFHL_FMT, dreg);
+      macro_build (NULL, "mflo", MFHL_FMT, op[0]);
       if (mips_trap)
        macro_build (NULL, "tne", TRAP_FMT, AT, ZERO, 6);
       else
@@ -11177,47 +11952,43 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_DROL:
       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
        {
-         if (dreg == sreg)
+         if (op[0] == op[1])
            {
              tempreg = AT;
              used_at = 1;
            }
-         else
-           {
-             tempreg = dreg;
-           }
-         macro_build (NULL, "dnegu", "d,w", tempreg, treg);
-         macro_build (NULL, "drorv", "d,t,s", dreg, sreg, tempreg);
+         else
+           tempreg = op[0];
+         macro_build (NULL, "dnegu", "d,w", tempreg, op[2]);
+         macro_build (NULL, "drorv", "d,t,s", op[0], op[1], tempreg);
          break;
        }
       used_at = 1;
-      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);
+      macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, op[2]);
+      macro_build (NULL, "dsrlv", "d,t,s", AT, op[1], AT);
+      macro_build (NULL, "dsllv", "d,t,s", op[0], op[1], op[2]);
+      macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       break;
 
     case M_ROL:
       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
        {
-         if (dreg == sreg)
+         if (op[0] == op[1])
            {
              tempreg = AT;
              used_at = 1;
            }
          else
-           {
-             tempreg = dreg;
-           }
-         macro_build (NULL, "negu", "d,w", tempreg, treg);
-         macro_build (NULL, "rorv", "d,t,s", dreg, sreg, tempreg);
+           tempreg = op[0];
+         macro_build (NULL, "negu", "d,w", tempreg, op[2]);
+         macro_build (NULL, "rorv", "d,t,s", op[0], op[1], tempreg);
          break;
        }
       used_at = 1;
-      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);
+      macro_build (NULL, "subu", "d,v,t", AT, ZERO, op[2]);
+      macro_build (NULL, "srlv", "d,t,s", AT, op[1], AT);
+      macro_build (NULL, "sllv", "d,t,s", op[0], op[1], op[2]);
+      macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       break;
 
     case M_DROL_I:
@@ -11226,30 +11997,28 @@ macro (struct mips_cl_insn *ip, char *str)
        char *l;
        char *rr;
 
-       if (imm_expr.X_op != O_constant)
-         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x3f;
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
          {
            rot = (64 - rot) & 0x3f;
            if (rot >= 32)
-             macro_build (NULL, "dror32", SHFT_FMT, dreg, sreg, rot - 32);
+             macro_build (NULL, "dror32", SHFT_FMT, op[0], op[1], rot - 32);
            else
-             macro_build (NULL, "dror", SHFT_FMT, dreg, sreg, rot);
+             macro_build (NULL, "dror", SHFT_FMT, op[0], op[1], rot);
            break;
          }
        if (rot == 0)
          {
-           macro_build (NULL, "dsrl", SHFT_FMT, dreg, sreg, 0);
+           macro_build (NULL, "dsrl", SHFT_FMT, op[0], op[1], 0);
            break;
          }
        l = (rot < 0x20) ? "dsll" : "dsll32";
        rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rot &= 0x1f;
        used_at = 1;
-       macro_build (NULL, l, SHFT_FMT, AT, sreg, rot);
-       macro_build (NULL, rr, SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
-       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, l, SHFT_FMT, AT, op[1], rot);
+       macro_build (NULL, rr, SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       }
       break;
 
@@ -11257,50 +12026,49 @@ macro (struct mips_cl_insn *ip, char *str)
       {
        unsigned int rot;
 
-       if (imm_expr.X_op != O_constant)
-         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x1f;
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
          {
-           macro_build (NULL, "ror", SHFT_FMT, dreg, sreg, (32 - rot) & 0x1f);
+           macro_build (NULL, "ror", SHFT_FMT, op[0], op[1],
+                        (32 - rot) & 0x1f);
            break;
          }
        if (rot == 0)
          {
-           macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, 0);
+           macro_build (NULL, "srl", SHFT_FMT, op[0], op[1], 0);
            break;
          }
        used_at = 1;
-       macro_build (NULL, "sll", SHFT_FMT, AT, sreg, rot);
-       macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
-       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, "sll", SHFT_FMT, AT, op[1], rot);
+       macro_build (NULL, "srl", SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       }
       break;
 
     case M_DROR:
       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
        {
-         macro_build (NULL, "drorv", "d,t,s", dreg, sreg, treg);
+         macro_build (NULL, "drorv", "d,t,s", op[0], op[1], op[2]);
          break;
        }
       used_at = 1;
-      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);
+      macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, op[2]);
+      macro_build (NULL, "dsllv", "d,t,s", AT, op[1], AT);
+      macro_build (NULL, "dsrlv", "d,t,s", op[0], op[1], op[2]);
+      macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       break;
 
     case M_ROR:
       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
        {
-         macro_build (NULL, "rorv", "d,t,s", dreg, sreg, treg);
+         macro_build (NULL, "rorv", "d,t,s", op[0], op[1], op[2]);
          break;
        }
       used_at = 1;
-      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);
+      macro_build (NULL, "subu", "d,v,t", AT, ZERO, op[2]);
+      macro_build (NULL, "sllv", "d,t,s", AT, op[1], AT);
+      macro_build (NULL, "srlv", "d,t,s", op[0], op[1], op[2]);
+      macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       break;
 
     case M_DROR_I:
@@ -11309,29 +12077,27 @@ macro (struct mips_cl_insn *ip, char *str)
        char *l;
        char *rr;
 
-       if (imm_expr.X_op != O_constant)
-         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x3f;
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
          {
            if (rot >= 32)
-             macro_build (NULL, "dror32", SHFT_FMT, dreg, sreg, rot - 32);
+             macro_build (NULL, "dror32", SHFT_FMT, op[0], op[1], rot - 32);
            else
-             macro_build (NULL, "dror", SHFT_FMT, dreg, sreg, rot);
+             macro_build (NULL, "dror", SHFT_FMT, op[0], op[1], rot);
            break;
          }
        if (rot == 0)
          {
-           macro_build (NULL, "dsrl", SHFT_FMT, dreg, sreg, 0);
+           macro_build (NULL, "dsrl", SHFT_FMT, op[0], op[1], 0);
            break;
          }
        rr = (rot < 0x20) ? "dsrl" : "dsrl32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        rot &= 0x1f;
        used_at = 1;
-       macro_build (NULL, rr, SHFT_FMT, AT, sreg, rot);
-       macro_build (NULL, l, SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
-       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, rr, SHFT_FMT, AT, op[1], rot);
+       macro_build (NULL, l, SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       }
       break;
 
@@ -11339,128 +12105,119 @@ macro (struct mips_cl_insn *ip, char *str)
       {
        unsigned int rot;
 
-       if (imm_expr.X_op != O_constant)
-         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x1f;
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
          {
-           macro_build (NULL, "ror", SHFT_FMT, dreg, sreg, rot);
+           macro_build (NULL, "ror", SHFT_FMT, op[0], op[1], rot);
            break;
          }
        if (rot == 0)
          {
-           macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, 0);
+           macro_build (NULL, "srl", SHFT_FMT, op[0], op[1], 0);
            break;
          }
        used_at = 1;
-       macro_build (NULL, "srl", SHFT_FMT, AT, sreg, rot);
-       macro_build (NULL, "sll", SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
-       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, "srl", SHFT_FMT, AT, op[1], rot);
+       macro_build (NULL, "sll", SHFT_FMT, op[0], op[1], (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
       }
       break;
 
     case M_SEQ:
-      if (sreg == 0)
-       macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
-      else if (treg == 0)
-       macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+      if (op[1] == 0)
+       macro_build (&expr1, "sltiu", "t,r,j", op[0], op[2], BFD_RELOC_LO16);
+      else if (op[2] == 0)
+       macro_build (&expr1, "sltiu", "t,r,j", op[0], op[1], BFD_RELOC_LO16);
       else
        {
-         macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
-         macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
+         macro_build (NULL, "xor", "d,v,t", op[0], op[1], op[2]);
+         macro_build (&expr1, "sltiu", "t,r,j", op[0], op[0], BFD_RELOC_LO16);
        }
       break;
 
     case M_SEQ_I:
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+      if (imm_expr.X_add_number == 0)
        {
-         macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&expr1, "sltiu", "t,r,j", op[0], op[1], BFD_RELOC_LO16);
          break;
        }
-      if (sreg == 0)
+      if (op[1] == 0)
        {
-         as_warn (_("Instruction %s: result is always false"),
+         as_warn (_("instruction %s: result is always false"),
                   ip->insn_mo->name);
-         move_register (dreg, 0);
+         move_register (op[0], 0);
          break;
        }
       if (CPU_HAS_SEQ (mips_opts.arch)
          && -512 <= imm_expr.X_add_number
          && imm_expr.X_add_number < 512)
        {
-         macro_build (NULL, "seqi", "t,r,+Q", dreg, sreg,
+         macro_build (NULL, "seqi", "t,r,+Q", op[0], op[1],
                       (int) imm_expr.X_add_number);
          break;
        }
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= 0
+      if (imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
-       {
-         macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
-       }
-      else if (imm_expr.X_op == O_constant
-              && imm_expr.X_add_number > -0x8000
+       macro_build (&imm_expr, "xori", "t,r,i", op[0], op[1], BFD_RELOC_LO16);
+      else if (imm_expr.X_add_number > -0x8000
               && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
-                      "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+                      "t,r,j", op[0], op[1], BFD_RELOC_LO16);
        }
       else if (CPU_HAS_SEQ (mips_opts.arch))
        {
          used_at = 1;
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, "seq", "d,v,t", dreg, sreg, AT);
+         macro_build (NULL, "seq", "d,v,t", op[0], op[1], AT);
          break;
        }
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
+         macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
          used_at = 1;
        }
-      macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
+      macro_build (&expr1, "sltiu", "t,r,j", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGE:                /* sreg >= treg <==> not (sreg < treg) */
+    case M_SGE:                /* X >= Y  <==>  not (X < Y) */
       s = "slt";
       goto sge;
     case M_SGEU:
       s = "sltu";
     sge:
-      macro_build (NULL, s, "d,v,t", dreg, sreg, treg);
-      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+      macro_build (NULL, s, "d,v,t", op[0], op[1], op[2]);
+      macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGE_I:              /* sreg >= I <==> not (sreg < I) */
+    case M_SGE_I:      /* X >= I  <==>  not (X < I) */
     case M_SGEU_I:
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= -0x8000
+      if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
-       {
-         macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
-                      dreg, sreg, BFD_RELOC_LO16);
-       }
+       macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
+                    op[0], op[1], BFD_RELOC_LO16);
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
          macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
-                      dreg, sreg, AT);
+                      op[0], op[1], AT);
          used_at = 1;
        }
-      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+      macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGT:                /* sreg > treg  <==>  treg < sreg */
+    case M_SGT:                /* X > Y  <==>  Y < X */
       s = "slt";
       goto sgt;
     case M_SGTU:
       s = "sltu";
     sgt:
-      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
+      macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
       break;
 
-    case M_SGT_I:              /* sreg > I  <==>  I < sreg */
+    case M_SGT_I:      /* X > I  <==>  I < X */
       s = "slt";
       goto sgti;
     case M_SGTU_I:
@@ -11468,20 +12225,20 @@ macro (struct mips_cl_insn *ip, char *str)
     sgti:
       used_at = 1;
       load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
+      macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
       break;
 
-    case M_SLE:        /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
+    case M_SLE:                /* X <= Y  <==>  Y >= X  <==>  not (Y < X) */
       s = "slt";
       goto sle;
     case M_SLEU:
       s = "sltu";
     sle:
-      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
-      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+      macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
+      macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SLE_I:      /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
+    case M_SLE_I:      /* X <= I  <==>  I >= X  <==>  not (I < X) */
       s = "slt";
       goto slei;
     case M_SLEU_I:
@@ -11489,99 +12246,97 @@ macro (struct mips_cl_insn *ip, char *str)
     slei:
       used_at = 1;
       load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
-      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
+      macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
+      macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
     case M_SLT_I:
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= -0x8000
+      if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (&imm_expr, "slti", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, "slti", "t,r,j", op[0], op[1],
+                      BFD_RELOC_LO16);
          break;
        }
       used_at = 1;
       load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, "slt", "d,v,t", dreg, sreg, AT);
+      macro_build (NULL, "slt", "d,v,t", op[0], op[1], AT);
       break;
 
     case M_SLTU_I:
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= -0x8000
+      if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (&imm_expr, "sltiu", "t,r,j", dreg, sreg,
+         macro_build (&imm_expr, "sltiu", "t,r,j", op[0], op[1],
                       BFD_RELOC_LO16);
          break;
        }
       used_at = 1;
       load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, "sltu", "d,v,t", dreg, sreg, AT);
+      macro_build (NULL, "sltu", "d,v,t", op[0], op[1], AT);
       break;
 
     case M_SNE:
-      if (sreg == 0)
-       macro_build (NULL, "sltu", "d,v,t", dreg, 0, treg);
-      else if (treg == 0)
-       macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
+      if (op[1] == 0)
+       macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[2]);
+      else if (op[2] == 0)
+       macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[1]);
       else
        {
-         macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
-         macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
+         macro_build (NULL, "xor", "d,v,t", op[0], op[1], op[2]);
+         macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[0]);
        }
       break;
 
     case M_SNE_I:
-      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
+      if (imm_expr.X_add_number == 0)
        {
-         macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
+         macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[1]);
          break;
        }
-      if (sreg == 0)
+      if (op[1] == 0)
        {
-         as_warn (_("Instruction %s: result is always true"),
+         as_warn (_("instruction %s: result is always true"),
                   ip->insn_mo->name);
          macro_build (&expr1, HAVE_32BIT_GPRS ? "addiu" : "daddiu", "t,r,j",
-                      dreg, 0, BFD_RELOC_LO16);
+                      op[0], 0, BFD_RELOC_LO16);
          break;
        }
       if (CPU_HAS_SEQ (mips_opts.arch)
          && -512 <= imm_expr.X_add_number
          && imm_expr.X_add_number < 512)
        {
-         macro_build (NULL, "snei", "t,r,+Q", dreg, sreg,
+         macro_build (NULL, "snei", "t,r,+Q", op[0], op[1],
                       (int) imm_expr.X_add_number);
          break;
        }
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= 0
+      if (imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
        {
-         macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, "xori", "t,r,i", op[0], op[1],
+                      BFD_RELOC_LO16);
        }
-      else if (imm_expr.X_op == O_constant
-              && imm_expr.X_add_number > -0x8000
+      else if (imm_expr.X_add_number > -0x8000
               && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
-                      "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+                      "t,r,j", op[0], op[1], BFD_RELOC_LO16);
        }
       else if (CPU_HAS_SEQ (mips_opts.arch))
        {
          used_at = 1;
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, "sne", "d,v,t", dreg, sreg, AT);
+         macro_build (NULL, "sne", "d,v,t", op[0], op[1], AT);
          break;
        }
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
+         macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
          used_at = 1;
        }
-      macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
+      macro_build (NULL, "sltu", "d,v,t", op[0], 0, op[0]);
       break;
 
     case M_SUB_I:
@@ -11598,11 +12353,11 @@ macro (struct mips_cl_insn *ip, char *str)
       s2 = "dsub";
       if (!mips_opts.micromips)
        goto do_subi;
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number > -0x200
+      if (imm_expr.X_add_number > -0x200
          && imm_expr.X_add_number <= 0x200)
        {
-         macro_build (NULL, s, "t,r,.", dreg, sreg, -imm_expr.X_add_number);
+         macro_build (NULL, s, "t,r,.", op[0], op[1],
+                      (int) -imm_expr.X_add_number);
          break;
        }
       goto do_subi_i;
@@ -11611,18 +12366,17 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "daddiu";
       s2 = "dsubu";
     do_subi:
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number > -0x8000
+      if (imm_expr.X_add_number > -0x8000
          && imm_expr.X_add_number <= 0x8000)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (&imm_expr, s, "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, s, "t,r,j", op[0], op[1], BFD_RELOC_LO16);
          break;
        }
     do_subi_i:
       used_at = 1;
       load_register (AT, &imm_expr, dbl);
-      macro_build (NULL, s2, "d,v,t", dreg, sreg, AT);
+      macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
       break;
 
     case M_TEQ_I:
@@ -11645,7 +12399,7 @@ macro (struct mips_cl_insn *ip, char *str)
     trap:
       used_at = 1;
       load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, s, "s,t", sreg, AT);
+      macro_build (NULL, s, "s,t", op[0], AT);
       break;
 
     case M_TRUNCWS:
@@ -11653,26 +12407,24 @@ macro (struct mips_cl_insn *ip, char *str)
       gas_assert (!mips_opts.micromips);
       gas_assert (mips_opts.isa == ISA_MIPS1);
       used_at = 1;
-      sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
-      dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
 
       /*
        * Is the double cfc1 instruction a bug in the mips assembler;
        * or is there a reason for it?
        */
       start_noreorder ();
-      macro_build (NULL, "cfc1", "t,G", treg, RA);
-      macro_build (NULL, "cfc1", "t,G", treg, RA);
+      macro_build (NULL, "cfc1", "t,G", op[2], RA);
+      macro_build (NULL, "cfc1", "t,G", op[2], RA);
       macro_build (NULL, "nop", "");
       expr1.X_add_number = 3;
-      macro_build (&expr1, "ori", "t,r,i", AT, treg, BFD_RELOC_LO16);
+      macro_build (&expr1, "ori", "t,r,i", AT, op[2], BFD_RELOC_LO16);
       expr1.X_add_number = 2;
       macro_build (&expr1, "xori", "t,r,i", AT, AT, BFD_RELOC_LO16);
       macro_build (NULL, "ctc1", "t,G", AT, RA);
       macro_build (NULL, "nop", "");
       macro_build (NULL, mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S",
-                  dreg, sreg);
-      macro_build (NULL, "ctc1", "t,G", treg, RA);
+                  op[0], op[1]);
+      macro_build (NULL, "ctc1", "t,G", op[2], RA);
       macro_build (NULL, "nop", "");
       end_noreorder ();
       break;
@@ -11720,6 +12472,7 @@ macro (struct mips_cl_insn *ip, char *str)
       ust = 1;
 
     uld_st:
+      breg = op[2];
       large_offset = !small_offset_p (off, align, offbits);
       ep = &offset_expr;
       expr1.X_add_number = 0;
@@ -11741,16 +12494,16 @@ macro (struct mips_cl_insn *ip, char *str)
          offset_reloc[1] = BFD_RELOC_UNUSED;
          offset_reloc[2] = BFD_RELOC_UNUSED;
          breg = tempreg;
-         tempreg = treg;
+         tempreg = op[0];
          ep = &expr1;
        }
-      else if (!ust && treg == breg)
+      else if (!ust && op[0] == breg)
        {
          used_at = 1;
          tempreg = AT;
        }
       else
-       tempreg = treg;
+       tempreg = op[0];
 
       if (off == 1)
        goto ulh_sh;
@@ -11775,11 +12528,11 @@ macro (struct mips_cl_insn *ip, char *str)
                     offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* If necessary, move the result in tempreg to the final destination.  */
-      if (!ust && treg != tempreg)
+      if (!ust && op[0] != tempreg)
         {
          /* Protect second load's delay slot.  */
          load_delay_nop ();
-         move_register (treg, tempreg);
+         move_register (op[0], tempreg);
        }
       break;
 
@@ -11787,7 +12540,7 @@ macro (struct mips_cl_insn *ip, char *str)
       used_at = 1;
       if (target_big_endian == ust)
        ep->X_add_number += off;
-      tempreg = ust || large_offset ? treg : AT;
+      tempreg = ust || large_offset ? op[0] : AT;
       macro_build (ep, s, "t,o(b)", tempreg, -1,
                   offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
@@ -11795,9 +12548,9 @@ macro (struct mips_cl_insn *ip, char *str)
          bytes.  Unfortunately for M_USH_A we have none available before
          the next store as AT holds the base address.  We deal with this
          case by clobbering TREG and then restoring it as with ULH.  */
-      tempreg = ust == large_offset ? treg : AT;
+      tempreg = ust == large_offset ? op[0] : AT;
       if (ust)
-       macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8);
+       macro_build (NULL, "srl", SHFT_FMT, tempreg, op[0], 8);
 
       if (target_big_endian == ust)
        ep->X_add_number -= off;
@@ -11819,20 +12572,20 @@ macro (struct mips_cl_insn *ip, char *str)
       /* For ULH and M_USH_A OR the LSB in.  */
       if (!ust || large_offset)
        {
-         tempreg = !large_offset ? AT : treg;
+         tempreg = !large_offset ? AT : op[0];
          macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8);
-         macro_build (NULL, "or", "d,v,t", treg, treg, AT);
+         macro_build (NULL, "or", "d,v,t", op[0], op[0], AT);
        }
       break;
 
     default:
       /* FIXME: Check if this is one of the itbl macros, since they
         are added dynamically.  */
-      as_bad (_("Macro %s not implemented yet"), ip->insn_mo->name);
+      as_bad (_("macro %s not implemented yet"), ip->insn_mo->name);
       break;
     }
   if (!mips_opts.at && used_at)
-    as_bad (_("Macro used $at after \".set noat\""));
+    as_bad (_("macro used $at after \".set noat\""));
 }
 
 /* Implement macros in mips16 mode.  */
@@ -11840,17 +12593,23 @@ macro (struct mips_cl_insn *ip, char *str)
 static void
 mips16_macro (struct mips_cl_insn *ip)
 {
+  const struct mips_operand_array *operands;
   int mask;
-  int xreg, yreg, zreg, tmp;
+  int tmp;
   expressionS expr1;
   int dbl;
   const char *s, *s2, *s3;
+  unsigned int op[MAX_OPERANDS];
+  unsigned int i;
 
   mask = ip->insn_mo->mask;
 
-  xreg = MIPS16_EXTRACT_OPERAND (RX, *ip);
-  yreg = MIPS16_EXTRACT_OPERAND (RY, *ip);
-  zreg = MIPS16_EXTRACT_OPERAND (RZ, *ip);
+  operands = insn_operands (ip);
+  for (i = 0; i < MAX_OPERANDS; i++)
+    if (operands->operand[i])
+      op[i] = insn_extract_operand (ip, operands->operand[i]);
+    else
+      op[i] = -1;
 
   expr1.X_op = O_constant;
   expr1.X_op_symbol = NULL;
@@ -11875,9 +12634,9 @@ mips16_macro (struct mips_cl_insn *ip)
       s = "mfhi";
     do_div3:
       start_noreorder ();
-      macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", xreg, yreg);
+      macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", op[1], op[2]);
       expr1.X_add_number = 2;
-      macro_build (&expr1, "bnez", "x,p", yreg);
+      macro_build (&expr1, "bnez", "x,p", op[2]);
       macro_build (NULL, "break", "6", 7);
 
       /* FIXME: The normal code checks for of -1 / -0x80000000 here,
@@ -11885,7 +12644,7 @@ mips16_macro (struct mips_cl_insn *ip)
          but I don't see how to do the comparisons without a temporary
          register.  */
       end_noreorder ();
-      macro_build (NULL, s, "x", zreg);
+      macro_build (NULL, s, "x", op[0]);
       break;
 
     case M_DIVU_3:
@@ -11905,19 +12664,19 @@ mips16_macro (struct mips_cl_insn *ip)
       s2 = "mfhi";
     do_divu3:
       start_noreorder ();
-      macro_build (NULL, s, "0,x,y", xreg, yreg);
+      macro_build (NULL, s, "0,x,y", op[1], op[2]);
       expr1.X_add_number = 2;
-      macro_build (&expr1, "bnez", "x,p", yreg);
+      macro_build (&expr1, "bnez", "x,p", op[2]);
       macro_build (NULL, "break", "6", 7);
       end_noreorder ();
-      macro_build (NULL, s2, "x", zreg);
+      macro_build (NULL, s2, "x", op[0]);
       break;
 
     case M_DMUL:
       dbl = 1;
     case M_MUL:
-      macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", xreg, yreg);
-      macro_build (NULL, "mflo", "x", zreg);
+      macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", op[1], op[2]);
+      macro_build (NULL, "mflo", "x", op[0]);
       break;
 
     case M_DSUBU_I:
@@ -11925,24 +12684,18 @@ mips16_macro (struct mips_cl_insn *ip)
       goto do_subu;
     case M_SUBU_I:
     do_subu:
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
-      macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "y,x,4", yreg, xreg);
+      macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "y,x,4", op[0], op[1]);
       break;
 
     case M_SUBU_I_2:
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
-      macro_build (&imm_expr, "addiu", "x,k", xreg);
+      macro_build (&imm_expr, "addiu", "x,k", op[0]);
       break;
 
     case M_DSUBU_I_2:
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
-      macro_build (&imm_expr, "daddiu", "y,j", yreg);
+      macro_build (&imm_expr, "daddiu", "y,j", op[0]);
       break;
 
     case M_BEQ:
@@ -11986,12 +12739,12 @@ mips16_macro (struct mips_cl_insn *ip)
       s2 = "btnez";
 
     do_reverse_branch:
-      tmp = xreg;
-      xreg = yreg;
-      yreg = tmp;
+      tmp = op[1];
+      op[1] = op[0];
+      op[0] = tmp;
 
     do_branch:
-      macro_build (NULL, s, "x,y", xreg, yreg);
+      macro_build (NULL, s, "x,y", op[0], op[1]);
       macro_build (&offset_expr, s2, "p");
       break;
 
@@ -12046,56 +12799,108 @@ mips16_macro (struct mips_cl_insn *ip)
       s3 = "x,8";
 
     do_addone_branch_i:
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("Unsupported large constant"));
       ++imm_expr.X_add_number;
 
     do_branch_i:
-      macro_build (&imm_expr, s, s3, xreg);
+      macro_build (&imm_expr, s, s3, op[0]);
       macro_build (&offset_expr, s2, "p");
       break;
 
     case M_ABS:
       expr1.X_add_number = 0;
-      macro_build (&expr1, "slti", "x,8", yreg);
-      if (xreg != yreg)
-       macro_build (NULL, "move", "y,X", xreg, mips16_to_32_reg_map[yreg]);
+      macro_build (&expr1, "slti", "x,8", op[1]);
+      if (op[0] != op[1])
+       macro_build (NULL, "move", "y,X", op[0], mips16_to_32_reg_map[op[1]]);
       expr1.X_add_number = 2;
       macro_build (&expr1, "bteqz", "p");
-      macro_build (NULL, "neg", "x,w", xreg, xreg);
+      macro_build (NULL, "neg", "x,w", op[0], op[0]);
       break;
     }
 }
 
+/* Look up instruction [START, START + LENGTH) in HASH.  Record any extra
+   opcode bits in *OPCODE_EXTRA.  */
+
+static struct mips_opcode *
+mips_lookup_insn (struct hash_control *hash, const char *start,
+                 ssize_t length, unsigned int *opcode_extra)
+{
+  char *name, *dot, *p;
+  unsigned int mask, suffix;
+  ssize_t opend;
+  struct mips_opcode *insn;
+
+  /* Make a copy of the instruction so that we can fiddle with it.  */
+  name = alloca (length + 1);
+  memcpy (name, start, length);
+  name[length] = '\0';
+
+  /* Look up the instruction as-is.  */
+  insn = (struct mips_opcode *) hash_find (hash, name);
+  if (insn)
+    return insn;
+
+  dot = strchr (name, '.');
+  if (dot && dot[1])
+    {
+      /* Try to interpret the text after the dot as a VU0 channel suffix.  */
+      p = mips_parse_vu0_channels (dot + 1, &mask);
+      if (*p == 0 && mask != 0)
+       {
+         *dot = 0;
+         insn = (struct mips_opcode *) hash_find (hash, name);
+         *dot = '.';
+         if (insn && (insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0)
+           {
+             *opcode_extra |= mask << mips_vu0_channel_mask.lsb;
+             return insn;
+           }
+       }
+    }
+
+  if (mips_opts.micromips)
+    {
+      /* See if there's an instruction size override suffix,
+        either `16' or `32', at the end of the mnemonic proper,
+        that defines the operation, i.e. before the first `.'
+        character if any.  Strip it and retry.  */
+      opend = dot != NULL ? dot - name : length;
+      if (opend >= 3 && name[opend - 2] == '1' && name[opend - 1] == '6')
+       suffix = 2;
+      else if (name[opend - 2] == '3' && name[opend - 1] == '2')
+       suffix = 4;
+      else
+       suffix = 0;
+      if (suffix)
+       {
+         memcpy (name + opend - 2, name + opend, length - opend + 1);
+         insn = (struct mips_opcode *) hash_find (hash, name);
+         if (insn)
+           {
+             forced_insn_length = suffix;
+             return insn;
+           }
+       }
+    }
+
+  return NULL;
+}
+
 /* Assemble an instruction into its binary format.  If the instruction
-   is a macro, set imm_expr, imm2_expr and offset_expr to the values
-   associated with "I", "+I" and "A" operands respectively.  Otherwise
-   store the value of the relocatable field (if any) in offset_expr.
-   In both cases set offset_reloc to the relocation operators applied
-   to offset_expr.  */
+   is a macro, set imm_expr and offset_expr to the values associated
+   with "I" and "A" operands respectively.  Otherwise store the value
+   of the relocatable field (if any) in offset_expr.  In both cases
+   set offset_reloc to the relocation operators applied to offset_expr.  */
 
 static void
-mips_ip (char *str, struct mips_cl_insn *ip)
+mips_ip (char *str, struct mips_cl_insn *insn)
 {
-  bfd_boolean wrong_delay_slot_insns = FALSE;
-  bfd_boolean need_delay_slot_ok = TRUE;
-  struct mips_opcode *firstinsn = NULL;
-  const struct mips_opcode *past;
+  const struct mips_opcode *first, *past;
   struct hash_control *hash;
-  const char *args;
-  char c = 0;
-  struct mips_opcode *insn;
-  long opend;
-  char *name;
-  char *dot;
   char format;
-  long end;
-  const struct mips_operand *operand;
-  struct mips_arg_info arg;
+  size_t end;
   struct mips_operand_token *tokens;
-  bfd_boolean optional_reg;
-
-  insn_error = NULL;
+  unsigned int opcode_extra;
 
   if (mips_opts.micromips)
     {
@@ -12108,51 +12913,22 @@ mips_ip (char *str, struct mips_cl_insn *ip)
       past = &mips_opcodes[NUMOPCODES];
     }
   forced_insn_length = 0;
-  insn = NULL;
+  opcode_extra = 0;
 
   /* We first try to match an instruction up to a space or to the end.  */
   for (end = 0; str[end] != '\0' && !ISSPACE (str[end]); end++)
     continue;
 
-  /* Make a copy of the instruction so that we can fiddle with it.  */
-  name = alloca (end + 1);
-  memcpy (name, str, end);
-  name[end] = '\0';
-
-  for (;;)
+  first = mips_lookup_insn (hash, str, end, &opcode_extra);
+  if (first == NULL)
     {
-      insn = (struct mips_opcode *) hash_find (hash, name);
-
-      if (insn != NULL || !mips_opts.micromips)
-       break;
-      if (forced_insn_length)
-       break;
-
-      /* See if there's an instruction size override suffix,
-         either `16' or `32', at the end of the mnemonic proper,
-         that defines the operation, i.e. before the first `.'
-         character if any.  Strip it and retry.  */
-      dot = strchr (name, '.');
-      opend = dot != NULL ? dot - name : end;
-      if (opend < 3)
-       break;
-      if (name[opend - 2] == '1' && name[opend - 1] == '6')
-       forced_insn_length = 2;
-      else if (name[opend - 2] == '3' && name[opend - 1] == '2')
-       forced_insn_length = 4;
-      else
-       break;
-      memcpy (name + opend - 2, name + opend, end - opend + 1);
-    }
-  if (insn == NULL)
-    {
-      insn_error = _("Unrecognized opcode");
+      set_insn_error (0, _("unrecognized opcode"));
       return;
     }
 
-  if (strcmp (name, "li.s") == 0)
+  if (strcmp (first->name, "li.s") == 0)
     format = 'f';
-  else if (strcmp (name, "li.d") == 0)
+  else if (strcmp (first->name, "li.d") == 0)
     format = 'd';
   else
     format = 0;
@@ -12160,380 +12936,11 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   if (!tokens)
     return;
 
-  /* For microMIPS instructions placed in a fixed-length branch delay slot
-     we make up to two passes over the relevant fragment of the opcode
-     table.  First we try instructions that meet the delay slot's length
-     requirement.  If none matched, then we retry with the remaining ones
-     and if one matches, then we use it and then issue an appropriate
-     warning later on.  */
-  for (;;)
-    {
-      bfd_boolean delay_slot_ok;
-      bfd_boolean size_ok;
-      bfd_boolean ok;
-      bfd_boolean more_alts;
-
-      gas_assert (strcmp (insn->name, name) == 0);
-
-      ok = is_opcode_valid (insn);
-      size_ok = is_size_valid (insn);
-      delay_slot_ok = is_delay_slot_valid (insn);
-      if (!delay_slot_ok && !wrong_delay_slot_insns)
-       {
-         firstinsn = insn;
-         wrong_delay_slot_insns = TRUE;
-       }
-      more_alts = (insn + 1 < past
-                  && strcmp (insn[0].name, insn[1].name) == 0);
-      if (!ok || !size_ok || delay_slot_ok != need_delay_slot_ok)
-       {
-         static char buf[256];
-
-         if (more_alts)
-           {
-             ++insn;
-             continue;
-           }
-         if (wrong_delay_slot_insns && need_delay_slot_ok)
-           {
-             gas_assert (firstinsn);
-             need_delay_slot_ok = FALSE;
-             past = insn + 1;
-             insn = firstinsn;
-             continue;
-           }
-
-         obstack_free (&mips_operand_tokens, tokens);
-         if (insn_error)
-           return;
-
-         if (!ok)
-           sprintf (buf, _("Opcode not supported on this processor: %s (%s)"),
-                    mips_cpu_info_from_arch (mips_opts.arch)->name,
-                    mips_cpu_info_from_isa (mips_opts.isa)->name);
-         else if (mips_opts.insn32)
-           sprintf (buf, _("Opcode not supported in the `insn32' mode"));
-         else
-           sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
-                    8 * forced_insn_length);
-         insn_error = buf;
-
-         return;
-       }
-
-      imm_expr.X_op = O_absent;
-      imm2_expr.X_op = O_absent;
-      offset_expr.X_op = O_absent;
-      offset_reloc[0] = BFD_RELOC_UNUSED;
-      offset_reloc[1] = BFD_RELOC_UNUSED;
-      offset_reloc[2] = BFD_RELOC_UNUSED;
-
-      create_insn (ip, insn);
-      insn_error = NULL;
-      memset (&arg, 0, sizeof (arg));
-      arg.insn = ip;
-      arg.token = tokens;
-      arg.argnum = 1;
-      arg.last_regno = ILLEGAL_REG;
-      arg.dest_regno = ILLEGAL_REG;
-      arg.soft_match = (more_alts
-                       || (wrong_delay_slot_insns && need_delay_slot_ok));
-      for (args = insn->args;; ++args)
-       {
-         if (arg.token->type == OT_END)
-           {
-             /* Handle unary instructions in which only one operand is given.
-                The source is then the same as the destination.  */
-             if (arg.opnum == 1 && *args == ',')
-               switch (args[1])
-                 {
-                 case 'r':
-                 case 'v':
-                 case 'w':
-                 case 'W':
-                 case 'V':
-                   arg.token = tokens;
-                   arg.argnum = 1;
-                   continue;
-                 }
-
-             /* Treat elided base registers as $0.  */
-             if (strcmp (args, "(b)") == 0)
-               args += 3;
-
-             /* Fail the match if there were too few operands.  */
-             if (*args)
-               break;
-
-             /* Successful match.  */
-             if (arg.dest_regno == arg.last_regno
-                 && strncmp (ip->insn_mo->name, "jalr", 4) == 0)
-               {
-                 if (arg.opnum == 2)
-                   as_bad (_("Source and destination must be different"));
-                 else if (arg.last_regno == 31)
-                   as_bad (_("A destination register must be supplied"));
-               }
-             check_completed_insn (&arg);
-             obstack_free (&mips_operand_tokens, tokens);
-             return;
-           }
-
-         /* Fail the match if the line has too many operands.   */
-         if (*args == 0)
-           break;
-
-         /* Handle characters that need to match exactly.  */
-         if (*args == '(' || *args == ')' || *args == ',')
-           {
-             if (match_char (&arg, *args))
-               continue;
-             break;
-           }
-
-         /* Handle special macro operands.  Work out the properties of
-            other operands.  */
-         arg.opnum += 1;
-         arg.lax_max = FALSE;
-         optional_reg = FALSE;
-         switch (*args)
-           {
-           case '+':
-             switch (args[1])
-               {
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case 'B':
-               case 'C':
-               case 'F':
-               case 'G':
-               case 'H':
-               case 'J':
-               case 'Q':
-               case 'S':
-               case 's':
-                 /* If these integer forms come last, there is no other
-                    form of the instruction that could match.  Prefer to
-                    give detailed error messages where possible.  */
-                 if (args[2] == 0)
-                   arg.soft_match = FALSE;
-                 break;
-
-               case 'I':
-                 /* "+I" is like "I", except that imm2_expr is used.  */
-                 if (match_const_int (&arg, &imm2_expr.X_add_number, 0))
-                   imm2_expr.X_op = O_constant;
-                 else
-                   insn_error = _("absolute expression required");
-                 if (HAVE_32BIT_GPRS)
-                   normalize_constant_expr (&imm2_expr);
-                 ++args;
-                 continue;
-
-               case 'i':
-                 *offset_reloc = BFD_RELOC_MIPS_JMP;
-                 break;
-               }
-             break;
-
-           case '\'':
-           case ':':
-           case '@':
-           case '^':
-           case '$':
-           case '\\':
-           case '%':
-           case '|':
-           case '0':
-           case '1':
-           case '2':
-           case '3':
-           case '4':
-           case '5':
-           case '6':
-           case '8':
-           case 'B':
-           case 'C':
-           case 'J':
-           case 'O':
-           case 'P':
-           case 'Q':
-           case 'c':
-           case 'h':
-           case 'q':
-             /* If these integer forms come last, there is no other
-                form of the instruction that could match.  Prefer to
-                give detailed error messages where possible.  */
-             if (args[1] == 0)
-               arg.soft_match = FALSE;
-             break;
-
-           case 'r':
-           case 'v':
-           case 'w':
-           case 'W':
-           case 'V':
-             /* We have already matched a comma by this point, so the register
-                is only optional if there is another operand to come.  */
-             gas_assert (arg.opnum == 2);
-             optional_reg = (args[1] == ',');
-             break;
-
-           case 'I':
-             if (match_const_int (&arg, &imm_expr.X_add_number, 0))
-               imm_expr.X_op = O_constant;
-             else
-               insn_error = _("absolute expression required");
-             if (HAVE_32BIT_GPRS)
-               normalize_constant_expr (&imm_expr);
-             continue;
-
-           case 'A':
-             if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
-               {
-                 /* Assume that the offset has been elided and that what
-                    we saw was a base register.  The match will fail later
-                    if that assumption turns out to be wrong.  */
-                 offset_expr.X_op = O_constant;
-                 offset_expr.X_add_number = 0;
-               }
-             else if (match_expression (&arg, &offset_expr, offset_reloc))
-               normalize_address_expr (&offset_expr);
-             else
-               insn_error = _("absolute expression required");
-             continue;
-
-           case 'F':
-             if (!match_float_constant (&arg, &imm_expr, &offset_expr,
-                                        8, TRUE))
-               insn_error = _("floating-point expression required");
-             continue;
-
-           case 'L':
-             if (!match_float_constant (&arg, &imm_expr, &offset_expr,
-                                        8, FALSE))
-               insn_error = _("floating-point expression required");
-             continue;
-
-           case 'f':
-             if (!match_float_constant (&arg, &imm_expr, &offset_expr,
-                                        4, TRUE))
-               insn_error = _("floating-point expression required");
-             continue;
-
-           case 'l':
-             if (!match_float_constant (&arg, &imm_expr, &offset_expr,
-                                        4, FALSE))
-               insn_error = _("floating-point expression required");
-             continue;
-
-             /* ??? This is the traditional behavior, but is flaky if
-                there are alternative versions of the same instruction
-                for different subarchitectures.  The next alternative
-                might not be suitable.  */
-           case 'j':
-             /* For compatibility with older assemblers, we accept
-                0x8000-0xffff as signed 16-bit numbers when only
-                signed numbers are allowed.  */
-             arg.lax_max = !more_alts;
-           case 'i':
-             /* Only accept non-constant operands if this is the
-                final alternative.  Later alternatives might include
-                a macro implementation.  */
-             arg.allow_nonconst = !more_alts;
-             break;
-
-           case 'u':
-             /* There are no macro implementations for out-of-range values.  */
-             arg.allow_nonconst = TRUE;
-             break;
-
-           case 'o':
-             /* There should always be a macro implementation.  */
-             arg.allow_nonconst = FALSE;
-             break;
-
-           case 'p':
-             *offset_reloc = BFD_RELOC_16_PCREL_S2;
-             break;
-
-           case 'a':
-             *offset_reloc = BFD_RELOC_MIPS_JMP;
-             break;
-
-           case 'm':
-             gas_assert (mips_opts.micromips);
-             c = args[1];
-             switch (c)
-               {
-               case 't':
-               case 'c':
-               case 'e':
-                 /* We have already matched a comma by this point,
-                    so the register is only optional if there is another
-                    operand to come.  */
-                 gas_assert (arg.opnum == 2);
-                 optional_reg = (args[2] == ',');
-                 break;
-
-               case 'D':
-               case 'E':
-                 if (!forced_insn_length)
-                   *offset_reloc = (int) BFD_RELOC_UNUSED + c;
-                 else if (c == 'D')
-                   *offset_reloc = BFD_RELOC_MICROMIPS_10_PCREL_S1;
-                 else
-                   *offset_reloc = BFD_RELOC_MICROMIPS_7_PCREL_S1;
-                 break;
-               }
-             break;
-           }
-
-         operand = (mips_opts.micromips
-                    ? decode_micromips_operand (args)
-                    : decode_mips_operand (args));
-         if (!operand)
-           abort ();
-
-         if (optional_reg
-             && (arg.token[0].type != OT_REG
-                 || arg.token[1].type == OT_END))
-           {
-             /* Assume that the register has been elided and is the
-                same as the first operand.  */
-             arg.token = tokens;
-             arg.argnum = 1;
-           }
-
-         if (!match_operand (&arg, operand))
-           break;
-
-         /* Skip prefixes.  */
-         if (*args == '+' || *args == 'm')
-           args++;
+  if (!match_insns (insn, first, past, tokens, opcode_extra, FALSE)
+      && !match_insns (insn, first, past, tokens, opcode_extra, TRUE))
+    set_insn_error (0, _("invalid operands"));
 
-         continue;
-       }
-      /* Args don't match.  */
-      insn_error = _("Illegal operands");
-      if (more_alts)
-       {
-         ++insn;
-         continue;
-       }
-      if (wrong_delay_slot_insns && need_delay_slot_ok)
-       {
-         gas_assert (firstinsn);
-         need_delay_slot_ok = FALSE;
-         past = insn + 1;
-         insn = firstinsn;
-         continue;
-       }
-      obstack_free (&mips_operand_tokens, tokens);
-      return;
-    }
+  obstack_free (&mips_operand_tokens, tokens);
 }
 
 /* As for mips_ip, but used when assembling MIPS16 code.
@@ -12541,59 +12948,56 @@ mips_ip (char *str, struct mips_cl_insn *ip)
    bytes if the user explicitly requested a small or extended instruction.  */
 
 static void
-mips16_ip (char *str, struct mips_cl_insn *ip)
+mips16_ip (char *str, struct mips_cl_insn *insn)
 {
-  char *s;
-  const char *args;
-  struct mips_opcode *insn;
-  const struct mips_operand *operand;
-  const struct mips_operand *ext_operand;
-  struct mips_arg_info arg;
+  char *end, *s, c;
+  struct mips_opcode *first;
   struct mips_operand_token *tokens;
-  bfd_boolean optional_reg;
-
-  insn_error = NULL;
 
   forced_insn_length = 0;
 
   for (s = str; ISLOWER (*s); ++s)
     ;
-  switch (*s)
+  end = s;
+  c = *end;
+  switch (c)
     {
     case '\0':
       break;
 
     case ' ':
-      *s++ = '\0';
+      s++;
       break;
 
     case '.':
       if (s[1] == 't' && s[2] == ' ')
        {
-         *s = '\0';
          forced_insn_length = 2;
          s += 3;
          break;
        }
       else if (s[1] == 'e' && s[2] == ' ')
        {
-         *s = '\0';
          forced_insn_length = 4;
          s += 3;
          break;
        }
       /* Fall through.  */
     default:
-      insn_error = _("unknown opcode");
+      set_insn_error (0, _("unrecognized opcode"));
       return;
     }
 
   if (mips_opts.noautoextend && !forced_insn_length)
     forced_insn_length = 2;
 
-  if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
+  *end = 0;
+  first = (struct mips_opcode *) hash_find (mips16_op_hash, str);
+  *end = c;
+
+  if (!first)
     {
-      insn_error = _("unrecognized opcode");
+      set_insn_error (0, _("unrecognized opcode"));
       return;
     }
 
@@ -12601,228 +13005,10 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
   if (!tokens)
     return;
 
-  for (;;)
-    {
-      bfd_boolean ok;
-      bfd_boolean more_alts;
-      char relax_char;
-
-      gas_assert (strcmp (insn->name, str) == 0);
-
-      ok = is_opcode_valid_16 (insn);
-      more_alts = (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
-                  && strcmp (insn[0].name, insn[1].name) == 0);
-      if (! ok)
-       {
-         if (more_alts)
-           {
-             ++insn;
-             continue;
-           }
-         else
-           {
-             if (!insn_error)
-               {
-                 static char buf[100];
-                 sprintf (buf,
-                          _("Opcode not supported on this processor: %s (%s)"),
-                          mips_cpu_info_from_arch (mips_opts.arch)->name,
-                          mips_cpu_info_from_isa (mips_opts.isa)->name);
-                 insn_error = buf;
-               }
-             obstack_free (&mips_operand_tokens, tokens);
-             return;
-           }
-       }
-
-      create_insn (ip, insn);
-      imm_expr.X_op = O_absent;
-      imm2_expr.X_op = O_absent;
-      offset_expr.X_op = O_absent;
-      offset_reloc[0] = BFD_RELOC_UNUSED;
-      offset_reloc[1] = BFD_RELOC_UNUSED;
-      offset_reloc[2] = BFD_RELOC_UNUSED;
-      relax_char = 0;
-
-      memset (&arg, 0, sizeof (arg));
-      arg.insn = ip;
-      arg.token = tokens;
-      arg.argnum = 1;
-      arg.last_regno = ILLEGAL_REG;
-      arg.dest_regno = ILLEGAL_REG;
-      arg.soft_match = more_alts;
-      relax_char = 0;
-      for (args = insn->args; 1; ++args)
-       {
-         int c;
-
-         if (arg.token->type == OT_END)
-           {
-             offsetT value;
-
-             /* Handle unary instructions in which only one operand is given.
-                The source is then the same as the destination.  */
-             if (arg.opnum == 1 && *args == ',')
-               switch (args[1])
-                 {
-                 case 'v':
-                 case 'w':
-                   arg.token = tokens;
-                   arg.argnum = 1;
-                   continue;
-                 }
-
-             /* Fail the match if there were too few operands.  */
-             if (*args)
-               break;
-
-             /* Successful match.  Stuff the immediate value in now, if
-                we can.  */
-             if (insn->pinfo == INSN_MACRO)
-               {
-                 gas_assert (relax_char == 0 || relax_char == 'p');
-                 gas_assert (*offset_reloc == BFD_RELOC_UNUSED);
-               }
-             else if (relax_char
-                      && offset_expr.X_op == O_constant
-                      && calculate_reloc (*offset_reloc,
-                                          offset_expr.X_add_number,
-                                          &value))
-               {
-                 mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
-                               forced_insn_length, &ip->insn_opcode);
-                 offset_expr.X_op = O_absent;
-                 *offset_reloc = BFD_RELOC_UNUSED;
-               }
-             else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
-               {
-                 if (forced_insn_length == 2)
-                   as_bad (_("invalid unextended operand value"));
-                 forced_insn_length = 4;
-                 ip->insn_opcode |= MIPS16_EXTEND;
-               }
-             else if (relax_char)
-               *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
-
-             check_completed_insn (&arg);
-             obstack_free (&mips_operand_tokens, tokens);
-             return;
-           }
-
-         /* Fail the match if the line has too many operands.   */
-         if (*args == 0)
-           break;
-
-         /* Handle characters that need to match exactly.  */
-         if (*args == '(' || *args == ')' || *args == ',')
-           {
-             if (match_char (&arg, *args))
-               continue;
-             break;
-           }
-
-         arg.opnum += 1;
-         optional_reg = FALSE;
-         c = *args;
-         switch (c)
-           {
-           case 'v':
-           case 'w':
-             optional_reg = (args[1] == ',');
-             break;
-
-           case 'p':
-           case 'q':
-           case 'A':
-           case 'B':
-           case 'E':
-             relax_char = c;
-             break;
-
-           case 'I':
-             if (match_const_int (&arg, &imm_expr.X_add_number, 0))
-               imm_expr.X_op = O_constant;
-             else
-               insn_error = _("absolute expression required");
-             if (HAVE_32BIT_GPRS)
-               normalize_constant_expr (&imm_expr);
-             continue;
-
-           case 'a':
-           case 'i':
-             *offset_reloc = BFD_RELOC_MIPS16_JMP;
-             ip->insn_opcode <<= 16;
-             break;
-           }
+  if (!match_mips16_insns (insn, first, tokens))
+    set_insn_error (0, _("invalid operands"));
 
-         operand = decode_mips16_operand (c, FALSE);
-         if (!operand)
-           abort ();
-
-         /* '6' is a special case.  It is used for BREAK and SDBBP,
-            whose operands are only meaningful to the software that decodes
-            them.  This means that there is no architectural reason why
-            they cannot be prefixed by EXTEND, but in practice,
-            exception handlers will only look at the instruction
-            itself.  We therefore allow '6' to be extended when
-            disassembling but not when assembling.  */
-         if (operand->type != OP_PCREL && c != '6')
-           {
-             ext_operand = decode_mips16_operand (c, TRUE);
-             if (operand != ext_operand)
-               {
-                 if (arg.token->type == OT_CHAR && arg.token->u.ch == '(')
-                   {
-                     offset_expr.X_op = O_constant;
-                     offset_expr.X_add_number = 0;
-                     relax_char = c;
-                     continue;
-                   }
-
-                 /* We need the OT_INTEGER check because some MIPS16
-                    immediate variants are listed before the register ones.  */
-                 if (arg.token->type != OT_INTEGER
-                     || !match_expression (&arg, &offset_expr, offset_reloc))
-                   break;
-
-                 /* '8' is used for SLTI(U) and has traditionally not
-                    been allowed to take relocation operators.  */
-                 if (offset_reloc[0] != BFD_RELOC_UNUSED
-                     && (ext_operand->size != 16 || c == '8'))
-                   break;
-
-                 relax_char = c;
-                 continue;
-               }
-           }
-
-         if (optional_reg
-             && (arg.token[0].type != OT_REG
-                 || arg.token[1].type == OT_END))
-           {
-             /* Assume that the register has been elided and is the
-                same as the first operand.  */
-             arg.token = tokens;
-             arg.argnum = 1;
-           }
-
-         if (!match_operand (&arg, operand))
-           break;
-         continue;
-       }
-
-      /* Args don't match.  */
-      if (more_alts)
-       {
-         ++insn;
-         continue;
-       }
-
-      insn_error = _("illegal operands");
-
-      obstack_free (&mips_operand_tokens, tokens);
-      return;
-    }
+  obstack_free (&mips_operand_tokens, tokens);
 }
 
 /* Marshal immediate value VAL for an extended MIPS16 instruction.
@@ -13147,7 +13333,7 @@ static void
 mips_set_option_string (const char **string_ptr, const char *new_value)
 {
   if (*string_ptr != 0 && strcasecmp (*string_ptr, new_value) != 0)
-    as_warn (_("A different %s was already specified, is now %s"),
+    as_warn (_("a different %s was already specified, is now %s"),
             string_ptr == &mips_arch_string ? "-march" : "-mtune",
             new_value);
 
@@ -13440,7 +13626,7 @@ md_parse_option (int c, char *arg)
     case OPTION_64:
       mips_abi = N64_ABI;
       if (!support_64bit_objects())
-       as_fatal (_("No compiled in support for 64 bit object file format"));
+       as_fatal (_("no compiled in support for 64 bit object file format"));
       break;
 
     case OPTION_GP32:
@@ -13486,7 +13672,7 @@ md_parse_option (int c, char *arg)
        {
          mips_abi = N64_ABI;
          if (! support_64bit_objects())
-           as_fatal (_("No compiled in support for 64 bit object file "
+           as_fatal (_("no compiled in support for 64 bit object file "
                        "format"));
        }
       else if (strcmp (arg, "eabi") == 0)
@@ -13533,7 +13719,7 @@ md_parse_option (int c, char *arg)
        mips_flag_nan2008 = FALSE;
       else
        {
-         as_fatal (_("Invalid NaN setting -mnan=%s"), arg);
+         as_fatal (_("invalid NaN setting -mnan=%s"), arg);
          return 0;
        }
       break;
@@ -13582,7 +13768,7 @@ mips_after_parse_args (void)
   if (strncmp (TARGET_OS, "pe", 2) == 0)
     {
       if (g_switch_seen && g_switch_value != 0)
-       as_bad (_("-G not supported in this configuration."));
+       as_bad (_("-G not supported in this configuration"));
       g_switch_value = 0;
     }
 
@@ -13608,7 +13794,8 @@ mips_after_parse_args (void)
             There's no harm in specifying both as long as the ISA levels
             are the same.  */
          if (file_mips_isa != arch_info->isa)
-           as_bad (_("-%s conflicts with the other architecture options, which imply -%s"),
+           as_bad (_("-%s conflicts with the other architecture options,"
+                     " which imply -%s"),
                    mips_cpu_info_from_isa (file_mips_isa)->name,
                    mips_cpu_info_from_isa (arch_info->isa)->name);
        }
@@ -13769,7 +13956,8 @@ md_pcrel_from (fixS *fixP)
       /* We have no relocation type for PC relative MIPS16 instructions.  */
       if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("PC relative MIPS16 instruction references a different section"));
+                     _("PC relative MIPS16 instruction references"
+                       " a different section"));
       return addr;
     }
 }
@@ -14110,7 +14298,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
            }
          else
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("Unsupported constant in relocation"));
+                         _("unsupported constant in relocation"));
        }
       break;
 
@@ -14149,7 +14337,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_16_PCREL_S2:
       if ((*valP & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("Branch to misaligned address (%lx)"), (long) *valP);
+                     _("branch to misaligned address (%lx)"), (long) *valP);
 
       /* We need to save the bits in the instruction since fixup_segment()
         might be deleting the relocation entry (i.e., a branch within
@@ -14193,7 +14381,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
             and there's nothing we can do to fix this instruction
             without turning it into a longer sequence.  */
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("Branch out of range"));
+                       _("branch out of range"));
        }
       break;
 
@@ -14291,10 +14479,10 @@ s_align (int x ATTRIBUTE_UNUSED)
 
   temp = get_absolute_expression ();
   if (temp > max_alignment)
-    as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment);
+    as_bad (_("alignment too large, %d assumed"), temp = max_alignment);
   else if (temp < 0)
     {
-      as_warn (_("Alignment negative: 0 assumed."));
+      as_warn (_("alignment negative, 0 assumed"));
       temp = 0;
     }
   if (*input_line_pointer == ',')
@@ -14590,7 +14778,7 @@ s_option (int x ATTRIBUTE_UNUSED)
        }
     }
   else
-    as_warn (_("Unrecognized option \"%s\""), opt);
+    as_warn (_("unrecognized option \"%s\""), opt);
 
   *input_line_pointer = c;
   demand_empty_rest_of_line ();
@@ -14634,7 +14822,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
       char *s = name + 3;
 
       if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &mips_opts.at))
-       as_bad (_("Unrecognized register name `%s'"), s);
+       as_bad (_("unrecognized register name `%s'"), s);
     }
   else if (strcmp (name, "at") == 0)
     {
@@ -14853,7 +15041,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     }
   else
     {
-      as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
+      as_warn (_("tried to set unrecognized symbol: %s\n"), name);
     }
   mips_check_isa_supports_ases ();
   *input_line_pointer = ch;
@@ -15210,7 +15398,7 @@ s_tls_rel_directive (const size_t bytes, const char *dirstr,
 
   if (ex.X_op != O_symbol)
     {
-      as_bad (_("Unsupported use of %s"), dirstr);
+      as_bad (_("unsupported use of %s"), dirstr);
       ignore_rest_of_line ();
     }
 
@@ -15301,7 +15489,7 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
-      as_bad (_("Unsupported use of .gpword"));
+      as_bad (_("unsupported use of .gpword"));
       ignore_rest_of_line ();
     }
 
@@ -15339,7 +15527,7 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
-      as_bad (_("Unsupported use of .gpdword"));
+      as_bad (_("unsupported use of .gpdword"));
       ignore_rest_of_line ();
     }
 
@@ -15371,7 +15559,7 @@ s_ehword (int ignore ATTRIBUTE_UNUSED)
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
-      as_bad (_("Unsupported use of .ehword"));
+      as_bad (_("unsupported use of .ehword"));
       ignore_rest_of_line ();
     }
 
@@ -15446,7 +15634,7 @@ s_nan (int ignore ATTRIBUTE_UNUSED)
           && memcmp (input_line_pointer, str_legacy, i) == 0)
     mips_flag_nan2008 = FALSE;
   else
-    as_bad (_("Bad .nan directive"));
+    as_bad (_("bad .nan directive"));
 
   input_line_pointer += i;
   demand_empty_rest_of_line ();
@@ -16245,7 +16433,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("Can not represent %s relocation in this object file format"),
+                   _("cannot represent %s relocation in this object file"
+                     " format"),
                    bfd_get_reloc_code_name (code));
       retval[0] = NULL;
     }
@@ -16339,7 +16528,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;
@@ -16592,7 +16781,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
 
       /* Relax 32-bit branches to a sequence of instructions.  */
       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"));
 
       /* Set the short-delay-slot bit.  */
       short_ds = al && (insn & 0x02000000) != 0;
@@ -17259,7 +17448,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
 
   if (!cur_proc_ptr)
     {
-      as_warn (_(".end directive without a preceding .ent directive."));
+      as_warn (_(".end directive without a preceding .ent directive"));
       demand_empty_rest_of_line ();
       return;
     }
@@ -17268,7 +17457,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
     {
       gas_assert (S_GET_NAME (p));
       if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
-       as_warn (_(".end symbol does not match .ent symbol."));
+       as_warn (_(".end symbol does not match .ent symbol"));
 
       if (debug_type == DEBUG_STABS)
        stabs_generate_asm_endfunc (S_GET_NAME (p),
@@ -17345,7 +17534,7 @@ s_mips_ent (int aent)
     get_number ();
 
   if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
-    as_warn (_(".ent or .aent not in text section."));
+    as_warn (_(".ent or .aent not in text section"));
 
   if (!aent && cur_proc_ptr)
     as_warn (_("missing .end"));
@@ -17401,7 +17590,7 @@ s_mips_frame (int ignore ATTRIBUTE_UNUSED)
       if (*input_line_pointer++ != ','
          || get_absolute_expression_and_terminator (&val) != ',')
        {
-         as_warn (_("Bad .frame directive"));
+         as_warn (_("bad .frame directive"));
          --input_line_pointer;
          demand_empty_rest_of_line ();
          return;
@@ -17438,7 +17627,7 @@ s_mips_mask (int reg_type)
 
       if (get_absolute_expression_and_terminator (&mask) != ',')
        {
-         as_warn (_("Bad .mask/.fmask directive"));
+         as_warn (_("bad .mask/.fmask directive"));
          --input_line_pointer;
          demand_empty_rest_of_line ();
          return;
@@ -17709,7 +17898,7 @@ mips_parse_cpu (const char *option, const char *cpu_string)
     if (mips_matching_cpu_name_p (p->name, cpu_string))
       return p;
 
-  as_bad (_("Bad value (%s) for %s"), cpu_string, option);
+  as_bad (_("bad value (%s) for %s"), cpu_string, option);
   return 0;
 }
 
This page took 0.111435 seconds and 4 git commands to generate.