Add support for a __gcc_isr pseudo isntruction to the AVR assembler.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 1df1f86ebea9cc07a7205ba3bf02cb7f7144b42d..1d477a11341eafe8f4661f45a58e6658ee6d4881 100644 (file)
@@ -1130,25 +1130,40 @@ static bfd_boolean mips_ignore_branch_isa;
    store whether this is known to be a branch to a different section,
    whether we have tried to relax this frag yet, and whether we have
    ever extended a PC relative fragment because of a shift count.  */
-#define RELAX_MIPS16_ENCODE(type, small, ext, dslot, jal_dslot)        \
+#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro,     \
+                           small, ext,                         \
+                           dslot, jal_dslot)                   \
   (0x80000000                                                  \
    | ((type) & 0xff)                                           \
-   | ((small) ? 0x100 : 0)                                     \
-   | ((ext) ? 0x200 : 0)                                       \
-   | ((dslot) ? 0x400 : 0)                                     \
-   | ((jal_dslot) ? 0x800 : 0))
+   | ((e2) ? 0x100 : 0)                                                \
+   | ((pic) ? 0x200 : 0)                                       \
+   | ((sym32) ? 0x400 : 0)                                     \
+   | ((nomacro) ? 0x800 : 0)                                   \
+   | ((small) ? 0x1000 : 0)                                    \
+   | ((ext) ? 0x2000 : 0)                                      \
+   | ((dslot) ? 0x4000 : 0)                                    \
+   | ((jal_dslot) ? 0x8000 : 0))
+
 #define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
 #define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
-#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
-#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
-#define RELAX_MIPS16_DSLOT(i) (((i) & 0x400) != 0)
-#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x800) != 0)
-#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x1000) != 0)
-#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x1000)
-#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
-#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
-#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
-#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
+#define RELAX_MIPS16_E2(i) (((i) & 0x100) != 0)
+#define RELAX_MIPS16_PIC(i) (((i) & 0x200) != 0)
+#define RELAX_MIPS16_SYM32(i) (((i) & 0x400) != 0)
+#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x800) != 0)
+#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x1000) != 0)
+#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x2000) != 0)
+#define RELAX_MIPS16_DSLOT(i) (((i) & 0x4000) != 0)
+#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x8000) != 0)
+
+#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x10000) != 0)
+#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x10000)
+#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x10000)
+#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x20000) != 0)
+#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x20000)
+#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x20000)
+#define RELAX_MIPS16_MACRO(i) (((i) & 0x40000) != 0)
+#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x40000)
+#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x40000)
 
 /* For microMIPS code, we use relaxation similar to one we use for
    MIPS16 code.  Some instructions that take immediate values support
@@ -1328,6 +1343,7 @@ static void macro (struct mips_cl_insn *ip, char *str);
 static void mips16_macro (struct mips_cl_insn * ip);
 static void mips_ip (char *str, struct mips_cl_insn * ip);
 static void mips16_ip (char *str, struct mips_cl_insn * ip);
+static unsigned long mips16_immed_extend (offsetT, unsigned int);
 static void mips16_immed
   (const char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
    unsigned int, unsigned long *);
@@ -1442,6 +1458,8 @@ enum options
     OPTION_NO_MICROMIPS,
     OPTION_MCU,
     OPTION_NO_MCU,
+    OPTION_MIPS16E2,
+    OPTION_NO_MIPS16E2,
     OPTION_COMPAT_ARCH_BASE,
     OPTION_M4650,
     OPTION_NO_M4650,
@@ -1562,6 +1580,8 @@ struct option md_longopts[] =
   {"mno-msa", no_argument, NULL, OPTION_NO_MSA},
   {"mxpa", no_argument, NULL, OPTION_XPA},
   {"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
+  {"mmips16e2", no_argument, NULL, OPTION_MIPS16E2},
+  {"mno-mips16e2", no_argument, NULL, OPTION_NO_MIPS16E2},
 
   /* Old-style architecture options.  Don't add more of these.  */
   {"m4650", no_argument, NULL, OPTION_M4650},
@@ -1742,8 +1762,13 @@ static const struct mips_ase mips_ases[] = {
 
   { "xpa", ASE_XPA, 0,
     OPTION_XPA, OPTION_NO_XPA,
-     2,  2, -1, -1,
+    2, 2, 2, 2,
     -1 },
+
+  { "mips16e2", ASE_MIPS16E2, 0,
+    OPTION_MIPS16E2, OPTION_NO_MIPS16E2,
+    2,  2, -1, -1,
+    6 },
 };
 
 /* The set of ASEs that require -mfp64.  */
@@ -2105,8 +2130,28 @@ mips_set_ase (const struct mips_ase *ase, struct mips_set_options *opts,
 
   mask = mips_ase_mask (ase->flags);
   opts->ase &= ~mask;
+
+  /* Clear combination ASE flags, which need to be recalculated based on
+     updated regular ASE settings.  */
+  opts->ase &= ~(ASE_MIPS16E2_MT | ASE_XPA_VIRT);
+
   if (enabled_p)
     opts->ase |= ase->flags;
+
+  /* The Virtualization ASE has eXtended Physical Addressing (XPA)
+     instructions which are only valid when both ASEs are enabled.
+     This sets the ASE_XPA_VIRT flag when both ASEs are present.  */
+  if ((opts->ase & (ASE_XPA | ASE_VIRT)) == (ASE_XPA | ASE_VIRT))
+    {
+      opts->ase |= ASE_XPA_VIRT;
+      mask |= ASE_XPA_VIRT;
+    }
+  if ((opts->ase & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT))
+    {
+      opts->ase |= ASE_MIPS16E2_MT;
+      mask |= ASE_MIPS16E2_MT;
+    }
+
   return mask;
 }
 
@@ -2213,7 +2258,12 @@ static inline void
 insn_insert_operand (struct mips_cl_insn *insn,
                     const struct mips_operand *operand, unsigned int uval)
 {
-  insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
+  if (mips_opts.mips16
+      && operand->type == OP_INT && operand->lsb == 0
+      && mips_opcode_32bit_p (insn->insn_mo))
+    insn->insn_opcode |= mips16_immed_extend (uval, operand->size);
+  else
+    insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
 }
 
 /* Extract the value of OPERAND from INSN.  */
@@ -3273,7 +3323,16 @@ is_opcode_valid (const struct mips_opcode *mo)
 static bfd_boolean
 is_opcode_valid_16 (const struct mips_opcode *mo)
 {
-  return opcode_is_member (mo, mips_opts.isa, 0, mips_opts.arch);
+  int isa = mips_opts.isa;
+  int ase = mips_opts.ase;
+  unsigned int i;
+
+  if (ISA_HAS_64BIT_REGS (isa))
+    for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+      if ((ase & mips_ases[i].flags) == mips_ases[i].flags)
+       ase |= mips_ases[i].flags64;
+
+  return opcode_is_member (mo, isa, ase, mips_opts.arch);
 }
 
 /* Return TRUE if the size of the microMIPS opcode MO matches one
@@ -3404,7 +3463,11 @@ validate_mips_insn (const struct mips_opcode *opcode,
          }
        gas_assert (opno < MAX_OPERANDS);
        operands->operand[opno] = operand;
-       if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
+       if (!decode_operand && operand
+           && operand->type == OP_INT && operand->lsb == 0
+           && mips_opcode_32bit_p (opcode))
+         used_bits |= mips16_immed_extend (-1, operand->size);
+       else if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
          {
            used_bits = mips_insert_operand (operand, used_bits, -1);
            if (operand->type == OP_MDMX_IMM_REG)
@@ -3413,6 +3476,10 @@ validate_mips_insn (const struct mips_opcode *opcode,
              used_bits &= ~(1 << (operand->lsb + 5));
            if (operand->type == OP_ENTRY_EXIT_LIST)
              used_bits &= ~(mask & 0x700);
+           /* interAptiv MR2 SAVE/RESTORE instructions have a discontiguous
+              operand field that cannot be fully described with LSB/SIZE.  */
+           if (operand->type == OP_SAVE_RESTORE_LIST && operand->lsb == 6)
+             used_bits &= ~0x6000;
          }
        /* Skip prefix characters.  */
        if (decode_operand && (*s == '+' || *s == 'm' || *s == '-'))
@@ -4488,6 +4555,9 @@ operand_reg_mask (const struct mips_cl_insn *insn,
     case OP_IMM_INDEX:
       abort ();
 
+    case OP_REG28:
+      return 1 << 28;
+
     case OP_REG:
     case OP_OPTIONAL_REG:
       {
@@ -4828,8 +4898,7 @@ match_expression (struct mips_arg_info *arg, expressionS *value,
 
 /* Try to get a constant expression from the next tokens in ARG.  Consume
    the tokens and return return true on success, storing the constant value
-   in *VALUE.  Use FALLBACK as the value if the match succeeded with an
-   error.  */
+   in *VALUE.  */
 
 static bfd_boolean
 match_const_int (struct mips_arg_info *arg, offsetT *value)
@@ -4844,7 +4913,10 @@ match_const_int (struct mips_arg_info *arg, offsetT *value)
     *value = ex.X_add_number;
   else
     {
-      match_not_constant (arg);
+      if (r[0] == BFD_RELOC_UNUSED && ex.X_op == O_big)
+       match_out_of_range (arg);
+      else
+       match_not_constant (arg);
       return FALSE;
     }
   return TRUE;
@@ -5050,6 +5122,12 @@ match_int_operand (struct mips_arg_info *arg,
       if (!match_expression (arg, &offset_expr, offset_reloc))
        return FALSE;
 
+      if (offset_expr.X_op == O_big)
+       {
+         match_out_of_range (arg);
+         return FALSE;
+       }
+
       if (offset_reloc[0] != BFD_RELOC_UNUSED)
        /* Relocation operators were used.  Accept the argument and
           leave the relocation value in offset_expr and offset_relocs
@@ -5061,7 +5139,10 @@ match_int_operand (struct mips_arg_info *arg,
          /* Accept non-constant operands if no later alternative matches,
             leaving it for the caller to process.  */
          if (!arg->lax_match)
-           return FALSE;
+           {
+             match_not_constant (arg);
+             return FALSE;
+           }
          offset_reloc[0] = BFD_RELOC_LO16;
          return TRUE;
        }
@@ -5078,7 +5159,10 @@ match_int_operand (struct mips_arg_info *arg,
        {
          max_val = ((1 << operand_base->size) - 1) << operand->shift;
          if (!arg->lax_match && sval <= max_val)
-           return FALSE;
+           {
+             match_out_of_range (arg);
+             return FALSE;
+           }
        }
     }
   else
@@ -5488,6 +5572,39 @@ match_entry_exit_operand (struct mips_arg_info *arg,
   return TRUE;
 }
 
+/* Encode regular MIPS SAVE/RESTORE instruction operands according to
+   the argument register mask AMASK, the number of static registers
+   saved NSREG, the $ra, $s0 and $s1 register specifiers RA, S0 and S1
+   respectively, and the frame size FRAME_SIZE.  */
+
+static unsigned int
+mips_encode_save_restore (unsigned int amask, unsigned int nsreg,
+                         unsigned int ra, unsigned int s0, unsigned int s1,
+                         unsigned int frame_size)
+{
+  return ((nsreg << 23) | ((frame_size & 0xf0) << 15) | (amask << 15)
+         | (ra << 12) | (s0 << 11) | (s1 << 10) | ((frame_size & 0xf) << 6));
+}
+
+/* Encode MIPS16 SAVE/RESTORE instruction operands according to the
+   argument register mask AMASK, the number of static registers saved
+   NSREG, the $ra, $s0 and $s1 register specifiers RA, S0 and S1
+   respectively, and the frame size FRAME_SIZE.  */
+
+static unsigned int
+mips16_encode_save_restore (unsigned int amask, unsigned int nsreg,
+                           unsigned int ra, unsigned int s0, unsigned int s1,
+                           unsigned int frame_size)
+{
+  unsigned int args;
+
+  args = (ra << 6) | (s0 << 5) | (s1 << 4) | (frame_size & 0xf);
+  if (nsreg || amask || frame_size == 0 || frame_size > 16)
+    args |= (MIPS16_EXTEND | (nsreg << 24) | (amask << 16)
+            | ((frame_size & 0xf0) << 16));
+  return args;
+}
+
 /* OP_SAVE_RESTORE_LIST matcher.  */
 
 static bfd_boolean
@@ -5495,6 +5612,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;
+  unsigned int arg_mask, ra, s0, s1;
   offsetT frame_size;
 
   opcode = arg->insn->insn_opcode;
@@ -5503,6 +5621,9 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
   args = 0;
   statics = 0;
   sregs = 0;
+  ra = 0;
+  s0 = 0;
+  s1 = 0;
   do
     {
       unsigned int regno1, regno2;
@@ -5538,7 +5659,7 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
                sregs |= 1 << 8;
              else if (regno1 == 31)
                /* Add $ra to insn.  */
-               opcode |= 0x40;
+               ra = 1;
              else
                return FALSE;
              regno1 += 1;
@@ -5554,10 +5675,10 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
     return FALSE;
   else if (args == 0xf)
     /* All $a0-$a3 are args.  */
-    opcode |= MIPS16_ALL_ARGS << 16;
+    arg_mask = MIPS_SVRS_ALL_ARGS;
   else if (statics == 0xf)
     /* All $a0-$a3 are statics.  */
-    opcode |= MIPS16_ALL_STATICS << 16;
+    arg_mask = MIPS_SVRS_ALL_STATICS;
   else
     {
       /* Count arg registers.  */
@@ -5581,14 +5702,14 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
        return FALSE;
 
       /* Encode args/statics.  */
-      opcode |= ((num_args << 2) | num_statics) << 16;
+      arg_mask = (num_args << 2) | num_statics;
     }
 
   /* Encode $s0/$s1.  */
   if (sregs & (1 << 0))                /* $s0 */
-    opcode |= 0x20;
+    s0 = 1;
   if (sregs & (1 << 1))                /* $s1 */
-    opcode |= 0x10;
+    s1 = 1;
   sregs >>= 2;
 
   /* Encode $s2-$s8. */
@@ -5600,7 +5721,6 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
     }
   if (sregs != 0)
     return FALSE;
-  opcode |= num_sregs << 24;
 
   /* Encode frame size.  */
   if (num_frame_sizes == 0)
@@ -5618,16 +5738,18 @@ match_save_restore_list_operand (struct mips_arg_info *arg)
       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));
-    }
+  frame_size /= 8;
 
   /* Finally build the instruction.  */
-  if ((opcode >> 16) != 0 || frame_size == 0)
-    opcode |= MIPS16_EXTEND;
+  if (mips_opts.mips16)
+    opcode |= mips16_encode_save_restore (arg_mask, num_sregs, ra, s0, s1,
+                                         frame_size);
+  else if (!mips_opts.micromips)
+    opcode |= mips_encode_save_restore (arg_mask, num_sregs, ra, s0, s1,
+                                       frame_size);
+  else
+    abort ();
+
   arg->insn->insn_opcode = opcode;
   return TRUE;
 }
@@ -5768,6 +5890,23 @@ match_pc_operand (struct mips_arg_info *arg)
   return FALSE;
 }
 
+/* OP_REG28 matcher.  */
+
+static bfd_boolean
+match_reg28_operand (struct mips_arg_info *arg)
+{
+  unsigned int regno;
+
+  if (arg->token->type == OT_REG
+      && match_regno (arg, OP_REG_GP, arg->token->u.regno, &regno)
+      && regno == GP)
+    {
+      ++arg->token;
+      return TRUE;
+    }
+  return FALSE;
+}
+
 /* OP_NON_ZERO_REG matcher.  */
 
 static bfd_boolean
@@ -5798,9 +5937,9 @@ match_tied_reg_operand (struct mips_arg_info *arg, unsigned int other_regno)
   return match_reg (arg, OP_REG_GP, &regno) && regno == other_regno;
 }
 
-/* Read a floating-point constant from S for LI.S or LI.D.  LENGTH is
-   the length of the value in bytes (4 for float, 8 for double) and
-   USING_GPRS says whether the destination is a GPR rather than an FPR.
+/* Try to match a floating-point constant from ARG for LI.S or LI.D.
+   LENGTH is the length of the value in bytes (4 for float, 8 for double)
+   and USING_GPRS says whether the destination is a GPR rather than an FPR.
 
    Return the constant in IMM and OFFSET as follows:
 
@@ -5994,8 +6133,8 @@ match_vu0_suffix_operand (struct mips_arg_info *arg,
   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.  */
+/* Try to match a token from ARG against OPERAND.  Consume the token
+   and return true on success, otherwise return false.  */
 
 static bfd_boolean
 match_operand (struct mips_arg_info *arg,
@@ -6052,6 +6191,9 @@ match_operand (struct mips_arg_info *arg,
     case OP_PC:
       return match_pc_operand (arg);
 
+    case OP_REG28:
+      return match_reg28_operand (arg);
+
     case OP_VU0_SUFFIX:
       return match_vu0_suffix_operand (arg, operand, FALSE);
 
@@ -6824,7 +6966,7 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
                   break;
                 }
             }
-          if (rv == FALSE)
+          if (!rv)
             {
               /* Insert nop after branch to fix short loop. */
               return FALSE;
@@ -7419,11 +7561,16 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
       else
        {
          symbol = make_expr_symbol (address_expr);
+         symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP);
          offset = 0;
        }
-      add_relaxed_insn (ip, 4, 0,
+      add_relaxed_insn (ip, 12, 0,
                        RELAX_MIPS16_ENCODE
                        (*reloc_type - BFD_RELOC_UNUSED,
+                        mips_opts.ase & ASE_MIPS16E2,
+                        mips_pic != NO_PIC,
+                        HAVE_32BIT_SYMBOLS,
+                        mips_opts.warn_about_macros,
                         require_unextended, require_extended,
                         delayed_branch_p (&history[0]),
                         history[0].mips16_absolute_jump_p),
@@ -8087,6 +8234,7 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
   const char *args;
   const struct mips_operand *operand;
   const struct mips_operand *ext_operand;
+  bfd_boolean pcrel = FALSE;
   int required_insn_length;
   struct mips_arg_info arg;
   int relax_char;
@@ -8148,6 +8296,7 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
            }
          else if (relax_char
                   && offset_expr.X_op == O_constant
+                  && !pcrel
                   && calculate_reloc (*offset_reloc,
                                       offset_expr.X_add_number,
                                       &value))
@@ -8161,7 +8310,7 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
            {
              if (required_insn_length == 2)
                set_insn_error (0, _("invalid unextended operand value"));
-             else
+             else if (!mips_opcode_32bit_p (opcode))
                {
                  forced_insn_length = 4;
                  insn->insn_opcode |= MIPS16_EXTEND;
@@ -8195,6 +8344,8 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
        case 'A':
        case 'B':
        case 'E':
+       case 'V':
+       case 'u':
          relax_char = c;
          break;
 
@@ -8216,7 +8367,9 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
       if (!operand)
        abort ();
 
-      if (operand->type != OP_PCREL)
+      if (operand->type == OP_PCREL)
+       pcrel = TRUE;
+      else
        {
          ext_operand = decode_mips16_operand (c, TRUE);
          if (operand != ext_operand)
@@ -8229,17 +8382,23 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
                  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))
+             if (!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;
+               {
+                 match_not_constant (&arg);
+                 return FALSE;
+               }
+
+             if (offset_expr.X_op == O_big)
+               {
+                 match_out_of_range (&arg);
+                 return FALSE;
+               }
 
              relax_char = c;
              continue;
@@ -13882,7 +14041,7 @@ mips16_ip (char *str, struct mips_cl_insn *insn)
   struct mips_operand_token *tokens;
   unsigned int l;
 
-  for (s = str; ISLOWER (*s); ++s)
+  for (s = str; *s != '\0' && *s != '.' && *s != ' '; ++s)
     ;
   end = s;
   c = *end;
@@ -13913,8 +14072,6 @@ mips16_ip (char *str, struct mips_cl_insn *insn)
        break;
       else if (*s++ == ' ')
        break;
-      /* Fall through.  */
-    default:
       set_insn_error (0, _("unrecognized opcode"));
       return;
     }
@@ -13947,7 +14104,10 @@ static unsigned long
 mips16_immed_extend (offsetT val, unsigned int nbits)
 {
   int extval;
-  if (nbits == 16)
+
+  extval = 0;
+  val &= (1U << nbits) - 1;
+  if (nbits == 16 || nbits == 9)
     {
       extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
       val &= 0x1f;
@@ -13957,7 +14117,7 @@ mips16_immed_extend (offsetT val, unsigned int nbits)
       extval = ((val >> 11) & 0xf) | (val & 0x7f0);
       val &= 0xf;
     }
-  else
+  else if (nbits == 6)
     {
       extval = ((val & 0x1f) << 6) | (val & 0x20);
       val = 0;
@@ -14073,6 +14233,7 @@ static const struct percent_op_match mips_percent_op[] =
   {"%got_lo", BFD_RELOC_MIPS_GOT_LO16},
   {"%got", BFD_RELOC_MIPS_GOT16},
   {"%gp_rel", BFD_RELOC_GPREL16},
+  {"%gprel", BFD_RELOC_GPREL16},
   {"%half", BFD_RELOC_16},
   {"%highest", BFD_RELOC_MIPS_HIGHEST},
   {"%higher", BFD_RELOC_MIPS_HIGHER},
@@ -14092,6 +14253,7 @@ static const struct percent_op_match mips_percent_op[] =
 static const struct percent_op_match mips16_percent_op[] =
 {
   {"%lo", BFD_RELOC_MIPS16_LO16},
+  {"%gp_rel", BFD_RELOC_MIPS16_GPREL},
   {"%gprel", BFD_RELOC_MIPS16_GPREL},
   {"%got", BFD_RELOC_MIPS16_GOT16},
   {"%call16", BFD_RELOC_MIPS16_CALL16},
@@ -17179,7 +17341,82 @@ pic_need_relax (symbolS *sym)
          /* A global or weak symbol is treated as external.  */
          && (!S_IS_WEAK (sym) && !S_IS_EXTERNAL (sym)));
 }
+\f
+/* Given a MIPS16 variant frag FRAGP and PC-relative operand PCREL_OP
+   convert a section-relative value VAL to the equivalent PC-relative
+   value.  */
+
+static offsetT
+mips16_pcrel_val (fragS *fragp, const struct mips_pcrel_operand *pcrel_op,
+                 offsetT val, long stretch)
+{
+  fragS *sym_frag;
+  addressT addr;
 
+  gas_assert (pcrel_op->root.root.type == OP_PCREL);
+
+  sym_frag = symbol_get_frag (fragp->fr_symbol);
+
+  /* If the relax_marker of the symbol fragment differs from the
+     relax_marker of this fragment, we have not yet adjusted the
+     symbol fragment fr_address.  We want to add in STRETCH in
+     order to get a better estimate of the address.  This
+     particularly matters because of the shift bits.  */
+  if (stretch != 0 && sym_frag->relax_marker != fragp->relax_marker)
+    {
+      fragS *f;
+
+      /* Adjust stretch for any alignment frag.  Note that if have
+        been expanding the earlier code, the symbol may be
+        defined in what appears to be an earlier frag.  FIXME:
+        This doesn't handle the fr_subtype field, which specifies
+        a maximum number of bytes to skip when doing an
+        alignment.  */
+      for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
+       {
+         if (f->fr_type == rs_align || f->fr_type == rs_align_code)
+           {
+             if (stretch < 0)
+               stretch = -(-stretch & ~((1 << (int) f->fr_offset) - 1));
+             else
+               stretch &= ~((1 << (int) f->fr_offset) - 1);
+             if (stretch == 0)
+               break;
+           }
+       }
+      if (f != NULL)
+       val += stretch;
+    }
+
+  addr = fragp->fr_address + fragp->fr_fix;
+
+  /* The base address rules are complicated.  The base address of
+     a branch is the following instruction.  The base address of a
+     PC relative load or add is the instruction itself, but if it
+     is in a delay slot (in which case it can not be extended) use
+     the address of the instruction whose delay slot it is in.  */
+  if (pcrel_op->include_isa_bit)
+    {
+      addr += 2;
+
+      /* If we are currently assuming that this frag should be
+        extended, then the current address is two bytes higher.  */
+      if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+       addr += 2;
+
+      /* Ignore the low bit in the target, since it will be set
+        for a text label.  */
+      val &= -2;
+    }
+  else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
+    addr -= 4;
+  else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
+    addr -= 2;
+
+  val -= addr & -(1 << pcrel_op->align_log2);
+
+  return val;
+}
 
 /* Given a mips16 variant frag FRAGP, return non-zero if it needs an
    extended opcode.  SEC is the section the frag is in.  */
@@ -17187,11 +17424,10 @@ pic_need_relax (symbolS *sym)
 static int
 mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
 {
-  int type;
   const struct mips_int_operand *operand;
   offsetT val;
   segT symsec;
-  fragS *sym_frag;
+  int type;
 
   if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
     return 0;
@@ -17207,80 +17443,18 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
          : !bfd_is_abs_section (symsec)))
     return 1;
 
-  sym_frag = symbol_get_frag (fragp->fr_symbol);
   val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
 
   if (operand->root.type == OP_PCREL)
     {
       const struct mips_pcrel_operand *pcrel_op;
-      addressT addr;
       offsetT maxtiny;
 
-      if (RELAX_MIPS16_LONG_BRANCH (fragp->fr_subtype))
+      if (RELAX_MIPS16_ALWAYS_EXTENDED (fragp->fr_subtype))
        return 1;
 
       pcrel_op = (const struct mips_pcrel_operand *) operand;
-
-      /* If the relax_marker of the symbol fragment differs from the
-        relax_marker of this fragment, we have not yet adjusted the
-        symbol fragment fr_address.  We want to add in STRETCH in
-        order to get a better estimate of the address.  This
-        particularly matters because of the shift bits.  */
-      if (stretch != 0
-         && sym_frag->relax_marker != fragp->relax_marker)
-       {
-         fragS *f;
-
-         /* Adjust stretch for any alignment frag.  Note that if have
-             been expanding the earlier code, the symbol may be
-             defined in what appears to be an earlier frag.  FIXME:
-             This doesn't handle the fr_subtype field, which specifies
-             a maximum number of bytes to skip when doing an
-             alignment.  */
-         for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
-           {
-             if (f->fr_type == rs_align || f->fr_type == rs_align_code)
-               {
-                 if (stretch < 0)
-                   stretch = - ((- stretch)
-                                & ~ ((1 << (int) f->fr_offset) - 1));
-                 else
-                   stretch &= ~ ((1 << (int) f->fr_offset) - 1);
-                 if (stretch == 0)
-                   break;
-               }
-           }
-         if (f != NULL)
-           val += stretch;
-       }
-
-      addr = fragp->fr_address + fragp->fr_fix;
-
-      /* The base address rules are complicated.  The base address of
-         a branch is the following instruction.  The base address of a
-         PC relative load or add is the instruction itself, but if it
-         is in a delay slot (in which case it can not be extended) use
-         the address of the instruction whose delay slot it is in.  */
-      if (pcrel_op->include_isa_bit)
-       {
-         addr += 2;
-
-         /* If we are currently assuming that this frag should be
-            extended, then, the current address is two bytes
-            higher.  */
-         if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
-           addr += 2;
-
-         /* Ignore the low bit in the target, since it will be set
-             for a text label.  */
-         val &= -2;
-       }
-      else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
-       addr -= 4;
-      else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
-       addr -= 2;
-
-      val -= addr & -(1 << pcrel_op->align_log2);
+      val = mips16_pcrel_val (fragp, pcrel_op, val, stretch);
 
       /* If any of the shifted bits are set, we must use an extended
          opcode.  If the address depends on the size of this
@@ -17289,7 +17463,7 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
       if ((val & ((1 << operand->shift) - 1)) != 0)
        {
          fragp->fr_subtype =
-           RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
+           RELAX_MIPS16_MARK_ALWAYS_EXTENDED (fragp->fr_subtype);
          return 1;
        }
 
@@ -17310,7 +17484,7 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
          && ! RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        {
          fragp->fr_subtype =
-           RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
+           RELAX_MIPS16_MARK_ALWAYS_EXTENDED (fragp->fr_subtype);
          return 1;
        }
     }
@@ -17318,6 +17492,53 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
   return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val);
 }
 
+/* Given a MIPS16 variant frag FRAGP, return non-zero if it needs
+   macro expansion.  SEC is the section the frag is in.  We only
+   support PC-relative instructions (LA, DLA, LW, LD) here, in
+   non-PIC code using 32-bit addressing.  */
+
+static int
+mips16_macro_frag (fragS *fragp, asection *sec, long stretch)
+{
+  const struct mips_pcrel_operand *pcrel_op;
+  const struct mips_int_operand *operand;
+  offsetT val;
+  segT symsec;
+  int type;
+
+  gas_assert (!RELAX_MIPS16_USER_SMALL (fragp->fr_subtype));
+
+  if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype))
+    return 0;
+  if (!RELAX_MIPS16_SYM32 (fragp->fr_subtype))
+    return 0;
+
+  type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
+  switch (type)
+    {
+    case 'A':
+    case 'B':
+    case 'E':
+      symsec = S_GET_SEGMENT (fragp->fr_symbol);
+      if (bfd_is_abs_section (symsec))
+       return 1;
+      if (RELAX_MIPS16_PIC (fragp->fr_subtype))
+       return 0;
+      if (S_FORCE_RELOC (fragp->fr_symbol, TRUE) || sec != symsec)
+       return 1;
+
+      operand = mips16_immed_operand (type, TRUE);
+      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+      pcrel_op = (const struct mips_pcrel_operand *) operand;
+      val = mips16_pcrel_val (fragp, pcrel_op, val, stretch);
+
+      return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val);
+
+    default:
+      return 0;
+    }
+}
+
 /* Compute the length of a branch sequence, and adjust the
    RELAX_BRANCH_TOOFAR bit accordingly.  If FRAGP is NULL, the
    worst-case length is computed, with UPDATE being used to indicate
@@ -17597,9 +17818,14 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
     }
 
   if (RELAX_MIPS16_P (fragp->fr_subtype))
-    /* We don't want to modify the EXTENDED bit here; it might get us
-       into infinite loops.  We change it only in mips_relax_frag().  */
-    return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
+    {
+      /* We don't want to modify the EXTENDED bit here; it might get us
+        into infinite loops.  We change it only in mips_relax_frag().  */
+      if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+       return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12;
+      else
+       return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2;
+    }
 
   if (RELAX_MICROMIPS_P (fragp->fr_subtype))
     {
@@ -17849,19 +18075,52 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
   if (! RELAX_MIPS16_P (fragp->fr_subtype))
     return 0;
 
-  if (mips16_extended_frag (fragp, sec, stretch))
+  if (!mips16_extended_frag (fragp, sec, stretch))
     {
-      if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+      if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+       {
+         fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10;
+       }
+      else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+       {
+         fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
+         return -2;
+       }
+      else
+       return 0;
+    }
+  else if (!mips16_macro_frag (fragp, sec, stretch))
+    {
+      if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+       {
+         fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
+         fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8;
+       }
+      else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+       {
+         fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
+         return 2;
+       }
+      else
        return 0;
-      fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
-      return 2;
     }
   else
     {
-      if (! RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+      if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
        return 0;
-      fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
-      return -2;
+      else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+       {
+         fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
+         fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8;
+       }
+      else
+       {
+         fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10;
+       }
     }
 
   return 0;
@@ -18356,60 +18615,44 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
       const struct mips_int_operand *operand;
       offsetT val;
       char *buf;
-      unsigned int user_length, length;
+      unsigned int user_length;
       bfd_boolean need_reloc;
       unsigned long insn;
+      bfd_boolean mac;
       bfd_boolean ext;
       segT symsec;
 
       type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
       operand = mips16_immed_operand (type, FALSE);
 
+      mac = RELAX_MIPS16_MACRO (fragp->fr_subtype);
       ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype);
       val = resolve_symbol_value (fragp->fr_symbol) + fragp->fr_offset;
 
       symsec = S_GET_SEGMENT (fragp->fr_symbol);
       need_reloc = (S_FORCE_RELOC (fragp->fr_symbol, TRUE)
-                   || (operand->root.type == OP_PCREL
+                   || (operand->root.type == OP_PCREL && !mac
                        ? asec != symsec
                        : !bfd_is_abs_section (symsec)));
 
-      if (operand->root.type == OP_PCREL)
+      if (operand->root.type == OP_PCREL && !mac)
        {
          const struct mips_pcrel_operand *pcrel_op;
-         addressT addr;
 
          pcrel_op = (const struct mips_pcrel_operand *) operand;
-         addr = fragp->fr_address + fragp->fr_fix;
 
-         /* The rules for the base address of a PC relative reloc are
-             complicated; see mips16_extended_frag.  */
-         if (pcrel_op->include_isa_bit)
+         if (pcrel_op->include_isa_bit && !need_reloc)
            {
-             if (!need_reloc)
-               {
-                 if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
-                   as_bad_where (fragp->fr_file, fragp->fr_line,
-                                 _("branch to a symbol in another ISA mode"));
-                 else if ((fragp->fr_offset & 0x1) != 0)
-                   as_bad_where (fragp->fr_file, fragp->fr_line,
-                                 _("branch to misaligned address (0x%lx)"),
-                                 (long) val);
-               }
-             addr += 2;
-             if (ext)
-               addr += 2;
-             /* Ignore the low bit in the target, since it will be
-                 set for a text label.  */
-             val &= -2;
+             if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
+               as_bad_where (fragp->fr_file, fragp->fr_line,
+                             _("branch to a symbol in another ISA mode"));
+             else if ((fragp->fr_offset & 0x1) != 0)
+               as_bad_where (fragp->fr_file, fragp->fr_line,
+                             _("branch to misaligned address (0x%lx)"),
+                             (long) val);
            }
-         else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
-           addr -= 4;
-         else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
-           addr -= 2;
 
-         addr &= -(1 << pcrel_op->align_log2);
-         val -= addr;
+         val = mips16_pcrel_val (fragp, pcrel_op, val, 0);
 
          /* Make sure the section winds up with the alignment we have
              assumed.  */
@@ -18417,11 +18660,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
            record_alignment (asec, operand->shift);
        }
 
-      if (ext
-         && (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
-             || RELAX_MIPS16_DSLOT (fragp->fr_subtype)))
+      if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
+         || RELAX_MIPS16_DSLOT (fragp->fr_subtype))
+       {
+         if (mac)
+           as_warn_where (fragp->fr_file, fragp->fr_line,
+                          _("macro instruction expanded into multiple "
+                            "instructions in a branch delay slot"));
+         else if (ext)
+           as_warn_where (fragp->fr_file, fragp->fr_line,
+                          _("extended instruction in a branch delay slot"));
+       }
+      else if (RELAX_MIPS16_NOMACRO (fragp->fr_subtype) && mac)
        as_warn_where (fragp->fr_file, fragp->fr_line,
-                      _("extended instruction in delay slot"));
+                      _("macro instruction expanded into multiple "
+                        "instructions"));
 
       buf = fragp->fr_literal + fragp->fr_fix;
 
@@ -18436,49 +18689,126 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
       else
        user_length = 0;
 
-      if (need_reloc)
+      if (mac)
        {
-         bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
-         expressionS exp;
-         fixS *fixp;
+         unsigned long reg;
+         unsigned long new;
+         unsigned long op;
+         bfd_boolean e2;
+
+         gas_assert (type == 'A' || type == 'B' || type == 'E');
+         gas_assert (RELAX_MIPS16_SYM32 (fragp->fr_subtype));
+
+         e2 = RELAX_MIPS16_E2 (fragp->fr_subtype);
+
+         if (need_reloc)
+           {
+             fixS *fixp;
+
+             gas_assert (!RELAX_MIPS16_PIC (fragp->fr_subtype));
 
-         switch (type)
+             fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             FALSE, BFD_RELOC_MIPS16_HI16_S);
+             fixp->fx_file = fragp->fr_file;
+             fixp->fx_line = fragp->fr_line;
+
+             fixp = fix_new (fragp, buf - fragp->fr_literal + (e2 ? 4 : 8), 4,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             FALSE, BFD_RELOC_MIPS16_LO16);
+             fixp->fx_file = fragp->fr_file;
+             fixp->fx_line = fragp->fr_line;
+
+             val = 0;
+           }
+
+         switch (insn & 0xf800)
            {
-           case 'p':
-           case 'q':
-             reloc = BFD_RELOC_MIPS16_16_PCREL_S1;
+           case 0x0800:                                        /* ADDIU */
+             reg = (insn >> 8) & 0x7;
+             op = 0xf0004800 | (reg << 8);
              break;
-           default:
-             as_bad_where (fragp->fr_file, fragp->fr_line,
-                           _("unsupported relocation"));
+           case 0xb000:                                        /* LW */
+             reg = (insn >> 8) & 0x7;
+             op = 0xf0009800 | (reg << 8) | (reg << 5);
+             break;
+           case 0xf800:                                        /* I64 */
+             reg = (insn >> 5) & 0x7;
+             switch (insn & 0x0700)
+               {
+               case 0x0400:                                    /* LD */
+                 op = 0xf0003800 | (reg << 8) | (reg << 5);
+                 break;
+               case 0x0600:                                    /* DADDIU */
+                 op = 0xf000fd00 | (reg << 5);
+                 break;
+               default:
+                 abort ();
+               }
              break;
+           default:
+             abort ();
            }
-         if (reloc == BFD_RELOC_NONE)
-           ;
-         else if (ext)
+
+         new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8);    /* LUI/LI */
+         new |= mips16_immed_extend ((val + 0x8000) >> 16, 16);
+         buf = write_compressed_insn (buf, new, 4);
+         if (!e2)
            {
-             exp.X_op = O_symbol;
-             exp.X_add_symbol = fragp->fr_symbol;
-             exp.X_add_number = fragp->fr_offset;
+             new = 0xf4003000 | (reg << 8) | (reg << 5);       /* SLL */
+             buf = write_compressed_insn (buf, new, 4);
+           }
+         op |= mips16_immed_extend (val, 16);
+         buf = write_compressed_insn (buf, op, 4);
 
-             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
-                                 TRUE, reloc);
+         fragp->fr_fix += e2 ? 8 : 12;
+       }
+      else
+       {
+         unsigned int length = ext ? 4 : 2;
 
-             fixp->fx_file = fragp->fr_file;
-             fixp->fx_line = fragp->fr_line;
+         if (need_reloc)
+           {
+             bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
+             expressionS exp;
+             fixS *fixp;
+
+             switch (type)
+               {
+               case 'p':
+               case 'q':
+                 reloc = BFD_RELOC_MIPS16_16_PCREL_S1;
+                 break;
+               default:
+                 break;
+               }
+             if (mac || reloc == BFD_RELOC_NONE)
+               as_bad_where (fragp->fr_file, fragp->fr_line,
+                             _("unsupported relocation"));
+             else if (ext)
+               {
+                 exp.X_op = O_symbol;
+                 exp.X_add_symbol = fragp->fr_symbol;
+                 exp.X_add_number = fragp->fr_offset;
+
+                 fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+                                     TRUE, reloc);
+
+                 fixp->fx_file = fragp->fr_file;
+                 fixp->fx_line = fragp->fr_line;
+               }
+             else
+               as_bad_where (fragp->fr_file, fragp->fr_line,
+                             _("invalid unextended operand value"));
            }
          else
-           as_bad_where (fragp->fr_file, fragp->fr_line,
-                         _("invalid unextended operand value"));
-       }
-      else
-       mips16_immed (fragp->fr_file, fragp->fr_line, type,
-                     BFD_RELOC_UNUSED, val, user_length, &insn);
+           mips16_immed (fragp->fr_file, fragp->fr_line, type,
+                         BFD_RELOC_UNUSED, val, user_length, &insn);
 
-      length = (ext ? 4 : 2);
-      gas_assert (mips16_opcode_length (insn) == length);
-      write_compressed_insn (buf, insn, length);
-      fragp->fr_fix += length;
+         gas_assert (mips16_opcode_length (insn) == length);
+         write_compressed_insn (buf, insn, length);
+         fragp->fr_fix += length;
+       }
     }
   else
     {
@@ -18661,6 +18991,8 @@ mips_convert_ase_flags (int ase)
     ext_ases |= AFL_ASE_MSA;
   if (ase & ASE_XPA)
     ext_ases |= AFL_ASE_XPA;
+  if (ase & ASE_MIPS16E2)
+    ext_ases |= file_ase_mips16 ? AFL_ASE_MIPS16E2 : 0;
 
   return ext_ases;
 }
@@ -19388,6 +19720,9 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "1004kf1_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   /* interaptiv is the new name for 1004kf */
   { "interaptiv",     0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "interaptiv-mr2", 0,
+    ASE_DSP | ASE_EVA | ASE_MT | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
+    ISA_MIPS32R3, CPU_INTERAPTIV_MR2 },
   /* M5100 family */
   { "m5100",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   { "m5101",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
This page took 0.041714 seconds and 4 git commands to generate.