]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-arm.c
[binutils, ARM, 15/16] Add support for VSCCLRM
[thirdparty/binutils-gdb.git] / gas / config / tc-arm.c
index 9a12bcc44d96cccc2ea0ec0411e743d9fb4f0a7d..b5dc3eb212ea414e86c8620160496d8f1ee508b6 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994-2016 Free Software Foundation, Inc.
+   Copyright (C) 1994-2019 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)
@@ -75,6 +75,9 @@ static struct
   unsigned       sp_restored:1;
 } unwind;
 
+/* Whether --fdpic was given.  */
+static int arm_fdpic;
+
 #endif /* OBJ_ELF */
 
 /* Results from operand parsing worker functions.  */
@@ -123,7 +126,12 @@ enum arm_float_abi
 
 #define streq(a, b)          (strcmp (a, b) == 0)
 
+/* Current set of feature bits available (CPU+FPU).  Different from
+   selected_cpu + selected_fpu in case of autodetection since the CPU
+   feature bits are then all set.  */
 static arm_feature_set cpu_variant;
+/* Feature bits used in each execution state.  Used to set build attribute
+   (in particular Tag_*_ISA_use) in CPU autodetection mode.  */
 static arm_feature_set arm_arch_used;
 static arm_feature_set thumb_arch_used;
 
@@ -143,15 +151,24 @@ bfd_boolean codecomposer_syntax = FALSE;
 /* Variables that we set while parsing command-line options.  Once all
    options have been read we re-process these values to set the real
    assembly flags.  */
+
+/* CPU and FPU feature bits set for legacy CPU and FPU options (eg. -marm1
+   instead of -mcpu=arm1).  */
 static const arm_feature_set *legacy_cpu = NULL;
 static const arm_feature_set *legacy_fpu = NULL;
 
+/* CPU, extension and FPU feature bits selected by -mcpu.  */
 static const arm_feature_set *mcpu_cpu_opt = NULL;
+static arm_feature_set *mcpu_ext_opt = NULL;
 static const arm_feature_set *mcpu_fpu_opt = NULL;
+
+/* CPU, extension and FPU feature bits selected by -march.  */
 static const arm_feature_set *march_cpu_opt = NULL;
+static arm_feature_set *march_ext_opt = NULL;
 static const arm_feature_set *march_fpu_opt = NULL;
+
+/* Feature bits selected by -mfpu.  */
 static const arm_feature_set *mfpu_opt = NULL;
-static const arm_feature_set *object_arch = NULL;
 
 /* Constants for known architecture features.  */
 static const arm_feature_set fpu_default = FPU_DEFAULT;
@@ -171,7 +188,7 @@ static const arm_feature_set cpu_default = CPU_DEFAULT;
 #endif
 
 static const arm_feature_set arm_ext_v1 = ARM_FEATURE_CORE_LOW (ARM_EXT_V1);
-static const arm_feature_set arm_ext_v2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V1);
+static const arm_feature_set arm_ext_v2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V2);
 static const arm_feature_set arm_ext_v2s = ARM_FEATURE_CORE_LOW (ARM_EXT_V2S);
 static const arm_feature_set arm_ext_v3 = ARM_FEATURE_CORE_LOW (ARM_EXT_V3);
 static const arm_feature_set arm_ext_v3m = ARM_FEATURE_CORE_LOW (ARM_EXT_V3M);
@@ -187,7 +204,9 @@ static const arm_feature_set arm_ext_v5j = ARM_FEATURE_CORE_LOW (ARM_EXT_V5J);
 static const arm_feature_set arm_ext_v6 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6);
 static const arm_feature_set arm_ext_v6k = ARM_FEATURE_CORE_LOW (ARM_EXT_V6K);
 static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6T2);
-static const arm_feature_set arm_ext_v6m = ARM_FEATURE_CORE_LOW (ARM_EXT_V6M);
+/* Only for compatability of hint instructions.  */
+static const arm_feature_set arm_ext_v6k_v6t2 =
+  ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V6T2);
 static const arm_feature_set arm_ext_v6_notm =
   ARM_FEATURE_CORE_LOW (ARM_EXT_V6_NOTM);
 static const arm_feature_set arm_ext_v6_dsp =
@@ -201,11 +220,11 @@ 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 ATTRIBUTE_UNUSED 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 =
-  ARM_FEATURE_CORE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M,
+  ARM_FEATURE_CORE (ARM_EXT_V6M | 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);
@@ -216,6 +235,8 @@ 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);
+static const arm_feature_set arm_ext_v8_1m_main =
+ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_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);
@@ -234,14 +255,24 @@ static const arm_feature_set arm_ext_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_fp16_fml =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_FML);
+static const arm_feature_set arm_ext_v8_2 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A);
+static const arm_feature_set arm_ext_v8_3 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A);
+static const arm_feature_set arm_ext_sb =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB);
+static const arm_feature_set arm_ext_predres =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES);
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
+#ifdef OBJ_ELF
+static const arm_feature_set fpu_any = FPU_ANY;
+#endif
 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;
-#ifdef OBJ_ELF
-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);
@@ -291,10 +322,24 @@ 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_RDMA);
+static const arm_feature_set fpu_neon_ext_dotprod =
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_DOTPROD);
 
 static int mfloat_abi_opt = -1;
-/* Record user cpu selection for object attributes.  */
+/* Architecture feature bits selected by the last -mcpu/-march or .cpu/.arch
+   directive.  */
+static arm_feature_set selected_arch = ARM_ARCH_NONE;
+/* Extension feature bits selected by the last -mcpu/-march or .arch_extension
+   directive.  */
+static arm_feature_set selected_ext = ARM_ARCH_NONE;
+/* Feature bits selected by the last -mcpu/-march or by the combination of the
+   last .cpu/.arch directive .arch_extension directives since that
+   directive.  */
 static arm_feature_set selected_cpu = ARM_ARCH_NONE;
+/* FPU feature bits selected by the last -mfpu or .fpu directive.  */
+static arm_feature_set selected_fpu = FPU_NONE;
+/* Feature bits selected by the last .object_arch directive.  */
+static arm_feature_set selected_object_arch = ARM_ARCH_NONE;
 /* Must be long enough to hold any of the names in arm_cpus.  */
 static char selected_cpu_name[20];
 
@@ -418,6 +463,7 @@ enum it_instruction_type
 
 /* The maximum number of operands we need.  */
 #define ARM_IT_MAX_OPERANDS 6
+#define ARM_IT_MAX_RELOCS 3
 
 struct arm_it
 {
@@ -442,7 +488,7 @@ struct arm_it
     bfd_reloc_code_real_type type;
     expressionS                     exp;
     int                             pc_rel;
-  } reloc;
+  } relocs[ARM_IT_MAX_RELOCS];
 
   enum it_instruction_type it_insn_type;
 
@@ -535,7 +581,7 @@ struct asm_barrier_opt
 
 struct reloc_entry
 {
-  const char *                    name;
+  const char *              name;
   bfd_reloc_code_real_type  reloc;
 };
 
@@ -562,7 +608,8 @@ struct neon_typed_alias
 };
 
 /* ARM register categories.  This includes coprocessor numbers and various
-   architecture extensions' registers. */
+   architecture extensions' registers.  Each entry should have an error message
+   in reg_expected_msgs below.  */
 enum arm_reg_type
 {
   REG_TYPE_RN,
@@ -574,6 +621,7 @@ enum arm_reg_type
   REG_TYPE_NQ,
   REG_TYPE_VFSD,
   REG_TYPE_NDQ,
+  REG_TYPE_NSD,
   REG_TYPE_NSDQ,
   REG_TYPE_VFC,
   REG_TYPE_MVF,
@@ -605,27 +653,30 @@ struct reg_entry
 /* Diagnostics used when we don't get a register of the expected type. */
 const char * const reg_expected_msgs[] =
 {
-  N_("ARM register expected"),
-  N_("bad or missing co-processor number"),
-  N_("co-processor register expected"),
-  N_("FPA register expected"),
-  N_("VFP single precision register expected"),
-  N_("VFP/Neon double precision register expected"),
-  N_("Neon quad precision register expected"),
-  N_("VFP single or double precision register expected"),
-  N_("Neon double or quad precision register expected"),
-  N_("VFP single, double or Neon quad precision register expected"),
-  N_("VFP system register expected"),
-  N_("Maverick MVF register expected"),
-  N_("Maverick MVD register expected"),
-  N_("Maverick MVFX register expected"),
-  N_("Maverick MVDX register expected"),
-  N_("Maverick MVAX register expected"),
-  N_("Maverick DSPSC register expected"),
-  N_("iWMMXt data register expected"),
-  N_("iWMMXt control register expected"),
-  N_("iWMMXt scalar register expected"),
-  N_("XScale accumulator register expected"),
+  [REG_TYPE_RN]            = N_("ARM register expected"),
+  [REG_TYPE_CP]            = N_("bad or missing co-processor number"),
+  [REG_TYPE_CN]            = N_("co-processor register expected"),
+  [REG_TYPE_FN]            = N_("FPA register expected"),
+  [REG_TYPE_VFS]    = N_("VFP single precision register expected"),
+  [REG_TYPE_VFD]    = N_("VFP/Neon double precision register expected"),
+  [REG_TYPE_NQ]            = N_("Neon quad precision register expected"),
+  [REG_TYPE_VFSD]   = N_("VFP single or double precision register expected"),
+  [REG_TYPE_NDQ]    = N_("Neon double or quad precision register expected"),
+  [REG_TYPE_NSD]    = N_("Neon single or double precision register expected"),
+  [REG_TYPE_NSDQ]   = N_("VFP single, double or Neon quad precision register"
+                        " expected"),
+  [REG_TYPE_VFC]    = N_("VFP system register expected"),
+  [REG_TYPE_MVF]    = N_("Maverick MVF register expected"),
+  [REG_TYPE_MVD]    = N_("Maverick MVD register expected"),
+  [REG_TYPE_MVFX]   = N_("Maverick MVFX register expected"),
+  [REG_TYPE_MVDX]   = N_("Maverick MVDX register expected"),
+  [REG_TYPE_MVAX]   = N_("Maverick MVAX register expected"),
+  [REG_TYPE_DSPSC]  = N_("Maverick DSPSC register expected"),
+  [REG_TYPE_MMXWR]  = N_("iWMMXt data register expected"),
+  [REG_TYPE_MMXWC]  = N_("iWMMXt control register expected"),
+  [REG_TYPE_MMXWCG] = N_("iWMMXt scalar register expected"),
+  [REG_TYPE_XSCALE] = N_("XScale accumulator register expected"),
+  [REG_TYPE_RNB]    = N_("")
 };
 
 /* Some well known registers that we refer to directly elsewhere.  */
@@ -795,6 +846,7 @@ struct asm_opcode
 #define BAD_THUMB32    _("instruction not supported in Thumb16 mode")
 #define BAD_ADDR_MODE   _("instruction does not accept this addressing mode");
 #define BAD_BRANCH     _("branch must be last instruction in IT block")
+#define BAD_BRANCH_OFF _("branch out of range or not a multiple of 2")
 #define BAD_NOT_IT     _("instruction not allowed in IT block")
 #define BAD_FPU                _("selected FPU does not support instruction")
 #define BAD_OUT_IT     _("thumb conditional instruction should be in IT block")
@@ -972,11 +1024,11 @@ skip_past_char (char ** str, char c)
 
 /* Return TRUE if anything in the expression is a bignum.  */
 
-static int
+static bfd_boolean
 walk_no_bignums (symbolS * sp)
 {
   if (symbol_get_value_expression (sp)->X_op == O_big)
-    return 1;
+    return TRUE;
 
   if (symbol_get_value_expression (sp)->X_add_symbol)
     {
@@ -985,10 +1037,10 @@ walk_no_bignums (symbolS * sp)
                  && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
     }
 
-  return 0;
+  return FALSE;
 }
 
-static int in_my_get_expression = 0;
+static bfd_boolean in_my_get_expression = FALSE;
 
 /* Third argument to my_get_expression.         */
 #define GE_NO_PREFIX 0
@@ -1002,7 +1054,6 @@ static int
 my_get_expression (expressionS * ep, char ** str, int prefix_mode)
 {
   char * save_in;
-  segT  seg;
 
   /* In unified syntax, all prefixes are optional.  */
   if (unified_syntax)
@@ -1025,16 +1076,17 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
       if (is_immediate_prefix (**str))
        (*str)++;
       break;
-    default: abort ();
+    default:
+      abort ();
     }
 
   memset (ep, 0, sizeof (expressionS));
 
   save_in = input_line_pointer;
   input_line_pointer = *str;
-  in_my_get_expression = 1;
-  seg = expression (ep);
-  in_my_get_expression = 0;
+  in_my_get_expression = TRUE;
+  expression (ep);
+  in_my_get_expression = FALSE;
 
   if (ep->X_op == O_illegal || ep->X_op == O_absent)
     {
@@ -1047,22 +1099,6 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
       return 1;
     }
 
-#ifdef OBJ_AOUT
-  if (seg != absolute_section
-      && seg != text_section
-      && seg != data_section
-      && seg != bss_section
-      && seg != undefined_section)
-    {
-      inst.error = _("bad segment");
-      *str = input_line_pointer;
-      input_line_pointer = save_in;
-      return 1;
-    }
-#else
-  (void) seg;
-#endif
-
   /* Get rid of any bignums now, so that we don't generate an error for which
      we can't establish a line number later on.         Big numbers are never valid
      in instructions, which is where this routine is always called.  */
@@ -1081,7 +1117,7 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
 
   *str = input_line_pointer;
   input_line_pointer = save_in;
-  return 0;
+  return SUCCESS;
 }
 
 /* Turn a string in input_line_pointer into a floating point constant
@@ -1176,6 +1212,7 @@ md_atof (int type, char * litP, int * sizeP)
 
 /* We handle all bad expressions here, so that we can report the faulty
    instruction in the error message.  */
+
 void
 md_operand (expressionS * exp)
 {
@@ -1185,10 +1222,11 @@ md_operand (expressionS * exp)
 
 /* Immediate values.  */
 
+#ifdef OBJ_ELF
 /* Generic immediate-value read function for use in directives.
    Accepts anything that 'expression' can fold to a constant.
    *val receives the number.  */
-#ifdef OBJ_ELF
+
 static int
 immediate_for_directive (int *val)
 {
@@ -1498,6 +1536,8 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
       || (type == REG_TYPE_NSDQ
          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
              || reg->type == REG_TYPE_NQ))
+      || (type == REG_TYPE_NSD
+         && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
       || (type == REG_TYPE_MMXWC
          && (reg->type == REG_TYPE_MMXWCG)))
     type = (enum arm_reg_type) reg->type;
@@ -1521,7 +1561,9 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
 
   if (skip_past_char (&str, '[') == SUCCESS)
     {
-      if (type != REG_TYPE_VFD)
+      if (type != REG_TYPE_VFD
+         && !(type == REG_TYPE_VFS
+              && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8_2)))
        {
          first_error (_("only D registers may be indexed"));
          return FAIL;
@@ -1567,7 +1609,7 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
   return reg->number;
 }
 
-/* Like arm_reg_parse, but allow allow the following extra features:
+/* Like arm_reg_parse, but also allow the following extra features:
     - If RTYPE is non-zero, return the (possibly restricted) type of the
       register (e.g. Neon double or quad reg when either has been requested).
     - If this is a Neon vector type with additional type information, fill
@@ -1617,8 +1659,12 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
   int reg;
   char *str = *ccp;
   struct neon_typed_alias atype;
+  enum arm_reg_type reg_type = REG_TYPE_VFD;
 
-  reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype);
+  if (elsize == 4)
+    reg_type = REG_TYPE_VFS;
+
+  reg = parse_typed_reg_or_scalar (&str, reg_type, NULL, &atype);
 
   if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0)
     return FAIL;
@@ -1642,14 +1688,29 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
   return reg * 16 + atype.index;
 }
 
+/* Types of registers in a list.  */
+
+enum reg_list_els
+{
+  REGLIST_RN,
+  REGLIST_CLRM,
+  REGLIST_VFP_S,
+  REGLIST_VFP_S_VPR,
+  REGLIST_VFP_D,
+  REGLIST_VFP_D_VPR,
+  REGLIST_NEON_D
+};
+
 /* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
 
 static long
-parse_reg_list (char ** strp)
+parse_reg_list (char ** strp, enum reg_list_els etype)
 {
-  char * str = * strp;
-  long  range = 0;
-  int   another_range;
+  char *str = *strp;
+  long range = 0;
+  int another_range;
+
+  gas_assert (etype == REGLIST_RN || etype == REGLIST_CLRM);
 
   /* We come back here if we get ranges concatenated by '+' or '|'.  */
   do
@@ -1667,11 +1728,35 @@ parse_reg_list (char ** strp)
          do
            {
              int reg;
+             const char apsr_str[] = "apsr";
+             int apsr_str_len = strlen (apsr_str);
 
-             if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
+             reg = arm_reg_parse (&str, REGLIST_RN);
+             if (etype == REGLIST_CLRM)
                {
-                 first_error (_(reg_expected_msgs[REG_TYPE_RN]));
-                 return FAIL;
+                 if (reg == REG_SP || reg == REG_PC)
+                   reg = FAIL;
+                 else if (reg == FAIL
+                          && !strncasecmp (str, apsr_str, apsr_str_len)
+                          && !ISALPHA (*(str + apsr_str_len)))
+                   {
+                     reg = 15;
+                     str += apsr_str_len;
+                   }
+
+                 if (reg == FAIL)
+                   {
+                     first_error (_("r0-r12, lr or APSR expected"));
+                     return FAIL;
+                   }
+               }
+             else /* etype == REGLIST_RN.  */
+               {
+                 if (reg == FAIL)
+                   {
+                     first_error (_(reg_expected_msgs[REGLIST_RN]));
+                     return FAIL;
+                   }
                }
 
              if (in_range)
@@ -1715,7 +1800,7 @@ parse_reg_list (char ** strp)
              return FAIL;
            }
        }
-      else
+      else if (etype == REGLIST_RN)
        {
          expressionS exp;
 
@@ -1746,15 +1831,15 @@ parse_reg_list (char ** strp)
            }
          else
            {
-             if (inst.reloc.type != 0)
+             if (inst.relocs[0].type != 0)
                {
                  inst.error = _("expression too complex");
                  return FAIL;
                }
 
-             memcpy (&inst.reloc.exp, &exp, sizeof (expressionS));
-             inst.reloc.type = BFD_RELOC_ARM_MULTI;
-             inst.reloc.pc_rel = 0;
+             memcpy (&inst.relocs[0].exp, &exp, sizeof (expressionS));
+             inst.relocs[0].type = BFD_RELOC_ARM_MULTI;
+             inst.relocs[0].pc_rel = 0;
            }
        }
 
@@ -1770,15 +1855,6 @@ parse_reg_list (char ** strp)
   return range;
 }
 
-/* Types of registers in a list.  */
-
-enum reg_list_els
-{
-  REGLIST_VFP_S,
-  REGLIST_VFP_D,
-  REGLIST_NEON_D
-};
-
 /* Parse a VFP register list.  If the string is invalid return FAIL.
    Otherwise return the number of registers, and set PBASE to the first
    register.  Parses registers of type ETYPE.
@@ -1795,7 +1871,8 @@ enum reg_list_els
    bug.  */
 
 static int
-parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
+parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype,
+                   bfd_boolean *partial_match)
 {
   char *str = *ccp;
   int base_reg;
@@ -1806,6 +1883,9 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   int warned = 0;
   unsigned long mask = 0;
   int i;
+  bfd_boolean vpr_seen = FALSE;
+  bfd_boolean expect_vpr =
+    (etype == REGLIST_VFP_S_VPR) || (etype == REGLIST_VFP_D_VPR);
 
   if (skip_past_char (&str, '{') == FAIL)
     {
@@ -1816,20 +1896,25 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   switch (etype)
     {
     case REGLIST_VFP_S:
+    case REGLIST_VFP_S_VPR:
       regtype = REG_TYPE_VFS;
       max_regs = 32;
       break;
 
     case REGLIST_VFP_D:
+    case REGLIST_VFP_D_VPR:
       regtype = REG_TYPE_VFD;
       break;
 
     case REGLIST_NEON_D:
       regtype = REG_TYPE_NDQ;
       break;
+
+    default:
+      gas_assert (0);
     }
 
-  if (etype != REGLIST_VFP_S)
+  if (etype != REGLIST_VFP_S && etype != REGLIST_VFP_S_VPR)
     {
       /* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant.  */
       if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
@@ -1847,19 +1932,54 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
     }
 
   base_reg = max_regs;
+  *partial_match = FALSE;
 
   do
     {
       int setmask = 1, addregs = 1;
+      const char vpr_str[] = "vpr";
+      int vpr_str_len = strlen (vpr_str);
 
       new_base = arm_typed_reg_parse (&str, regtype, &regtype, NULL);
 
-      if (new_base == FAIL)
+      if (expect_vpr)
+       {
+         if (new_base == FAIL
+             && !strncasecmp (str, vpr_str, vpr_str_len)
+             && !ISALPHA (*(str + vpr_str_len))
+             && !vpr_seen)
+           {
+             vpr_seen = TRUE;
+             str += vpr_str_len;
+             if (count == 0)
+               base_reg = 0; /* Canonicalize VPR only on d0 with 0 regs.  */
+           }
+         else if (vpr_seen)
+           {
+             first_error (_("VPR expected last"));
+             return FAIL;
+           }
+         else if (new_base == FAIL)
+           {
+             if (regtype == REG_TYPE_VFS)
+               first_error (_("VFP single precision register or VPR "
+                              "expected"));
+             else /* regtype == REG_TYPE_VFD.  */
+               first_error (_("VFP/Neon double precision register or VPR "
+                              "expected"));
+             return FAIL;
+           }
+       }
+      else if (new_base == FAIL)
        {
          first_error (_(reg_expected_msgs[regtype]));
          return FAIL;
        }
 
+      *partial_match = TRUE;
+      if (vpr_seen)
+       continue;
+
       if (new_base >= max_regs)
        {
          first_error (_("register out of range in list"));
@@ -1882,7 +2002,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
          return FAIL;
        }
 
-      if ((mask >> new_base) != 0 && ! warned)
+      if ((mask >> new_base) != 0 && ! warned && !vpr_seen)
        {
          as_tsktsk (_("register list not in ascending order"));
          warned = 1;
@@ -1937,11 +2057,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   str++;
 
   /* Sanity check -- should have raised a parse error above.  */
-  if (count == 0 || count > max_regs)
+  if ((!vpr_seen && count == 0) || count > max_regs)
     abort ();
 
   *pbase = base_reg;
 
+  if (expect_vpr && !vpr_seen)
+    {
+      first_error (_("VPR expected last"));
+      return FAIL;
+    }
+
   /* Final test -- the registers must be consecutive.  */
   mask >>= base_reg;
   for (i = 0; i < count; i++)
@@ -2708,7 +2834,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
-       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.  */
@@ -3045,7 +3171,7 @@ s_ccs_ref (int unused ATTRIBUTE_UNUSED)
 }
 
 /*  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)
 {
@@ -3204,7 +3330,7 @@ add_to_lit_pool (unsigned int nbytes)
     {
       imm1 = inst.operands[1].imm;
       imm2 = (inst.operands[1].regisimm ? inst.operands[1].reg
-              : inst.reloc.exp.X_unsigned ? 0
+              : inst.relocs[0].exp.X_unsigned ? 0
               : ((bfd_int64_t) inst.operands[1].imm) >> 32);
       if (target_big_endian)
        {
@@ -3220,23 +3346,23 @@ add_to_lit_pool (unsigned int nbytes)
     {
       if (nbytes == 4)
        {
-         if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
-             && (inst.reloc.exp.X_op == O_constant)
+         if ((pool->literals[entry].X_op == inst.relocs[0].exp.X_op)
+             && (inst.relocs[0].exp.X_op == O_constant)
              && (pool->literals[entry].X_add_number
-                 == inst.reloc.exp.X_add_number)
+                 == inst.relocs[0].exp.X_add_number)
              && (pool->literals[entry].X_md == nbytes)
              && (pool->literals[entry].X_unsigned
-                 == inst.reloc.exp.X_unsigned))
+                 == inst.relocs[0].exp.X_unsigned))
            break;
 
-         if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
-             && (inst.reloc.exp.X_op == O_symbol)
+         if ((pool->literals[entry].X_op == inst.relocs[0].exp.X_op)
+             && (inst.relocs[0].exp.X_op == O_symbol)
              && (pool->literals[entry].X_add_number
-                 == inst.reloc.exp.X_add_number)
+                 == inst.relocs[0].exp.X_add_number)
              && (pool->literals[entry].X_add_symbol
-                 == inst.reloc.exp.X_add_symbol)
+                 == inst.relocs[0].exp.X_add_symbol)
              && (pool->literals[entry].X_op_symbol
-                 == inst.reloc.exp.X_op_symbol)
+                 == inst.relocs[0].exp.X_op_symbol)
              && (pool->literals[entry].X_md == nbytes))
            break;
        }
@@ -3246,11 +3372,11 @@ add_to_lit_pool (unsigned int nbytes)
               && (pool->literals[entry].X_op == O_constant)
               && (pool->literals[entry].X_add_number == (offsetT) imm1)
               && (pool->literals[entry].X_unsigned
-                  == inst.reloc.exp.X_unsigned)
+                  == inst.relocs[0].exp.X_unsigned)
               && (pool->literals[entry + 1].X_op == O_constant)
               && (pool->literals[entry + 1].X_add_number == (offsetT) imm2)
               && (pool->literals[entry + 1].X_unsigned
-                  == inst.reloc.exp.X_unsigned))
+                  == inst.relocs[0].exp.X_unsigned))
        break;
 
       padding_slot_p = ((pool->literals[entry].X_md >> 8) == PADDING_SLOT);
@@ -3282,8 +3408,8 @@ add_to_lit_pool (unsigned int nbytes)
 
             We also check to make sure the literal operand is a
             constant number.  */
-         if (!(inst.reloc.exp.X_op == O_constant
-               || inst.reloc.exp.X_op == O_big))
+         if (!(inst.relocs[0].exp.X_op == O_constant
+               || inst.relocs[0].exp.X_op == O_big))
            {
              inst.error = _("invalid type for literal pool");
              return FAIL;
@@ -3296,7 +3422,7 @@ add_to_lit_pool (unsigned int nbytes)
                  return FAIL;
                }
 
-             pool->literals[entry] = inst.reloc.exp;
+             pool->literals[entry] = inst.relocs[0].exp;
              pool->literals[entry].X_op = O_constant;
              pool->literals[entry].X_add_number = 0;
              pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4;
@@ -3309,22 +3435,22 @@ add_to_lit_pool (unsigned int nbytes)
              return FAIL;
            }
 
-         pool->literals[entry] = inst.reloc.exp;
+         pool->literals[entry] = inst.relocs[0].exp;
          pool->literals[entry].X_op = O_constant;
          pool->literals[entry].X_add_number = imm1;
-         pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned;
+         pool->literals[entry].X_unsigned = inst.relocs[0].exp.X_unsigned;
          pool->literals[entry++].X_md = 4;
-         pool->literals[entry] = inst.reloc.exp;
+         pool->literals[entry] = inst.relocs[0].exp;
          pool->literals[entry].X_op = O_constant;
          pool->literals[entry].X_add_number = imm2;
-         pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned;
+         pool->literals[entry].X_unsigned = inst.relocs[0].exp.X_unsigned;
          pool->literals[entry].X_md = 4;
          pool->alignment = 3;
          pool->next_free_entry += 1;
        }
       else
        {
-         pool->literals[entry] = inst.reloc.exp;
+         pool->literals[entry] = inst.relocs[0].exp;
          pool->literals[entry].X_md = 4;
        }
 
@@ -3340,13 +3466,13 @@ add_to_lit_pool (unsigned int nbytes)
     }
   else if (padding_slot_p)
     {
-      pool->literals[entry] = inst.reloc.exp;
+      pool->literals[entry] = inst.relocs[0].exp;
       pool->literals[entry].X_md = nbytes;
     }
 
-  inst.reloc.exp.X_op        = O_symbol;
-  inst.reloc.exp.X_add_number = pool_size;
-  inst.reloc.exp.X_add_symbol = pool->symbol;
+  inst.relocs[0].exp.X_op            = O_symbol;
+  inst.relocs[0].exp.X_add_number = pool_size;
+  inst.relocs[0].exp.X_add_symbol = pool->symbol;
 
   return SUCCESS;
 }
@@ -3378,7 +3504,7 @@ tc_start_label_without_colon (void)
 }
 
 /* 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,
@@ -3547,7 +3673,9 @@ s_arm_elf_cons (int nbytes)
                }
 
              if (size > nbytes)
-               as_bad (_("%s relocations do not fit in %d bytes"),
+               as_bad (ngettext ("%s relocations do not fit in %d byte",
+                                 "%s relocations do not fit in %d bytes",
+                                 nbytes),
                        howto->name, nbytes);
              else
                {
@@ -3940,7 +4068,7 @@ s_arm_unwind_save_core (void)
   long range;
   int n;
 
-  range = parse_reg_list (&input_line_pointer);
+  range = parse_reg_list (&input_line_pointer, REGLIST_RN);
   if (range == FAIL)
     {
       as_bad (_("expected register list"));
@@ -4067,8 +4195,10 @@ s_arm_unwind_save_vfp_armv6 (void)
   valueT op;
   int num_vfpv3_regs = 0;
   int num_regs_below_16;
+  bfd_boolean partial_match;
 
-  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
+  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D,
+                             &partial_match);
   if (count == FAIL)
     {
       as_bad (_("expected register list"));
@@ -4115,8 +4245,10 @@ s_arm_unwind_save_vfp (void)
   int count;
   unsigned int reg;
   valueT op;
+  bfd_boolean partial_match;
 
-  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D);
+  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D,
+                             &partial_match);
   if (count == FAIL)
     {
       as_bad (_("expected register list"));
@@ -4731,7 +4863,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"4byte", cons, 4},
   {"8byte", cons, 8},
   /* These are used for dwarf2.  */
-  { "file", (void (*) (int)) dwarf2_directive_file, 0 },
+  { "file", dwarf2_directive_file, 0 },
   { "loc",  dwarf2_directive_loc,  0 },
   { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
 #endif
@@ -4764,6 +4896,7 @@ parse_immediate (char **str, int *val, int min, int max,
                 bfd_boolean prefix_opt)
 {
   expressionS exp;
+
   my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
   if (exp.X_op != O_constant)
     {
@@ -4967,9 +5100,13 @@ parse_ifimm_zero (char **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)
@@ -5160,7 +5297,7 @@ parse_shift (char **str, int i, enum parse_shift_mode mode)
          inst.operands[i].imm = reg;
          inst.operands[i].immisreg = 1;
        }
-      else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+      else if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX))
        return FAIL;
     }
   inst.operands[i].shift_kind = shift;
@@ -5192,8 +5329,8 @@ parse_shifter_operand (char **str, int i)
       inst.operands[i].isreg = 1;
 
       /* parse_shift will override this if appropriate */
-      inst.reloc.exp.X_op = O_constant;
-      inst.reloc.exp.X_add_number = 0;
+      inst.relocs[0].exp.X_op = O_constant;
+      inst.relocs[0].exp.X_add_number = 0;
 
       if (skip_past_comma (str) == FAIL)
        return SUCCESS;
@@ -5202,7 +5339,7 @@ parse_shifter_operand (char **str, int i)
       return parse_shift (str, i, NO_SHIFT_RESTRICT);
     }
 
-  if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
+  if (my_get_expression (&inst.relocs[0].exp, str, GE_IMM_PREFIX))
     return FAIL;
 
   if (skip_past_comma (str) == SUCCESS)
@@ -5211,7 +5348,7 @@ parse_shifter_operand (char **str, int i)
       if (my_get_expression (&exp, str, GE_NO_PREFIX))
        return FAIL;
 
-      if (exp.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
+      if (exp.X_op != O_constant || inst.relocs[0].exp.X_op != O_constant)
        {
          inst.error = _("constant expression expected");
          return FAIL;
@@ -5223,19 +5360,20 @@ parse_shifter_operand (char **str, int i)
          inst.error = _("invalid rotation");
          return FAIL;
        }
-      if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
+      if (inst.relocs[0].exp.X_add_number < 0
+         || inst.relocs[0].exp.X_add_number > 255)
        {
          inst.error = _("invalid constant");
          return FAIL;
        }
 
       /* Encode as specified.  */
-      inst.operands[i].imm = inst.reloc.exp.X_add_number | value << 7;
+      inst.operands[i].imm = inst.relocs[0].exp.X_add_number | value << 7;
       return SUCCESS;
     }
 
-  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-  inst.reloc.pc_rel = 0;
+  inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE;
+  inst.relocs[0].pc_rel = 0;
   return SUCCESS;
 }
 
@@ -5406,12 +5544,12 @@ parse_shifter_operand_group_reloc (char **str, int i)
 
       /* We now have the group relocation table entry corresponding to
         the name in the assembler source.  Next, we parse the expression.  */
-      if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
+      if (my_get_expression (&inst.relocs[0].exp, str, GE_NO_PREFIX))
        return PARSE_OPERAND_FAIL_NO_BACKTRACK;
 
       /* Record the relocation type (always the ALU variant here).  */
-      inst.reloc.type = (bfd_reloc_code_real_type) entry->alu_code;
-      gas_assert (inst.reloc.type != 0);
+      inst.relocs[0].type = (bfd_reloc_code_real_type) entry->alu_code;
+      gas_assert (inst.relocs[0].type != 0);
 
       return PARSE_OPERAND_SUCCESS;
     }
@@ -5450,23 +5588,23 @@ parse_neon_alignment (char **str, int i)
 }
 
 /* Parse all forms of an ARM address expression.  Information is written
-   to inst.operands[i] and/or inst.reloc.
+   to inst.operands[i] and/or inst.relocs[0].
 
    Preindexed addressing (.preind=1):
 
-   [Rn, #offset]       .reg=Rn .reloc.exp=offset
+   [Rn, #offset]       .reg=Rn .relocs[0].exp=offset
    [Rn, +/-Rm]        .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
    [Rn, +/-Rm, shift]  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
-                      .shift_kind=shift .reloc.exp=shift_imm
+                      .shift_kind=shift .relocs[0].exp=shift_imm
 
    These three may have a trailing ! which causes .writeback to be set also.
 
    Postindexed addressing (.postind=1, .writeback=1):
 
-   [Rn], #offset       .reg=Rn .reloc.exp=offset
+   [Rn], #offset       .reg=Rn .relocs[0].exp=offset
    [Rn], +/-Rm        .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
    [Rn], +/-Rm, shift  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
-                      .shift_kind=shift .reloc.exp=shift_imm
+                      .shift_kind=shift .relocs[0].exp=shift_imm
 
    Unindexed addressing (.preind=0, .postind=0):
 
@@ -5475,11 +5613,11 @@ parse_neon_alignment (char **str, int i)
    Other:
 
    [Rn]{!}            shorthand for [Rn,#0]{!}
-   =immediate         .isreg=0 .reloc.exp=immediate
-   label              .reg=PC .reloc.pc_rel=1 .reloc.exp=label
+   =immediate         .isreg=0 .relocs[0].exp=immediate
+   label              .reg=PC .relocs[0].pc_rel=1 .relocs[0].exp=label
 
   It is the caller's responsibility to check for addressing modes not
-  supported by the instruction, and to set inst.reloc.type.  */
+  supported by the instruction, and to set inst.relocs[0].type.  */
 
 static parse_operand_result
 parse_address_main (char **str, int i, int group_relocations,
@@ -5493,15 +5631,15 @@ parse_address_main (char **str, int i, int group_relocations,
       if (skip_past_char (&p, '=') == FAIL)
        {
          /* Bare address - translate to PC-relative offset.  */
-         inst.reloc.pc_rel = 1;
+         inst.relocs[0].pc_rel = 1;
          inst.operands[i].reg = REG_PC;
          inst.operands[i].isreg = 1;
          inst.operands[i].preind = 1;
 
-         if (my_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX_BIG))
+         if (my_get_expression (&inst.relocs[0].exp, &p, GE_OPT_PREFIX_BIG))
            return PARSE_OPERAND_FAIL;
        }
-      else if (parse_big_immediate (&p, i, &inst.reloc.exp,
+      else if (parse_big_immediate (&p, i, &inst.relocs[0].exp,
                                    /*allow_symbol_p=*/TRUE))
        return PARSE_OPERAND_FAIL;
 
@@ -5576,29 +5714,32 @@ parse_address_main (char **str, int i, int group_relocations,
              /* We now have the group relocation table entry corresponding to
                 the name in the assembler source.  Next, we parse the
                 expression.  */
-             if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+             if (my_get_expression (&inst.relocs[0].exp, &p, GE_NO_PREFIX))
                return PARSE_OPERAND_FAIL_NO_BACKTRACK;
 
              /* Record the relocation type.  */
              switch (group_type)
                {
                  case GROUP_LDR:
-                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldr_code;
+                   inst.relocs[0].type
+                       = (bfd_reloc_code_real_type) entry->ldr_code;
                    break;
 
                  case GROUP_LDRS:
-                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldrs_code;
+                   inst.relocs[0].type
+                       = (bfd_reloc_code_real_type) entry->ldrs_code;
                    break;
 
                  case GROUP_LDC:
-                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldc_code;
+                   inst.relocs[0].type
+                       = (bfd_reloc_code_real_type) entry->ldc_code;
                    break;
 
                  default:
                    gas_assert (0);
                }
 
-             if (inst.reloc.type == 0)
+             if (inst.relocs[0].type == 0)
                {
                  inst.error = _("this group relocation is not allowed on this instruction");
                  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
@@ -5607,11 +5748,12 @@ parse_address_main (char **str, int i, int group_relocations,
          else
            {
              char *q = p;
-             if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+
+             if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX))
                return PARSE_OPERAND_FAIL;
              /* If the offset is 0, find out if it's a +0 or -0.  */
-             if (inst.reloc.exp.X_op == O_constant
-                 && inst.reloc.exp.X_add_number == 0)
+             if (inst.relocs[0].exp.X_op == O_constant
+                 && inst.relocs[0].exp.X_add_number == 0)
                {
                  skip_whitespace (q);
                  if (*q == '#')
@@ -5697,16 +5839,17 @@ parse_address_main (char **str, int i, int group_relocations,
          else
            {
              char *q = p;
+
              if (inst.operands[i].negative)
                {
                  inst.operands[i].negative = 0;
                  p--;
                }
-             if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+             if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX))
                return PARSE_OPERAND_FAIL;
              /* If the offset is 0, find out if it's a +0 or -0.  */
-             if (inst.reloc.exp.X_op == O_constant
-                 && inst.reloc.exp.X_add_number == 0)
+             if (inst.relocs[0].exp.X_op == O_constant
+                 && inst.relocs[0].exp.X_add_number == 0)
                {
                  skip_whitespace (q);
                  if (*q == '#')
@@ -5726,8 +5869,8 @@ parse_address_main (char **str, int i, int group_relocations,
   if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
     {
       inst.operands[i].preind = 1;
-      inst.reloc.exp.X_op = O_constant;
-      inst.reloc.exp.X_add_number = 0;
+      inst.relocs[0].exp.X_op = O_constant;
+      inst.relocs[0].exp.X_add_number = 0;
     }
   *str = p;
   return PARSE_OPERAND_SUCCESS;
@@ -5755,28 +5898,28 @@ parse_half (char **str)
   p = *str;
   skip_past_char (&p, '#');
   if (strncasecmp (p, ":lower16:", 9) == 0)
-    inst.reloc.type = BFD_RELOC_ARM_MOVW;
+    inst.relocs[0].type = BFD_RELOC_ARM_MOVW;
   else if (strncasecmp (p, ":upper16:", 9) == 0)
-    inst.reloc.type = BFD_RELOC_ARM_MOVT;
+    inst.relocs[0].type = BFD_RELOC_ARM_MOVT;
 
-  if (inst.reloc.type != BFD_RELOC_UNUSED)
+  if (inst.relocs[0].type != BFD_RELOC_UNUSED)
     {
       p += 9;
       skip_whitespace (p);
     }
 
-  if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+  if (my_get_expression (&inst.relocs[0].exp, &p, GE_NO_PREFIX))
     return FAIL;
 
-  if (inst.reloc.type == BFD_RELOC_UNUSED)
+  if (inst.relocs[0].type == BFD_RELOC_UNUSED)
     {
-      if (inst.reloc.exp.X_op != O_constant)
+      if (inst.relocs[0].exp.X_op != O_constant)
        {
          inst.error = _("constant expression expected");
          return FAIL;
        }
-      if (inst.reloc.exp.X_add_number < 0
-         || inst.reloc.exp.X_add_number > 0xffff)
+      if (inst.relocs[0].exp.X_add_number < 0
+         || inst.relocs[0].exp.X_add_number > 0xffff)
        {
          inst.error = _("immediate value out of range");
          return FAIL;
@@ -6126,17 +6269,16 @@ record_feature_use (const arm_feature_set *feature)
     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.  */
+/* If the given feature is currently allowed, mark it as used and return TRUE.
+   Return FALSE otherwise.  */
 static bfd_boolean
 mark_feature_used (const arm_feature_set *feature)
 {
-  /* Ensure the option is valid on the current architecture.  */
+  /* Ensure the option is currently allowed.  */
   if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
     return FALSE;
 
-  /* Add the appropriate architecture feature for the barrier option used.
-     */
+  /* Add the appropriate architecture feature for the barrier option used.  */
   record_feature_use (feature);
 
   return TRUE;
@@ -6204,7 +6346,7 @@ parse_tb (char **str)
     {
       if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
        return FAIL;
-      if (inst.reloc.exp.X_add_number != 1)
+      if (inst.relocs[0].exp.X_add_number != 1)
        {
          inst.error = _("invalid shift");
          return FAIL;
@@ -6469,6 +6611,7 @@ enum operand_parse_code
   OP_RND,       /* Neon double precision register (0..31) */
   OP_RNQ,      /* Neon quad precision register */
   OP_RVSD,     /* VFP single or double precision register */
+  OP_RNSD,      /* Neon single or double precision register */
   OP_RNDQ,      /* Neon double or quad precision register */
   OP_RNSDQ,    /* Neon single, double or quad precision register */
   OP_RNSC,      /* Neon scalar D[X] */
@@ -6484,17 +6627,24 @@ enum operand_parse_code
   OP_RIWG,     /* iWMMXt wCG register */
   OP_RXA,      /* XScale accumulator register */
 
+  /* New operands for Armv8.1-M Mainline.  */
+  OP_LR,       /* ARM LR register */
+  OP_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */
+
   OP_REGLST,   /* ARM register list */
+  OP_CLRMLST,  /* CLRM register list */
   OP_VRSLST,   /* VFP single-precision register list */
   OP_VRDLST,   /* VFP double-precision register list */
   OP_VRSDLST,   /* VFP single or double-precision register list (& quad) */
   OP_NRDLST,    /* Neon double-precision register list (d0-d31, qN aliases) */
   OP_NSTRLST,   /* Neon element/structure list */
+  OP_VRSDVLST,  /* VFP single or double-precision register list and VPR */
 
   OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
   OP_RVSD_I0,  /* VFP S or D reg, or immediate zero.  */
   OP_RSVD_FI0, /* VFP S or D reg, or floating point immediate zero.  */
   OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
+  OP_RNSD_RNSC, /* Neon S or D reg, or Neon scalar.  */
   OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
   OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
   OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
@@ -6532,7 +6682,10 @@ enum operand_parse_code
   OP_EXP,      /* arbitrary expression */
   OP_EXPi,     /* same, with optional immediate prefix */
   OP_EXPr,     /* same, with optional relocation suffix */
+  OP_EXPs,     /* same, with optional non-first operand 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 */
@@ -6544,7 +6697,7 @@ enum operand_parse_code
   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 */
@@ -6559,6 +6712,7 @@ enum operand_parse_code
   OP_oI255c,    /*       curly-brace enclosed, 0 .. 255 */
 
   OP_oRR,       /* ARM register */
+  OP_oLR,       /* ARM LR register */
   OP_oRRnpc,    /* ARM register, not the PC */
   OP_oRRnpcsp,  /* ARM register, neither the PC nor the SP (a.k.a. BadReg) */
   OP_oRRw,      /* ARM register, not r15, optional trailing ! */
@@ -6594,6 +6748,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   enum arm_reg_type rtype;
   parse_operand_result result;
   unsigned int op_parse_code;
+  bfd_boolean partial_match;
 
 #define po_char_or_fail(chr)                   \
   do                                           \
@@ -6727,6 +6882,8 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RRnpc:
        case OP_RRnpcsp:
        case OP_oRR:
+       case OP_LR:
+       case OP_oLR:
        case OP_RR:    po_reg_or_fail (REG_TYPE_RN);      break;
        case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);      break;
        case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);      break;
@@ -6754,6 +6911,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
        case OP_oRNQ:
        case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
+       case OP_RNSD:  po_reg_or_fail (REG_TYPE_NSD);     break;
        case OP_oRNDQ:
        case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
@@ -6811,6 +6969,18 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          }
          break;
 
+       case OP_RNSD_RNSC:
+         {
+           po_scalar_or_goto (8, try_s_scalar);
+           break;
+           try_s_scalar:
+           po_scalar_or_goto (4, try_nsd);
+           break;
+           try_nsd:
+           po_reg_or_fail (REG_TYPE_NSD);
+         }
+         break;
+
        case OP_RNDQ_RNSC:
          {
            po_scalar_or_goto (8, try_ndq);
@@ -6925,19 +7095,19 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
          /* Expressions */
        case OP_EXPi:   EXPi:
-         po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+         po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str,
                                              GE_OPT_PREFIX));
          break;
 
        case OP_EXP:
-         po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+         po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str,
                                              GE_NO_PREFIX));
          break;
 
        case OP_EXPr:   EXPr:
-         po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+         po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str,
                                              GE_NO_PREFIX));
-         if (inst.reloc.exp.X_op == O_symbol)
+         if (inst.relocs[0].exp.X_op == O_symbol)
            {
              val = parse_reloc (&str);
              if (val == -1)
@@ -6953,6 +7123,20 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
            }
          break;
 
+       case OP_EXPs:
+         po_misc_or_fail (my_get_expression (&inst.relocs[i].exp, &str,
+                                             GE_NO_PREFIX));
+         if (inst.relocs[i].exp.X_op == O_symbol)
+           {
+             inst.operands[i].hasreloc = 1;
+           }
+         else if (inst.relocs[i].exp.X_op == O_constant)
+           {
+             inst.operands[i].imm = inst.relocs[i].exp.X_add_number;
+             inst.operands[i].hasreloc = 0;
+           }
+         break;
+
          /* Operand for MOVW or MOVT.  */
        case OP_HALF:
          po_misc_or_fail (parse_half (&str));
@@ -7076,7 +7260,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
          /* Register lists.  */
        case OP_REGLST:
-         val = parse_reg_list (&str);
+         val = parse_reg_list (&str, REGLIST_RN);
          if (*str == '^')
            {
              inst.operands[i].writeback = 1;
@@ -7084,30 +7268,48 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
            }
          break;
 
+       case OP_CLRMLST:
+         val = parse_reg_list (&str, REGLIST_CLRM);
+         break;
+
        case OP_VRSLST:
-         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S,
+                                   &partial_match);
          break;
 
        case OP_VRDLST:
-         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D,
+                                   &partial_match);
          break;
 
        case OP_VRSDLST:
          /* Allow Q registers too.  */
          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                   REGLIST_NEON_D);
+                                   REGLIST_NEON_D, &partial_match);
          if (val == FAIL)
            {
              inst.error = NULL;
              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                       REGLIST_VFP_S);
+                                       REGLIST_VFP_S, &partial_match);
+             inst.operands[i].issingle = 1;
+           }
+         break;
+
+       case OP_VRSDVLST:
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                   REGLIST_VFP_D_VPR, &partial_match);
+         if (val == FAIL && !partial_match)
+           {
+             inst.error = NULL;
+             val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                       REGLIST_VFP_S_VPR, &partial_match);
              inst.operands[i].issingle = 1;
            }
          break;
 
        case OP_NRDLST:
          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                   REGLIST_NEON_D);
+                                   REGLIST_NEON_D, &partial_match);
          break;
 
        case OP_NSTRLST:
@@ -7181,8 +7383,14 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
            {
              if (inst.operands[i].reg == REG_PC)
                inst.error = BAD_PC;
-             else if (inst.operands[i].reg == REG_SP)
-               inst.error = BAD_SP;
+             else if (inst.operands[i].reg == REG_SP
+                      /* The restriction on Rd/Rt/Rt2 on Thumb mode has been
+                         relaxed since ARMv8-A.  */
+                      && !ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+               {
+                 gas_assert (thumb);
+                 inst.error = BAD_SP;
+               }
            }
          break;
 
@@ -7201,9 +7409,11 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_COND:
        case OP_oBARRIER_I15:
        case OP_REGLST:
+       case OP_CLRMLST:
        case OP_VRSLST:
        case OP_VRDLST:
        case OP_VRSDLST:
+       case OP_VRSDVLST:
        case OP_NRDLST:
        case OP_NSTRLST:
          if (val == FAIL)
@@ -7211,6 +7421,12 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          inst.operands[i].imm = val;
          break;
 
+       case OP_LR:
+       case OP_oLR:
+         if (inst.operands[i].reg != REG_LR)
+           inst.error = _("operand must be LR register");
+         break;
+
        default:
          break;
        }
@@ -7280,14 +7496,23 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
 /* Reject "bad registers" for Thumb-2 instructions.  Many Thumb-2
    instructions are unpredictable if these registers are used.  This
-   is the BadReg predicate in ARM's Thumb-2 documentation.  */
-#define reject_bad_reg(reg)                            \
-  do                                                   \
-   if (reg == REG_SP || reg == REG_PC)                 \
-     {                                                 \
-       inst.error = (reg == REG_SP) ? BAD_SP : BAD_PC; \
-       return;                                         \
-     }                                                 \
+   is the BadReg predicate in ARM's Thumb-2 documentation.
+
+   Before ARMv8-A, REG_PC and REG_SP were not allowed in quite a few
+   places, while the restriction on REG_SP was relaxed since ARMv8-A.  */
+#define reject_bad_reg(reg)                                    \
+  do                                                           \
+   if (reg == REG_PC)                                          \
+     {                                                         \
+       inst.error = BAD_PC;                                    \
+       return;                                                 \
+     }                                                         \
+   else if (reg == REG_SP                                      \
+           && !ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))  \
+     {                                                         \
+       inst.error = BAD_SP;                                    \
+       return;                                                 \
+     }                                                         \
   while (0)
 
 /* If REG is R13 (the stack pointer), warn that its use is
@@ -7306,7 +7531,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
    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 instuction that
+   instruction is the same as the equivalent Coprocessor 10 instruction that
    exists for Single-Precision operation.  */
 
 static void
@@ -7432,11 +7657,14 @@ encode_arm_shift (int i)
   /* register-shifted register.  */
   if (inst.operands[i].immisreg)
     {
-      int index;
-      for (index = 0; index <= i; ++index)
+      int op_index;
+      for (op_index = 0; op_index <= i; ++op_index)
        {
-         gas_assert (inst.operands[index].present);
-         if (inst.operands[index].isreg && inst.operands[index].reg == REG_PC)
+         /* 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"));
        }
 
@@ -7455,7 +7683,7 @@ encode_arm_shift (int i)
          inst.instruction |= inst.operands[i].imm << 8;
        }
       else
-       inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+       inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM;
     }
 }
 
@@ -7470,7 +7698,7 @@ encode_arm_shifter_operand (int i)
   else
     {
       inst.instruction |= INST_IMMEDIATE;
-      if (inst.reloc.type != BFD_RELOC_ARM_IMMEDIATE)
+      if (inst.relocs[0].type != BFD_RELOC_ARM_IMMEDIATE)
        inst.instruction |= inst.operands[i].imm;
     }
 }
@@ -7545,13 +7773,13 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
          else
            {
              inst.instruction |= inst.operands[i].shift_kind << 5;
-             inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+             inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM;
            }
        }
     }
-  else /* immediate offset in inst.reloc */
+  else /* immediate offset in inst.relocs[0] */
     {
-      if (is_pc && !inst.reloc.pc_rel)
+      if (is_pc && !inst.relocs[0].pc_rel)
        {
          const bfd_boolean is_load = ((inst.instruction & LOAD_BIT) != 0);
 
@@ -7568,12 +7796,12 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
            as_tsktsk (_("use of PC in this instruction is deprecated"));
        }
 
-      if (inst.reloc.type == BFD_RELOC_UNUSED)
+      if (inst.relocs[0].type == BFD_RELOC_UNUSED)
        {
          /* Prefer + for zero encoded value.  */
          if (!inst.operands[i].negative)
            inst.instruction |= INDEX_UP;
-         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+         inst.relocs[0].type = BFD_RELOC_ARM_OFFSET_IMM;
        }
     }
 }
@@ -7605,19 +7833,19 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
       if (!inst.operands[i].negative)
        inst.instruction |= INDEX_UP;
     }
-  else /* immediate offset in inst.reloc */
+  else /* immediate offset in inst.relocs[0] */
     {
-      constraint ((inst.operands[i].reg == REG_PC && !inst.reloc.pc_rel
+      constraint ((inst.operands[i].reg == REG_PC && !inst.relocs[0].pc_rel
                   && inst.operands[i].writeback),
                  BAD_PC_WRITEBACK);
       inst.instruction |= HWOFFSET_IMM;
-      if (inst.reloc.type == BFD_RELOC_UNUSED)
+      if (inst.relocs[0].type == BFD_RELOC_UNUSED)
        {
          /* Prefer + for zero encoded value.  */
          if (!inst.operands[i].negative)
            inst.instruction |= INDEX_UP;
 
-         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+         inst.relocs[0].type = BFD_RELOC_ARM_OFFSET_IMM8;
        }
     }
 }
@@ -7870,7 +8098,7 @@ enum lit_type
 
 static void do_vfp_nsyn_opcode (const char *);
 
-/* inst.reloc.exp describes an "=expr" load pseudo-operation.
+/* inst.relocs[0].exp describes an "=expr" load pseudo-operation.
    Determine whether it can be performed with a move instruction; if
    it can, convert inst.instruction to that move instruction and
    return TRUE; if it can't, convert inst.instruction to a literal-pool
@@ -7897,28 +8125,28 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
       return TRUE;
     }
 
-  if (inst.reloc.exp.X_op != O_constant
-      && inst.reloc.exp.X_op != O_symbol
-      && inst.reloc.exp.X_op != O_big)
+  if (inst.relocs[0].exp.X_op != O_constant
+      && inst.relocs[0].exp.X_op != O_symbol
+      && inst.relocs[0].exp.X_op != O_big)
     {
       inst.error = _("constant expression expected");
       return TRUE;
     }
 
-  if (inst.reloc.exp.X_op == O_constant
-      || inst.reloc.exp.X_op == O_big)
+  if (inst.relocs[0].exp.X_op == O_constant
+      || inst.relocs[0].exp.X_op == O_big)
     {
 #if defined BFD_HOST_64_BIT
       bfd_int64_t v;
 #else
       offsetT v;
 #endif
-      if (inst.reloc.exp.X_op == O_big)
+      if (inst.relocs[0].exp.X_op == O_big)
        {
          LITTLENUM_TYPE w[X_PRECISION];
          LITTLENUM_TYPE * l;
 
-         if (inst.reloc.exp.X_add_number == -1)
+         if (inst.relocs[0].exp.X_add_number == -1)
            {
              gen_to_words (w, X_PRECISION, E_PRECISION);
              l = w;
@@ -7942,23 +8170,19 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
 #endif
        }
       else
-       v = inst.reloc.exp.X_add_number;
+       v = inst.relocs[0].exp.X_add_number;
 
       if (!inst.operands[i].issingle)
        {
          if (thumb_p)
            {
-             /* 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);
-                 inst.instruction |= v;
-                 return TRUE;
-               }
+             /* LDR should not use lead in a flag-setting instruction being
+                chosen so we do not check whether movs can be used.  */
 
-             if (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))
+                 && inst.operands[i].reg != 13
+                 && inst.operands[i].reg != 15)
                {
                  /* Check if on thumb2 it can be done with a mov.w, mvn or
                     movw instruction.  */
@@ -8035,7 +8259,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
              unsigned immlo = inst.operands[1].imm;
              unsigned immhi = inst.operands[1].regisimm
                ? inst.operands[1].reg
-               : inst.reloc.exp.X_unsigned
+               : inst.relocs[0].exp.X_unsigned
                ? 0
                : ((bfd_int64_t)((int) immlo)) >> 32;
              int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
@@ -8110,8 +8334,8 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
   inst.operands[1].reg = REG_PC;
   inst.operands[1].isreg = 1;
   inst.operands[1].preind = 1;
-  inst.reloc.pc_rel = 1;
-  inst.reloc.type = (thumb_p
+  inst.relocs[0].pc_rel = 1;
+  inst.relocs[0].type = (thumb_p
                     ? BFD_RELOC_ARM_THUMB_OFFSET
                     : (mode_3
                        ? BFD_RELOC_ARM_HWLITERAL
@@ -8178,15 +8402,15 @@ encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
     }
 
   if (reloc_override)
-    inst.reloc.type = (bfd_reloc_code_real_type) reloc_override;
-  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
-           || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
-          && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
+    inst.relocs[0].type = (bfd_reloc_code_real_type) reloc_override;
+  else if ((inst.relocs[0].type < BFD_RELOC_ARM_ALU_PC_G0_NC
+           || inst.relocs[0].type > BFD_RELOC_ARM_LDC_SB_G2)
+          && inst.relocs[0].type != BFD_RELOC_ARM_LDR_PC_G0)
     {
       if (thumb_mode)
-       inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
+       inst.relocs[0].type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
       else
-       inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+       inst.relocs[0].type = BFD_RELOC_ARM_CP_OFF_IMM;
     }
 
   /* Prefer + for zero encoded value.  */
@@ -8305,9 +8529,9 @@ static void
 do_rm_rd_rn (void)
 {
   constraint ((inst.operands[2].reg == REG_PC), BAD_PC);
-  constraint (((inst.reloc.exp.X_op != O_constant
-               && inst.reloc.exp.X_op != O_illegal)
-              || inst.reloc.exp.X_add_number != 0),
+  constraint (((inst.relocs[0].exp.X_op != O_constant
+               && inst.relocs[0].exp.X_op != O_illegal)
+              || inst.relocs[0].exp.X_add_number != 0),
              BAD_ADDR_MODE);
   inst.instruction |= inst.operands[0].reg;
   inst.instruction |= inst.operands[1].reg << 12;
@@ -8341,9 +8565,16 @@ do_adr (void)
 
   /* Frag hacking will turn this into a sub instruction if the offset turns
      out to be negative.  */
-  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-  inst.reloc.pc_rel = 1;
-  inst.reloc.exp.X_add_number -= 8;
+  inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE;
+  inst.relocs[0].pc_rel = 1;
+  inst.relocs[0].exp.X_add_number -= 8;
+
+  if (support_interwork
+      && inst.relocs[0].exp.X_op == O_symbol
+      && inst.relocs[0].exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+      && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+    inst.relocs[0].exp.X_add_number |= 1;
 }
 
 /* This is a pseudo-op of the form "adrl rd, label" to be converted
@@ -8358,17 +8589,24 @@ do_adrl (void)
 
   /* Frag hacking will turn this into a sub instruction if the offset turns
      out to be negative.  */
-  inst.reloc.type             = BFD_RELOC_ARM_ADRL_IMMEDIATE;
-  inst.reloc.pc_rel           = 1;
+  inst.relocs[0].type         = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+  inst.relocs[0].pc_rel               = 1;
   inst.size                   = INSN_SIZE * 2;
-  inst.reloc.exp.X_add_number -= 8;
+  inst.relocs[0].exp.X_add_number -= 8;
+
+  if (support_interwork
+      && inst.relocs[0].exp.X_op == O_symbol
+      && inst.relocs[0].exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+      && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+    inst.relocs[0].exp.X_add_number |= 1;
 }
 
 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 ,
+  constraint (inst.relocs[0].type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+             && inst.relocs[0].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;
@@ -8453,13 +8691,13 @@ encode_branch (int default_reloc)
       constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32
                  && inst.operands[0].imm != BFD_RELOC_ARM_TLS_CALL,
                  _("the only valid suffixes here are '(plt)' and '(tlscall)'"));
-      inst.reloc.type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
+      inst.relocs[0].type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
        ? BFD_RELOC_ARM_PLT32
        : thumb_mode ? BFD_RELOC_ARM_THM_TLS_CALL : BFD_RELOC_ARM_TLS_CALL;
     }
   else
-    inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
-  inst.reloc.pc_rel = 1;
+    inst.relocs[0].type = (bfd_reloc_code_real_type) default_reloc;
+  inst.relocs[0].pc_rel = 1;
 }
 
 static void
@@ -8533,7 +8771,8 @@ do_bx (void)
   /* Output R_ARM_V4BX relocations if is an EABI object that looks like
      it is for ARMv4t or earlier.  */
   want_reloc = !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5);
-  if (object_arch && !ARM_CPU_HAS_FEATURE (*object_arch, arm_ext_v5))
+  if (!ARM_FEATURE_ZERO (selected_object_arch)
+      && !ARM_CPU_HAS_FEATURE (selected_object_arch, arm_ext_v5))
       want_reloc = TRUE;
 
 #ifdef OBJ_ELF
@@ -8542,7 +8781,7 @@ do_bx (void)
     want_reloc = FALSE;
 
   if (want_reloc)
-    inst.reloc.type = BFD_RELOC_ARM_V4BX;
+    inst.relocs[0].type = BFD_RELOC_ARM_V4BX;
 }
 
 
@@ -8640,7 +8879,7 @@ do_co_reg (void)
          || inst.instruction == 0xfe000010)
        /* MCR, MCR2  */
        reject_bad_reg (Rd);
-      else
+      else if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
        /* MRC, MRC2  */
        constraint (Rd == REG_SP, BAD_SP);
     }
@@ -8831,6 +9070,11 @@ encode_ldmstm(int from_push_pop_mnem)
     {
       int is_push = (inst.instruction & A_PUSH_POP_OP_MASK) == A1_OPCODE_PUSH;
 
+      if (is_push && one_reg == 13 /* SP */)
+       /* PR 22483: The A2 encoding cannot be used when
+          pushing the stack pointer as this is UNPREDICTABLE.  */
+       return;
+
       inst.instruction &= A_COND_MASK;
       inst.instruction |= is_push ? A2_OPCODE_PUSH : A2_OPCODE_POP;
       inst.instruction |= one_reg << 12;
@@ -8906,15 +9150,15 @@ do_ldrex (void)
              || (inst.operands[1].reg == REG_PC),
              BAD_ADDR_MODE);
 
-  constraint (inst.reloc.exp.X_op != O_constant
-             || inst.reloc.exp.X_add_number != 0,
+  constraint (inst.relocs[0].exp.X_op != O_constant
+             || inst.relocs[0].exp.X_add_number != 0,
              _("offset must be zero in ARM encoding"));
 
   constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
 
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
-  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.relocs[0].type = BFD_RELOC_UNUSED;
 }
 
 static void
@@ -8941,8 +9185,8 @@ check_ldr_r15_aligned (void)
   constraint (!(inst.operands[1].immisreg)
              && (inst.operands[0].reg == REG_PC
              && inst.operands[1].reg == REG_PC
-             && (inst.reloc.exp.X_add_number & 0x3)),
-             _("ldr to register 15 must be 4-byte alligned"));
+             && (inst.relocs[0].exp.X_add_number & 0x3)),
+             _("ldr to register 15 must be 4-byte aligned"));
 }
 
 static void
@@ -8963,8 +9207,8 @@ do_ldstt (void)
      reject [Rn,...].  */
   if (inst.operands[1].preind)
     {
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
+      constraint (inst.relocs[0].exp.X_op != O_constant
+                 || inst.relocs[0].exp.X_add_number != 0,
                  _("this instruction requires a post-indexed address"));
 
       inst.operands[1].preind = 0;
@@ -8995,8 +9239,8 @@ do_ldsttv4 (void)
      reject [Rn,...].  */
   if (inst.operands[1].preind)
     {
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
+      constraint (inst.relocs[0].exp.X_op != O_constant
+                 || inst.relocs[0].exp.X_add_number != 0,
                  _("this instruction requires a post-indexed address"));
 
       inst.operands[1].preind = 0;
@@ -9035,8 +9279,8 @@ do_mlas (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 ,
+  constraint (inst.relocs[0].type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+             && inst.relocs[0].type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
              THUMB1_RELOC_ONLY);
   inst.instruction |= inst.operands[0].reg << 12;
   encode_arm_shifter_operand (1);
@@ -9050,14 +9294,14 @@ do_mov16 (void)
   bfd_boolean top;
 
   top = (inst.instruction & 0x00400000) != 0;
-  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
-             _(":lower16: not allowed this instruction"));
-  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
-             _(":upper16: not allowed instruction"));
+  constraint (top && inst.relocs[0].type == BFD_RELOC_ARM_MOVW,
+             _(":lower16: not allowed in this instruction"));
+  constraint (!top && inst.relocs[0].type == BFD_RELOC_ARM_MOVT,
+             _(":upper16: not allowed in this instruction"));
   inst.instruction |= inst.operands[0].reg << 12;
-  if (inst.reloc.type == BFD_RELOC_UNUSED)
+  if (inst.relocs[0].type == BFD_RELOC_UNUSED)
     {
-      imm = inst.reloc.exp.X_add_number;
+      imm = inst.relocs[0].exp.X_add_number;
       /* The value is in two pieces: 0:11, 16:19.  */
       inst.instruction |= (imm & 0x00000fff);
       inst.instruction |= (imm & 0x0000f000) << 4;
@@ -9105,6 +9349,11 @@ do_vmrs (void)
       return;
     }
 
+  /* MVFR2 is only valid at ARMv8-A.  */
+  if (inst.operands[1].reg == 5)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+               _(BAD_FPU));
+
   /* APSR_ sets isvec. All other refs to PC are illegal.  */
   if (!inst.operands[0].isvec && Rt == REG_PC)
     {
@@ -9131,6 +9380,11 @@ do_vmsr (void)
       return;
     }
 
+  /* MVFR2 is only valid for ARMv8-A.  */
+  if (inst.operands[0].reg == 5)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+               _(BAD_FPU));
+
   /* If we get through parsing the register name, we just insert the number
      generated into the instruction without further validation.  */
   inst.instruction |= (inst.operands[0].reg << 16);
@@ -9151,7 +9405,7 @@ do_mrs (void)
   if (inst.operands[1].isreg)
     {
       br = inst.operands[1].reg;
-      if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf000))
+      if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf0000))
        as_bad (_("bad register for mrs"));
     }
   else
@@ -9182,8 +9436,8 @@ do_msr (void)
   else
     {
       inst.instruction |= INST_IMMEDIATE;
-      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-      inst.reloc.pc_rel = 0;
+      inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE;
+      inst.relocs[0].pc_rel = 0;
     }
 }
 
@@ -9423,28 +9677,28 @@ do_shift (void)
                  _("extraneous shift as part of operand to shift insn"));
     }
   else
-    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+    inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM;
 }
 
 static void
 do_smc (void)
 {
-  inst.reloc.type = BFD_RELOC_ARM_SMC;
-  inst.reloc.pc_rel = 0;
+  inst.relocs[0].type = BFD_RELOC_ARM_SMC;
+  inst.relocs[0].pc_rel = 0;
 }
 
 static void
 do_hvc (void)
 {
-  inst.reloc.type = BFD_RELOC_ARM_HVC;
-  inst.reloc.pc_rel = 0;
+  inst.relocs[0].type = BFD_RELOC_ARM_HVC;
+  inst.relocs[0].pc_rel = 0;
 }
 
 static void
 do_swi (void)
 {
-  inst.reloc.type = BFD_RELOC_ARM_SWI;
-  inst.reloc.pc_rel = 0;
+  inst.relocs[0].type = BFD_RELOC_ARM_SWI;
+  inst.relocs[0].pc_rel = 0;
 }
 
 static void
@@ -9546,14 +9800,14 @@ do_strex (void)
   constraint (inst.operands[0].reg == inst.operands[1].reg
              || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
 
-  constraint (inst.reloc.exp.X_op != O_constant
-             || inst.reloc.exp.X_add_number != 0,
+  constraint (inst.relocs[0].exp.X_op != O_constant
+             || inst.relocs[0].exp.X_add_number != 0,
              _("offset must be zero in ARM encoding"));
 
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg;
   inst.instruction |= inst.operands[2].reg << 16;
-  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.relocs[0].type = BFD_RELOC_UNUSED;
 }
 
 static void
@@ -9940,15 +10194,15 @@ do_fpa_ldmstm (void)
         [Rn]{!}.  The instruction does not really support stacking or
         unstacking, so we have to emulate these by setting appropriate
         bits and offsets.  */
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
+      constraint (inst.relocs[0].exp.X_op != O_constant
+                 || inst.relocs[0].exp.X_add_number != 0,
                  _("this instruction does not support indexing"));
 
       if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
-       inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
+       inst.relocs[0].exp.X_add_number = 12 * inst.operands[1].imm;
 
       if (!(inst.instruction & INDEX_UP))
-       inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
+       inst.relocs[0].exp.X_add_number = -inst.relocs[0].exp.X_add_number;
 
       if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
        {
@@ -10068,7 +10322,7 @@ do_iwmmxt_wldstd (void)
       if (inst.operands[1].writeback)
        inst.instruction |= WRITE_BACK;
       inst.instruction |= inst.operands[1].reg << 16;
-      inst.instruction |= inst.reloc.exp.X_add_number << 4;
+      inst.instruction |= inst.relocs[0].exp.X_add_number << 4;
       inst.instruction |= inst.operands[1].imm;
     }
   else
@@ -10240,7 +10494,7 @@ do_xsc_mra (void)
 static void
 encode_thumb32_shifted_operand (int i)
 {
-  unsigned int value = inst.reloc.exp.X_add_number;
+  unsigned int value = inst.relocs[0].exp.X_add_number;
   unsigned int shift = inst.operands[i].shift_kind;
 
   constraint (inst.operands[i].immisreg,
@@ -10250,7 +10504,7 @@ encode_thumb32_shifted_operand (int i)
     inst.instruction |= SHIFT_ROR << 4;
   else
     {
-      constraint (inst.reloc.exp.X_op != O_constant,
+      constraint (inst.relocs[0].exp.X_op != O_constant,
                  _("expression too complex"));
 
       constraint (value > 32
@@ -10302,14 +10556,14 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
       inst.instruction |= inst.operands[i].imm;
       if (inst.operands[i].shifted)
        {
-         constraint (inst.reloc.exp.X_op != O_constant,
+         constraint (inst.relocs[0].exp.X_op != O_constant,
                      _("expression too complex"));
-         constraint (inst.reloc.exp.X_add_number < 0
-                     || inst.reloc.exp.X_add_number > 3,
+         constraint (inst.relocs[0].exp.X_add_number < 0
+                     || inst.relocs[0].exp.X_add_number > 3,
                      _("shift out of range"));
-         inst.instruction |= inst.reloc.exp.X_add_number << 4;
+         inst.instruction |= inst.relocs[0].exp.X_add_number << 4;
        }
-      inst.reloc.type = BFD_RELOC_UNUSED;
+      inst.relocs[0].type = BFD_RELOC_UNUSED;
     }
   else if (inst.operands[i].preind)
     {
@@ -10331,7 +10585,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
          if (inst.operands[i].writeback)
            inst.instruction |= 0x00000100;
        }
-      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
+      inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_IMM;
     }
   else if (inst.operands[i].postind)
     {
@@ -10343,7 +10597,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
        inst.instruction |= 0x00200000;
       else
        inst.instruction |= 0x00000900;
-      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
+      inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_IMM;
     }
   else /* unindexed - only for coprocessor */
     inst.error = _("instruction does not accept unindexed addressing");
@@ -10371,6 +10625,11 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_asrs,  1000, fa50f000),                   \
   X(_b,     e000, f000b000),                   \
   X(_bcond, d000, f0008000),                   \
+  X(_bf,    0000, f040e001),                   \
+  X(_bfcsel,0000, f000e001),                   \
+  X(_bfx,   0000, f060e001),                   \
+  X(_bfl,   0000, f000c001),                   \
+  X(_bflx,  0000, f070e001),                   \
   X(_bic,   4380, ea200000),                   \
   X(_bics,  4380, ea300000),                   \
   X(_cmn,   42c0, eb100f00),                   \
@@ -10379,6 +10638,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_cpsid, b670, f3af8600),                   \
   X(_cpy,   4600, ea4f0000),                   \
   X(_dec_sp,80dd, f1ad0d00),                   \
+  X(_dls,   0000, f040e001),                   \
   X(_eor,   4040, ea800000),                   \
   X(_eors,  4040, ea900000),                   \
   X(_inc_sp,00dd, f10d0d00),                   \
@@ -10391,6 +10651,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_ldr_pc,4800, f85f0000),                   \
   X(_ldr_pc2,4800, f85f0000),                  \
   X(_ldr_sp,9800, f85d0000),                   \
+  X(_le,    0000, f00fc001),                   \
   X(_lsl,   0000, fa00f000),                   \
   X(_lsls,  0000, fa10f000),                   \
   X(_lsr,   0800, fa20f000),                   \
@@ -10432,6 +10693,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_yield, bf10, f3af8001),                   \
   X(_wfe,   bf20, f3af8002),                   \
   X(_wfi,   bf30, f3af8003),                   \
+  X(_wls,   0000, f040c001),                   \
   X(_sev,   bf40, f3af8004),                    \
   X(_sevl,  bf50, f3af8005),                   \
   X(_udf,   de00, f7f0a000)
@@ -10475,11 +10737,11 @@ do_t_add_sub_w (void)
     reject_bad_reg (Rd);
 
   inst.instruction |= (Rn << 16) | (Rd << 8);
-  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+  inst.relocs[0].type = BFD_RELOC_ARM_T32_IMM12;
 }
 
 /* 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)
@@ -10510,7 +10772,8 @@ do_t_add_sub (void)
        {
          int add;
 
-         constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
+         if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+           constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
 
          add = (inst.instruction == T_MNEM_add
                 || inst.instruction == T_MNEM_adds);
@@ -10536,11 +10799,12 @@ do_t_add_sub (void)
                {
                  inst.instruction = THUMB_OP16(opcode);
                  inst.instruction |= (Rd << 4) | Rs;
-                 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.relocs[0].type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                     || (inst.relocs[0].type
+                         > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC))
                  {
                    if (inst.size_req == 2)
-                     inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+                     inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD;
                    else
                      inst.relax = opcode;
                  }
@@ -10551,29 +10815,31 @@ do_t_add_sub (void)
          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 ,
+             constraint ((inst.relocs[0].type
+                          >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC)
+                         && (inst.relocs[0].type
+                             <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) ,
                          THUMB1_RELOC_ONLY);
              if (Rd == REG_PC)
                {
                  constraint (add, BAD_PC);
                  constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
                             _("only SUBS PC, LR, #const allowed"));
-                 constraint (inst.reloc.exp.X_op != O_constant,
+                 constraint (inst.relocs[0].exp.X_op != O_constant,
                              _("expression too complex"));
-                 constraint (inst.reloc.exp.X_add_number < 0
-                             || inst.reloc.exp.X_add_number > 0xff,
+                 constraint (inst.relocs[0].exp.X_add_number < 0
+                             || inst.relocs[0].exp.X_add_number > 0xff,
                             _("immediate value out of range"));
                  inst.instruction = T2_SUBS_PC_LR
-                                    | inst.reloc.exp.X_add_number;
-                 inst.reloc.type = BFD_RELOC_UNUSED;
+                                    | inst.relocs[0].exp.X_add_number;
+                 inst.relocs[0].type = BFD_RELOC_UNUSED;
                  return;
                }
              else if (Rs == REG_PC)
                {
                  /* Always use addw/subw.  */
                  inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
-                 inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+                 inst.relocs[0].type = BFD_RELOC_ARM_T32_IMM12;
                }
              else
                {
@@ -10581,9 +10847,9 @@ do_t_add_sub (void)
                  inst.instruction = (inst.instruction & 0xe1ffffff)
                                     | 0x10000000;
                  if (flags)
-                   inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+                   inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
                  else
-                   inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
+                   inst.relocs[0].type = BFD_RELOC_ARM_T32_ADD_IMM;
                }
              inst.instruction |= Rd << 8;
              inst.instruction |= Rs << 16;
@@ -10591,7 +10857,7 @@ do_t_add_sub (void)
        }
       else
        {
-         unsigned int value = inst.reloc.exp.X_add_number;
+         unsigned int value = inst.relocs[0].exp.X_add_number;
          unsigned int shift = inst.operands[2].shift_kind;
 
          Rn = inst.operands[2].reg;
@@ -10634,7 +10900,8 @@ do_t_add_sub (void)
            }
 
          constraint (Rd == REG_PC, BAD_PC);
-         constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
+         if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+           constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
          constraint (Rs == REG_PC, BAD_PC);
          reject_bad_reg (Rn);
 
@@ -10666,7 +10933,7 @@ do_t_add_sub (void)
          inst.instruction = (inst.instruction == T_MNEM_add
                              ? 0x0000 : 0x8000);
          inst.instruction |= (Rd << 4) | Rs;
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+         inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD;
          return;
        }
 
@@ -10717,19 +10984,24 @@ do_t_adr (void)
       /* Generate a 32-bit opcode.  */
       inst.instruction = THUMB_OP32 (inst.instruction);
       inst.instruction |= Rd << 8;
-      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
-      inst.reloc.pc_rel = 1;
+      inst.relocs[0].type = BFD_RELOC_ARM_T32_ADD_PC12;
+      inst.relocs[0].pc_rel = 1;
     }
   else
     {
       /* Generate a 16-bit opcode.  */
       inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
-      inst.reloc.pc_rel = 1;
-
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD;
+      inst.relocs[0].exp.X_add_number -= 4; /* PC relative adjust.  */
+      inst.relocs[0].pc_rel = 1;
       inst.instruction |= Rd << 4;
     }
+
+  if (inst.relocs[0].exp.X_op == O_symbol
+      && inst.relocs[0].exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+      && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+    inst.relocs[0].exp.X_add_number += 1;
 }
 
 /* Arithmetic instructions for which there is just one 16-bit
@@ -10764,7 +11036,7 @@ do_t_arit3 (void)
          inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
          inst.instruction |= Rd << 8;
          inst.instruction |= Rs << 16;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+         inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
        }
       else
        {
@@ -10852,7 +11124,7 @@ do_t_arit3c (void)
          inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
          inst.instruction |= Rd << 8;
          inst.instruction |= Rs << 16;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+         inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
        }
       else
        {
@@ -11045,7 +11317,7 @@ do_t_branch (void)
       && (inst.size_req == 4
          || (inst.size_req != 2
              && (inst.operands[0].hasreloc
-                 || inst.reloc.exp.X_op == O_constant))))
+                 || inst.relocs[0].exp.X_op == O_constant))))
     {
       inst.instruction = THUMB_OP32(opcode);
       if (cond == COND_ALWAYS)
@@ -11075,8 +11347,8 @@ do_t_branch (void)
       if (unified_syntax && inst.size_req != 2)
        inst.relax = opcode;
     }
-  inst.reloc.type = reloc;
-  inst.reloc.pc_rel = 1;
+  inst.relocs[0].type = reloc;
+  inst.relocs[0].pc_rel = 1;
 }
 
 /* Actually do the work for Thumb state bkpt and hlt.  The only difference
@@ -11120,20 +11392,20 @@ do_t_branch23 (void)
      the branch encoding is now needed to deal with TLSCALL relocs.
      So if we see a PLT reloc now, put it back to how it used to be to
      keep the preexisting behaviour.  */
-  if (inst.reloc.type == BFD_RELOC_ARM_PLT32)
-    inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
+  if (inst.relocs[0].type == BFD_RELOC_ARM_PLT32)
+    inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH23;
 
 #if defined(OBJ_COFF)
   /* If the destination of the branch is a defined symbol which does not have
      the THUMB_FUNC attribute, then we must be calling a function which has
      the (interfacearm) attribute.  We look for the Thumb entry point to that
      function and change the branch to refer to that function instead. */
-  if (  inst.reloc.exp.X_op == O_symbol
-      && inst.reloc.exp.X_add_symbol != NULL
-      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
-      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
-    inst.reloc.exp.X_add_symbol =
-      find_real_start (inst.reloc.exp.X_add_symbol);
+  if (  inst.relocs[0].exp.X_op == O_symbol
+      && inst.relocs[0].exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+      && ! THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+    inst.relocs[0].exp.X_add_symbol
+      = find_real_start (inst.relocs[0].exp.X_add_symbol);
 #endif
 }
 
@@ -11175,6 +11447,12 @@ do_t_clz (void)
   inst.instruction |= Rm;
 }
 
+static void
+do_t_csdb (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+}
+
 static void
 do_t_cps (void)
 {
@@ -11235,8 +11513,8 @@ do_t_cbz (void)
   set_it_insn_type (OUTSIDE_IT_INSN);
   constraint (inst.operands[0].reg > 7, BAD_HIREG);
   inst.instruction |= inst.operands[0].reg;
-  inst.reloc.pc_rel = 1;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
+  inst.relocs[0].pc_rel = 1;
+  inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH7;
 }
 
 static void
@@ -11318,16 +11596,19 @@ do_t_it (void)
 
 /* Helper function used for both push/pop and ldm/stm.  */
 static void
-encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
+encode_thumb2_multi (bfd_boolean do_io, int base, unsigned mask,
+                    bfd_boolean writeback)
 {
-  bfd_boolean load;
+  bfd_boolean load, store;
 
-  load = (inst.instruction & (1 << 20)) != 0;
+  gas_assert (base != -1 || !do_io);
+  load = do_io && ((inst.instruction & (1 << 20)) != 0);
+  store = do_io && !load;
 
   if (mask & (1 << 13))
     inst.error =  _("SP not allowed in register list");
 
-  if ((mask & (1 << base)) != 0
+  if (do_io && (mask & (1 << base)) != 0
       && writeback)
     inst.error = _("having the base register in the register list when "
                   "using write back is UNPREDICTABLE");
@@ -11342,13 +11623,13 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
            set_it_insn_type_last ();
        }
     }
-  else
+  else if (store)
     {
       if (mask & (1 << 15))
        inst.error = _("PC not allowed in register list");
     }
 
-  if ((mask & (mask - 1)) == 0)
+  if (do_io && ((mask & (mask - 1)) == 0))
     {
       /* Single register transfers implemented as str/ldr.  */
       if (writeback)
@@ -11377,14 +11658,15 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
     inst.instruction |= WRITE_BACK;
 
   inst.instruction |= mask;
-  inst.instruction |= base << 16;
+  if (do_io)
+    inst.instruction |= base << 16;
 }
 
 static void
 do_t_ldmstm (void)
 {
   /* This really doesn't seem worth it.  */
-  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
+  constraint (inst.relocs[0].type != BFD_RELOC_UNUSED,
              _("expression too complex"));
   constraint (inst.operands[1].writeback,
              _("Thumb load/store multiple does not support {reglist}^"));
@@ -11472,8 +11754,9 @@ do_t_ldmstm (void)
          if (inst.instruction < 0xffff)
            inst.instruction = THUMB_OP32 (inst.instruction);
 
-         encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
-                               inst.operands[0].writeback);
+         encode_thumb2_multi (TRUE /* do_io */, inst.operands[0].reg,
+                              inst.operands[1].imm,
+                              inst.operands[0].writeback);
        }
     }
   else
@@ -11521,7 +11804,7 @@ do_t_ldrex (void)
 
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
-  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
+  inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_U8;
 }
 
 static void
@@ -11591,7 +11874,7 @@ do_t_ldst (void)
                {
                  if (Rn == REG_PC)
                    {
-                     if (inst.reloc.pc_rel)
+                     if (inst.relocs[0].pc_rel)
                        opcode = T_MNEM_ldr_pc2;
                      else
                        opcode = T_MNEM_ldr_pc;
@@ -11612,7 +11895,7 @@ do_t_ldst (void)
                }
              inst.instruction |= THUMB_OP16 (opcode);
              if (inst.size_req == 2)
-               inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+               inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET;
              else
                inst.relax = opcode;
              return;
@@ -11691,7 +11974,7 @@ do_t_ldst (void)
        inst.instruction = T_OPCODE_STR_SP;
 
       inst.instruction |= inst.operands[0].reg << 8;
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET;
       return;
     }
 
@@ -11701,7 +11984,7 @@ do_t_ldst (void)
       /* Immediate offset.  */
       inst.instruction |= inst.operands[0].reg;
       inst.instruction |= inst.operands[1].reg << 3;
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET;
       return;
     }
 
@@ -11882,7 +12165,8 @@ do_t_mov_cmp (void)
                  /* This is mov.w.  */
                  constraint (Rn == REG_PC, BAD_PC);
                  constraint (Rm == REG_PC, BAD_PC);
-                 constraint (Rn == REG_SP && Rm == REG_SP, BAD_SP);
+                 if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+                   constraint (Rn == REG_SP && Rm == REG_SP, BAD_SP);
                }
            }
          else
@@ -11898,25 +12182,27 @@ do_t_mov_cmp (void)
            {
              inst.instruction = THUMB_OP16 (opcode);
              inst.instruction |= Rn << 8;
-             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.relocs[0].type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                 || inst.relocs[0].type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
                {
                  if (inst.size_req == 2)
-                   inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+                   inst.relocs[0].type = BFD_RELOC_ARM_THUMB_IMM;
                  else
                    inst.relax = opcode;
                }
            }
          else
            {
-             constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
-                         && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+             constraint ((inst.relocs[0].type
+                          >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC)
+                         && (inst.relocs[0].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.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+             inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
            }
        }
       else if (inst.operands[1].shifted && inst.operands[1].immisreg
@@ -12003,7 +12289,7 @@ do_t_mov_cmp (void)
            {
              inst.instruction |= Rn;
              inst.instruction |= Rm << 3;
-             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+             inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT;
            }
          else
            {
@@ -12094,7 +12380,7 @@ do_t_mov_cmp (void)
       constraint (Rn > 7,
                  _("only lo regs allowed with immediate"));
       inst.instruction |= Rn << 8;
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_IMM;
     }
 }
 
@@ -12106,24 +12392,24 @@ do_t_mov16 (void)
   bfd_boolean top;
 
   top = (inst.instruction & 0x00800000) != 0;
-  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
+  if (inst.relocs[0].type == BFD_RELOC_ARM_MOVW)
     {
-      constraint (top, _(":lower16: not allowed this instruction"));
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
+      constraint (top, _(":lower16: not allowed in this instruction"));
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_MOVW;
     }
-  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
+  else if (inst.relocs[0].type == BFD_RELOC_ARM_MOVT)
     {
-      constraint (!top, _(":upper16: not allowed this instruction"));
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
+      constraint (!top, _(":upper16: not allowed in this instruction"));
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_MOVT;
     }
 
   Rd = inst.operands[0].reg;
   reject_bad_reg (Rd);
 
   inst.instruction |= Rd << 8;
-  if (inst.reloc.type == BFD_RELOC_UNUSED)
+  if (inst.relocs[0].type == BFD_RELOC_UNUSED)
     {
-      imm = inst.reloc.exp.X_add_number;
+      imm = inst.relocs[0].exp.X_add_number;
       inst.instruction |= (imm & 0xf000) << 4;
       inst.instruction |= (imm & 0x0800) << 15;
       inst.instruction |= (imm & 0x0700) << 4;
@@ -12173,7 +12459,7 @@ do_t_mvn_tst (void)
            inst.instruction = THUMB_OP32 (inst.instruction);
          inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
          inst.instruction |= Rn << r0off;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+         inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
        }
       else
        {
@@ -12485,7 +12771,7 @@ do_t_orn (void)
   if (!inst.operands[2].isreg)
     {
       inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+      inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
     }
   else
     {
@@ -12519,8 +12805,8 @@ do_t_pkhbt (void)
   inst.instruction |= Rm;
   if (inst.operands[3].present)
     {
-      unsigned int val = inst.reloc.exp.X_add_number;
-      constraint (inst.reloc.exp.X_op != O_constant,
+      unsigned int val = inst.relocs[0].exp.X_add_number;
+      constraint (inst.relocs[0].exp.X_op != O_constant,
                  _("expression too complex"));
       inst.instruction |= (val & 0x1c) << 10;
       inst.instruction |= (val & 0x03) << 6;
@@ -12560,7 +12846,7 @@ do_t_push_pop (void)
 
   constraint (inst.operands[0].writeback,
              _("push/pop do not support {reglist}^"));
-  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
+  constraint (inst.relocs[0].type != BFD_RELOC_UNUSED,
              _("expression too complex"));
 
   mask = inst.operands[0].imm;
@@ -12577,7 +12863,7 @@ do_t_push_pop (void)
   else if (unified_syntax)
     {
       inst.instruction = THUMB_OP32 (inst.instruction);
-      encode_thumb2_ldmstm (13, mask, TRUE);
+      encode_thumb2_multi (TRUE /* do_io */, 13, mask, TRUE);
     }
   else
     {
@@ -12586,6 +12872,36 @@ do_t_push_pop (void)
     }
 }
 
+static void
+do_t_clrm (void)
+{
+  if (unified_syntax)
+    encode_thumb2_multi (FALSE /* do_io */, -1, inst.operands[0].imm, FALSE);
+  else
+    {
+      inst.error = _("invalid register list to push/pop instruction");
+      return;
+    }
+}
+
+static void
+do_t_vscclrm (void)
+{
+  if (inst.operands[0].issingle)
+    {
+      inst.instruction |= (inst.operands[0].reg & 0x1) << 22;
+      inst.instruction |= (inst.operands[0].reg & 0x1e) << 11;
+      inst.instruction |= inst.operands[0].imm;
+    }
+  else
+    {
+      inst.instruction |= (inst.operands[0].reg & 0x10) << 18;
+      inst.instruction |= (inst.operands[0].reg & 0xf) << 12;
+      inst.instruction |= 1 << 8;
+      inst.instruction |= inst.operands[0].imm << 1;
+    }
+}
+
 static void
 do_t_rbit (void)
 {
@@ -12678,15 +12994,15 @@ do_t_rsb (void)
       if (inst.size_req == 4 || !unified_syntax)
        narrow = FALSE;
 
-      if (inst.reloc.exp.X_op != O_constant
-         || inst.reloc.exp.X_add_number != 0)
+      if (inst.relocs[0].exp.X_op != O_constant
+         || inst.relocs[0].exp.X_add_number != 0)
        narrow = FALSE;
 
       /* Turn rsb #0 into 16-bit neg.  We should probably do this via
         relaxation, but it doesn't seem worth the hassle.  */
       if (narrow)
        {
-         inst.reloc.type = BFD_RELOC_UNUSED;
+         inst.relocs[0].type = BFD_RELOC_UNUSED;
          inst.instruction = THUMB_OP16 (T_MNEM_negs);
          inst.instruction |= Rs << 3;
          inst.instruction |= Rd;
@@ -12694,7 +13010,7 @@ do_t_rsb (void)
       else
        {
          inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+         inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
        }
     }
   else
@@ -12778,7 +13094,7 @@ do_t_shift (void)
              inst.instruction |= inst.operands[0].reg << 8;
              encode_thumb32_shifted_operand (1);
              /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
-             inst.reloc.type = BFD_RELOC_UNUSED;
+             inst.relocs[0].type = BFD_RELOC_UNUSED;
            }
        }
       else
@@ -12810,7 +13126,7 @@ do_t_shift (void)
                case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
                default: abort ();
                }
-             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+             inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT;
              inst.instruction |= inst.operands[0].reg;
              inst.instruction |= inst.operands[1].reg << 3;
            }
@@ -12854,7 +13170,7 @@ do_t_shift (void)
            case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
            default: abort ();
            }
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+         inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT;
          inst.instruction |= inst.operands[0].reg;
          inst.instruction |= inst.operands[1].reg << 3;
        }
@@ -12900,12 +13216,12 @@ do_t_simd2 (void)
 static void
 do_t_smc (void)
 {
-  unsigned int value = inst.reloc.exp.X_add_number;
+  unsigned int value = inst.relocs[0].exp.X_add_number;
   constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a),
              _("SMC is not permitted on this architecture"));
-  constraint (inst.reloc.exp.X_op != O_constant,
+  constraint (inst.relocs[0].exp.X_op != O_constant,
              _("expression too complex"));
-  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.relocs[0].type = BFD_RELOC_UNUSED;
   inst.instruction |= (value & 0xf000) >> 12;
   inst.instruction |= (value & 0x0ff0);
   inst.instruction |= (value & 0x000f) << 16;
@@ -12916,9 +13232,9 @@ do_t_smc (void)
 static void
 do_t_hvc (void)
 {
-  unsigned int value = inst.reloc.exp.X_add_number;
+  unsigned int value = inst.relocs[0].exp.X_add_number;
 
-  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.relocs[0].type = BFD_RELOC_UNUSED;
   inst.instruction |= (value & 0x0fff);
   inst.instruction |= (value & 0xf000) << 4;
 }
@@ -12940,11 +13256,11 @@ do_t_ssat_usat (int bias)
 
   if (inst.operands[3].present)
     {
-      offsetT shift_amount = inst.reloc.exp.X_add_number;
+      offsetT shift_amount = inst.relocs[0].exp.X_add_number;
 
-      inst.reloc.type = BFD_RELOC_UNUSED;
+      inst.relocs[0].type = BFD_RELOC_UNUSED;
 
-      constraint (inst.reloc.exp.X_op != O_constant,
+      constraint (inst.relocs[0].exp.X_op != O_constant,
                  _("expression too complex"));
 
       if (shift_amount != 0)
@@ -12997,7 +13313,7 @@ do_t_strex (void)
   inst.instruction |= inst.operands[0].reg << 8;
   inst.instruction |= inst.operands[1].reg << 12;
   inst.instruction |= inst.operands[2].reg << 16;
-  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
+  inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_U8;
 }
 
 static void
@@ -13075,18 +13391,7 @@ do_t_sxth (void)
 static void
 do_t_swi (void)
 {
-  /* We have to do the following check manually as ARM_EXT_OS only applies
-     to ARM_EXT_V6M.  */
-  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.  */
-         && ! 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);
-    }
-
-  inst.reloc.type = BFD_RELOC_ARM_SWI;
+  inst.relocs[0].type = BFD_RELOC_ARM_SWI;
 }
 
 static void
@@ -13103,7 +13408,8 @@ do_t_tb (void)
   Rn = inst.operands[0].reg;
   Rm = inst.operands[0].imm;
 
-  constraint (Rn == REG_SP, BAD_SP);
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+    constraint (Rn == REG_SP, BAD_SP);
   reject_bad_reg (Rm);
 
   constraint (!half && inst.operands[0].shifted,
@@ -13157,6 +13463,193 @@ do_t_usat16 (void)
   inst.instruction |= Rn << 16;
 }
 
+/* Checking the range of the branch offset (VAL) with NBITS bits
+   and IS_SIGNED signedness.  Also checks the LSB to be 0.  */
+static int
+v8_1_branch_value_check (int val, int nbits, int is_signed)
+{
+  gas_assert (nbits > 0 && nbits <= 32);
+  if (is_signed)
+    {
+      int cmp = (1 << (nbits - 1));
+      if ((val < -cmp) || (val >= cmp) || (val & 0x01))
+       return FAIL;
+    }
+  else
+    {
+      if ((val <= 0) || (val >= (1 << nbits)) || (val & 0x1))
+       return FAIL;
+    }
+    return SUCCESS;
+}
+
+/* For branches in Armv8.1-M Mainline.  */
+static void
+do_t_branch_future (void)
+{
+  unsigned long insn = inst.instruction;
+
+  inst.instruction = THUMB_OP32 (inst.instruction);
+  if (inst.operands[0].hasreloc == 0)
+    {
+      if (v8_1_branch_value_check (inst.operands[0].imm, 5, FALSE) == FAIL)
+       as_bad (BAD_BRANCH_OFF);
+
+      inst.instruction |= ((inst.operands[0].imm & 0x1f) >> 1) << 23;
+    }
+  else
+    {
+      inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH5;
+      inst.relocs[0].pc_rel = 1;
+    }
+
+  switch (insn)
+    {
+      case T_MNEM_bf:
+       if (inst.operands[1].hasreloc == 0)
+         {
+           int val = inst.operands[1].imm;
+           if (v8_1_branch_value_check (inst.operands[1].imm, 17, TRUE) == FAIL)
+             as_bad (BAD_BRANCH_OFF);
+
+           int immA = (val & 0x0001f000) >> 12;
+           int immB = (val & 0x00000ffc) >> 2;
+           int immC = (val & 0x00000002) >> 1;
+           inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+         }
+       else
+         {
+           inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF17;
+           inst.relocs[1].pc_rel = 1;
+         }
+       break;
+
+      case T_MNEM_bfl:
+       if (inst.operands[1].hasreloc == 0)
+         {
+           int val = inst.operands[1].imm;
+           if (v8_1_branch_value_check (inst.operands[1].imm, 19, TRUE) == FAIL)
+             as_bad (BAD_BRANCH_OFF);
+
+           int immA = (val & 0x0007f000) >> 12;
+           int immB = (val & 0x00000ffc) >> 2;
+           int immC = (val & 0x00000002) >> 1;
+           inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+         }
+         else
+         {
+           inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF19;
+           inst.relocs[1].pc_rel = 1;
+         }
+       break;
+
+      case T_MNEM_bfcsel:
+       /* Operand 1.  */
+       if (inst.operands[1].hasreloc == 0)
+         {
+           int val = inst.operands[1].imm;
+           int immA = (val & 0x00001000) >> 12;
+           int immB = (val & 0x00000ffc) >> 2;
+           int immC = (val & 0x00000002) >> 1;
+           inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+         }
+         else
+         {
+           inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF13;
+           inst.relocs[1].pc_rel = 1;
+         }
+
+       /* Operand 2.  */
+       if (inst.operands[2].hasreloc == 0)
+         {
+             constraint ((inst.operands[0].hasreloc != 0), BAD_ARGS);
+             int val2 = inst.operands[2].imm;
+             int val0 = inst.operands[0].imm & 0x1f;
+             int diff = val2 - val0;
+             if (diff == 4)
+               inst.instruction |= 1 << 17; /* T bit.  */
+             else if (diff != 2)
+               as_bad (_("out of range label-relative fixup value"));
+         }
+       else
+         {
+             constraint ((inst.operands[0].hasreloc == 0), BAD_ARGS);
+             inst.relocs[2].type = BFD_RELOC_THUMB_PCREL_BFCSEL;
+             inst.relocs[2].pc_rel = 1;
+         }
+
+       /* Operand 3.  */
+       constraint (inst.cond != COND_ALWAYS, BAD_COND);
+       inst.instruction |= (inst.operands[3].imm & 0xf) << 18;
+       break;
+
+      case T_MNEM_bfx:
+      case T_MNEM_bflx:
+       inst.instruction |= inst.operands[1].reg << 16;
+       break;
+
+      default: abort ();
+    }
+}
+
+/* Helper function for do_t_loloop to handle relocations.  */
+static void
+v8_1_loop_reloc (int is_le)
+{
+  if (inst.relocs[0].exp.X_op == O_constant)
+    {
+      int value = inst.relocs[0].exp.X_add_number;
+      value = (is_le) ? -value : value;
+
+      if (v8_1_branch_value_check (value, 12, FALSE) == FAIL)
+       as_bad (BAD_BRANCH_OFF);
+
+      int imml, immh;
+
+      immh = (value & 0x00000ffc) >> 2;
+      imml = (value & 0x00000002) >> 1;
+
+      inst.instruction |= (imml << 11) | (immh << 1);
+    }
+  else
+    {
+      inst.relocs[0].type = BFD_RELOC_ARM_THUMB_LOOP12;
+      inst.relocs[0].pc_rel = 1;
+    }
+}
+
+/* To handle the Scalar Low Overhead Loop instructions
+   in Armv8.1-M Mainline.  */
+static void
+do_t_loloop (void)
+{
+  unsigned long insn = inst.instruction;
+
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  inst.instruction = THUMB_OP32 (inst.instruction);
+
+  switch (insn)
+    {
+    case T_MNEM_le:
+      /* le <label>.  */
+      if (!inst.operands[0].present)
+       inst.instruction |= 1 << 21;
+
+      v8_1_loop_reloc (TRUE);
+      break;
+
+    case T_MNEM_wls:
+      v8_1_loop_reloc (FALSE);
+      /* Fall through.  */
+    case T_MNEM_dls:
+      constraint (inst.operands[1].isreg != 1, BAD_ARGS);
+      inst.instruction |= (inst.operands[1].reg << 16);
+      break;
+
+    default: abort();
+    }
+}
+
 /* Neon instruction encoder helpers.  */
 
 /* Encodings for the different types for various Neon opcodes.  */
@@ -13343,6 +13836,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(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),                        \
@@ -13368,7 +13863,9 @@ NEON_ENC_TAB
   X (2, (H, I), HALF),                 \
   X (3, (H, H, H), HALF),              \
   X (3, (H, F, I), MIXED),             \
-  X (3, (F, H, I), MIXED)
+  X (3, (F, H, I), MIXED),             \
+  X (3, (D, H, H), MIXED),             \
+  X (3, (D, H, S), MIXED)
 
 #define S2(A,B)                NS_##A##B
 #define S3(A,B,C)      NS_##A##B##C
@@ -14988,7 +15485,14 @@ do_neon_ceq (void)
    scalars, which are encoded in 5 bits, M : Rm.
    For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
    M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
-   index in M.  */
+   index in M.
+
+   Dot Product instructions are similar to multiply instructions except elsize
+   should always be 32.
+
+   This function translates SCALAR, which is GAS's internal encoding of indexed
+   scalar register, to raw encoding.  There is also register and index range
+   check based on ELSIZE.  */
 
 static unsigned
 neon_scalar_for_mul (unsigned scalar, unsigned elsize)
@@ -15791,6 +16295,8 @@ do_neon_cvt_1 (enum neon_cvt_mode mode)
     /* Half-precision conversions for Advanced SIMD -- neon.  */
     case NS_QD:
     case NS_DQ:
+      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+       return;
 
       if ((rs == NS_DQ)
          && (inst.vectype.el[0].size != 16 || inst.vectype.el[1].size != 32))
@@ -16071,6 +16577,133 @@ do_neon_mac_maybe_scalar_long (void)
   neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
 }
 
+/* Like neon_scalar_for_mul, this function generate Rm encoding from GAS's
+   internal SCALAR.  QUAD_P is 1 if it's for Q format, otherwise it's 0.  */
+
+static unsigned
+neon_scalar_for_fmac_fp16_long (unsigned scalar, unsigned quad_p)
+{
+  unsigned regno = NEON_SCALAR_REG (scalar);
+  unsigned elno = NEON_SCALAR_INDEX (scalar);
+
+  if (quad_p)
+    {
+      if (regno > 7 || elno > 3)
+       goto bad_scalar;
+
+      return ((regno & 0x7)
+             | ((elno & 0x1) << 3)
+             | (((elno >> 1) & 0x1) << 5));
+    }
+  else
+    {
+      if (regno > 15 || elno > 1)
+       goto bad_scalar;
+
+      return (((regno & 0x1) << 5)
+             | ((regno >> 1) & 0x7)
+             | ((elno & 0x1) << 3));
+    }
+
+bad_scalar:
+  first_error (_("scalar out of range for multiply instruction"));
+  return 0;
+}
+
+static void
+do_neon_fmac_maybe_scalar_long (int subtype)
+{
+  enum neon_shape rs;
+  int high8;
+  /* NOTE: vfmal/vfmsl use slightly different NEON three-same encoding.  'size"
+     field (bits[21:20]) has different meaning.  For scalar index variant, it's
+     used to differentiate add and subtract, otherwise it's with fixed value
+     0x2.  */
+  int size = -1;
+
+  if (inst.cond != COND_ALWAYS)
+    as_warn (_("vfmal/vfmsl with FP16 type cannot be conditional, the "
+              "behaviour is UNPREDICTABLE"));
+
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16_fml),
+             _(BAD_FP16));
+
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
+             _(BAD_FPU));
+
+  /* vfmal/vfmsl are in three-same D/Q register format or the third operand can
+     be a scalar index register.  */
+  if (inst.operands[2].isscalar)
+    {
+      high8 = 0xfe000000;
+      if (subtype)
+       size = 16;
+      rs = neon_select_shape (NS_DHS, NS_QDS, NS_NULL);
+    }
+  else
+    {
+      high8 = 0xfc000000;
+      size = 32;
+      if (subtype)
+       inst.instruction |= (0x1 << 23);
+      rs = neon_select_shape (NS_DHH, NS_QDD, NS_NULL);
+    }
+
+  neon_check_type (3, rs, N_EQK, N_EQK, N_KEY | N_F16);
+
+  /* "opcode" from template has included "ubit", so simply pass 0 here.  Also,
+     the "S" bit in size field has been reused to differentiate vfmal and vfmsl,
+     so we simply pass -1 as size.  */
+  unsigned quad_p = (rs == NS_QDD || rs == NS_QDS);
+  neon_three_same (quad_p, 0, size);
+
+  /* Undo neon_dp_fixup.  Redo the high eight bits.  */
+  inst.instruction &= 0x00ffffff;
+  inst.instruction |= high8;
+
+#define LOW1(R) ((R) & 0x1)
+#define HI4(R) (((R) >> 1) & 0xf)
+  /* Unlike usually NEON three-same, encoding for Vn and Vm will depend on
+     whether the instruction is in Q form and whether Vm is a scalar indexed
+     operand.  */
+  if (inst.operands[2].isscalar)
+    {
+      unsigned rm
+       = neon_scalar_for_fmac_fp16_long (inst.operands[2].reg, quad_p);
+      inst.instruction &= 0xffffffd0;
+      inst.instruction |= rm;
+
+      if (!quad_p)
+       {
+         /* Redo Rn as well.  */
+         inst.instruction &= 0xfff0ff7f;
+         inst.instruction |= HI4 (inst.operands[1].reg) << 16;
+         inst.instruction |= LOW1 (inst.operands[1].reg) << 7;
+       }
+    }
+  else if (!quad_p)
+    {
+      /* Redo Rn and Rm.  */
+      inst.instruction &= 0xfff0ff50;
+      inst.instruction |= HI4 (inst.operands[1].reg) << 16;
+      inst.instruction |= LOW1 (inst.operands[1].reg) << 7;
+      inst.instruction |= HI4 (inst.operands[2].reg);
+      inst.instruction |= LOW1 (inst.operands[2].reg) << 5;
+    }
+}
+
+static void
+do_neon_vfmal (void)
+{
+  return do_neon_fmac_maybe_scalar_long (0);
+}
+
+static void
+do_neon_vfmsl (void)
+{
+  return do_neon_fmac_maybe_scalar_long (1);
+}
+
 static void
 do_neon_dyadic_wide (void)
 {
@@ -16446,7 +17079,26 @@ do_neon_mov (void)
     case NS_HI:
     case NS_FI:  /* case 10 (fconsts).  */
       ldconst = "fconsts";
-      encode_fconstd:
+    encode_fconstd:
+      if (!inst.operands[1].immisfloat)
+       {
+         unsigned new_imm;
+         /* Immediate has to fit in 8 bits so float is enough.  */
+         float imm = (float) inst.operands[1].imm;
+         memcpy (&new_imm, &imm, sizeof (float));
+         /* But the assembly may have been written to provide an integer
+            bit pattern that equates to a float, so check that the
+            conversion has worked.  */
+         if (is_quarter_float (new_imm))
+           {
+             if (is_quarter_float (inst.operands[1].imm))
+               as_warn (_("immediate constant is valid both as a bit-pattern and a floating point value (using the fp value)"));
+
+             inst.operands[1].imm = new_imm;
+             inst.operands[1].immisfloat = 1;
+           }
+       }
+
       if (is_quarter_float (inst.operands[1].imm))
        {
          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
@@ -16535,8 +17187,19 @@ 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));
+  if (inst.cond != COND_ALWAYS)
+    {
+      if (thumb_mode)
+       {
+         as_warn (_("ARMv8.2 scalar fp16 instruction cannot be conditional,"
+                    " the behaviour is UNPREDICTABLE"));
+       }
+      else
+       {
+         inst.error = BAD_COND;
+         return;
+       }
+    }
 
   do_vfp_sp_monadic ();
 
@@ -17052,8 +17715,8 @@ do_neon_ldx_stx (void)
   else
     {
       constraint (inst.operands[1].immisreg, BAD_ADDR_MODE);
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
+      constraint (inst.relocs[0].exp.X_op != O_constant
+                 || inst.relocs[0].exp.X_add_number != 0,
                  BAD_ADDR_MODE);
 
       if (inst.operands[1].writeback)
@@ -17256,6 +17919,155 @@ do_vrintm (void)
   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.relocs[0].exp.X_op != O_constant,
+             _("expression too complex"));
+  unsigned rot = inst.relocs[0].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.relocs[0].exp.X_op != O_constant,
+             _("expression too complex"));
+  unsigned rot = inst.relocs[0].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;
+}
+
+/* Dot Product instructions encoding support.  */
+
+static void
+do_neon_dotproduct (int unsigned_p)
+{
+  enum neon_shape rs;
+  unsigned scalar_oprd2 = 0;
+  int high8;
+
+  if (inst.cond != COND_ALWAYS)
+    as_warn (_("Dot Product instructions cannot be conditional,  the behaviour "
+              "is UNPREDICTABLE"));
+
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
+             _(BAD_FPU));
+
+  /* Dot Product instructions are in three-same D/Q register format or the third
+     operand can be a scalar index register.  */
+  if (inst.operands[2].isscalar)
+    {
+      scalar_oprd2 = neon_scalar_for_mul (inst.operands[2].reg, 32);
+      high8 = 0xfe000000;
+      rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
+    }
+  else
+    {
+      high8 = 0xfc000000;
+      rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+    }
+
+  if (unsigned_p)
+    neon_check_type (3, rs, N_EQK, N_EQK, N_KEY | N_U8);
+  else
+    neon_check_type (3, rs, N_EQK, N_EQK, N_KEY | N_S8);
+
+  /* The "U" bit in traditional Three Same encoding is fixed to 0 for Dot
+     Product instruction, so we pass 0 as the "ubit" parameter.  And the
+     "Size" field are fixed to 0x2, so we pass 32 as the "size" parameter.  */
+  neon_three_same (neon_quad (rs), 0, 32);
+
+  /* Undo neon_dp_fixup.  Dot Product instructions are using a slightly
+     different NEON three-same encoding.  */
+  inst.instruction &= 0x00ffffff;
+  inst.instruction |= high8;
+  /* Encode 'U' bit which indicates signedness.  */
+  inst.instruction |= (unsigned_p ? 1 : 0) << 4;
+  /* Re-encode operand2 if it's indexed scalar operand.  What has been encoded
+     from inst.operand[2].reg in neon_three_same is GAS's internal encoding, not
+     the instruction encoding.  */
+  if (inst.operands[2].isscalar)
+    {
+      inst.instruction &= 0xffffffd0;
+      inst.instruction |= LOW4 (scalar_oprd2);
+      inst.instruction |= HI1 (scalar_oprd2) << 5;
+    }
+}
+
+/* Dot Product instructions for signed integer.  */
+
+static void
+do_neon_dotproduct_s (void)
+{
+  return do_neon_dotproduct (0);
+}
+
+/* Dot Product instructions for unsigned integer.  */
+
+static void
+do_neon_dotproduct_u (void)
+{
+  return do_neon_dotproduct (1);
+}
+
 /* Crypto v1 instructions.  */
 static void
 do_crypto_2op_1 (unsigned elttype, int op)
@@ -17397,8 +18209,6 @@ do_crc32_1 (unsigned int poly, unsigned int sz)
 
   if (Rd == REG_PC || Rn == REG_PC || Rm == REG_PC)
     as_warn (UNPRED_REG ("r15"));
-  if (thumb_mode && (Rd == REG_SP || Rn == REG_SP || Rm == REG_SP))
-    as_warn (UNPRED_REG ("r13"));
 }
 
 static void
@@ -17437,6 +18247,16 @@ do_crc32cw (void)
   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. */
 
@@ -17513,18 +18333,18 @@ output_relax_insn (void)
      start of the instruction.  */
   dwarf2_emit_insn (0);
 
-  switch (inst.reloc.exp.X_op)
+  switch (inst.relocs[0].exp.X_op)
     {
     case O_symbol:
-      sym = inst.reloc.exp.X_add_symbol;
-      offset = inst.reloc.exp.X_add_number;
+      sym = inst.relocs[0].exp.X_add_symbol;
+      offset = inst.relocs[0].exp.X_add_number;
       break;
     case O_constant:
       sym = NULL;
-      offset = inst.reloc.exp.X_add_number;
+      offset = inst.relocs[0].exp.X_add_number;
       break;
     default:
-      sym = make_expr_symbol (&inst.reloc.exp);
+      sym = make_expr_symbol (&inst.relocs[0].exp);
       offset = 0;
       break;
   }
@@ -17580,10 +18400,14 @@ output_inst (const char * str)
   else
     md_number_to_chars (to, inst.instruction, inst.size);
 
-  if (inst.reloc.type != BFD_RELOC_UNUSED)
-    fix_new_arm (frag_now, to - frag_now->fr_literal,
-                inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
-                inst.reloc.type);
+  int r;
+  for (r = 0; r < ARM_IT_MAX_RELOCS; r++)
+    {
+      if (inst.relocs[r].type != BFD_RELOC_UNUSED)
+       fix_new_arm (frag_now, to - frag_now->fr_literal,
+                    inst.size, & inst.relocs[r].exp, inst.relocs[r].pc_rel,
+                    inst.relocs[r].type);
+    }
 
   dwarf2_emit_insn (inst.size);
 }
@@ -17790,7 +18614,7 @@ opcode_lookup (char **str)
        case OT_cinfix3_deprecated:
        case OT_odd_infix_unc:
          if (!unified_syntax)
-           return 0;
+           return NULL;
          /* Fall through.  */
 
        case OT_csuffix:
@@ -17914,7 +18738,7 @@ now_it_add_mask (int cond)
      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 (),
@@ -17947,7 +18771,7 @@ now_it_add_mask (int cond)
        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.
@@ -18038,7 +18862,7 @@ handle_it_state (void)
       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;
@@ -18170,12 +18994,13 @@ it_fsm_post_encode (void)
   if (now_it.insn_cond
       && !now_it.warn_deprecated
       && warn_on_deprecated
-      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)
+      && !ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m))
     {
       if (inst.instruction >= 0x10000)
        {
          as_tsktsk (_("IT blocks containing 32-bit Thumb instructions are "
-                    "deprecated in ARMv8"));
+                    "performance deprecated in ARMv8-A and ARMv8-R"));
          now_it.warn_deprecated = TRUE;
        }
       else
@@ -18186,9 +19011,10 @@ it_fsm_post_encode (void)
            {
              if ((inst.instruction & p->mask) == p->pattern)
                {
-                 as_tsktsk (_("IT blocks containing 16-bit Thumb instructions "
-                            "of the following class are deprecated in ARMv8: "
-                            "%s"), p->description);
+                 as_tsktsk (_("IT blocks containing 16-bit Thumb "
+                              "instructions of the following class are "
+                              "performance deprecated in ARMv8-A and "
+                              "ARMv8-R: %s"), p->description);
                  now_it.warn_deprecated = TRUE;
                  break;
                }
@@ -18200,7 +19026,8 @@ it_fsm_post_encode (void)
       if (now_it.block_length > 1)
        {
          as_tsktsk (_("IT blocks containing more than one conditional "
-                    "instruction are deprecated in ARMv8"));
+                    "instruction are performance deprecated in ARMv8-A and "
+                    "ARMv8-R"));
          now_it.warn_deprecated = TRUE;
        }
     }
@@ -18305,7 +19132,9 @@ md_assemble (char *str)
     }
 
   memset (&inst, '\0', sizeof (inst));
-  inst.reloc.type = BFD_RELOC_UNUSED;
+  int r;
+  for (r = 0; r < ARM_IT_MAX_RELOCS; r++)
+    inst.relocs[r].type = BFD_RELOC_UNUSED;
 
   opcode = opcode_lookup (&p);
   if (!opcode)
@@ -18339,7 +19168,10 @@ md_assemble (char *str)
          || (thumb_mode == 1
              && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
        {
-         as_bad (_("selected processor does not support `%s' in Thumb mode"), str);
+         if (opcode->tencode == do_t_swi)
+           as_bad (_("SVC is not permitted on this architecture"));
+         else
+           as_bad (_("selected processor does not support `%s' in Thumb mode"), str);
          return;
        }
       if (inst.cond != COND_ALWAYS && !unified_syntax
@@ -18706,6 +19538,7 @@ static const struct reg_entry reg_names[] =
   REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC),
   REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
   REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
+  REGDEF(mvfr2,5,VFC), REGDEF(MVFR2,5,VFC),
 
   /* Maverick DSP coprocessor registers.  */
   REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
@@ -18883,7 +19716,16 @@ static struct reloc_entry reloc_names[] =
   { "tlscall", BFD_RELOC_ARM_TLS_CALL},
        { "TLSCALL", BFD_RELOC_ARM_TLS_CALL},
   { "tlsdescseq", BFD_RELOC_ARM_TLS_DESCSEQ},
-       { "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ}
+       { "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ},
+  { "gotfuncdesc", BFD_RELOC_ARM_GOTFUNCDESC },
+       { "GOTFUNCDESC", BFD_RELOC_ARM_GOTFUNCDESC },
+  { "gotofffuncdesc", BFD_RELOC_ARM_GOTOFFFUNCDESC },
+       { "GOTOFFFUNCDESC", BFD_RELOC_ARM_GOTOFFFUNCDESC },
+  { "funcdesc", BFD_RELOC_ARM_FUNCDESC },
+       { "FUNCDESC", BFD_RELOC_ARM_FUNCDESC },
+   { "tlsgd_fdpic", BFD_RELOC_ARM_TLS_GD32_FDPIC },      { "TLSGD_FDPIC", BFD_RELOC_ARM_TLS_GD32_FDPIC },
+   { "tlsldm_fdpic", BFD_RELOC_ARM_TLS_LDM32_FDPIC },    { "TLSLDM_FDPIC", BFD_RELOC_ARM_TLS_LDM32_FDPIC },
+   { "gottpoff_fdpic", BFD_RELOC_ARM_TLS_IE32_FDPIC },   { "GOTTPOFF_FDIC", BFD_RELOC_ARM_TLS_IE32_FDPIC },
 };
 #endif
 
@@ -19017,6 +19859,25 @@ static struct asm_barrier_opt barrier_opt_names[] =
 #define C3(mnem, op, nops, ops, ae)    \
   { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
 
+/* Thumb-only variants of TCE and TUE.  */
+#define ToC(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_csuffix, 0x0, 0x##top, 0, THUMB_VARIANT, NULL, \
+    do_##te }
+
+#define ToU(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x0, 0x##top, 0, THUMB_VARIANT, \
+    NULL, do_##te }
+
+/* T_MNEM_xyz enumerator variants of ToC.  */
+#define toC(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_csuffix, 0x0, T_MNEM##top, 0, THUMB_VARIANT, NULL, \
+    do_##te }
+
+/* T_MNEM_xyz enumerator variants of ToU.  */
+#define toU(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x0, T_MNEM##top, 0, THUMB_VARIANT, \
+    NULL, do_##te }
+
 /* Legacy mnemonics that always have conditional infix after the third
    character.  */
 #define CL(mnem, op, nops, ops, ae)    \
@@ -19163,8 +20024,6 @@ static const struct asm_opcode insns[] =
  tC3("ldmia",  8900000, _ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
  tC3("ldmfd",  8900000, _ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
 
- TCE("swi",    f000000, df00,     1, (EXPi),        swi, t_swi),
- TCE("svc",    f000000, df00,     1, (EXPi),        swi, t_swi),
  tCE("b",      a000000, _b,       1, (EXPr),        branch, t_branch),
  TCE("bl",     b000000, f000f800, 1, (EXPr),        bl, t_branch23),
 
@@ -19192,6 +20051,12 @@ static const struct asm_opcode insns[] =
  TCE("rsb",    0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
  TC3("rsbs",   0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
 
+#undef THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_os
+
+ TCE("swi",    f000000, df00,     1, (EXPi),        swi, t_swi),
+ TCE("svc",    f000000, df00,     1, (EXPi),        swi, t_swi),
+
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6
 
@@ -19525,9 +20390,9 @@ static const struct asm_opcode insns[] =
  TCE("usat16", 6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc),         usat16, t_usat16),
 
 #undef  ARM_VARIANT
-#define ARM_VARIANT   & arm_ext_v6k
+#define ARM_VARIANT   & arm_ext_v6k_v6t2
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT & arm_ext_v6k
+#define THUMB_VARIANT & arm_ext_v6k_v6t2
 
  tCE("yield",  320f001, _yield,    0, (), noargs, t_hint),
  tCE("wfe",    320f002, _wfe,      0, (), noargs, t_hint),
@@ -19593,6 +20458,17 @@ 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),
 
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & arm_ext_v3
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
+
+ TUE("csdb",   320f014, f3af8014, 0, (), noargs, t_csdb),
+ TUF("ssbb",   57ff040, f3bf8f40, 0, (), noargs, t_csdb),
+ TUF("pssbb",  57ff044, f3bf8f44, 0, (), noargs, t_csdb),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & arm_ext_v6t2
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6t2_v8m
  TCE("movw",   3000000, f2400000, 2, (RRnpc, HALF),                mov16, t_mov16),
@@ -19704,11 +20580,22 @@ static const struct asm_opcode insns[] =
 #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),
+
+/* Defined in V8 but is in undefined encoding space for earlier
+   architectures.  However earlier architectures are required to treat
+   this instuction as a semihosting trap as well.  Hence while not explicitly
+   defined as such, it is in fact correct to define the instruction for all
+   architectures.  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v1
+#undef  ARM_VARIANT
+#define ARM_VARIANT  & arm_ext_v1
+ TUE("hlt",    1000070, ba80,     1, (oIffffb),        bkpt,   t_hlt),
+
  /* ARMv8 T32 only.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT  NULL
@@ -19779,6 +20666,21 @@ static const struct asm_opcode insns[] =
 #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_neon_ext_dotprod
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & fpu_neon_ext_dotprod
+ NUF (vsdot, d00, 3, (RNDQ, RNDQ, RNDQ_RNSC), neon_dotproduct_s),
+ NUF (vudot, d00, 3, (RNDQ, RNDQ, RNDQ_RNSC), neon_dotproduct_u),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
 #undef  THUMB_VARIANT
@@ -20404,6 +21306,10 @@ static const struct asm_opcode insns[] =
  NCE (vmovx,     eb00a40,       2, (RVS, RVS), neon_movhf),
  NCE (vins,      eb00ac0,       2, (RVS, RVS), neon_movhf),
 
+ /* New backported fma/fms instructions optional in v8.2.  */
+ NCE (vfmal, 810, 3, (RNDQ, RNSD, RNSD_RNSC), neon_vfmal),
+ NCE (vfmsl, 810, 3, (RNDQ, RNSD, RNSD_RNSC), neon_vfmsl),
+
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & fpu_neon_ext_v1
 #undef  ARM_VARIANT
@@ -21023,25 +21929,56 @@ static const struct asm_opcode insns[] =
  cCE("cfmadda32", e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
  cCE("cfmsuba32", e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
 
+ /* ARMv8.5-A instructions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_sb
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_sb
+ TUF("sb", 57ff070, f3bf8f70, 0, (), noargs, noargs),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_predres
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_predres
+ CE("cfprctx", e070f93, 1, (RRnpc), rd),
+ CE("dvprctx", e070fb3, 1, (RRnpc), rd),
+ CE("cpprctx", e070ff3, 1, (RRnpc), rd),
+
  /* 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),
+ ToU("sg",    e97fe97f,        0, (),             noargs),
+ ToC("blxns", 4784,    1, (RRnpc),        t_blx),
+ ToC("bxns",  4704,    1, (RRnpc),        t_bx),
+ ToC("tt",    e840f000,        2, (RRnpc, RRnpc), tt),
+ ToC("ttt",   e840f040,        2, (RRnpc, RRnpc), tt),
+ ToC("tta",   e840f080,        2, (RRnpc, RRnpc), tt),
+ ToC("ttat",  e840f0c0,        2, (RRnpc, RRnpc), 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),
+ ToC("vlldm", ec300a00, 1, (RRnpc), rn),
+ ToC("vlstm", ec200a00, 1, (RRnpc), rn),
+
+ /* Armv8.1-M Mainline instructions.  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8_1m_main
+ toC("bf",     _bf,    2, (EXPs, EXPs),             t_branch_future),
+ toU("bfcsel", _bfcsel,        4, (EXPs, EXPs, EXPs, COND), t_branch_future),
+ toC("bfx",    _bfx,   2, (EXPs, RRnpcsp),          t_branch_future),
+ toC("bfl",    _bfl,   2, (EXPs, EXPs),             t_branch_future),
+ toC("bflx",   _bflx,  2, (EXPs, RRnpcsp),          t_branch_future),
+
+ toU("dls", _dls, 2, (LR, RRnpcsp),     t_loloop),
+ toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
+ toU("le",  _le,  2, (oLR, EXP),        t_loloop),
+
+ ToC("clrm",   e89f0000, 1, (CLRMLST),  t_clrm),
+ ToC("vscclrm",        ec9f0a00, 1, (VRSDVLST), t_vscclrm)
 };
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
@@ -21052,8 +21989,10 @@ static const struct asm_opcode insns[] =
 #undef cCE
 #undef cCL
 #undef C3E
+#undef C3
 #undef CE
 #undef CM
+#undef CL
 #undef UE
 #undef UF
 #undef UT
@@ -21069,6 +22008,10 @@ static const struct asm_opcode insns[] =
 #undef OPS5
 #undef OPS6
 #undef do_0
+#undef ToC
+#undef toC
+#undef ToU
+#undef toU
 \f
 /* MD interface: bits in the object file.  */
 
@@ -21585,21 +22528,6 @@ valueT
 md_section_align (segT  segment ATTRIBUTE_UNUSED,
                  valueT size)
 {
-#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
-  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
-    {
-      /* For a.out, force the section size to be aligned.  If we don't do
-        this, BFD will align it for us, but it will not write out the
-        final bytes of the section.  This may be a bug in BFD, but it is
-        easier to fix it here since that is how the other a.out targets
-        work.  */
-      int align;
-
-      align = bfd_get_section_alignment (stdoutput, segment);
-      size = ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
-    }
-#endif
-
   return size;
 }
 
@@ -21757,7 +22685,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
-   this initialisationis performed first.  */
+   this initialisation is performed first.  */
 
 #ifndef OBJ_ELF
 void
@@ -21771,13 +22699,18 @@ arm_init_frag (fragS * fragP, int max_chars ATTRIBUTE_UNUSED)
 void
 arm_init_frag (fragS * fragP, int max_chars)
 {
-  int frag_thumb_mode;
+  bfd_boolean frag_thumb_mode;
 
   /* If the current ARM vs THUMB mode has not already
      been recorded into this frag then do so now.  */
   if ((fragP->tc_frag_data.thumb_mode & MODE_RECORDED) == 0)
     fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED;
 
+  /* PR 21809: Do not set a mapping state for debug sections
+     - it just confuses other tools.  */
+  if (bfd_get_section_flags (NULL, now_seg) & SEC_DEBUGGING)
+    return;
+
   frag_thumb_mode = fragP->tc_frag_data.thumb_mode ^ MODE_RECORDED;
 
   /* Record a mapping symbol for alignment frags.  We will delete this
@@ -21928,6 +22861,7 @@ add_unwind_adjustsp (offsetT offset)
 }
 
 /* Finish the list of unwind opcodes for this function.         */
+
 static void
 finish_unwind_opcodes (void)
 {
@@ -22008,7 +22942,8 @@ start_unwind_section (const segT text_seg, int idx)
       linkonce = 1;
     }
 
-  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
+  obj_elf_change_section (sec_name, type, 0, flags, 0, group_name,
+                         linkonce, 0);
 
   /* Set the section link for index tables.  */
   if (idx)
@@ -22213,7 +23148,7 @@ tc_arm_regname_to_dw2regnum (char *regname)
   if (reg != FAIL)
     return reg + 256;
 
-  return -1;
+  return FAIL;
 }
 
 #ifdef TE_PE
@@ -22274,11 +23209,17 @@ md_pcrel_from_section (fixS * fixP, segT seg)
       return (base + 4) & ~3;
 
       /* Thumb branches are simply offset by +4.  */
+    case BFD_RELOC_THUMB_PCREL_BRANCH5:
     case BFD_RELOC_THUMB_PCREL_BRANCH7:
     case BFD_RELOC_THUMB_PCREL_BRANCH9:
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH20:
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+    case BFD_RELOC_ARM_THUMB_BF17:
+    case BFD_RELOC_ARM_THUMB_BF19:
+    case BFD_RELOC_ARM_THUMB_BF13:
+    case BFD_RELOC_ARM_THUMB_LOOP12:
       return base + 4;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
@@ -22643,6 +23584,7 @@ thumb32_negate_data_op (offsetT *instruction, unsigned int value)
 }
 
 /* Read a 32-bit thumb instruction from buf.  */
+
 static unsigned long
 get_thumb32_insn (char * buf)
 {
@@ -22653,7 +23595,6 @@ get_thumb32_insn (char * buf)
   return insn;
 }
 
-
 /* We usually want to set the low bit on the address of thumb function
    symbols.  In particular .word foo - . should have the low bit set.
    Generic code tries to fold the difference of two symbols to
@@ -23152,12 +24093,14 @@ md_apply_fix (fixS *  fixP,
              /* 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.  */
+                overlap.  */
              if (((newval >> T2_DATA_OP_SHIFT) & 0xf) == T2_OPCODE_ORR
+                 /* NOTE: MOV uses the ORR opcode in Thumb 2 mode
+                    but with the Rn field [19:16] set to 1111.  */
+                 && (((newval >> 16) & 0xf) == 0xf)
                  && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m)
                  && !((newval >> T2_SBIT_SHIFT) & 0x1)
-                 && value >= 0 && value <=0xffff)
+                 && value >= 0 && value <= 0xffff)
                {
                  /* Toggle bit[25] to change encoding from T2 to T3.  */
                  newval ^= 1 << 25;
@@ -23307,7 +24250,7 @@ md_apply_fix (fixS *    fixP,
       /* We are going to store value (shifted right by two) in the
         instruction, in a 24 bit, signed field.  Bits 26 through 32 either
         all clear or all set and bit 0 must be clear.  For B/BL bit 1 must
-        also be be clear.  */
+        also be clear.  */
       if (value & temp)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("misaligned branch destination"));
@@ -23521,6 +24464,21 @@ md_apply_fix (fixS *   fixP,
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       break;
 
+      /* Same handling as above, but with the arm_fdpic guard.  */
+    case BFD_RELOC_ARM_TLS_GD32_FDPIC:
+    case BFD_RELOC_ARM_TLS_IE32_FDPIC:
+    case BFD_RELOC_ARM_TLS_LDM32_FDPIC:
+      if (arm_fdpic)
+       {
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
+       }
+      else
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("Relocation supported only in FDPIC mode"));
+       }
+      break;
+
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
       break;
@@ -23537,6 +24495,22 @@ md_apply_fix (fixS *   fixP,
       if (fixP->fx_done || !seg->use_rela_p)
        md_number_to_chars (buf, fixP->fx_offset, 4);
       break;
+
+      /* Relocations for FDPIC.  */
+    case BFD_RELOC_ARM_GOTFUNCDESC:
+    case BFD_RELOC_ARM_GOTOFFFUNCDESC:
+    case BFD_RELOC_ARM_FUNCDESC:
+      if (arm_fdpic)
+       {
+         if (fixP->fx_done || !seg->use_rela_p)
+           md_number_to_chars (buf, 0, 4);
+       }
+      else
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("Relocation supported only in FDPIC mode"));
+      }
+      break;
 #endif
 
     case BFD_RELOC_RVA:
@@ -23965,7 +24939,7 @@ md_apply_fix (fixS *    fixP,
        {
         bfd_vma insn;
         bfd_vma encoded_addend;
-        bfd_vma addend_abs = abs (value);
+        bfd_vma addend_abs = llabs (value);
 
         /* Check that the absolute value of the addend can be
            expressed as an 8-bit constant plus a rotation.  */
@@ -24006,7 +24980,7 @@ md_apply_fix (fixS *    fixP,
       if (!seg->use_rela_p)
        {
          bfd_vma insn;
-         bfd_vma addend_abs = abs (value);
+         bfd_vma addend_abs = llabs (value);
 
          /* Check that the absolute value of the addend can be
             encoded in 12 bits.  */
@@ -24045,7 +25019,7 @@ md_apply_fix (fixS *    fixP,
       if (!seg->use_rela_p)
        {
          bfd_vma insn;
-         bfd_vma addend_abs = abs (value);
+         bfd_vma addend_abs = llabs (value);
 
          /* Check that the absolute value of the addend can be
             encoded in 8 bits.  */
@@ -24085,7 +25059,7 @@ md_apply_fix (fixS *    fixP,
       if (!seg->use_rela_p)
        {
          bfd_vma insn;
-         bfd_vma addend_abs = abs (value);
+         bfd_vma addend_abs = llabs (value);
 
          /* Check that the absolute value of the addend is a multiple of
             four and, when divided by four, fits in 8 bits.  */
@@ -24119,20 +25093,209 @@ md_apply_fix (fixS * fixP,
        }
       break;
 
-    case BFD_RELOC_ARM_V4BX:
-      /* This will need to go in the object file.  */
-      fixP->fx_done = 0;
+    case BFD_RELOC_THUMB_PCREL_BRANCH5:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 5 bits wide.  */
+         fixP->fx_done = 0;
+       }
+      if (v8_1_branch_value_check (value, 5, FALSE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         addressT boff = value >> 1;
+
+         newval  = md_chars_to_number (buf, THUMB_SIZE);
+         newval |= (boff << 7);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
       break;
 
-    case BFD_RELOC_UNUSED:
-    default:
-      as_bad_where (fixP->fx_file, fixP->fx_line,
-                   _("bad relocation fixup type (%d)"), fixP->fx_r_type);
-    }
-}
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         fixP->fx_done = 0;
+       }
+      if ((value & ~0x7f) && ((value & ~0x3f) != ~0x3f))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-/* Translate internal representation of relocation info to BFD target
-   format.  */
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         newval  = md_chars_to_number (buf, THUMB_SIZE);
+
+         addressT boff = ((newval & 0x0780) >> 7) << 1;
+         addressT diff = value - boff;
+
+         if (diff == 4)
+           {
+             newval |= 1 << 1; /* T bit.  */
+           }
+         else if (diff != 2)
+           {
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           _("out of range label-relative fixup value"));
+           }
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_THUMB_BF17:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 17 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      if (v8_1_branch_value_check (value, 17, TRUE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT immA, immB, immC;
+
+         immA = (value & 0x0001f000) >> 12;
+         immB = (value & 0x00000ffc) >> 2;
+         immC = (value & 0x00000002) >> 1;
+
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= immA;
+         newval2 |= (immC << 11) | (immB << 1);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_THUMB_BF19:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 19 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      if (v8_1_branch_value_check (value, 19, TRUE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT immA, immB, immC;
+
+         immA = (value & 0x0007f000) >> 12;
+         immB = (value & 0x00000ffc) >> 2;
+         immC = (value & 0x00000002) >> 1;
+
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= immA;
+         newval2 |= (immC << 11) | (immB << 1);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_THUMB_BF13:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 13 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      if (v8_1_branch_value_check (value, 13, TRUE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT immA, immB, immC;
+
+         immA = (value & 0x00001000) >> 12;
+         immB = (value & 0x00000ffc) >> 2;
+         immC = (value & 0x00000002) >> 1;
+
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= immA;
+         newval2 |= (immC << 11) | (immB << 1);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_THUMB_LOOP12:
+      if (fixP->fx_addsy
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+         && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+       {
+         /* Force a relocation for a branch 12 bits wide.  */
+         fixP->fx_done = 0;
+       }
+
+      bfd_vma insn = get_thumb32_insn (buf);
+      /* le lr, <label> or le <label> */
+      if (((insn & 0xffffffff) == 0xf00fc001)
+         || ((insn & 0xffffffff) == 0xf02fc001))
+       value = -value;
+
+      if (v8_1_branch_value_check (value, 12, FALSE) == FAIL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     BAD_BRANCH_OFF);
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         addressT imml, immh;
+
+         immh = (value & 0x00000ffc) >> 2;
+         imml = (value & 0x00000002) >> 1;
+
+         newval  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval |= (imml << 11) | (immh << 1);
+         md_number_to_chars (buf + THUMB_SIZE, newval, THUMB_SIZE);
+       }
+      break;
+
+    case BFD_RELOC_ARM_V4BX:
+      /* This will need to go in the object file.  */
+      fixP->fx_done = 0;
+      break;
+
+    case BFD_RELOC_UNUSED:
+    default:
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+                   _("bad relocation fixup type (%d)"), fixP->fx_r_type);
+    }
+}
+
+/* Translate internal representation of relocation info to BFD target
+   format.  */
 
 arelent *
 tc_gen_reloc (asection *section, fixS *fixp)
@@ -24298,14 +25461,23 @@ tc_gen_reloc (asection *section, fixS *fixp)
     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:
+    case BFD_RELOC_ARM_GOTFUNCDESC:
+    case BFD_RELOC_ARM_GOTOFFFUNCDESC:
+    case BFD_RELOC_ARM_FUNCDESC:
+    case BFD_RELOC_ARM_THUMB_BF17:
+    case BFD_RELOC_ARM_THUMB_BF19:
+    case BFD_RELOC_ARM_THUMB_BF13:
       code = fixp->fx_r_type;
       break;
 
     case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
+    case BFD_RELOC_ARM_TLS_GD32_FDPIC:
     case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_IE32:
+    case BFD_RELOC_ARM_TLS_IE32_FDPIC:
     case BFD_RELOC_ARM_TLS_LDM32:
+    case BFD_RELOC_ARM_TLS_LDM32_FDPIC:
       /* BFD will include the symbol's address in the addend.
         But we don't want that, so subtract it out again here.  */
       if (!S_IS_COMMON (fixp->fx_addsy))
@@ -24324,6 +25496,14 @@ tc_gen_reloc (asection *section, fixS *fixp)
                    _("ADRL used for a symbol not defined in the same file"));
       return NULL;
 
+    case BFD_RELOC_THUMB_PCREL_BRANCH5:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+    case BFD_RELOC_ARM_THUMB_LOOP12:
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   _("%s used for a symbol not defined in the same file"),
+                   bfd_get_reloc_code_name (fixp->fx_r_type));
+      return NULL;
+
     case BFD_RELOC_ARM_OFFSET_IMM:
       if (section->use_rela_p)
        {
@@ -24571,9 +25751,12 @@ arm_fix_adjustable (fixS * fixP)
       || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
       || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32_FDPIC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32_FDPIC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32_FDPIC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GOTDESC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_CALL
@@ -24627,10 +25810,20 @@ elf32_arm_target_format (void)
          ? "elf32-bigarm-nacl"
          : "elf32-littlearm-nacl");
 #else
-  if (target_big_endian)
-    return "elf32-bigarm";
+  if (arm_fdpic)
+    {
+      if (target_big_endian)
+       return "elf32-bigarm-fdpic";
+      else
+       return "elf32-littlearm-fdpic";
+    }
   else
-    return "elf32-littlearm";
+    {
+      if (target_big_endian)
+       return "elf32-bigarm";
+      else
+       return "elf32-littlearm";
+    }
 #endif
 }
 
@@ -24892,60 +26085,70 @@ md_begin (void)
       if (mcpu_cpu_opt || march_cpu_opt)
        as_bad (_("use of old and new-style options to set CPU type"));
 
-      mcpu_cpu_opt = legacy_cpu;
+      selected_arch = *legacy_cpu;
     }
-  else if (!mcpu_cpu_opt)
-    mcpu_cpu_opt = march_cpu_opt;
+  else if (mcpu_cpu_opt)
+    {
+      selected_arch = *mcpu_cpu_opt;
+      selected_ext = *mcpu_ext_opt;
+    }
+  else if (march_cpu_opt)
+    {
+      selected_arch = *march_cpu_opt;
+      selected_ext = *march_ext_opt;
+    }
+  ARM_MERGE_FEATURE_SETS (selected_cpu, selected_arch, selected_ext);
 
   if (legacy_fpu)
     {
       if (mfpu_opt)
        as_bad (_("use of old and new-style options to set FPU type"));
 
-      mfpu_opt = legacy_fpu;
+      selected_fpu = *legacy_fpu;
     }
-  else if (!mfpu_opt)
+  else if (mfpu_opt)
+    selected_fpu = *mfpu_opt;
+  else
     {
 #if !(defined (EABI_DEFAULT) || defined (TE_LINUX) \
        || defined (TE_NetBSD) || defined (TE_VXWORKS))
       /* Some environments specify a default FPU.  If they don't, infer it
         from the processor.  */
       if (mcpu_fpu_opt)
-       mfpu_opt = mcpu_fpu_opt;
-      else
-       mfpu_opt = march_fpu_opt;
+       selected_fpu = *mcpu_fpu_opt;
+      else if (march_fpu_opt)
+       selected_fpu = *march_fpu_opt;
 #else
-      mfpu_opt = &fpu_default;
+      selected_fpu = fpu_default;
 #endif
     }
 
-  if (!mfpu_opt)
+  if (ARM_FEATURE_ZERO (selected_fpu))
     {
-      if (mcpu_cpu_opt != NULL)
-       mfpu_opt = &fpu_default;
-      else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
-       mfpu_opt = &fpu_arch_vfp_v2;
+      if (!no_cpu_selected ())
+       selected_fpu = fpu_default;
       else
-       mfpu_opt = &fpu_arch_fpa;
+       selected_fpu = fpu_arch_fpa;
     }
 
 #ifdef CPU_DEFAULT
-  if (!mcpu_cpu_opt)
+  if (ARM_FEATURE_ZERO (selected_arch))
     {
-      mcpu_cpu_opt = &cpu_default;
-      selected_cpu = cpu_default;
+      selected_arch = cpu_default;
+      selected_cpu = selected_arch;
     }
-  else if (no_cpu_selected ())
-    selected_cpu = cpu_default;
+  ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
 #else
-  if (mcpu_cpu_opt)
-    selected_cpu = *mcpu_cpu_opt;
+  /*  Autodection of feature mode: allow all features in cpu_variant but leave
+      selected_cpu unset.  It will be set in aeabi_set_public_attributes ()
+      after all instruction have been processed and we can decide what CPU
+      should be selected.  */
+  if (ARM_FEATURE_ZERO (selected_arch))
+    ARM_MERGE_FEATURE_SETS (cpu_variant, arm_arch_any, selected_fpu);
   else
-    mcpu_cpu_opt = &arm_arch_any;
+    ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
 #endif
 
-  ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
-
   autoselect_thumb_from_cpu_variant ();
 
   arm_arch_used = thumb_arch_used = arm_arch_none;
@@ -25140,6 +26343,7 @@ const char * md_shortopts = "m:k";
 #endif
 #endif
 #define OPTION_FIX_V4BX (OPTION_MD_BASE + 2)
+#define OPTION_FDPIC (OPTION_MD_BASE + 3)
 
 struct option md_longopts[] =
 {
@@ -25150,19 +26354,21 @@ struct option md_longopts[] =
   {"EL", no_argument, NULL, OPTION_EL},
 #endif
   {"fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX},
+#ifdef OBJ_ELF
+  {"fdpic", no_argument, NULL, OPTION_FDPIC},
+#endif
   {NULL, no_argument, NULL, 0}
 };
 
-
 size_t md_longopts_size = sizeof (md_longopts);
 
 struct arm_option_table
 {
-  const char *option;          /* Option name to match.  */
-  const char *help;            /* Help information.  */
-  int  *var;           /* Variable to change.  */
-  int  value;          /* What to change it to.  */
-  const char *deprecated;      /* If non-null, print this message.  */
+  const char *  option;                /* Option name to match.  */
+  const char *  help;          /* Help information.  */
+  int *         var;           /* Variable to change.  */
+  int          value;          /* What to change it to.  */
+  const char *  deprecated;    /* If non-null, print this message.  */
 };
 
 struct arm_option_table arm_opts[] =
@@ -25195,10 +26401,10 @@ struct arm_option_table arm_opts[] =
 
 struct arm_legacy_option_table
 {
-  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 char *deprecated;                      /* If non-null, print this message.  */
+  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 char *              deprecated;                /* If non-null, print this message.  */
 };
 
 const struct arm_legacy_option_table arm_legacy_opts[] =
@@ -25305,10 +26511,10 @@ const struct arm_legacy_option_table arm_legacy_opts[] =
   {"marmv5e",   &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
 
   /* Floating point variants -- don't add any more to this list either.         */
-  {"mfpe-old", &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
-  {"mfpa10",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
-  {"mfpa11",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
-  {"mno-fpu",  &legacy_fpu, ARM_ARCH_NONE,
+  {"mfpe-old",   &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
+  {"mfpa10",     &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
+  {"mfpa11",     &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
+  {"mno-fpu",    &legacy_fpu, ARM_ARCH_NONE,
    N_("use either -mfpu=softfpa or -mfpu=softvfp")},
 
   {NULL, NULL, ARM_ARCH_NONE, NULL}
@@ -25316,284 +26522,726 @@ const struct arm_legacy_option_table arm_legacy_opts[] =
 
 struct arm_cpu_option_table
 {
-  const char *name;
-  size_t name_len;
-  const arm_feature_set        value;
+  const char *           name;
+  size_t                 name_len;
+  const arm_feature_set         value;
+  const arm_feature_set         ext;
   /* For some CPUs we assume an FPU unless the user explicitly sets
      -mfpu=... */
-  const arm_feature_set        default_fpu;
+  const arm_feature_set         default_fpu;
   /* The canonical name of the CPU, or NULL to use NAME converted to upper
      case.  */
-  const char *canonical_name;
+  const char *           canonical_name;
 };
 
 /* This list should, at a minimum, contain all the cpu names
    recognized by GCC.  */
-#define ARM_CPU_OPT(N, V, DF, CN) { N, sizeof (N) - 1, V, DF, CN }
+#define ARM_CPU_OPT(N, CN, V, E, DF) { N, sizeof (N) - 1, V, E, DF, CN }
+
 static const struct arm_cpu_option_table arm_cpus[] =
 {
-  ARM_CPU_OPT ("all",          ARM_ANY,         FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm1",         ARM_ARCH_V1,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm2",         ARM_ARCH_V2,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm250",       ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm3",         ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm6",         ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm60",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm600",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm610",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm620",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7",         ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7m",                ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7d",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7dm",       ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7di",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7dmi",      ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm70",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm700",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm700i",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm710",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm710t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm720",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm720t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm740t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm710c",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7100",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7500",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7500fe",    ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7t",                ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7tdmi",     ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm7tdmi-s",   ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm8",         ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm810",       ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("strongarm",    ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("strongarm1",   ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("strongarm110", ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("strongarm1100",        ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("strongarm1110",        ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm9",         ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm920",       ARM_ARCH_V4T,    FPU_ARCH_FPA,    "ARM920T"),
-  ARM_CPU_OPT ("arm920t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm922t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm940t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("arm9tdmi",     ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("fa526",                ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
-  ARM_CPU_OPT ("fa626",                ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("all",            NULL,                ARM_ANY,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm1",           NULL,                ARM_ARCH_V1,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm2",           NULL,                ARM_ARCH_V2,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm250",         NULL,                ARM_ARCH_V2S,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm3",           NULL,                ARM_ARCH_V2S,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm6",           NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm60",                  NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm600",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm610",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm620",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7",           NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7m",                  NULL,                ARM_ARCH_V3M,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7d",                  NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7dm",         NULL,                ARM_ARCH_V3M,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7di",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7dmi",        NULL,                ARM_ARCH_V3M,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm70",                  NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm700",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm700i",        NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm710",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm710t",        NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm720",         NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm720t",        NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm740t",        NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm710c",        NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7100",        NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7500",        NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7500fe",      NULL,                ARM_ARCH_V3,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7t",                  NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7tdmi",       NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm7tdmi-s",     NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm8",           NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm810",         NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("strongarm",      NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("strongarm1",     NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("strongarm110",   NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("strongarm1100",          NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("strongarm1110",          NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm9",           NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm920",         "ARM920T",           ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm920t",        NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm922t",        NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm940t",        NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("arm9tdmi",       NULL,                ARM_ARCH_V4T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("fa526",                  NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+  ARM_CPU_OPT ("fa626",                  NULL,                ARM_ARCH_V4,
+              ARM_ARCH_NONE,
+              FPU_ARCH_FPA),
+
   /* For V5 or later processors we default to using VFP; but the user
      should really set the FPU type explicitly.         */
-  ARM_CPU_OPT ("arm9e-r0",     ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm9e",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm926ej",     ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"),
-  ARM_CPU_OPT ("arm926ejs",    ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"),
-  ARM_CPU_OPT ("arm926ej-s",   ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm946e-r0",   ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm946e",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM946E-S"),
-  ARM_CPU_OPT ("arm946e-s",    ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm966e-r0",   ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm966e",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM966E-S"),
-  ARM_CPU_OPT ("arm966e-s",    ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm968e-s",    ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm10t",       ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL),
-  ARM_CPU_OPT ("arm10tdmi",    ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL),
-  ARM_CPU_OPT ("arm10e",       ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm1020",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM1020E"),
-  ARM_CPU_OPT ("arm1020t",     ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL),
-  ARM_CPU_OPT ("arm1020e",     ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm1022e",     ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm1026ejs",   ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2,
-                                                                "ARM1026EJ-S"),
-  ARM_CPU_OPT ("arm1026ej-s",  ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("fa606te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("fa616te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("fa626te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("fmp626",       ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("fa726te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("arm1136js",    ARM_ARCH_V6,     FPU_NONE,        "ARM1136J-S"),
-  ARM_CPU_OPT ("arm1136j-s",   ARM_ARCH_V6,     FPU_NONE,        NULL),
-  ARM_CPU_OPT ("arm1136jfs",   ARM_ARCH_V6,     FPU_ARCH_VFP_V2,
-                                                                "ARM1136JF-S"),
-  ARM_CPU_OPT ("arm1136jf-s",  ARM_ARCH_V6,     FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("mpcore",       ARM_ARCH_V6K,    FPU_ARCH_VFP_V2, "MPCore"),
-  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_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,
-                                                                 "Cortex-A7"),
-  ARM_CPU_OPT ("cortex-a8",    ARM_ARCH_V7A_SEC,
-                                                ARM_FEATURE_COPROC (FPU_VFP_V3
-                                                       | FPU_NEON_EXT_V1),
-                                                                 "Cortex-A8"),
-  ARM_CPU_OPT ("cortex-a9",    ARM_ARCH_V7A_MP_SEC,
-                                                ARM_FEATURE_COPROC (FPU_VFP_V3
-                                                       | FPU_NEON_EXT_V1),
-                                                                 "Cortex-A9"),
-  ARM_CPU_OPT ("cortex-a12",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
-                                                                 "Cortex-A12"),
-  ARM_CPU_OPT ("cortex-a15",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
-                                                                 "Cortex-A15"),
-  ARM_CPU_OPT ("cortex-a17",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
-                                                                 "Cortex-A17"),
-  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"),
-  ARM_CPU_OPT ("cortex-a57",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
-                                                                 "Cortex-A57"),
-  ARM_CPU_OPT ("cortex-a72",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
-                                                                 "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-r5",    ARM_ARCH_V7R_IDIV,
-                                                FPU_NONE,        "Cortex-R5"),
-  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 ("exynos-m1",    ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
-                                                                 "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"),
-
+  ARM_CPU_OPT ("arm9e-r0",       NULL,                ARM_ARCH_V5TExP,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm9e",                  NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm926ej",       "ARM926EJ-S",        ARM_ARCH_V5TEJ,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm926ejs",      "ARM926EJ-S",        ARM_ARCH_V5TEJ,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm926ej-s",     NULL,                ARM_ARCH_V5TEJ,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm946e-r0",     NULL,                ARM_ARCH_V5TExP,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm946e",        "ARM946E-S",         ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm946e-s",      NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm966e-r0",     NULL,                ARM_ARCH_V5TExP,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm966e",        "ARM966E-S",         ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm966e-s",      NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm968e-s",      NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm10t",         NULL,                ARM_ARCH_V5T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V1),
+  ARM_CPU_OPT ("arm10tdmi",      NULL,                ARM_ARCH_V5T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V1),
+  ARM_CPU_OPT ("arm10e",         NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1020",        "ARM1020E",          ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1020t",       NULL,                ARM_ARCH_V5T,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V1),
+  ARM_CPU_OPT ("arm1020e",       NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1022e",       NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1026ejs",     "ARM1026EJ-S",       ARM_ARCH_V5TEJ,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1026ej-s",    NULL,                ARM_ARCH_V5TEJ,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("fa606te",        NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("fa616te",        NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("fa626te",        NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("fmp626",         NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("fa726te",        NULL,                ARM_ARCH_V5TE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1136js",      "ARM1136J-S",        ARM_ARCH_V6,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("arm1136j-s",     NULL,                ARM_ARCH_V6,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("arm1136jfs",     "ARM1136JF-S",       ARM_ARCH_V6,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1136jf-s",    NULL,                ARM_ARCH_V6,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("mpcore",         "MPCore",            ARM_ARCH_V6K,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("mpcorenovfp",    "MPCore",            ARM_ARCH_V6K,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("arm1156t2-s",    NULL,                ARM_ARCH_V6T2,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("arm1156t2f-s",   NULL,                ARM_ARCH_V6T2,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("arm1176jz-s",    NULL,                ARM_ARCH_V6KZ,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("arm1176jzf-s",   NULL,                ARM_ARCH_V6KZ,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("cortex-a5",      "Cortex-A5",         ARM_ARCH_V7A,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_MP | ARM_EXT_SEC),
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-a7",      "Cortex-A7",         ARM_ARCH_V7VE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_NEON_VFP_V4),
+  ARM_CPU_OPT ("cortex-a8",      "Cortex-A8",         ARM_ARCH_V7A,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
+              ARM_FEATURE_COPROC (FPU_VFP_V3 | FPU_NEON_EXT_V1)),
+  ARM_CPU_OPT ("cortex-a9",      "Cortex-A9",         ARM_ARCH_V7A,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_MP | ARM_EXT_SEC),
+              ARM_FEATURE_COPROC (FPU_VFP_V3 | FPU_NEON_EXT_V1)),
+  ARM_CPU_OPT ("cortex-a12",     "Cortex-A12",        ARM_ARCH_V7VE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_NEON_VFP_V4),
+  ARM_CPU_OPT ("cortex-a15",     "Cortex-A15",        ARM_ARCH_V7VE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_NEON_VFP_V4),
+  ARM_CPU_OPT ("cortex-a17",     "Cortex-A17",        ARM_ARCH_V7VE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_NEON_VFP_V4),
+  ARM_CPU_OPT ("cortex-a32",     "Cortex-A32",        ARM_ARCH_V8A,
+              ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-a35",     "Cortex-A35",        ARM_ARCH_V8A,
+              ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-a53",     "Cortex-A53",        ARM_ARCH_V8A,
+              ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-a55",    "Cortex-A55",         ARM_ARCH_V8_2A,
+              ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+  ARM_CPU_OPT ("cortex-a57",     "Cortex-A57",        ARM_ARCH_V8A,
+              ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-a72",     "Cortex-A72",        ARM_ARCH_V8A,
+             ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+             FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-a73",     "Cortex-A73",        ARM_ARCH_V8A,
+             ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+             FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-a75",    "Cortex-A75",         ARM_ARCH_V8_2A,
+              ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+  ARM_CPU_OPT ("cortex-a76",    "Cortex-A76",         ARM_ARCH_V8_2A,
+              ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+  ARM_CPU_OPT ("ares",    "Ares",             ARM_ARCH_V8_2A,
+              ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+  ARM_CPU_OPT ("cortex-r4",      "Cortex-R4",         ARM_ARCH_V7R,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-r4f",     "Cortex-R4F",        ARM_ARCH_V7R,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V3D16),
+  ARM_CPU_OPT ("cortex-r5",      "Cortex-R5",         ARM_ARCH_V7R,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV),
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-r7",      "Cortex-R7",         ARM_ARCH_V7R,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV),
+              FPU_ARCH_VFP_V3D16),
+  ARM_CPU_OPT ("cortex-r8",      "Cortex-R8",         ARM_ARCH_V7R,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV),
+              FPU_ARCH_VFP_V3D16),
+  ARM_CPU_OPT ("cortex-r52",     "Cortex-R52",        ARM_ARCH_V8R,
+             ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+             FPU_ARCH_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("cortex-m33",     "Cortex-M33",        ARM_ARCH_V8M_MAIN,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m23",     "Cortex-M23",        ARM_ARCH_V8M_BASE,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m7",      "Cortex-M7",         ARM_ARCH_V7EM,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m4",      "Cortex-M4",         ARM_ARCH_V7EM,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m3",      "Cortex-M3",         ARM_ARCH_V7M,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m1",      "Cortex-M1",         ARM_ARCH_V6SM,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m0",      "Cortex-M0",         ARM_ARCH_V6SM,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("cortex-m0plus",          "Cortex-M0+",        ARM_ARCH_V6SM,
+              ARM_ARCH_NONE,
+              FPU_NONE),
+  ARM_CPU_OPT ("exynos-m1",      "Samsung Exynos M1", ARM_ARCH_V8A,
+              ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("neoverse-n1",    "Neoverse N1",               ARM_ARCH_V8_2A,
+              ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
   /* ??? XSCALE is really an architecture.  */
-  ARM_CPU_OPT ("xscale",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("xscale",         NULL,                ARM_ARCH_XSCALE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+
   /* ??? iwmmxt is not a processor.  */
-  ARM_CPU_OPT ("iwmmxt",       ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("iwmmxt2",      ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL),
-  ARM_CPU_OPT ("i80200",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
-  /* Maverick */
-  ARM_CPU_OPT ("ep9312",       ARM_FEATURE_LOW (ARM_AEXT_V4T, ARM_CEXT_MAVERICK),
-                                                FPU_ARCH_MAVERICK, "ARM920T"),
+  ARM_CPU_OPT ("iwmmxt",         NULL,                ARM_ARCH_IWMMXT,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("iwmmxt2",        NULL,                ARM_ARCH_IWMMXT2,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+  ARM_CPU_OPT ("i80200",         NULL,                ARM_ARCH_XSCALE,
+              ARM_ARCH_NONE,
+              FPU_ARCH_VFP_V2),
+
+  /* Maverick.  */
+  ARM_CPU_OPT ("ep9312",         "ARM920T",
+              ARM_FEATURE_LOW (ARM_AEXT_V4T, ARM_CEXT_MAVERICK),
+              ARM_ARCH_NONE, FPU_ARCH_MAVERICK),
+
   /* Marvell processors.  */
-  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),
-  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"),
-  ARM_CPU_OPT ("xgene2",        ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
-                                                                 "APM X-Gene 2"),
+  ARM_CPU_OPT ("marvell-pj4",    NULL,                ARM_ARCH_V7A,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_MP | ARM_EXT_SEC),
+              FPU_ARCH_VFP_V3D16),
+  ARM_CPU_OPT ("marvell-whitney", NULL,                       ARM_ARCH_V7A,
+              ARM_FEATURE_CORE_LOW (ARM_EXT_MP | ARM_EXT_SEC),
+              FPU_ARCH_NEON_VFP_V4),
 
-  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
+  /* APM X-Gene family.  */
+  ARM_CPU_OPT ("xgene1",         "APM X-Gene 1",      ARM_ARCH_V8A,
+              ARM_ARCH_NONE,
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+  ARM_CPU_OPT ("xgene2",         "APM X-Gene 2",      ARM_ARCH_V8A,
+              ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+              FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
+
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
 };
 #undef ARM_CPU_OPT
 
+struct arm_ext_table
+{
+  const char *           name;
+  size_t                 name_len;
+  const arm_feature_set          merge;
+  const arm_feature_set          clear;
+};
+
 struct arm_arch_option_table
 {
-  const char *name;
-  size_t name_len;
-  const arm_feature_set        value;
-  const arm_feature_set        default_fpu;
+  const char *                 name;
+  size_t                       name_len;
+  const arm_feature_set                value;
+  const arm_feature_set                default_fpu;
+  const struct arm_ext_table * ext_table;
+};
+
+/* Used to add support for +E and +noE extension.  */
+#define ARM_EXT(E, M, C) { E, sizeof (E) - 1, M, C }
+/* Used to add support for a +E extension.  */
+#define ARM_ADD(E, M) { E, sizeof(E) - 1, M, ARM_ARCH_NONE }
+/* Used to add support for a +noE extension.  */
+#define ARM_REMOVE(E, C) { E, sizeof(E) -1, ARM_ARCH_NONE, C }
+
+#define ALL_FP ARM_FEATURE (0, ARM_EXT2_FP16_INST | ARM_EXT2_FP16_FML, \
+                           ~0 & ~FPU_ENDIAN_PURE)
+
+static const struct arm_ext_table armv5te_ext_table[] =
+{
+  ARM_EXT ("fp", FPU_ARCH_VFP_V2, ALL_FP),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7_ext_table[] =
+{
+  ARM_EXT ("fp", FPU_ARCH_VFP_V3D16, ALL_FP),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7ve_ext_table[] =
+{
+  ARM_EXT ("fp", FPU_ARCH_VFP_V4D16, ALL_FP),
+  ARM_ADD ("vfpv3-d16", FPU_ARCH_VFP_V3D16),
+  ARM_ADD ("vfpv3", FPU_ARCH_VFP_V3),
+  ARM_ADD ("vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16),
+  ARM_ADD ("vfpv3-fp16", FPU_ARCH_VFP_V3_FP16),
+  ARM_ADD ("vfpv4-d16", FPU_ARCH_VFP_V4D16),  /* Alias for +fp.  */
+  ARM_ADD ("vfpv4", FPU_ARCH_VFP_V4),
+
+  ARM_EXT ("simd", FPU_ARCH_NEON_VFP_V4,
+          ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_NEON_EXT_FMA)),
+
+  /* Aliases for +simd.  */
+  ARM_ADD ("neon-vfpv4", FPU_ARCH_NEON_VFP_V4),
+
+  ARM_ADD ("neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+  ARM_ADD ("neon-vfpv3", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+  ARM_ADD ("neon-fp16", FPU_ARCH_NEON_FP16),
+
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7a_ext_table[] =
+{
+  ARM_EXT ("fp", FPU_ARCH_VFP_V3D16, ALL_FP),
+  ARM_ADD ("vfpv3-d16", FPU_ARCH_VFP_V3D16), /* Alias for +fp.  */
+  ARM_ADD ("vfpv3", FPU_ARCH_VFP_V3),
+  ARM_ADD ("vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16),
+  ARM_ADD ("vfpv3-fp16", FPU_ARCH_VFP_V3_FP16),
+  ARM_ADD ("vfpv4-d16", FPU_ARCH_VFP_V4D16),
+  ARM_ADD ("vfpv4", FPU_ARCH_VFP_V4),
+
+  ARM_EXT ("simd", FPU_ARCH_VFP_V3_PLUS_NEON_V1,
+          ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_NEON_EXT_FMA)),
+
+  /* Aliases for +simd.  */
+  ARM_ADD ("neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+  ARM_ADD ("neon-vfpv3", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+
+  ARM_ADD ("neon-fp16", FPU_ARCH_NEON_FP16),
+  ARM_ADD ("neon-vfpv4", FPU_ARCH_NEON_VFP_V4),
+
+  ARM_ADD ("mp", ARM_FEATURE_CORE_LOW (ARM_EXT_MP)),
+  ARM_ADD ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7r_ext_table[] =
+{
+  ARM_ADD ("fp.sp", FPU_ARCH_VFP_V3xD),
+  ARM_ADD ("vfpv3xd", FPU_ARCH_VFP_V3xD), /* Alias for +fp.sp.  */
+  ARM_EXT ("fp", FPU_ARCH_VFP_V3D16, ALL_FP),
+  ARM_ADD ("vfpv3-d16", FPU_ARCH_VFP_V3D16), /* Alias for +fp.  */
+  ARM_ADD ("vfpv3xd-fp16", FPU_ARCH_VFP_V3xD_FP16),
+  ARM_ADD ("vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16),
+  ARM_EXT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
+          ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7em_ext_table[] =
+{
+  ARM_EXT ("fp", FPU_ARCH_VFP_V4_SP_D16, ALL_FP),
+  /* Alias for +fp, used to be known as fpv4-sp-d16.  */
+  ARM_ADD ("vfpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16),
+  ARM_ADD ("fpv5", FPU_ARCH_VFP_V5_SP_D16),
+  ARM_ADD ("fp.dp", FPU_ARCH_VFP_V5D16),
+  ARM_ADD ("fpv5-d16", FPU_ARCH_VFP_V5D16),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8a_ext_table[] =
+{
+  ARM_ADD ("crc", ARCH_CRC_ARMV8),
+  ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8),
+  ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+          ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+  /* Armv8-a does not allow an FP implementation without SIMD, so the user
+     should use the +simd option to turn on FP.  */
+  ARM_REMOVE ("fp", ALL_FP),
+  ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+  ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+
+static const struct arm_ext_table armv81a_ext_table[] =
+{
+  ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8_1),
+  ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1,
+          ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+  /* Armv8-a does not allow an FP implementation without SIMD, so the user
+     should use the +simd option to turn on FP.  */
+  ARM_REMOVE ("fp", ALL_FP),
+  ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+  ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv82a_ext_table[] =
+{
+  ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8_1),
+  ARM_ADD ("fp16", FPU_ARCH_NEON_VFP_ARMV8_2_FP16),
+  ARM_ADD ("fp16fml", FPU_ARCH_NEON_VFP_ARMV8_2_FP16FML),
+  ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1,
+          ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+  ARM_ADD ("dotprod", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8),
+
+  /* Armv8-a does not allow an FP implementation without SIMD, so the user
+     should use the +simd option to turn on FP.  */
+  ARM_REMOVE ("fp", ALL_FP),
+  ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+  ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv84a_ext_table[] =
+{
+  ARM_ADD ("simd", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8),
+  ARM_ADD ("fp16", FPU_ARCH_NEON_VFP_ARMV8_4_FP16FML),
+  ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_4,
+          ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+  /* Armv8-a does not allow an FP implementation without SIMD, so the user
+     should use the +simd option to turn on FP.  */
+  ARM_REMOVE ("fp", ALL_FP),
+  ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+  ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv85a_ext_table[] =
+{
+  ARM_ADD ("simd", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8),
+  ARM_ADD ("fp16", FPU_ARCH_NEON_VFP_ARMV8_4_FP16FML),
+  ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_4,
+          ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+  /* Armv8-a does not allow an FP implementation without SIMD, so the user
+     should use the +simd option to turn on FP.  */
+  ARM_REMOVE ("fp", ALL_FP),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8m_main_ext_table[] =
+{
+  ARM_EXT ("dsp", ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+                 ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP)),
+  ARM_EXT ("fp", FPU_ARCH_VFP_V5_SP_D16, ALL_FP),
+  ARM_ADD ("fp.dp", FPU_ARCH_VFP_V5D16),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8_1m_main_ext_table[] =
+{
+  ARM_EXT ("dsp", ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+                 ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP)),
+  ARM_EXT ("fp",
+          ARM_FEATURE (0, ARM_EXT2_FP16_INST,
+                       FPU_VFP_V5_SP_D16 | FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA),
+          ALL_FP),
+  ARM_ADD ("fp.dp",
+          ARM_FEATURE (0, ARM_EXT2_FP16_INST,
+                       FPU_VFP_V5D16 | FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA)),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8r_ext_table[] =
+{
+  ARM_ADD ("crc", ARCH_CRC_ARMV8),
+  ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8),
+  ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+          ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+  ARM_REMOVE ("fp", ALL_FP),
+  ARM_ADD ("fp.sp", FPU_ARCH_VFP_V5_SP_D16),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
 
 /* This list should, at a minimum, contain all the architecture names
    recognized by GCC.  */
-#define ARM_ARCH_OPT(N, V, DF) { N, sizeof (N) - 1, V, DF }
+#define ARM_ARCH_OPT(N, V, DF) { N, sizeof (N) - 1, V, DF, NULL }
+#define ARM_ARCH_OPT2(N, V, DF, ext) \
+  { N, sizeof (N) - 1, V, DF, ext##_ext_table }
+
 static const struct arm_arch_option_table arm_archs[] =
 {
-  ARM_ARCH_OPT ("all",         ARM_ANY,         FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv1",       ARM_ARCH_V1,     FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv2",       ARM_ARCH_V2,     FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv2a",      ARM_ARCH_V2S,    FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv2s",      ARM_ARCH_V2S,    FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv3",       ARM_ARCH_V3,     FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv3m",      ARM_ARCH_V3M,    FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv4",       ARM_ARCH_V4,     FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv4xm",     ARM_ARCH_V4xM,   FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv4t",      ARM_ARCH_V4T,    FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv4txm",    ARM_ARCH_V4TxM,  FPU_ARCH_FPA),
-  ARM_ARCH_OPT ("armv5",       ARM_ARCH_V5,     FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv5t",      ARM_ARCH_V5T,    FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv5txm",    ARM_ARCH_V5TxM,  FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv5te",     ARM_ARCH_V5TE,   FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv5texp",   ARM_ARCH_V5TExP, FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv5tej",    ARM_ARCH_V5TEJ,  FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv6",       ARM_ARCH_V6,     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 ("all",           ARM_ANY,              FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv1",         ARM_ARCH_V1,          FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv2",         ARM_ARCH_V2,          FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv2a",        ARM_ARCH_V2S,         FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv2s",        ARM_ARCH_V2S,         FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv3",         ARM_ARCH_V3,          FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv3m",        ARM_ARCH_V3M,         FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4",         ARM_ARCH_V4,          FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4xm",       ARM_ARCH_V4xM,        FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4t",        ARM_ARCH_V4T,         FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4txm",      ARM_ARCH_V4TxM,       FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv5",         ARM_ARCH_V5,          FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5t",        ARM_ARCH_V5T,         FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5txm",      ARM_ARCH_V5TxM,       FPU_ARCH_VFP),
+  ARM_ARCH_OPT2 ("armv5te",      ARM_ARCH_V5TE,        FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv5texp",    ARM_ARCH_V5TExP,      FPU_ARCH_VFP, armv5te),
+  ARM_ARCH_OPT2 ("armv5tej",     ARM_ARCH_V5TEJ,       FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6",        ARM_ARCH_V6,          FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6j",       ARM_ARCH_V6,          FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6k",       ARM_ARCH_V6K,         FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6z",       ARM_ARCH_V6Z,         FPU_ARCH_VFP,   armv5te),
   /* 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_OPT2 ("armv6kz",      ARM_ARCH_V6KZ,        FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6zk",      ARM_ARCH_V6KZ,        FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6t2",      ARM_ARCH_V6T2,        FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6kt2",     ARM_ARCH_V6KT2,       FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6zt2",     ARM_ARCH_V6ZT2,       FPU_ARCH_VFP,   armv5te),
   /* 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_OPT2 ("armv6kzt2",    ARM_ARCH_V6KZT2,      FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT2 ("armv6zkt2",    ARM_ARCH_V6KZT2,      FPU_ARCH_VFP,   armv5te),
+  ARM_ARCH_OPT ("armv6-m",       ARM_ARCH_V6M,         FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6s-m",      ARM_ARCH_V6SM,        FPU_ARCH_VFP),
+  ARM_ARCH_OPT2 ("armv7",        ARM_ARCH_V7,          FPU_ARCH_VFP, armv7),
   /* The official spelling of the ARMv7 profile variants is the dashed form.
      Accept the non-dashed form for compatibility with old toolchains.  */
-  ARM_ARCH_OPT ("armv7a",      ARM_ARCH_V7A,    FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv7ve",     ARM_ARCH_V7VE,   FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv7r",      ARM_ARCH_V7R,    FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv7m",      ARM_ARCH_V7M,    FPU_ARCH_VFP),
-  ARM_ARCH_OPT ("armv7-a",     ARM_ARCH_V7A,    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.2-a",   ARM_ARCH_V8_2A,  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),
-  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+  ARM_ARCH_OPT2 ("armv7a",       ARM_ARCH_V7A,         FPU_ARCH_VFP, armv7a),
+  ARM_ARCH_OPT2 ("armv7ve",      ARM_ARCH_V7VE,        FPU_ARCH_VFP, armv7ve),
+  ARM_ARCH_OPT2 ("armv7r",       ARM_ARCH_V7R,         FPU_ARCH_VFP, armv7r),
+  ARM_ARCH_OPT ("armv7m",        ARM_ARCH_V7M,         FPU_ARCH_VFP),
+  ARM_ARCH_OPT2 ("armv7-a",      ARM_ARCH_V7A,         FPU_ARCH_VFP, armv7a),
+  ARM_ARCH_OPT2 ("armv7-r",      ARM_ARCH_V7R,         FPU_ARCH_VFP, armv7r),
+  ARM_ARCH_OPT ("armv7-m",       ARM_ARCH_V7M,         FPU_ARCH_VFP),
+  ARM_ARCH_OPT2 ("armv7e-m",     ARM_ARCH_V7EM,        FPU_ARCH_VFP, armv7em),
+  ARM_ARCH_OPT ("armv8-m.base",          ARM_ARCH_V8M_BASE,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT2 ("armv8-m.main",  ARM_ARCH_V8M_MAIN,   FPU_ARCH_VFP,
+                armv8m_main),
+  ARM_ARCH_OPT2 ("armv8.1-m.main", ARM_ARCH_V8_1M_MAIN,        FPU_ARCH_VFP,
+                armv8_1m_main),
+  ARM_ARCH_OPT2 ("armv8-a",      ARM_ARCH_V8A,         FPU_ARCH_VFP, armv8a),
+  ARM_ARCH_OPT2 ("armv8.1-a",    ARM_ARCH_V8_1A,       FPU_ARCH_VFP, armv81a),
+  ARM_ARCH_OPT2 ("armv8.2-a",    ARM_ARCH_V8_2A,       FPU_ARCH_VFP, armv82a),
+  ARM_ARCH_OPT2 ("armv8.3-a",    ARM_ARCH_V8_3A,       FPU_ARCH_VFP, armv82a),
+  ARM_ARCH_OPT2 ("armv8-r",      ARM_ARCH_V8R,         FPU_ARCH_VFP, armv8r),
+  ARM_ARCH_OPT2 ("armv8.4-a",    ARM_ARCH_V8_4A,       FPU_ARCH_VFP, armv84a),
+  ARM_ARCH_OPT2 ("armv8.5-a",    ARM_ARCH_V8_5A,       FPU_ARCH_VFP, armv85a),
+  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),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
 };
 #undef ARM_ARCH_OPT
 
 /* ISA extensions in the co-processor and main instruction set space.  */
+
 struct arm_option_extension_value_table
 {
-  const char *name;
-  size_t name_len;
-  const arm_feature_set merge_value;
-  const arm_feature_set clear_value;
+  const char *           name;
+  size_t                 name_len;
+  const arm_feature_set  merge_value;
+  const arm_feature_set  clear_value;
   /* 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];
+  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, ARM_ANY } }
 #define ARM_EXT_OPT2(N, M, C, AA1, AA2) { N, sizeof (N) - 1, M, C, {AA1, AA2} }
+
+/* DEPRECATED: Refrain from using this table to add any new extensions, instead
+   use the context sensitive approach using arm_ext_table's.  */
 static const struct arm_option_extension_value_table arm_extensions[] =
 {
   ARM_EXT_OPT ("crc",  ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
@@ -25601,6 +27249,9 @@ 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 ("dotprod", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8,
+                         ARM_FEATURE_COPROC (FPU_NEON_EXT_DOTPROD),
+                         ARM_ARCH_V8_2A),
   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)),
@@ -25609,10 +27260,22 @@ static const struct arm_option_extension_value_table arm_extensions[] =
   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_OPT ("fp16fml",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST
+                                                 | ARM_EXT2_FP16_FML),
+                          ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST
+                                                 | ARM_EXT2_FP16_FML),
+                          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_V7A),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_V7R)),
+  /* Duplicate entry for the purpose of allowing ARMv7 to match in presence of
+     Thumb divide instruction.  Due to this having the same name as the
+     previous entry, this will be ignored when doing command-line parsing and
+     only considered by build attribute selection code.  */
+  ARM_EXT_OPT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_DIV),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_DIV),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V7)),
   ARM_EXT_OPT ("iwmmxt",ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT),
                        ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ARCH_NONE),
   ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2),
@@ -25628,13 +27291,19 @@ static const struct arm_option_extension_value_table arm_extensions[] =
                                   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_FEATURE_CORE_HIGH (ARM_EXT2_V8A)),
+  ARM_EXT_OPT ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES),
+                       ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES),
+                       ARM_ARCH_V8A),
   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_FEATURE_CORE_HIGH (ARM_EXT2_V8A)),
   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_FEATURE_CORE_HIGH (ARM_EXT2_V8A)),
+  ARM_EXT_OPT ("sb",   ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB),
+                       ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB),
+                       ARM_ARCH_V8A),
   ARM_EXT_OPT2 ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
                        ARM_FEATURE_CORE_LOW (ARM_EXT_V6K),
@@ -25655,8 +27324,8 @@ static const struct arm_option_extension_value_table arm_extensions[] =
 /* ISA floating-point and Advanced SIMD extensions.  */
 struct arm_option_fpu_value_table
 {
-  const char *name;
-  const arm_feature_set value;
+  const char *           name;
+  const arm_feature_set  value;
 };
 
 /* This list should, at a minimum, contain all the fpu names
@@ -25675,7 +27344,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},
-  {"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},
@@ -25688,10 +27357,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},
-  {"arm1136jfs",       FPU_ARCH_VFP_V2},
+  {"arm1136jfs",       FPU_ARCH_VFP_V2}, /* Undocumented, use arm1136jf-s.  */
   {"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},
@@ -25736,17 +27406,17 @@ static const struct arm_option_value_table arm_eabis[] =
 
 struct arm_long_option_table
 {
-  const char * option;         /* Substring to match.  */
+  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
-arm_parse_extension (const char *str, const arm_feature_set **opt_p)
+arm_parse_extension (const char *str, const arm_feature_set *opt_set,
+                    arm_feature_set *ext_set,
+                    const struct arm_ext_table *ext_table)
 {
-  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
      the global ARM_EXTENSIONS table in alphabetical order, and using the
@@ -25757,10 +27427,6 @@ arm_parse_extension (const char *str, const arm_feature_set **opt_p)
   const arm_feature_set arm_any = ARM_ANY;
   int adding_value = -1;
 
-  /* Copy the feature set, so that we can modify it.  */
-  *ext_set = **opt_p;
-  *opt_p = ext_set;
-
   while (str != NULL && *str != 0)
     {
       const char *ext;
@@ -25815,6 +27481,41 @@ arm_parse_extension (const char *str, const arm_feature_set **opt_p)
       gas_assert (adding_value != -1);
       gas_assert (opt != NULL);
 
+      if (ext_table != NULL)
+       {
+         const struct arm_ext_table * ext_opt = ext_table;
+         bfd_boolean found = FALSE;
+         for (; ext_opt->name != NULL; ext_opt++)
+           if (ext_opt->name_len == len
+               && strncmp (ext_opt->name, str, len) == 0)
+             {
+               if (adding_value)
+                 {
+                   if (ARM_FEATURE_ZERO (ext_opt->merge))
+                       /* TODO: Option not supported.  When we remove the
+                          legacy table this case should error out.  */
+                       continue;
+
+                   ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, ext_opt->merge);
+                 }
+               else
+                 {
+                   if (ARM_FEATURE_ZERO (ext_opt->clear))
+                       /* TODO: Option not supported.  When we remove the
+                          legacy table this case should error out.  */
+                       continue;
+                   ARM_CLEAR_FEATURE (*ext_set, *ext_set, ext_opt->clear);
+                 }
+               found = TRUE;
+               break;
+             }
+         if (found)
+           {
+             str = ext;
+             continue;
+           }
+       }
+
       /* Scan over the options table trying to find an exact match. */
       for (; opt->name != NULL; opt++)
        if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
@@ -25827,7 +27528,7 @@ arm_parse_extension (const char *str, const arm_feature_set **opt_p)
                /* Empty entry.  */
                if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
                  continue;
-               if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *ext_set))
+               if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *opt_set))
                  break;
              }
            if (i == nb_allowed_archs)
@@ -25842,6 +27543,10 @@ arm_parse_extension (const char *str, const arm_feature_set **opt_p)
            else
              ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->clear_value);
 
+           /* Allowing Thumb division instructions for ARMv7 in autodetection
+              rely on this break so that duplicate extensions (extensions
+              with the same name as a previous extension in the list) are not
+              considered for command-line parsing.  */
            break;
          }
 
@@ -25897,6 +27602,9 @@ arm_parse_cpu (const char *str)
     if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
       {
        mcpu_cpu_opt = &opt->value;
+       if (mcpu_ext_opt == NULL)
+         mcpu_ext_opt = XNEW (arm_feature_set);
+       *mcpu_ext_opt = opt->ext;
        mcpu_fpu_opt = &opt->default_fpu;
        if (opt->canonical_name)
          {
@@ -25916,7 +27624,7 @@ arm_parse_cpu (const char *str)
          }
 
        if (ext != NULL)
-         return arm_parse_extension (ext, &mcpu_cpu_opt);
+         return arm_parse_extension (ext, mcpu_cpu_opt, mcpu_ext_opt, NULL);
 
        return TRUE;
       }
@@ -25947,11 +27655,15 @@ arm_parse_arch (const char *str)
     if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
       {
        march_cpu_opt = &opt->value;
+       if (march_ext_opt == NULL)
+         march_ext_opt = XNEW (arm_feature_set);
+       *march_ext_opt = arm_arch_none;
        march_fpu_opt = &opt->default_fpu;
        strcpy (selected_cpu_name, opt->name);
 
        if (ext != NULL)
-         return arm_parse_extension (ext, &march_cpu_opt);
+         return arm_parse_extension (ext, march_cpu_opt, march_ext_opt,
+                                     opt->ext_table);
 
        return TRUE;
       }
@@ -26087,6 +27799,12 @@ md_parse_option (int c, const char * arg)
       fix_v4bx = TRUE;
       break;
 
+#ifdef OBJ_ELF
+    case OPTION_FDPIC:
+      arm_fdpic = TRUE;
+      break;
+#endif /* OBJ_ELF */
+
     case 'a':
       /* Listing option.  Just ignore these, we don't support additional
         ones.  */
@@ -26181,43 +27899,84 @@ md_show_usage (FILE * fp)
 
   fprintf (fp, _("\
   --fix-v4bx              Allow BX in ARMv4 code\n"));
-}
 
+#ifdef OBJ_ELF
+  fprintf (fp, _("\
+  --fdpic                 generate an FDPIC object file\n"));
+#endif /* OBJ_ELF */
+}
 
 #ifdef OBJ_ELF
+
 typedef struct
 {
   int val;
   arm_feature_set flags;
 } cpu_arch_ver_table;
 
-/* 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.  */
+/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
+   chronologically for architectures, with an exception for ARMv6-M and
+   ARMv6S-M due to legacy reasons.  No new architecture should have a
+   special case.  This allows for build attribute selection results to be
+   stable when new architectures are added.  */
 static const cpu_arch_ver_table cpu_arch_ver[] =
 {
-    {1, ARM_ARCH_V4},
-    {2, ARM_ARCH_V4T},
-    {3, ARM_ARCH_V5},
-    {3, ARM_ARCH_V5T},
-    {4, ARM_ARCH_V5TE},
-    {5, ARM_ARCH_V5TEJ},
-    {6, ARM_ARCH_V6},
-    {9, ARM_ARCH_V6K},
-    {7, ARM_ARCH_V6Z},
-    {11, ARM_ARCH_V6M},
-    {12, ARM_ARCH_V6SM},
-    {8, ARM_ARCH_V6T2},
-    {10, ARM_ARCH_V7VE},
-    {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}
+    {TAG_CPU_ARCH_PRE_V4,     ARM_ARCH_V1},
+    {TAG_CPU_ARCH_PRE_V4,     ARM_ARCH_V2},
+    {TAG_CPU_ARCH_PRE_V4,     ARM_ARCH_V2S},
+    {TAG_CPU_ARCH_PRE_V4,     ARM_ARCH_V3},
+    {TAG_CPU_ARCH_PRE_V4,     ARM_ARCH_V3M},
+    {TAG_CPU_ARCH_V4,        ARM_ARCH_V4xM},
+    {TAG_CPU_ARCH_V4,        ARM_ARCH_V4},
+    {TAG_CPU_ARCH_V4T,       ARM_ARCH_V4TxM},
+    {TAG_CPU_ARCH_V4T,       ARM_ARCH_V4T},
+    {TAG_CPU_ARCH_V5T,       ARM_ARCH_V5xM},
+    {TAG_CPU_ARCH_V5T,       ARM_ARCH_V5},
+    {TAG_CPU_ARCH_V5T,       ARM_ARCH_V5TxM},
+    {TAG_CPU_ARCH_V5T,       ARM_ARCH_V5T},
+    {TAG_CPU_ARCH_V5TE,              ARM_ARCH_V5TExP},
+    {TAG_CPU_ARCH_V5TE,              ARM_ARCH_V5TE},
+    {TAG_CPU_ARCH_V5TEJ,      ARM_ARCH_V5TEJ},
+    {TAG_CPU_ARCH_V6,        ARM_ARCH_V6},
+    {TAG_CPU_ARCH_V6KZ,              ARM_ARCH_V6Z},
+    {TAG_CPU_ARCH_V6KZ,              ARM_ARCH_V6KZ},
+    {TAG_CPU_ARCH_V6K,       ARM_ARCH_V6K},
+    {TAG_CPU_ARCH_V6T2,              ARM_ARCH_V6T2},
+    {TAG_CPU_ARCH_V6T2,              ARM_ARCH_V6KT2},
+    {TAG_CPU_ARCH_V6T2,              ARM_ARCH_V6ZT2},
+    {TAG_CPU_ARCH_V6T2,              ARM_ARCH_V6KZT2},
+
+    /* When assembling a file with only ARMv6-M or ARMv6S-M instruction, GNU as
+       always selected build attributes to match those of ARMv6-M
+       (resp. ARMv6S-M).  However, due to these architectures being a strict
+       subset of ARMv7-M in terms of instructions available, ARMv7-M attributes
+       would be selected when fully respecting chronology of architectures.
+       It is thus necessary to make a special case of ARMv6-M and ARMv6S-M and
+       move them before ARMv7 architectures.  */
+    {TAG_CPU_ARCH_V6_M,              ARM_ARCH_V6M},
+    {TAG_CPU_ARCH_V6S_M,      ARM_ARCH_V6SM},
+
+    {TAG_CPU_ARCH_V7,        ARM_ARCH_V7},
+    {TAG_CPU_ARCH_V7,        ARM_ARCH_V7A},
+    {TAG_CPU_ARCH_V7,        ARM_ARCH_V7R},
+    {TAG_CPU_ARCH_V7,        ARM_ARCH_V7M},
+    {TAG_CPU_ARCH_V7,        ARM_ARCH_V7VE},
+    {TAG_CPU_ARCH_V7E_M,      ARM_ARCH_V7EM},
+    {TAG_CPU_ARCH_V8,        ARM_ARCH_V8A},
+    {TAG_CPU_ARCH_V8,        ARM_ARCH_V8_1A},
+    {TAG_CPU_ARCH_V8,        ARM_ARCH_V8_2A},
+    {TAG_CPU_ARCH_V8,        ARM_ARCH_V8_3A},
+    {TAG_CPU_ARCH_V8M_BASE,   ARM_ARCH_V8M_BASE},
+    {TAG_CPU_ARCH_V8M_MAIN,   ARM_ARCH_V8M_MAIN},
+    {TAG_CPU_ARCH_V8R,       ARM_ARCH_V8R},
+    {TAG_CPU_ARCH_V8,        ARM_ARCH_V8_4A},
+    {TAG_CPU_ARCH_V8,        ARM_ARCH_V8_5A},
+    {TAG_CPU_ARCH_V8_1M_MAIN, ARM_ARCH_V8_1M_MAIN},
+    {-1,                     ARM_ARCH_NONE}
 };
 
 /* Set an attribute if it has not already been set by the user.  */
+
 static void
 aeabi_set_attribute_int (int tag, int value)
 {
@@ -26236,92 +27995,218 @@ aeabi_set_attribute_string (int tag, const char *value)
     bfd_elf_add_proc_attr_string (stdoutput, tag, value);
 }
 
-/* Set the public EABI object attributes.  */
-void
-aeabi_set_public_attributes (void)
+/* Return whether features in the *NEEDED feature set are available via
+   extensions for the architecture whose feature set is *ARCH_FSET.  */
+
+static bfd_boolean
+have_ext_for_needed_feat_p (const arm_feature_set *arch_fset,
+                           const arm_feature_set *needed)
 {
-  int arch;
-  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 arm_arch_v8m_base = ARM_ARCH_V8M_BASE;
-  const cpu_arch_ver_table *p;
+  int i, nb_allowed_archs;
+  arm_feature_set ext_fset;
+  const struct arm_option_extension_value_table *opt;
 
-  /* Choose the architecture based on the capabilities of the requested cpu
-     (if any) and/or the instructions actually used.  */
-  ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
-  ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
-  ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
+  ext_fset = arm_arch_none;
+  for (opt = arm_extensions; opt->name != NULL; opt++)
+    {
+      /* Extension does not provide any feature we need.  */
+      if (!ARM_CPU_HAS_FEATURE (*needed, opt->merge_value))
+       continue;
+
+      nb_allowed_archs =
+       sizeof (opt->allowed_archs) / sizeof (opt->allowed_archs[0]);
+      for (i = 0; i < nb_allowed_archs; i++)
+       {
+         /* Empty entry.  */
+         if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_arch_any))
+           break;
 
-  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any))
-    ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v1);
+         /* Extension is available, add it.  */
+         if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *arch_fset))
+           ARM_MERGE_FEATURE_SETS (ext_fset, ext_fset, opt->merge_value);
+       }
+    }
 
-  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_any))
-    ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t);
+  /* Can we enable all features in *needed?  */
+  return ARM_FSET_CPU_SUBSET (*needed, ext_fset);
+}
 
-  selected_cpu = flags;
+/* Select value for Tag_CPU_arch and Tag_CPU_arch_profile build attributes for
+   a given architecture feature set *ARCH_EXT_FSET including extension feature
+   set *EXT_FSET.  Selection logic used depend on EXACT_MATCH:
+   - if true, check for an exact match of the architecture modulo extensions;
+   - otherwise, select build attribute value of the first superset
+     architecture released so that results remains stable when new architectures
+     are added.
+   For -march/-mcpu=all the build attribute value of the most featureful
+   architecture is returned.  Tag_CPU_arch_profile result is returned in
+   PROFILE.  */
 
-  /* Allow the user to override the reported architecture.  */
-  if (object_arch)
+static int
+get_aeabi_cpu_arch_from_fset (const arm_feature_set *arch_ext_fset,
+                             const arm_feature_set *ext_fset,
+                             char *profile, int exact_match)
+{
+  arm_feature_set arch_fset;
+  const cpu_arch_ver_table *p_ver, *p_ver_ret = NULL;
+
+  /* Select most featureful architecture with all its extensions if building
+     for -march=all as the feature sets used to set build attributes.  */
+  if (ARM_FEATURE_EQUAL (*arch_ext_fset, arm_arch_any))
     {
-      ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
-      ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
+      /* Force revisiting of decision for each new architecture.  */
+      gas_assert (MAX_TAG_CPU_ARCH <= TAG_CPU_ARCH_V8_1M_MAIN);
+      *profile = 'A';
+      return TAG_CPU_ARCH_V8;
     }
 
-  /* We need to make sure that the attributes do not identify us as v6S-M
-     when the only v6S-M feature in use is the Operating System Extensions.  */
-  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_os))
-      if (!ARM_CPU_HAS_FEATURE (flags, arm_arch_v6m_only))
-       ARM_CLEAR_FEATURE (flags, flags, arm_ext_os);
+  ARM_CLEAR_FEATURE (arch_fset, *arch_ext_fset, *ext_fset);
 
-  tmp = flags;
-  arch = 0;
-  for (p = cpu_arch_ver; p->val; p++)
+  for (p_ver = cpu_arch_ver; p_ver->val != -1; p_ver++)
     {
-      if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
+      arm_feature_set known_arch_fset;
+
+      ARM_CLEAR_FEATURE (known_arch_fset, p_ver->flags, fpu_any);
+      if (exact_match)
        {
-         arch = p->val;
-         arm_arch = p->flags;
-         ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
+         /* Base architecture match user-specified architecture and
+            extensions, eg. ARMv6S-M matching -march=armv6-m+os.  */
+         if (ARM_FEATURE_EQUAL (*arch_ext_fset, known_arch_fset))
+           {
+             p_ver_ret = p_ver;
+             goto found;
+           }
+         /* Base architecture match user-specified architecture only
+            (eg. ARMv6-M in the same case as above).  Record it in case we
+            find a match with above condition.  */
+         else if (p_ver_ret == NULL
+                  && ARM_FEATURE_EQUAL (arch_fset, known_arch_fset))
+           p_ver_ret = p_ver;
+       }
+      else
+       {
+
+         /* Architecture has all features wanted.  */
+         if (ARM_FSET_CPU_SUBSET (arch_fset, known_arch_fset))
+           {
+             arm_feature_set added_fset;
+
+             /* Compute features added by this architecture over the one
+                recorded in p_ver_ret.  */
+             if (p_ver_ret != NULL)
+               ARM_CLEAR_FEATURE (added_fset, known_arch_fset,
+                                  p_ver_ret->flags);
+             /* First architecture that match incl. with extensions, or the
+                only difference in features over the recorded match is
+                features that were optional and are now mandatory.  */
+             if (p_ver_ret == NULL
+                 || ARM_FSET_CPU_SUBSET (added_fset, arch_fset))
+               {
+                 p_ver_ret = p_ver;
+                 goto found;
+               }
+           }
+         else if (p_ver_ret == NULL)
+           {
+             arm_feature_set needed_ext_fset;
+
+             ARM_CLEAR_FEATURE (needed_ext_fset, arch_fset, known_arch_fset);
+
+             /* Architecture has all features needed when using some
+                extensions.  Record it and continue searching in case there
+                exist an architecture providing all needed features without
+                the need for extensions (eg. ARMv6S-M Vs ARMv6-M with
+                OS extension).  */
+             if (have_ext_for_needed_feat_p (&known_arch_fset,
+                                             &needed_ext_fset))
+               p_ver_ret = p_ver;
+           }
        }
     }
 
-  /* The table lookup above finds the last architecture to contribute
-     a new feature.  Unfortunately, Tag13 is a subset of the union of
-     v6T2 and v7-M, so it is never seen as contributing a new feature.
-     We can not search for the last entry which is entirely used,
-     because if no CPU is specified we build up only those flags
-     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 == 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))
+  if (p_ver_ret == NULL)
+    return -1;
+
+found:
+  /* Tag_CPU_arch_profile.  */
+  if (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v7a)
+      || ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v8)
+      || (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_atomics)
+         && !ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v8m_m_only)))
+    *profile = 'A';
+  else if (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v7r))
+    *profile = 'R';
+  else if (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_m))
+    *profile = 'M';
+  else
+    *profile = '\0';
+  return p_ver_ret->val;
+}
+
+/* Set the public EABI object attributes.  */
+
+static void
+aeabi_set_public_attributes (void)
+{
+  char profile = '\0';
+  int arch = -1;
+  int virt_sec = 0;
+  int fp16_optional = 0;
+  int skip_exact_match = 0;
+  arm_feature_set flags, flags_arch, flags_ext;
+
+  /* Autodetection mode, choose the architecture based the instructions
+     actually used.  */
+  if (no_cpu_selected ())
     {
-      arch = TAG_CPU_ARCH_V7E_M;
-      arm_arch = (arm_feature_set) ARM_ARCH_V7EM;
-    }
+      ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
+
+      if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any))
+       ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v1);
 
-  ARM_CLEAR_FEATURE (tmp, flags, arm_arch_v8m_base);
-  if (arch == TAG_CPU_ARCH_V8M_BASE && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
+      if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_any))
+       ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t);
+
+      /* Code run during relaxation relies on selected_cpu being set.  */
+      ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
+      flags_ext = arm_arch_none;
+      ARM_CLEAR_FEATURE (selected_arch, flags_arch, flags_ext);
+      selected_ext = flags_ext;
+      selected_cpu = flags;
+    }
+  /* Otherwise, choose the architecture based on the capabilities of the
+     requested cpu.  */
+  else
     {
-      arch = TAG_CPU_ARCH_V8M_MAIN;
-      arm_arch = (arm_feature_set) ARM_ARCH_V8M_MAIN;
+      ARM_MERGE_FEATURE_SETS (flags_arch, selected_arch, selected_ext);
+      ARM_CLEAR_FEATURE (flags_arch, flags_arch, fpu_any);
+      flags_ext = selected_ext;
+      flags = selected_cpu;
     }
+  ARM_MERGE_FEATURE_SETS (flags, flags, selected_fpu);
 
-  /* 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))
+  /* Allow the user to override the reported architecture.  */
+  if (!ARM_FEATURE_ZERO (selected_object_arch))
     {
-      arch = TAG_CPU_ARCH_V8;
-      arm_arch = (arm_feature_set) ARM_ARCH_V8A;
+      ARM_CLEAR_FEATURE (flags_arch, selected_object_arch, fpu_any);
+      flags_ext = arm_arch_none;
     }
+  else
+    skip_exact_match = ARM_FEATURE_EQUAL (selected_cpu, arm_arch_any);
+
+  /* When this function is run again after relaxation has happened there is no
+     way to determine whether an architecture or CPU was specified by the user:
+     - selected_cpu is set above for relaxation to work;
+     - march_cpu_opt is not set if only -mcpu or .cpu is used;
+     - mcpu_cpu_opt is set to arm_arch_any for autodetection.
+     Therefore, if not in -march=all case we first try an exact match and fall
+     back to autodetection.  */
+  if (!skip_exact_match)
+    arch = get_aeabi_cpu_arch_from_fset (&flags_arch, &flags_ext, &profile, 1);
+  if (arch == -1)
+    arch = get_aeabi_cpu_arch_from_fset (&flags_arch, &flags_ext, &profile, 0);
+  if (arch == -1)
+    as_bad (_("no architecture contains all the instructions used\n"));
 
   /* Tag_CPU_name.  */
   if (selected_cpu_name[0])
@@ -26344,40 +28229,22 @@ aeabi_set_public_attributes (void)
   aeabi_set_attribute_int (Tag_CPU_arch, arch);
 
   /* Tag_CPU_arch_profile.  */
-  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';
-  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_m))
-    profile = 'M';
-  else
-    profile = '\0';
-
   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);
-    }
+  if (ARM_CPU_HAS_FEATURE (selected_ext, arm_ext_dsp))
+    aeabi_set_attribute_int (Tag_DSP_extension, 1);
 
+  ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
-      || arch == 0)
+      || ARM_FEATURE_ZERO (flags_arch))
     aeabi_set_attribute_int (Tag_ARM_ISA_use, 1);
 
   /* Tag_THUMB_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v4t)
-      || arch == 0)
+      || ARM_FEATURE_ZERO (flags_arch))
     {
       int thumb_isa_use;
 
@@ -26459,9 +28326,7 @@ aeabi_set_public_attributes (void)
      by the base architecture.
 
      For new architectures we will have to check these tests.  */
-  gas_assert (arch <= TAG_CPU_ARCH_V8
-             || (arch >= TAG_CPU_ARCH_V8M_BASE
-                 && arch <= TAG_CPU_ARCH_V8M_MAIN));
+  gas_assert (arch <= TAG_CPU_ARCH_V8_1M_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);
@@ -26484,7 +28349,21 @@ aeabi_set_public_attributes (void)
     aeabi_set_attribute_int (Tag_Virtualization_use, virt_sec);
 }
 
+/* Post relaxation hook.  Recompute ARM attributes now that relaxation is
+   finished and free extension feature bits which will not be used anymore.  */
+
+void
+arm_md_post_relax (void)
+{
+  aeabi_set_public_attributes ();
+  XDELETE (mcpu_ext_opt);
+  mcpu_ext_opt = NULL;
+  XDELETE (march_ext_opt);
+  march_ext_opt = NULL;
+}
+
 /* Add the default contents for the .ARM.attributes section.  */
+
 void
 arm_md_end (void)
 {
@@ -26495,7 +28374,6 @@ arm_md_end (void)
 }
 #endif /* OBJ_ELF */
 
-
 /* Parse a .cpu directive.  */
 
 static void
@@ -26515,8 +28393,9 @@ s_arm_cpu (int ignored ATTRIBUTE_UNUSED)
   for (opt = arm_cpus + 1; opt->name != NULL; opt++)
     if (streq (opt->name, name))
       {
-       mcpu_cpu_opt = &opt->value;
-       selected_cpu = opt->value;
+       selected_arch = opt->value;
+       selected_ext = opt->ext;
+       ARM_MERGE_FEATURE_SETS (selected_cpu, selected_arch, selected_ext);
        if (opt->canonical_name)
          strcpy (selected_cpu_name, opt->canonical_name);
        else
@@ -26527,7 +28406,8 @@ s_arm_cpu (int ignored ATTRIBUTE_UNUSED)
 
            selected_cpu_name[i] = 0;
          }
-       ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+       ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
+
        *input_line_pointer = saved_char;
        demand_empty_rest_of_line ();
        return;
@@ -26537,7 +28417,6 @@ s_arm_cpu (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 
-
 /* Parse a .arch directive.  */
 
 static void
@@ -26557,10 +28436,11 @@ s_arm_arch (int ignored ATTRIBUTE_UNUSED)
   for (opt = arm_archs + 1; opt->name != NULL; opt++)
     if (streq (opt->name, name))
       {
-       mcpu_cpu_opt = &opt->value;
-       selected_cpu = opt->value;
+       selected_arch = opt->value;
+       selected_ext = arm_arch_none;
+       selected_cpu = selected_arch;
        strcpy (selected_cpu_name, opt->name);
-       ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+       ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
        *input_line_pointer = saved_char;
        demand_empty_rest_of_line ();
        return;
@@ -26571,7 +28451,6 @@ s_arm_arch (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 
-
 /* Parse a .object_arch directive.  */
 
 static void
@@ -26591,7 +28470,7 @@ s_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
   for (opt = arm_archs + 1; opt->name != NULL; opt++)
     if (streq (opt->name, name))
       {
-       object_arch = &opt->value;
+       selected_object_arch = opt->value;
        *input_line_pointer = saved_char;
        demand_empty_rest_of_line ();
        return;
@@ -26608,7 +28487,6 @@ static void
 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;
@@ -26634,9 +28512,9 @@ s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
        for (i = 0; i < nb_allowed_archs; i++)
          {
            /* Empty entry.  */
-           if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
+           if (ARM_CPU_IS_ANY (opt->allowed_archs[i]))
              continue;
-           if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *mcpu_cpu_opt))
+           if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], selected_arch))
              break;
          }
 
@@ -26648,15 +28526,19 @@ s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
          }
 
        if (adding_value)
-         ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu,
+         ARM_MERGE_FEATURE_SETS (selected_ext, selected_ext,
                                  opt->merge_value);
        else
-         ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->clear_value);
+         ARM_CLEAR_FEATURE (selected_ext, selected_ext, opt->clear_value);
 
-       mcpu_cpu_opt = &selected_cpu;
-       ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+       ARM_MERGE_FEATURE_SETS (selected_cpu, selected_arch, selected_ext);
+       ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
        *input_line_pointer = saved_char;
        demand_empty_rest_of_line ();
+       /* Allowing Thumb division instructions for ARMv7 in autodetection rely
+          on this return so that duplicate extensions (extensions with the
+          same name as a previous extension in the list) are not considered
+          for command-line parsing.  */
        return;
       }
 
@@ -26685,8 +28567,13 @@ s_arm_fpu (int ignored ATTRIBUTE_UNUSED)
   for (opt = arm_fpus; opt->name != NULL; opt++)
     if (streq (opt->name, name))
       {
-       mfpu_opt = &opt->value;
-       ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+       selected_fpu = opt->value;
+#ifndef CPU_DEFAULT
+       if (no_cpu_selected ())
+         ARM_MERGE_FEATURE_SETS (cpu_variant, arm_arch_any, selected_fpu);
+       else
+#endif
+         ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
        *input_line_pointer = saved_char;
        demand_empty_rest_of_line ();
        return;
@@ -26781,10 +28668,10 @@ arm_convert_symbolic_attribute (const char *name)
   return -1;
 }
 
-
 /* Apply sym value for relocations only in the case that they are for
    local symbols in the same segment as the fixup and you have the
    respective architectural feature for blx and simple switches.  */
+
 int
 arm_apply_sym_value (struct fix * fixP, segT this_seg)
 {