readelf: Fix incorrect "Version definition past end of section" message (ChangeLog)
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 0bcbc09adab3238f79390f62300b9d379df1da34..ef6b609d0878c140d4b48128e5cc7cf6b7144e5d 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
 /* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994-2015 Free Software Foundation, Inc.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
        Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
        Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
@@ -155,13 +155,15 @@ static const arm_feature_set *object_arch = NULL;
 
 /* Constants for known architecture features.  */
 static const arm_feature_set fpu_default = FPU_DEFAULT;
 
 /* Constants for known architecture features.  */
 static const arm_feature_set fpu_default = FPU_DEFAULT;
-static const arm_feature_set fpu_arch_vfp_v1 = FPU_ARCH_VFP_V1;
+static const arm_feature_set fpu_arch_vfp_v1 ATTRIBUTE_UNUSED = FPU_ARCH_VFP_V1;
 static const arm_feature_set fpu_arch_vfp_v2 = FPU_ARCH_VFP_V2;
 static const arm_feature_set fpu_arch_vfp_v2 = FPU_ARCH_VFP_V2;
-static const arm_feature_set fpu_arch_vfp_v3 = FPU_ARCH_VFP_V3;
-static const arm_feature_set fpu_arch_neon_v1 = FPU_ARCH_NEON_V1;
+static const arm_feature_set fpu_arch_vfp_v3 ATTRIBUTE_UNUSED = FPU_ARCH_VFP_V3;
+static const arm_feature_set fpu_arch_neon_v1 ATTRIBUTE_UNUSED = FPU_ARCH_NEON_V1;
 static const arm_feature_set fpu_arch_fpa = FPU_ARCH_FPA;
 static const arm_feature_set fpu_any_hard = FPU_ANY_HARD;
 static const arm_feature_set fpu_arch_fpa = FPU_ARCH_FPA;
 static const arm_feature_set fpu_any_hard = FPU_ANY_HARD;
+#ifdef OBJ_ELF
 static const arm_feature_set fpu_arch_maverick = FPU_ARCH_MAVERICK;
 static const arm_feature_set fpu_arch_maverick = FPU_ARCH_MAVERICK;
+#endif
 static const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE;
 
 #ifdef CPU_DEFAULT
 static const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE;
 
 #ifdef CPU_DEFAULT
@@ -198,22 +200,50 @@ static const arm_feature_set arm_ext_div = ARM_FEATURE_CORE_LOW (ARM_EXT_DIV);
 static const arm_feature_set arm_ext_v7 = ARM_FEATURE_CORE_LOW (ARM_EXT_V7);
 static const arm_feature_set arm_ext_v7a = ARM_FEATURE_CORE_LOW (ARM_EXT_V7A);
 static const arm_feature_set arm_ext_v7r = ARM_FEATURE_CORE_LOW (ARM_EXT_V7R);
 static const arm_feature_set arm_ext_v7 = ARM_FEATURE_CORE_LOW (ARM_EXT_V7);
 static const arm_feature_set arm_ext_v7a = ARM_FEATURE_CORE_LOW (ARM_EXT_V7A);
 static const arm_feature_set arm_ext_v7r = ARM_FEATURE_CORE_LOW (ARM_EXT_V7R);
+#ifdef OBJ_ELF
 static const arm_feature_set arm_ext_v7m = ARM_FEATURE_CORE_LOW (ARM_EXT_V7M);
 static const arm_feature_set arm_ext_v7m = ARM_FEATURE_CORE_LOW (ARM_EXT_V7M);
+#endif
 static const arm_feature_set arm_ext_v8 = ARM_FEATURE_CORE_LOW (ARM_EXT_V8);
 static const arm_feature_set arm_ext_m =
 static const arm_feature_set arm_ext_v8 = ARM_FEATURE_CORE_LOW (ARM_EXT_V8);
 static const arm_feature_set arm_ext_m =
-  ARM_FEATURE_CORE_LOW (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M);
+  ARM_FEATURE_CORE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M,
+                   ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN);
 static const arm_feature_set arm_ext_mp = ARM_FEATURE_CORE_LOW (ARM_EXT_MP);
 static const arm_feature_set arm_ext_sec = ARM_FEATURE_CORE_LOW (ARM_EXT_SEC);
 static const arm_feature_set arm_ext_os = ARM_FEATURE_CORE_LOW (ARM_EXT_OS);
 static const arm_feature_set arm_ext_adiv = ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV);
 static const arm_feature_set arm_ext_virt = ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT);
 static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN);
 static const arm_feature_set arm_ext_mp = ARM_FEATURE_CORE_LOW (ARM_EXT_MP);
 static const arm_feature_set arm_ext_sec = ARM_FEATURE_CORE_LOW (ARM_EXT_SEC);
 static const arm_feature_set arm_ext_os = ARM_FEATURE_CORE_LOW (ARM_EXT_OS);
 static const arm_feature_set arm_ext_adiv = ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV);
 static const arm_feature_set arm_ext_virt = ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT);
 static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN);
+static const arm_feature_set arm_ext_v8m = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M);
+static const arm_feature_set arm_ext_v8m_main =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN);
+/* Instructions in ARMv8-M only found in M profile architectures.  */
+static const arm_feature_set arm_ext_v8m_m_only =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN);
+static const arm_feature_set arm_ext_v6t2_v8m =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V6T2_V8M);
+/* Instructions shared between ARMv8-A and ARMv8-M.  */
+static const arm_feature_set arm_ext_atomics =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_ATOMICS);
+#ifdef OBJ_ELF
+/* DSP instructions Tag_DSP_extension refers to.  */
+static const arm_feature_set arm_ext_dsp =
+  ARM_FEATURE_CORE_LOW (ARM_EXT_V5E | ARM_EXT_V5ExP | ARM_EXT_V6_DSP);
+#endif
+static const arm_feature_set arm_ext_ras =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS);
+/* FP16 instructions.  */
+static const arm_feature_set arm_ext_fp16 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST);
+static const arm_feature_set arm_ext_v8_3 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A);
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
-static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1, -1);
+static const arm_feature_set arm_arch_full ATTRIBUTE_UNUSED = ARM_FEATURE (-1, -1, -1);
 static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
 static const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
 static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
 static const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
+#ifdef OBJ_ELF
 static const arm_feature_set arm_arch_v6m_only = ARM_ARCH_V6M_ONLY;
 static const arm_feature_set arm_arch_v6m_only = ARM_ARCH_V6M_ONLY;
+#endif
 
 static const arm_feature_set arm_cext_iwmmxt2 =
   ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2);
 
 static const arm_feature_set arm_cext_iwmmxt2 =
   ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2);
@@ -243,10 +273,12 @@ 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);
   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);
+#ifdef OBJ_ELF
 static const arm_feature_set fpu_vfp_fp16 =
   ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16);
 static const arm_feature_set fpu_neon_ext_fma =
   ARM_FEATURE_COPROC (FPU_NEON_EXT_FMA);
 static const arm_feature_set fpu_vfp_fp16 =
   ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16);
 static const arm_feature_set fpu_neon_ext_fma =
   ARM_FEATURE_COPROC (FPU_NEON_EXT_FMA);
+#endif
 static const arm_feature_set fpu_vfp_ext_fma =
   ARM_FEATURE_COPROC (FPU_VFP_EXT_FMA);
 static const arm_feature_set fpu_vfp_ext_armv8 =
 static const arm_feature_set fpu_vfp_ext_fma =
   ARM_FEATURE_COPROC (FPU_VFP_EXT_FMA);
 static const arm_feature_set fpu_vfp_ext_armv8 =
@@ -260,13 +292,13 @@ static const arm_feature_set fpu_crypto_ext_armv8 =
 static const arm_feature_set crc_ext_armv8 =
   ARM_FEATURE_COPROC (CRC_EXT_ARMV8);
 static const arm_feature_set fpu_neon_ext_v8_1 =
 static const arm_feature_set crc_ext_armv8 =
   ARM_FEATURE_COPROC (CRC_EXT_ARMV8);
 static const arm_feature_set fpu_neon_ext_v8_1 =
-  ARM_FEATURE_COPROC (FPU_NEON_EXT_ARMV8 | FPU_NEON_EXT_RDMA);
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_RDMA);
 
 static int mfloat_abi_opt = -1;
 /* Record user cpu selection for object attributes.  */
 static arm_feature_set selected_cpu = ARM_ARCH_NONE;
 /* Must be long enough to hold any of the names in arm_cpus.  */
 
 static int mfloat_abi_opt = -1;
 /* Record user cpu selection for object attributes.  */
 static arm_feature_set selected_cpu = ARM_ARCH_NONE;
 /* Must be long enough to hold any of the names in arm_cpus.  */
-static char selected_cpu_name[16];
+static char selected_cpu_name[20];
 
 extern FLONUM_TYPE generic_floating_point_number;
 
 
 extern FLONUM_TYPE generic_floating_point_number;
 
@@ -505,7 +537,7 @@ struct asm_barrier_opt
 
 struct reloc_entry
 {
 
 struct reloc_entry
 {
-  char *                    name;
+  const char *                    name;
   bfd_reloc_code_real_type  reloc;
 };
 
   bfd_reloc_code_real_type  reloc;
 };
 
@@ -655,9 +687,11 @@ struct asm_opcode
 #define T2_SUBS_PC_LR  0xf3de8f00
 
 #define DATA_OP_SHIFT  21
 #define T2_SUBS_PC_LR  0xf3de8f00
 
 #define DATA_OP_SHIFT  21
+#define SBIT_SHIFT     20
 
 #define T2_OPCODE_MASK 0xfe1fffff
 #define T2_DATA_OP_SHIFT 21
 
 #define T2_OPCODE_MASK 0xfe1fffff
 #define T2_DATA_OP_SHIFT 21
+#define T2_SBIT_SHIFT   20
 
 #define A_COND_MASK         0xf0000000
 #define A_PUSH_POP_OP_MASK  0x0fff0000
 
 #define A_COND_MASK         0xf0000000
 #define A_PUSH_POP_OP_MASK  0x0fff0000
@@ -773,8 +807,10 @@ struct asm_opcode
        _("cannot use register index with PC-relative addressing")
 #define BAD_PC_WRITEBACK \
        _("cannot use writeback with PC-relative addressing")
        _("cannot use register index with PC-relative addressing")
 #define BAD_PC_WRITEBACK \
        _("cannot use writeback with PC-relative addressing")
-#define BAD_RANGE     _("branch out of range")
+#define BAD_RANGE      _("branch out of range")
+#define BAD_FP16       _("selected processor does not support fp16 instruction")
 #define UNPRED_REG(R)  _("using " R " results in unpredictable behaviour")
 #define UNPRED_REG(R)  _("using " R " results in unpredictable behaviour")
+#define THUMB1_RELOC_ONLY  _("relocation valid in thumb1 code only")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
@@ -1064,7 +1100,7 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
 
    ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
 
 
    ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
 
-char *
+const char *
 md_atof (int type, char * litP, int * sizeP)
 {
   int prec;
 md_atof (int type, char * litP, int * sizeP)
 {
   int prec;
@@ -1244,6 +1280,7 @@ arm_reg_alt_syntax (char **ccp, char *start, struct reg_entry *reg,
        if (*ccp != start && processor <= 15)
          return processor;
       }
        if (*ccp != start && processor <= 15)
          return processor;
       }
+      /* Fall through.  */
 
     case REG_TYPE_MMXWC:
       /* WC includes WCG.  ??? I'm not sure this is true for all
 
     case REG_TYPE_MMXWC:
       /* WC includes WCG.  ??? I'm not sure this is true for all
@@ -1975,6 +2012,10 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
   const char *const incr_error = _("register stride must be 1 or 2");
   const char *const type_error = _("mismatched element/structure types in list");
   struct neon_typed_alias firsttype;
   const char *const incr_error = _("register stride must be 1 or 2");
   const char *const type_error = _("mismatched element/structure types in list");
   struct neon_typed_alias firsttype;
+  firsttype.defined = 0;
+  firsttype.eltype.type = NT_invtype;
+  firsttype.eltype.size = -1;
+  firsttype.index = -1;
 
   if (skip_past_char (&ptr, '{') == SUCCESS)
     leading_brace = 1;
 
   if (skip_past_char (&ptr, '{') == SUCCESS)
     leading_brace = 1;
@@ -2167,7 +2208,7 @@ insert_reg_alias (char *str, unsigned number, int type)
     }
 
   name = xstrdup (str);
     }
 
   name = xstrdup (str);
-  new_reg = (struct reg_entry *) xmalloc (sizeof (struct reg_entry));
+  new_reg = XNEW (struct reg_entry);
 
   new_reg->name = name;
   new_reg->number = number;
 
   new_reg->name = name;
   new_reg->number = number;
@@ -2195,8 +2236,7 @@ insert_neon_reg_alias (char *str, int number, int type,
 
   if (atype)
     {
 
   if (atype)
     {
-      reg->neon = (struct neon_typed_alias *)
-         xmalloc (sizeof (struct neon_typed_alias));
+      reg->neon = XNEW (struct neon_typed_alias);
       *reg->neon = *atype;
     }
 }
       *reg->neon = *atype;
     }
 }
@@ -2242,9 +2282,7 @@ create_register_alias (char * newname, char *p)
   nlen = strlen (newname);
 #endif
 
   nlen = strlen (newname);
 #endif
 
-  nbuf = (char *) alloca (nlen + 1);
-  memcpy (nbuf, newname, nlen);
-  nbuf[nlen] = '\0';
+  nbuf = xmemdup0 (newname, nlen);
 
   /* Create aliases under the new name as stated; an all-lowercase
      version of the new name; and an all-uppercase version of the new
 
   /* Create aliases under the new name as stated; an all-lowercase
      version of the new name; and an all-uppercase version of the new
@@ -2266,7 +2304,10 @@ create_register_alias (char * newname, char *p)
             the artificial FOO alias because it has already been created by the
             first .req.  */
          if (insert_reg_alias (nbuf, old->number, old->type) == NULL)
             the artificial FOO alias because it has already been created by the
             first .req.  */
          if (insert_reg_alias (nbuf, old->number, old->type) == NULL)
-           return TRUE;
+           {
+             free (nbuf);
+             return TRUE;
+           }
        }
 
       for (p = nbuf; *p; p++)
        }
 
       for (p = nbuf; *p; p++)
@@ -2276,6 +2317,7 @@ create_register_alias (char * newname, char *p)
        insert_reg_alias (nbuf, old->number, old->type);
     }
 
        insert_reg_alias (nbuf, old->number, old->type);
     }
 
+  free (nbuf);
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -2403,9 +2445,7 @@ create_neon_reg_alias (char *newname, char *p)
   namelen = strlen (newname);
 #endif
 
   namelen = strlen (newname);
 #endif
 
-  namebuf = (char *) alloca (namelen + 1);
-  strncpy (namebuf, newname, namelen);
-  namebuf[namelen] = '\0';
+  namebuf = xmemdup0 (newname, namelen);
 
   insert_neon_reg_alias (namebuf, basereg->number, basetype,
                         typeinfo.defined != 0 ? &typeinfo : NULL);
 
   insert_neon_reg_alias (namebuf, basereg->number, basetype,
                         typeinfo.defined != 0 ? &typeinfo : NULL);
@@ -2426,6 +2466,7 @@ create_neon_reg_alias (char *newname, char *p)
     insert_neon_reg_alias (namebuf, basereg->number, basetype,
                           typeinfo.defined != 0 ? &typeinfo : NULL);
 
     insert_neon_reg_alias (namebuf, basereg->number, basetype,
                           typeinfo.defined != 0 ? &typeinfo : NULL);
 
+  free (namebuf);
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -2669,7 +2710,7 @@ mapping_state (enum mstate state)
 
        Some Thumb instructions are alignment-sensitive modulo 4 bytes,
        but themselves require 2-byte alignment; this applies to some
 
        Some Thumb instructions are alignment-sensitive modulo 4 bytes,
        but themselves require 2-byte alignment; this applies to some
-       PC- relative forms.  However, these cases will invovle implicit
+       PC- relative forms.  However, these cases will involve implicit
        literal pool generation or an explicit .align >=2, both of
        which will cause the section to me marked with sufficient
        alignment.  Thus, we don't handle those cases here.  */
        literal pool generation or an explicit .align >=2, both of
        which will cause the section to me marked with sufficient
        alignment.  Thus, we don't handle those cases here.  */
@@ -2741,8 +2782,9 @@ find_real_start (symbolS * symbolP)
   if (S_IS_LOCAL (symbolP) || name[0] == '.')
     return symbolP;
 
   if (S_IS_LOCAL (symbolP) || name[0] == '.')
     return symbolP;
 
-  real_start = ACONCAT ((STUB_NAME, name, NULL));
+  real_start = concat (STUB_NAME, name, NULL);
   new_target = symbol_find (real_start);
   new_target = symbol_find (real_start);
+  free (real_start);
 
   if (new_target == NULL)
     {
 
   if (new_target == NULL)
     {
@@ -2868,10 +2910,9 @@ s_thumb_set (int equiv)
   /* Especial apologies for the random logic:
      This just grew, and could be parsed much more simply!
      Dean - in haste.  */
   /* Especial apologies for the random logic:
      This just grew, and could be parsed much more simply!
      Dean - in haste.  */
-  name     = input_line_pointer;
-  delim            = get_symbol_end ();
+  delim            = get_symbol_name (& name);
   end_name  = input_line_pointer;
   end_name  = input_line_pointer;
-  *end_name = delim;
+  (void) restore_line_pointer (delim);
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
@@ -2951,8 +2992,7 @@ s_syntax (int unused ATTRIBUTE_UNUSED)
 {
   char *name, delim;
 
 {
   char *name, delim;
 
-  name = input_line_pointer;
-  delim = get_symbol_end ();
+  delim = get_symbol_name (& name);
 
   if (!strcasecmp (name, "unified"))
     unified_syntax = TRUE;
 
   if (!strcasecmp (name, "unified"))
     unified_syntax = TRUE;
@@ -2963,59 +3003,12 @@ s_syntax (int unused ATTRIBUTE_UNUSED)
       as_bad (_("unrecognized syntax mode \"%s\""), name);
       return;
     }
       as_bad (_("unrecognized syntax mode \"%s\""), name);
       return;
     }
-  *input_line_pointer = delim;
+  (void) restore_line_pointer (delim);
   demand_empty_rest_of_line ();
 }
 
 /* Directives: sectioning and alignment.  */
 
   demand_empty_rest_of_line ();
 }
 
 /* Directives: sectioning and alignment.  */
 
-/* Same as s_align_ptwo but align 0 => align 2.         */
-
-static void
-s_align (int unused ATTRIBUTE_UNUSED)
-{
-  int temp;
-  bfd_boolean fill_p;
-  long temp_fill;
-  long max_alignment = 15;
-
-  temp = get_absolute_expression ();
-  if (temp > max_alignment)
-    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
-  else if (temp < 0)
-    {
-      as_bad (_("alignment negative. 0 assumed."));
-      temp = 0;
-    }
-
-  if (*input_line_pointer == ',')
-    {
-      input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-      fill_p = TRUE;
-    }
-  else
-    {
-      fill_p = FALSE;
-      temp_fill = 0;
-    }
-
-  if (!temp)
-    temp = 2;
-
-  /* Only make a frag if we HAVE to.  */
-  if (temp && !need_pass_2)
-    {
-      if (!fill_p && subseg_text_p (now_seg))
-       frag_align_code (temp, 0);
-      else
-       frag_align (temp, (int) temp_fill, 0);
-    }
-  demand_empty_rest_of_line ();
-
-  record_alignment (now_seg, temp);
-}
-
 static void
 s_bss (int ignore ATTRIBUTE_UNUSED)
 {
 static void
 s_bss (int ignore ATTRIBUTE_UNUSED)
 {
@@ -3054,7 +3047,7 @@ s_ccs_ref (int unused ATTRIBUTE_UNUSED)
 }
 
 /*  If name is not NULL, then it is used for marking the beginning of a
 }
 
 /*  If name is not NULL, then it is used for marking the beginning of a
-    function, wherease if it is NULL then it means the function end.  */
+    function, whereas if it is NULL then it means the function end.  */
 static void
 asmfunc_debug (const char * name)
 {
 static void
 asmfunc_debug (const char * name)
 {
@@ -3168,7 +3161,7 @@ find_or_make_literal_pool (void)
   if (pool == NULL)
     {
       /* Create a new pool.  */
   if (pool == NULL)
     {
       /* Create a new pool.  */
-      pool = (literal_pool *) xmalloc (sizeof (* pool));
+      pool = XNEW (literal_pool);
       if (! pool)
        return NULL;
 
       if (! pool)
        return NULL;
 
@@ -3306,6 +3299,7 @@ add_to_lit_pool (unsigned int nbytes)
                }
 
              pool->literals[entry] = inst.reloc.exp;
                }
 
              pool->literals[entry] = inst.reloc.exp;
+             pool->literals[entry].X_op = O_constant;
              pool->literals[entry].X_add_number = 0;
              pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4;
              pool->next_free_entry += 1;
              pool->literals[entry].X_add_number = 0;
              pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4;
              pool->next_free_entry += 1;
@@ -3360,13 +3354,13 @@ add_to_lit_pool (unsigned int nbytes)
 }
 
 bfd_boolean
 }
 
 bfd_boolean
-tc_start_label_without_colon (char unused1 ATTRIBUTE_UNUSED, const char * rest)
+tc_start_label_without_colon (void)
 {
   bfd_boolean ret = TRUE;
 
   if (codecomposer_syntax && asmfunc_state == WAITING_ASMFUNC_NAME)
     {
 {
   bfd_boolean ret = TRUE;
 
   if (codecomposer_syntax && asmfunc_state == WAITING_ASMFUNC_NAME)
     {
-      const char *label = rest;
+      const char *label = input_line_pointer;
 
       while (!is_end_of_line[(int) label[-1]])
        --label;
 
       while (!is_end_of_line[(int) label[-1]])
        --label;
@@ -3386,7 +3380,7 @@ tc_start_label_without_colon (char unused1 ATTRIBUTE_UNUSED, const char * rest)
 }
 
 /* Can't use symbol_new here, so have to create a symbol and then at
 }
 
 /* Can't use symbol_new here, so have to create a symbol and then at
-   a later date assign it a value. Thats what these functions do.  */
+   a later date assign it a value. That's what these functions do.  */
 
 static void
 symbol_locate (symbolS *    symbolP,
 
 static void
 symbol_locate (symbolS *    symbolP,
@@ -3565,7 +3559,8 @@ s_arm_elf_cons (int nbytes)
                     XXX Surely there is a cleaner way to do this.  */
                  char *p = input_line_pointer;
                  int offset;
                     XXX Surely there is a cleaner way to do this.  */
                  char *p = input_line_pointer;
                  int offset;
-                 char *save_buf = (char *) alloca (input_line_pointer - base);
+                 char *save_buf = XNEWVEC (char, input_line_pointer - base);
+
                  memcpy (save_buf, base, input_line_pointer - base);
                  memmove (base + (input_line_pointer - before_reloc),
                           base, before_reloc - base);
                  memcpy (save_buf, base, input_line_pointer - base);
                  memmove (base + (input_line_pointer - before_reloc),
                           base, before_reloc - base);
@@ -3579,6 +3574,7 @@ s_arm_elf_cons (int nbytes)
                  memset (p, 0, nbytes);
                  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
                               size, &exp, 0, (enum bfd_reloc_code_real) reloc);
                  memset (p, 0, nbytes);
                  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
                               size, &exp, 0, (enum bfd_reloc_code_real) reloc);
+                 free (save_buf);
                }
            }
        }
                }
            }
        }
@@ -3927,9 +3923,10 @@ s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
   if (unwind.personality_routine || unwind.personality_index != -1)
     as_bad (_("duplicate .personality directive"));
 
   if (unwind.personality_routine || unwind.personality_index != -1)
     as_bad (_("duplicate .personality directive"));
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (& name);
   p = input_line_pointer;
   p = input_line_pointer;
+  if (c == '"')
+    ++ input_line_pointer;
   unwind.personality_routine = symbol_find_or_make (name);
   *p = c;
   demand_empty_rest_of_line ();
   unwind.personality_routine = symbol_find_or_make (name);
   *p = c;
   demand_empty_rest_of_line ();
@@ -4691,7 +4688,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "qn",          s_qn,          0 },
   { "unreq",      s_unreq,       0 },
   { "bss",        s_bss,         0 },
   { "qn",          s_qn,          0 },
   { "unreq",      s_unreq,       0 },
   { "bss",        s_bss,         0 },
-  { "align",      s_align,       0 },
+  { "align",      s_align_ptwo,  2 },
   { "arm",        s_arm,         0 },
   { "thumb",      s_thumb,       0 },
   { "code",       s_code,        0 },
   { "arm",        s_arm,         0 },
   { "thumb",      s_thumb,       0 },
   { "code",       s_code,        0 },
@@ -4972,9 +4969,13 @@ parse_ifimm_zero (char **in)
   int error_code;
 
   if (!is_immediate_prefix (**in))
   int error_code;
 
   if (!is_immediate_prefix (**in))
-    return FALSE;
-
-  ++*in;
+    {
+      /* In unified syntax, all prefixes are optional.  */
+      if (!unified_syntax)
+       return FALSE;
+    }
+  else
+    ++*in;
 
   /* Accept #0x0 as a synonym for #0.  */
   if (strncmp (*in, "0x", 2) == 0)
 
   /* Accept #0x0 as a synonym for #0.  */
   if (strncmp (*in, "0x", 2) == 0)
@@ -5321,7 +5322,28 @@ static struct group_reloc_table_entry group_reloc_table[] =
       BFD_RELOC_ARM_ALU_SB_G2,         /* ALU */
       BFD_RELOC_ARM_LDR_SB_G2,         /* LDR */
       BFD_RELOC_ARM_LDRS_SB_G2,                /* LDRS */
       BFD_RELOC_ARM_ALU_SB_G2,         /* ALU */
       BFD_RELOC_ARM_LDR_SB_G2,         /* LDR */
       BFD_RELOC_ARM_LDRS_SB_G2,                /* LDRS */
-      BFD_RELOC_ARM_LDC_SB_G2 }        };      /* LDC */
+      BFD_RELOC_ARM_LDC_SB_G2 },       /* LDC */
+    /* Absolute thumb alu relocations.  */
+    { "lower0_7",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 },                             /* LDC.  */
+    { "lower8_15",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 },                             /* LDC.  */
+    { "upper0_7",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 },                             /* LDC.  */
+    { "upper8_15",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 } };                           /* LDC.  */
 
 /* Given the address of a pointer pointing to the textual name of a group
    relocation as may appear in assembler source, attempt to find its details
 
 /* Given the address of a pointer pointing to the textual name of a group
    relocation as may appear in assembler source, attempt to find its details
@@ -6100,6 +6122,16 @@ parse_cond (char **str)
   return c->value;
 }
 
   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 available in the selected CPU, mark it as used.
    Returns TRUE iff feature is available.  */
 static bfd_boolean
 /* If the given feature available in the selected CPU, mark it as used.
    Returns TRUE iff feature is available.  */
 static bfd_boolean
@@ -6111,10 +6143,7 @@ mark_feature_used (const arm_feature_set *feature)
 
   /* Add the appropriate architecture feature for the barrier option used.
      */
 
   /* Add the appropriate architecture feature for the barrier option used.
      */
-  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);
+  record_feature_use (feature);
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -6510,6 +6539,8 @@ enum operand_parse_code
   OP_EXPi,     /* same, with optional immediate prefix */
   OP_EXPr,     /* same, with optional relocation suffix */
   OP_HALF,     /* 0 .. 65535 or low/high reloc.  */
   OP_EXPi,     /* same, with optional immediate prefix */
   OP_EXPr,     /* same, with optional relocation suffix */
   OP_HALF,     /* 0 .. 65535 or low/high reloc.  */
+  OP_IROT1,    /* VCADD rotate immediate: 90, 270.  */
+  OP_IROT2,    /* VCMLA rotate immediate: 0, 90, 180, 270.  */
 
   OP_CPSF,     /* CPS flags */
   OP_ENDI,     /* Endianness specifier */
 
   OP_CPSF,     /* CPS flags */
   OP_ENDI,     /* Endianness specifier */
@@ -6521,7 +6552,7 @@ enum operand_parse_code
   OP_APSR_RR,   /* ARM register or "APSR_nzcv".  */
 
   OP_RRnpc_I0, /* ARM register or literal 0 */
   OP_APSR_RR,   /* ARM register or "APSR_nzcv".  */
 
   OP_RRnpc_I0, /* ARM register or literal 0 */
-  OP_RR_EXr,   /* ARM register or expression with opt. reloc suff. */
+  OP_RR_EXr,   /* ARM register or expression with opt. reloc stuff. */
   OP_RR_EXi,   /* ARM register or expression with imm prefix */
   OP_RF_IF,    /* FPA register or immediate */
   OP_RIWR_RIWC, /* iWMMXt R or C reg */
   OP_RR_EXi,   /* ARM register or expression with imm prefix */
   OP_RF_IF,    /* FPA register or immediate */
   OP_RIWR_RIWC, /* iWMMXt R or C reg */
@@ -7279,6 +7310,26 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
 #define rotate_left(v, n) (v << (n & 31) | v >> ((32 - n) & 31))
 
 
 #define rotate_left(v, n) (v << (n & 31) | v >> ((32 - n) & 31))
 
+/* If the current inst is scalar ARMv8.2 fp16 instruction, do special encoding.
+
+   The only binary encoding difference is the Coprocessor number.  Coprocessor
+   9 is used for half-precision calculations or conversions.  The format of the
+   instruction is the same as the equivalent Coprocessor 10 instruction that
+   exists for Single-Precision operation.  */
+
+static void
+do_scalar_fp16_v82_encode (void)
+{
+  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),
+             _(BAD_FP16));
+
+  inst.instruction = (inst.instruction & 0xfffff0ff) | 0x900;
+  mark_feature_used (&arm_ext_fp16);
+}
+
 /* If VAL can be encoded in the immediate field of an ARM instruction,
    return the encoded form.  Otherwise, return FAIL.  */
 
 /* If VAL can be encoded in the immediate field of an ARM instruction,
    return the encoded form.  Otherwise, return FAIL.  */
 
@@ -7287,7 +7338,10 @@ encode_arm_immediate (unsigned int val)
 {
   unsigned int a, i;
 
 {
   unsigned int a, i;
 
-  for (i = 0; i < 32; i += 2)
+  if (val <= 0xff)
+    return val;
+
+  for (i = 2; i < 32; i += 2)
     if ((a = rotate_left (val, i)) <= 0xff)
       return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
 
     if ((a = rotate_left (val, i)) <= 0xff)
       return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
 
@@ -7383,6 +7437,24 @@ encode_arm_vfp_reg (int reg, enum vfp_reg_pos pos)
 static void
 encode_arm_shift (int i)
 {
 static void
 encode_arm_shift (int i)
 {
+  /* register-shifted register.  */
+  if (inst.operands[i].immisreg)
+    {
+      int op_index;
+      for (op_index = 0; op_index <= i; ++op_index)
+       {
+         /* Check the operand only when it's presented.  In pre-UAL syntax,
+            if the destination register is the same as the first operand, two
+            register form of the instruction can be used.  */
+         if (inst.operands[op_index].present && inst.operands[op_index].isreg
+             && inst.operands[op_index].reg == REG_PC)
+           as_warn (UNPRED_REG ("r15"));
+       }
+
+      if (inst.operands[i].imm == REG_PC)
+       as_warn (UNPRED_REG ("r15"));
+    }
+
   if (inst.operands[i].shift_kind == SHIFT_RRX)
     inst.instruction |= SHIFT_ROR << 5;
   else
   if (inst.operands[i].shift_kind == SHIFT_RRX)
     inst.instruction |= SHIFT_ROR << 5;
   else
@@ -7760,14 +7832,14 @@ static bfd_boolean
 is_double_a_single (bfd_int64_t v)
 {
   int exp = (int)((v >> 52) & 0x7FF);
 is_double_a_single (bfd_int64_t v)
 {
   int exp = (int)((v >> 52) & 0x7FF);
-  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFF);
+  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFFULL);
 
   return (exp == 0 || exp == 0x7FF
          || (exp >= 1023 - 126 && exp <= 1023 + 127))
     && (mantissa & 0x1FFFFFFFl) == 0;
 }
 
 
   return (exp == 0 || exp == 0x7FF
          || (exp >= 1023 - 126 && exp <= 1023 + 127))
     && (mantissa & 0x1FFFFFFFl) == 0;
 }
 
-/* Returns a double precision value casted to single precision 
+/* Returns a double precision value casted to single precision
    (ignoring the least significant bits in exponent and mantissa).  */
 
 static int
    (ignoring the least significant bits in exponent and mantissa).  */
 
 static int
@@ -7775,7 +7847,7 @@ double_to_single (bfd_int64_t v)
 {
   int sign = (int) ((v >> 63) & 1l);
   int exp = (int) ((v >> 52) & 0x7FF);
 {
   int sign = (int) ((v >> 63) & 1l);
   int exp = (int) ((v >> 52) & 0x7FF);
-  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFF);
+  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFFULL);
 
   if (exp == 0x7FF)
     exp = 0xFF;
 
   if (exp == 0x7FF)
     exp = 0xFF;
@@ -7865,7 +7937,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
            }
          else
            l = generic_bignum;
            }
          else
            l = generic_bignum;
-         
+
 #if defined BFD_HOST_64_BIT
          v =
            ((((((((bfd_int64_t) l[3] & LITTLENUM_MASK)
 #if defined BFD_HOST_64_BIT
          v =
            ((((((((bfd_int64_t) l[3] & LITTLENUM_MASK)
@@ -7887,7 +7959,8 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
        {
          if (thumb_p)
            {
        {
          if (thumb_p)
            {
-             if ((v & ~0xFF) == 0)
+             /* This can be encoded only for a low register.  */
+             if ((v & ~0xFF) == 0 && (inst.operands[i].reg < 8))
                {
                  /* This can be done with a mov(1) instruction.  */
                  inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
                {
                  /* This can be done with a mov(1) instruction.  */
                  inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
@@ -7895,10 +7968,11 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
                  return TRUE;
                }
 
                  return TRUE;
                }
 
-             if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2)
-                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
+             if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)
+                 || ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m))
                {
                {
-                 /* Check if on thumb2 it can be done with a mov.w or mvn.w instruction.  */
+                 /* Check if on thumb2 it can be done with a mov.w, mvn or
+                    movw instruction.  */
                  unsigned int newimm;
                  bfd_boolean isNegated;
 
                  unsigned int newimm;
                  bfd_boolean isNegated;
 
@@ -7907,36 +7981,32 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
                    isNegated = FALSE;
                  else
                    {
                    isNegated = FALSE;
                  else
                    {
-                     newimm = encode_thumb32_immediate (~ v);
+                     newimm = encode_thumb32_immediate (~v);
                      if (newimm != (unsigned int) FAIL)
                        isNegated = TRUE;
                    }
 
                      if (newimm != (unsigned int) FAIL)
                        isNegated = TRUE;
                    }
 
-                 if (newimm != (unsigned int) FAIL)
+                 /* The number can be loaded with a mov.w or mvn
+                    instruction.  */
+                 if (newimm != (unsigned int) FAIL
+                     && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
                    {
                    {
-                     inst.instruction = 0xf04f0000 | (inst.operands[i].reg << 8);
-                     inst.instruction |= (isNegated?0x200000:0);
+                     inst.instruction = (0xf04f0000  /*  MOV.W.  */
+                                         | (inst.operands[i].reg << 8));
+                     /* Change to MOVN.  */
+                     inst.instruction |= (isNegated ? 0x200000 : 0);
                      inst.instruction |= (newimm & 0x800) << 15;
                      inst.instruction |= (newimm & 0x700) << 4;
                      inst.instruction |= (newimm & 0x0ff);
                      return TRUE;
                    }
                      inst.instruction |= (newimm & 0x800) << 15;
                      inst.instruction |= (newimm & 0x700) << 4;
                      inst.instruction |= (newimm & 0x0ff);
                      return TRUE;
                    }
-                 else if ((v & ~0xFFFF) == 0 || (v & ~0xFFFF0000) == 0)
-                   { 
-                     /* The number may be loaded with a movw/movt instruction.  */
-                     int imm;
-
-                     if ((inst.reloc.exp.X_add_number & ~0xFFFF) == 0)
-                       {
-                         inst.instruction= 0xf2400000;
-                         imm = v;
-                       }
-                     else
-                       {
-                         inst.instruction = 0xf2c00000;
-                         imm = v >> 16;
-                       }
+                 /* The number can be loaded with a movw instruction.  */
+                 else if ((v & ~0xFFFF) == 0
+                          && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m))
+                   {
+                     int imm = v & 0xFFFF;
 
 
+                     inst.instruction = 0xf2400000;  /* MOVW.  */
                      inst.instruction |= (inst.operands[i].reg << 8);
                      inst.instruction |= (imm & 0xf000) << 4;
                      inst.instruction |= (imm & 0x0800) << 15;
                      inst.instruction |= (inst.operands[i].reg << 8);
                      inst.instruction |= (imm & 0xf000) << 4;
                      inst.instruction |= (imm & 0x0800) << 15;
@@ -7969,7 +8039,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
                  return TRUE;
                }
            }
                  return TRUE;
                }
            }
-         else if (t == CONST_VEC)
+         else if (t == CONST_VEC && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
            {
              int op = 0;
              unsigned immbits = 0;
            {
              int op = 0;
              unsigned immbits = 0;
@@ -8000,9 +8070,9 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
 
                  /* Fill other bits in vmov encoding for both thumb and arm.  */
                  if (thumb_mode)
 
                  /* Fill other bits in vmov encoding for both thumb and arm.  */
                  if (thumb_mode)
-                   inst.instruction |= (0x7 << 29) | (0xF << 24);
+                   inst.instruction |= (0x7U << 29) | (0xF << 24);
                  else
                  else
-                   inst.instruction |= (0xF << 28) | (0x1 << 25);
+                   inst.instruction |= (0xFU << 28) | (0x1 << 25);
                  neon_write_immbits (immbits);
                  return TRUE;
                }
                  neon_write_immbits (immbits);
                  return TRUE;
                }
@@ -8152,6 +8222,12 @@ do_rd (void)
   inst.instruction |= inst.operands[0].reg << 12;
 }
 
   inst.instruction |= inst.operands[0].reg << 12;
 }
 
+static void
+do_rn (void)
+{
+  inst.instruction |= inst.operands[0].reg << 16;
+}
+
 static void
 do_rd_rm (void)
 {
 static void
 do_rd_rm (void)
 {
@@ -8180,6 +8256,13 @@ do_rn_rd (void)
   inst.instruction |= inst.operands[1].reg << 12;
 }
 
   inst.instruction |= inst.operands[1].reg << 12;
 }
 
+static void
+do_tt (void)
+{
+  inst.instruction |= inst.operands[0].reg << 8;
+  inst.instruction |= inst.operands[1].reg << 16;
+}
+
 static bfd_boolean
 check_obsolete (const arm_feature_set *feature, const char *msg)
 {
 static bfd_boolean
 check_obsolete (const arm_feature_set *feature, const char *msg)
 {
@@ -8295,6 +8378,9 @@ do_adrl (void)
 static void
 do_arit (void)
 {
 static void
 do_arit (void)
 {
+  constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+             && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+             THUMB1_RELOC_ONLY);
   if (!inst.operands[1].present)
     inst.operands[1].reg = inst.operands[0].reg;
   inst.instruction |= inst.operands[0].reg << 12;
   if (!inst.operands[1].present)
     inst.operands[1].reg = inst.operands[0].reg;
   inst.instruction |= inst.operands[0].reg << 12;
@@ -8634,6 +8720,14 @@ do_co_reg2c (void)
       constraint (Rn == REG_PC, BAD_PC);
     }
 
       constraint (Rn == REG_PC, BAD_PC);
     }
 
+  /* Only check the MRRC{2} variants.  */
+  if ((inst.instruction & 0x0FF00000) == 0x0C500000)
+    {
+       /* If Rd == Rn, error that the operation is
+         unpredictable (example MRRC p3,#1,r1,r1,c4).  */
+       constraint (Rd == Rn, BAD_OVERLAP);
+    }
+
   inst.instruction |= inst.operands[0].reg << 8;
   inst.instruction |= inst.operands[1].imm << 4;
   inst.instruction |= Rd << 12;
   inst.instruction |= inst.operands[0].reg << 8;
   inst.instruction |= inst.operands[1].imm << 4;
   inst.instruction |= Rd << 12;
@@ -8952,6 +9046,9 @@ do_mlas (void)
 static void
 do_mov (void)
 {
 static void
 do_mov (void)
 {
+  constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+             && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+             THUMB1_RELOC_ONLY);
   inst.instruction |= inst.operands[0].reg << 12;
   encode_arm_shifter_operand (1);
 }
   inst.instruction |= inst.operands[0].reg << 12;
   encode_arm_shifter_operand (1);
 }
@@ -8965,9 +9062,9 @@ do_mov16 (void)
 
   top = (inst.instruction & 0x00400000) != 0;
   constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
 
   top = (inst.instruction & 0x00400000) != 0;
   constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
-             _(":lower16: not allowed this instruction"));
+             _(":lower16: not allowed in this instruction"));
   constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
   constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
-             _(":upper16: not allowed instruction"));
+             _(":upper16: not allowed in this instruction"));
   inst.instruction |= inst.operands[0].reg << 12;
   if (inst.reloc.type == BFD_RELOC_UNUSED)
     {
   inst.instruction |= inst.operands[0].reg << 12;
   if (inst.reloc.type == BFD_RELOC_UNUSED)
     {
@@ -9974,7 +10071,7 @@ do_iwmmxt_wldstd (void)
       && inst.operands[1].immisreg)
     {
       inst.instruction &= ~0x1a000ff;
       && inst.operands[1].immisreg)
     {
       inst.instruction &= ~0x1a000ff;
-      inst.instruction |= (0xf << 28);
+      inst.instruction |= (0xfU << 28);
       if (inst.operands[1].preind)
        inst.instruction |= PRE_INDEX;
       if (!inst.operands[1].negative)
       if (inst.operands[1].preind)
        inst.instruction |= PRE_INDEX;
       if (!inst.operands[1].negative)
@@ -10053,7 +10150,7 @@ do_iwmmxt_wrwrwr_or_imm5 (void)
       }
     /* Map 32 -> 0, etc.  */
     inst.operands[2].imm &= 0x1f;
       }
     /* Map 32 -> 0, etc.  */
     inst.operands[2].imm &= 0x1f;
-    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
+    inst.instruction |= (0xfU << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
   }
 }
 \f
   }
 }
 \f
@@ -10393,7 +10490,7 @@ do_t_add_sub_w (void)
 }
 
 /* Parse an add or subtract instruction.  We get here with inst.instruction
 }
 
 /* Parse an add or subtract instruction.  We get here with inst.instruction
-   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
+   equaling any of THUMB_OPCODE_add, adds, sub, or subs.  */
 
 static void
 do_t_add_sub (void)
 
 static void
 do_t_add_sub (void)
@@ -10450,9 +10547,14 @@ do_t_add_sub (void)
                {
                  inst.instruction = THUMB_OP16(opcode);
                  inst.instruction |= (Rd << 4) | Rs;
                {
                  inst.instruction = THUMB_OP16(opcode);
                  inst.instruction |= (Rd << 4) | Rs;
-                 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-                 if (inst.size_req != 2)
-                   inst.relax = opcode;
+                 if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                     || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+                 {
+                   if (inst.size_req == 2)
+                     inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+                   else
+                     inst.relax = opcode;
+                 }
                }
              else
                constraint (inst.size_req == 2, BAD_HIREG);
                }
              else
                constraint (inst.size_req == 2, BAD_HIREG);
@@ -10460,6 +10562,9 @@ do_t_add_sub (void)
          if (inst.size_req == 4
              || (inst.size_req != 2 && !opcode))
            {
          if (inst.size_req == 4
              || (inst.size_req != 2 && !opcode))
            {
+             constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                         && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+                         THUMB1_RELOC_ONLY);
              if (Rd == REG_PC)
                {
                  constraint (add, BAD_PC);
              if (Rd == REG_PC)
                {
                  constraint (add, BAD_PC);
@@ -10928,7 +11033,7 @@ do_t_branch (void)
 {
   int opcode;
   int cond;
 {
   int opcode;
   int cond;
-  int reloc;
+  bfd_reloc_code_real_type reloc;
 
   cond = inst.cond;
   set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
 
   cond = inst.cond;
   set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
@@ -10958,6 +11063,10 @@ do_t_branch (void)
        reloc = BFD_RELOC_THUMB_PCREL_BRANCH25;
       else
        {
        reloc = BFD_RELOC_THUMB_PCREL_BRANCH25;
       else
        {
+         constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2),
+                     _("selected architecture does not support "
+                       "wide conditional branch instruction"));
+
          gas_assert (cond != 0xF);
          inst.instruction |= cond << 22;
          reloc = BFD_RELOC_THUMB_PCREL_BRANCH20;
          gas_assert (cond != 0xF);
          inst.instruction |= cond << 22;
          reloc = BFD_RELOC_THUMB_PCREL_BRANCH20;
@@ -11800,13 +11909,21 @@ do_t_mov_cmp (void)
            {
              inst.instruction = THUMB_OP16 (opcode);
              inst.instruction |= Rn << 8;
            {
              inst.instruction = THUMB_OP16 (opcode);
              inst.instruction |= Rn << 8;
-             if (inst.size_req == 2)
-               inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
-             else
-               inst.relax = opcode;
+             if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                 || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+               {
+                 if (inst.size_req == 2)
+                   inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+                 else
+                   inst.relax = opcode;
+               }
            }
          else
            {
            }
          else
            {
+             constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                         && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+                         THUMB1_RELOC_ONLY);
+
              inst.instruction = THUMB_OP32 (inst.instruction);
              inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
              inst.instruction |= Rn << r0off;
              inst.instruction = THUMB_OP32 (inst.instruction);
              inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
              inst.instruction |= Rn << r0off;
@@ -12002,12 +12119,12 @@ do_t_mov16 (void)
   top = (inst.instruction & 0x00800000) != 0;
   if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
     {
   top = (inst.instruction & 0x00800000) != 0;
   if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
     {
-      constraint (top, _(":lower16: not allowed this instruction"));
+      constraint (top, _(":lower16: not allowed in this instruction"));
       inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
     }
   else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
     {
       inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
     }
   else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
     {
-      constraint (!top, _(":upper16: not allowed this instruction"));
+      constraint (!top, _(":upper16: not allowed in this instruction"));
       inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
     }
 
       inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
     }
 
@@ -12461,7 +12578,7 @@ do_t_push_pop (void)
   if (inst.size_req != 4 && (mask & ~0xff) == 0)
     inst.instruction = THUMB_OP16 (inst.instruction) | mask;
   else if (inst.size_req != 4
   if (inst.size_req != 4 && (mask & ~0xff) == 0)
     inst.instruction = THUMB_OP16 (inst.instruction) | mask;
   else if (inst.size_req != 4
-          && (mask & ~0xff) == (1 << (inst.instruction == T_MNEM_push
+          && (mask & ~0xff) == (1U << (inst.instruction == T_MNEM_push
                                       ? REG_LR : REG_PC)))
     {
       inst.instruction = THUMB_OP16 (inst.instruction);
                                       ? REG_LR : REG_PC)))
     {
       inst.instruction = THUMB_OP16 (inst.instruction);
@@ -12974,7 +13091,7 @@ do_t_swi (void)
   if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6m))
     {
       if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_os)
   if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6m))
     {
       if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_os)
-         /* This only applies to the v6m howver, not later architectures.  */
+         /* This only applies to the v6m however, not later architectures.  */
          && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7))
        as_bad (_("SVC is not permitted on this architecture"));
       ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, arm_ext_os);
          && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7))
        as_bad (_("SVC is not permitted on this architecture"));
       ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, arm_ext_os);
@@ -13237,6 +13354,8 @@ NEON_ENC_TAB
   X(3, (D, Q, S), MIXED),              \
   X(4, (D, D, D, I), DOUBLE),          \
   X(4, (Q, Q, Q, I), QUAD),            \
   X(3, (D, Q, S), MIXED),              \
   X(4, (D, D, D, I), DOUBLE),          \
   X(4, (Q, Q, Q, I), QUAD),            \
+  X(4, (D, D, S, I), DOUBLE),          \
+  X(4, (Q, Q, S, I), QUAD),            \
   X(2, (F, F), SINGLE),                        \
   X(3, (F, F, F), SINGLE),             \
   X(2, (F, I), SINGLE),                        \
   X(2, (F, F), SINGLE),                        \
   X(3, (F, F, F), SINGLE),             \
   X(2, (F, I), SINGLE),                        \
@@ -13250,7 +13369,19 @@ NEON_ENC_TAB
   X(2, (S, R), SINGLE),                        \
   X(2, (R, S), SINGLE),                        \
   X(2, (F, R), SINGLE),                        \
   X(2, (S, R), SINGLE),                        \
   X(2, (R, S), SINGLE),                        \
   X(2, (F, R), SINGLE),                        \
-  X(2, (R, F), SINGLE)
+  X(2, (R, F), SINGLE),                        \
+/* Half float shape supported so far.  */\
+  X (2, (H, D), MIXED),                        \
+  X (2, (D, H), MIXED),                        \
+  X (2, (H, F), MIXED),                        \
+  X (2, (F, H), MIXED),                        \
+  X (2, (H, H), HALF),                 \
+  X (2, (H, R), HALF),                 \
+  X (2, (R, H), HALF),                 \
+  X (2, (H, I), HALF),                 \
+  X (3, (H, H, H), HALF),              \
+  X (3, (H, F, I), MIXED),             \
+  X (3, (F, H, I), MIXED)
 
 #define S2(A,B)                NS_##A##B
 #define S3(A,B,C)      NS_##A##B##C
 
 #define S2(A,B)                NS_##A##B
 #define S3(A,B,C)      NS_##A##B##C
@@ -13271,6 +13402,7 @@ enum neon_shape
 
 enum neon_shape_class
 {
 
 enum neon_shape_class
 {
+  SC_HALF,
   SC_SINGLE,
   SC_DOUBLE,
   SC_QUAD,
   SC_SINGLE,
   SC_DOUBLE,
   SC_QUAD,
@@ -13288,6 +13420,7 @@ static enum neon_shape_class neon_shape_class[] =
 
 enum neon_shape_el
 {
 
 enum neon_shape_el
 {
+  SE_H,
   SE_F,
   SE_D,
   SE_Q,
   SE_F,
   SE_D,
   SE_Q,
@@ -13300,6 +13433,7 @@ enum neon_shape_el
 /* Register widths of above.  */
 static unsigned neon_shape_el_size[] =
 {
 /* Register widths of above.  */
 static unsigned neon_shape_el_size[] =
 {
+  16,
   32,
   64,
   128,
   32,
   64,
   128,
@@ -13381,9 +13515,12 @@ enum neon_type_mask
 #define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
 #define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
 #define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
 #define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
 #define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
 #define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
-#define N_SUF_32   (N_SU_32 | N_F32)
+#define N_S_32     (N_S8 | N_S16 | N_S32)
+#define N_F_16_32  (N_F16 | N_F32)
+#define N_SUF_32   (N_SU_32 | N_F_16_32)
 #define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
 #define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
-#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F32)
+#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F16 | N_F32)
+#define N_F_ALL    (N_F16 | N_F32 | N_F64)
 
 /* Pass this as the first type argument to neon_check_type to ignore types
    altogether.  */
 
 /* Pass this as the first type argument to neon_check_type to ignore types
    altogether.  */
@@ -13425,11 +13562,56 @@ neon_select_shape (enum neon_shape shape, ...)
 
          switch (neon_shape_tab[shape].el[j])
            {
 
          switch (neon_shape_tab[shape].el[j])
            {
+             /* If a  .f16,  .16,  .u16,  .s16 type specifier is given over
+                a VFP single precision register operand, it's essentially
+                means only half of the register is used.
+
+                If the type specifier is given after the mnemonics, the
+                information is stored in inst.vectype.  If the type specifier
+                is given after register operand, the information is stored
+                in inst.operands[].vectype.
+
+                When there is only one type specifier, and all the register
+                operands are the same type of hardware register, the type
+                specifier applies to all register operands.
+
+                If no type specifier is given, the shape is inferred from
+                operand information.
+
+                for example:
+                vadd.f16 s0, s1, s2:           NS_HHH
+                vabs.f16 s0, s1:               NS_HH
+                vmov.f16 s0, r1:               NS_HR
+                vmov.f16 r0, s1:               NS_RH
+                vcvt.f16 r0, s1:               NS_RH
+                vcvt.f16.s32   s2, s2, #29:    NS_HFI
+                vcvt.f16.s32   s2, s2:         NS_HF
+             */
+           case SE_H:
+             if (!(inst.operands[j].isreg
+                   && inst.operands[j].isvec
+                   && inst.operands[j].issingle
+                   && !inst.operands[j].isquad
+                   && ((inst.vectype.elems == 1
+                        && inst.vectype.el[0].size == 16)
+                       || (inst.vectype.elems > 1
+                           && inst.vectype.el[j].size == 16)
+                       || (inst.vectype.elems == 0
+                           && inst.operands[j].vectype.type != NT_invtype
+                           && inst.operands[j].vectype.size == 16))))
+               matches = 0;
+             break;
+
            case SE_F:
              if (!(inst.operands[j].isreg
                    && inst.operands[j].isvec
                    && inst.operands[j].issingle
            case SE_F:
              if (!(inst.operands[j].isreg
                    && inst.operands[j].isvec
                    && inst.operands[j].issingle
-                   && !inst.operands[j].isquad))
+                   && !inst.operands[j].isquad
+                   && ((inst.vectype.elems == 1 && inst.vectype.el[0].size == 32)
+                       || (inst.vectype.elems > 1 && inst.vectype.el[j].size == 32)
+                       || (inst.vectype.elems == 0
+                           && (inst.operands[j].vectype.size == 32
+                               || inst.operands[j].vectype.type == NT_invtype)))))
                matches = 0;
              break;
 
                matches = 0;
              break;
 
@@ -13645,7 +13827,7 @@ el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
     *type = NT_untyped;
   else if ((mask & (N_P8 | N_P16 | N_P64)) != 0)
     *type = NT_poly;
     *type = NT_untyped;
   else if ((mask & (N_P8 | N_P16 | N_P64)) != 0)
     *type = NT_poly;
-  else if ((mask & (N_F16 | N_F32 | N_F64)) != 0)
+  else if ((mask & (N_F_ALL)) != 0)
     *type = NT_float;
   else
     return FAIL;
     *type = NT_float;
   else
     return FAIL;
@@ -13807,6 +13989,15 @@ neon_check_type (unsigned els, enum neon_shape ns, ...)
                  k_type = g_type;
                  k_size = g_size;
                  key_allowed = thisarg & ~N_KEY;
                  k_type = g_type;
                  k_size = g_size;
                  key_allowed = thisarg & ~N_KEY;
+
+                 /* Check architecture constraint on FP16 extension.  */
+                 if (k_size == 16
+                     && k_type == NT_float
+                     && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16))
+                   {
+                     inst.error = _(BAD_FP16);
+                     return badtype;
+                   }
                }
            }
          else
                }
            }
          else
@@ -13833,6 +14024,18 @@ neon_check_type (unsigned els, enum neon_shape ns, ...)
                  else
                    match = g_size;
 
                  else
                    match = g_size;
 
+                 /* FP16 will use a single precision register.  */
+                 if (regwidth == 32 && match == 16)
+                   {
+                     if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16))
+                       match = regwidth;
+                     else
+                       {
+                         inst.error = _(BAD_FP16);
+                         return badtype;
+                       }
+                   }
+
                  if (regwidth != match)
                    {
                      first_error (_("operand size must match register width"));
                  if (regwidth != match)
                    {
                      first_error (_("operand size must match register width"));
@@ -13924,12 +14127,16 @@ do_vfp_nsyn_add_sub (enum neon_shape rs)
 {
   int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
 
 {
   int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
 
-  if (rs == NS_FFF)
+  if (rs == NS_FFF || rs == NS_HHH)
     {
       if (is_add)
        do_vfp_nsyn_opcode ("fadds");
       else
        do_vfp_nsyn_opcode ("fsubs");
     {
       if (is_add)
        do_vfp_nsyn_opcode ("fadds");
       else
        do_vfp_nsyn_opcode ("fsubs");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
     }
   else
     {
@@ -13952,15 +14159,14 @@ try_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
   switch (args)
     {
     case 2:
   switch (args)
     {
     case 2:
-      rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
-      et = neon_check_type (2, rs,
-       N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+      rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_NULL);
+      et = neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY | N_VFP);
       break;
 
     case 3:
       break;
 
     case 3:
-      rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
-      et = neon_check_type (3, rs,
-       N_EQK | N_VFP, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+      rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_NULL);
+      et = neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
+                           N_F_ALL | N_KEY | N_VFP);
       break;
 
     default:
       break;
 
     default:
@@ -13982,12 +14188,16 @@ do_vfp_nsyn_mla_mls (enum neon_shape rs)
 {
   int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
 
 {
   int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
 
-  if (rs == NS_FFF)
+  if (rs == NS_FFF || rs == NS_HHH)
     {
       if (is_mla)
        do_vfp_nsyn_opcode ("fmacs");
       else
        do_vfp_nsyn_opcode ("fnmacs");
     {
       if (is_mla)
        do_vfp_nsyn_opcode ("fmacs");
       else
        do_vfp_nsyn_opcode ("fnmacs");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
     }
   else
     {
@@ -14003,12 +14213,16 @@ do_vfp_nsyn_fma_fms (enum neon_shape rs)
 {
   int is_fma = (inst.instruction & 0x0fffffff) == N_MNEM_vfma;
 
 {
   int is_fma = (inst.instruction & 0x0fffffff) == N_MNEM_vfma;
 
-  if (rs == NS_FFF)
+  if (rs == NS_FFF || rs == NS_HHH)
     {
       if (is_fma)
        do_vfp_nsyn_opcode ("ffmas");
       else
        do_vfp_nsyn_opcode ("ffnmas");
     {
       if (is_fma)
        do_vfp_nsyn_opcode ("ffmas");
       else
        do_vfp_nsyn_opcode ("ffnmas");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
     }
   else
     {
@@ -14022,8 +14236,14 @@ do_vfp_nsyn_fma_fms (enum neon_shape rs)
 static void
 do_vfp_nsyn_mul (enum neon_shape rs)
 {
 static void
 do_vfp_nsyn_mul (enum neon_shape rs)
 {
-  if (rs == NS_FFF)
-    do_vfp_nsyn_opcode ("fmuls");
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      do_vfp_nsyn_opcode ("fmuls");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
   else
     do_vfp_nsyn_opcode ("fmuld");
 }
   else
     do_vfp_nsyn_opcode ("fmuld");
 }
@@ -14032,14 +14252,18 @@ static void
 do_vfp_nsyn_abs_neg (enum neon_shape rs)
 {
   int is_neg = (inst.instruction & 0x80) != 0;
 do_vfp_nsyn_abs_neg (enum neon_shape rs)
 {
   int is_neg = (inst.instruction & 0x80) != 0;
-  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_VFP | N_KEY);
+  neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_VFP | N_KEY);
 
 
-  if (rs == NS_FF)
+  if (rs == NS_FF || rs == NS_HH)
     {
       if (is_neg)
        do_vfp_nsyn_opcode ("fnegs");
       else
        do_vfp_nsyn_opcode ("fabss");
     {
       if (is_neg)
        do_vfp_nsyn_opcode ("fnegs");
       else
        do_vfp_nsyn_opcode ("fabss");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HH)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
     }
   else
     {
@@ -14076,11 +14300,17 @@ do_vfp_nsyn_ldm_stm (int is_dbmode)
 static void
 do_vfp_nsyn_sqrt (void)
 {
 static void
 do_vfp_nsyn_sqrt (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
-  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+  enum neon_shape rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_NULL);
+  neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY | N_VFP);
 
 
-  if (rs == NS_FF)
-    do_vfp_nsyn_opcode ("fsqrts");
+  if (rs == NS_FF || rs == NS_HH)
+    {
+      do_vfp_nsyn_opcode ("fsqrts");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HH)
+       do_scalar_fp16_v82_encode ();
+    }
   else
     do_vfp_nsyn_opcode ("fsqrtd");
 }
   else
     do_vfp_nsyn_opcode ("fsqrtd");
 }
@@ -14088,12 +14318,18 @@ do_vfp_nsyn_sqrt (void)
 static void
 do_vfp_nsyn_div (void)
 {
 static void
 do_vfp_nsyn_div (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_NULL);
   neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
   neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
-    N_F32 | N_F64 | N_KEY | N_VFP);
+                  N_F_ALL | N_KEY | N_VFP);
 
 
-  if (rs == NS_FFF)
-    do_vfp_nsyn_opcode ("fdivs");
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      do_vfp_nsyn_opcode ("fdivs");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
   else
     do_vfp_nsyn_opcode ("fdivd");
 }
   else
     do_vfp_nsyn_opcode ("fdivd");
 }
@@ -14101,14 +14337,18 @@ do_vfp_nsyn_div (void)
 static void
 do_vfp_nsyn_nmul (void)
 {
 static void
 do_vfp_nsyn_nmul (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_NULL);
   neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
   neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
-    N_F32 | N_F64 | N_KEY | N_VFP);
+                  N_F_ALL | N_KEY | N_VFP);
 
 
-  if (rs == NS_FFF)
+  if (rs == NS_FFF || rs == NS_HHH)
     {
       NEON_ENCODE (SINGLE, inst);
       do_vfp_sp_dyadic ();
     {
       NEON_ENCODE (SINGLE, inst);
       do_vfp_sp_dyadic ();
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
     }
   else
     {
@@ -14116,17 +14356,19 @@ do_vfp_nsyn_nmul (void)
       do_vfp_dp_rd_rn_rm ();
     }
   do_vfp_cond_or_thumb ();
       do_vfp_dp_rd_rn_rm ();
     }
   do_vfp_cond_or_thumb ();
+
 }
 
 static void
 do_vfp_nsyn_cmp (void)
 {
 }
 
 static void
 do_vfp_nsyn_cmp (void)
 {
+  enum neon_shape rs;
   if (inst.operands[1].isreg)
     {
   if (inst.operands[1].isreg)
     {
-      enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
-      neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+      rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_NULL);
+      neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY | N_VFP);
 
 
-      if (rs == NS_FF)
+      if (rs == NS_FF || rs == NS_HH)
        {
          NEON_ENCODE (SINGLE, inst);
          do_vfp_sp_monadic ();
        {
          NEON_ENCODE (SINGLE, inst);
          do_vfp_sp_monadic ();
@@ -14139,8 +14381,8 @@ do_vfp_nsyn_cmp (void)
     }
   else
     {
     }
   else
     {
-      enum neon_shape rs = neon_select_shape (NS_FI, NS_DI, NS_NULL);
-      neon_check_type (2, rs, N_F32 | N_F64 | N_KEY | N_VFP, N_EQK);
+      rs = neon_select_shape (NS_HI, NS_FI, NS_DI, NS_NULL);
+      neon_check_type (2, rs, N_F_ALL | N_KEY | N_VFP, N_EQK);
 
       switch (inst.instruction & 0x0fffffff)
        {
 
       switch (inst.instruction & 0x0fffffff)
        {
@@ -14154,7 +14396,7 @@ do_vfp_nsyn_cmp (void)
          abort ();
        }
 
          abort ();
        }
 
-      if (rs == NS_FI)
+      if (rs == NS_FI || rs == NS_HI)
        {
          NEON_ENCODE (SINGLE, inst);
          do_vfp_sp_compare_z ();
        {
          NEON_ENCODE (SINGLE, inst);
          do_vfp_sp_compare_z ();
@@ -14166,6 +14408,10 @@ do_vfp_nsyn_cmp (void)
        }
     }
   do_vfp_cond_or_thumb ();
        }
     }
   do_vfp_cond_or_thumb ();
+
+  /* ARMv8.2 fp16 instruction.  */
+  if (rs == NS_HI || rs == NS_HH)
+    do_scalar_fp16_v82_encode ();
 }
 
 static void
 }
 
 static void
@@ -14183,6 +14429,11 @@ static void
 do_vfp_nsyn_push (void)
 {
   nsyn_insert_sp ();
 do_vfp_nsyn_push (void)
 {
   nsyn_insert_sp ();
+
+  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
+             _("register list must contain at least 1 and at most 16 "
+               "registers"));
+
   if (inst.operands[1].issingle)
     do_vfp_nsyn_opcode ("fstmdbs");
   else
   if (inst.operands[1].issingle)
     do_vfp_nsyn_opcode ("fstmdbs");
   else
@@ -14193,6 +14444,11 @@ static void
 do_vfp_nsyn_pop (void)
 {
   nsyn_insert_sp ();
 do_vfp_nsyn_pop (void)
 {
   nsyn_insert_sp ();
+
+  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
+             _("register list must contain at least 1 and at most 16 "
+               "registers"));
+
   if (inst.operands[1].issingle)
     do_vfp_nsyn_opcode ("fldmias");
   else
   if (inst.operands[1].issingle)
     do_vfp_nsyn_opcode ("fldmias");
   else
@@ -14563,7 +14819,7 @@ neon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
   if (et.type == NT_float)
     {
       NEON_ENCODE (FLOAT, inst);
   if (et.type == NT_float)
     {
       NEON_ENCODE (FLOAT, inst);
-      neon_three_same (neon_quad (rs), 0, -1);
+      neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
     }
   else
     {
     }
   else
     {
@@ -14678,13 +14934,15 @@ do_neon_addsub_if_i (void)
 static void
 neon_exchange_operands (void)
 {
 static void
 neon_exchange_operands (void)
 {
-  void *scratch = alloca (sizeof (inst.operands[0]));
   if (inst.operands[1].present)
     {
   if (inst.operands[1].present)
     {
+      void *scratch = xmalloc (sizeof (inst.operands[0]));
+
       /* Swap operands[1] and operands[2].  */
       memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
       inst.operands[1] = inst.operands[2];
       memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
       /* Swap operands[1] and operands[2].  */
       memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
       inst.operands[1] = inst.operands[2];
       memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
+      free (scratch);
     }
   else
     {
     }
   else
     {
@@ -14724,13 +14982,13 @@ neon_compare (unsigned regtypes, unsigned immtypes, int invert)
 static void
 do_neon_cmp (void)
 {
 static void
 do_neon_cmp (void)
 {
-  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
+  neon_compare (N_SUF_32, N_S_32 | N_F_16_32, FALSE);
 }
 
 static void
 do_neon_cmp_inv (void)
 {
 }
 
 static void
 do_neon_cmp_inv (void)
 {
-  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
+  neon_compare (N_SUF_32, N_S_32 | N_F_16_32, TRUE);
 }
 
 static void
 }
 
 static void
@@ -14809,7 +15067,7 @@ do_neon_mac_maybe_scalar (void)
     {
       enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
       struct neon_type_el et = neon_check_type (3, rs,
     {
       enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
       struct neon_type_el et = neon_check_type (3, rs,
-       N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
+       N_EQK, N_EQK, N_I16 | N_I32 | N_F_16_32 | N_KEY);
       NEON_ENCODE (SCALAR, inst);
       neon_mul_mac (et, neon_quad (rs));
     }
       NEON_ENCODE (SCALAR, inst);
       neon_mul_mac (et, neon_quad (rs));
     }
@@ -14858,7 +15116,7 @@ do_neon_mul (void)
   if (inst.operands[2].isscalar)
     do_neon_mac_maybe_scalar ();
   else
   if (inst.operands[2].isscalar)
     do_neon_mac_maybe_scalar ();
   else
-    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8, 0);
+    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F16 | N_F32 | N_P8, 0);
 }
 
 static void
 }
 
 static void
@@ -14883,13 +15141,46 @@ do_neon_qdmulh (void)
     }
 }
 
     }
 }
 
+static void
+do_neon_qrdmlah (void)
+{
+  /* Check we're on the correct architecture.  */
+  if (!mark_feature_used (&fpu_neon_ext_armv8))
+    inst.error =
+      _("instruction form not available on this architecture.");
+  else if (!mark_feature_used (&fpu_neon_ext_v8_1))
+    {
+      as_warn (_("this instruction implies use of ARMv8.1 AdvSIMD."));
+      record_feature_use (&fpu_neon_ext_v8_1);
+    }
+
+  if (inst.operands[2].isscalar)
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
+      NEON_ENCODE (SCALAR, inst);
+      neon_mul_mac (et, neon_quad (rs));
+    }
+  else
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
+      NEON_ENCODE (INTEGER, inst);
+      /* The U bit (rounding) comes from bit mask.  */
+      neon_three_same (neon_quad (rs), 0, et.size);
+    }
+}
+
 static void
 do_neon_fcmp_absolute (void)
 {
   enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
 static void
 do_neon_fcmp_absolute (void)
 {
   enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK,
+                                           N_F_16_32 | N_KEY);
   /* Size field comes from bit mask.  */
   /* Size field comes from bit mask.  */
-  neon_three_same (neon_quad (rs), 1, -1);
+  neon_three_same (neon_quad (rs), 1, et.size == 16 ? (int) et.size : -1);
 }
 
 static void
 }
 
 static void
@@ -14903,8 +15194,9 @@ static void
 do_neon_step (void)
 {
   enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
 do_neon_step (void)
 {
   enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
-  neon_three_same (neon_quad (rs), 0, -1);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK,
+                                           N_F_16_32 | N_KEY);
+  neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
 }
 
 static void
 }
 
 static void
@@ -14920,7 +15212,7 @@ do_neon_abs_neg (void)
     return;
 
   rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
     return;
 
   rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
+  et = neon_check_type (2, rs, N_EQK, N_S_32 | N_F_16_32 | N_KEY);
 
   inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
   inst.instruction |= HI1 (inst.operands[0].reg) << 22;
 
   inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
   inst.instruction |= HI1 (inst.operands[0].reg) << 22;
@@ -15129,8 +15421,19 @@ do_neon_shll (void)
   CVT_VAR (f32_s32, N_F32, N_S32, whole_reg,   "fsltos", "fsitos", NULL)      \
   CVT_VAR (f32_u32, N_F32, N_U32, whole_reg,   "fultos", "fuitos", NULL)      \
   /* Half-precision conversions.  */                                         \
   CVT_VAR (f32_s32, N_F32, N_S32, whole_reg,   "fsltos", "fsitos", NULL)      \
   CVT_VAR (f32_u32, N_F32, N_U32, whole_reg,   "fultos", "fuitos", NULL)      \
   /* Half-precision conversions.  */                                         \
+  CVT_VAR (s16_f16, N_S16, N_F16 | N_KEY, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (u16_f16, N_U16, N_F16 | N_KEY, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (f16_s16, N_F16 | N_KEY, N_S16, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (f16_u16, N_F16 | N_KEY, N_U16, whole_reg, NULL, NULL, NULL)       \
   CVT_VAR (f32_f16, N_F32, N_F16, whole_reg,   NULL,     NULL,     NULL)      \
   CVT_VAR (f16_f32, N_F16, N_F32, whole_reg,   NULL,     NULL,     NULL)      \
   CVT_VAR (f32_f16, N_F32, N_F16, whole_reg,   NULL,     NULL,     NULL)      \
   CVT_VAR (f16_f32, N_F16, N_F32, whole_reg,   NULL,     NULL,     NULL)      \
+  /* New VCVT instructions introduced by ARMv8.2 fp16 extension.             \
+     Compared with single/double precision variants, only the co-processor    \
+     field is different, so the encoding flow is reused here.  */            \
+  CVT_VAR (f16_s32, N_F16 | N_KEY, N_S32, N_VFP, "fsltos", "fsitos", NULL)    \
+  CVT_VAR (f16_u32, N_F16 | N_KEY, N_U32, N_VFP, "fultos", "fuitos", NULL)    \
+  CVT_VAR (u32_f16, N_U32, N_F16 | N_KEY, N_VFP, "ftouls", "ftouis", "ftouizs")\
+  CVT_VAR (s32_f16, N_S32, N_F16 | N_KEY, N_VFP, "ftosls", "ftosis", "ftosizs")\
   /* VFP instructions.  */                                                   \
   CVT_VAR (f32_f64, N_F32, N_F64, N_VFP,       NULL,     "fcvtsd", NULL)      \
   CVT_VAR (f64_f32, N_F64, N_F32, N_VFP,       NULL,     "fcvtds", NULL)      \
   /* VFP instructions.  */                                                   \
   CVT_VAR (f32_f64, N_F32, N_F64, N_VFP,       NULL,     "fcvtsd", NULL)      \
   CVT_VAR (f64_f32, N_F64, N_F32, N_VFP,       NULL,     "fcvtds", NULL)      \
@@ -15205,7 +15508,8 @@ do_vfp_nsyn_cvt (enum neon_shape rs, enum neon_cvt_flavour flavour)
 {
   const char *opname = 0;
 
 {
   const char *opname = 0;
 
-  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
+  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI
+      || rs == NS_FHI || rs == NS_HFI)
     {
       /* Conversions with immediate bitshift.  */
       const char *enc[] =
     {
       /* Conversions with immediate bitshift.  */
       const char *enc[] =
@@ -15242,12 +15546,19 @@ do_vfp_nsyn_cvt (enum neon_shape rs, enum neon_cvt_flavour flavour)
 
   if (opname)
     do_vfp_nsyn_opcode (opname);
 
   if (opname)
     do_vfp_nsyn_opcode (opname);
+
+  /* ARMv8.2 fp16 VCVT instruction.  */
+  if (flavour == neon_cvt_flavour_s32_f16
+      || flavour == neon_cvt_flavour_u32_f16
+      || flavour == neon_cvt_flavour_f16_u32
+      || flavour == neon_cvt_flavour_f16_s32)
+    do_scalar_fp16_v82_encode ();
 }
 
 static void
 do_vfp_nsyn_cvtz (void)
 {
 }
 
 static void
 do_vfp_nsyn_cvtz (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_FH, NS_FF, NS_FD, NS_NULL);
   enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
   const char *enc[] =
     {
   enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
   const char *enc[] =
     {
@@ -15275,6 +15586,11 @@ do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
     constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
                _(BAD_FPU));
 
     constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
                _(BAD_FPU));
 
+  if (flavour == neon_cvt_flavour_s32_f16
+      || flavour == neon_cvt_flavour_u32_f16)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16),
+               _(BAD_FP16));
+
   set_it_insn_type (OUTSIDE_IT_INSN);
 
   switch (flavour)
   set_it_insn_type (OUTSIDE_IT_INSN);
 
   switch (flavour)
@@ -15287,6 +15603,10 @@ do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
       sz = 0;
       op = 1;
       break;
       sz = 0;
       op = 1;
       break;
+    case neon_cvt_flavour_s32_f16:
+      sz = 0;
+      op = 1;
+      break;
     case neon_cvt_flavour_u32_f64:
       sz = 1;
       op = 0;
     case neon_cvt_flavour_u32_f64:
       sz = 1;
       op = 0;
@@ -15295,6 +15615,10 @@ do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
       sz = 0;
       op = 0;
       break;
       sz = 0;
       op = 0;
       break;
+    case neon_cvt_flavour_u32_f16:
+      sz = 0;
+      op = 0;
+      break;
     default:
       first_error (_("invalid instruction shape"));
       return;
     default:
       first_error (_("invalid instruction shape"));
       return;
@@ -15313,6 +15637,11 @@ do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
   encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
   encode_arm_vfp_reg (inst.operands[1].reg, sz == 1 ? VFP_REG_Dm : VFP_REG_Sm);
   inst.instruction |= sz << 8;
   encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
   encode_arm_vfp_reg (inst.operands[1].reg, sz == 1 ? VFP_REG_Dm : VFP_REG_Sm);
   inst.instruction |= sz << 8;
+
+  /* ARMv8.2 fp16 VCVT instruction.  */
+  if (flavour == neon_cvt_flavour_s32_f16
+      ||flavour == neon_cvt_flavour_u32_f16)
+    do_scalar_fp16_v82_encode ();
   inst.instruction |= op << 7;
   inst.instruction |= rm << 16;
   inst.instruction |= 0xf0000000;
   inst.instruction |= op << 7;
   inst.instruction |= rm << 16;
   inst.instruction |= 0xf0000000;
@@ -15323,13 +15652,20 @@ static void
 do_neon_cvt_1 (enum neon_cvt_mode mode)
 {
   enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
 do_neon_cvt_1 (enum neon_cvt_mode mode)
 {
   enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
-    NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ, NS_NULL);
+                                         NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ,
+                                         NS_FH, NS_HF, NS_FHI, NS_HFI,
+                                         NS_NULL);
   enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
 
   enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
 
+  if (flavour == neon_cvt_flavour_invalid)
+    return;
+
   /* PR11109: Handle round-to-zero for VCVT conversions.  */
   if (mode == neon_cvt_mode_z
       && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_vfp_v2)
   /* PR11109: Handle round-to-zero for VCVT conversions.  */
   if (mode == neon_cvt_mode_z
       && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_vfp_v2)
-      && (flavour == neon_cvt_flavour_s32_f32
+      && (flavour == neon_cvt_flavour_s16_f16
+         || flavour == neon_cvt_flavour_u16_f16
+         || flavour == neon_cvt_flavour_s32_f32
          || flavour == neon_cvt_flavour_u32_f32
          || flavour == neon_cvt_flavour_s32_f64
          || flavour == neon_cvt_flavour_u32_f64)
          || flavour == neon_cvt_flavour_u32_f32
          || flavour == neon_cvt_flavour_s32_f64
          || flavour == neon_cvt_flavour_u32_f64)
@@ -15339,6 +15675,18 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
       return;
     }
 
       return;
     }
 
+  /* ARMv8.2 fp16 VCVT conversions.  */
+  if (mode == neon_cvt_mode_z
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16)
+      && (flavour == neon_cvt_flavour_s32_f16
+         || flavour == neon_cvt_flavour_u32_f16)
+      && (rs == NS_FH))
+    {
+      do_vfp_nsyn_cvtz ();
+      do_scalar_fp16_v82_encode ();
+      return;
+    }
+
   /* VFP rather than Neon conversions.  */
   if (flavour >= neon_cvt_flavour_first_fp)
     {
   /* VFP rather than Neon conversions.  */
   if (flavour >= neon_cvt_flavour_first_fp)
     {
@@ -15356,7 +15704,8 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
     case NS_QQI:
       {
        unsigned immbits;
     case NS_QQI:
       {
        unsigned immbits;
-       unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
+       unsigned enctab[] = {0x0000100, 0x1000100, 0x0, 0x1000000,
+                            0x0000100, 0x1000100, 0x0, 0x1000000};
 
        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
          return;
 
        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
          return;
@@ -15365,7 +15714,6 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
           integer conversion.  */
        if (inst.operands[2].present && inst.operands[2].imm == 0)
          goto int_encode;
           integer conversion.  */
        if (inst.operands[2].present && inst.operands[2].imm == 0)
          goto int_encode;
-       immbits = 32 - inst.operands[2].imm;
        NEON_ENCODE (IMMED, inst);
        if (flavour != neon_cvt_flavour_invalid)
          inst.instruction |= enctab[flavour];
        NEON_ENCODE (IMMED, inst);
        if (flavour != neon_cvt_flavour_invalid)
          inst.instruction |= enctab[flavour];
@@ -15375,7 +15723,19 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
        inst.instruction |= neon_quad (rs) << 6;
        inst.instruction |= 1 << 21;
        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
        inst.instruction |= neon_quad (rs) << 6;
        inst.instruction |= 1 << 21;
-       inst.instruction |= immbits << 16;
+       if (flavour < neon_cvt_flavour_s16_f16)
+         {
+           inst.instruction |= 1 << 21;
+           immbits = 32 - inst.operands[2].imm;
+           inst.instruction |= immbits << 16;
+         }
+       else
+         {
+           inst.instruction |= 3 << 20;
+           immbits = 16 - inst.operands[2].imm;
+           inst.instruction |= immbits << 16;
+           inst.instruction &= ~(1 << 9);
+         }
 
        neon_dp_fixup (&inst);
       }
 
        neon_dp_fixup (&inst);
       }
@@ -15396,8 +15756,14 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
          inst.instruction |= LOW4 (inst.operands[1].reg);
          inst.instruction |= HI1 (inst.operands[1].reg) << 5;
          inst.instruction |= neon_quad (rs) << 6;
          inst.instruction |= LOW4 (inst.operands[1].reg);
          inst.instruction |= HI1 (inst.operands[1].reg) << 5;
          inst.instruction |= neon_quad (rs) << 6;
-         inst.instruction |= (flavour == neon_cvt_flavour_u32_f32) << 7;
+         inst.instruction |= (flavour == neon_cvt_flavour_u16_f16
+                              || flavour == neon_cvt_flavour_u32_f32) << 7;
          inst.instruction |= mode << 8;
          inst.instruction |= mode << 8;
+         if (flavour == neon_cvt_flavour_u16_f16
+             || flavour == neon_cvt_flavour_s16_f16)
+           /* Mask off the original size bits and reencode them.  */
+           inst.instruction = ((inst.instruction & 0xfff3ffff) | (1 << 18));
+
          if (thumb_mode)
            inst.instruction |= 0xfc000000;
          else
          if (thumb_mode)
            inst.instruction |= 0xfc000000;
          else
@@ -15407,7 +15773,8 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
        {
     int_encode:
          {
        {
     int_encode:
          {
-           unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
+           unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080,
+                                 0x100, 0x180, 0x0, 0x080};
 
            NEON_ENCODE (INTEGER, inst);
 
 
            NEON_ENCODE (INTEGER, inst);
 
@@ -15422,7 +15789,12 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
            inst.instruction |= LOW4 (inst.operands[1].reg);
            inst.instruction |= HI1 (inst.operands[1].reg) << 5;
            inst.instruction |= neon_quad (rs) << 6;
            inst.instruction |= LOW4 (inst.operands[1].reg);
            inst.instruction |= HI1 (inst.operands[1].reg) << 5;
            inst.instruction |= neon_quad (rs) << 6;
-           inst.instruction |= 2 << 18;
+           if (flavour >= neon_cvt_flavour_s16_f16
+               && flavour <= neon_cvt_flavour_f16_u16)
+             /* Half precision.  */
+             inst.instruction |= 1 << 18;
+           else
+             inst.instruction |= 2 << 18;
 
            neon_dp_fixup (&inst);
          }
 
            neon_dp_fixup (&inst);
          }
@@ -15523,7 +15895,8 @@ do_neon_cvttb_2 (bfd_boolean t, bfd_boolean to, bfd_boolean is_double)
 static void
 do_neon_cvttb_1 (bfd_boolean t)
 {
 static void
 do_neon_cvttb_1 (bfd_boolean t)
 {
-  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_DF, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_HF, NS_HD, NS_FH, NS_FF, NS_FD,
+                                         NS_DF, NS_DH, NS_NULL);
 
   if (rs == NS_NULL)
     return;
 
   if (rs == NS_NULL)
     return;
@@ -15903,8 +16276,9 @@ static void
 do_neon_mov (void)
 {
   enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
 do_neon_mov (void)
 {
   enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
-    NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR, NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
-    NS_NULL);
+                                         NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR,
+                                         NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
+                                         NS_HR, NS_RH, NS_HI, NS_NULL);
   struct neon_type_el et;
   const char *ldconst = 0;
 
   struct neon_type_el et;
   const char *ldconst = 0;
 
@@ -16082,6 +16456,7 @@ do_neon_mov (void)
       do_vfp_nsyn_opcode ("fcpys");
       break;
 
       do_vfp_nsyn_opcode ("fcpys");
       break;
 
+    case NS_HI:
     case NS_FI:  /* case 10 (fconsts).  */
       ldconst = "fconsts";
       encode_fconstd:
     case NS_FI:  /* case 10 (fconsts).  */
       ldconst = "fconsts";
       encode_fconstd:
@@ -16089,17 +16464,29 @@ do_neon_mov (void)
        {
          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
          do_vfp_nsyn_opcode (ldconst);
        {
          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
          do_vfp_nsyn_opcode (ldconst);
+
+         /* ARMv8.2 fp16 vmov.f16 instruction.  */
+         if (rs == NS_HI)
+           do_scalar_fp16_v82_encode ();
        }
       else
        first_error (_("immediate out of range"));
       break;
 
        }
       else
        first_error (_("immediate out of range"));
       break;
 
+    case NS_RH:
     case NS_RF:  /* case 12 (fmrs).  */
       do_vfp_nsyn_opcode ("fmrs");
     case NS_RF:  /* case 12 (fmrs).  */
       do_vfp_nsyn_opcode ("fmrs");
+      /* ARMv8.2 fp16 vmov.f16 instruction.  */
+      if (rs == NS_RH)
+       do_scalar_fp16_v82_encode ();
       break;
 
       break;
 
+    case NS_HR:
     case NS_FR:  /* case 13 (fmsr).  */
       do_vfp_nsyn_opcode ("fmsr");
     case NS_FR:  /* case 13 (fmsr).  */
       do_vfp_nsyn_opcode ("fmsr");
+      /* ARMv8.2 fp16 vmov.f16 instruction.  */
+      if (rs == NS_HR)
+       do_scalar_fp16_v82_encode ();
       break;
 
     /* The encoders for the fmrrs and fmsrr instructions expect three operands
       break;
 
     /* The encoders for the fmrrs and fmsrr instructions expect three operands
@@ -16155,6 +16542,21 @@ do_neon_rshift_round_imm (void)
                  et.size - imm);
 }
 
                  et.size - imm);
 }
 
+static void
+do_neon_movhf (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_HH, NS_NULL);
+  constraint (rs != NS_HH, _("invalid suffix"));
+
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+             _(BAD_FPU));
+
+  do_vfp_sp_monadic ();
+
+  inst.is_neon = 1;
+  inst.instruction |= 0xf0000000;
+}
+
 static void
 do_neon_movl (void)
 {
 static void
 do_neon_movl (void)
 {
@@ -16215,7 +16617,7 @@ do_neon_recip_est (void)
 {
   enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
   struct neon_type_el et = neon_check_type (2, rs,
 {
   enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
   struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
+    N_EQK | N_FLT, N_F_16_32 | N_U32 | N_KEY);
   inst.instruction |= (et.type == NT_float) << 8;
   neon_two_same (neon_quad (rs), 1, et.size);
 }
   inst.instruction |= (et.type == NT_float) << 8;
   neon_two_same (neon_quad (rs), 1, et.size);
 }
@@ -16331,6 +16733,10 @@ do_neon_ldr_str (void)
        do_vfp_nsyn_opcode ("flds");
       else
        do_vfp_nsyn_opcode ("fsts");
        do_vfp_nsyn_opcode ("flds");
       else
        do_vfp_nsyn_opcode ("fsts");
+
+      /* ARMv8.2 vldr.16/vstr.16 instruction.  */
+      if (inst.vectype.el[0].size == 16)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
     }
   else
     {
@@ -16416,18 +16822,18 @@ do_neon_ld_st_interleave (void)
    values, terminated with -1.  */
 
 static int
    values, terminated with -1.  */
 
 static int
-neon_alignment_bit (int size, int align, int *do_align, ...)
+neon_alignment_bit (int size, int align, int *do_alignment, ...)
 {
   va_list ap;
   int result = FAIL, thissize, thisalign;
 
   if (!inst.operands[1].immisalign)
     {
 {
   va_list ap;
   int result = FAIL, thissize, thisalign;
 
   if (!inst.operands[1].immisalign)
     {
-      *do_align = 0;
+      *do_alignment = 0;
       return SUCCESS;
     }
 
       return SUCCESS;
     }
 
-  va_start (ap, do_align);
+  va_start (ap, do_alignment);
 
   do
     {
 
   do
     {
@@ -16444,7 +16850,7 @@ neon_alignment_bit (int size, int align, int *do_align, ...)
   va_end (ap);
 
   if (result == SUCCESS)
   va_end (ap);
 
   if (result == SUCCESS)
-    *do_align = 1;
+    *do_alignment = 1;
   else
     first_error (_("unsupported alignment for instruction"));
 
   else
     first_error (_("unsupported alignment for instruction"));
 
@@ -16455,7 +16861,7 @@ static void
 do_neon_ld_st_lane (void)
 {
   struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
 do_neon_ld_st_lane (void)
 {
   struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
-  int align_good, do_align = 0;
+  int align_good, do_alignment = 0;
   int logsize = neon_logbits (et.size);
   int align = inst.operands[1].imm >> 8;
   int n = (inst.instruction >> 8) & 3;
   int logsize = neon_logbits (et.size);
   int align = inst.operands[1].imm >> 8;
   int n = (inst.instruction >> 8) & 3;
@@ -16475,11 +16881,11 @@ do_neon_ld_st_lane (void)
   switch (n)
     {
     case 0:  /* VLD1 / VST1.  */
   switch (n)
     {
     case 0:  /* VLD1 / VST1.  */
-      align_good = neon_alignment_bit (et.size, align, &do_align, 16, 16,
+      align_good = neon_alignment_bit (et.size, align, &do_alignment, 16, 16,
                                       32, 32, -1);
       if (align_good == FAIL)
        return;
                                       32, 32, -1);
       if (align_good == FAIL)
        return;
-      if (do_align)
+      if (do_alignment)
        {
          unsigned alignbits = 0;
          switch (et.size)
        {
          unsigned alignbits = 0;
          switch (et.size)
@@ -16493,11 +16899,11 @@ do_neon_ld_st_lane (void)
       break;
 
     case 1:  /* VLD2 / VST2.  */
       break;
 
     case 1:  /* VLD2 / VST2.  */
-      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 16, 16, 32,
-                                      32, 64, -1);
+      align_good = neon_alignment_bit (et.size, align, &do_alignment, 8, 16,
+                     16, 32, 32, 64, -1);
       if (align_good == FAIL)
        return;
       if (align_good == FAIL)
        return;
-      if (do_align)
+      if (do_alignment)
        inst.instruction |= 1 << 4;
       break;
 
        inst.instruction |= 1 << 4;
       break;
 
@@ -16507,11 +16913,11 @@ do_neon_ld_st_lane (void)
       break;
 
     case 3:  /* VLD4 / VST4.  */
       break;
 
     case 3:  /* VLD4 / VST4.  */
-      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
+      align_good = neon_alignment_bit (et.size, align, &do_alignment, 8, 32,
                                       16, 64, 32, 64, 32, 128, -1);
       if (align_good == FAIL)
        return;
                                       16, 64, 32, 64, 32, 128, -1);
       if (align_good == FAIL)
        return;
-      if (do_align)
+      if (do_alignment)
        {
          unsigned alignbits = 0;
          switch (et.size)
        {
          unsigned alignbits = 0;
          switch (et.size)
@@ -16542,7 +16948,7 @@ static void
 do_neon_ld_dup (void)
 {
   struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
 do_neon_ld_dup (void)
 {
   struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
-  int align_good, do_align = 0;
+  int align_good, do_alignment = 0;
 
   if (et.type == NT_invtype)
     return;
 
   if (et.type == NT_invtype)
     return;
@@ -16552,7 +16958,7 @@ do_neon_ld_dup (void)
     case 0:  /* VLD1.  */
       gas_assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
       align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
     case 0:  /* VLD1.  */
       gas_assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
       align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
-                                      &do_align, 16, 16, 32, 32, -1);
+                                      &do_alignment, 16, 16, 32, 32, -1);
       if (align_good == FAIL)
        return;
       switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
       if (align_good == FAIL)
        return;
       switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
@@ -16566,7 +16972,8 @@ do_neon_ld_dup (void)
 
     case 1:  /* VLD2.  */
       align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
 
     case 1:  /* VLD2.  */
       align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
-                                      &do_align, 8, 16, 16, 32, 32, 64, -1);
+                                      &do_alignment, 8, 16, 16, 32, 32, 64,
+                                      -1);
       if (align_good == FAIL)
        return;
       constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
       if (align_good == FAIL)
        return;
       constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
@@ -16589,7 +16996,7 @@ do_neon_ld_dup (void)
     case 3:  /* VLD4.  */
       {
        int align = inst.operands[1].imm >> 8;
     case 3:  /* VLD4.  */
       {
        int align = inst.operands[1].imm >> 8;
-       align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
+       align_good = neon_alignment_bit (et.size, align, &do_alignment, 8, 32,
                                         16, 64, 32, 64, 32, 128, -1);
        if (align_good == FAIL)
          return;
                                         16, 64, 32, 64, 32, 128, -1);
        if (align_good == FAIL)
          return;
@@ -16607,7 +17014,7 @@ do_neon_ld_dup (void)
     default: ;
     }
 
     default: ;
     }
 
-  inst.instruction |= do_align << 4;
+  inst.instruction |= do_alignment << 4;
 }
 
 /* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
 }
 
 /* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
@@ -16688,8 +17095,14 @@ do_vfp_nsyn_fpv8 (enum neon_shape rs)
 
   NEON_ENCODE (FPV8, inst);
 
 
   NEON_ENCODE (FPV8, inst);
 
-  if (rs == NS_FFF)
-    do_vfp_sp_dyadic ();
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      do_vfp_sp_dyadic ();
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
   else
     do_vfp_dp_rd_rn_rm ();
 
   else
     do_vfp_dp_rd_rn_rm ();
 
@@ -16719,13 +17132,13 @@ do_vmaxnm (void)
   if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
     return;
 
   if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
     return;
 
-  neon_dyadic_misc (NT_untyped, N_F32, 0);
+  neon_dyadic_misc (NT_untyped, N_F_16_32, 0);
 }
 
 static void
 do_vrint_1 (enum neon_cvt_mode mode)
 {
 }
 
 static void
 do_vrint_1 (enum neon_cvt_mode mode)
 {
-  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_QQ, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_QQ, NS_NULL);
   struct neon_type_el et;
 
   if (rs == NS_NULL)
   struct neon_type_el et;
 
   if (rs == NS_NULL)
@@ -16737,7 +17150,8 @@ do_vrint_1 (enum neon_cvt_mode mode)
     constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
                _(BAD_FPU));
 
     constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
                _(BAD_FPU));
 
-  et = neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+  et = neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY
+                       | N_VFP);
   if (et.type != NT_invtype)
     {
       /* VFP encodings.  */
   if (et.type != NT_invtype)
     {
       /* VFP encodings.  */
@@ -16746,7 +17160,7 @@ do_vrint_1 (enum neon_cvt_mode mode)
        set_it_insn_type (OUTSIDE_IT_INSN);
 
       NEON_ENCODE (FPV8, inst);
        set_it_insn_type (OUTSIDE_IT_INSN);
 
       NEON_ENCODE (FPV8, inst);
-      if (rs == NS_FF)
+      if (rs == NS_FF || rs == NS_HH)
        do_vfp_sp_monadic ();
       else
        do_vfp_dp_rd_rm ();
        do_vfp_sp_monadic ();
       else
        do_vfp_dp_rd_rm ();
@@ -16765,12 +17179,16 @@ do_vrint_1 (enum neon_cvt_mode mode)
 
       inst.instruction |= (rs == NS_DD) << 8;
       do_vfp_cond_or_thumb ();
 
       inst.instruction |= (rs == NS_DD) << 8;
       do_vfp_cond_or_thumb ();
+
+      /* ARMv8.2 fp16 vrint instruction.  */
+      if (rs == NS_HH)
+      do_scalar_fp16_v82_encode ();
     }
   else
     {
       /* Neon encodings (or something broken...).  */
       inst.error = NULL;
     }
   else
     {
       /* Neon encodings (or something broken...).  */
       inst.error = NULL;
-      et = neon_check_type (2, rs, N_EQK, N_F32 | N_KEY);
+      et = neon_check_type (2, rs, N_EQK, N_F_16_32 | N_KEY);
 
       if (et.type == NT_invtype)
        return;
 
       if (et.type == NT_invtype)
        return;
@@ -16786,6 +17204,10 @@ do_vrint_1 (enum neon_cvt_mode mode)
       inst.instruction |= LOW4 (inst.operands[1].reg);
       inst.instruction |= HI1 (inst.operands[1].reg) << 5;
       inst.instruction |= neon_quad (rs) << 6;
       inst.instruction |= LOW4 (inst.operands[1].reg);
       inst.instruction |= HI1 (inst.operands[1].reg) << 5;
       inst.instruction |= neon_quad (rs) << 6;
+      /* Mask off the original size bits and reencode them.  */
+      inst.instruction = ((inst.instruction & 0xfff3ffff)
+                         | neon_logbits (et.size) << 18);
+
       switch (mode)
        {
        case neon_cvt_mode_z: inst.instruction |= 3 << 7; break;
       switch (mode)
        {
        case neon_cvt_mode_z: inst.instruction |= 3 << 7; break;
@@ -16847,6 +17269,80 @@ do_vrintm (void)
   do_vrint_1 (neon_cvt_mode_m);
 }
 
   do_vrint_1 (neon_cvt_mode_m);
 }
 
+static unsigned
+neon_scalar_for_vcmla (unsigned opnd, unsigned elsize)
+{
+  unsigned regno = NEON_SCALAR_REG (opnd);
+  unsigned elno = NEON_SCALAR_INDEX (opnd);
+
+  if (elsize == 16 && elno < 2 && regno < 16)
+    return regno | (elno << 4);
+  else if (elsize == 32 && elno == 0)
+    return regno;
+
+  first_error (_("scalar out of range"));
+  return 0;
+}
+
+static void
+do_vcmla (void)
+{
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
+             _(BAD_FPU));
+  constraint (inst.reloc.exp.X_op != O_constant, _("expression too complex"));
+  unsigned rot = inst.reloc.exp.X_add_number;
+  constraint (rot != 0 && rot != 90 && rot != 180 && rot != 270,
+             _("immediate out of range"));
+  rot /= 90;
+  if (inst.operands[2].isscalar)
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDSI, NS_QQSI, NS_NULL);
+      unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
+                                      N_KEY | N_F16 | N_F32).size;
+      unsigned m = neon_scalar_for_vcmla (inst.operands[2].reg, size);
+      inst.is_neon = 1;
+      inst.instruction = 0xfe000800;
+      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 |= LOW4 (m);
+      inst.instruction |= HI1 (m) << 5;
+      inst.instruction |= neon_quad (rs) << 6;
+      inst.instruction |= rot << 20;
+      inst.instruction |= (size == 32) << 23;
+    }
+  else
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
+      unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
+                                      N_KEY | N_F16 | N_F32).size;
+      neon_three_same (neon_quad (rs), 0, -1);
+      inst.instruction &= 0x00ffffff; /* Undo neon_dp_fixup.  */
+      inst.instruction |= 0xfc200800;
+      inst.instruction |= rot << 23;
+      inst.instruction |= (size == 32) << 20;
+    }
+}
+
+static void
+do_vcadd (void)
+{
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
+             _(BAD_FPU));
+  constraint (inst.reloc.exp.X_op != O_constant, _("expression too complex"));
+  unsigned rot = inst.reloc.exp.X_add_number;
+  constraint (rot != 90 && rot != 270, _("immediate out of range"));
+  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
+  unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
+                                  N_KEY | N_F16 | N_F32).size;
+  neon_three_same (neon_quad (rs), 0, -1);
+  inst.instruction &= 0x00ffffff; /* Undo neon_dp_fixup.  */
+  inst.instruction |= 0xfc800800;
+  inst.instruction |= (rot == 270) << 24;
+  inst.instruction |= (size == 32) << 20;
+}
+
 /* Crypto v1 instructions.  */
 static void
 do_crypto_2op_1 (unsigned elttype, int op)
 /* Crypto v1 instructions.  */
 static void
 do_crypto_2op_1 (unsigned elttype, int op)
@@ -17028,6 +17524,16 @@ do_crc32cw (void)
   do_crc32_1 (1, 2);
 }
 
   do_crc32_1 (1, 2);
 }
 
+static void
+do_vjcvt (void)
+{
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+             _(BAD_FPU));
+  neon_check_type (2, NS_FD, N_S32, N_F64);
+  do_vfp_sp_dp_cvt ();
+  do_vfp_cond_or_thumb ();
+}
+
 \f
 /* Overall per-instruction processing. */
 
 \f
 /* Overall per-instruction processing. */
 
@@ -17382,7 +17888,7 @@ opcode_lookup (char **str)
        case OT_odd_infix_unc:
          if (!unified_syntax)
            return 0;
        case OT_odd_infix_unc:
          if (!unified_syntax)
            return 0;
-         /* else fall through */
+         /* Fall through.  */
 
        case OT_csuffix:
        case OT_csuffixF:
 
        case OT_csuffix:
        case OT_csuffixF:
@@ -17505,7 +18011,7 @@ now_it_add_mask (int cond)
      set_it_insn_type_last ()           ditto
      in_it_block ()                     ditto
      it_fsm_post_encode ()              from md_assemble ()
      set_it_insn_type_last ()           ditto
      in_it_block ()                     ditto
      it_fsm_post_encode ()              from md_assemble ()
-     force_automatic_it_block_close ()  from label habdling functions
+     force_automatic_it_block_close ()  from label handling functions
 
    Rationale:
      1) md_assemble () calls it_fsm_pre_encode () before calling tencode (),
 
    Rationale:
      1) md_assemble () calls it_fsm_pre_encode () before calling tencode (),
@@ -17538,7 +18044,7 @@ now_it_add_mask (int cond)
        for covering other cases.
 
        Calling handle_it_state () may not transition the IT block state to
        for covering other cases.
 
        Calling handle_it_state () may not transition the IT block state to
-       OUTSIDE_IT_BLOCK immediatelly, since the (current) state could be
+       OUTSIDE_IT_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
        after the tencode () function: that's what it_fsm_post_encode () does.
        still queried. Instead, if the FSM determines that the state should
        be transitioned to OUTSIDE_IT_BLOCK, a flag is marked to be closed
        after the tencode () function: that's what it_fsm_post_encode () does.
@@ -17592,7 +18098,7 @@ handle_it_state (void)
          else
            {
              if ((implicit_it_mode & IMPLICIT_IT_MODE_THUMB)
          else
            {
              if ((implicit_it_mode & IMPLICIT_IT_MODE_THUMB)
-                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2))
+                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
                {
                  /* Automatically generate the IT instruction.  */
                  new_automatic_it_block (inst.cond);
                {
                  /* Automatically generate the IT instruction.  */
                  new_automatic_it_block (inst.cond);
@@ -17629,7 +18135,7 @@ handle_it_state (void)
       switch (inst.it_insn_type)
        {
        case OUTSIDE_IT_INSN:
       switch (inst.it_insn_type)
        {
        case OUTSIDE_IT_INSN:
-         /* The closure of the block shall happen immediatelly,
+         /* The closure of the block shall happen immediately,
             so any in_it_block () call reports the block as closed.  */
          force_automatic_it_block_close ();
          break;
             so any in_it_block () call reports the block as closed.  */
          force_automatic_it_block_close ();
          break;
@@ -17824,6 +18330,63 @@ in_it_block (void)
   return now_it.state != OUTSIDE_IT_BLOCK;
 }
 
   return now_it.state != OUTSIDE_IT_BLOCK;
 }
 
+/* Whether OPCODE only has T32 encoding.  Since this function is only used by
+   t32_insn_ok, OPCODE enabled by v6t2 extension bit do not need to be listed
+   here, hence the "known" in the function name.  */
+
+static bfd_boolean
+known_t32_only_insn (const struct asm_opcode *opcode)
+{
+  /* Original Thumb-1 wide instruction.  */
+  if (opcode->tencode == do_t_blx
+      || opcode->tencode == do_t_branch23
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier))
+    return TRUE;
+
+  /* Wide-only instruction added to ARMv8-M Baseline.  */
+  if (ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v8m_m_only)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_atomics)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v6t2_v8m)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_div))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Whether wide instruction variant can be used if available for a valid OPCODE
+   in ARCH.  */
+
+static bfd_boolean
+t32_insn_ok (arm_feature_set arch, const struct asm_opcode *opcode)
+{
+  if (known_t32_only_insn (opcode))
+    return TRUE;
+
+  /* Instruction with narrow and wide encoding added to ARMv8-M.  Availability
+     of variant T3 of B.W is checked in do_t_branch.  */
+  if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v8m)
+      && opcode->tencode == do_t_branch)
+    return TRUE;
+
+  /* MOV accepts T1/T3 encodings under Baseline, T3 encoding is 32bit.  */
+  if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v8m)
+      && opcode->tencode == do_t_mov_cmp
+      /* Make sure CMP instruction is not affected.  */
+      && opcode->aencode == do_mov)
+    return TRUE;
+
+  /* Wide instruction variants of all instructions with narrow *and* wide
+     variants become available with ARMv6t2.  Other opcodes are either
+     narrow-only or wide-only and are thus available if OPCODE is valid.  */
+  if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v6t2))
+    return TRUE;
+
+  /* OPCODE with narrow only instruction variant or wide variant not
+     available.  */
+  return FALSE;
+}
+
 void
 md_assemble (char *str)
 {
 void
 md_assemble (char *str)
 {
@@ -17873,7 +18436,7 @@ md_assemble (char *str)
          || (thumb_mode == 1
              && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
        {
          || (thumb_mode == 1
              && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
        {
-         as_bad (_("selected processor does not support Thumb mode `%s'"), str);
+         as_bad (_("selected processor does not support `%s' in Thumb mode"), str);
          return;
        }
       if (inst.cond != COND_ALWAYS && !unified_syntax
          return;
        }
       if (inst.cond != COND_ALWAYS && !unified_syntax
@@ -17883,24 +18446,28 @@ md_assemble (char *str)
          return;
        }
 
          return;
        }
 
-      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2))
+      /* Two things are addressed here:
+        1) Implicit require narrow instructions on Thumb-1.
+           This avoids relaxation accidentally introducing Thumb-2
+           instructions.
+        2) Reject wide instructions in non Thumb-2 cores.
+
+        Only instructions with narrow and wide variants need to be handled
+        but selecting all non wide-only instructions is easier.  */
+      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2)
+         && !t32_insn_ok (variant, opcode))
        {
        {
-         if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23
-             && !(ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr)
-                  || ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_barrier)))
+         if (inst.size_req == 0)
+           inst.size_req = 2;
+         else if (inst.size_req == 4)
            {
            {
-             /* Two things are addressed here.
-                1) Implicit require narrow instructions on Thumb-1.
-                   This avoids relaxation accidentally introducing Thumb-2
-                    instructions.
-                2) Reject wide instructions in non Thumb-2 cores.  */
-             if (inst.size_req == 0)
-               inst.size_req = 2;
-             else if (inst.size_req == 4)
-               {
-                 as_bad (_("selected processor does not support Thumb-2 mode `%s'"), str);
-                 return;
-               }
+             if (ARM_CPU_HAS_FEATURE (variant, arm_ext_v8m))
+               as_bad (_("selected processor does not support 32bit wide "
+                         "variant of instruction `%s'"), str);
+             else
+               as_bad (_("selected processor does not support `%s' in "
+                         "Thumb-2 mode"), str);
+             return;
            }
        }
 
            }
        }
 
@@ -17935,13 +18502,14 @@ md_assemble (char *str)
       ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                              *opcode->tvariant);
       /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
       ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                              *opcode->tvariant);
       /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
-        set those bits when Thumb-2 32-bit instructions are seen.  ie.
-        anything other than bl/blx and v6-M instructions.
-        The impact of relaxable instructions will be considered later after we
-        finish all relaxation.  */
-      if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
-         && !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
-              || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier)))
+        set those bits when Thumb-2 32-bit instructions are seen.  The impact
+        of relaxable instructions will be considered later after we finish all
+        relaxation.  */
+      if (ARM_FEATURE_CORE_EQUAL (cpu_variant, arm_arch_any))
+       variant = arm_arch_none;
+      else
+       variant = cpu_variant;
+      if (inst.size == 4 && !t32_insn_ok (variant, opcode))
        ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                                arm_ext_v6t2);
 
        ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                                arm_ext_v6t2);
 
@@ -17964,7 +18532,7 @@ md_assemble (char *str)
          && !(opcode->avariant &&
               ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
        {
          && !(opcode->avariant &&
               ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
        {
-         as_bad (_("selected processor does not support ARM mode `%s'"), str);
+         as_bad (_("selected processor does not support `%s' in ARM mode"), str);
          return;
        }
       if (inst.size_req)
          return;
        }
       if (inst.size_req)
@@ -17975,7 +18543,7 @@ md_assemble (char *str)
 
       inst.instruction = opcode->avalue;
       if (opcode->tag == OT_unconditionalF)
 
       inst.instruction = opcode->avalue;
       if (opcode->tag == OT_unconditionalF)
-       inst.instruction |= 0xF << 28;
+       inst.instruction |= 0xFU << 28;
       else
        inst.instruction |= inst.cond << 28;
       inst.size = INSN_SIZE;
       else
        inst.instruction |= inst.cond << 28;
       inst.size = INSN_SIZE;
@@ -18352,22 +18920,32 @@ static const struct asm_psr psrs[] =
 /* Table of V7M psr names.  */
 static const struct asm_psr v7m_psrs[] =
 {
 /* Table of V7M psr names.  */
 static const struct asm_psr v7m_psrs[] =
 {
-  {"apsr",       0 }, {"APSR",         0 },
-  {"iapsr",      1 }, {"IAPSR",        1 },
-  {"eapsr",      2 }, {"EAPSR",        2 },
-  {"psr",        3 }, {"PSR",          3 },
-  {"xpsr",       3 }, {"XPSR",         3 }, {"xPSR",     3 },
-  {"ipsr",       5 }, {"IPSR",         5 },
-  {"epsr",       6 }, {"EPSR",         6 },
-  {"iepsr",      7 }, {"IEPSR",        7 },
-  {"msp",        8 }, {"MSP",          8 },
-  {"psp",        9 }, {"PSP",          9 },
-  {"primask",    16}, {"PRIMASK",      16},
-  {"basepri",    17}, {"BASEPRI",      17},
-  {"basepri_max", 18}, {"BASEPRI_MAX", 18},
-  {"basepri_max", 18}, {"BASEPRI_MASK",        18}, /* Typo, preserved for backwards compatibility.  */
-  {"faultmask",          19}, {"FAULTMASK",    19},
-  {"control",    20}, {"CONTROL",      20}
+  {"apsr",        0x0 }, {"APSR",         0x0 },
+  {"iapsr",       0x1 }, {"IAPSR",        0x1 },
+  {"eapsr",       0x2 }, {"EAPSR",        0x2 },
+  {"psr",         0x3 }, {"PSR",          0x3 },
+  {"xpsr",        0x3 }, {"XPSR",         0x3 }, {"xPSR",        3 },
+  {"ipsr",        0x5 }, {"IPSR",         0x5 },
+  {"epsr",        0x6 }, {"EPSR",         0x6 },
+  {"iepsr",       0x7 }, {"IEPSR",        0x7 },
+  {"msp",         0x8 }, {"MSP",          0x8 },
+  {"psp",         0x9 }, {"PSP",          0x9 },
+  {"msplim",      0xa }, {"MSPLIM",       0xa },
+  {"psplim",      0xb }, {"PSPLIM",       0xb },
+  {"primask",     0x10}, {"PRIMASK",      0x10},
+  {"basepri",     0x11}, {"BASEPRI",      0x11},
+  {"basepri_max",  0x12}, {"BASEPRI_MAX",  0x12},
+  {"faultmask",           0x13}, {"FAULTMASK",    0x13},
+  {"control",     0x14}, {"CONTROL",      0x14},
+  {"msp_ns",      0x88}, {"MSP_NS",       0x88},
+  {"psp_ns",      0x89}, {"PSP_NS",       0x89},
+  {"msplim_ns",           0x8a}, {"MSPLIM_NS",    0x8a},
+  {"psplim_ns",           0x8b}, {"PSPLIM_NS",    0x8b},
+  {"primask_ns",   0x90}, {"PRIMASK_NS",   0x90},
+  {"basepri_ns",   0x91}, {"BASEPRI_NS",   0x91},
+  {"faultmask_ns", 0x93}, {"FAULTMASK_NS", 0x93},
+  {"control_ns",   0x94}, {"CONTROL_NS",   0x94},
+  {"sp_ns",       0x98}, {"SP_NS",        0x98 }
 };
 
 /* Table of all shift-in-operand names.         */
 };
 
 /* Table of all shift-in-operand names.         */
@@ -18664,7 +19242,7 @@ static const struct asm_opcode insns[] =
   CL("cmnp",   170f000,           2, (RR, SH),      cmp),
 
  tCE("mov",    1a00000, _mov,     2, (RR, SH),      mov,  t_mov_cmp),
   CL("cmnp",   170f000,           2, (RR, SH),      cmp),
 
  tCE("mov",    1a00000, _mov,     2, (RR, SH),      mov,  t_mov_cmp),
- tC3("movs",   1b00000, _movs,    2, (RR, SH),      mov,  t_mov_cmp),
+ tC3("movs",   1b00000, _movs,    2, (RR, SHG),     mov,  t_mov_cmp),
  tCE("mvn",    1e00000, _mvn,     2, (RR, SH),      mov,  t_mvn_tst),
  tC3("mvns",   1f00000, _mvns,    2, (RR, SH),      mov,  t_mvn_tst),
 
  tCE("mvn",    1e00000, _mvn,     2, (RR, SH),      mov,  t_mvn_tst),
  tC3("mvns",   1f00000, _mvns,    2, (RR, SH),      mov,  t_mvn_tst),
 
@@ -18908,11 +19486,14 @@ static const struct asm_opcode insns[] =
  TUF("setend",    1010000, b650,     1, (ENDI),                     setend, t_setend),
 
 #undef  THUMB_VARIANT
  TUF("setend",    1010000, b650,     1, (ENDI),                     setend, t_setend),
 
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT  & arm_ext_v6t2
+#define THUMB_VARIANT  & arm_ext_v6t2_v8m
 
  TCE("ldrex",  1900f9f, e8500f00, 2, (RRnpc_npcsp, ADDR),        ldrex, t_ldrex),
  TCE("strex",  1800f90, e8400000, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
                                      strex,  t_strex),
 
  TCE("ldrex",  1900f9f, e8500f00, 2, (RRnpc_npcsp, ADDR),        ldrex, t_ldrex),
  TCE("strex",  1800f90, e8400000, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
                                      strex,  t_strex),
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
+
  TUF("mcrr2",  c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
  TUF("mrrc2",  c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
 
  TUF("mcrr2",  c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
  TUF("mrrc2",  c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
 
@@ -18940,11 +19521,11 @@ static const struct asm_opcode insns[] =
   UF(srsed,    8400500,           2, (oRRw, I31w),                srs),
  TUF("srsdb",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
  TUF("srsfd",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
   UF(srsed,    8400500,           2, (oRRw, I31w),                srs),
  TUF("srsdb",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
  TUF("srsfd",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("cps",    1020000, f3af8100, 1, (I31b),                     imm0, t_cps),
 
 /*  ARM V6 not included in V7M (eg. integer SIMD).  */
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6_dsp
 
 /*  ARM V6 not included in V7M (eg. integer SIMD).  */
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6_dsp
- TUF("cps",    1020000, f3af8100, 1, (I31b),                     imm0, t_cps),
  TCE("pkhbt",  6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
  TCE("pkhtb",  6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
  TCE("qadd16", 6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("pkhbt",  6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
  TCE("pkhtb",  6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
  TCE("qadd16", 6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
@@ -19058,7 +19639,7 @@ static const struct asm_opcode insns[] =
                                       RRnpcb), strexd, t_strexd),
 
 #undef  THUMB_VARIANT
                                       RRnpcb), strexd, t_strexd),
 
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT  & arm_ext_v6t2
+#define THUMB_VARIANT  & arm_ext_v6t2_v8m
  TCE("ldrexb", 1d00f9f, e8d00f4f, 2, (RRnpc_npcsp,RRnpcb),
      rd_rn,  rd_rn),
  TCE("ldrexh", 1f00f9f, e8d00f5f, 2, (RRnpc_npcsp, RRnpcb),
  TCE("ldrexb", 1d00f9f, e8d00f4f, 2, (RRnpc_npcsp,RRnpcb),
      rd_rn,  rd_rn),
  TCE("ldrexh", 1f00f9f, e8d00f5f, 2, (RRnpc_npcsp, RRnpcb),
@@ -19102,8 +19683,6 @@ static const struct asm_opcode insns[] =
  TCE("ubfx",   7e00050, f3c00000, 4, (RR, RR, I31, I32),          bfx, t_bfx),
 
  TCE("mls",    0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
  TCE("ubfx",   7e00050, f3c00000, 4, (RR, RR, I31, I32),          bfx, t_bfx),
 
  TCE("mls",    0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
- TCE("movw",   3000000, f2400000, 2, (RRnpc, HALF),                mov16, t_mov16),
- TCE("movt",   3400000, f2c00000, 2, (RRnpc, HALF),                mov16, t_mov16),
  TCE("rbit",   6ff0f30, fa90f0a0, 2, (RR, RR),                     rd_rm, t_rbit),
 
  TC3("ldrht",  03000b0, f8300e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
  TCE("rbit",   6ff0f30, fa90f0a0, 2, (RR, RR),                     rd_rm, t_rbit),
 
  TC3("ldrht",  03000b0, f8300e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
@@ -19111,6 +19690,11 @@ static const struct asm_opcode insns[] =
  TC3("ldrsbt", 03000d0, f9100e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
  TC3("strht",  02000b0, f8200e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
 
  TC3("ldrsbt", 03000d0, f9100e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
  TC3("strht",  02000b0, f8200e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
 
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2_v8m
+ TCE("movw",   3000000, f2400000, 2, (RRnpc, HALF),                mov16, t_mov16),
+ TCE("movt",   3400000, f2c00000, 2, (RRnpc, HALF),                mov16, t_mov16),
+
  /* Thumb-only instructions.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT NULL
  /* Thumb-only instructions.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT NULL
@@ -19122,6 +19706,8 @@ static const struct asm_opcode insns[] =
     -mimplicit-it=[never | arm] modes.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v1
     -mimplicit-it=[never | arm] modes.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v1
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
 
  TUE("it",        bf08,        bf08,     1, (COND),   it,    t_it),
  TUE("itt",       bf0c,        bf0c,     1, (COND),   it,    t_it),
 
  TUE("it",        bf08,        bf08,     1, (COND),   it,    t_it),
  TUE("itt",       bf0c,        bf0c,     1, (COND),   it,    t_it),
@@ -19191,31 +19777,35 @@ static const struct asm_opcode insns[] =
  /* AArchv8 instructions.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT   & arm_ext_v8
  /* AArchv8 instructions.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT   & arm_ext_v8
+
+/* Instructions shared between armv8-a and armv8-m.  */
 #undef  THUMB_VARIANT
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT & arm_ext_v8
+#define THUMB_VARIANT & arm_ext_atomics
 
 
- tCE("sevl",   320f005, _sevl,    0, (),               noargs, t_hint),
- TUE("hlt",    1000070, ba80,     1, (oIffffb),        bkpt,   t_hlt),
+ TCE("lda",    1900c9f, e8d00faf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldab",   1d00c9f, e8d00f8f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldah",   1f00c9f, e8d00f9f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("stl",    180fc90, e8c00faf, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("stlb",   1c0fc90, e8c00f8f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("stlh",   1e0fc90, e8c00f9f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
  TCE("ldaex",  1900e9f, e8d00fef, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
  TCE("ldaex",  1900e9f, e8d00fef, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
- TCE("ldaexd", 1b00e9f, e8d000ff, 3, (RRnpc, oRRnpc, RRnpcb),
-                                                       ldrexd, t_ldrexd),
  TCE("ldaexb", 1d00e9f, e8d00fcf, 2, (RRnpc,RRnpcb),   rd_rn,  rd_rn),
  TCE("ldaexh", 1f00e9f, e8d00fdf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
  TCE("stlex",  1800e90, e8c00fe0, 3, (RRnpc, RRnpc, RRnpcb),
                                                        stlex,  t_stlex),
  TCE("ldaexb", 1d00e9f, e8d00fcf, 2, (RRnpc,RRnpcb),   rd_rn,  rd_rn),
  TCE("ldaexh", 1f00e9f, e8d00fdf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
  TCE("stlex",  1800e90, e8c00fe0, 3, (RRnpc, RRnpc, RRnpcb),
                                                        stlex,  t_stlex),
- TCE("stlexd", 1a00e90, e8c000f0, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb),
-                                                       strexd, t_strexd),
  TCE("stlexb", 1c00e90, e8c00fc0, 3, (RRnpc, RRnpc, RRnpcb),
                                                        stlex, t_stlex),
  TCE("stlexh", 1e00e90, e8c00fd0, 3, (RRnpc, RRnpc, RRnpcb),
                                                        stlex, t_stlex),
  TCE("stlexb", 1c00e90, e8c00fc0, 3, (RRnpc, RRnpc, RRnpcb),
                                                        stlex, t_stlex),
  TCE("stlexh", 1e00e90, e8c00fd0, 3, (RRnpc, RRnpc, RRnpcb),
                                                        stlex, t_stlex),
- TCE("lda",    1900c9f, e8d00faf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
- TCE("ldab",   1d00c9f, e8d00f8f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
- TCE("ldah",   1f00c9f, e8d00f9f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
- TCE("stl",    180fc90, e8c00faf, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
- TCE("stlb",   1c0fc90, e8c00f8f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
- TCE("stlh",   1e0fc90, e8c00f9f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8
 
 
+ tCE("sevl",   320f005, _sevl,    0, (),               noargs, t_hint),
+ TUE("hlt",    1000070, ba80,     1, (oIffffb),        bkpt,   t_hlt),
+ TCE("ldaexd", 1b00e9f, e8d000ff, 3, (RRnpc, oRRnpc, RRnpcb),
+                                                       ldrexd, t_ldrexd),
+ TCE("stlexd", 1a00e90, e8c000f0, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb),
+                                                       strexd, t_strexd),
  /* ARMv8 T32 only.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT  NULL
  /* ARMv8 T32 only.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT  NULL
@@ -19279,6 +19869,21 @@ static const struct asm_opcode insns[] =
   TUEc("crc32ch",1200240, fad0f090, 3, (RR, oRR, RR), crc32ch),
   TUEc("crc32cw",1400240, fad0f0a0, 3, (RR, oRR, RR), crc32cw),
 
   TUEc("crc32ch",1200240, fad0f090, 3, (RR, oRR, RR), crc32ch),
   TUEc("crc32cw",1400240, fad0f0a0, 3, (RR, oRR, RR), crc32cw),
 
+ /* ARMv8.2 RAS extension.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_ras
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_ras
+ TUE ("esb", 320f010, f3af8010, 0, (), noargs,  noargs),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_v8_3
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8_3
+ NCE (vjcvt, eb90bc0, 2, (RVS, RVD), vjcvt),
+ NUF (vcmla, 0, 4, (RNDQ, RNDQ, RNDQ_RNSC, EXPi), vcmla),
+ NUF (vcadd, 0, 4, (RNDQ, RNDQ, RNDQ, EXPi), vcadd),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
 #undef  THUMB_VARIANT
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
 #undef  THUMB_VARIANT
@@ -19895,6 +20500,15 @@ static const struct asm_opcode insns[] =
  NCE(vmov,      0,       1, (VMOV), neon_mov),
  NCE(vmovq,     0,       1, (VMOV), neon_mov),
 
  NCE(vmov,      0,       1, (VMOV), neon_mov),
  NCE(vmovq,     0,       1, (VMOV), neon_mov),
 
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & arm_ext_fp16
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_fp16
+ /* New instructions added from v8.2, allowing the extraction and insertion of
+    the upper 16 bits of a 32-bit vector register.  */
+ NCE (vmovx,     eb00a40,       2, (RVS, RVS), neon_movhf),
+ NCE (vins,      eb00ac0,       2, (RVS, RVS), neon_movhf),
+
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & fpu_neon_ext_v1
 #undef  ARM_VARIANT
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & fpu_neon_ext_v1
 #undef  ARM_VARIANT
@@ -19944,7 +20558,7 @@ static const struct asm_opcode insns[] =
  NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
  NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
  NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
  NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
  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 F32.  */
+  /* 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(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),
@@ -19997,10 +20611,10 @@ static const struct asm_opcode insns[] =
  NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
  NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
  /* ARM v8.1 extension.  */
  NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
  NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
  /* ARM v8.1 extension.  */
- nUF(vqrdmlah,  _vqrdmlah, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
- nUF(vqrdmlahq, _vqrdmlah, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
- nUF(vqrdmlsh,  _vqrdmlsh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
- nUF(vqrdmlshq, _vqrdmlsh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
+ nUF (vqrdmlah,  _vqrdmlah, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qrdmlah),
+ nUF (vqrdmlahq, _vqrdmlah, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qrdmlah),
+ nUF (vqrdmlsh,  _vqrdmlsh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qrdmlah),
+ nUF (vqrdmlshq, _vqrdmlsh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qrdmlah),
 
   /* Two address, int/float. Types S8 S16 S32 F32.  */
  NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
 
   /* Two address, int/float. Types S8 S16 S32 F32.  */
  NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
@@ -20107,7 +20721,7 @@ static const struct asm_opcode insns[] =
  NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
  NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
  NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
  NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
  NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
  NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
-  /* Reciprocal estimates. Types U32 F32.  */
+  /* Reciprocal estimates.  Types U32 F16 F32.  */
  NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
  NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
  NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
  NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
  NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
  NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
@@ -20513,6 +21127,26 @@ static const struct asm_opcode insns[] =
  cCE("cfmsub32",e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
  cCE("cfmadda32", e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
  cCE("cfmsuba32", e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
  cCE("cfmsub32",e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
  cCE("cfmadda32", e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
  cCE("cfmsuba32", e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
+
+ /* ARMv8-M instructions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT NULL
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8m
+ TUE("sg", 0, e97fe97f, 0, (), 0, noargs),
+ TUE("blxns", 0, 4784, 1, (RRnpc), 0, t_blx),
+ TUE("bxns", 0, 4704, 1, (RRnpc), 0, t_bx),
+ TUE("tt", 0, e840f000, 2, (RRnpc, RRnpc), 0, tt),
+ TUE("ttt", 0, e840f040, 2, (RRnpc, RRnpc), 0, tt),
+ TUE("tta", 0, e840f080, 2, (RRnpc, RRnpc), 0, tt),
+ TUE("ttat", 0, e840f0c0, 2, (RRnpc, RRnpc), 0, tt),
+
+ /* FP for ARMv8-M Mainline.  Enabled for ARMv8-M Mainline because the
+    instructions behave as nop if no VFP is present.  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8m_main
+ TUEc("vlldm", 0,       ec300a00, 1, (RRnpc),  rn),
+ TUEc("vlstm", 0,       ec200a00, 1, (RRnpc),  rn),
 };
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
 };
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
@@ -21067,7 +21701,7 @@ md_section_align (segT   segment ATTRIBUTE_UNUSED,
       int align;
 
       align = bfd_get_section_alignment (stdoutput, segment);
       int align;
 
       align = bfd_get_section_alignment (stdoutput, segment);
-      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+      size = ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
     }
 #endif
 
     }
 #endif
 
@@ -21080,7 +21714,7 @@ md_section_align (segT   segment ATTRIBUTE_UNUSED,
 void
 arm_handle_align (fragS * fragP)
 {
 void
 arm_handle_align (fragS * fragP)
 {
-  static char const arm_noop[2][2][4] =
+  static unsigned char const arm_noop[2][2][4] =
     {
       {  /* ARMv1 */
        {0x00, 0x00, 0xa0, 0xe1},  /* LE */
     {
       {  /* ARMv1 */
        {0x00, 0x00, 0xa0, 0xe1},  /* LE */
@@ -21091,7 +21725,7 @@ arm_handle_align (fragS * fragP)
        {0xe3, 0x20, 0xf0, 0x00},  /* BE */
       },
     };
        {0xe3, 0x20, 0xf0, 0x00},  /* BE */
       },
     };
-  static char const thumb_noop[2][2][2] =
+  static unsigned char const thumb_noop[2][2][2] =
     {
       {  /* Thumb-1 */
        {0xc0, 0x46},  /* LE */
     {
       {  /* Thumb-1 */
        {0xc0, 0x46},  /* LE */
@@ -21102,7 +21736,7 @@ arm_handle_align (fragS * fragP)
        {0xbf, 0x00}   /* BE */
       }
     };
        {0xbf, 0x00}   /* BE */
       }
     };
-  static char const wide_thumb_noop[2][4] =
+  static unsigned char const wide_thumb_noop[2][4] =
     {  /* Wide Thumb-2 */
       {0xaf, 0xf3, 0x00, 0x80},  /* LE */
       {0xf3, 0xaf, 0x80, 0x00},  /* BE */
     {  /* Wide Thumb-2 */
       {0xaf, 0xf3, 0x00, 0x80},  /* LE */
       {0xf3, 0xaf, 0x80, 0x00},  /* BE */
@@ -21110,8 +21744,8 @@ arm_handle_align (fragS * fragP)
 
   unsigned bytes, fix, noop_size;
   char * p;
 
   unsigned bytes, fix, noop_size;
   char * p;
-  const char * noop;
-  const char *narrow_noop = NULL;
+  const unsigned char * noop;
+  const unsigned char *narrow_noop = NULL;
 #ifdef OBJ_ELF
   enum mstate state;
 #endif
 #ifdef OBJ_ELF
   enum mstate state;
 #endif
@@ -21228,7 +21862,7 @@ arm_frag_align_code (int n, int max)
    Note - despite the name this initialisation is not done when the frag
    is created, but only when its type is assigned.  A frag can be created
    and used a long time before its type is set, so beware of assuming that
    Note - despite the name this initialisation is not done when the frag
    is created, but only when its type is assigned.  A frag can be created
    and used a long time before its type is set, so beware of assuming that
-   this initialisationis performed first.  */
+   this initialisation is performed first.  */
 
 #ifndef OBJ_ELF
 void
 
 #ifndef OBJ_ELF
 void
@@ -21322,10 +21956,10 @@ add_unwind_opcode (valueT op, int length)
     {
       unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
       if (unwind.opcodes)
     {
       unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
       if (unwind.opcodes)
-       unwind.opcodes = (unsigned char *) xrealloc (unwind.opcodes,
-                                                    unwind.opcode_alloc);
+       unwind.opcodes = XRESIZEVEC (unsigned char, unwind.opcodes,
+                                    unwind.opcode_alloc);
       else
       else
-       unwind.opcodes = (unsigned char *) xmalloc (unwind.opcode_alloc);
+       unwind.opcodes = XNEWVEC (unsigned char, unwind.opcode_alloc);
     }
   while (length > 0)
     {
     }
   while (length > 0)
     {
@@ -21429,10 +22063,7 @@ start_unwind_section (const segT text_seg, int idx)
   const char * prefix;
   const char * prefix_once;
   const char * group_name;
   const char * prefix;
   const char * prefix_once;
   const char * group_name;
-  size_t prefix_len;
-  size_t text_len;
   char * sec_name;
   char * sec_name;
-  size_t sec_name_len;
   int type;
   int flags;
   int linkonce;
   int type;
   int flags;
   int linkonce;
@@ -21461,13 +22092,7 @@ start_unwind_section (const segT text_seg, int idx)
       text_name += strlen (".gnu.linkonce.t.");
     }
 
       text_name += strlen (".gnu.linkonce.t.");
     }
 
-  prefix_len = strlen (prefix);
-  text_len = strlen (text_name);
-  sec_name_len = prefix_len + text_len;
-  sec_name = (char *) xmalloc (sec_name_len + 1);
-  memcpy (sec_name, prefix, prefix_len);
-  memcpy (sec_name + prefix_len, text_name, text_len);
-  sec_name[prefix_len + text_len] = '\0';
+  sec_name = concat (prefix, text_name, (char *) NULL);
 
   flags = SHF_ALLOC;
   linkonce = 0;
 
   flags = SHF_ALLOC;
   linkonce = 0;
@@ -21880,7 +22505,7 @@ arm_tc_equal_in_insn (int c ATTRIBUTE_UNUSED, char * name)
       else
        free (nbuf);
     }
       else
        free (nbuf);
     }
-  
+
   return FALSE;
 }
 
   return FALSE;
 }
 
@@ -22262,6 +22887,23 @@ md_apply_fix (fixS *   fixP,
             changing the opcode.  */
          if (newimm == (unsigned int) FAIL)
            newimm = negate_data_op (&temp, value);
             changing the opcode.  */
          if (newimm == (unsigned int) FAIL)
            newimm = negate_data_op (&temp, value);
+         /* MOV accepts both ARM modified immediate (A1 encoding) and
+            UINT16 (A2 encoding) when possible, MOVW only accepts UINT16.
+            When disassembling, MOV is preferred when there is no encoding
+            overlap.  */
+         if (newimm == (unsigned int) FAIL
+             && ((temp >> DATA_OP_SHIFT) & 0xf) == OPCODE_MOV
+             && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)
+             && !((temp >> SBIT_SHIFT) & 0x1)
+             && value >= 0 && value <= 0xffff)
+           {
+             /* Clear bits[23:20] to change encoding from A1 to A2.  */
+             temp &= 0xff0fffff;
+             /* Encoding high 4bits imm.  Code below will encode the remaining
+                low 12bits.  */
+             temp |= (value & 0x0000f000) << 4;
+             newimm = value & 0x00000fff;
+           }
        }
 
       if (newimm == (unsigned int) FAIL)
        }
 
       if (newimm == (unsigned int) FAIL)
@@ -22347,6 +22989,7 @@ md_apply_fix (fixS *    fixP,
     case BFD_RELOC_ARM_OFFSET_IMM:
       if (!fixP->fx_done && seg->use_rela_p)
        value = 0;
     case BFD_RELOC_ARM_OFFSET_IMM:
       if (!fixP->fx_done && seg->use_rela_p)
        value = 0;
+      /* Fall through.  */
 
     case BFD_RELOC_ARM_LITERAL:
       sign = value > 0;
 
     case BFD_RELOC_ARM_LITERAL:
       sign = value > 0;
@@ -22577,32 +23220,59 @@ md_apply_fix (fixS *  fixP,
       newval |= md_chars_to_number (buf+2, THUMB_SIZE);
 
       newimm = FAIL;
       newval |= md_chars_to_number (buf+2, THUMB_SIZE);
 
       newimm = FAIL;
-      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
+      if ((fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
+          /* ARMv8-M Baseline MOV will reach here, but it doesn't support
+             Thumb2 modified immediate encoding (T2).  */
+          && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
          || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
        {
          newimm = encode_thumb32_immediate (value);
          if (newimm == (unsigned int) FAIL)
            newimm = thumb32_negate_data_op (&newval, value);
        }
          || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
        {
          newimm = encode_thumb32_immediate (value);
          if (newimm == (unsigned int) FAIL)
            newimm = thumb32_negate_data_op (&newval, value);
        }
-      if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
-         && newimm == (unsigned int) FAIL)
+      if (newimm == (unsigned int) FAIL)
        {
        {
-         /* Turn add/sum into addw/subw.  */
-         if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
-           newval = (newval & 0xfeffffff) | 0x02000000;
-         /* No flat 12-bit imm encoding for addsw/subsw.  */
-         if ((newval & 0x00100000) == 0)
+         if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE)
            {
            {
-             /* 12 bit immediate for addw/subw.  */
-             if (value < 0)
+             /* Turn add/sum into addw/subw.  */
+             if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
+               newval = (newval & 0xfeffffff) | 0x02000000;
+             /* No flat 12-bit imm encoding for addsw/subsw.  */
+             if ((newval & 0x00100000) == 0)
                {
                {
-                 value = -value;
-                 newval ^= 0x00a00000;
+                 /* 12 bit immediate for addw/subw.  */
+                 if (value < 0)
+                   {
+                     value = -value;
+                     newval ^= 0x00a00000;
+                   }
+                 if (value > 0xfff)
+                   newimm = (unsigned int) FAIL;
+                 else
+                   newimm = value;
+               }
+           }
+         else
+           {
+             /* MOV accepts both Thumb2 modified immediate (T2 encoding) and
+                UINT16 (T3 encoding), MOVW only accepts UINT16.  When
+                disassembling, MOV is preferred when there is no encoding
+                overlap.
+                NOTE: MOV is using ORR opcode under Thumb 2 mode.  */
+             if (((newval >> T2_DATA_OP_SHIFT) & 0xf) == T2_OPCODE_ORR
+                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m)
+                 && !((newval >> T2_SBIT_SHIFT) & 0x1)
+                 && value >= 0 && value <=0xffff)
+               {
+                 /* Toggle bit[25] to change encoding from T2 to T3.  */
+                 newval ^= 1 << 25;
+                 /* Clear bits[19:16].  */
+                 newval &= 0xfff0ffff;
+                 /* Encoding high 4bits imm.  Code below will encode the
+                    remaining low 12bits.  */
+                 newval |= (value & 0x0000f000) << 4;
+                 newimm = value & 0x00000fff;
                }
                }
-             if (value > 0xfff)
-               newimm = (unsigned int) FAIL;
-             else
-               newimm = value;
            }
        }
 
            }
        }
 
@@ -22705,6 +23375,7 @@ md_apply_fix (fixS *    fixP,
          newval = md_chars_to_number (buf, INSN_SIZE);
          fixP->fx_done = 0;
        }
          newval = md_chars_to_number (buf, INSN_SIZE);
          fixP->fx_done = 0;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_ARM_PLT32:
 #endif
 
     case BFD_RELOC_ARM_PLT32:
 #endif
@@ -22909,7 +23580,7 @@ md_apply_fix (fixS *    fixP,
 
       if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
        {
 
       if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
        {
-         if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2)))
+         if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)))
            as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
          else if ((value & ~0x1ffffff)
                   && ((value & ~0x1ffffff) != ~0x1ffffff))
            as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
          else if ((value & ~0x1ffffff)
                   && ((value & ~0x1ffffff) != ~0x1ffffff))
@@ -23008,7 +23679,20 @@ md_apply_fix (fixS *   fixP,
 
     case BFD_RELOC_ARM_CP_OFF_IMM:
     case BFD_RELOC_ARM_T32_CP_OFF_IMM:
 
     case BFD_RELOC_ARM_CP_OFF_IMM:
     case BFD_RELOC_ARM_T32_CP_OFF_IMM:
-      if (value < -1023 || value > 1023 || (value & 3))
+      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM)
+       newval = md_chars_to_number (buf, INSN_SIZE);
+      else
+       newval = get_thumb32_insn (buf);
+      if ((newval & 0x0f200f00) == 0x0d000900)
+       {
+         /* This is a fp16 vstr/vldr.  The immediate offset in the mnemonic
+            has permitted values that are multiples of 2, in the range 0
+            to 510.  */
+         if (value < -510 || value > 510 || (value & 1))
+           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"));
     cp_off_common:
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("co-processor offset out of range"));
     cp_off_common:
@@ -23025,6 +23709,17 @@ md_apply_fix (fixS *   fixP,
       else
        {
          newval &= 0xff7fff00;
       else
        {
          newval &= 0xff7fff00;
+         if ((newval & 0x0f200f00) == 0x0d000900)
+           {
+             /* This is a fp16 vstr/vldr.
+
+                It requires the immediate offset in the instruction is shifted
+                left by 1 to be a half-word offset.
+
+                Here, left shift by 1 first, and later right shift by 2
+                should get the right offset.  */
+             value <<= 1;
+           }
          newval |= (value >> 2) | (sign ? INDEX_UP : 0);
        }
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
          newval |= (value >> 2) | (sign ? INDEX_UP : 0);
        }
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
@@ -23150,7 +23845,7 @@ md_apply_fix (fixS *    fixP,
 
        if (rd == REG_SP)
          {
 
        if (rd == REG_SP)
          {
-           if (value & ~0x1fc)
+           if (value & ~0x1fc)
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("invalid immediate for stack address calculation"));
            newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("invalid immediate for stack address calculation"));
            newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
@@ -23158,6 +23853,45 @@ md_apply_fix (fixS *   fixP,
          }
        else if (rs == REG_PC || rs == REG_SP)
          {
          }
        else if (rs == REG_PC || rs == REG_SP)
          {
+           /* PR gas/18541.  If the addition is for a defined symbol
+              within range of an ADR instruction then accept it.  */
+           if (subtract
+               && value == 4
+               && fixP->fx_addsy != NULL)
+             {
+               subtract = 0;
+
+               if (! S_IS_DEFINED (fixP->fx_addsy)
+                   || S_GET_SEGMENT (fixP->fx_addsy) != seg
+                   || S_IS_WEAK (fixP->fx_addsy))
+                 {
+                   as_bad_where (fixP->fx_file, fixP->fx_line,
+                                 _("address calculation needs a strongly defined nearby symbol"));
+                 }
+               else
+                 {
+                   offsetT v = fixP->fx_where + fixP->fx_frag->fr_address;
+
+                   /* Round up to the next 4-byte boundary.  */
+                   if (v & 3)
+                     v = (v + 3) & ~ 3;
+                   else
+                     v += 4;
+                   v = S_GET_VALUE (fixP->fx_addsy) - v;
+
+                   if (v & ~0x3fc)
+                     {
+                       as_bad_where (fixP->fx_file, fixP->fx_line,
+                                     _("symbol too far away"));
+                     }
+                   else
+                     {
+                       fixP->fx_done = 1;
+                       value = v;
+                     }
+                 }
+             }
+
            if (subtract || value & ~0x3fc)
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("invalid immediate for address calculation (value = 0x%08lX)"),
            if (subtract || value & ~0x3fc)
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("invalid immediate for address calculation (value = 0x%08lX)"),
@@ -23259,6 +23993,68 @@ md_apply_fix (fixS *   fixP,
        }
       return;
 
        }
       return;
 
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC:
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
+      gas_assert (!fixP->fx_done);
+      {
+       bfd_vma insn;
+       bfd_boolean is_mov;
+       bfd_vma encoded_addend = value;
+
+       /* Check that addend can be encoded in instruction.  */
+       if (!seg->use_rela_p && (value < 0 || value > 255))
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("the offset 0x%08lX is not representable"),
+                       (unsigned long) encoded_addend);
+
+       /* Extract the instruction.  */
+       insn = md_chars_to_number (buf, THUMB_SIZE);
+       is_mov = (insn & 0xf800) == 0x2000;
+
+       /* Encode insn.  */
+       if (is_mov)
+         {
+           if (!seg->use_rela_p)
+             insn |= encoded_addend;
+         }
+       else
+         {
+           int rd, rs;
+
+           /* Extract the instruction.  */
+            /* Encoding is the following
+               0x8000  SUB
+               0x00F0  Rd
+               0x000F  Rs
+            */
+            /* The following conditions must be true :
+               - ADD
+               - Rd == Rs
+               - Rd <= 7
+            */
+           rd = (insn >> 4) & 0xf;
+           rs = insn & 0xf;
+           if ((insn & 0x8000) || (rd != rs) || rd > 7)
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("Unable to process relocation for thumb opcode: %lx"),
+                       (unsigned long) insn);
+
+           /* Encode as ADD immediate8 thumb 1 code.  */
+           insn = 0x3000 | (rd << 8);
+
+           /* Place the encoded addend into the first 8 bits of the
+              instruction.  */
+           if (!seg->use_rela_p)
+             insn |= encoded_addend;
+         }
+
+       /* Update the instruction.  */
+       md_number_to_chars (buf, insn, THUMB_SIZE);
+      }
+      break;
+
    case BFD_RELOC_ARM_ALU_PC_G0_NC:
    case BFD_RELOC_ARM_ALU_PC_G0:
    case BFD_RELOC_ARM_ALU_PC_G1_NC:
    case BFD_RELOC_ARM_ALU_PC_G0_NC:
    case BFD_RELOC_ARM_ALU_PC_G0:
    case BFD_RELOC_ARM_ALU_PC_G1_NC:
@@ -23449,9 +24245,9 @@ tc_gen_reloc (asection *section, fixS *fixp)
   arelent * reloc;
   bfd_reloc_code_real_type code;
 
   arelent * reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+  reloc = XNEW (arelent);
 
 
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
@@ -23472,6 +24268,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_8_PCREL;
          break;
        }
          code = BFD_RELOC_8_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_16:
       if (fixp->fx_pcrel)
 
     case BFD_RELOC_16:
       if (fixp->fx_pcrel)
@@ -23479,6 +24276,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_16_PCREL;
          break;
        }
          code = BFD_RELOC_16_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_32:
       if (fixp->fx_pcrel)
 
     case BFD_RELOC_32:
       if (fixp->fx_pcrel)
@@ -23486,6 +24284,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_32_PCREL;
          break;
        }
          code = BFD_RELOC_32_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_ARM_MOVW:
       if (fixp->fx_pcrel)
 
     case BFD_RELOC_ARM_MOVW:
       if (fixp->fx_pcrel)
@@ -23493,6 +24292,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_ARM_MOVW_PCREL;
          break;
        }
          code = BFD_RELOC_ARM_MOVW_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_ARM_MOVT:
       if (fixp->fx_pcrel)
 
     case BFD_RELOC_ARM_MOVT:
       if (fixp->fx_pcrel)
@@ -23500,6 +24300,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_ARM_MOVT_PCREL;
          break;
        }
          code = BFD_RELOC_ARM_MOVT_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_ARM_THUMB_MOVW:
       if (fixp->fx_pcrel)
 
     case BFD_RELOC_ARM_THUMB_MOVW:
       if (fixp->fx_pcrel)
@@ -23507,6 +24308,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
          break;
        }
          code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_ARM_THUMB_MOVT:
       if (fixp->fx_pcrel)
 
     case BFD_RELOC_ARM_THUMB_MOVT:
       if (fixp->fx_pcrel)
@@ -23514,6 +24316,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
          break;
        }
          code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
          break;
        }
+      /* Fall through.  */
 
     case BFD_RELOC_NONE:
     case BFD_RELOC_ARM_PCREL_BRANCH:
 
     case BFD_RELOC_NONE:
     case BFD_RELOC_ARM_PCREL_BRANCH:
@@ -23564,7 +24367,6 @@ tc_gen_reloc (asection *section, fixS *fixp)
     case BFD_RELOC_ARM_SBREL32:
     case BFD_RELOC_ARM_PREL31:
     case BFD_RELOC_ARM_TARGET2:
     case BFD_RELOC_ARM_SBREL32:
     case BFD_RELOC_ARM_PREL31:
     case BFD_RELOC_ARM_TARGET2:
-    case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_LDO32:
     case BFD_RELOC_ARM_PCREL_CALL:
     case BFD_RELOC_ARM_PCREL_JUMP:
     case BFD_RELOC_ARM_TLS_LDO32:
     case BFD_RELOC_ARM_PCREL_CALL:
     case BFD_RELOC_ARM_PCREL_JUMP:
@@ -23597,11 +24399,16 @@ tc_gen_reloc (asection *section, fixS *fixp)
     case BFD_RELOC_ARM_LDC_SB_G1:
     case BFD_RELOC_ARM_LDC_SB_G2:
     case BFD_RELOC_ARM_V4BX:
     case BFD_RELOC_ARM_LDC_SB_G1:
     case BFD_RELOC_ARM_LDC_SB_G2:
     case BFD_RELOC_ARM_V4BX:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
       code = fixp->fx_r_type;
       break;
 
     case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
       code = fixp->fx_r_type;
       break;
 
     case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
+    case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_IE32:
     case BFD_RELOC_ARM_TLS_LDM32:
       /* BFD will include the symbol's address in the addend.
     case BFD_RELOC_ARM_TLS_IE32:
     case BFD_RELOC_ARM_TLS_LDM32:
       /* BFD will include the symbol's address in the addend.
@@ -23645,7 +24452,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
 
     default:
       {
 
     default:
       {
-       char * type;
+       const char * type;
 
        switch (fixp->fx_r_type)
          {
 
        switch (fixp->fx_r_type)
          {
@@ -23898,12 +24705,17 @@ arm_fix_adjustable (fixS * fixP)
       || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT_PCREL)
     return FALSE;
 
       || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT_PCREL)
     return FALSE;
 
+  /* BFD_RELOC_ARM_THUMB_ALU_ABS_Gx_NC relocations have VERY limited
+     offsets, so keep these symbols.  */
+  if (fixP->fx_r_type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+      && fixP->fx_r_type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+    return FALSE;
+
   return TRUE;
 }
 #endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
 
 #ifdef OBJ_ELF
   return TRUE;
 }
 #endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
 
 #ifdef OBJ_ELF
-
 const char *
 elf32_arm_target_format (void)
 {
 const char *
 elf32_arm_target_format (void)
 {
@@ -24089,8 +24901,8 @@ arm_adjust_symtab (void)
              /* If it's a .thumb_func, declare it as so,
                 otherwise tag label as .code 16.  */
              if (THUMB_IS_FUNC (sym))
              /* If it's a .thumb_func, declare it as so,
                 otherwise tag label as .code 16.  */
              if (THUMB_IS_FUNC (sym))
-               elf_sym->internal_elf_sym.st_target_internal
-                 = ST_BRANCH_TO_THUMB;
+               ARM_SET_SYM_BRANCH_TYPE (elf_sym->internal_elf_sym.st_target_internal,
+                                        ST_BRANCH_TO_THUMB);
              else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
                elf_sym->internal_elf_sym.st_info =
                  ELF_ST_INFO (bind, STT_ARM_16BIT);
              else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
                elf_sym->internal_elf_sym.st_info =
                  ELF_ST_INFO (bind, STT_ARM_16BIT);
@@ -24451,11 +25263,11 @@ size_t md_longopts_size = sizeof (md_longopts);
 
 struct arm_option_table
 {
 
 struct arm_option_table
 {
-  char *option;                /* Option name to match.  */
-  char *help;          /* Help information.  */
+  const char *option;          /* Option name to match.  */
+  const char *help;            /* Help information.  */
   int  *var;           /* Variable to change.  */
   int  value;          /* What to change it to.  */
   int  *var;           /* Variable to change.  */
   int  value;          /* What to change it to.  */
-  char *deprecated;    /* If non-null, print this message.  */
+  const char *deprecated;      /* If non-null, print this message.  */
 };
 
 struct arm_option_table arm_opts[] =
 };
 
 struct arm_option_table arm_opts[] =
@@ -24488,10 +25300,10 @@ struct arm_option_table arm_opts[] =
 
 struct arm_legacy_option_table
 {
 
 struct arm_legacy_option_table
 {
-  char *option;                                /* Option name to match.  */
+  const char *option;                          /* Option name to match.  */
   const arm_feature_set        **var;          /* Variable to change.  */
   const arm_feature_set        value;          /* What to change it to.  */
   const arm_feature_set        **var;          /* Variable to change.  */
   const arm_feature_set        value;          /* What to change it to.  */
-  char *deprecated;                    /* If non-null, print this message.  */
+  const char *deprecated;                      /* If non-null, print this message.  */
 };
 
 const struct arm_legacy_option_table arm_legacy_opts[] =
 };
 
 const struct arm_legacy_option_table arm_legacy_opts[] =
@@ -24609,7 +25421,7 @@ const struct arm_legacy_option_table arm_legacy_opts[] =
 
 struct arm_cpu_option_table
 {
 
 struct arm_cpu_option_table
 {
-  char *name;
+  const char *name;
   size_t name_len;
   const arm_feature_set        value;
   /* For some CPUs we assume an FPU unless the user explicitly sets
   size_t name_len;
   const arm_feature_set        value;
   /* For some CPUs we assume an FPU unless the user explicitly sets
@@ -24709,8 +25521,8 @@ static const struct arm_cpu_option_table arm_cpus[] =
   ARM_CPU_OPT ("mpcorenovfp",  ARM_ARCH_V6K,    FPU_NONE,        "MPCore"),
   ARM_CPU_OPT ("arm1156t2-s",  ARM_ARCH_V6T2,   FPU_NONE,        NULL),
   ARM_CPU_OPT ("arm1156t2f-s", ARM_ARCH_V6T2,   FPU_ARCH_VFP_V2, NULL),
   ARM_CPU_OPT ("mpcorenovfp",  ARM_ARCH_V6K,    FPU_NONE,        "MPCore"),
   ARM_CPU_OPT ("arm1156t2-s",  ARM_ARCH_V6T2,   FPU_NONE,        NULL),
   ARM_CPU_OPT ("arm1156t2f-s", ARM_ARCH_V6T2,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm1176jz-s",  ARM_ARCH_V6ZK,   FPU_NONE,        NULL),
-  ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6ZK,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm1176jz-s",  ARM_ARCH_V6KZ,   FPU_NONE,        NULL),
+  ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6KZ,   FPU_ARCH_VFP_V2, NULL),
   ARM_CPU_OPT ("cortex-a5",    ARM_ARCH_V7A_MP_SEC,
                                                 FPU_NONE,        "Cortex-A5"),
   ARM_CPU_OPT ("cortex-a7",    ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
   ARM_CPU_OPT ("cortex-a5",    ARM_ARCH_V7A_MP_SEC,
                                                 FPU_NONE,        "Cortex-A5"),
   ARM_CPU_OPT ("cortex-a7",    ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
@@ -24729,12 +25541,18 @@ static const struct arm_cpu_option_table arm_cpus[] =
                                                                  "Cortex-A15"),
   ARM_CPU_OPT ("cortex-a17",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
                                                                  "Cortex-A17"),
                                                                  "Cortex-A15"),
   ARM_CPU_OPT ("cortex-a17",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
                                                                  "Cortex-A17"),
-  ARM_CPU_OPT ("cortex-a53",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+  ARM_CPU_OPT ("cortex-a32",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A32"),
+  ARM_CPU_OPT ("cortex-a35",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A35"),
+  ARM_CPU_OPT ("cortex-a53",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "Cortex-A53"),
                                                                  "Cortex-A53"),
-  ARM_CPU_OPT ("cortex-a57",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+  ARM_CPU_OPT ("cortex-a57",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "Cortex-A57"),
                                                                  "Cortex-A57"),
-  ARM_CPU_OPT ("cortex-a72",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+  ARM_CPU_OPT ("cortex-a72",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "Cortex-A72"),
                                                                  "Cortex-A72"),
+  ARM_CPU_OPT ("cortex-a73",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A73"),
   ARM_CPU_OPT ("cortex-r4",    ARM_ARCH_V7R,    FPU_NONE,        "Cortex-R4"),
   ARM_CPU_OPT ("cortex-r4f",   ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,
                                                                  "Cortex-R4F"),
   ARM_CPU_OPT ("cortex-r4",    ARM_ARCH_V7R,    FPU_NONE,        "Cortex-R4"),
   ARM_CPU_OPT ("cortex-r4f",   ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,
                                                                  "Cortex-R4F"),
@@ -24743,15 +25561,29 @@ static const struct arm_cpu_option_table arm_cpus[] =
   ARM_CPU_OPT ("cortex-r7",    ARM_ARCH_V7R_IDIV,
                                                 FPU_ARCH_VFP_V3D16,
                                                                  "Cortex-R7"),
   ARM_CPU_OPT ("cortex-r7",    ARM_ARCH_V7R_IDIV,
                                                 FPU_ARCH_VFP_V3D16,
                                                                  "Cortex-R7"),
+  ARM_CPU_OPT ("cortex-r8",    ARM_ARCH_V7R_IDIV,
+                                                FPU_ARCH_VFP_V3D16,
+                                                                 "Cortex-R8"),
+  ARM_CPU_OPT ("cortex-m33",   ARM_ARCH_V8M_MAIN_DSP,
+                                                FPU_NONE,        "Cortex-M33"),
+  ARM_CPU_OPT ("cortex-m23",   ARM_ARCH_V8M_BASE,
+                                                FPU_NONE,        "Cortex-M23"),
   ARM_CPU_OPT ("cortex-m7",    ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M7"),
   ARM_CPU_OPT ("cortex-m4",    ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M4"),
   ARM_CPU_OPT ("cortex-m3",    ARM_ARCH_V7M,    FPU_NONE,        "Cortex-M3"),
   ARM_CPU_OPT ("cortex-m1",    ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M1"),
   ARM_CPU_OPT ("cortex-m0",    ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0"),
   ARM_CPU_OPT ("cortex-m0plus",        ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0+"),
   ARM_CPU_OPT ("cortex-m7",    ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M7"),
   ARM_CPU_OPT ("cortex-m4",    ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M4"),
   ARM_CPU_OPT ("cortex-m3",    ARM_ARCH_V7M,    FPU_NONE,        "Cortex-M3"),
   ARM_CPU_OPT ("cortex-m1",    ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M1"),
   ARM_CPU_OPT ("cortex-m0",    ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0"),
   ARM_CPU_OPT ("cortex-m0plus",        ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0+"),
-  ARM_CPU_OPT ("exynos-m1",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+  ARM_CPU_OPT ("exynos-m1",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "Samsung " \
                                                                  "Exynos M1"),
                                                                  "Samsung " \
                                                                  "Exynos M1"),
+  ARM_CPU_OPT ("falkor",       ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Qualcomm "
+                                                                 "Falkor"),
+  ARM_CPU_OPT ("qdf24xx",      ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Qualcomm "
+                                                                 "QDF24XX"),
+
   /* ??? XSCALE is really an architecture.  */
   ARM_CPU_OPT ("xscale",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
   /* ??? iwmmxt is not a processor.  */
   /* ??? XSCALE is really an architecture.  */
   ARM_CPU_OPT ("xscale",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
   /* ??? iwmmxt is not a processor.  */
@@ -24762,16 +25594,18 @@ static const struct arm_cpu_option_table arm_cpus[] =
   ARM_CPU_OPT ("ep9312",       ARM_FEATURE_LOW (ARM_AEXT_V4T, ARM_CEXT_MAVERICK),
                                                 FPU_ARCH_MAVERICK, "ARM920T"),
   /* Marvell processors.  */
   ARM_CPU_OPT ("ep9312",       ARM_FEATURE_LOW (ARM_AEXT_V4T, ARM_CEXT_MAVERICK),
                                                 FPU_ARCH_MAVERICK, "ARM920T"),
   /* Marvell processors.  */
-  ARM_CPU_OPT ("marvell-pj4",   ARM_FEATURE_CORE_LOW (ARM_AEXT_V7A | ARM_EXT_MP
-                                                     | ARM_EXT_SEC),
+  ARM_CPU_OPT ("marvell-pj4",   ARM_FEATURE_CORE (ARM_AEXT_V7A | ARM_EXT_MP
+                                                 | ARM_EXT_SEC,
+                                                 ARM_EXT2_V6T2_V8M),
                                                FPU_ARCH_VFP_V3D16, NULL),
                                                FPU_ARCH_VFP_V3D16, NULL),
-  ARM_CPU_OPT ("marvell-whitney", ARM_FEATURE_CORE_LOW (ARM_AEXT_V7A | ARM_EXT_MP
-                                                       | ARM_EXT_SEC),
+  ARM_CPU_OPT ("marvell-whitney", ARM_FEATURE_CORE (ARM_AEXT_V7A | ARM_EXT_MP
+                                                   | ARM_EXT_SEC,
+                                                   ARM_EXT2_V6T2_V8M),
                                               FPU_ARCH_NEON_VFP_V4, NULL),
   /* APM X-Gene family.  */
   ARM_CPU_OPT ("xgene1",        ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "APM X-Gene 1"),
                                               FPU_ARCH_NEON_VFP_V4, NULL),
   /* APM X-Gene family.  */
   ARM_CPU_OPT ("xgene1",        ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "APM X-Gene 1"),
-  ARM_CPU_OPT ("xgene2",        ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+  ARM_CPU_OPT ("xgene2",        ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                                                                  "APM X-Gene 2"),
 
   { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
                                                                  "APM X-Gene 2"),
 
   { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
@@ -24780,7 +25614,7 @@ static const struct arm_cpu_option_table arm_cpus[] =
 
 struct arm_arch_option_table
 {
 
 struct arm_arch_option_table
 {
-  char *name;
+  const char *name;
   size_t name_len;
   const arm_feature_set        value;
   const arm_feature_set        default_fpu;
   size_t name_len;
   const arm_feature_set        value;
   const arm_feature_set        default_fpu;
@@ -24812,11 +25646,17 @@ static const struct arm_arch_option_table arm_archs[] =
   ARM_ARCH_OPT ("armv6j",      ARM_ARCH_V6,     FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6k",      ARM_ARCH_V6K,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6z",      ARM_ARCH_V6Z,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6j",      ARM_ARCH_V6,     FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6k",      ARM_ARCH_V6K,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6z",      ARM_ARCH_V6Z,    FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv6zk",     ARM_ARCH_V6ZK,   FPU_ARCH_VFP),
+  /* The official spelling of this variant is ARMv6KZ, the name "armv6zk" is
+     kept to preserve existing behaviour.  */
+  ARM_ARCH_OPT ("armv6kz",     ARM_ARCH_V6KZ,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zk",     ARM_ARCH_V6KZ,   FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6t2",     ARM_ARCH_V6T2,   FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6kt2",    ARM_ARCH_V6KT2,  FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6zt2",    ARM_ARCH_V6ZT2,  FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6t2",     ARM_ARCH_V6T2,   FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6kt2",    ARM_ARCH_V6KT2,  FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6zt2",    ARM_ARCH_V6ZT2,  FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv6zkt2",   ARM_ARCH_V6ZKT2, FPU_ARCH_VFP),
+  /* The official spelling of this variant is ARMv6KZ, the name "armv6zkt2" is
+     kept to preserve existing behaviour.  */
+  ARM_ARCH_OPT ("armv6kzt2",   ARM_ARCH_V6KZT2, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zkt2",   ARM_ARCH_V6KZT2, FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6-m",     ARM_ARCH_V6M,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6s-m",    ARM_ARCH_V6SM,   FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7",       ARM_ARCH_V7,     FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6-m",     ARM_ARCH_V6M,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv6s-m",    ARM_ARCH_V6SM,   FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7",       ARM_ARCH_V7,     FPU_ARCH_VFP),
@@ -24830,8 +25670,12 @@ static const struct arm_arch_option_table arm_archs[] =
   ARM_ARCH_OPT ("armv7-r",     ARM_ARCH_V7R,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7-m",     ARM_ARCH_V7M,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7e-m",    ARM_ARCH_V7EM,   FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7-r",     ARM_ARCH_V7R,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7-m",     ARM_ARCH_V7M,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv7e-m",    ARM_ARCH_V7EM,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8-m.base",        ARM_ARCH_V8M_BASE, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8-m.main",        ARM_ARCH_V8M_MAIN, FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv8-a",     ARM_ARCH_V8A,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv8.1-a",   ARM_ARCH_V8_1A,  FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv8-a",     ARM_ARCH_V8A,    FPU_ARCH_VFP),
   ARM_ARCH_OPT ("armv8.1-a",   ARM_ARCH_V8_1A,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8.2-a",   ARM_ARCH_V8_2A,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8.3-a",   ARM_ARCH_V8_3A,  FPU_ARCH_VFP),
   ARM_ARCH_OPT ("xscale",      ARM_ARCH_XSCALE, FPU_ARCH_VFP),
   ARM_ARCH_OPT ("iwmmxt",      ARM_ARCH_IWMMXT, FPU_ARCH_VFP),
   ARM_ARCH_OPT ("iwmmxt2",     ARM_ARCH_IWMMXT2,FPU_ARCH_VFP),
   ARM_ARCH_OPT ("xscale",      ARM_ARCH_XSCALE, FPU_ARCH_VFP),
   ARM_ARCH_OPT ("iwmmxt",      ARM_ARCH_IWMMXT, FPU_ARCH_VFP),
   ARM_ARCH_OPT ("iwmmxt2",     ARM_ARCH_IWMMXT2,FPU_ARCH_VFP),
@@ -24842,16 +25686,20 @@ static const struct arm_arch_option_table arm_archs[] =
 /* ISA extensions in the co-processor and main instruction set space.  */
 struct arm_option_extension_value_table
 {
 /* ISA extensions in the co-processor and main instruction set space.  */
 struct arm_option_extension_value_table
 {
-  char *name;
+  const char *name;
   size_t name_len;
   const arm_feature_set merge_value;
   const arm_feature_set clear_value;
   size_t name_len;
   const arm_feature_set merge_value;
   const arm_feature_set clear_value;
-  const arm_feature_set allowed_archs;
+  /* List of architectures for which an extension is available.  ARM_ARCH_NONE
+     indicates that an extension is available for all architectures while
+     ARM_ANY marks an empty entry.  */
+  const arm_feature_set allowed_archs[2];
 };
 
 /* The following table must be in alphabetical order with a NULL last entry.
    */
 };
 
 /* The following table must be in alphabetical order with a NULL last entry.
    */
-#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, AA }
+#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, { AA, ARM_ANY } }
+#define ARM_EXT_OPT2(N, M, C, AA1, AA2) { N, sizeof (N) - 1, M, C, {AA1, AA2} }
 static const struct arm_option_extension_value_table arm_extensions[] =
 {
   ARM_EXT_OPT ("crc",  ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
 static const struct arm_option_extension_value_table arm_extensions[] =
 {
   ARM_EXT_OPT ("crc",  ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
@@ -24859,49 +25707,61 @@ static const struct arm_option_extension_value_table arm_extensions[] =
   ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                         ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
   ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
                         ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("dsp",  ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+                       ARM_FEATURE_CORE (ARM_EXT_V7M, ARM_EXT2_V8M)),
   ARM_EXT_OPT ("fp",     FPU_ARCH_VFP_ARMV8, ARM_FEATURE_COPROC (FPU_VFP_ARMV8),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
   ARM_EXT_OPT ("fp",     FPU_ARCH_VFP_ARMV8, ARM_FEATURE_COPROC (FPU_VFP_ARMV8),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
-  ARM_EXT_OPT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
+  ARM_EXT_OPT ("fp16",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+                       ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+                       ARM_ARCH_V8_2A),
+  ARM_EXT_OPT2 ("idiv",        ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
-                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V7A),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V7R)),
   ARM_EXT_OPT ("iwmmxt",ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT),
   ARM_EXT_OPT ("iwmmxt",ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT),
-                       ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ANY),
+                       ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ARCH_NONE),
   ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2),
   ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2),
-                       ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), ARM_ANY),
+                       ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), ARM_ARCH_NONE),
   ARM_EXT_OPT ("maverick", ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK),
   ARM_EXT_OPT ("maverick", ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK),
-                       ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), ARM_ANY),
-  ARM_EXT_OPT ("mp",   ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
+                       ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), ARM_ARCH_NONE),
+  ARM_EXT_OPT2 ("mp",  ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
-                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)),
-  ARM_EXT_OPT ("simd",   FPU_ARCH_NEON_VFP_ARMV8,
-                       ARM_FEATURE_COPROC (FPU_NEON_ARMV8),
-                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V7A),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V7R)),
   ARM_EXT_OPT ("os",   ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V6M)),
   ARM_EXT_OPT ("pan",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN),
                        ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_PAN, 0),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
   ARM_EXT_OPT ("os",   ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V6M)),
   ARM_EXT_OPT ("pan",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN),
                        ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_PAN, 0),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
-  ARM_EXT_OPT ("sec",  ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
+  ARM_EXT_OPT ("ras",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS),
+                       ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_RAS, 0),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("rdma",  FPU_ARCH_NEON_VFP_ARMV8_1,
+                       ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT2 ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
-                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V7A)),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V6K),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
+  ARM_EXT_OPT ("simd",  FPU_ARCH_NEON_VFP_ARMV8,
+                       ARM_FEATURE_COPROC (FPU_NEON_ARMV8),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
   ARM_EXT_OPT ("virt", ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT | ARM_EXT_ADIV
                                     | ARM_EXT_DIV),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
   ARM_EXT_OPT ("virt", ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT | ARM_EXT_ADIV
                                     | ARM_EXT_DIV),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT),
                                   ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
-  ARM_EXT_OPT ("rdma",  FPU_ARCH_NEON_VFP_ARMV8,
-                       ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA),
-                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
   ARM_EXT_OPT ("xscale",ARM_FEATURE_COPROC (ARM_CEXT_XSCALE),
   ARM_EXT_OPT ("xscale",ARM_FEATURE_COPROC (ARM_CEXT_XSCALE),
-                       ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), ARM_ANY),
-  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, ARM_ARCH_NONE }
+                       ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), ARM_ARCH_NONE),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, { ARM_ARCH_NONE, ARM_ARCH_NONE } }
 };
 #undef ARM_EXT_OPT
 
 /* ISA floating-point and Advanced SIMD extensions.  */
 struct arm_option_fpu_value_table
 {
 };
 #undef ARM_EXT_OPT
 
 /* ISA floating-point and Advanced SIMD extensions.  */
 struct arm_option_fpu_value_table
 {
-  char *name;
+  const char *name;
   const arm_feature_set value;
 };
 
   const arm_feature_set value;
 };
 
@@ -24921,7 +25781,7 @@ static const struct arm_option_fpu_value_table arm_fpus[] =
   {"softvfp+vfp",      FPU_ARCH_VFP_V2},
   {"vfp",              FPU_ARCH_VFP_V2},
   {"vfp9",             FPU_ARCH_VFP_V2},
   {"softvfp+vfp",      FPU_ARCH_VFP_V2},
   {"vfp",              FPU_ARCH_VFP_V2},
   {"vfp9",             FPU_ARCH_VFP_V2},
-  {"vfp3",              FPU_ARCH_VFP_V3}, /* For backwards compatbility.  */
+  {"vfp3",             FPU_ARCH_VFP_V3}, /* Undocumented, use vfpv3.  */
   {"vfp10",            FPU_ARCH_VFP_V2},
   {"vfp10-r0",         FPU_ARCH_VFP_V1},
   {"vfpxd",            FPU_ARCH_VFP_V1xD},
   {"vfp10",            FPU_ARCH_VFP_V2},
   {"vfp10-r0",         FPU_ARCH_VFP_V1},
   {"vfpxd",            FPU_ARCH_VFP_V1xD},
@@ -24934,10 +25794,11 @@ static const struct arm_option_fpu_value_table arm_fpus[] =
   {"vfpv3xd-fp16",     FPU_ARCH_VFP_V3xD_FP16},
   {"arm1020t",         FPU_ARCH_VFP_V1},
   {"arm1020e",         FPU_ARCH_VFP_V2},
   {"vfpv3xd-fp16",     FPU_ARCH_VFP_V3xD_FP16},
   {"arm1020t",         FPU_ARCH_VFP_V1},
   {"arm1020e",         FPU_ARCH_VFP_V2},
-  {"arm1136jfs",       FPU_ARCH_VFP_V2},
+  {"arm1136jfs",       FPU_ARCH_VFP_V2}, /* Undocumented, use arm1136jf-s.  */
   {"arm1136jf-s",      FPU_ARCH_VFP_V2},
   {"maverick",         FPU_ARCH_MAVERICK},
   {"arm1136jf-s",      FPU_ARCH_VFP_V2},
   {"maverick",         FPU_ARCH_MAVERICK},
-  {"neon",              FPU_ARCH_VFP_V3_PLUS_NEON_V1},
+  {"neon",             FPU_ARCH_VFP_V3_PLUS_NEON_V1},
+  {"neon-vfpv3",       FPU_ARCH_VFP_V3_PLUS_NEON_V1},
   {"neon-fp16",                FPU_ARCH_NEON_FP16},
   {"vfpv4",            FPU_ARCH_VFP_V4},
   {"vfpv4-d16",                FPU_ARCH_VFP_V4D16},
   {"neon-fp16",                FPU_ARCH_NEON_FP16},
   {"vfpv4",            FPU_ARCH_VFP_V4},
   {"vfpv4-d16",                FPU_ARCH_VFP_V4D16},
@@ -24950,12 +25811,14 @@ static const struct arm_option_fpu_value_table arm_fpus[] =
   {"crypto-neon-fp-armv8",
                        FPU_ARCH_CRYPTO_NEON_VFP_ARMV8},
   {"neon-fp-armv8.1",  FPU_ARCH_NEON_VFP_ARMV8_1},
   {"crypto-neon-fp-armv8",
                        FPU_ARCH_CRYPTO_NEON_VFP_ARMV8},
   {"neon-fp-armv8.1",  FPU_ARCH_NEON_VFP_ARMV8_1},
+  {"crypto-neon-fp-armv8.1",
+                       FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1},
   {NULL,               ARM_ARCH_NONE}
 };
 
 struct arm_option_value_table
 {
   {NULL,               ARM_ARCH_NONE}
 };
 
 struct arm_option_value_table
 {
-  char *name;
+  const char *name;
   long value;
 };
 
   long value;
 };
 
@@ -24980,17 +25843,16 @@ static const struct arm_option_value_table arm_eabis[] =
 
 struct arm_long_option_table
 {
 
 struct arm_long_option_table
 {
-  char * option;               /* Substring to match.  */
-  char * help;                 /* Help information.  */
-  int (* func) (char * subopt);        /* Function to decode sub-option.  */
-  char * deprecated;           /* If non-null, print this message.  */
+  const char * option;         /* Substring to match.  */
+  const char * help;                   /* Help information.  */
+  int (* func) (const char * subopt);  /* Function to decode sub-option.  */
+  const char * deprecated;             /* If non-null, print this message.  */
 };
 
 static bfd_boolean
 };
 
 static bfd_boolean
-arm_parse_extension (char *str, const arm_feature_set **opt_p)
+arm_parse_extension (const char *str, const arm_feature_set **opt_p)
 {
 {
-  arm_feature_set *ext_set = (arm_feature_set *)
-      xmalloc (sizeof (arm_feature_set));
+  arm_feature_set *ext_set = XNEW (arm_feature_set);
 
   /* We insist on extensions being specified in alphabetical order, and with
      extensions being added before being removed.  We achieve this by having
 
   /* We insist on extensions being specified in alphabetical order, and with
      extensions being added before being removed.  We achieve this by having
@@ -24999,6 +25861,7 @@ arm_parse_extension (char *str, const arm_feature_set **opt_p)
      or removing it (0) and only allowing it to change in the order
      -1 -> 1 -> 0.  */
   const struct arm_option_extension_value_table * opt = NULL;
      or removing it (0) and only allowing it to change in the order
      -1 -> 1 -> 0.  */
   const struct arm_option_extension_value_table * opt = NULL;
+  const arm_feature_set arm_any = ARM_ANY;
   int adding_value = -1;
 
   /* Copy the feature set, so that we can modify it.  */
   int adding_value = -1;
 
   /* Copy the feature set, so that we can modify it.  */
@@ -25007,7 +25870,7 @@ arm_parse_extension (char *str, const arm_feature_set **opt_p)
 
   while (str != NULL && *str != 0)
     {
 
   while (str != NULL && *str != 0)
     {
-      char *ext;
+      const char *ext;
       size_t len;
 
       if (*str != '+')
       size_t len;
 
       if (*str != '+')
@@ -25063,8 +25926,18 @@ arm_parse_extension (char *str, const arm_feature_set **opt_p)
       for (; opt->name != NULL; opt++)
        if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
          {
       for (; opt->name != NULL; opt++)
        if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
          {
+           int i, nb_allowed_archs =
+             sizeof (opt->allowed_archs) / sizeof (opt->allowed_archs[0]);
            /* Check we can apply the extension to this architecture.  */
            /* Check we can apply the extension to this architecture.  */
-           if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs))
+           for (i = 0; i < nb_allowed_archs; i++)
+             {
+               /* Empty entry.  */
+               if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
+                 continue;
+               if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *ext_set))
+                 break;
+             }
+           if (i == nb_allowed_archs)
              {
                as_bad (_("extension does not apply to the base architecture"));
                return FALSE;
              {
                as_bad (_("extension does not apply to the base architecture"));
                return FALSE;
@@ -25110,10 +25983,10 @@ arm_parse_extension (char *str, const arm_feature_set **opt_p)
 }
 
 static bfd_boolean
 }
 
 static bfd_boolean
-arm_parse_cpu (char *str)
+arm_parse_cpu (const char *str)
 {
   const struct arm_cpu_option_table *opt;
 {
   const struct arm_cpu_option_table *opt;
-  char *ext = strchr (str, '+');
+  const char *ext = strchr (str, '+');
   size_t len;
 
   if (ext != NULL)
   size_t len;
 
   if (ext != NULL)
@@ -25133,11 +26006,17 @@ arm_parse_cpu (char *str)
        mcpu_cpu_opt = &opt->value;
        mcpu_fpu_opt = &opt->default_fpu;
        if (opt->canonical_name)
        mcpu_cpu_opt = &opt->value;
        mcpu_fpu_opt = &opt->default_fpu;
        if (opt->canonical_name)
-         strcpy (selected_cpu_name, opt->canonical_name);
+         {
+           gas_assert (sizeof selected_cpu_name > strlen (opt->canonical_name));
+           strcpy (selected_cpu_name, opt->canonical_name);
+         }
        else
          {
            size_t i;
 
        else
          {
            size_t i;
 
+           if (len >= sizeof selected_cpu_name)
+             len = (sizeof selected_cpu_name) - 1;
+
            for (i = 0; i < len; i++)
              selected_cpu_name[i] = TOUPPER (opt->name[i]);
            selected_cpu_name[i] = 0;
            for (i = 0; i < len; i++)
              selected_cpu_name[i] = TOUPPER (opt->name[i]);
            selected_cpu_name[i] = 0;
@@ -25154,10 +26033,10 @@ arm_parse_cpu (char *str)
 }
 
 static bfd_boolean
 }
 
 static bfd_boolean
-arm_parse_arch (char *str)
+arm_parse_arch (const char *str)
 {
   const struct arm_arch_option_table *opt;
 {
   const struct arm_arch_option_table *opt;
-  char *ext = strchr (str, '+');
+  const char *ext = strchr (str, '+');
   size_t len;
 
   if (ext != NULL)
   size_t len;
 
   if (ext != NULL)
@@ -25189,7 +26068,7 @@ arm_parse_arch (char *str)
 }
 
 static bfd_boolean
 }
 
 static bfd_boolean
-arm_parse_fpu (char * str)
+arm_parse_fpu (const char * str)
 {
   const struct arm_option_fpu_value_table * opt;
 
 {
   const struct arm_option_fpu_value_table * opt;
 
@@ -25205,7 +26084,7 @@ arm_parse_fpu (char * str)
 }
 
 static bfd_boolean
 }
 
 static bfd_boolean
-arm_parse_float_abi (char * str)
+arm_parse_float_abi (const char * str)
 {
   const struct arm_option_value_table * opt;
 
 {
   const struct arm_option_value_table * opt;
 
@@ -25222,7 +26101,7 @@ arm_parse_float_abi (char * str)
 
 #ifdef OBJ_ELF
 static bfd_boolean
 
 #ifdef OBJ_ELF
 static bfd_boolean
-arm_parse_eabi (char * str)
+arm_parse_eabi (const char * str)
 {
   const struct arm_option_value_table *opt;
 
 {
   const struct arm_option_value_table *opt;
 
@@ -25238,7 +26117,7 @@ arm_parse_eabi (char * str)
 #endif
 
 static bfd_boolean
 #endif
 
 static bfd_boolean
-arm_parse_it_mode (char * str)
+arm_parse_it_mode (const char * str)
 {
   bfd_boolean ret = TRUE;
 
 {
   bfd_boolean ret = TRUE;
 
@@ -25261,7 +26140,7 @@ arm_parse_it_mode (char * str)
 }
 
 static bfd_boolean
 }
 
 static bfd_boolean
-arm_ccs_mode (char * unused ATTRIBUTE_UNUSED)
+arm_ccs_mode (const char * unused ATTRIBUTE_UNUSED)
 {
   codecomposer_syntax = TRUE;
   arm_comment_chars[0] = ';';
 {
   codecomposer_syntax = TRUE;
   arm_comment_chars[0] = ';';
@@ -25291,7 +26170,7 @@ struct arm_long_option_table arm_long_opts[] =
 };
 
 int
 };
 
 int
-md_parse_option (int c, char * arg)
+md_parse_option (int c, const char * arg)
 {
   struct arm_option_table *opt;
   const struct arm_legacy_option_table *fopt;
 {
   struct arm_option_table *opt;
   const struct arm_legacy_option_table *fopt;
@@ -25419,8 +26298,9 @@ typedef struct
   arm_feature_set flags;
 } cpu_arch_ver_table;
 
   arm_feature_set flags;
 } cpu_arch_ver_table;
 
-/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
-   least features first.  */
+/* Mapping from CPU features to EABI CPU arch values.  As a general rule, table
+   must be sorted least features first but some reordering is needed, eg. for
+   Thumb-2 instructions to be detected as coming from ARMv6T2.  */
 static const cpu_arch_ver_table cpu_arch_ver[] =
 {
     {1, ARM_ARCH_V4},
 static const cpu_arch_ver_table cpu_arch_ver[] =
 {
     {1, ARM_ARCH_V4},
@@ -25439,6 +26319,8 @@ static const cpu_arch_ver_table cpu_arch_ver[] =
     {10, ARM_ARCH_V7R},
     {10, ARM_ARCH_V7M},
     {14, ARM_ARCH_V8A},
     {10, ARM_ARCH_V7R},
     {10, ARM_ARCH_V7M},
     {14, ARM_ARCH_V8A},
+    {16, ARM_ARCH_V8M_BASE},
+    {17, ARM_ARCH_V8M_MAIN},
     {0, ARM_ARCH_NONE}
 };
 
     {0, ARM_ARCH_NONE}
 };
 
@@ -25469,8 +26351,10 @@ aeabi_set_public_attributes (void)
   char profile;
   int virt_sec = 0;
   int fp16_optional = 0;
   char profile;
   int virt_sec = 0;
   int fp16_optional = 0;
+  arm_feature_set arm_arch = ARM_ARCH_NONE;
   arm_feature_set flags;
   arm_feature_set tmp;
   arm_feature_set flags;
   arm_feature_set tmp;
+  arm_feature_set arm_arch_v8m_base = ARM_ARCH_V8M_BASE;
   const cpu_arch_ver_table *p;
 
   /* Choose the architecture based on the capabilities of the requested cpu
   const cpu_arch_ver_table *p;
 
   /* Choose the architecture based on the capabilities of the requested cpu
@@ -25507,6 +26391,7 @@ aeabi_set_public_attributes (void)
       if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
        {
          arch = p->val;
       if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
        {
          arch = p->val;
+         arm_arch = p->flags;
          ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
        }
     }
          ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
        }
     }
@@ -25519,11 +26404,31 @@ aeabi_set_public_attributes (void)
      actually used.  Perhaps we should separate out the specified
      and implicit cases.  Avoid taking this path for -march=all by
      checking for contradictory v7-A / v7-M features.  */
      actually used.  Perhaps we should separate out the specified
      and implicit cases.  Avoid taking this path for -march=all by
      checking for contradictory v7-A / v7-M features.  */
-  if (arch == 10
+  if (arch == TAG_CPU_ARCH_V7
       && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
       && ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)
       && ARM_CPU_HAS_FEATURE (flags, arm_ext_v6_dsp))
       && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
       && ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)
       && ARM_CPU_HAS_FEATURE (flags, arm_ext_v6_dsp))
-    arch = 13;
+    {
+      arch = TAG_CPU_ARCH_V7E_M;
+      arm_arch = (arm_feature_set) ARM_ARCH_V7EM;
+    }
+
+  ARM_CLEAR_FEATURE (tmp, flags, arm_arch_v8m_base);
+  if (arch == TAG_CPU_ARCH_V8M_BASE && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
+    {
+      arch = TAG_CPU_ARCH_V8M_MAIN;
+      arm_arch = (arm_feature_set) ARM_ARCH_V8M_MAIN;
+    }
+
+  /* In cpu_arch_ver ARMv8-A is before ARMv8-M for atomics to be detected as
+     coming from ARMv8-A.  However, since ARMv8-A has more instructions than
+     ARMv8-M, -march=all must be detected as ARMv8-A.  */
+  if (arch == TAG_CPU_ARCH_V8M_MAIN
+      && ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
+    {
+      arch = TAG_CPU_ARCH_V8;
+      arm_arch = (arm_feature_set) ARM_ARCH_V8A;
+    }
 
   /* Tag_CPU_name.  */
   if (selected_cpu_name[0])
 
   /* Tag_CPU_name.  */
   if (selected_cpu_name[0])
@@ -25546,7 +26451,10 @@ aeabi_set_public_attributes (void)
   aeabi_set_attribute_int (Tag_CPU_arch, arch);
 
   /* Tag_CPU_arch_profile.  */
   aeabi_set_attribute_int (Tag_CPU_arch, arch);
 
   /* Tag_CPU_arch_profile.  */
-  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
+      || ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
+      || (ARM_CPU_HAS_FEATURE (flags, arm_ext_atomics)
+         && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m_m_only)))
     profile = 'A';
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
     profile = 'R';
     profile = 'A';
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
     profile = 'R';
@@ -25558,6 +26466,17 @@ aeabi_set_public_attributes (void)
   if (profile != '\0')
     aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
 
   if (profile != '\0')
     aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
 
+  /* Tag_DSP_extension.  */
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_dsp))
+    {
+      arm_feature_set ext;
+
+      /* DSP instructions not in architecture.  */
+      ARM_CLEAR_FEATURE (ext, flags, arm_arch);
+      if (ARM_CPU_HAS_FEATURE (ext, arm_ext_dsp))
+       aeabi_set_attribute_int (Tag_DSP_extension, 1);
+    }
+
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
       || arch == 0)
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
       || arch == 0)
@@ -25566,8 +26485,18 @@ aeabi_set_public_attributes (void)
   /* Tag_THUMB_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v4t)
       || arch == 0)
   /* Tag_THUMB_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v4t)
       || arch == 0)
-    aeabi_set_attribute_int (Tag_THUMB_ISA_use,
-       ARM_CPU_HAS_FEATURE (flags, arm_arch_t2) ? 2 : 1);
+    {
+      int thumb_isa_use;
+
+      if (!ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
+         && ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m_m_only))
+       thumb_isa_use = 3;
+      else if (ARM_CPU_HAS_FEATURE (flags, arm_arch_t2))
+       thumb_isa_use = 2;
+      else
+       thumb_isa_use = 1;
+      aeabi_set_attribute_int (Tag_THUMB_ISA_use, thumb_isa_use);
+    }
 
   /* Tag_VFP_arch.  */
   if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8xd))
 
   /* Tag_VFP_arch.  */
   if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8xd))
@@ -25606,7 +26535,9 @@ aeabi_set_public_attributes (void)
     aeabi_set_attribute_int (Tag_WMMX_arch, 1);
 
   /* Tag_Advanced_SIMD_arch (formerly Tag_NEON_arch).  */
     aeabi_set_attribute_int (Tag_WMMX_arch, 1);
 
   /* Tag_Advanced_SIMD_arch (formerly Tag_NEON_arch).  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_armv8))
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v8_1))
+    aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 4);
+  else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_armv8))
     aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 3);
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1))
     {
     aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 3);
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1))
     {
@@ -25631,12 +26562,15 @@ aeabi_set_public_attributes (void)
      in ARM state, or when Thumb integer divide instructions have been used,
      but we have no architecture profile set, nor have we any ARM instructions.
 
      in ARM state, or when Thumb integer divide instructions have been used,
      but we have no architecture profile set, nor have we any ARM instructions.
 
-     For ARMv8 we set the tag to 0 as integer divide is implied by the base
-     architecture.
+     For ARMv8-A and ARMv8-M we set the tag to 0 as integer divide is implied
+     by the base architecture.
 
      For new architectures we will have to check these tests.  */
 
      For new architectures we will have to check these tests.  */
-  gas_assert (arch <= TAG_CPU_ARCH_V8);
-  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v8))
+  gas_assert (arch <= TAG_CPU_ARCH_V8
+             || (arch >= TAG_CPU_ARCH_V8M_BASE
+                 && arch <= TAG_CPU_ARCH_V8M_MAIN));
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
+      || ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m))
     aeabi_set_attribute_int (Tag_DIV_use, 0);
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv)
           || (profile == '\0'
     aeabi_set_attribute_int (Tag_DIV_use, 0);
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv)
           || (profile == '\0'
@@ -25781,6 +26715,7 @@ static void
 s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
 {
   const struct arm_option_extension_value_table *opt;
 s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
 {
   const struct arm_option_extension_value_table *opt;
+  const arm_feature_set arm_any = ARM_ANY;
   char saved_char;
   char *name;
   int adding_value = 1;
   char saved_char;
   char *name;
   int adding_value = 1;
@@ -25801,7 +26736,18 @@ s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
   for (opt = arm_extensions; opt->name != NULL; opt++)
     if (streq (opt->name, name))
       {
   for (opt = arm_extensions; opt->name != NULL; opt++)
     if (streq (opt->name, name))
       {
-       if (!ARM_CPU_HAS_FEATURE (*mcpu_cpu_opt, opt->allowed_archs))
+       int i, nb_allowed_archs =
+         sizeof (opt->allowed_archs) / sizeof (opt->allowed_archs[i]);
+       for (i = 0; i < nb_allowed_archs; i++)
+         {
+           /* Empty entry.  */
+           if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
+             continue;
+           if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *mcpu_cpu_opt))
+             break;
+         }
+
+       if (i == nb_allowed_archs)
          {
            as_bad (_("architectural extension `%s' is not allowed for the "
                      "current base architecture"), name);
          {
            as_bad (_("architectural extension `%s' is not allowed for the "
                      "current base architecture"), name);
@@ -25926,6 +26872,7 @@ arm_convert_symbolic_attribute (const char *name)
       T (Tag_conformance),
       T (Tag_T2EE_use),
       T (Tag_Virtualization_use),
       T (Tag_conformance),
       T (Tag_T2EE_use),
       T (Tag_Virtualization_use),
+      T (Tag_DSP_extension),
       /* We deliberately do not include Tag_MPextension_use_legacy.  */
 #undef T
     };
       /* We deliberately do not include Tag_MPextension_use_legacy.  */
 #undef T
     };
This page took 0.1183 seconds and 4 git commands to generate.