[PATCH 5/57][Arm][GAS] Add support for MVE instructions: vmull{b,t}
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index c7c1a82a998ce08330e05f3f2b3e34e453b87b2c..f325dcf1f1161d105b098b1463f09dfe0833a99b 100644 (file)
@@ -302,6 +302,10 @@ static const arm_feature_set fpu_neon_ext_v1 =
   ARM_FEATURE_COPROC (FPU_NEON_EXT_V1);
 static const arm_feature_set fpu_vfp_v3_or_neon_ext =
   ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
+static const arm_feature_set mve_ext =
+  ARM_FEATURE_COPROC (FPU_MVE);
+static const arm_feature_set mve_fp_ext =
+  ARM_FEATURE_COPROC (FPU_MVE_FP);
 #ifdef OBJ_ELF
 static const arm_feature_set fpu_vfp_fp16 =
   ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16);
@@ -449,16 +453,20 @@ struct neon_type
   unsigned elems;
 };
 
-enum it_instruction_type
+enum pred_instruction_type
 {
-   OUTSIDE_IT_INSN,
+   OUTSIDE_PRED_INSN,
+   INSIDE_VPT_INSN,
    INSIDE_IT_INSN,
    INSIDE_IT_LAST_INSN,
    IF_INSIDE_IT_LAST_INSN, /* Either outside or inside;
                              if inside, should be the last one.  */
    NEUTRAL_IT_INSN,        /* This could be either inside or outside,
                              i.e. BKPT and NOP.  */
-   IT_INSN                 /* The IT insn has been parsed.  */
+   IT_INSN,               /* The IT insn has been parsed.  */
+   VPT_INSN,              /* The VPT/VPST insn has been parsed.  */
+   MVE_OUTSIDE_PRED_INSN   /* Instruction to indicate a MVE instruction without
+                             a predication code.  */
 };
 
 /* The maximum number of operands we need.  */
@@ -490,7 +498,7 @@ struct arm_it
     int                             pc_rel;
   } relocs[ARM_IT_MAX_RELOCS];
 
-  enum it_instruction_type it_insn_type;
+  enum pred_instruction_type pred_insn_type;
 
   struct
   {
@@ -507,7 +515,7 @@ struct arm_it
        instructions. This allows us to disambiguate ARM <-> vector insns.  */
     unsigned regisimm   : 1;  /* 64-bit immediate, reg forms high 32 bits.  */
     unsigned isvec      : 1;  /* Is a single, double or quad VFP/Neon reg.  */
-    unsigned isquad     : 1;  /* Operand is Neon quad-precision register.  */
+    unsigned isquad     : 1;  /* Operand is SIMD quad register.  */
     unsigned issingle   : 1;  /* Operand is VFP single-precision register.  */
     unsigned hasreloc  : 1;  /* Operand has relocation suffix.  */
     unsigned writeback : 1;  /* Operand has trailing !  */
@@ -528,9 +536,6 @@ const char * fp_const[] =
   "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
 };
 
-/* Number of littlenums required to hold an extended precision number. */
-#define MAX_LITTLENUMS 6
-
 LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
 
 #define FAIL   (-1)
@@ -629,12 +634,13 @@ enum arm_reg_type
   REG_TYPE_MVFX,
   REG_TYPE_MVDX,
   REG_TYPE_MVAX,
+  REG_TYPE_MQ,
   REG_TYPE_DSPSC,
   REG_TYPE_MMXWR,
   REG_TYPE_MMXWC,
   REG_TYPE_MMXWCG,
   REG_TYPE_XSCALE,
-  REG_TYPE_RNB
+  REG_TYPE_RNB,
 };
 
 /* Structure for a hash table entry for a register.
@@ -676,6 +682,7 @@ const char * const reg_expected_msgs[] =
   [REG_TYPE_MMXWC]  = N_("iWMMXt control register expected"),
   [REG_TYPE_MMXWCG] = N_("iWMMXt scalar register expected"),
   [REG_TYPE_XSCALE] = N_("XScale accumulator register expected"),
+  [REG_TYPE_MQ]            = N_("MVE vector register expected"),
   [REG_TYPE_RNB]    = N_("")
 };
 
@@ -701,7 +708,7 @@ struct asm_opcode
   unsigned int tag : 4;
 
   /* Basic instruction code.  */
-  unsigned int avalue : 28;
+  unsigned int avalue;
 
   /* Thumb-format instruction code.  */
   unsigned int tvalue;
@@ -715,6 +722,9 @@ struct asm_opcode
 
   /* Function to call to encode instruction in Thumb format.  */
   void (* tencode) (void);
+
+  /* Indicates whether this instruction may be vector predicated.  */
+  unsigned int mayBeVecPred : 1;
 };
 
 /* Defines for various bits that we will want to toggle.  */
@@ -837,9 +847,12 @@ struct asm_opcode
 #define THUMB_LOAD_BIT 0x0800
 #define THUMB2_LOAD_BIT 0x00100000
 
+#define BAD_SYNTAX     _("syntax error")
 #define BAD_ARGS       _("bad arguments to instruction")
 #define BAD_SP          _("r13 not allowed here")
 #define BAD_PC         _("r15 not allowed here")
+#define BAD_ODD                _("Odd register not allowed here")
+#define BAD_EVEN       _("Even register not allowed here")
 #define BAD_COND       _("instruction cannot be conditional")
 #define BAD_OVERLAP    _("registers may not be the same")
 #define BAD_HIREG      _("lo register required")
@@ -848,9 +861,13 @@ struct asm_opcode
 #define BAD_BRANCH     _("branch must be last instruction in IT block")
 #define BAD_BRANCH_OFF _("branch out of range or not a multiple of 2")
 #define BAD_NOT_IT     _("instruction not allowed in IT block")
+#define BAD_NOT_VPT    _("instruction missing MVE vector predication code")
 #define BAD_FPU                _("selected FPU does not support instruction")
 #define BAD_OUT_IT     _("thumb conditional instruction should be in IT block")
+#define BAD_OUT_VPT    \
+       _("vector predicated instruction should be in VPT/VPST block")
 #define BAD_IT_COND    _("incorrect condition in IT block")
+#define BAD_VPT_COND   _("incorrect condition in VPT/VPST block")
 #define BAD_IT_IT      _("IT falling in the range of a previous IT block")
 #define MISSING_FNSTART        _("missing .fnstart before unwinding directive")
 #define BAD_PC_ADDRESSING \
@@ -861,9 +878,24 @@ struct asm_opcode
 #define BAD_FP16       _("selected processor does not support fp16 instruction")
 #define UNPRED_REG(R)  _("using " R " results in unpredictable behaviour")
 #define THUMB1_RELOC_ONLY  _("relocation valid in thumb1 code only")
+#define MVE_NOT_IT     _("Warning: instruction is UNPREDICTABLE in an IT " \
+                         "block")
+#define MVE_NOT_VPT    _("Warning: instruction is UNPREDICTABLE in a VPT " \
+                         "block")
+#define MVE_BAD_PC     _("Warning: instruction is UNPREDICTABLE with PC" \
+                         " operand")
+#define MVE_BAD_SP     _("Warning: instruction is UNPREDICTABLE with SP" \
+                         " operand")
+#define BAD_SIMD_TYPE  _("bad type in SIMD instruction")
+#define BAD_MVE_AUTO   \
+  _("GAS auto-detection mode and -march=all is deprecated for MVE, please" \
+    " use a valid -march or -mcpu option.")
+#define BAD_MVE_SRCDEST        _("Warning: 32-bit element size and same destination "\
+                         "and source operands makes instruction UNPREDICTABLE")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
+static struct hash_control * arm_vcond_hsh;
 static struct hash_control * arm_shift_hsh;
 static struct hash_control * arm_psr_hsh;
 static struct hash_control * arm_v7m_psr_hsh;
@@ -915,15 +947,15 @@ typedef enum asmfunc_states
 static asmfunc_states asmfunc_state = OUTSIDE_ASMFUNC;
 
 #ifdef OBJ_ELF
-#  define now_it seg_info (now_seg)->tc_segment_info_data.current_it
+#  define now_pred seg_info (now_seg)->tc_segment_info_data.current_pred
 #else
-static struct current_it now_it;
+static struct current_pred now_pred;
 #endif
 
 static inline int
-now_it_compatible (int cond)
+now_pred_compatible (int cond)
 {
-  return (cond & ~1) == (now_it.cc & ~1);
+  return (cond & ~1) == (now_pred.cc & ~1);
 }
 
 static inline int
@@ -932,39 +964,39 @@ conditional_insn (void)
   return inst.cond != COND_ALWAYS;
 }
 
-static int in_it_block (void);
+static int in_pred_block (void);
 
-static int handle_it_state (void);
+static int handle_pred_state (void);
 
 static void force_automatic_it_block_close (void);
 
 static void it_fsm_post_encode (void);
 
-#define set_it_insn_type(type)                 \
+#define set_pred_insn_type(type)                       \
   do                                           \
     {                                          \
-      inst.it_insn_type = type;                        \
-      if (handle_it_state () == FAIL)          \
+      inst.pred_insn_type = type;                      \
+      if (handle_pred_state () == FAIL)                \
        return;                                 \
     }                                          \
   while (0)
 
-#define set_it_insn_type_nonvoid(type, failret) \
+#define set_pred_insn_type_nonvoid(type, failret) \
   do                                           \
     {                                           \
-      inst.it_insn_type = type;                        \
-      if (handle_it_state () == FAIL)          \
+      inst.pred_insn_type = type;                      \
+      if (handle_pred_state () == FAIL)                \
        return failret;                         \
     }                                          \
   while(0)
 
-#define set_it_insn_type_last()                                \
+#define set_pred_insn_type_last()                              \
   do                                                   \
     {                                                  \
       if (inst.cond == COND_ALWAYS)                    \
-       set_it_insn_type (IF_INSIDE_IT_LAST_INSN);      \
+       set_pred_insn_type (IF_INSIDE_IT_LAST_INSN);    \
       else                                             \
-       set_it_insn_type (INSIDE_IT_LAST_INSN);         \
+       set_pred_insn_type (INSIDE_IT_LAST_INSN);               \
     }                                                  \
   while (0)
 
@@ -1496,6 +1528,41 @@ parse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
 #define NEON_ALL_LANES         15
 #define NEON_INTERLEAVE_LANES  14
 
+/* Record a use of the given feature.  */
+static void
+record_feature_use (const arm_feature_set *feature)
+{
+  if (thumb_mode)
+    ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature);
+  else
+    ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature);
+}
+
+/* If the given feature available in the selected CPU, mark it as used.
+   Returns TRUE iff feature is available.  */
+static bfd_boolean
+mark_feature_used (const arm_feature_set *feature)
+{
+
+  /* Do not support the use of MVE only instructions when in auto-detection or
+     -march=all.  */
+  if (((feature == &mve_ext) || (feature == &mve_fp_ext))
+      && ARM_CPU_IS_ANY (cpu_variant))
+    {
+      first_error (BAD_MVE_AUTO);
+      return FALSE;
+    }
+  /* Ensure the option is valid on the current architecture.  */
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
+    return FALSE;
+
+  /* Add the appropriate architecture feature for the barrier option used.
+     */
+  record_feature_use (feature);
+
+  return TRUE;
+}
+
 /* Parse either a register or a scalar, with an optional type. Return the
    register number, and optionally fill in the actual type of the register
    when multiple alternatives were given (NEON_TYPE_NDQ) in *RTYPE, and
@@ -1542,6 +1609,26 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
          && (reg->type == REG_TYPE_MMXWCG)))
     type = (enum arm_reg_type) reg->type;
 
+  if (type == REG_TYPE_MQ)
+    {
+      if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+       return FAIL;
+
+      if (!reg || reg->type != REG_TYPE_NQ)
+       return FAIL;
+
+      if (reg->number > 14 && !mark_feature_used (&fpu_vfp_ext_d32))
+       {
+         first_error (_("expected MVE register [q0..q7]"));
+         return FAIL;
+       }
+      type = REG_TYPE_NQ;
+    }
+  else if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+          && (type == REG_TYPE_NQ))
+    return FAIL;
+
+
   if (type != reg->type)
     return FAIL;
 
@@ -1609,7 +1696,7 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
   return reg->number;
 }
 
-/* Like arm_reg_parse, but allow allow the following extra features:
+/* Like arm_reg_parse, but also allow the following extra features:
     - If RTYPE is non-zero, return the (possibly restricted) type of the
       register (e.g. Neon double or quad reg when either has been requested).
     - If this is a Neon vector type with additional type information, fill
@@ -1688,14 +1775,29 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
   return reg * 16 + atype.index;
 }
 
+/* Types of registers in a list.  */
+
+enum reg_list_els
+{
+  REGLIST_RN,
+  REGLIST_CLRM,
+  REGLIST_VFP_S,
+  REGLIST_VFP_S_VPR,
+  REGLIST_VFP_D,
+  REGLIST_VFP_D_VPR,
+  REGLIST_NEON_D
+};
+
 /* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
 
 static long
-parse_reg_list (char ** strp)
+parse_reg_list (char ** strp, enum reg_list_els etype)
 {
-  char * str = * strp;
-  long  range = 0;
-  int   another_range;
+  char *str = *strp;
+  long range = 0;
+  int another_range;
+
+  gas_assert (etype == REGLIST_RN || etype == REGLIST_CLRM);
 
   /* We come back here if we get ranges concatenated by '+' or '|'.  */
   do
@@ -1713,11 +1815,35 @@ parse_reg_list (char ** strp)
          do
            {
              int reg;
+             const char apsr_str[] = "apsr";
+             int apsr_str_len = strlen (apsr_str);
 
-             if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
+             reg = arm_reg_parse (&str, REGLIST_RN);
+             if (etype == REGLIST_CLRM)
                {
-                 first_error (_(reg_expected_msgs[REG_TYPE_RN]));
-                 return FAIL;
+                 if (reg == REG_SP || reg == REG_PC)
+                   reg = FAIL;
+                 else if (reg == FAIL
+                          && !strncasecmp (str, apsr_str, apsr_str_len)
+                          && !ISALPHA (*(str + apsr_str_len)))
+                   {
+                     reg = 15;
+                     str += apsr_str_len;
+                   }
+
+                 if (reg == FAIL)
+                   {
+                     first_error (_("r0-r12, lr or APSR expected"));
+                     return FAIL;
+                   }
+               }
+             else /* etype == REGLIST_RN.  */
+               {
+                 if (reg == FAIL)
+                   {
+                     first_error (_(reg_expected_msgs[REGLIST_RN]));
+                     return FAIL;
+                   }
                }
 
              if (in_range)
@@ -1761,7 +1887,7 @@ parse_reg_list (char ** strp)
              return FAIL;
            }
        }
-      else
+      else if (etype == REGLIST_RN)
        {
          expressionS exp;
 
@@ -1816,15 +1942,6 @@ parse_reg_list (char ** strp)
   return range;
 }
 
-/* Types of registers in a list.  */
-
-enum reg_list_els
-{
-  REGLIST_VFP_S,
-  REGLIST_VFP_D,
-  REGLIST_NEON_D
-};
-
 /* Parse a VFP register list.  If the string is invalid return FAIL.
    Otherwise return the number of registers, and set PBASE to the first
    register.  Parses registers of type ETYPE.
@@ -1841,7 +1958,8 @@ enum reg_list_els
    bug.  */
 
 static int
-parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
+parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype,
+                   bfd_boolean *partial_match)
 {
   char *str = *ccp;
   int base_reg;
@@ -1852,6 +1970,9 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   int warned = 0;
   unsigned long mask = 0;
   int i;
+  bfd_boolean vpr_seen = FALSE;
+  bfd_boolean expect_vpr =
+    (etype == REGLIST_VFP_S_VPR) || (etype == REGLIST_VFP_D_VPR);
 
   if (skip_past_char (&str, '{') == FAIL)
     {
@@ -1862,20 +1983,25 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   switch (etype)
     {
     case REGLIST_VFP_S:
+    case REGLIST_VFP_S_VPR:
       regtype = REG_TYPE_VFS;
       max_regs = 32;
       break;
 
     case REGLIST_VFP_D:
+    case REGLIST_VFP_D_VPR:
       regtype = REG_TYPE_VFD;
       break;
 
     case REGLIST_NEON_D:
       regtype = REG_TYPE_NDQ;
       break;
+
+    default:
+      gas_assert (0);
     }
 
-  if (etype != REGLIST_VFP_S)
+  if (etype != REGLIST_VFP_S && etype != REGLIST_VFP_S_VPR)
     {
       /* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant.  */
       if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
@@ -1893,19 +2019,54 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
     }
 
   base_reg = max_regs;
+  *partial_match = FALSE;
 
   do
     {
       int setmask = 1, addregs = 1;
+      const char vpr_str[] = "vpr";
+      int vpr_str_len = strlen (vpr_str);
 
       new_base = arm_typed_reg_parse (&str, regtype, &regtype, NULL);
 
-      if (new_base == FAIL)
+      if (expect_vpr)
+       {
+         if (new_base == FAIL
+             && !strncasecmp (str, vpr_str, vpr_str_len)
+             && !ISALPHA (*(str + vpr_str_len))
+             && !vpr_seen)
+           {
+             vpr_seen = TRUE;
+             str += vpr_str_len;
+             if (count == 0)
+               base_reg = 0; /* Canonicalize VPR only on d0 with 0 regs.  */
+           }
+         else if (vpr_seen)
+           {
+             first_error (_("VPR expected last"));
+             return FAIL;
+           }
+         else if (new_base == FAIL)
+           {
+             if (regtype == REG_TYPE_VFS)
+               first_error (_("VFP single precision register or VPR "
+                              "expected"));
+             else /* regtype == REG_TYPE_VFD.  */
+               first_error (_("VFP/Neon double precision register or VPR "
+                              "expected"));
+             return FAIL;
+           }
+       }
+      else if (new_base == FAIL)
        {
          first_error (_(reg_expected_msgs[regtype]));
          return FAIL;
        }
 
+      *partial_match = TRUE;
+      if (vpr_seen)
+       continue;
+
       if (new_base >= max_regs)
        {
          first_error (_("register out of range in list"));
@@ -1928,7 +2089,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
          return FAIL;
        }
 
-      if ((mask >> new_base) != 0 && ! warned)
+      if ((mask >> new_base) != 0 && ! warned && !vpr_seen)
        {
          as_tsktsk (_("register list not in ascending order"));
          warned = 1;
@@ -1983,11 +2144,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   str++;
 
   /* Sanity check -- should have raised a parse error above.  */
-  if (count == 0 || count > max_regs)
+  if ((!vpr_seen && count == 0) || count > max_regs)
     abort ();
 
   *pbase = base_reg;
 
+  if (expect_vpr && !vpr_seen)
+    {
+      first_error (_("VPR expected last"));
+      return FAIL;
+    }
+
   /* Final test -- the registers must be consecutive.  */
   mask >>= base_reg;
   for (i = 0; i < count; i++)
@@ -3681,10 +3848,10 @@ emit_insn (expressionS *exp, int nbytes)
            }
          else
            {
-             if (now_it.state == AUTOMATIC_IT_BLOCK)
-               set_it_insn_type_nonvoid (OUTSIDE_IT_INSN, 0);
+             if (now_pred.state == AUTOMATIC_PRED_BLOCK)
+               set_pred_insn_type_nonvoid (OUTSIDE_PRED_INSN, 0);
              else
-               set_it_insn_type_nonvoid (NEUTRAL_IT_INSN, 0);
+               set_pred_insn_type_nonvoid (NEUTRAL_IT_INSN, 0);
 
              if (thumb_mode && (size > THUMB_SIZE) && !target_big_endian)
                emit_thumb32_expr (exp);
@@ -3988,7 +4155,7 @@ s_arm_unwind_save_core (void)
   long range;
   int n;
 
-  range = parse_reg_list (&input_line_pointer);
+  range = parse_reg_list (&input_line_pointer, REGLIST_RN);
   if (range == FAIL)
     {
       as_bad (_("expected register list"));
@@ -4115,8 +4282,10 @@ s_arm_unwind_save_vfp_armv6 (void)
   valueT op;
   int num_vfpv3_regs = 0;
   int num_regs_below_16;
+  bfd_boolean partial_match;
 
-  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
+  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D,
+                             &partial_match);
   if (count == FAIL)
     {
       as_bad (_("expected register list"));
@@ -4163,8 +4332,10 @@ s_arm_unwind_save_vfp (void)
   int count;
   unsigned int reg;
   valueT op;
+  bfd_boolean partial_match;
 
-  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D);
+  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D,
+                             &partial_match);
   if (count == FAIL)
     {
       as_bad (_("expected register list"));
@@ -4662,7 +4833,7 @@ s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
 {
   int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
 
-  if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
+  if (tag >= 0 && tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     attributes_set_explicitly[tag] = 1;
 }
 
@@ -6044,6 +6215,39 @@ check_suffix:
   return FAIL;
 }
 
+static int
+parse_sys_vldr_vstr (char **str)
+{
+  unsigned i;
+  int val = FAIL;
+  struct {
+    const char *name;
+    int regl;
+    int regh;
+  } sysregs[] = {
+    {"FPSCR",          0x1, 0x0},
+    {"FPSCR_nzcvqc",   0x2, 0x0},
+    {"VPR",            0x4, 0x1},
+    {"P0",             0x5, 0x1},
+    {"FPCXTNS",                0x6, 0x1},
+    {"FPCXTS",         0x7, 0x1}
+  };
+  char *op_end = strchr (*str, ',');
+  size_t op_strlen = op_end - *str;
+
+  for (i = 0; i < sizeof (sysregs) / sizeof (sysregs[0]); i++)
+    {
+      if (!strncmp (*str, sysregs[i].name, op_strlen))
+       {
+         val = sysregs[i].regl | (sysregs[i].regh << 3);
+         *str = op_end;
+         break;
+       }
+    }
+
+  return val;
+}
+
 /* Parse the flags argument to CPSI[ED].  Returns FAIL on error, or a
    value suitable for splatting into the AIF field of the instruction. */
 
@@ -6175,31 +6379,6 @@ parse_cond (char **str)
   return c->value;
 }
 
-/* Record a use of the given feature.  */
-static void
-record_feature_use (const arm_feature_set *feature)
-{
-  if (thumb_mode)
-    ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature);
-  else
-    ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature);
-}
-
-/* If the given feature is currently allowed, mark it as used and return TRUE.
-   Return FALSE otherwise.  */
-static bfd_boolean
-mark_feature_used (const arm_feature_set *feature)
-{
-  /* Ensure the option is currently allowed.  */
-  if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
-    return FALSE;
-
-  /* Add the appropriate architecture feature for the barrier option used.  */
-  record_feature_use (feature);
-
-  return TRUE;
-}
-
 /* Parse an option for a barrier instruction.  Returns the encoding for the
    option, or FAIL.  */
 static int
@@ -6525,10 +6704,15 @@ enum operand_parse_code
   OP_RVS,      /* VFP single precision register */
   OP_RVD,      /* VFP double precision register (0..15) */
   OP_RND,       /* Neon double precision register (0..31) */
+  OP_RNDMQ,     /* Neon double precision (0..31) or MVE vector register.  */
+  OP_RNDMQR,    /* Neon double precision (0..31), MVE vector or ARM register.
+                */
   OP_RNQ,      /* Neon quad precision register */
+  OP_RNQMQ,    /* Neon quad or MVE vector register.  */
   OP_RVSD,     /* VFP single or double precision register */
   OP_RNSD,      /* Neon single or double precision register */
   OP_RNDQ,      /* Neon double or quad precision register */
+  OP_RNDQMQ,     /* Neon double, quad or MVE vector register.  */
   OP_RNSDQ,    /* Neon single, double or quad precision register */
   OP_RNSC,      /* Neon scalar D[X] */
   OP_RVC,      /* VFP control register */
@@ -6543,12 +6727,26 @@ enum operand_parse_code
   OP_RIWG,     /* iWMMXt wCG register */
   OP_RXA,      /* XScale accumulator register */
 
+  OP_RNSDQMQ,  /* Neon single, double or quad register or MVE vector register
+                */
+  OP_RNSDQMQR, /* Neon single, double or quad register, MVE vector register or
+                  GPR (no SP/SP)  */
+  OP_RMQ,      /* MVE vector register.  */
+
+  /* New operands for Armv8.1-M Mainline.  */
+  OP_LR,       /* ARM LR register */
+  OP_RRe,      /* ARM register, only even numbered.  */
+  OP_RRo,      /* ARM register, only odd numbered, not r13 or r15.  */
+  OP_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */
+
   OP_REGLST,   /* ARM register list */
+  OP_CLRMLST,  /* CLRM register list */
   OP_VRSLST,   /* VFP single-precision register list */
   OP_VRDLST,   /* VFP double-precision register list */
   OP_VRSDLST,   /* VFP single or double-precision register list (& quad) */
   OP_NRDLST,    /* Neon double-precision register list (d0-d31, qN aliases) */
   OP_NSTRLST,   /* Neon element/structure list */
+  OP_VRSDVLST,  /* VFP single or double-precision register list and VPR */
 
   OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
   OP_RVSD_I0,  /* VFP S or D reg, or immediate zero.  */
@@ -6556,12 +6754,15 @@ enum operand_parse_code
   OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
   OP_RNSD_RNSC, /* Neon S or D reg, or Neon scalar.  */
   OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
+  OP_RNSDQ_RNSC_MQ, /* Vector S, D or Q reg, Neon scalar or MVE vector register.
+                    */
   OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
   OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
   OP_VMOV,      /* Neon VMOV operands.  */
   OP_RNDQ_Ibig,        /* Neon D or Q reg, or big immediate for logic and VMVN.  */
   OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift.  */
   OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2.  */
+  OP_VLDR,     /* VLDR operand.  */
 
   OP_I0,        /* immediate zero */
   OP_I7,       /* immediate value 0 .. 7 */
@@ -6622,13 +6823,17 @@ enum operand_parse_code
   OP_oI255c,    /*       curly-brace enclosed, 0 .. 255 */
 
   OP_oRR,       /* ARM register */
+  OP_oLR,       /* ARM LR register */
   OP_oRRnpc,    /* ARM register, not the PC */
   OP_oRRnpcsp,  /* ARM register, neither the PC nor the SP (a.k.a. BadReg) */
   OP_oRRw,      /* ARM register, not r15, optional trailing ! */
   OP_oRND,       /* Optional Neon double precision register */
   OP_oRNQ,       /* Optional Neon quad precision register */
+  OP_oRNDQMQ,     /* Optional Neon double, quad or MVE vector register.  */
   OP_oRNDQ,      /* Optional Neon double or quad precision register */
   OP_oRNSDQ,    /* Optional single, double or quad precision vector register */
+  OP_oRNSDQMQ,  /* Optional single, double or quad register or MVE vector
+                   register.  */
   OP_oSHll,     /* LSL immediate */
   OP_oSHar,     /* ASR immediate */
   OP_oSHllar,   /* LSL or ASR immediate */
@@ -6657,6 +6862,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   enum arm_reg_type rtype;
   parse_operand_result result;
   unsigned int op_parse_code;
+  bfd_boolean partial_match;
 
 #define po_char_or_fail(chr)                   \
   do                                           \
@@ -6790,6 +6996,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RRnpc:
        case OP_RRnpcsp:
        case OP_oRR:
+       case OP_RRe:
+       case OP_RRo:
+       case OP_LR:
+       case OP_oLR:
        case OP_RR:    po_reg_or_fail (REG_TYPE_RN);      break;
        case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);      break;
        case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);      break;
@@ -6797,6 +7007,14 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RVS:   po_reg_or_fail (REG_TYPE_VFS);     break;
        case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);     break;
        case OP_oRND:
+       case OP_RNDMQR:
+         po_reg_or_goto (REG_TYPE_RN, try_rndmq);
+         break;
+       try_rndmq:
+       case OP_RNDMQ:
+         po_reg_or_goto (REG_TYPE_MQ, try_rnd);
+         break;
+       try_rnd:
        case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);     break;
        case OP_RVC:
          po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
@@ -6816,14 +7034,37 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RIWG:  po_reg_or_fail (REG_TYPE_MMXWCG);  break;
        case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
        case OP_oRNQ:
+       case OP_RNQMQ:
+         po_reg_or_goto (REG_TYPE_MQ, try_nq);
+         break;
+       try_nq:
        case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
        case OP_RNSD:  po_reg_or_fail (REG_TYPE_NSD);     break;
+       case OP_oRNDQMQ:
+       case OP_RNDQMQ:
+         po_reg_or_goto (REG_TYPE_MQ, try_rndq);
+         break;
+       try_rndq:
        case OP_oRNDQ:
        case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
        case OP_oRNSDQ:
        case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
-
+       case OP_RNSDQMQR:
+         po_reg_or_goto (REG_TYPE_RN, try_mq);
+         break;
+         try_mq:
+       case OP_oRNSDQMQ:
+       case OP_RNSDQMQ:
+         po_reg_or_goto (REG_TYPE_MQ, try_nsdq2);
+         break;
+         try_nsdq2:
+         po_reg_or_fail (REG_TYPE_NSDQ);
+         inst.error = 0;
+         break;
+       case OP_RMQ:
+         po_reg_or_fail (REG_TYPE_MQ);
+         break;
        /* Neon scalar. Using an element size of 8 means that some invalid
           scalars are accepted here, so deal with those in later code.  */
        case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
@@ -6866,6 +7107,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          }
          break;
 
+       case OP_RNSDQ_RNSC_MQ:
+         po_reg_or_goto (REG_TYPE_MQ, try_rnsdq_rnsc);
+         break;
+       try_rnsdq_rnsc:
        case OP_RNSDQ_RNSC:
          {
            po_scalar_or_goto (8, try_nsdq);
@@ -7131,6 +7376,13 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          val = parse_psr (&str, op_parse_code == OP_wPSR);
          break;
 
+       case OP_VLDR:
+         po_reg_or_goto (REG_TYPE_VFSD, try_sysreg);
+         break;
+       try_sysreg:
+         val = parse_sys_vldr_vstr (&str);
+         break;
+
        case OP_APSR_RR:
          po_reg_or_goto (REG_TYPE_RN, try_apsr);
          break;
@@ -7166,7 +7418,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
          /* Register lists.  */
        case OP_REGLST:
-         val = parse_reg_list (&str);
+         val = parse_reg_list (&str, REGLIST_RN);
          if (*str == '^')
            {
              inst.operands[i].writeback = 1;
@@ -7174,30 +7426,48 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
            }
          break;
 
+       case OP_CLRMLST:
+         val = parse_reg_list (&str, REGLIST_CLRM);
+         break;
+
        case OP_VRSLST:
-         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S,
+                                   &partial_match);
          break;
 
        case OP_VRDLST:
-         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D,
+                                   &partial_match);
          break;
 
        case OP_VRSDLST:
          /* Allow Q registers too.  */
          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                   REGLIST_NEON_D);
+                                   REGLIST_NEON_D, &partial_match);
          if (val == FAIL)
            {
              inst.error = NULL;
              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                       REGLIST_VFP_S);
+                                       REGLIST_VFP_S, &partial_match);
+             inst.operands[i].issingle = 1;
+           }
+         break;
+
+       case OP_VRSDVLST:
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                   REGLIST_VFP_D_VPR, &partial_match);
+         if (val == FAIL && !partial_match)
+           {
+             inst.error = NULL;
+             val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                       REGLIST_VFP_S_VPR, &partial_match);
              inst.operands[i].issingle = 1;
            }
          break;
 
        case OP_NRDLST:
          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                   REGLIST_NEON_D);
+                                   REGLIST_NEON_D, &partial_match);
          break;
 
        case OP_NSTRLST:
@@ -7289,6 +7559,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
            inst.error = BAD_PC;
          break;
 
+       case OP_VLDR:
+         if (inst.operands[i].isreg)
+           break;
+       /* fall through.  */
        case OP_CPSF:
        case OP_ENDI:
        case OP_oROR:
@@ -7297,9 +7571,11 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_COND:
        case OP_oBARRIER_I15:
        case OP_REGLST:
+       case OP_CLRMLST:
        case OP_VRSLST:
        case OP_VRDLST:
        case OP_VRSDLST:
+       case OP_VRSDVLST:
        case OP_NRDLST:
        case OP_NSTRLST:
          if (val == FAIL)
@@ -7307,6 +7583,30 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          inst.operands[i].imm = val;
          break;
 
+       case OP_LR:
+       case OP_oLR:
+         if (inst.operands[i].reg != REG_LR)
+           inst.error = _("operand must be LR register");
+         break;
+
+       case OP_RRe:
+         if (inst.operands[i].isreg
+             && (inst.operands[i].reg & 0x00000001) != 0)
+           inst.error = BAD_ODD;
+         break;
+
+       case OP_RRo:
+         if (inst.operands[i].isreg)
+           {
+             if ((inst.operands[i].reg & 0x00000001) != 1)
+               inst.error = BAD_EVEN;
+             else if (inst.operands[i].reg == REG_SP)
+               as_tsktsk (MVE_BAD_SP);
+             else if (inst.operands[i].reg == REG_PC)
+               inst.error = BAD_PC;
+           }
+         break;
+
        default:
          break;
        }
@@ -7324,7 +7624,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          /* The parse routine should already have set inst.error, but set a
             default here just in case.  */
          if (!inst.error)
-           inst.error = _("syntax error");
+           inst.error = BAD_SYNTAX;
          return FAIL;
        }
 
@@ -7336,7 +7636,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          && upat[i+1] == OP_stop)
        {
          if (!inst.error)
-           inst.error = _("syntax error");
+           inst.error = BAD_SYNTAX;
          return FAIL;
        }
 
@@ -7417,7 +7717,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 static void
 do_scalar_fp16_v82_encode (void)
 {
-  if (inst.cond != COND_ALWAYS)
+  if (inst.cond < COND_ALWAYS)
     as_warn (_("ARMv8.2 scalar fp16 instruction cannot be conditional,"
               " the behaviour is UNPREDICTABLE"));
   constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16),
@@ -8890,9 +9190,9 @@ do_it (void)
   inst.size = 0;
   if (unified_syntax)
     {
-      set_it_insn_type (IT_INSN);
-      now_it.mask = (inst.instruction & 0xf) | 0x10;
-      now_it.cc = inst.operands[0].imm;
+      set_pred_insn_type (IT_INSN);
+      now_pred.mask = (inst.instruction & 0xf) | 0x10;
+      now_pred.cc = inst.operands[0].imm;
     }
 }
 
@@ -10506,7 +10806,9 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_b,     e000, f000b000),                   \
   X(_bcond, d000, f0008000),                   \
   X(_bf,    0000, f040e001),                   \
+  X(_bfcsel,0000, f000e001),                   \
   X(_bfx,   0000, f060e001),                   \
+  X(_bfl,   0000, f000c001),                   \
   X(_bflx,  0000, f070e001),                   \
   X(_bic,   4380, ea200000),                   \
   X(_bics,  4380, ea300000),                   \
@@ -10516,6 +10818,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_cpsid, b670, f3af8600),                   \
   X(_cpy,   4600, ea4f0000),                   \
   X(_dec_sp,80dd, f1ad0d00),                   \
+  X(_dls,   0000, f040e001),                   \
   X(_eor,   4040, ea800000),                   \
   X(_eors,  4040, ea900000),                   \
   X(_inc_sp,00dd, f10d0d00),                   \
@@ -10528,6 +10831,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_ldr_pc,4800, f85f0000),                   \
   X(_ldr_pc2,4800, f85f0000),                  \
   X(_ldr_sp,9800, f85d0000),                   \
+  X(_le,    0000, f00fc001),                   \
   X(_lsl,   0000, fa00f000),                   \
   X(_lsls,  0000, fa10f000),                   \
   X(_lsr,   0800, fa20f000),                   \
@@ -10569,6 +10873,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_yield, bf10, f3af8001),                   \
   X(_wfe,   bf20, f3af8002),                   \
   X(_wfi,   bf30, f3af8003),                   \
+  X(_wls,   0000, f040c001),                   \
   X(_sev,   bf40, f3af8004),                    \
   X(_sevl,  bf50, f3af8005),                   \
   X(_udf,   de00, f7f0a000)
@@ -10629,7 +10934,7 @@ do_t_add_sub (void)
        : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
 
   if (Rd == REG_PC)
-    set_it_insn_type_last ();
+    set_pred_insn_type_last ();
 
   if (unified_syntax)
     {
@@ -10640,9 +10945,9 @@ do_t_add_sub (void)
       flags = (inst.instruction == T_MNEM_adds
               || inst.instruction == T_MNEM_subs);
       if (flags)
-       narrow = !in_it_block ();
+       narrow = !in_pred_block ();
       else
-       narrow = in_it_block ();
+       narrow = in_pred_block ();
       if (!inst.operands[2].isreg)
        {
          int add;
@@ -10919,9 +11224,9 @@ do_t_arit3 (void)
 
          /* See if we can do this with a 16-bit instruction.  */
          if (THUMB_SETS_FLAGS (inst.instruction))
-           narrow = !in_it_block ();
+           narrow = !in_pred_block ();
          else
-           narrow = in_it_block ();
+           narrow = in_pred_block ();
 
          if (Rd > 7 || Rn > 7 || Rs > 7)
            narrow = FALSE;
@@ -11007,9 +11312,9 @@ do_t_arit3c (void)
 
          /* See if we can do this with a 16-bit instruction.  */
          if (THUMB_SETS_FLAGS (inst.instruction))
-           narrow = !in_it_block ();
+           narrow = !in_pred_block ();
          else
-           narrow = in_it_block ();
+           narrow = in_pred_block ();
 
          if (Rd > 7 || Rn > 7 || Rs > 7)
            narrow = FALSE;
@@ -11148,7 +11453,7 @@ do_t_bfx (void)
 static void
 do_t_blx (void)
 {
-  set_it_insn_type_last ();
+  set_pred_insn_type_last ();
 
   if (inst.operands[0].isreg)
     {
@@ -11172,9 +11477,9 @@ do_t_branch (void)
   bfd_reloc_code_real_type reloc;
 
   cond = inst.cond;
-  set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
+  set_pred_insn_type (IF_INSIDE_IT_LAST_INSN);
 
-  if (in_it_block ())
+  if (in_pred_block ())
     {
       /* Conditional branches inside IT blocks are encoded as unconditional
         branches.  */
@@ -11241,7 +11546,7 @@ do_t_bkpt_hlt1 (int range)
       inst.instruction |= inst.operands[0].imm;
     }
 
-  set_it_insn_type (NEUTRAL_IT_INSN);
+  set_pred_insn_type (NEUTRAL_IT_INSN);
 }
 
 static void
@@ -11259,7 +11564,7 @@ do_t_bkpt (void)
 static void
 do_t_branch23 (void)
 {
-  set_it_insn_type_last ();
+  set_pred_insn_type_last ();
   encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23);
 
   /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in
@@ -11287,7 +11592,7 @@ do_t_branch23 (void)
 static void
 do_t_bx (void)
 {
-  set_it_insn_type_last ();
+  set_pred_insn_type_last ();
   inst.instruction |= inst.operands[0].reg << 3;
   /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.         The reloc
      should cause the alignment to be checked once it is known.         This is
@@ -11299,7 +11604,7 @@ do_t_bxj (void)
 {
   int Rm;
 
-  set_it_insn_type_last ();
+  set_pred_insn_type_last ();
   Rm = inst.operands[0].reg;
   reject_bad_reg (Rm);
   inst.instruction |= Rm << 16;
@@ -11325,20 +11630,20 @@ do_t_clz (void)
 static void
 do_t_csdb (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
 }
 
 static void
 do_t_cps (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
   inst.instruction |= inst.operands[0].imm;
 }
 
 static void
 do_t_cpsi (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
   if (unified_syntax
       && (inst.operands[1].present || inst.size_req == 4)
       && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
@@ -11385,7 +11690,7 @@ do_t_cpy (void)
 static void
 do_t_cbz (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
   constraint (inst.operands[0].reg > 7, BAD_HIREG);
   inst.instruction |= inst.operands[0].reg;
   inst.relocs[0].pc_rel = 1;
@@ -11431,10 +11736,11 @@ do_t_it (void)
 {
   unsigned int cond = inst.operands[0].imm;
 
-  set_it_insn_type (IT_INSN);
-  now_it.mask = (inst.instruction & 0xf) | 0x10;
-  now_it.cc = cond;
-  now_it.warn_deprecated = FALSE;
+  set_pred_insn_type (IT_INSN);
+  now_pred.mask = (inst.instruction & 0xf) | 0x10;
+  now_pred.cc = cond;
+  now_pred.warn_deprecated = FALSE;
+  now_pred.type = SCALAR_PRED;
 
   /* If the condition is a negative condition, invert the mask.  */
   if ((cond & 0x1) == 0x0)
@@ -11444,22 +11750,22 @@ do_t_it (void)
       if ((mask & 0x7) == 0)
        {
          /* No conversion needed.  */
-         now_it.block_length = 1;
+         now_pred.block_length = 1;
        }
       else if ((mask & 0x3) == 0)
        {
          mask ^= 0x8;
-         now_it.block_length = 2;
+         now_pred.block_length = 2;
        }
       else if ((mask & 0x1) == 0)
        {
          mask ^= 0xC;
-         now_it.block_length = 3;
+         now_pred.block_length = 3;
        }
       else
        {
          mask ^= 0xE;
-         now_it.block_length = 4;
+         now_pred.block_length = 4;
        }
 
       inst.instruction &= 0xfff0;
@@ -11469,18 +11775,33 @@ do_t_it (void)
   inst.instruction |= cond << 4;
 }
 
+static void
+do_mve_vpt (void)
+{
+  /* We are dealing with a vector predicated block.  */
+  set_pred_insn_type (VPT_INSN);
+  now_pred.cc = 0;
+  now_pred.mask = ((inst.instruction & 0x00400000) >> 19)
+                 | ((inst.instruction & 0xe000) >> 13);
+  now_pred.warn_deprecated = FALSE;
+  now_pred.type = VECTOR_PRED;
+}
+
 /* Helper function used for both push/pop and ldm/stm.  */
 static void
-encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
+encode_thumb2_multi (bfd_boolean do_io, int base, unsigned mask,
+                    bfd_boolean writeback)
 {
-  bfd_boolean load;
+  bfd_boolean load, store;
 
-  load = (inst.instruction & (1 << 20)) != 0;
+  gas_assert (base != -1 || !do_io);
+  load = do_io && ((inst.instruction & (1 << 20)) != 0);
+  store = do_io && !load;
 
   if (mask & (1 << 13))
     inst.error =  _("SP not allowed in register list");
 
-  if ((mask & (1 << base)) != 0
+  if (do_io && (mask & (1 << base)) != 0
       && writeback)
     inst.error = _("having the base register in the register list when "
                   "using write back is UNPREDICTABLE");
@@ -11492,16 +11813,16 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
          if (mask & (1 << 14))
            inst.error = _("LR and PC should not both be in register list");
          else
-           set_it_insn_type_last ();
+           set_pred_insn_type_last ();
        }
     }
-  else
+  else if (store)
     {
       if (mask & (1 << 15))
        inst.error = _("PC not allowed in register list");
     }
 
-  if ((mask & (mask - 1)) == 0)
+  if (do_io && ((mask & (mask - 1)) == 0))
     {
       /* Single register transfers implemented as str/ldr.  */
       if (writeback)
@@ -11530,7 +11851,8 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
     inst.instruction |= WRITE_BACK;
 
   inst.instruction |= mask;
-  inst.instruction |= base << 16;
+  if (do_io)
+    inst.instruction |= base << 16;
 }
 
 static void
@@ -11625,8 +11947,9 @@ do_t_ldmstm (void)
          if (inst.instruction < 0xffff)
            inst.instruction = THUMB_OP32 (inst.instruction);
 
-         encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
-                               inst.operands[0].writeback);
+         encode_thumb2_multi (TRUE /* do_io */, inst.operands[0].reg,
+                              inst.operands[1].imm,
+                              inst.operands[0].writeback);
        }
     }
   else
@@ -11704,7 +12027,7 @@ do_t_ldst (void)
   if (inst.operands[0].isreg
       && !inst.operands[0].preind
       && inst.operands[0].reg == REG_PC)
-    set_it_insn_type_last ();
+    set_pred_insn_type_last ();
 
   opcode = inst.instruction;
   if (unified_syntax)
@@ -11963,7 +12286,7 @@ do_t_mov_cmp (void)
   Rm = inst.operands[1].reg;
 
   if (Rn == REG_PC)
-    set_it_insn_type_last ();
+    set_pred_insn_type_last ();
 
   if (unified_syntax)
     {
@@ -11975,7 +12298,7 @@ do_t_mov_cmp (void)
 
       low_regs = (Rn <= 7 && Rm <= 7);
       opcode = inst.instruction;
-      if (in_it_block ())
+      if (in_pred_block ())
        narrow = opcode != T_MNEM_movs;
       else
        narrow = opcode != T_MNEM_movs || low_regs;
@@ -12046,7 +12369,7 @@ do_t_mov_cmp (void)
       if (!inst.operands[1].isreg)
        {
          /* Immediate operand.  */
-         if (!in_it_block () && opcode == T_MNEM_mov)
+         if (!in_pred_block () && opcode == T_MNEM_mov)
            narrow = 0;
          if (low_regs && narrow)
            {
@@ -12082,7 +12405,7 @@ do_t_mov_cmp (void)
          /* Register shifts are encoded as separate shift instructions.  */
          bfd_boolean flags = (inst.instruction == T_MNEM_movs);
 
-         if (in_it_block ())
+         if (in_pred_block ())
            narrow = !flags;
          else
            narrow = flags;
@@ -12138,7 +12461,7 @@ do_t_mov_cmp (void)
              && (inst.instruction == T_MNEM_mov
                  || inst.instruction == T_MNEM_movs))
            {
-             if (in_it_block ())
+             if (in_pred_block ())
                narrow = (inst.instruction == T_MNEM_mov);
              else
                narrow = (inst.instruction == T_MNEM_movs);
@@ -12317,9 +12640,9 @@ do_t_mvn_tst (void)
               || inst.instruction == T_MNEM_tst)
        narrow = TRUE;
       else if (THUMB_SETS_FLAGS (inst.instruction))
-       narrow = !in_it_block ();
+       narrow = !in_pred_block ();
       else
-       narrow = in_it_block ();
+       narrow = in_pred_block ();
 
       if (!inst.operands[1].isreg)
        {
@@ -12484,9 +12807,9 @@ do_t_mul (void)
          || Rm > 7)
        narrow = FALSE;
       else if (inst.instruction == T_MNEM_muls)
-       narrow = !in_it_block ();
+       narrow = !in_pred_block ();
       else
-       narrow = in_it_block ();
+       narrow = in_pred_block ();
     }
   else
     {
@@ -12552,7 +12875,7 @@ do_t_mull (void)
 static void
 do_t_nop (void)
 {
-  set_it_insn_type (NEUTRAL_IT_INSN);
+  set_pred_insn_type (NEUTRAL_IT_INSN);
 
   if (unified_syntax)
     {
@@ -12590,9 +12913,9 @@ do_t_neg (void)
       bfd_boolean narrow;
 
       if (THUMB_SETS_FLAGS (inst.instruction))
-       narrow = !in_it_block ();
+       narrow = !in_pred_block ();
       else
-       narrow = in_it_block ();
+       narrow = in_pred_block ();
       if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
        narrow = FALSE;
       if (inst.size_req == 4)
@@ -12733,8 +13056,20 @@ do_t_push_pop (void)
   else if (unified_syntax)
     {
       inst.instruction = THUMB_OP32 (inst.instruction);
-      encode_thumb2_ldmstm (13, mask, TRUE);
+      encode_thumb2_multi (TRUE /* do_io */, 13, mask, TRUE);
+    }
+  else
+    {
+      inst.error = _("invalid register list to push/pop instruction");
+      return;
     }
+}
+
+static void
+do_t_clrm (void)
+{
+  if (unified_syntax)
+    encode_thumb2_multi (FALSE /* do_io */, -1, inst.operands[0].imm, FALSE);
   else
     {
       inst.error = _("invalid register list to push/pop instruction");
@@ -12742,6 +13077,24 @@ do_t_push_pop (void)
     }
 }
 
+static void
+do_t_vscclrm (void)
+{
+  if (inst.operands[0].issingle)
+    {
+      inst.instruction |= (inst.operands[0].reg & 0x1) << 22;
+      inst.instruction |= (inst.operands[0].reg & 0x1e) << 11;
+      inst.instruction |= inst.operands[0].imm;
+    }
+  else
+    {
+      inst.instruction |= (inst.operands[0].reg & 0x10) << 18;
+      inst.instruction |= (inst.operands[0].reg & 0xf) << 12;
+      inst.instruction |= 1 << 8;
+      inst.instruction |= inst.operands[0].imm << 1;
+    }
+}
+
 static void
 do_t_rbit (void)
 {
@@ -12824,9 +13177,9 @@ do_t_rsb (void)
       bfd_boolean narrow;
 
       if ((inst.instruction & 0x00100000) != 0)
-       narrow = !in_it_block ();
+       narrow = !in_pred_block ();
       else
-       narrow = in_it_block ();
+       narrow = in_pred_block ();
 
       if (Rd > 7 || Rs > 7)
        narrow = FALSE;
@@ -12864,7 +13217,7 @@ do_t_setend (void)
       && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
       as_tsktsk (_("setend use is deprecated for ARMv8"));
 
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
   if (inst.operands[0].imm)
     inst.instruction |= 0x8;
 }
@@ -12894,9 +13247,9 @@ do_t_shift (void)
        }
 
       if (THUMB_SETS_FLAGS (inst.instruction))
-       narrow = !in_it_block ();
+       narrow = !in_pred_block ();
       else
-       narrow = in_it_block ();
+       narrow = in_pred_block ();
       if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
        narrow = FALSE;
       if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
@@ -13066,7 +13419,7 @@ do_t_smc (void)
   inst.instruction |= (value & 0x0ff0);
   inst.instruction |= (value & 0x000f) << 16;
   /* PR gas/15623: SMC instructions must be last in an IT block.  */
-  set_it_insn_type_last ();
+  set_pred_insn_type_last ();
 }
 
 static void
@@ -13241,7 +13594,7 @@ do_t_tb (void)
   int half;
 
   half = (inst.instruction & 0x10) != 0;
-  set_it_insn_type_last ();
+  set_pred_insn_type_last ();
   constraint (inst.operands[0].immisreg,
              _("instruction requires register index"));
 
@@ -13277,7 +13630,7 @@ do_t_udf (void)
       inst.instruction |= inst.operands[0].imm;
     }
 
-  set_it_insn_type (NEUTRAL_IT_INSN);
+  set_pred_insn_type (NEUTRAL_IT_INSN);
 }
 
 
@@ -13364,6 +13717,65 @@ do_t_branch_future (void)
          }
        break;
 
+      case T_MNEM_bfl:
+       if (inst.operands[1].hasreloc == 0)
+         {
+           int val = inst.operands[1].imm;
+           if (v8_1_branch_value_check (inst.operands[1].imm, 19, TRUE) == FAIL)
+             as_bad (BAD_BRANCH_OFF);
+
+           int immA = (val & 0x0007f000) >> 12;
+           int immB = (val & 0x00000ffc) >> 2;
+           int immC = (val & 0x00000002) >> 1;
+           inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+         }
+         else
+         {
+           inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF19;
+           inst.relocs[1].pc_rel = 1;
+         }
+       break;
+
+      case T_MNEM_bfcsel:
+       /* Operand 1.  */
+       if (inst.operands[1].hasreloc == 0)
+         {
+           int val = inst.operands[1].imm;
+           int immA = (val & 0x00001000) >> 12;
+           int immB = (val & 0x00000ffc) >> 2;
+           int immC = (val & 0x00000002) >> 1;
+           inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+         }
+         else
+         {
+           inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF13;
+           inst.relocs[1].pc_rel = 1;
+         }
+
+       /* Operand 2.  */
+       if (inst.operands[2].hasreloc == 0)
+         {
+             constraint ((inst.operands[0].hasreloc != 0), BAD_ARGS);
+             int val2 = inst.operands[2].imm;
+             int val0 = inst.operands[0].imm & 0x1f;
+             int diff = val2 - val0;
+             if (diff == 4)
+               inst.instruction |= 1 << 17; /* T bit.  */
+             else if (diff != 2)
+               as_bad (_("out of range label-relative fixup value"));
+         }
+       else
+         {
+             constraint ((inst.operands[0].hasreloc == 0), BAD_ARGS);
+             inst.relocs[2].type = BFD_RELOC_THUMB_PCREL_BFCSEL;
+             inst.relocs[2].pc_rel = 1;
+         }
+
+       /* Operand 3.  */
+       constraint (inst.cond != COND_ALWAYS, BAD_COND);
+       inst.instruction |= (inst.operands[3].imm & 0xf) << 18;
+       break;
+
       case T_MNEM_bfx:
       case T_MNEM_bflx:
        inst.instruction |= inst.operands[1].reg << 16;
@@ -13373,6 +13785,77 @@ do_t_branch_future (void)
     }
 }
 
+/* Helper function for do_t_loloop to handle relocations.  */
+static void
+v8_1_loop_reloc (int is_le)
+{
+  if (inst.relocs[0].exp.X_op == O_constant)
+    {
+      int value = inst.relocs[0].exp.X_add_number;
+      value = (is_le) ? -value : value;
+
+      if (v8_1_branch_value_check (value, 12, FALSE) == FAIL)
+       as_bad (BAD_BRANCH_OFF);
+
+      int imml, immh;
+
+      immh = (value & 0x00000ffc) >> 2;
+      imml = (value & 0x00000002) >> 1;
+
+      inst.instruction |= (imml << 11) | (immh << 1);
+    }
+  else
+    {
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_LOOP12;
+      inst.relocs[0].pc_rel = 1;
+    }
+}
+
+/* To handle the Scalar Low Overhead Loop instructions
+   in Armv8.1-M Mainline.  */
+static void
+do_t_loloop (void)
+{
+  unsigned long insn = inst.instruction;
+
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
+  inst.instruction = THUMB_OP32 (inst.instruction);
+
+  switch (insn)
+    {
+    case T_MNEM_le:
+      /* le <label>.  */
+      if (!inst.operands[0].present)
+       inst.instruction |= 1 << 21;
+
+      v8_1_loop_reloc (TRUE);
+      break;
+
+    case T_MNEM_wls:
+      v8_1_loop_reloc (FALSE);
+      /* Fall through.  */
+    case T_MNEM_dls:
+      constraint (inst.operands[1].isreg != 1, BAD_ARGS);
+      inst.instruction |= (inst.operands[1].reg << 16);
+      break;
+
+    default: abort();
+    }
+}
+
+/* MVE instruction encoder helpers.  */
+#define M_MNEM_vabav   0xee800f01
+#define M_MNEM_vmladav   0xeef00e00
+#define M_MNEM_vmladava          0xeef00e20
+#define M_MNEM_vmladavx          0xeef01e00
+#define M_MNEM_vmladavax  0xeef01e20
+#define M_MNEM_vmlsdav   0xeef00e01
+#define M_MNEM_vmlsdava          0xeef00e21
+#define M_MNEM_vmlsdavx          0xeef01e01
+#define M_MNEM_vmlsdavax  0xeef01e21
+#define M_MNEM_vmullt  0xee011e00
+#define M_MNEM_vmullb  0xee010e00
+
 /* Neon instruction encoder helpers.  */
 
 /* Encodings for the different types for various Neon opcodes.  */
@@ -13390,13 +13873,16 @@ struct neon_tab_entry
 /* Map overloaded Neon opcodes to their respective encodings.  */
 #define NEON_ENC_TAB                                   \
   X(vabd,      0x0000700, 0x1200d00, N_INV),           \
+  X(vabdl,     0x0800700, N_INV,     N_INV),           \
   X(vmax,      0x0000600, 0x0000f00, N_INV),           \
   X(vmin,      0x0000610, 0x0200f00, N_INV),           \
   X(vpadd,     0x0000b10, 0x1000d00, N_INV),           \
   X(vpmax,     0x0000a00, 0x1000f00, N_INV),           \
   X(vpmin,     0x0000a10, 0x1200f00, N_INV),           \
   X(vadd,      0x0000800, 0x0000d00, N_INV),           \
+  X(vaddl,     0x0800000, N_INV,     N_INV),           \
   X(vsub,      0x1000800, 0x0200d00, N_INV),           \
+  X(vsubl,     0x0800200, N_INV,     N_INV),           \
   X(vceq,      0x1000810, 0x0000e00, 0x1b10100),       \
   X(vcge,      0x0000310, 0x1000e00, 0x1b10080),       \
   X(vcgt,      0x0000300, 0x1200e00, 0x1b10000),       \
@@ -13533,12 +14019,14 @@ NEON_ENC_TAB
      - a table used to drive neon_select_shape.  */
 
 #define NEON_SHAPE_DEF                 \
+  X(3, (R, Q, Q), QUAD),               \
   X(3, (D, D, D), DOUBLE),             \
   X(3, (Q, Q, Q), QUAD),               \
   X(3, (D, D, I), DOUBLE),             \
   X(3, (Q, Q, I), QUAD),               \
   X(3, (D, D, S), DOUBLE),             \
   X(3, (Q, Q, S), QUAD),               \
+  X(3, (Q, Q, R), QUAD),               \
   X(2, (D, D), DOUBLE),                        \
   X(2, (Q, Q), QUAD),                  \
   X(2, (D, S), DOUBLE),                        \
@@ -13728,6 +14216,9 @@ enum neon_type_mask
 #define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
 #define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F16 | N_F32)
 #define N_F_ALL    (N_F16 | N_F32 | N_F64)
+#define N_I_MVE           (N_I8 | N_I16 | N_I32)
+#define N_F_MVE           (N_F16 | N_F32)
+#define N_SU_MVE   (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
 
 /* Pass this as the first type argument to neon_check_type to ignore types
    altogether.  */
@@ -14256,7 +14747,7 @@ neon_check_type (unsigned els, enum neon_shape ns, ...)
 
                  if ((given_type & types_allowed) == 0)
                    {
-                     first_error (_("bad type in Neon instruction"));
+                     first_error (BAD_SIMD_TYPE);
                      return badtype;
                    }
                }
@@ -14699,9 +15190,78 @@ neon_logbits (unsigned x)
 #define LOW4(R) ((R) & 0xf)
 #define HI1(R) (((R) >> 4) & 1)
 
-/* Encode insns with bit pattern:
+static void
+mve_encode_qqr (int size, int fp)
+{
+  if (inst.operands[2].reg == REG_SP)
+    as_tsktsk (MVE_BAD_SP);
+  else if (inst.operands[2].reg == REG_PC)
+    as_tsktsk (MVE_BAD_PC);
 
-  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
+  if (fp)
+    {
+      /* vadd.  */
+      if (((unsigned)inst.instruction) == 0xd00)
+       inst.instruction = 0xee300f40;
+      /* vsub.  */
+      else if (((unsigned)inst.instruction) == 0x200d00)
+       inst.instruction = 0xee301f40;
+
+      /* Setting size which is 1 for F16 and 0 for F32.  */
+      inst.instruction |= (size == 16) << 28;
+    }
+  else
+    {
+      /* vadd.  */
+      if (((unsigned)inst.instruction) == 0x800)
+       inst.instruction = 0xee010f40;
+      /* vsub.  */
+      else if (((unsigned)inst.instruction) == 0x1000800)
+       inst.instruction = 0xee011f40;
+      /* Setting bits for size.  */
+      inst.instruction |= neon_logbits (size) << 20;
+    }
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= inst.operands[2].reg;
+  inst.is_neon = 1;
+}
+
+static void
+mve_encode_rqq (unsigned bit28, unsigned size)
+{
+  inst.instruction |= bit28 << 28;
+  inst.instruction |= neon_logbits (size) << 20;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+  inst.instruction |= LOW4 (inst.operands[2].reg);
+  inst.is_neon = 1;
+}
+
+static void
+mve_encode_qqq (int ubit, int size)
+{
+
+  inst.instruction |= (ubit != 0) << 28;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= neon_logbits (size) << 20;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+  inst.instruction |= LOW4 (inst.operands[2].reg);
+
+  inst.is_neon = 1;
+}
+
+
+/* Encode insns with bit pattern:
+
+  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
   |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
 
   SIZE is passed in bits. -1 means size field isn't changed, in case it has a
@@ -15020,26 +15580,27 @@ static void
 neon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
                  unsigned destbits)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_QQR, NS_NULL);
   struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
                                            types | N_KEY);
   if (et.type == NT_float)
     {
       NEON_ENCODE (FLOAT, inst);
-      neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
+      if (rs == NS_QQR)
+       mve_encode_qqr (et.size, 1);
+      else
+       neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
     }
   else
     {
       NEON_ENCODE (INTEGER, inst);
-      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
+      if (rs == NS_QQR)
+       mve_encode_qqr (et.size, 0);
+      else
+       neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
     }
 }
 
-static void
-do_neon_dyadic_if_su (void)
-{
-  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
-}
 
 static void
 do_neon_dyadic_if_su_d (void)
@@ -15098,31 +15659,92 @@ vfp_or_neon_is_neon (unsigned check)
        inst.instruction |= inst.uncond_value << 28;
     }
 
-  if ((check & NEON_CHECK_ARCH)
-      && !mark_feature_used (&fpu_neon_ext_v1))
+
+    if (((check & NEON_CHECK_ARCH) && !mark_feature_used (&fpu_neon_ext_v1))
+       || ((check & NEON_CHECK_ARCH8)
+           && !mark_feature_used (&fpu_neon_ext_armv8)))
+      {
+       first_error (_(BAD_FPU));
+       return FAIL;
+      }
+
+  return SUCCESS;
+}
+
+static int
+check_simd_pred_availability (int fp, unsigned check)
+{
+  if (inst.cond > COND_ALWAYS)
     {
-      first_error (_(BAD_FPU));
-      return FAIL;
+      if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+       {
+         inst.error = BAD_FPU;
+         return 1;
+       }
+      inst.pred_insn_type = INSIDE_VPT_INSN;
     }
-
-  if ((check & NEON_CHECK_ARCH8)
-      && !mark_feature_used (&fpu_neon_ext_armv8))
+  else if (inst.cond < COND_ALWAYS)
     {
-      first_error (_(BAD_FPU));
-      return FAIL;
+      if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+       inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
+      else if (vfp_or_neon_is_neon (check) == FAIL)
+       return 2;
+    }
+  else
+    {
+      if (!ARM_CPU_HAS_FEATURE (cpu_variant, fp ? mve_fp_ext : mve_ext)
+         && vfp_or_neon_is_neon (check) == FAIL)
+       return 3;
+
+      if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+       inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
     }
+  return 0;
+}
 
-  return SUCCESS;
+static void
+do_neon_dyadic_if_su (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_QQR, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK , N_EQK,
+                                           N_SUF_32 | N_KEY);
+
+  if (check_simd_pred_availability (et.type == NT_float,
+                                   NEON_CHECK_ARCH | NEON_CHECK_CC))
+    return;
+
+  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
 }
 
 static void
 do_neon_addsub_if_i (void)
 {
-  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
+  if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1xd)
+      && try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
     return;
 
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-    return;
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_QQR, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK,
+                                           N_EQK, N_IF_32 | N_I64 | N_KEY);
+
+  constraint (rs == NS_QQR && et.size == 64, BAD_FPU);
+  /* If we are parsing Q registers and the element types match MVE, which NEON
+     also supports, then we must check whether this is an instruction that can
+     be used by both MVE/NEON.  This distinction can be made based on whether
+     they are predicated or not.  */
+  if ((rs == NS_QQQ || rs == NS_QQR) && et.size != 64)
+    {
+      if (check_simd_pred_availability (et.type == NT_float,
+                                       NEON_CHECK_ARCH | NEON_CHECK_CC))
+       return;
+    }
+  else
+    {
+      /* If they are either in a D register or are using an unsupported.  */
+      if (rs != NS_QQR
+         && vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+       return;
+    }
 
   /* The "untyped" case can't happen. Do this to stop the "U" bit being
      affected if we specify unsigned args.  */
@@ -15355,6 +15977,120 @@ do_neon_qdmulh (void)
     }
 }
 
+static void
+do_mve_vmull (void)
+{
+
+  enum neon_shape rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_DDS,
+                                         NS_QQS, NS_QQQ, NS_QQR, NS_NULL);
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+      && inst.cond == COND_ALWAYS
+      && ((unsigned)inst.instruction) == M_MNEM_vmullt)
+    {
+      if (rs == NS_QQQ)
+       {
+
+         struct neon_type_el et = neon_check_type (3, rs, N_EQK , N_EQK,
+                                                   N_SUF_32 | N_F64 | N_P8
+                                                   | N_P16 | N_I_MVE | N_KEY);
+         if (((et.type == NT_poly) && et.size == 8
+              && ARM_CPU_IS_ANY (cpu_variant))
+             || (et.type == NT_integer) || (et.type == NT_float))
+           goto neon_vmul;
+       }
+      else
+       goto neon_vmul;
+    }
+
+  constraint (rs != NS_QQQ, BAD_FPU);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK , N_EQK,
+                                           N_SU_32 | N_P8 | N_P16 | N_KEY);
+
+  /* We are dealing with MVE's vmullt.  */
+  if (et.size == 32
+      && (inst.operands[0].reg == inst.operands[1].reg
+         || inst.operands[0].reg == inst.operands[2].reg))
+    as_tsktsk (BAD_MVE_SRCDEST);
+
+  if (inst.cond > COND_ALWAYS)
+    inst.pred_insn_type = INSIDE_VPT_INSN;
+  else
+    inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
+
+  if (et.type == NT_poly)
+    mve_encode_qqq (neon_logbits (et.size), 64);
+  else
+    mve_encode_qqq (et.type == NT_unsigned, et.size);
+
+  return;
+
+neon_vmul:
+  inst.instruction = N_MNEM_vmul;
+  inst.cond = 0xb;
+  if (thumb_mode)
+    inst.pred_insn_type = INSIDE_IT_INSN;
+  do_neon_mul ();
+}
+
+static void
+do_mve_vabav (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_RQQ, NS_NULL);
+
+  if (rs == NS_NULL)
+    return;
+
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+    return;
+
+  struct neon_type_el et = neon_check_type (2, NS_NULL, N_EQK, N_KEY | N_S8
+                                           | N_S16 | N_S32 | N_U8 | N_U16
+                                           | N_U32);
+
+  if (inst.cond > COND_ALWAYS)
+    inst.pred_insn_type = INSIDE_VPT_INSN;
+  else
+    inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
+
+  mve_encode_rqq (et.type == NT_unsigned, et.size);
+}
+
+static void
+do_mve_vmladav (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_RQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs,
+                                           N_EQK, N_EQK, N_SU_MVE | N_KEY);
+
+  if (et.type == NT_unsigned
+      && (inst.instruction == M_MNEM_vmladavx
+         || inst.instruction == M_MNEM_vmladavax
+         || inst.instruction == M_MNEM_vmlsdav
+         || inst.instruction == M_MNEM_vmlsdava
+         || inst.instruction == M_MNEM_vmlsdavx
+         || inst.instruction == M_MNEM_vmlsdavax))
+    first_error (BAD_SIMD_TYPE);
+
+  constraint (inst.operands[2].reg > 14,
+             _("MVE vector register in the range [Q0..Q7] expected"));
+
+  if (inst.cond > COND_ALWAYS)
+    inst.pred_insn_type = INSIDE_VPT_INSN;
+  else
+    inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
+
+  if (inst.instruction == M_MNEM_vmlsdav
+      || inst.instruction == M_MNEM_vmlsdava
+      || inst.instruction == M_MNEM_vmlsdavx
+      || inst.instruction == M_MNEM_vmlsdavax)
+    inst.instruction |= (et.size == 8) << 28;
+  else
+    inst.instruction |= (et.size == 8) << 8;
+
+  mve_encode_rqq (et.type == NT_unsigned, 64);
+  inst.instruction |= (et.size == 32) << 16;
+}
+
 static void
 do_neon_qrdmlah (void)
 {
@@ -15422,12 +16158,13 @@ do_neon_abs_neg (void)
   if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
     return;
 
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-    return;
-
   rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
   et = neon_check_type (2, rs, N_EQK, N_S_32 | N_F_16_32 | N_KEY);
 
+  if (check_simd_pred_availability (et.type == NT_float,
+                                   NEON_CHECK_ARCH | NEON_CHECK_CC))
+    return;
+
   inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
   inst.instruction |= HI1 (inst.operands[0].reg) << 22;
   inst.instruction |= LOW4 (inst.operands[1].reg);
@@ -15805,7 +16542,7 @@ do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
     constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16),
                _(BAD_FP16));
 
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
 
   switch (flavour)
     {
@@ -15960,7 +16697,7 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
       if (mode != neon_cvt_mode_x && mode != neon_cvt_mode_z)
        {
          NEON_ENCODE (FLOAT, inst);
-         set_it_insn_type (OUTSIDE_IT_INSN);
+         set_pred_insn_type (OUTSIDE_PRED_INSN);
 
          if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
            return;
@@ -16261,10 +16998,49 @@ neon_mixed_length (struct neon_type_el et, unsigned size)
 static void
 do_neon_dyadic_long (void)
 {
-  /* FIXME: Type checking for lengthening op.  */
-  struct neon_type_el et = neon_check_type (3, NS_QDD,
-    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
-  neon_mixed_length (et, et.size);
+  enum neon_shape rs = neon_select_shape (NS_QDD, NS_QQQ, NS_QQR, NS_NULL);
+  if (rs == NS_QDD)
+    {
+      if (vfp_or_neon_is_neon (NEON_CHECK_ARCH | NEON_CHECK_CC) == FAIL)
+       return;
+
+      NEON_ENCODE (INTEGER, inst);
+      /* FIXME: Type checking for lengthening op.  */
+      struct neon_type_el et = neon_check_type (3, NS_QDD,
+       N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
+      neon_mixed_length (et, et.size);
+    }
+  else if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+          && (inst.cond == 0xf || inst.cond == 0x10))
+    {
+      /* If parsing for MVE, vaddl/vsubl/vabdl{e,t} can only be vadd/vsub/vabd
+        in an IT block with le/lt conditions.  */
+
+      if (inst.cond == 0xf)
+       inst.cond = 0xb;
+      else if (inst.cond == 0x10)
+       inst.cond = 0xd;
+
+      inst.pred_insn_type = INSIDE_IT_INSN;
+
+      if (inst.instruction == N_MNEM_vaddl)
+       {
+         inst.instruction = N_MNEM_vadd;
+         do_neon_addsub_if_i ();
+       }
+      else if (inst.instruction == N_MNEM_vsubl)
+       {
+         inst.instruction = N_MNEM_vsub;
+         do_neon_addsub_if_i ();
+       }
+      else if (inst.instruction == N_MNEM_vabdl)
+       {
+         inst.instruction = N_MNEM_vabd;
+         do_neon_dyadic_if_su ();
+       }
+    }
+  else
+    first_error (BAD_FPU);
 }
 
 static void
@@ -17120,6 +17896,55 @@ do_neon_ldr_str (void)
     }
 }
 
+static void
+do_t_vldr_vstr_sysreg (void)
+{
+  int fp_vldr_bitno = 20, sysreg_vldr_bitno = 20;
+  bfd_boolean is_vldr = ((inst.instruction & (1 << fp_vldr_bitno)) != 0);
+
+  /* Use of PC is UNPREDICTABLE.  */
+  if (inst.operands[1].reg == REG_PC)
+    inst.error = _("Use of PC here is UNPREDICTABLE");
+
+  if (inst.operands[1].immisreg)
+    inst.error = _("instruction does not accept register index");
+
+  if (!inst.operands[1].isreg)
+    inst.error = _("instruction does not accept PC-relative addressing");
+
+  if (abs (inst.operands[1].imm) >= (1 << 7))
+    inst.error = _("immediate value out of range");
+
+  inst.instruction = 0xec000f80;
+  if (is_vldr)
+    inst.instruction |= 1 << sysreg_vldr_bitno;
+  encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM);
+  inst.instruction |= (inst.operands[0].imm & 0x7) << 13;
+  inst.instruction |= (inst.operands[0].imm & 0x8) << 19;
+}
+
+static void
+do_vldr_vstr (void)
+{
+  bfd_boolean sysreg_op = !inst.operands[0].isreg;
+
+  /* VLDR/VSTR (System Register).  */
+  if (sysreg_op)
+    {
+      if (!mark_feature_used (&arm_ext_v8_1m_main))
+       as_bad (_("Instruction not permitted on this architecture"));
+
+      do_t_vldr_vstr_sysreg ();
+    }
+  /* VLDR/VSTR.  */
+  else
+    {
+      if (!mark_feature_used (&fpu_vfp_ext_v1xd))
+       as_bad (_("Instruction not permitted on this architecture"));
+      do_neon_ldr_str ();
+    }
+}
+
 /* "interleave" version also handles non-interleaving register VLD1/VST1
    instructions.  */
 
@@ -17488,7 +18313,7 @@ do_vfp_nsyn_fpv8 (enum neon_shape rs)
 static void
 do_vsel (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
 
   if (try_vfp_nsyn (3, do_vfp_nsyn_fpv8) != SUCCESS)
     first_error (_("invalid instruction shape"));
@@ -17497,7 +18322,7 @@ do_vsel (void)
 static void
 do_vmaxnm (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
 
   if (try_vfp_nsyn (3, do_vfp_nsyn_fpv8) == SUCCESS)
     return;
@@ -17530,7 +18355,7 @@ do_vrint_1 (enum neon_cvt_mode mode)
       /* VFP encodings.  */
       if (mode == neon_cvt_mode_a || mode == neon_cvt_mode_n
          || mode == neon_cvt_mode_p || mode == neon_cvt_mode_m)
-       set_it_insn_type (OUTSIDE_IT_INSN);
+       set_pred_insn_type (OUTSIDE_PRED_INSN);
 
       NEON_ENCODE (FPV8, inst);
       if (rs == NS_FF || rs == NS_HH)
@@ -17566,7 +18391,7 @@ do_vrint_1 (enum neon_cvt_mode mode)
       if (et.type == NT_invtype)
        return;
 
-      set_it_insn_type (OUTSIDE_IT_INSN);
+      set_pred_insn_type (OUTSIDE_PRED_INSN);
       NEON_ENCODE (FLOAT, inst);
 
       if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
@@ -17795,7 +18620,7 @@ do_neon_dotproduct_u (void)
 static void
 do_crypto_2op_1 (unsigned elttype, int op)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
 
   if (neon_check_type (2, NS_QQ, N_EQK | N_UNT, elttype | N_UNT | N_KEY).type
       == NT_invtype)
@@ -17820,7 +18645,7 @@ do_crypto_2op_1 (unsigned elttype, int op)
 static void
 do_crypto_3op_1 (int u, int op)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
 
   if (neon_check_type (3, NS_QQQ, N_EQK | N_UNT, N_EQK | N_UNT,
                       N_32 | N_UNT | N_KEY).type == NT_invtype)
@@ -17923,7 +18748,7 @@ do_crc32_1 (unsigned int poly, unsigned int sz)
   unsigned int Rn = inst.operands[1].reg;
   unsigned int Rm = inst.operands[2].reg;
 
-  set_it_insn_type (OUTSIDE_IT_INSN);
+  set_pred_insn_type (OUTSIDE_PRED_INSN);
   inst.instruction |= LOW4 (Rd) << (thumb_mode ? 8 : 12);
   inst.instruction |= LOW4 (Rn) << 16;
   inst.instruction |= LOW4 (Rm);
@@ -18165,9 +18990,10 @@ enum opcode_tag
   OT_unconditionalF,   /* Instruction cannot be conditionalized
                           and carries 0xF in its ARM condition field.  */
   OT_csuffix,          /* Instruction takes a conditional suffix.  */
-  OT_csuffixF,         /* Some forms of the instruction take a conditional
-                          suffix, others place 0xF where the condition field
-                          would be.  */
+  OT_csuffixF,         /* Some forms of the instruction take a scalar
+                          conditional suffix, others place 0xF where the
+                          condition field would be, others take a vector
+                          conditional suffix.  */
   OT_cinfix3,          /* Instruction takes a conditional infix,
                           beginning at character index 3.  (In
                           unified mode, it becomes a suffix.)  */
@@ -18313,17 +19139,35 @@ opcode_lookup (char **str)
       inst.cond = cond->value;
       return opcode;
     }
+ if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+   {
+    /* Cannot have a conditional suffix on a mnemonic of less than a character.
+     */
+    if (end - base < 2)
+      return NULL;
+     affix = end - 1;
+     cond = (const struct asm_cond *) hash_find_n (arm_vcond_hsh, affix, 1);
+     opcode = (const struct asm_opcode *) hash_find_n (arm_ops_hsh, base,
+                                                     affix - base);
+     /* If this opcode can not be vector predicated then don't accept it with a
+       vector predication code.  */
+     if (opcode && !opcode->mayBeVecPred)
+       opcode = NULL;
+   }
+  if (!opcode || !cond)
+    {
+      /* Cannot have a conditional suffix on a mnemonic of less than two
+        characters.  */
+      if (end - base < 3)
+       return NULL;
 
-  /* Cannot have a conditional suffix on a mnemonic of less than two
-     characters.  */
-  if (end - base < 3)
-    return NULL;
+      /* Look for suffixed mnemonic.  */
+      affix = end - 2;
+      cond = (const struct asm_cond *) hash_find_n (arm_cond_hsh, affix, 2);
+      opcode = (const struct asm_opcode *) hash_find_n (arm_ops_hsh, base,
+                                                       affix - base);
+    }
 
-  /* Look for suffixed mnemonic.  */
-  affix = end - 2;
-  cond = (const struct asm_cond *) hash_find_n (arm_cond_hsh, affix, 2);
-  opcode = (const struct asm_opcode *) hash_find_n (arm_ops_hsh, base,
-                                                   affix - base);
   if (opcode && cond)
     {
       /* step CE */
@@ -18402,7 +19246,7 @@ opcode_lookup (char **str)
 
 /* This function generates an initial IT instruction, leaving its block
    virtually open for the new instructions. Eventually,
-   the mask will be updated by now_it_add_mask () each time
+   the mask will be updated by now_pred_add_mask () each time
    a new instruction needs to be included in the IT block.
    Finally, the block is closed with close_automatic_it_block ().
    The block closure can be requested either from md_assemble (),
@@ -18411,14 +19255,14 @@ opcode_lookup (char **str)
 static void
 new_automatic_it_block (int cond)
 {
-  now_it.state = AUTOMATIC_IT_BLOCK;
-  now_it.mask = 0x18;
-  now_it.cc = cond;
-  now_it.block_length = 1;
+  now_pred.state = AUTOMATIC_PRED_BLOCK;
+  now_pred.mask = 0x18;
+  now_pred.cc = cond;
+  now_pred.block_length = 1;
   mapping_state (MAP_THUMB);
-  now_it.insn = output_it_inst (cond, now_it.mask, NULL);
-  now_it.warn_deprecated = FALSE;
-  now_it.insn_cond = TRUE;
+  now_pred.insn = output_it_inst (cond, now_pred.mask, NULL);
+  now_pred.warn_deprecated = FALSE;
+  now_pred.insn_cond = TRUE;
 }
 
 /* Close an automatic IT block.
@@ -18427,29 +19271,29 @@ new_automatic_it_block (int cond)
 static void
 close_automatic_it_block (void)
 {
-  now_it.mask = 0x10;
-  now_it.block_length = 0;
+  now_pred.mask = 0x10;
+  now_pred.block_length = 0;
 }
 
 /* Update the mask of the current automatically-generated IT
    instruction. See comments in new_automatic_it_block ().  */
 
 static void
-now_it_add_mask (int cond)
+now_pred_add_mask (int cond)
 {
 #define CLEAR_BIT(value, nbit)  ((value) & ~(1 << (nbit)))
 #define SET_BIT_VALUE(value, bitvalue, nbit)  (CLEAR_BIT (value, nbit) \
                                              | ((bitvalue) << (nbit)))
   const int resulting_bit = (cond & 1);
 
-  now_it.mask &= 0xf;
-  now_it.mask = SET_BIT_VALUE (now_it.mask,
+  now_pred.mask &= 0xf;
+  now_pred.mask = SET_BIT_VALUE (now_pred.mask,
                                   resulting_bit,
-                                 (5 - now_it.block_length));
-  now_it.mask = SET_BIT_VALUE (now_it.mask,
+                                 (5 - now_pred.block_length));
+  now_pred.mask = SET_BIT_VALUE (now_pred.mask,
                                   1,
-                                  ((5 - now_it.block_length) - 1) );
-  output_it_inst (now_it.cc, now_it.mask, now_it.insn);
+                                  ((5 - now_pred.block_length) - 1));
+  output_it_inst (now_pred.cc, now_pred.mask, now_pred.insn);
 
 #undef CLEAR_BIT
 #undef SET_BIT_VALUE
@@ -18457,9 +19301,9 @@ now_it_add_mask (int cond)
 
 /* The IT blocks handling machinery is accessed through the these functions:
      it_fsm_pre_encode ()               from md_assemble ()
-     set_it_insn_type ()                optional, from the tencode functions
-     set_it_insn_type_last ()           ditto
-     in_it_block ()                     ditto
+     set_pred_insn_type ()             optional, from the tencode functions
+     set_pred_insn_type_last ()                ditto
+     in_pred_block ()                  ditto
      it_fsm_post_encode ()              from md_assemble ()
      force_automatic_it_block_close ()  from label handling functions
 
@@ -18469,37 +19313,38 @@ now_it_add_mask (int cond)
        on the inst.condition.
      2) During the tencode function, two things may happen:
        a) The tencode function overrides the IT insn type by
-          calling either set_it_insn_type (type) or set_it_insn_type_last ().
+          calling either set_pred_insn_type (type) or
+          set_pred_insn_type_last ().
        b) The tencode function queries the IT block state by
-          calling in_it_block () (i.e. to determine narrow/not narrow mode).
+          calling in_pred_block () (i.e. to determine narrow/not narrow mode).
 
-       Both set_it_insn_type and in_it_block run the internal FSM state
-       handling function (handle_it_state), because: a) setting the IT insn
+       Both set_pred_insn_type and in_pred_block run the internal FSM state
+       handling function (handle_pred_state), because: a) setting the IT insn
        type may incur in an invalid state (exiting the function),
        and b) querying the state requires the FSM to be updated.
        Specifically we want to avoid creating an IT block for conditional
        branches, so it_fsm_pre_encode is actually a guess and we can't
        determine whether an IT block is required until the tencode () routine
        has decided what type of instruction this actually it.
-       Because of this, if set_it_insn_type and in_it_block have to be used,
-       set_it_insn_type has to be called first.
+       Because of this, if set_pred_insn_type and in_pred_block have to be
+       used, set_pred_insn_type has to be called first.
 
-       set_it_insn_type_last () is a wrapper of set_it_insn_type (type), that
-       determines the insn IT type depending on the inst.cond code.
+       set_pred_insn_type_last () is a wrapper of set_pred_insn_type (type),
+       that determines the insn IT type depending on the inst.cond code.
        When a tencode () routine encodes an instruction that can be
        either outside an IT block, or, in the case of being inside, has to be
-       the last one, set_it_insn_type_last () will determine the proper
+       the last one, set_pred_insn_type_last () will determine the proper
        IT instruction type based on the inst.cond code. Otherwise,
-       set_it_insn_type can be called for overriding that logic or
+       set_pred_insn_type can be called for overriding that logic or
        for covering other cases.
 
-       Calling handle_it_state () may not transition the IT block state to
-       OUTSIDE_IT_BLOCK immediately, since the (current) state could be
+       Calling handle_pred_state () may not transition the IT block state to
+       OUTSIDE_PRED_BLOCK immediately, since the (current) state could be
        still queried. Instead, if the FSM determines that the state should
-       be transitioned to OUTSIDE_IT_BLOCK, a flag is marked to be closed
+       be transitioned to OUTSIDE_PRED_BLOCK, a flag is marked to be closed
        after the tencode () function: that's what it_fsm_post_encode () does.
 
-       Since in_it_block () calls the state handling function to get an
+       Since in_pred_block () calls the state handling function to get an
        updated state, an error may occur (due to invalid insns combination).
        In that case, inst.error is set.
        Therefore, inst.error has to be checked after the execution of
@@ -18507,74 +19352,150 @@ now_it_add_mask (int cond)
 
      3) Back in md_assemble(), it_fsm_post_encode () is called to commit
        any pending state change (if any) that didn't take place in
-       handle_it_state () as explained above.  */
+       handle_pred_state () as explained above.  */
 
 static void
 it_fsm_pre_encode (void)
 {
   if (inst.cond != COND_ALWAYS)
-    inst.it_insn_type = INSIDE_IT_INSN;
+    inst.pred_insn_type =  INSIDE_IT_INSN;
   else
-    inst.it_insn_type = OUTSIDE_IT_INSN;
+    inst.pred_insn_type = OUTSIDE_PRED_INSN;
 
-  now_it.state_handled = 0;
+  now_pred.state_handled = 0;
 }
 
 /* IT state FSM handling function.  */
+/* MVE instructions and non-MVE instructions are handled differently because of
+   the introduction of VPT blocks.
+   Specifications say that any non-MVE instruction inside a VPT block is
+   UNPREDICTABLE, with the exception of the BKPT instruction.  Whereas most MVE
+   instructions are deemed to be UNPREDICTABLE if inside an IT block.  For the
+   few exceptions this will be handled at their respective handler functions.
+   The error messages provided depending on the different combinations possible
+   are described in the cases below:
+   For 'most' MVE instructions:
+   1) In an IT block, with an IT code: syntax error
+   2) In an IT block, with a VPT code: error: must be in a VPT block
+   3) In an IT block, with no code: warning: UNPREDICTABLE
+   4) In a VPT block, with an IT code: syntax error
+   5) In a VPT block, with a VPT code: OK!
+   6) In a VPT block, with no code: error: missing code
+   7) Outside a pred block, with an IT code: error: syntax error
+   8) Outside a pred block, with a VPT code: error: should be in a VPT block
+   9) Outside a pred block, with no code: OK!
+   For non-MVE instructions:
+   10) In an IT block, with an IT code: OK!
+   11) In an IT block, with a VPT code: syntax error
+   12) In an IT block, with no code: error: missing code
+   13) In a VPT block, with an IT code: error: should be in an IT block
+   14) In a VPT block, with a VPT code: syntax error
+   15) In a VPT block, with no code: UNPREDICTABLE
+   16) Outside a pred block, with an IT code: error: should be in an IT block
+   17) Outside a pred block, with a VPT code: syntax error
+   18) Outside a pred block, with no code: OK!
+ */
+
 
 static int
-handle_it_state (void)
+handle_pred_state (void)
 {
-  now_it.state_handled = 1;
-  now_it.insn_cond = FALSE;
+  now_pred.state_handled = 1;
+  now_pred.insn_cond = FALSE;
 
-  switch (now_it.state)
+  switch (now_pred.state)
     {
-    case OUTSIDE_IT_BLOCK:
-      switch (inst.it_insn_type)
+    case OUTSIDE_PRED_BLOCK:
+      switch (inst.pred_insn_type)
        {
-       case OUTSIDE_IT_INSN:
+       case MVE_OUTSIDE_PRED_INSN:
+         if (inst.cond < COND_ALWAYS)
+           {
+             /* Case 7: Outside a pred block, with an IT code: error: syntax
+                error.  */
+             inst.error = BAD_SYNTAX;
+             return FAIL;
+           }
+         /* Case 9:  Outside a pred block, with no code: OK!  */
          break;
+       case OUTSIDE_PRED_INSN:
+         if (inst.cond > COND_ALWAYS)
+           {
+             /* Case 17:  Outside a pred block, with a VPT code: syntax error.
+              */
+             inst.error = BAD_SYNTAX;
+             return FAIL;
+           }
+         /* Case 18: Outside a pred block, with no code: OK!  */
+         break;
+
+       case INSIDE_VPT_INSN:
+         /* Case 8: Outside a pred block, with a VPT code: error: should be in
+            a VPT block.  */
+         inst.error = BAD_OUT_VPT;
+         return FAIL;
 
        case INSIDE_IT_INSN:
        case INSIDE_IT_LAST_INSN:
-         if (thumb_mode == 0)
+         if (inst.cond < COND_ALWAYS)
            {
-             if (unified_syntax
-                 && !(implicit_it_mode & IMPLICIT_IT_MODE_ARM))
-               as_tsktsk (_("Warning: conditional outside an IT block"\
-                            " for Thumb."));
-           }
-         else
-           {
-             if ((implicit_it_mode & IMPLICIT_IT_MODE_THUMB)
-                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
+             /* Case 16: Outside a pred block, with an IT code: error: should
+                be in an IT block.  */
+             if (thumb_mode == 0)
                {
-                 /* Automatically generate the IT instruction.  */
-                 new_automatic_it_block (inst.cond);
-                 if (inst.it_insn_type == INSIDE_IT_LAST_INSN)
-                   close_automatic_it_block ();
+                 if (unified_syntax
+                     && !(implicit_it_mode & IMPLICIT_IT_MODE_ARM))
+                   as_tsktsk (_("Warning: conditional outside an IT block"\
+                                " for Thumb."));
                }
              else
                {
-                 inst.error = BAD_OUT_IT;
-                 return FAIL;
+                 if ((implicit_it_mode & IMPLICIT_IT_MODE_THUMB)
+                     && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
+                   {
+                     /* Automatically generate the IT instruction.  */
+                     new_automatic_it_block (inst.cond);
+                     if (inst.pred_insn_type == INSIDE_IT_LAST_INSN)
+                       close_automatic_it_block ();
+                   }
+                 else
+                   {
+                     inst.error = BAD_OUT_IT;
+                     return FAIL;
+                   }
                }
+             break;
            }
-         break;
-
+         else if (inst.cond > COND_ALWAYS)
+           {
+             /* Case 17: Outside a pred block, with a VPT code: syntax error.
+              */
+             inst.error = BAD_SYNTAX;
+             return FAIL;
+           }
+         else
+           gas_assert (0);
        case IF_INSIDE_IT_LAST_INSN:
        case NEUTRAL_IT_INSN:
          break;
 
+       case VPT_INSN:
+         if (inst.cond != COND_ALWAYS)
+           first_error (BAD_SYNTAX);
+         now_pred.state = MANUAL_PRED_BLOCK;
+         now_pred.block_length = 0;
+         now_pred.type = VECTOR_PRED;
+         now_pred.cc = 0;
+         break;
        case IT_INSN:
-         now_it.state = MANUAL_IT_BLOCK;
-         now_it.block_length = 0;
+         now_pred.state = MANUAL_PRED_BLOCK;
+         now_pred.block_length = 0;
+         now_pred.type = SCALAR_PRED;
          break;
        }
       break;
 
-    case AUTOMATIC_IT_BLOCK:
+    case AUTOMATIC_PRED_BLOCK:
       /* Three things may happen now:
         a) We should increment current it block size;
         b) We should close current it block (closing insn or 4 insns);
@@ -18582,82 +19503,211 @@ handle_it_state (void)
         to incompatible conditions or
         4 insns-length block reached).  */
 
-      switch (inst.it_insn_type)
+      switch (inst.pred_insn_type)
        {
-       case OUTSIDE_IT_INSN:
+       case INSIDE_VPT_INSN:
+       case VPT_INSN:
+       case MVE_OUTSIDE_PRED_INSN:
+         gas_assert (0);
+       case OUTSIDE_PRED_INSN:
          /* The closure of the block shall happen immediately,
-            so any in_it_block () call reports the block as closed.  */
+            so any in_pred_block () call reports the block as closed.  */
          force_automatic_it_block_close ();
          break;
 
        case INSIDE_IT_INSN:
        case INSIDE_IT_LAST_INSN:
        case IF_INSIDE_IT_LAST_INSN:
-         now_it.block_length++;
+         now_pred.block_length++;
 
-         if (now_it.block_length > 4
-             || !now_it_compatible (inst.cond))
+         if (now_pred.block_length > 4
+             || !now_pred_compatible (inst.cond))
            {
              force_automatic_it_block_close ();
-             if (inst.it_insn_type != IF_INSIDE_IT_LAST_INSN)
+             if (inst.pred_insn_type != IF_INSIDE_IT_LAST_INSN)
                new_automatic_it_block (inst.cond);
            }
          else
            {
-             now_it.insn_cond = TRUE;
-             now_it_add_mask (inst.cond);
+             now_pred.insn_cond = TRUE;
+             now_pred_add_mask (inst.cond);
            }
 
-         if (now_it.state == AUTOMATIC_IT_BLOCK
-             && (inst.it_insn_type == INSIDE_IT_LAST_INSN
-                 || inst.it_insn_type == IF_INSIDE_IT_LAST_INSN))
+         if (now_pred.state == AUTOMATIC_PRED_BLOCK
+             && (inst.pred_insn_type == INSIDE_IT_LAST_INSN
+                 || inst.pred_insn_type == IF_INSIDE_IT_LAST_INSN))
            close_automatic_it_block ();
          break;
 
        case NEUTRAL_IT_INSN:
-         now_it.block_length++;
-         now_it.insn_cond = TRUE;
+         now_pred.block_length++;
+         now_pred.insn_cond = TRUE;
 
-         if (now_it.block_length > 4)
+         if (now_pred.block_length > 4)
            force_automatic_it_block_close ();
          else
-           now_it_add_mask (now_it.cc & 1);
+           now_pred_add_mask (now_pred.cc & 1);
          break;
 
        case IT_INSN:
          close_automatic_it_block ();
-         now_it.state = MANUAL_IT_BLOCK;
+         now_pred.state = MANUAL_PRED_BLOCK;
          break;
        }
       break;
 
-    case MANUAL_IT_BLOCK:
+    case MANUAL_PRED_BLOCK:
       {
-       /* Check conditional suffixes.  */
-       const int cond = now_it.cc ^ ((now_it.mask >> 4) & 1) ^ 1;
-       int is_last;
-       now_it.mask <<= 1;
-       now_it.mask &= 0x1f;
-       is_last = (now_it.mask == 0x10);
-       now_it.insn_cond = TRUE;
-
-       switch (inst.it_insn_type)
+       int cond, is_last;
+       if (now_pred.type == SCALAR_PRED)
          {
-         case OUTSIDE_IT_INSN:
-           inst.error = BAD_NOT_IT;
-           return FAIL;
+           /* Check conditional suffixes.  */
+           cond = now_pred.cc ^ ((now_pred.mask >> 4) & 1) ^ 1;
+           now_pred.mask <<= 1;
+           now_pred.mask &= 0x1f;
+           is_last = (now_pred.mask == 0x10);
+         }
+       else
+         {
+           now_pred.cc ^= (now_pred.mask >> 4);
+           cond = now_pred.cc + 0xf;
+           now_pred.mask <<= 1;
+           now_pred.mask &= 0x1f;
+           is_last = now_pred.mask == 0x10;
+         }
+       now_pred.insn_cond = TRUE;
 
+       switch (inst.pred_insn_type)
+         {
+         case OUTSIDE_PRED_INSN:
+           if (now_pred.type == SCALAR_PRED)
+             {
+               if (inst.cond == COND_ALWAYS)
+                 {
+                   /* Case 12: In an IT block, with no code: error: missing
+                      code.  */
+                   inst.error = BAD_NOT_IT;
+                   return FAIL;
+                 }
+               else if (inst.cond > COND_ALWAYS)
+                 {
+                   /* Case 11: In an IT block, with a VPT code: syntax error.
+                    */
+                   inst.error = BAD_SYNTAX;
+                   return FAIL;
+                 }
+               else if (thumb_mode)
+                 {
+                   /* This is for some special cases where a non-MVE
+                      instruction is not allowed in an IT block, such as cbz,
+                      but are put into one with a condition code.
+                      You could argue this should be a syntax error, but we
+                      gave the 'not allowed in IT block' diagnostic in the
+                      past so we will keep doing so.  */
+                   inst.error = BAD_NOT_IT;
+                   return FAIL;
+                 }
+               break;
+             }
+           else
+             {
+               /* Case 15: In a VPT block, with no code: UNPREDICTABLE.  */
+               as_tsktsk (MVE_NOT_VPT);
+               return SUCCESS;
+             }
+         case MVE_OUTSIDE_PRED_INSN:
+           if (now_pred.type == SCALAR_PRED)
+             {
+               if (inst.cond == COND_ALWAYS)
+                 {
+                   /* Case 3: In an IT block, with no code: warning:
+                      UNPREDICTABLE.  */
+                   as_tsktsk (MVE_NOT_IT);
+                   return SUCCESS;
+                 }
+               else if (inst.cond < COND_ALWAYS)
+                 {
+                   /* Case 1: In an IT block, with an IT code: syntax error.
+                    */
+                   inst.error = BAD_SYNTAX;
+                   return FAIL;
+                 }
+               else
+                 gas_assert (0);
+             }
+           else
+             {
+               if (inst.cond < COND_ALWAYS)
+                 {
+                   /* Case 4: In a VPT block, with an IT code: syntax error.
+                    */
+                   inst.error = BAD_SYNTAX;
+                   return FAIL;
+                 }
+               else if (inst.cond == COND_ALWAYS)
+                 {
+                   /* Case 6: In a VPT block, with no code: error: missing
+                      code.  */
+                   inst.error = BAD_NOT_VPT;
+                   return FAIL;
+                 }
+               else
+                 {
+                   gas_assert (0);
+                 }
+             }
          case INSIDE_IT_INSN:
-           if (cond != inst.cond)
+           if (inst.cond > COND_ALWAYS)
              {
-               inst.error = BAD_IT_COND;
+               /* Case 11: In an IT block, with a VPT code: syntax error.  */
+               /* Case 14: In a VPT block, with a VPT code: syntax error.  */
+               inst.error = BAD_SYNTAX;
+               return FAIL;
+             }
+           else if (now_pred.type == SCALAR_PRED)
+             {
+               /* Case 10: In an IT block, with an IT code: OK!  */
+               if (cond != inst.cond)
+                 {
+                   inst.error = now_pred.type == SCALAR_PRED ? BAD_IT_COND :
+                     BAD_VPT_COND;
+                   return FAIL;
+                 }
+             }
+           else
+             {
+               /* Case 13: In a VPT block, with an IT code: error: should be
+                  in an IT block.  */
+               inst.error = BAD_OUT_IT;
                return FAIL;
              }
            break;
 
+         case INSIDE_VPT_INSN:
+           if (now_pred.type == SCALAR_PRED)
+             {
+               /* Case 2: In an IT block, with a VPT code: error: must be in a
+                  VPT block.  */
+               inst.error = BAD_OUT_VPT;
+               return FAIL;
+             }
+           /* Case 5:  In a VPT block, with a VPT code: OK!  */
+           else if (cond != inst.cond)
+             {
+               inst.error = BAD_VPT_COND;
+               return FAIL;
+             }
+           break;
          case INSIDE_IT_LAST_INSN:
          case IF_INSIDE_IT_LAST_INSN:
-           if (cond != inst.cond)
+           if (now_pred.type == VECTOR_PRED || inst.cond > COND_ALWAYS)
+             {
+               /* Case 4: In a VPT block, with an IT code: syntax error.  */
+               /* Case 11: In an IT block, with a VPT code: syntax error.  */
+               inst.error = BAD_SYNTAX;
+               return FAIL;
+             }
+           else if (cond != inst.cond)
              {
                inst.error = BAD_IT_COND;
                return FAIL;
@@ -18670,14 +19720,37 @@ handle_it_state (void)
            break;
 
          case NEUTRAL_IT_INSN:
-           /* The BKPT instruction is unconditional even in an IT block.  */
+           /* The BKPT instruction is unconditional even in a IT or VPT
+              block.  */
            break;
 
          case IT_INSN:
-           inst.error = BAD_IT_IT;
-           return FAIL;
+           if (now_pred.type == SCALAR_PRED)
+             {
+               inst.error = BAD_IT_IT;
+               return FAIL;
+             }
+           /* fall through.  */
+         case VPT_INSN:
+           if (inst.cond == COND_ALWAYS)
+             {
+               /* Executing a VPT/VPST instruction inside an IT block or a
+                  VPT/VPST/IT instruction inside a VPT block is UNPREDICTABLE.
+                */
+               if (now_pred.type == SCALAR_PRED)
+                 as_tsktsk (MVE_NOT_IT);
+               else
+                 as_tsktsk (MVE_NOT_VPT);
+               return SUCCESS;
+             }
+           else
+             {
+               /* VPT/VPST do not accept condition codes.  */
+               inst.error = BAD_SYNTAX;
+               return FAIL;
+             }
          }
-      }
+       }
       break;
     }
 
@@ -18711,11 +19784,11 @@ it_fsm_post_encode (void)
 {
   int is_last;
 
-  if (!now_it.state_handled)
-    handle_it_state ();
+  if (!now_pred.state_handled)
+    handle_pred_state ();
 
-  if (now_it.insn_cond
-      && !now_it.warn_deprecated
+  if (now_pred.insn_cond
+      && !now_pred.warn_deprecated
       && warn_on_deprecated
       && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)
       && !ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m))
@@ -18724,7 +19797,7 @@ it_fsm_post_encode (void)
        {
          as_tsktsk (_("IT blocks containing 32-bit Thumb instructions are "
                     "performance deprecated in ARMv8-A and ARMv8-R"));
-         now_it.warn_deprecated = TRUE;
+         now_pred.warn_deprecated = TRUE;
        }
       else
        {
@@ -18738,7 +19811,7 @@ it_fsm_post_encode (void)
                               "instructions of the following class are "
                               "performance deprecated in ARMv8-A and "
                               "ARMv8-R: %s"), p->description);
-                 now_it.warn_deprecated = TRUE;
+                 now_pred.warn_deprecated = TRUE;
                  break;
                }
 
@@ -18746,41 +19819,41 @@ it_fsm_post_encode (void)
            }
        }
 
-      if (now_it.block_length > 1)
+      if (now_pred.block_length > 1)
        {
          as_tsktsk (_("IT blocks containing more than one conditional "
                     "instruction are performance deprecated in ARMv8-A and "
                     "ARMv8-R"));
-         now_it.warn_deprecated = TRUE;
+         now_pred.warn_deprecated = TRUE;
        }
     }
 
-  is_last = (now_it.mask == 0x10);
-  if (is_last)
-    {
-      now_it.state = OUTSIDE_IT_BLOCK;
-      now_it.mask = 0;
-    }
+    is_last = (now_pred.mask == 0x10);
+    if (is_last)
+      {
+       now_pred.state = OUTSIDE_PRED_BLOCK;
+       now_pred.mask = 0;
+      }
 }
 
 static void
 force_automatic_it_block_close (void)
 {
-  if (now_it.state == AUTOMATIC_IT_BLOCK)
+  if (now_pred.state == AUTOMATIC_PRED_BLOCK)
     {
       close_automatic_it_block ();
-      now_it.state = OUTSIDE_IT_BLOCK;
-      now_it.mask = 0;
+      now_pred.state = OUTSIDE_PRED_BLOCK;
+      now_pred.mask = 0;
     }
 }
 
 static int
-in_it_block (void)
+in_pred_block (void)
 {
-  if (!now_it.state_handled)
-    handle_it_state ();
+  if (!now_pred.state_handled)
+    handle_pred_state ();
 
-  return now_it.state != OUTSIDE_IT_BLOCK;
+  return now_pred.state != OUTSIDE_PRED_BLOCK;
 }
 
 /* Whether OPCODE only has T32 encoding.  Since this function is only used by
@@ -18933,7 +20006,7 @@ md_assemble (char *str)
 
       if (!parse_operands (p, opcode->operands, /*thumb=*/TRUE))
        {
-         /* Prepare the it_insn_type for those encodings that don't set
+         /* Prepare the pred_insn_type for those encodings that don't set
             it.  */
          it_fsm_pre_encode ();
 
@@ -19036,21 +20109,30 @@ md_assemble (char *str)
 }
 
 static void
-check_it_blocks_finished (void)
+check_pred_blocks_finished (void)
 {
 #ifdef OBJ_ELF
   asection *sect;
 
   for (sect = stdoutput->sections; sect != NULL; sect = sect->next)
-    if (seg_info (sect)->tc_segment_info_data.current_it.state
-       == MANUAL_IT_BLOCK)
+    if (seg_info (sect)->tc_segment_info_data.current_pred.state
+       == MANUAL_PRED_BLOCK)
       {
-       as_warn (_("section '%s' finished with an open IT block."),
-                sect->name);
+       if (now_pred.type == SCALAR_PRED)
+         as_warn (_("section '%s' finished with an open IT block."),
+                  sect->name);
+       else
+         as_warn (_("section '%s' finished with an open VPT/VPST block."),
+                  sect->name);
       }
 #else
-  if (now_it.state == MANUAL_IT_BLOCK)
-    as_warn (_("file finished with an open IT block."));
+  if (now_pred.state == MANUAL_PRED_BLOCK)
+    {
+      if (now_pred.type == SCALAR_PRED)
+       as_warn (_("file finished with an open IT block."));
+      else
+       as_warn (_("file finished with an open VPT/VPST block."));
+    }
 #endif
 }
 
@@ -19452,7 +20534,7 @@ static struct reloc_entry reloc_names[] =
 };
 #endif
 
-/* Table of all conditional affixes.  0xF is not defined as a condition code.  */
+/* Table of all conditional affixes.  */
 static const struct asm_cond conds[] =
 {
   {"eq", 0x0},
@@ -19471,6 +20553,11 @@ static const struct asm_cond conds[] =
   {"le", 0xd},
   {"al", 0xe}
 };
+static const struct asm_cond vconds[] =
+{
+    {"t", 0xf},
+    {"e", 0x10}
+};
 
 #define UL_BARRIER(L,U,CODE,FEAT) \
   { L, CODE, ARM_FEATURE_CORE_LOW (FEAT) }, \
@@ -19529,7 +20616,7 @@ static struct asm_barrier_opt barrier_opt_names[] =
 /* The normal sort of mnemonic; has a Thumb variant; takes a conditional suffix.  */
 #define TxCE(mnem, op, top, nops, ops, ae, te) \
   { mnem, OPS##nops ops, OT_csuffix, 0x##op, top, ARM_VARIANT, \
-    THUMB_VARIANT, do_##ae, do_##te }
+    THUMB_VARIANT, do_##ae, do_##te, 0 }
 
 /* Two variants of the above - TCE for a numeric Thumb opcode, tCE for
    a T_MNEM_xyz enumerator.  */
@@ -19542,10 +20629,10 @@ static struct asm_barrier_opt barrier_opt_names[] =
    infix after the third character.  */
 #define TxC3(mnem, op, top, nops, ops, ae, te) \
   { mnem, OPS##nops ops, OT_cinfix3, 0x##op, top, ARM_VARIANT, \
-    THUMB_VARIANT, do_##ae, do_##te }
+    THUMB_VARIANT, do_##ae, do_##te, 0 }
 #define TxC3w(mnem, op, top, nops, ops, ae, te) \
   { mnem, OPS##nops ops, OT_cinfix3_deprecated, 0x##op, top, ARM_VARIANT, \
-    THUMB_VARIANT, do_##ae, do_##te }
+    THUMB_VARIANT, do_##ae, do_##te, 0 }
 #define TC3(mnem, aop, top, nops, ops, ae, te) \
       TxC3 (mnem, aop, 0x##top, nops, ops, ae, te)
 #define TC3w(mnem, aop, top, nops, ops, ae, te) \
@@ -19560,69 +20647,74 @@ static struct asm_barrier_opt barrier_opt_names[] =
    conditionally, so this is checked separately.  */
 #define TUE(mnem, op, top, nops, ops, ae, te)                          \
   { mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
-    THUMB_VARIANT, do_##ae, do_##te }
+    THUMB_VARIANT, do_##ae, do_##te, 0 }
 
 /* Same as TUE but the encoding function for ARM and Thumb modes is the same.
    Used by mnemonics that have very minimal differences in the encoding for
    ARM and Thumb variants and can be handled in a common function.  */
 #define TUEc(mnem, op, top, nops, ops, en) \
   { mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
-    THUMB_VARIANT, do_##en, do_##en }
+    THUMB_VARIANT, do_##en, do_##en, 0 }
 
 /* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
    condition code field.  */
 #define TUF(mnem, op, top, nops, ops, ae, te)                          \
   { mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##top, ARM_VARIANT, \
-    THUMB_VARIANT, do_##ae, do_##te }
+    THUMB_VARIANT, do_##ae, do_##te, 0 }
 
 /* ARM-only variants of all the above.  */
 #define CE(mnem,  op, nops, ops, ae)   \
-  { mnem, OPS##nops ops, OT_csuffix, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
+  { mnem, OPS##nops ops, OT_csuffix, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL, 0 }
 
 #define C3(mnem, op, nops, ops, ae)    \
-  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
+  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL, 0 }
 
 /* Thumb-only variants of TCE and TUE.  */
 #define ToC(mnem, top, nops, ops, te) \
   { mnem, OPS##nops ops, OT_csuffix, 0x0, 0x##top, 0, THUMB_VARIANT, NULL, \
-    do_##te }
+    do_##te, 0 }
 
 #define ToU(mnem, top, nops, ops, te) \
   { mnem, OPS##nops ops, OT_unconditional, 0x0, 0x##top, 0, THUMB_VARIANT, \
-    NULL, do_##te }
+    NULL, do_##te, 0 }
 
 /* T_MNEM_xyz enumerator variants of ToC.  */
 #define toC(mnem, top, nops, ops, te) \
   { mnem, OPS##nops ops, OT_csuffix, 0x0, T_MNEM##top, 0, THUMB_VARIANT, NULL, \
-    do_##te }
+    do_##te, 0 }
+
+/* T_MNEM_xyz enumerator variants of ToU.  */
+#define toU(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x0, T_MNEM##top, 0, THUMB_VARIANT, \
+    NULL, do_##te, 0 }
 
 /* Legacy mnemonics that always have conditional infix after the third
    character.  */
 #define CL(mnem, op, nops, ops, ae)    \
   { mnem, OPS##nops ops, OT_cinfix3_legacy, \
-    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
+    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL, 0 }
 
 /* Coprocessor instructions.  Isomorphic between Arm and Thumb-2.  */
 #define cCE(mnem,  op, nops, ops, ae)  \
-  { mnem, OPS##nops ops, OT_csuffix, 0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
+  { mnem, OPS##nops ops, OT_csuffix, 0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae, 0 }
 
 /* Legacy coprocessor instructions where conditional infix and conditional
    suffix are ambiguous.  For consistency this includes all FPA instructions,
    not just the potentially ambiguous ones.  */
 #define cCL(mnem, op, nops, ops, ae)   \
   { mnem, OPS##nops ops, OT_cinfix3_legacy, \
-    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
+    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae, 0 }
 
 /* Coprocessor, takes either a suffix or a position-3 infix
    (for an FPA corner case). */
 #define C3E(mnem, op, nops, ops, ae) \
   { mnem, OPS##nops ops, OT_csuf_or_in3, \
-    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
+    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae, 0 }
 
 #define xCM_(m1, m2, m3, op, nops, ops, ae)    \
   { m1 #m2 m3, OPS##nops ops, \
     sizeof (#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof (m1) - 1, \
-    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
+    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL, 0 }
 
 #define CM(m1, m2, op, nops, ops, ae)  \
   xCM_ (m1,   , m2, op, nops, ops, ae),        \
@@ -19646,47 +20738,83 @@ static struct asm_barrier_opt barrier_opt_names[] =
   xCM_ (m1, al, m2, op, nops, ops, ae)
 
 #define UE(mnem, op, nops, ops, ae)    \
-  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
+  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL, 0 }
 
 #define UF(mnem, op, nops, ops, ae)    \
-  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
+  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL, 0 }
 
 /* Neon data-processing. ARM versions are unconditional with cond=0xf.
    The Thumb and ARM variants are mostly the same (bits 0-23 and 24/28), so we
    use the same encoding function for each.  */
 #define NUF(mnem, op, nops, ops, enc)                                  \
   { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##op,           \
-    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
+    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc, 0 }
 
 /* Neon data processing, version which indirects through neon_enc_tab for
    the various overloaded versions of opcodes.  */
 #define nUF(mnem, op, nops, ops, enc)                                  \
   { #mnem, OPS##nops ops, OT_unconditionalF, N_MNEM##op, N_MNEM##op,   \
-    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
+    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc, 0 }
 
 /* Neon insn with conditional suffix for the ARM version, non-overloaded
    version.  */
-#define NCE_tag(mnem, op, nops, ops, enc, tag)                         \
+#define NCE_tag(mnem, op, nops, ops, enc, tag, mve_p)                          \
   { #mnem, OPS##nops ops, tag, 0x##op, 0x##op, ARM_VARIANT,            \
-    THUMB_VARIANT, do_##enc, do_##enc }
+    THUMB_VARIANT, do_##enc, do_##enc, mve_p }
 
 #define NCE(mnem, op, nops, ops, enc)                                  \
-   NCE_tag (mnem, op, nops, ops, enc, OT_csuffix)
+   NCE_tag (mnem, op, nops, ops, enc, OT_csuffix, 0)
 
 #define NCEF(mnem, op, nops, ops, enc)                                 \
-    NCE_tag (mnem, op, nops, ops, enc, OT_csuffixF)
+    NCE_tag (mnem, op, nops, ops, enc, OT_csuffixF, 0)
 
 /* Neon insn with conditional suffix for the ARM version, overloaded types.  */
-#define nCE_tag(mnem, op, nops, ops, enc, tag)                         \
+#define nCE_tag(mnem, op, nops, ops, enc, tag, mve_p)                          \
   { #mnem, OPS##nops ops, tag, N_MNEM##op, N_MNEM##op,         \
-    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
+    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc, mve_p }
 
 #define nCE(mnem, op, nops, ops, enc)                                  \
-   nCE_tag (mnem, op, nops, ops, enc, OT_csuffix)
+   nCE_tag (mnem, op, nops, ops, enc, OT_csuffix, 0)
 
 #define nCEF(mnem, op, nops, ops, enc)                                 \
-    nCE_tag (mnem, op, nops, ops, enc, OT_csuffixF)
+    nCE_tag (mnem, op, nops, ops, enc, OT_csuffixF, 0)
+
+/*   */
+#define mCEF(mnem, op, nops, ops, enc)                         \
+  { #mnem, OPS##nops ops, OT_csuffixF, M_MNEM##op, M_MNEM##op, \
+    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc, 1 }
+
 
+/* nCEF but for MVE predicated instructions.  */
+#define mnCEF(mnem, op, nops, ops, enc)                                        \
+    nCE_tag (mnem, op, nops, ops, enc, OT_csuffixF, 1)
+
+/* nCE but for MVE predicated instructions.  */
+#define mnCE(mnem, op, nops, ops, enc)                                 \
+   nCE_tag (mnem, op, nops, ops, enc, OT_csuffix, 1)
+
+/* NUF but for potentially MVE predicated instructions.  */
+#define MNUF(mnem, op, nops, ops, enc)                                 \
+  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##op,           \
+    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc, 1 }
+
+/* nUF but for potentially MVE predicated instructions.  */
+#define mnUF(mnem, op, nops, ops, enc)                                 \
+  { #mnem, OPS##nops ops, OT_unconditionalF, N_MNEM##op, N_MNEM##op,   \
+    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc, 1 }
+
+/* ToC but for potentially MVE predicated instructions.  */
+#define mToC(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_csuffix, 0x0, 0x##top, 0, THUMB_VARIANT, NULL, \
+    do_##te, 1 }
+
+/* NCE but for MVE predicated instructions.  */
+#define MNCE(mnem, op, nops, ops, enc)                                 \
+   NCE_tag (mnem, op, nops, ops, enc, OT_csuffix, 1)
+
+/* NCEF but for MVE predicated instructions.  */
+#define MNCEF(mnem, op, nops, ops, enc)                                        \
+    NCE_tag (mnem, op, nops, ops, enc, OT_csuffixF, 1)
 #define do_0 0
 
 static const struct asm_opcode insns[] =
@@ -20990,20 +22118,12 @@ static const struct asm_opcode insns[] =
  nCEF(vmla,     _vmla,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
  nCEF(vmls,     _vmls,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
 
- nCEF(vadd,     _vadd,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
- nCEF(vsub,     _vsub,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
-
- NCEF(vabs,     1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
- NCEF(vneg,     1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
-
  NCE(vldm,      c900b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
  NCE(vldmia,    c900b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
  NCE(vldmdb,    d100b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
  NCE(vstm,      c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
  NCE(vstmia,    c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
  NCE(vstmdb,    d000b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
- NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
- NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
 
  nCEF(vcvt,     _vcvt,   3, (RNSDQ, RNSDQ, oI32z), neon_cvt),
  nCEF(vcvtr,    _vcvt,   2, (RNSDQ, RNSDQ), neon_cvtr),
@@ -21015,6 +22135,15 @@ static const struct asm_opcode insns[] =
  NCE(vmov,      0,       1, (VMOV), neon_mov),
  NCE(vmovq,     0,       1, (VMOV), neon_mov),
 
+#undef  THUMB_VARIANT
+/* Could be either VLDR/VSTR or VLDR/VSTR (system register) which are guarded
+   by different feature bits.  Since we are setting the Thumb guard, we can
+   require Thumb-1 which makes it a nop guard and set the right feature bit in
+   do_vldr_vstr ().  */
+#define THUMB_VARIANT  & arm_ext_v4t
+ NCE(vldr,      d100b00, 2, (VLDR, ADDRGLDC), vldr_vstr),
+ NCE(vstr,      d000b00, 2, (VLDR, ADDRGLDC), vldr_vstr),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT    & arm_ext_fp16
 #undef  THUMB_VARIANT
@@ -21078,7 +22207,6 @@ static const struct asm_opcode insns[] =
  NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
  NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
   /* Int and float variants, types S8 S16 S32 U8 U16 U32 F16 F32.  */
- nUF(vabd,      _vabd,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
  nUF(vabdq,     _vabd,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
  nUF(vmax,      _vmax,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
  nUF(vmaxq,     _vmax,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
@@ -21179,9 +22307,6 @@ static const struct asm_opcode insns[] =
   /* Data processing, three registers of different lengths.  */
   /* Dyadic, long insns. Types S8 S16 S32 U8 U16 U32.  */
  NUF(vabal,     0800500, 3, (RNQ, RND, RND),  neon_abal),
- NUF(vabdl,     0800700, 3, (RNQ, RND, RND),  neon_dyadic_long),
- NUF(vaddl,     0800000, 3, (RNQ, RND, RND),  neon_dyadic_long),
- NUF(vsubl,     0800200, 3, (RNQ, RND, RND),  neon_dyadic_long),
   /* If not scalar, fall back to neon_dyadic_long.
      Vector types as above, scalar types S16 S32 U16 U32.  */
  nUF(vmlal,     _vmlal,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
@@ -21686,8 +22811,68 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT & arm_ext_v8_1m_main
  toC("bf",     _bf,    2, (EXPs, EXPs),             t_branch_future),
+ toU("bfcsel", _bfcsel,        4, (EXPs, EXPs, EXPs, COND), t_branch_future),
  toC("bfx",    _bfx,   2, (EXPs, RRnpcsp),          t_branch_future),
+ toC("bfl",    _bfl,   2, (EXPs, EXPs),             t_branch_future),
  toC("bflx",   _bflx,  2, (EXPs, RRnpcsp),          t_branch_future),
+
+ toU("dls", _dls, 2, (LR, RRnpcsp),     t_loloop),
+ toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
+ toU("le",  _le,  2, (oLR, EXP),        t_loloop),
+
+ ToC("clrm",   e89f0000, 1, (CLRMLST),  t_clrm),
+ ToC("vscclrm",        ec9f0a00, 1, (VRSDVLST), t_vscclrm),
+
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & mve_ext
+ ToC("vpst",   fe710f4d, 0, (), mve_vpt),
+ ToC("vpstt",  fe318f4d, 0, (), mve_vpt),
+ ToC("vpste",  fe718f4d, 0, (), mve_vpt),
+ ToC("vpsttt", fe314f4d, 0, (), mve_vpt),
+ ToC("vpstte", fe31cf4d, 0, (), mve_vpt),
+ ToC("vpstet", fe71cf4d, 0, (), mve_vpt),
+ ToC("vpstee", fe714f4d, 0, (), mve_vpt),
+ ToC("vpstttt",        fe312f4d, 0, (), mve_vpt),
+ ToC("vpsttte", fe316f4d, 0, (), mve_vpt),
+ ToC("vpsttet",        fe31ef4d, 0, (), mve_vpt),
+ ToC("vpsttee",        fe31af4d, 0, (), mve_vpt),
+ ToC("vpstett",        fe71af4d, 0, (), mve_vpt),
+ ToC("vpstete",        fe71ef4d, 0, (), mve_vpt),
+ ToC("vpsteet",        fe716f4d, 0, (), mve_vpt),
+ ToC("vpsteee",        fe712f4d, 0, (), mve_vpt),
+
+ /* MVE and MVE FP only.  */
+ mCEF(vmullb,  _vmullb,    3, (RMQ, RMQ, RMQ),                   mve_vmull),
+ mCEF(vabav,   _vabav,     3, (RRnpcsp, RMQ, RMQ),               mve_vabav),
+ mCEF(vmladav,   _vmladav,     3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmladava,          _vmladava,    3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmladavx,          _vmladavx,    3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmladavax,  _vmladavax,  3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmlav,     _vmladav,     3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmlava,    _vmladava,    3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmlsdav,   _vmlsdav,     3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmlsdava,          _vmlsdava,    3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmlsdavx,          _vmlsdavx,    3, (RRe, RMQ, RMQ),             mve_vmladav),
+ mCEF(vmlsdavax,  _vmlsdavax,  3, (RRe, RMQ, RMQ),             mve_vmladav),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & fpu_vfp_ext_v1xd
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
+
+ mCEF(vmullt, _vmullt, 3, (RNSDQMQ, oRNSDQMQ, RNSDQ_RNSC_MQ),  mve_vmull),
+ mnCEF(vadd,  _vadd,   3, (RNSDQMQ, oRNSDQMQ, RNSDQMQR),       neon_addsub_if_i),
+ mnCEF(vsub,  _vsub,   3, (RNSDQMQ, oRNSDQMQ, RNSDQMQR),       neon_addsub_if_i),
+
+ MNCEF(vabs,  1b10300, 2, (RNSDQMQ, RNSDQMQ),  neon_abs_neg),
+ MNCEF(vneg,  1b10380, 2, (RNSDQMQ, RNSDQMQ),  neon_abs_neg),
+
+#undef ARM_VARIANT
+#define ARM_VARIANT & fpu_neon_ext_v1
+ mnUF(vabd,      _vabd,    3, (RNDQMQ, oRNDQMQ, RNDQMQ), neon_dyadic_if_su),
+ mnUF(vabdl,     _vabdl,         3, (RNQMQ, RNDMQ, RNDMQ),   neon_dyadic_long),
+ mnUF(vaddl,     _vaddl,         3, (RNQMQ, RNDMQ, RNDMQR),  neon_dyadic_long),
+ mnUF(vsubl,     _vsubl,         3, (RNQMQ, RNDMQ, RNDMQR),  neon_dyadic_long),
 };
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
@@ -21720,6 +22905,7 @@ static const struct asm_opcode insns[] =
 #undef ToC
 #undef toC
 #undef ToU
+#undef toU
 \f
 /* MD interface: bits in the object file.  */
 
@@ -22923,7 +24109,11 @@ md_pcrel_from_section (fixS * fixP, segT seg)
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH20:
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
     case BFD_RELOC_ARM_THUMB_BF17:
+    case BFD_RELOC_ARM_THUMB_BF19:
+    case BFD_RELOC_ARM_THUMB_BF13:
+    case BFD_RELOC_ARM_THUMB_LOOP12:
       return base + 4;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
@@ -23039,7 +24229,7 @@ arm_tc_equal_in_insn (int c ATTRIBUTE_UNUSED, char * name)
            already_warned = hash_new ();
          /* Only warn about the symbol once.  To keep the code
             simple we let hash_insert do the lookup for us.  */
-         if (hash_insert (already_warned, name, NULL) == NULL)
+         if (hash_insert (already_warned, nbuf, NULL) == NULL)
            as_warn (_("[-mwarn-syms]: Assignment makes a symbol match an ARM instruction: %s"), name);
        }
       else
@@ -24252,6 +25442,7 @@ md_apply_fix (fixS *    fixP,
 
     case BFD_RELOC_ARM_CP_OFF_IMM:
     case BFD_RELOC_ARM_T32_CP_OFF_IMM:
+    case BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM:
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM)
        newval = md_chars_to_number (buf, INSN_SIZE);
       else
@@ -24265,6 +25456,12 @@ md_apply_fix (fixS *   fixP,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("co-processor offset out of range"));
        }
+      else if ((newval & 0xfe001f80) == 0xec000f80)
+       {
+         if (value < -511 || value > 512 || (value & 3))
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("co-processor offset out of range"));
+       }
       else if (value < -1023 || value > 1023 || (value & 3))
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("co-processor offset out of range"));
@@ -24278,10 +25475,18 @@ md_apply_fix (fixS *  fixP,
       else
        newval = get_thumb32_insn (buf);
       if (value == 0)
-       newval &= 0xffffff00;
+       {
+         if (fixP->fx_r_type == BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM)
+           newval &= 0xffffff80;
+         else
+           newval &= 0xffffff00;
+       }
       else
        {
-         newval &= 0xff7fff00;
+         if (fixP->fx_r_type == BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM)
+           newval &= 0xff7fff80;
+         else
+           newval &= 0xff7fff00;
          if ((newval & 0x0f200f00) == 0x0d000900)
            {
              /* This is a fp16 vstr/vldr.
@@ -24821,6 +26026,39 @@ md_apply_fix (fixS *   fixP,
        }
       break;
 
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         fixP->fx_done = 0;
+       }
+      if ((value & ~0x7f) && ((value & ~0x3f) != ~0x3f))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         newval  = md_chars_to_number (buf, THUMB_SIZE);
+
+         addressT boff = ((newval & 0x0780) >> 7) << 1;
+         addressT diff = value - boff;
+
+         if (diff == 4)
+           {
+             newval |= 1 << 1; /* T bit.  */
+           }
+         else if (diff != 2)
+           {
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           _("out of range label-relative fixup value"));
+           }
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
+      break;
+
     case BFD_RELOC_ARM_THUMB_BF17:
       if (fixP->fx_addsy
          && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
@@ -24854,6 +26092,105 @@ md_apply_fix (fixS *  fixP,
        }
       break;
 
+    case BFD_RELOC_ARM_THUMB_BF19:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 19 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      if (v8_1_branch_value_check (value, 19, TRUE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT immA, immB, immC;
+
+         immA = (value & 0x0007f000) >> 12;
+         immB = (value & 0x00000ffc) >> 2;
+         immC = (value & 0x00000002) >> 1;
+
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= immA;
+         newval2 |= (immC << 11) | (immB << 1);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_THUMB_BF13:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 13 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      if (v8_1_branch_value_check (value, 13, TRUE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT immA, immB, immC;
+
+         immA = (value & 0x00001000) >> 12;
+         immB = (value & 0x00000ffc) >> 2;
+         immC = (value & 0x00000002) >> 1;
+
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= immA;
+         newval2 |= (immC << 11) | (immB << 1);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_THUMB_LOOP12:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 12 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      bfd_vma insn = get_thumb32_insn (buf);
+      /* le lr, <label> or le <label> */
+      if (((insn & 0xffffffff) == 0xf00fc001)
+         || ((insn & 0xffffffff) == 0xf02fc001))
+       value = -value;
+
+      if (v8_1_branch_value_check (value, 12, FALSE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         addressT imml, immh;
+
+         immh = (value & 0x00000ffc) >> 2;
+         imml = (value & 0x00000002) >> 1;
+
+         newval  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval |= (imml << 11) | (immh << 1);
+         md_number_to_chars (buf + THUMB_SIZE, newval, THUMB_SIZE);
+       }
+      break;
+
     case BFD_RELOC_ARM_V4BX:
       /* This will need to go in the object file.  */
       fixP->fx_done = 0;
@@ -25037,6 +26374,8 @@ tc_gen_reloc (asection *section, fixS *fixp)
     case BFD_RELOC_ARM_GOTOFFFUNCDESC:
     case BFD_RELOC_ARM_FUNCDESC:
     case BFD_RELOC_ARM_THUMB_BF17:
+    case BFD_RELOC_ARM_THUMB_BF19:
+    case BFD_RELOC_ARM_THUMB_BF13:
       code = fixp->fx_r_type;
       break;
 
@@ -25067,6 +26406,8 @@ tc_gen_reloc (asection *section, fixS *fixp)
       return NULL;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH5:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+    case BFD_RELOC_ARM_THUMB_LOOP12:
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("%s used for a symbol not defined in the same file"),
                    bfd_get_reloc_code_name (fixp->fx_r_type));
@@ -25410,8 +26751,8 @@ arm_cleanup (void)
 {
   literal_pool * pool;
 
-  /* Ensure that all the IT blocks are properly closed.  */
-  check_it_blocks_finished ();
+  /* Ensure that all the predication blocks are properly closed.  */
+  check_pred_blocks_finished ();
 
   for (pool = list_of_pools; pool; pool = pool->next)
     {
@@ -25603,6 +26944,7 @@ md_begin (void)
 
   if (  (arm_ops_hsh = hash_new ()) == NULL
       || (arm_cond_hsh = hash_new ()) == NULL
+      || (arm_vcond_hsh = hash_new ()) == NULL
       || (arm_shift_hsh = hash_new ()) == NULL
       || (arm_psr_hsh = hash_new ()) == NULL
       || (arm_v7m_psr_hsh = hash_new ()) == NULL
@@ -25615,6 +26957,8 @@ md_begin (void)
     hash_insert (arm_ops_hsh, insns[i].template_name, (void *) (insns + i));
   for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
     hash_insert (arm_cond_hsh, conds[i].template_name, (void *) (conds + i));
+  for (i = 0; i < sizeof (vconds) / sizeof (struct asm_cond); i++)
+    hash_insert (arm_vcond_hsh, vconds[i].template_name, (void *) (vconds + i));
   for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
     hash_insert (arm_shift_hsh, shift_names[i].name, (void *) (shift_names + i));
   for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
@@ -26703,6 +28047,12 @@ static const struct arm_ext_table armv8_1m_main_ext_table[] =
   ARM_ADD ("fp.dp",
           ARM_FEATURE (0, ARM_EXT2_FP16_INST,
                        FPU_VFP_V5D16 | FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA)),
+  ARM_EXT ("mve", ARM_FEATURE_COPROC (FPU_MVE),
+          ARM_FEATURE_COPROC (FPU_MVE | FPU_MVE_FP)),
+  ARM_ADD ("mve.fp",
+          ARM_FEATURE (0, ARM_EXT2_FP16_INST,
+                       FPU_MVE | FPU_MVE_FP | FPU_VFP_V5_SP_D16 |
+                       FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA)),
   { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
 
@@ -27880,6 +29230,11 @@ aeabi_set_public_attributes (void)
        }
     }
 
+  if (ARM_CPU_HAS_FEATURE (flags, mve_fp_ext))
+    aeabi_set_attribute_int (Tag_MVE_arch, 2);
+  else if (ARM_CPU_HAS_FEATURE (flags, mve_ext))
+    aeabi_set_attribute_int (Tag_MVE_arch, 1);
+
   /* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch).  */
   if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16) && fp16_optional)
     aeabi_set_attribute_int (Tag_VFP_HP_extension, 1);
@@ -28221,6 +29576,7 @@ arm_convert_symbolic_attribute (const char *name)
       T (Tag_T2EE_use),
       T (Tag_Virtualization_use),
       T (Tag_DSP_extension),
+      T (Tag_MVE_arch),
       /* We deliberately do not include Tag_MPextension_use_legacy.  */
 #undef T
     };
This page took 0.080167 seconds and 4 git commands to generate.