Add support for a __gcc_isr pseudo isntruction to the AVR assembler.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 27ce0437e782520e2d32303403751cc49fd497ce..1d477a11341eafe8f4661f45a58e6658ee6d4881 100644 (file)
@@ -1130,38 +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, pic, sym32, nomacro,         \
+#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro,     \
                            small, ext,                         \
                            dslot, jal_dslot)                   \
   (0x80000000                                                  \
    | ((type) & 0xff)                                           \
-   | ((pic) ? 0x100 : 0)                                       \
-   | ((sym32) ? 0x200 : 0)                                     \
-   | ((nomacro) ? 0x400 : 0)                                   \
-   | ((small) ? 0x800 : 0)                                     \
-   | ((ext) ? 0x1000 : 0)                                      \
-   | ((dslot) ? 0x2000 : 0)                                    \
-   | ((jal_dslot) ? 0x4000 : 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_PIC(i) (((i) & 0x100) != 0)
-#define RELAX_MIPS16_SYM32(i) (((i) & 0x200) != 0)
-#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x400) != 0)
-#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x800) != 0)
-#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x1000) != 0)
-#define RELAX_MIPS16_DSLOT(i) (((i) & 0x2000) != 0)
-#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x4000) != 0)
-
-#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x8000) != 0)
-#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x8000)
-#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x8000)
-#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x10000) != 0)
-#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x10000)
-#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x10000)
-#define RELAX_MIPS16_MACRO(i) (((i) & 0x20000) != 0)
-#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x20000)
-#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x20000)
+#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
@@ -1341,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 *);
@@ -1455,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,
@@ -1575,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},
@@ -1755,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.  */
@@ -2118,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;
 }
 
@@ -2226,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.  */
@@ -3286,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
@@ -3417,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)
@@ -3426,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 == '-'))
@@ -4501,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:
       {
@@ -4856,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;
@@ -5062,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
@@ -5073,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;
        }
@@ -5090,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
@@ -5500,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
@@ -5507,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;
@@ -5515,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;
@@ -5550,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;
@@ -5566,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.  */
@@ -5593,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. */
@@ -5612,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)
@@ -5630,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;
 }
@@ -5780,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
@@ -5810,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:
 
@@ -6006,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,
@@ -6064,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);
 
@@ -6836,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;
@@ -7437,6 +7567,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
       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,
@@ -8179,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;
@@ -8213,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;
 
@@ -8249,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;
@@ -13902,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;
@@ -13933,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;
     }
@@ -13967,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;
@@ -13977,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;
@@ -17682,7 +17822,7 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
       /* 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 12;
+       return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12;
       else
        return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2;
     }
@@ -17940,7 +18080,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
       if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
        {
          fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
-         return -10;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10;
        }
       else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        {
@@ -17956,7 +18096,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
        {
          fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
          fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
-         return -8;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8;
        }
       else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        {
@@ -17974,12 +18114,12 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
        {
          fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
          fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
-         return 8;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8;
        }
       else
        {
          fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
-         return 10;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10;
        }
     }
 
@@ -18554,10 +18694,13 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          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;
@@ -18570,7 +18713,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
-             fixp = fix_new (fragp, buf - fragp->fr_literal + 8, 4,
+             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;
@@ -18607,15 +18750,18 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              abort ();
            }
 
-         new = 0xf0006800 | (reg << 8);                        /* LI */
+         new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8);    /* LUI/LI */
          new |= mips16_immed_extend ((val + 0x8000) >> 16, 16);
          buf = write_compressed_insn (buf, new, 4);
-         new = 0xf4003000 | (reg << 8) | (reg << 5);           /* SLL */
-         buf = write_compressed_insn (buf, new, 4);
+         if (!e2)
+           {
+             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);
 
-         fragp->fr_fix += 12;
+         fragp->fr_fix += e2 ? 8 : 12;
        }
       else
        {
@@ -18845,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;
 }
@@ -19572,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.034296 seconds and 4 git commands to generate.