* gas/config/tc-avr.c: Change ISA for devices with USB support to
[external/binutils.git] / gas / config / tc-arm.c
index 8189c51..72eb0de 100644 (file)
@@ -1,7 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright 1994-2013 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)
@@ -32,7 +30,7 @@
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "obstack.h"
-
+#include "libiberty.h"
 #include "opcode/arm.h"
 
 #ifdef OBJ_ELF
@@ -98,7 +96,7 @@ enum arm_float_abi
 /* Types of processor to assemble for. */
 #ifndef CPU_DEFAULT
 /* The code that was here used to select a default CPU depending on compiler
-   pre-defines which were only present when doing native builds, thus 
+   pre-defines which were only present when doing native builds, thus
    changing gas' default behaviour depending upon the build host.
 
    If you have a target that requires a default CPU option then the you
@@ -195,6 +193,7 @@ static const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0);
 static const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0);
 static const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0);
 static const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0);
+static const arm_feature_set arm_ext_v8 = ARM_FEATURE (ARM_EXT_V8, 0);
 static const arm_feature_set arm_ext_m =
   ARM_FEATURE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M, 0);
 static const arm_feature_set arm_ext_mp = ARM_FEATURE (ARM_EXT_MP, 0);
@@ -233,6 +232,14 @@ static const arm_feature_set fpu_vfp_v3_or_neon_ext =
 static const arm_feature_set fpu_vfp_fp16 = ARM_FEATURE (0, FPU_VFP_EXT_FP16);
 static const arm_feature_set fpu_neon_ext_fma = ARM_FEATURE (0, FPU_NEON_EXT_FMA);
 static const arm_feature_set fpu_vfp_ext_fma = ARM_FEATURE (0, FPU_VFP_EXT_FMA);
+static const arm_feature_set fpu_vfp_ext_armv8 =
+  ARM_FEATURE (0, FPU_VFP_EXT_ARMV8);
+static const arm_feature_set fpu_neon_ext_armv8 =
+  ARM_FEATURE (0, FPU_NEON_EXT_ARMV8);
+static const arm_feature_set fpu_crypto_ext_armv8 =
+  ARM_FEATURE (0, FPU_CRYPTO_EXT_ARMV8);
+static const arm_feature_set crc_ext_armv8 =
+  ARM_FEATURE (0, CRC_EXT_ARMV8);
 
 static int mfloat_abi_opt = -1;
 /* Record user cpu selection for object attributes.  */
@@ -314,6 +321,11 @@ static int implicit_it_mode = IMPLICIT_IT_MODE_ARM;
 
 static bfd_boolean unified_syntax = FALSE;
 
+/* An immediate operand can start with #, and ld*, st*, pld operands
+   can contain [ and ].  We need to tell APP not to elide whitespace
+   before a [, which can appear as the first operand for pld.  */
+const char arm_symbol_chars[] = "#[]";
+
 enum neon_el_type
 {
   NT_invtype,
@@ -351,6 +363,9 @@ enum it_instruction_type
    IT_INSN                 /* The IT insn has been parsed.  */
 };
 
+/* The maximum number of operands we need.  */
+#define ARM_IT_MAX_OPERANDS 6
+
 struct arm_it
 {
   const char * error;
@@ -402,7 +417,7 @@ struct arm_it
     unsigned negative  : 1;  /* Index register was negated.  */
     unsigned shifted   : 1;  /* Shift applied to operation.  */
     unsigned shift_kind : 3;  /* Shift operation (enum shift_kind).  */
-  } operands[6];
+  } operands[ARM_IT_MAX_OPERANDS];
 };
 
 static struct arm_it inst;
@@ -451,8 +466,9 @@ struct asm_psr
 
 struct asm_barrier_opt
 {
-  const char *   template_name;
-  unsigned long  value;
+  const char *    template_name;
+  unsigned long   value;
+  const arm_feature_set arch;
 };
 
 /* The bit that distinguishes CPSR and SPSR.  */
@@ -560,6 +576,7 @@ const char * const reg_expected_msgs[] =
 };
 
 /* Some well known registers that we refer to directly elsewhere.  */
+#define REG_R12        12
 #define REG_SP 13
 #define REG_LR 14
 #define REG_PC 15
@@ -618,6 +635,14 @@ struct asm_opcode
 #define T2_OPCODE_MASK 0xfe1fffff
 #define T2_DATA_OP_SHIFT 21
 
+#define A_COND_MASK         0xf0000000
+#define A_PUSH_POP_OP_MASK  0x0fff0000
+
+/* Opcodes for pushing/poping registers to/from the stack.  */
+#define A1_OPCODE_PUSH    0x092d0000
+#define A2_OPCODE_PUSH    0x052d0004
+#define A2_OPCODE_POP     0x049d0004
+
 /* Codes to distinguish the arithmetic instructions.  */
 #define OPCODE_AND     0
 #define OPCODE_EOR     1
@@ -725,6 +750,7 @@ struct asm_opcode
 #define BAD_PC_WRITEBACK \
        _("cannot use writeback with PC-relative addressing")
 #define BAD_RANGE     _("branch out of range")
+#define UNPRED_REG(R)  _("using " R " results in unpredictable behaviour")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
@@ -860,6 +886,9 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 static inline int
 skip_past_char (char ** str, char c)
 {
+  /* PR gas/14987: Allow for whitespace before the expected character.  */
+  skip_whitespace (*str);
+
   if (**str == c)
     {
       (*str)++;
@@ -2054,6 +2083,7 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
    arm_reloc_hsh contains no entries, so this function can only
    succeed if there is no () after the word.  Returns -1 on error,
    BFD_RELOC_UNUSED if there wasn't any suffix.         */
+
 static int
 parse_reloc (char **str)
 {
@@ -3535,6 +3565,7 @@ s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
   record_alignment (now_seg, 2);
 
   ptr = frag_more (8);
+  memset (ptr, 0, 8);
   where = frag_now_fix () - 8;
 
   /* Self relative offset of the function start.  */
@@ -4314,7 +4345,7 @@ s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
 static void
 s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
 {
-  int tag = s_vendor_attribute (OBJ_ATTR_PROC);
+  int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
 
   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     attributes_set_explicitly[tag] = 1;
@@ -4884,10 +4915,9 @@ parse_shifter_operand (char **str, int i)
          return FAIL;
        }
 
-      /* Convert to decoded value.  md_apply_fix will put it back.  */
-      inst.reloc.exp.X_add_number
-       = (((inst.reloc.exp.X_add_number << (32 - value))
-           | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
+      /* Encode as specified.  */
+      inst.operands[i].imm = inst.reloc.exp.X_add_number | value << 7;
+      return SUCCESS;
     }
 
   inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
@@ -5059,7 +5089,7 @@ parse_shifter_operand_group_reloc (char **str, int i)
 
 /* Parse a Neon alignment expression.  Information is written to
    inst.operands[i].  We assume the initial ':' has been skipped.
-   
+
    align       .imm = align << 8, .immisalign=1, .preind=0  */
 static parse_operand_result
 parse_neon_alignment (char **str, int i)
@@ -5142,6 +5172,9 @@ parse_address_main (char **str, int i, int group_relocations,
       return PARSE_OPERAND_SUCCESS;
     }
 
+  /* PR gas/14887: Allow for whitespace after the opening bracket.  */
+  skip_whitespace (p);
+
   if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
     {
       inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
@@ -5172,7 +5205,7 @@ parse_address_main (char **str, int i, int group_relocations,
             code before we get to see it here. This may be subject to
             change.  */
          parse_operand_result result = parse_neon_alignment (&p, i);
-         
+
          if (result != PARSE_OPERAND_SUCCESS)
            return result;
        }
@@ -5260,7 +5293,7 @@ parse_address_main (char **str, int i, int group_relocations,
       /* FIXME: '@' should be used here, but it's filtered out by generic code
         before we get to see it here. This may be subject to change.  */
       parse_operand_result result = parse_neon_alignment (&p, i);
-      
+
       if (result != PARSE_OPERAND_SUCCESS)
        return result;
     }
@@ -5443,7 +5476,7 @@ parse_psr (char **str, bfd_boolean lhs)
     {
       if (m_profile)
        goto unsupported_psr;
-       
+
       psr_field = SPSR_BIT;
     }
   else if (strncasecmp (p, "CPSR", 4) == 0)
@@ -5516,7 +5549,7 @@ check_suffix:
          unsigned int nzcvq_bits = 0;
          unsigned int g_bit = 0;
          char *bit;
-         
+
          for (bit = start; bit != p; bit++)
            {
              switch (TOLOWER (*bit))
@@ -5536,24 +5569,24 @@ check_suffix:
                case 'v':
                  nzcvq_bits |= (nzcvq_bits & 0x08) ? 0x20 : 0x08;
                  break;
-               
+
                case 'q':
                  nzcvq_bits |= (nzcvq_bits & 0x10) ? 0x20 : 0x10;
                  break;
-               
+
                case 'g':
                  g_bit |= (g_bit & 0x1) ? 0x2 : 0x1;
                  break;
-               
+
                default:
                  inst.error = _("unexpected bit specified after APSR");
                  return FAIL;
                }
            }
-         
+
          if (nzcvq_bits == 0x1f)
            psr_field |= PSR_f;
-         
+
          if (g_bit == 0x1)
            {
              if (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp))
@@ -5565,7 +5598,7 @@ check_suffix:
 
              psr_field |= PSR_s;
            }
-         
+
          if ((nzcvq_bits & 0x20) != 0
              || (nzcvq_bits != 0x1f && nzcvq_bits != 0)
              || (g_bit & 0x2) != 0)
@@ -5746,6 +5779,25 @@ parse_cond (char **str)
   return c->value;
 }
 
+/* If the given feature available in the selected CPU, mark it as used.
+   Returns TRUE iff feature is available.  */
+static bfd_boolean
+mark_feature_used (const arm_feature_set *feature)
+{
+  /* Ensure the option is valid on the current architecture.  */
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
+    return FALSE;
+
+  /* Add the appropriate architecture feature for the barrier option used.
+     */
+  if (thumb_mode)
+    ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature);
+  else
+    ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature);
+
+  return TRUE;
+}
+
 /* Parse an option for a barrier instruction.  Returns the encoding for the
    option, or FAIL.  */
 static int
@@ -5763,6 +5815,9 @@ parse_barrier (char **str)
   if (!o)
     return FAIL;
 
+  if (!mark_feature_used (&o->arch))
+    return FAIL;
+
   *str = q;
   return o->value;
 }
@@ -5931,7 +5986,7 @@ parse_neon_mov (char **str, int *which_operand)
 
               inst.operands[i].reg = val;
               inst.operands[i].isreg = 1;
-              inst.operands[i++].present = 1;
+              inst.operands[i].present = 1;
             }
         }
       else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
@@ -6021,7 +6076,7 @@ parse_neon_mov (char **str, int *which_operand)
           inst.operands[i].isvec = 1;
           inst.operands[i].issingle = 1;
           inst.operands[i].vectype = optype;
-          inst.operands[i++].present = 1;
+          inst.operands[i].present = 1;
         }
     }
   else
@@ -6058,7 +6113,7 @@ enum operand_parse_code
   OP_RRnpc,    /* ARM register, not r15 */
   OP_RRnpcsp,  /* ARM register, neither r15 nor r13 (a.k.a. 'BadReg') */
   OP_RRnpcb,   /* ARM register, not r15, in square brackets */
-  OP_RRnpctw,  /* ARM register, not r15 in Thumb-state or with writeback, 
+  OP_RRnpctw,  /* ARM register, not r15 in Thumb-state or with writeback,
                   optional trailing ! */
   OP_RRw,      /* ARM register, not r15, optional trailing ! */
   OP_RCP,      /* Coprocessor number */
@@ -6189,7 +6244,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   unsigned const int *upat = pattern;
   char *backtrack_pos = 0;
   const char *backtrack_error = 0;
-  int i, val, backtrack_index = 0;
+  int i, val = 0, backtrack_index = 0;
   enum arm_reg_type rtype;
   parse_operand_result result;
   unsigned int op_parse_code;
@@ -6283,22 +6338,16 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   do                                                      \
     {                                                     \
       val = parse_barrier (&str);                         \
-      if (val == FAIL)                                    \
-       {                                                  \
-         if (ISALPHA (*str))                              \
-             goto failure;                                \
-         else                                             \
-             goto immediate;                              \
-       }                                                  \
-      else                                                \
+      if (val == FAIL && ! ISALPHA (*str))                \
+       goto immediate;                                    \
+      if (val == FAIL                                     \
+         /* ISB can only take SY as an option.  */        \
+         || ((inst.instruction & 0xf0) == 0x60            \
+              && val != 0xf))                             \
        {                                                  \
-         if ((inst.instruction & 0xf0) == 0x60            \
-             && val != 0xf)                               \
-           {                                              \
-              /* ISB can only take SY as an option.  */   \
-              inst.error = _("invalid barrier type");     \
-              goto failure;                               \
-           }                                              \
+          inst.error = _("invalid barrier type");         \
+          backtrack_pos = 0;                              \
+          goto failure;                                   \
        }                                                  \
     }                                                     \
   while (0)
@@ -6615,7 +6664,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
             goto failure;
          break;
 
-       case OP_wPSR:    
+       case OP_wPSR:
        case OP_rPSR:
          po_reg_or_goto (REG_TYPE_RNB, try_psr);
          if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_virt))
@@ -6775,8 +6824,8 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          break;
 
        case OP_RRnpctw:
-         if (inst.operands[i].isreg 
-             && inst.operands[i].reg == REG_PC 
+         if (inst.operands[i].isreg
+             && inst.operands[i].reg == REG_PC
              && (inst.operands[i].writeback || thumb))
            inst.error = BAD_PC;
          break;
@@ -7018,14 +7067,22 @@ encode_arm_shifter_operand (int i)
       encode_arm_shift (i);
     }
   else
-    inst.instruction |= INST_IMMEDIATE;
+    {
+      inst.instruction |= INST_IMMEDIATE;
+      if (inst.reloc.type != BFD_RELOC_ARM_IMMEDIATE)
+       inst.instruction |= inst.operands[i].imm;
+    }
 }
 
 /* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3.  */
 static void
 encode_arm_addr_mode_common (int i, bfd_boolean is_t)
 {
-  gas_assert (inst.operands[i].isreg);
+  /* PR 14260:
+     Generate an error if the operand is not a register.  */
+  constraint (!inst.operands[i].isreg,
+             _("Instruction does not support =N addresses"));
+
   inst.instruction |= inst.operands[i].reg << 16;
 
   if (inst.operands[i].preind)
@@ -7139,8 +7196,10 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
   if (inst.operands[i].immisreg)
     {
       constraint ((inst.operands[i].imm == REG_PC
-                  || inst.operands[i].reg == REG_PC),
+                  || (is_t && inst.operands[i].reg == REG_PC)),
                  BAD_PC_ADDRESSING);
+      constraint (inst.operands[i].reg == REG_PC && inst.operands[i].writeback,
+                 BAD_PC_WRITEBACK);
       inst.instruction |= inst.operands[i].imm;
       if (!inst.operands[i].negative)
        inst.instruction |= INDEX_UP;
@@ -7332,6 +7391,13 @@ do_rd_rm (void)
 }
 
 static void
+do_rm_rn (void)
+{
+  inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[1].reg << 16;
+}
+
+static void
 do_rd_rn (void)
 {
   inst.instruction |= inst.operands[0].reg << 12;
@@ -7345,6 +7411,23 @@ do_rn_rd (void)
   inst.instruction |= inst.operands[1].reg << 12;
 }
 
+static bfd_boolean
+check_obsolete (const arm_feature_set *feature, const char *msg)
+{
+  if (ARM_CPU_IS_ANY (cpu_variant))
+    {
+      as_warn ("%s", msg);
+      return TRUE;
+    }
+  else if (ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
+    {
+      as_bad ("%s", msg);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static void
 do_rd_rm_rn (void)
 {
@@ -7355,12 +7438,15 @@ do_rd_rm_rn (void)
       constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
                  _("Rn must not overlap other operands"));
 
-      /* SWP{b} is deprecated for ARMv6* and ARMv7.  */
-      if (warn_on_deprecated
-         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
-       as_warn (_("swp{b} use is deprecated for this architecture"));
-
+      /* SWP{b} is obsolete for ARMv8-A, and deprecated for ARMv6* and ARMv7.
+       */
+      if (!check_obsolete (&arm_ext_v8,
+                          _("swp{b} use is obsoleted for ARMv8 and later"))
+         && warn_on_deprecated
+         && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6))
+       as_warn (_("swp{b} use is deprecated for ARMv6 and ARMv7"));
     }
+
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg;
   inst.instruction |= Rn << 16;
@@ -7451,13 +7537,7 @@ static void
 do_barrier (void)
 {
   if (inst.operands[0].present)
-    {
-      constraint ((inst.instruction & 0xf0) != 0x40
-                 && inst.operands[0].imm > 0xf
-                 && inst.operands[0].imm < 0x0,
-                 _("bad barrier type"));
-      inst.instruction |= inst.operands[0].imm;
-    }
+    inst.instruction |= inst.operands[0].imm;
   else
     inst.instruction |= 0xf;
 }
@@ -7662,10 +7742,52 @@ do_cmp (void)
 
    No special properties.  */
 
+struct deprecated_coproc_regs_s
+{
+  unsigned cp;
+  int opc1;
+  unsigned crn;
+  unsigned crm;
+  int opc2;
+  arm_feature_set deprecated;
+  arm_feature_set obsoleted;
+  const char *dep_msg;
+  const char *obs_msg;
+};
+
+#define DEPR_ACCESS_V8 \
+  N_("This coprocessor register access is deprecated in ARMv8")
+
+/* Table of all deprecated coprocessor registers.  */
+static struct deprecated_coproc_regs_s deprecated_coproc_regs[] =
+{
+    {15, 0, 7, 10, 5,                                  /* CP15DMB.  */
+     ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0),
+     DEPR_ACCESS_V8, NULL},
+    {15, 0, 7, 10, 4,                                  /* CP15DSB.  */
+     ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0),
+     DEPR_ACCESS_V8, NULL},
+    {15, 0, 7,  5, 4,                                  /* CP15ISB.  */
+     ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0),
+     DEPR_ACCESS_V8, NULL},
+    {14, 6, 1,  0, 0,                                  /* TEEHBR.  */
+     ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0),
+     DEPR_ACCESS_V8, NULL},
+    {14, 6, 0,  0, 0,                                  /* TEECR.  */
+     ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0),
+     DEPR_ACCESS_V8, NULL},
+};
+
+#undef DEPR_ACCESS_V8
+
+static const size_t deprecated_coproc_reg_count =
+  sizeof (deprecated_coproc_regs) / sizeof (deprecated_coproc_regs[0]);
+
 static void
 do_co_reg (void)
 {
   unsigned Rd;
+  size_t i;
 
   Rd = inst.operands[2].reg;
   if (thumb_mode)
@@ -7685,6 +7807,23 @@ do_co_reg (void)
        constraint (Rd == REG_PC, BAD_PC);
     }
 
+    for (i = 0; i < deprecated_coproc_reg_count; ++i)
+      {
+       const struct deprecated_coproc_regs_s *r =
+         deprecated_coproc_regs + i;
+
+       if (inst.operands[0].reg == r->cp
+           && inst.operands[1].imm == r->opc1
+           && inst.operands[3].reg == r->crn
+           && inst.operands[4].reg == r->crm
+           && inst.operands[5].imm == r->opc2)
+         {
+           if (! ARM_CPU_IS_ANY (cpu_variant)
+               && warn_on_deprecated
+               && ARM_CPU_HAS_FEATURE (cpu_variant, r->deprecated))
+             as_warn ("%s", r->dep_msg);
+         }
+      }
 
   inst.instruction |= inst.operands[0].reg << 8;
   inst.instruction |= inst.operands[1].imm << 21;
@@ -7786,11 +7925,21 @@ do_it (void)
     }
 }
 
+/* If there is only one register in the register list,
+   then return its register number.  Otherwise return -1.  */
+static int
+only_one_reg_in_list (int range)
+{
+  int i = ffs (range) - 1;
+  return (i > 15 || range != (1 << i)) ? -1 : i;
+}
+
 static void
-do_ldmstm (void)
+encode_ldmstm(int from_push_pop_mnem)
 {
   int base_reg = inst.operands[0].reg;
   int range = inst.operands[1].imm;
+  int one_reg;
 
   inst.instruction |= base_reg << 16;
   inst.instruction |= range;
@@ -7823,6 +7972,23 @@ do_ldmstm (void)
            as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
        }
     }
+
+  /* If PUSH/POP has only one register, then use the A2 encoding.  */
+  one_reg = only_one_reg_in_list (range);
+  if (from_push_pop_mnem && one_reg >= 0)
+    {
+      int is_push = (inst.instruction & A_PUSH_POP_OP_MASK) == A1_OPCODE_PUSH;
+
+      inst.instruction &= A_COND_MASK;
+      inst.instruction |= is_push ? A2_OPCODE_PUSH : A2_OPCODE_POP;
+      inst.instruction |= one_reg << 12;
+    }
+}
+
+static void
+do_ldmstm (void)
+{
+  encode_ldmstm (/*from_push_pop_mnem=*/FALSE);
 }
 
 /* ARMv5TE load-consecutive (argument parse)
@@ -8079,23 +8245,23 @@ static void
 do_vmrs (void)
 {
   unsigned Rt = inst.operands[0].reg;
-  
-  if (thumb_mode && inst.operands[0].reg == REG_SP)
+
+  if (thumb_mode && Rt == REG_SP)
     {
       inst.error = BAD_SP;
       return;
     }
 
   /* APSR_ sets isvec. All other refs to PC are illegal.  */
-  if (!inst.operands[0].isvec && inst.operands[0].reg == REG_PC)
+  if (!inst.operands[0].isvec && Rt == REG_PC)
     {
       inst.error = BAD_PC;
       return;
     }
 
-  if (inst.operands[1].reg != 1)
-    first_error (_("operand 1 must be FPSCR"));
-
+  /* If we get through parsing the register name, we just insert the number
+     generated into the instruction without further validation.  */
+  inst.instruction |= (inst.operands[1].reg << 16);
   inst.instruction |= (Rt << 12);
 }
 
@@ -8103,7 +8269,7 @@ static void
 do_vmsr (void)
 {
   unsigned Rt = inst.operands[1].reg;
-  
+
   if (thumb_mode)
     reject_bad_reg (Rt);
   else if (Rt == REG_PC)
@@ -8112,9 +8278,9 @@ do_vmsr (void)
       return;
     }
 
-  if (inst.operands[0].reg != 1)
-    first_error (_("operand 0 must be FPSCR"));
-
+  /* 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);
   inst.instruction |= (Rt << 12);
 }
 
@@ -8306,7 +8472,7 @@ do_push_pop (void)
   inst.operands[0].isreg = 1;
   inst.operands[0].writeback = 1;
   inst.operands[0].reg = REG_SP;
-  do_ldmstm ();
+  encode_ldmstm (/*from_push_pop_mnem=*/TRUE);
 }
 
 /* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
@@ -8376,6 +8542,10 @@ do_usat16 (void)
 static void
 do_setend (void)
 {
+  if (warn_on_deprecated
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+      as_warn (_("setend use is deprecated for ARMv8"));
+
   if (inst.operands[0].imm)
     inst.instruction |= 0x200;
 }
@@ -8550,6 +8720,25 @@ do_strexd (void)
   inst.instruction |= inst.operands[3].reg << 16;
 }
 
+/* ARM V8 STRL.  */
+static void
+do_stlex (void)
+{
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  do_rd_rm_rn ();
+}
+
+static void
+do_t_stlex (void)
+{
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  do_rm_rd_rn ();
+}
+
 /* ARM V6 SXTAH extracts a 16-bit value from a register, sign
    extends it to 32-bits, and adds the result to a value in another
    register.  You can specify a rotation by 0, 8, 16, or 24 bits
@@ -8803,14 +8992,14 @@ vfp_conv (int srcsize)
 {
   int immbits = srcsize - inst.operands[1].imm;
 
-  if (srcsize == 16 && !(immbits >= 0 && immbits <= srcsize)) 
-    {  
+  if (srcsize == 16 && !(immbits >= 0 && immbits <= srcsize))
+    {
       /* If srcsize is 16, inst.operands[1].imm must be in the range 0-16.
          i.e. immbits must be in range 0 - 16.  */
       inst.error = _("immediate value out of range, expected range [0, 16]");
       return;
     }
-  else if (srcsize == 32 && !(immbits >= 0 && immbits < srcsize)) 
+  else if (srcsize == 32 && !(immbits >= 0 && immbits < srcsize))
     {
       /* If srcsize is 32, inst.operands[1].imm must be in the range 1-32.
          i.e. immbits must be in range 0 - 31.  */
@@ -9254,8 +9443,8 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
       constraint (is_pc && inst.operands[i].writeback, BAD_PC_WRITEBACK);
       constraint (is_t && inst.operands[i].writeback,
                  _("cannot use writeback with this instruction"));
-      constraint (is_pc && ((inst.instruction & THUMB2_LOAD_BIT) == 0)
-                 && !inst.reloc.pc_rel, BAD_PC_ADDRESSING);
+      constraint (is_pc && ((inst.instruction & THUMB2_LOAD_BIT) == 0),
+                 BAD_PC_ADDRESSING);
 
       if (is_d)
        {
@@ -9370,7 +9559,8 @@ 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(_sev,   bf40, f3af8004),
+  X(_sev,   bf40, f3af8004),                    \
+  X(_sevl,  bf50, f3af8005)
 
 /* To catch errors in encoding functions, the codes are all offset by
    0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
@@ -9851,21 +10041,6 @@ do_t_arit3c (void)
 }
 
 static void
-do_t_barrier (void)
-{
-  if (inst.operands[0].present)
-    {
-      constraint ((inst.instruction & 0xf0) != 0x40
-                 && inst.operands[0].imm > 0xf
-                 && inst.operands[0].imm < 0x0,
-                 _("bad barrier type"));
-      inst.instruction |= inst.operands[0].imm;
-    }
-  else
-    inst.instruction |= 0xf;
-}
-
-static void
 do_t_bfc (void)
 {
   unsigned Rd;
@@ -10018,18 +10193,34 @@ do_t_branch (void)
   inst.reloc.pc_rel = 1;
 }
 
+/* Actually do the work for Thumb state bkpt and hlt.  The only difference
+   between the two is the maximum immediate allowed - which is passed in
+   RANGE.  */
 static void
-do_t_bkpt (void)
+do_t_bkpt_hlt1 (int range)
 {
   constraint (inst.cond != COND_ALWAYS,
              _("instruction is always unconditional"));
   if (inst.operands[0].present)
     {
-      constraint (inst.operands[0].imm > 255,
+      constraint (inst.operands[0].imm > range,
                  _("immediate value out of range"));
       inst.instruction |= inst.operands[0].imm;
-      set_it_insn_type (NEUTRAL_IT_INSN);
     }
+
+  set_it_insn_type (NEUTRAL_IT_INSN);
+}
+
+static void
+do_t_hlt (void)
+{
+  do_t_bkpt_hlt1 (63);
+}
+
+static void
+do_t_bkpt (void)
+{
+  do_t_bkpt_hlt1 (255);
 }
 
 static void
@@ -10037,7 +10228,7 @@ do_t_branch23 (void)
 {
   set_it_insn_type_last ();
   encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23);
-  
+
   /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in
      this file.  We used to simply ignore the PLT reloc type here --
      the branch encoding is now needed to deal with TLSCALL relocs.
@@ -10204,6 +10395,7 @@ do_t_it (void)
   set_it_insn_type (IT_INSN);
   now_it.mask = (inst.instruction & 0xf) | 0x10;
   now_it.cc = cond;
+  now_it.warn_deprecated = FALSE;
 
   /* If the condition is a negative condition, invert the mask.  */
   if ((cond & 0x1) == 0x0)
@@ -10211,13 +10403,25 @@ do_t_it (void)
       unsigned int mask = inst.instruction & 0x000f;
 
       if ((mask & 0x7) == 0)
-       /* no conversion needed */;
+       {
+         /* No conversion needed.  */
+         now_it.block_length = 1;
+       }
       else if ((mask & 0x3) == 0)
-       mask ^= 0x8;
+       {
+         mask ^= 0x8;
+         now_it.block_length = 2;
+       }
       else if ((mask & 0x1) == 0)
-       mask ^= 0xC;
+       {
+         mask ^= 0xC;
+         now_it.block_length = 3;
+       }
       else
-       mask ^= 0xE;
+       {
+         mask ^= 0xE;
+         now_it.block_length = 4;
+       }
 
       inst.instruction &= 0xfff0;
       inst.instruction |= mask;
@@ -10344,11 +10548,11 @@ do_t_ldmstm (void)
                  /* First, record an error for Case 3.  */
                  if (inst.operands[1].imm & mask
                      && inst.operands[0].writeback)
-                   inst.error = 
+                   inst.error =
                        _("having the base register in the register list when "
                          "using write back is UNPREDICTABLE");
-                   
-                 opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str 
+
+                 opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str
                                                             : T_MNEM_ldr);
                  inst.instruction = THUMB_OP16 (opcode);
                  inst.instruction |= inst.operands[0].reg << 3;
@@ -10360,7 +10564,7 @@ do_t_ldmstm (void)
            {
              if (inst.operands[0].writeback)
                {
-                 inst.instruction = 
+                 inst.instruction =
                        THUMB_OP16 (inst.instruction == T_MNEM_stmia
                                    ? T_MNEM_push : T_MNEM_pop);
                  inst.instruction |= inst.operands[1].imm;
@@ -10368,7 +10572,7 @@ do_t_ldmstm (void)
                }
              else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
                {
-                 inst.instruction = 
+                 inst.instruction =
                        THUMB_OP16 (inst.instruction == T_MNEM_stmia
                                    ? T_MNEM_str_sp : T_MNEM_ldr_sp);
                  inst.instruction |= ((ffs (inst.operands[1].imm)-1) << 8);
@@ -10647,7 +10851,16 @@ do_t_ldstd (void)
       inst.operands[1].reg = inst.operands[0].reg + 1;
       constraint (inst.operands[0].reg == REG_LR,
                  _("r14 not allowed here"));
+      constraint (inst.operands[0].reg == REG_R12,
+                  _("r12 not allowed here"));
     }
+
+  if (inst.operands[2].writeback
+      && (inst.operands[0].reg == inst.operands[2].reg
+      || inst.operands[1].reg == inst.operands[2].reg))
+    as_warn (_("base register written back, and overlaps "
+               "one of transfer registers"));
+
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 8;
   encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
@@ -10909,6 +11122,17 @@ do_t_mov_cmp (void)
        switch (inst.instruction)
          {
          case T_MNEM_mov:
+           /* In v4t or v5t a move of two lowregs produces unpredictable
+              results. Don't allow this.  */
+           if (low_regs)
+             {
+               constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6),
+                           "MOV Rd, Rs with two low registers is not "
+                           "permitted on this architecture");
+               ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
+                                       arm_ext_v6);
+             }
+
            inst.instruction = T_OPCODE_MOV_HR;
            inst.instruction |= (Rn & 0x8) << 4;
            inst.instruction |= (Rn & 0x7);
@@ -11119,8 +11343,14 @@ do_t_mrs (void)
       int flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
 
       if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m))
-       constraint (flags != 0, _("selected processor does not support "
-                   "requested special purpose register"));
+       {
+         /* PR gas/12698:  The constraint is only applied for m_profile.
+            If the user has specified -march=all, we want to ignore it as
+            we are building for any CPU type, including non-m variants.  */
+         bfd_boolean m_profile = selected_cpu.core != arm_arch_any.core;
+         constraint ((flags != 0) && m_profile, _("selected processor does "
+                                                  "not support requested special purpose register"));
+       }
       else
        /* mrs only accepts APSR/CPSR/SPSR/CPSR_all/SPSR_all (for non-M profile
           devices).  */
@@ -11154,12 +11384,16 @@ do_t_msr (void)
     {
       int bits = inst.operands[0].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
 
-      constraint ((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
-                  && (bits & ~(PSR_s | PSR_f)) != 0)
-                 || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
-                     && bits != PSR_f),
-                 _("selected processor does not support requested special "
-                   "purpose register"));
+      /* PR gas/12698:  The constraint is only applied for m_profile.
+         If the user has specified -march=all, we want to ignore it as
+         we are building for any CPU type, including non-m variants.  */
+      bfd_boolean m_profile = selected_cpu.core != arm_arch_any.core;
+      constraint (((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
+           && (bits & ~(PSR_s | PSR_f)) != 0)
+          || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
+              && bits != PSR_f)) && m_profile,
+          _("selected processor does not support requested special "
+            "purpose register"));
     }
   else
      constraint ((flags & 0xff) != 0, _("selected processor does not support "
@@ -11574,6 +11808,10 @@ do_t_rsb (void)
 static void
 do_t_setend (void)
 {
+  if (warn_on_deprecated
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+      as_warn (_("setend use is deprecated for ARMv8"));
+
   set_it_insn_type (OUTSIDE_IT_INSN);
   if (inst.operands[0].imm)
     inst.instruction |= 0x8;
@@ -12072,7 +12310,20 @@ struct neon_tab_entry
   X(vcmp,      0xeb40a40, 0xeb40b40, N_INV),           \
   X(vcmpz,     0xeb50a40, 0xeb50b40, N_INV),           \
   X(vcmpe,     0xeb40ac0, 0xeb40bc0, N_INV),           \
-  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV)
+  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV),          \
+  X(vseleq,    0xe000a00, N_INV,     N_INV),           \
+  X(vselvs,    0xe100a00, N_INV,     N_INV),           \
+  X(vselge,    0xe200a00, N_INV,     N_INV),           \
+  X(vselgt,    0xe300a00, N_INV,     N_INV),           \
+  X(vmaxnm,    0xe800a00, 0x3000f10, N_INV),           \
+  X(vminnm,    0xe800a40, 0x3200f10, N_INV),           \
+  X(vcvta,     0xebc0a40, 0x3bb0000, N_INV),           \
+  X(vrintr,    0xeb60a40, 0x3ba0400, N_INV),           \
+  X(vrinta,    0xeb80a40, 0x3ba0400, N_INV),           \
+  X(aes,       0x3b00300, N_INV,     N_INV),           \
+  X(sha3op,    0x2000c00, N_INV,     N_INV),           \
+  X(sha1h,     0x3b902c0, N_INV,     N_INV),           \
+  X(sha2op,     0x3ba0380, N_INV,     N_INV)
 
 enum neon_opc
 {
@@ -12102,6 +12353,8 @@ NEON_ENC_TAB
   ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
 #define NEON_ENC_DOUBLE_(X) \
   ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
+#define NEON_ENC_FPV8_(X) \
+  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf000000))
 
 #define NEON_ENCODE(type, inst)                                        \
   do                                                           \
@@ -12289,9 +12542,11 @@ enum neon_type_mask
   N_F16  = 0x0040000,
   N_F32  = 0x0080000,
   N_F64  = 0x0100000,
+  N_P64         = 0x0200000,
   N_KEY  = 0x1000000, /* Key element (main type specifier).  */
   N_EQK  = 0x2000000, /* Given operand has the same type & size as the key.  */
   N_VFP  = 0x4000000, /* VFP mode: operand size must match register width.  */
+  N_UNT  = 0x8000000, /* Must be explicitly untyped.  */
   N_DBL  = 0x0000001, /* If N_EQK, this operand is twice the size.  */
   N_HLF  = 0x0000002, /* If N_EQK, this operand is half the size.  */
   N_SGN  = 0x0000004, /* If N_EQK, this operand is forced to be signed.  */
@@ -12300,7 +12555,7 @@ enum neon_type_mask
   N_FLT  = 0x0000020, /* If N_EQK, this operand is forced to be float.  */
   N_SIZ  = 0x0000040, /* If N_EQK, this operand is forced to be size-only.  */
   N_UTYP = 0,
-  N_MAX_NONSPECIAL = N_F64
+  N_MAX_NONSPECIAL = N_P64
 };
 
 #define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
@@ -12400,7 +12655,9 @@ neon_select_shape (enum neon_shape shape, ...)
          if (!matches)
            break;
         }
-      if (matches)
+      if (matches && (j >= ARM_IT_MAX_OPERANDS || !inst.operands[j].present))
+       /* We've matched all the entries in the shape table, and we don't
+          have any left over operands which have not been matched.  */
         break;
     }
 
@@ -12506,6 +12763,7 @@ type_chk_of_el_type (enum neon_el_type type, unsigned size)
         {
         case 8:  return N_P8;
         case 16: return N_P16;
+       case 64: return N_P64;
         default: ;
         }
       break;
@@ -12550,11 +12808,11 @@ el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
 
   if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
     *size = 8;
-  else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
+  else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_F16 | N_P16)) != 0)
     *size = 16;
   else if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
     *size = 32;
-  else if ((mask & (N_S64 | N_U64 | N_I64 | N_64 | N_F64)) != 0)
+  else if ((mask & (N_S64 | N_U64 | N_I64 | N_64 | N_F64 | N_P64)) != 0)
     *size = 64;
   else
     return FAIL;
@@ -12567,9 +12825,9 @@ el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
     *type = NT_integer;
   else if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
     *type = NT_untyped;
-  else if ((mask & (N_P8 | N_P16)) != 0)
+  else if ((mask & (N_P8 | N_P16 | N_P64)) != 0)
     *type = NT_poly;
-  else if ((mask & (N_F32 | N_F64)) != 0)
+  else if ((mask & (N_F16 | N_F32 | N_F64)) != 0)
     *type = NT_float;
   else
     return FAIL;
@@ -12717,10 +12975,11 @@ neon_check_type (unsigned els, enum neon_shape ns, ...)
           /* If only untyped args are allowed, decay any more specific types to
             them. Some instructions only care about signs for some element
             sizes, so handle that properly.  */
-          if ((g_size == 8 && (types_allowed & N_8) != 0)
-             || (g_size == 16 && (types_allowed & N_16) != 0)
-             || (g_size == 32 && (types_allowed & N_32) != 0)
-             || (g_size == 64 && (types_allowed & N_64) != 0))
+          if (((types_allowed & N_UNT) == 0)
+             && ((g_size == 8 && (types_allowed & N_8) != 0)
+                 || (g_size == 16 && (types_allowed & N_16) != 0)
+                 || (g_size == 32 && (types_allowed & N_32) != 0)
+                 || (g_size == 64 && (types_allowed & N_64) != 0)))
            g_type = NT_untyped;
 
           if (pass == 0)
@@ -13705,7 +13964,8 @@ do_neon_dyadic_if_i_d (void)
 enum vfp_or_neon_is_neon_bits
 {
   NEON_CHECK_CC = 1,
-  NEON_CHECK_ARCH = 2
+  NEON_CHECK_ARCH = 2,
+  NEON_CHECK_ARCH8 = 4
 };
 
 /* Call this function if an instruction which may have belonged to the VFP or
@@ -13743,7 +14003,14 @@ vfp_or_neon_is_neon (unsigned check)
     }
 
   if ((check & NEON_CHECK_ARCH)
-      && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
+      && !mark_feature_used (&fpu_neon_ext_v1))
+    {
+      first_error (_(BAD_FPU));
+      return FAIL;
+    }
+
+  if ((check & NEON_CHECK_ARCH8)
+      && !mark_feature_used (&fpu_neon_ext_armv8))
     {
       first_error (_(BAD_FPU));
       return FAIL;
@@ -14223,16 +14490,55 @@ do_neon_shll (void)
 /* Check the various types for the VCVT instruction, and return which version
    the current instruction is.  */
 
-static int
-neon_cvt_flavour (enum neon_shape rs)
+#define CVT_FLAVOUR_VAR                                                              \
+  CVT_VAR (s32_f32, N_S32, N_F32, whole_reg,   "ftosls", "ftosis", "ftosizs") \
+  CVT_VAR (u32_f32, N_U32, N_F32, whole_reg,   "ftouls", "ftouis", "ftouizs") \
+  CVT_VAR (f32_s32, N_F32, N_S32, whole_reg,   "fsltos", "fsitos", NULL)      \
+  CVT_VAR (f32_u32, N_F32, N_U32, whole_reg,   "fultos", "fuitos", NULL)      \
+  /* Half-precision conversions.  */                                         \
+  CVT_VAR (f32_f16, N_F32, N_F16, whole_reg,   NULL,     NULL,     NULL)      \
+  CVT_VAR (f16_f32, N_F16, N_F32, whole_reg,   NULL,     NULL,     NULL)      \
+  /* VFP instructions.  */                                                   \
+  CVT_VAR (f32_f64, N_F32, N_F64, N_VFP,       NULL,     "fcvtsd", NULL)      \
+  CVT_VAR (f64_f32, N_F64, N_F32, N_VFP,       NULL,     "fcvtds", NULL)      \
+  CVT_VAR (s32_f64, N_S32, N_F64 | key, N_VFP, "ftosld", "ftosid", "ftosizd") \
+  CVT_VAR (u32_f64, N_U32, N_F64 | key, N_VFP, "ftould", "ftouid", "ftouizd") \
+  CVT_VAR (f64_s32, N_F64 | key, N_S32, N_VFP, "fsltod", "fsitod", NULL)      \
+  CVT_VAR (f64_u32, N_F64 | key, N_U32, N_VFP, "fultod", "fuitod", NULL)      \
+  /* VFP instructions with bitshift.  */                                     \
+  CVT_VAR (f32_s16, N_F32 | key, N_S16, N_VFP, "fshtos", NULL,     NULL)      \
+  CVT_VAR (f32_u16, N_F32 | key, N_U16, N_VFP, "fuhtos", NULL,     NULL)      \
+  CVT_VAR (f64_s16, N_F64 | key, N_S16, N_VFP, "fshtod", NULL,     NULL)      \
+  CVT_VAR (f64_u16, N_F64 | key, N_U16, N_VFP, "fuhtod", NULL,     NULL)      \
+  CVT_VAR (s16_f32, N_S16, N_F32 | key, N_VFP, "ftoshs", NULL,     NULL)      \
+  CVT_VAR (u16_f32, N_U16, N_F32 | key, N_VFP, "ftouhs", NULL,     NULL)      \
+  CVT_VAR (s16_f64, N_S16, N_F64 | key, N_VFP, "ftoshd", NULL,     NULL)      \
+  CVT_VAR (u16_f64, N_U16, N_F64 | key, N_VFP, "ftouhd", NULL,     NULL)
+
+#define CVT_VAR(C, X, Y, R, BSN, CN, ZN) \
+  neon_cvt_flavour_##C,
+
+/* The different types of conversions we can do.  */
+enum neon_cvt_flavour
+{
+  CVT_FLAVOUR_VAR
+  neon_cvt_flavour_invalid,
+  neon_cvt_flavour_first_fp = neon_cvt_flavour_f32_f64
+};
+
+#undef CVT_VAR
+
+static enum neon_cvt_flavour
+get_neon_cvt_flavour (enum neon_shape rs)
 {
-#define CVT_VAR(C,X,Y)                                                 \
-  et = neon_check_type (2, rs, whole_reg | (X), whole_reg | (Y));      \
-  if (et.type != NT_invtype)                                           \
-    {                                                                  \
-      inst.error = NULL;                                               \
-      return (C);                                                      \
+#define CVT_VAR(C,X,Y,R,BSN,CN,ZN)                     \
+  et = neon_check_type (2, rs, (R) | (X), (R) | (Y));  \
+  if (et.type != NT_invtype)                           \
+    {                                                  \
+      inst.error = NULL;                               \
+      return (neon_cvt_flavour_##C);                   \
     }
+
   struct neon_type_el et;
   unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
                         || rs == NS_FF) ? N_VFP : 0;
@@ -14242,41 +14548,27 @@ neon_cvt_flavour (enum neon_shape rs)
      here by making the size equal to the key (wider, in this case) operand.  */
   unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
 
-  CVT_VAR (0, N_S32, N_F32);
-  CVT_VAR (1, N_U32, N_F32);
-  CVT_VAR (2, N_F32, N_S32);
-  CVT_VAR (3, N_F32, N_U32);
-  /* Half-precision conversions.  */
-  CVT_VAR (4, N_F32, N_F16);
-  CVT_VAR (5, N_F16, N_F32);
-
-  whole_reg = N_VFP;
-
-  /* VFP instructions.  */
-  CVT_VAR (6, N_F32, N_F64);
-  CVT_VAR (7, N_F64, N_F32);
-  CVT_VAR (8, N_S32, N_F64 | key);
-  CVT_VAR (9, N_U32, N_F64 | key);
-  CVT_VAR (10, N_F64 | key, N_S32);
-  CVT_VAR (11, N_F64 | key, N_U32);
-  /* VFP instructions with bitshift.  */
-  CVT_VAR (12, N_F32 | key, N_S16);
-  CVT_VAR (13, N_F32 | key, N_U16);
-  CVT_VAR (14, N_F64 | key, N_S16);
-  CVT_VAR (15, N_F64 | key, N_U16);
-  CVT_VAR (16, N_S16, N_F32 | key);
-  CVT_VAR (17, N_U16, N_F32 | key);
-  CVT_VAR (18, N_S16, N_F64 | key);
-  CVT_VAR (19, N_U16, N_F64 | key);
+  CVT_FLAVOUR_VAR;
 
-  return -1;
+  return neon_cvt_flavour_invalid;
 #undef CVT_VAR
 }
 
+enum neon_cvt_mode
+{
+  neon_cvt_mode_a,
+  neon_cvt_mode_n,
+  neon_cvt_mode_p,
+  neon_cvt_mode_m,
+  neon_cvt_mode_z,
+  neon_cvt_mode_x,
+  neon_cvt_mode_r
+};
+
 /* Neon-syntax VFP conversions.  */
 
 static void
-do_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
+do_vfp_nsyn_cvt (enum neon_shape rs, enum neon_cvt_flavour flavour)
 {
   const char *opname = 0;
 
@@ -14285,29 +14577,13 @@ do_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
       /* Conversions with immediate bitshift.  */
       const char *enc[] =
         {
-          "ftosls",
-          "ftouls",
-          "fsltos",
-          "fultos",
-          NULL,
-          NULL,
-         NULL,
-         NULL,
-          "ftosld",
-          "ftould",
-          "fsltod",
-          "fultod",
-          "fshtos",
-          "fuhtos",
-          "fshtod",
-          "fuhtod",
-          "ftoshs",
-          "ftouhs",
-          "ftoshd",
-          "ftouhd"
+#define CVT_VAR(C,A,B,R,BSN,CN,ZN) BSN,
+         CVT_FLAVOUR_VAR
+         NULL
+#undef CVT_VAR
         };
 
-      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
+      if (flavour < (int) ARRAY_SIZE (enc))
         {
           opname = enc[flavour];
           constraint (inst.operands[0].reg != inst.operands[1].reg,
@@ -14321,21 +14597,13 @@ do_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
       /* Conversions without bitshift.  */
       const char *enc[] =
         {
-          "ftosis",
-          "ftouis",
-          "fsitos",
-          "fuitos",
-         "NULL",
-         "NULL",
-          "fcvtsd",
-          "fcvtds",
-          "ftosid",
-          "ftouid",
-          "fsitod",
-          "fuitod"
+#define CVT_VAR(C,A,B,R,BSN,CN,ZN) CN,
+         CVT_FLAVOUR_VAR
+         NULL
+#undef CVT_VAR
         };
 
-      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
+      if (flavour < (int) ARRAY_SIZE (enc))
         opname = enc[flavour];
     }
 
@@ -14347,36 +14615,84 @@ static void
 do_vfp_nsyn_cvtz (void)
 {
   enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
-  int flavour = neon_cvt_flavour (rs);
+  enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
   const char *enc[] =
     {
-      "ftosizs",
-      "ftouizs",
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      "ftosizd",
-      "ftouizd"
+#define CVT_VAR(C,A,B,R,BSN,CN,ZN) ZN,
+      CVT_FLAVOUR_VAR
+      NULL
+#undef CVT_VAR
     };
 
-  if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
+  if (flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
     do_vfp_nsyn_opcode (enc[flavour]);
 }
 
 static void
-do_neon_cvt_1 (bfd_boolean round_to_zero ATTRIBUTE_UNUSED)
+do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
+                     enum neon_cvt_mode mode)
+{
+  int sz, op;
+  int rm;
+
+  set_it_insn_type (OUTSIDE_IT_INSN);
+
+  switch (flavour)
+    {
+    case neon_cvt_flavour_s32_f64:
+      sz = 1;
+      op = 0;
+      break;
+    case neon_cvt_flavour_s32_f32:
+      sz = 0;
+      op = 1;
+      break;
+    case neon_cvt_flavour_u32_f64:
+      sz = 1;
+      op = 0;
+      break;
+    case neon_cvt_flavour_u32_f32:
+      sz = 0;
+      op = 0;
+      break;
+    default:
+      first_error (_("invalid instruction shape"));
+      return;
+    }
+
+  switch (mode)
+    {
+    case neon_cvt_mode_a: rm = 0; break;
+    case neon_cvt_mode_n: rm = 1; break;
+    case neon_cvt_mode_p: rm = 2; break;
+    case neon_cvt_mode_m: rm = 3; break;
+    default: first_error (_("invalid rounding mode")); return;
+    }
+
+  NEON_ENCODE (FPV8, inst);
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg, sz == 1 ? VFP_REG_Dm : VFP_REG_Sm);
+  inst.instruction |= sz << 8;
+  inst.instruction |= op << 7;
+  inst.instruction |= rm << 16;
+  inst.instruction |= 0xf0000000;
+  inst.is_neon = TRUE;
+}
+
+static void
+do_neon_cvt_1 (enum neon_cvt_mode mode)
 {
   enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
     NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ, NS_NULL);
-  int flavour = neon_cvt_flavour (rs);
+  enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
 
   /* PR11109: Handle round-to-zero for VCVT conversions.  */
-  if (round_to_zero
+  if (mode == neon_cvt_mode_z
       && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_vfp_v2)
-      && (flavour == 0 || flavour == 1 || flavour == 8 || flavour == 9)
+      && (flavour == neon_cvt_flavour_s32_f32
+         || flavour == neon_cvt_flavour_u32_f32
+         || flavour == neon_cvt_flavour_s32_f64
+         || flavour == neon_cvt_flavour_u32_f64)
       && (rs == NS_FD || rs == NS_FF))
     {
       do_vfp_nsyn_cvtz ();
@@ -14384,9 +14700,13 @@ do_neon_cvt_1 (bfd_boolean round_to_zero ATTRIBUTE_UNUSED)
     }
 
   /* VFP rather than Neon conversions.  */
-  if (flavour >= 6)
+  if (flavour >= neon_cvt_flavour_first_fp)
     {
-      do_vfp_nsyn_cvt (rs, flavour);
+      if (mode == neon_cvt_mode_x || mode == neon_cvt_mode_z)
+       do_vfp_nsyn_cvt (rs, flavour);
+      else
+       do_vfp_nsyn_cvt_fpv8 (flavour, mode);
+
       return;
     }
 
@@ -14407,7 +14727,7 @@ do_neon_cvt_1 (bfd_boolean round_to_zero ATTRIBUTE_UNUSED)
           goto int_encode;
        immbits = 32 - inst.operands[2].imm;
         NEON_ENCODE (IMMED, inst);
-        if (flavour != -1)
+        if (flavour != neon_cvt_flavour_invalid)
           inst.instruction |= enctab[flavour];
         inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
         inst.instruction |= HI1 (inst.operands[0].reg) << 22;
@@ -14423,28 +14743,51 @@ do_neon_cvt_1 (bfd_boolean round_to_zero ATTRIBUTE_UNUSED)
 
     case NS_DD:
     case NS_QQ:
+      if (mode != neon_cvt_mode_x && mode != neon_cvt_mode_z)
+       {
+         NEON_ENCODE (FLOAT, inst);
+         set_it_insn_type (OUTSIDE_IT_INSN);
+
+         if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
+           return;
+
+         inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+         inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+         inst.instruction |= LOW4 (inst.operands[1].reg);
+         inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+         inst.instruction |= neon_quad (rs) << 6;
+         inst.instruction |= (flavour == neon_cvt_flavour_u32_f32) << 7;
+         inst.instruction |= mode << 8;
+         if (thumb_mode)
+           inst.instruction |= 0xfc000000;
+         else
+           inst.instruction |= 0xf0000000;
+       }
+      else
+       {
     int_encode:
-      {
-        unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
+         {
+           unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
 
-        NEON_ENCODE (INTEGER, inst);
+           NEON_ENCODE (INTEGER, inst);
 
-        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-          return;
+           if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+             return;
 
-        if (flavour != -1)
-          inst.instruction |= enctab[flavour];
+           if (flavour != neon_cvt_flavour_invalid)
+             inst.instruction |= enctab[flavour];
 
-        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-        inst.instruction |= LOW4 (inst.operands[1].reg);
-        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-        inst.instruction |= neon_quad (rs) << 6;
-        inst.instruction |= 2 << 18;
+           inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+           inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+           inst.instruction |= LOW4 (inst.operands[1].reg);
+           inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+           inst.instruction |= neon_quad (rs) << 6;
+           inst.instruction |= 2 << 18;
 
-        neon_dp_fixup (&inst);
-      }
-    break;
+           neon_dp_fixup (&inst);
+         }
+       }
+      break;
 
     /* Half-precision conversions for Advanced SIMD -- neon.  */
     case NS_QD:
@@ -14478,64 +14821,123 @@ do_neon_cvt_1 (bfd_boolean round_to_zero ATTRIBUTE_UNUSED)
 
     default:
       /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
-      do_vfp_nsyn_cvt (rs, flavour);
+      if (mode == neon_cvt_mode_x || mode == neon_cvt_mode_z)
+       do_vfp_nsyn_cvt (rs, flavour);
+      else
+       do_vfp_nsyn_cvt_fpv8 (flavour, mode);
     }
 }
 
 static void
 do_neon_cvtr (void)
 {
-  do_neon_cvt_1 (FALSE);
+  do_neon_cvt_1 (neon_cvt_mode_x);
 }
 
 static void
 do_neon_cvt (void)
 {
-  do_neon_cvt_1 (TRUE);
+  do_neon_cvt_1 (neon_cvt_mode_z);
 }
 
 static void
-do_neon_cvtb (void)
+do_neon_cvta (void)
 {
-  inst.instruction = 0xeb20a40;
-
-  /* The sizes are attached to the mnemonic.  */
-  if (inst.vectype.el[0].type != NT_invtype
-      && inst.vectype.el[0].size == 16)
-    inst.instruction |= 0x00010000;
-
-  /* Programmer's syntax: the sizes are attached to the operands.  */
-  else if (inst.operands[0].vectype.type != NT_invtype
-          && inst.operands[0].vectype.size == 16)
-    inst.instruction |= 0x00010000;
+  do_neon_cvt_1 (neon_cvt_mode_a);
+}
 
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
-  do_vfp_cond_or_thumb ();
+static void
+do_neon_cvtn (void)
+{
+  do_neon_cvt_1 (neon_cvt_mode_n);
 }
 
+static void
+do_neon_cvtp (void)
+{
+  do_neon_cvt_1 (neon_cvt_mode_p);
+}
 
 static void
-do_neon_cvtt (void)
+do_neon_cvtm (void)
 {
-  do_neon_cvtb ();
-  inst.instruction |= 0x80;
+  do_neon_cvt_1 (neon_cvt_mode_m);
 }
 
 static void
-neon_move_immediate (void)
+do_neon_cvttb_2 (bfd_boolean t, bfd_boolean to, bfd_boolean is_double)
 {
-  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
-  unsigned immlo, immhi = 0, immbits;
-  int op, cmode, float_p;
+  if (is_double)
+    mark_feature_used (&fpu_vfp_ext_armv8);
 
-  constraint (et.type == NT_invtype,
-              _("operand size must be specified for immediate VMOV"));
+  encode_arm_vfp_reg (inst.operands[0].reg,
+                     (is_double && !to) ? VFP_REG_Dd : VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg,
+                     (is_double && to) ? VFP_REG_Dm : VFP_REG_Sm);
+  inst.instruction |= to ? 0x10000 : 0;
+  inst.instruction |= t ? 0x80 : 0;
+  inst.instruction |= is_double ? 0x100 : 0;
+  do_vfp_cond_or_thumb ();
+}
 
-  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
-  op = (inst.instruction & (1 << 5)) != 0;
+static void
+do_neon_cvttb_1 (bfd_boolean t)
+{
+  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_DF, NS_NULL);
+
+  if (rs == NS_NULL)
+    return;
+  else if (neon_check_type (2, rs, N_F16, N_F32 | N_VFP).type != NT_invtype)
+    {
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/TRUE, /*is_double=*/FALSE);
+    }
+  else if (neon_check_type (2, rs, N_F32 | N_VFP, N_F16).type != NT_invtype)
+    {
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/FALSE, /*is_double=*/FALSE);
+    }
+  else if (neon_check_type (2, rs, N_F16, N_F64 | N_VFP).type != NT_invtype)
+    {
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/TRUE, /*is_double=*/TRUE);
+    }
+  else if (neon_check_type (2, rs, N_F64 | N_VFP, N_F16).type != NT_invtype)
+    {
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/FALSE, /*is_double=*/TRUE);
+    }
+  else
+    return;
+}
+
+static void
+do_neon_cvtb (void)
+{
+  do_neon_cvttb_1 (FALSE);
+}
+
+
+static void
+do_neon_cvtt (void)
+{
+  do_neon_cvttb_1 (TRUE);
+}
+
+static void
+neon_move_immediate (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
+  unsigned immlo, immhi = 0, immbits;
+  int op, cmode, float_p;
+
+  constraint (et.type == NT_invtype,
+              _("operand size must be specified for immediate VMOV"));
+
+  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
+  op = (inst.instruction & (1 << 5)) != 0;
 
   immlo = inst.operands[1].imm;
   if (inst.operands[1].regisimm)
@@ -14692,13 +15094,26 @@ do_neon_vmull (void)
   else
     {
       struct neon_type_el et = neon_check_type (3, NS_QDD,
-        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_KEY);
+        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_P64 | N_KEY);
+
       if (et.type == NT_poly)
         NEON_ENCODE (POLY, inst);
       else
         NEON_ENCODE (INTEGER, inst);
-      /* For polynomial encoding, size field must be 0b00 and the U bit must be
-         zero. Should be OK as-is.  */
+
+      /* For polynomial encoding the U bit must be zero, and the size must
+        be 8 (encoded as 0b00) or, on ARMv8 or later 64 (encoded, non
+        obviously, as 0b10).  */
+      if (et.size == 64)
+       {
+         /* Check we're on the correct architecture.  */
+         if (!mark_feature_used (&fpu_crypto_ext_armv8))
+           inst.error =
+             _("Instruction form not available on this architecture.");
+
+         et.size = 32;
+       }
+
       neon_mixed_length (et, et.size);
     }
 }
@@ -14902,6 +15317,16 @@ do_neon_mov (void)
         unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
         unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
 
+       /* .<size> is optional here, defaulting to .32. */
+       if (inst.vectype.elems == 0
+           && inst.operands[0].vectype.type == NT_invtype
+           && inst.operands[1].vectype.type == NT_invtype)
+         {
+           inst.vectype.el[0].type = NT_untyped;
+           inst.vectype.el[0].size = 32;
+           inst.vectype.elems = 1;
+         }
+
         et = neon_check_type (2, NS_NULL, N_8 | N_16 | N_32 | N_KEY, N_EQK);
         logsize = neon_logbits (et.size);
 
@@ -14951,6 +15376,16 @@ do_neon_mov (void)
         unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
         unsigned abcdebits = 0;
 
+       /* .<dt> is optional here, defaulting to .32. */
+       if (inst.vectype.elems == 0
+           && inst.operands[0].vectype.type == NT_invtype
+           && inst.operands[1].vectype.type == NT_invtype)
+         {
+           inst.vectype.el[0].type = NT_untyped;
+           inst.vectype.el[0].size = 32;
+           inst.vectype.elems = 1;
+         }
+
        et = neon_check_type (2, NS_NULL,
                              N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
         logsize = neon_logbits (et.size);
@@ -15039,6 +15474,11 @@ do_neon_mov (void)
       do_vfp_nsyn_opcode ("fmsrr");
       break;
 
+    case NS_NULL:
+      /* neon_select_shape has determined that the instruction
+        shape is wrong and has already set the error message.  */
+      break;
+
     default:
       abort ();
     }
@@ -15225,14 +15665,14 @@ do_neon_ldr_str (void)
 
   /* Use of PC in vstr in ARM mode is deprecated in ARMv7.
      And is UNPREDICTABLE in thumb mode.  */
-  if (!is_ldr 
+  if (!is_ldr
       && inst.operands[1].reg == REG_PC
-      && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7))
+      && (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7) || thumb_mode))
     {
-      if (!thumb_mode && warn_on_deprecated)
-       as_warn (_("Use of PC here is deprecated"));
-      else
+      if (thumb_mode)
        inst.error = _("Use of PC here is UNPREDICTABLE");
+      else if (warn_on_deprecated)
+       as_warn (_("Use of PC here is deprecated"));
     }
 
   if (inst.operands[0].issingle)
@@ -15536,6 +15976,11 @@ do_neon_ldx_stx (void)
 
     case NEON_ALL_LANES:
       NEON_ENCODE (DUP, inst);
+      if (inst.instruction == N_INV)
+       {
+         first_error ("only loads support such operands");
+         break;
+       }
       do_neon_ld_dup ();
       break;
 
@@ -15570,6 +16015,347 @@ do_neon_ldx_stx (void)
   else
     inst.instruction |= 0xf4000000;
 }
+
+/* FP v8.  */
+static void
+do_vfp_nsyn_fpv8 (enum neon_shape rs)
+{
+  NEON_ENCODE (FPV8, inst);
+
+  if (rs == NS_FFF)
+    do_vfp_sp_dyadic ();
+  else
+    do_vfp_dp_rd_rn_rm ();
+
+  if (rs == NS_DDD)
+    inst.instruction |= 0x100;
+
+  inst.instruction |= 0xf0000000;
+}
+
+static void
+do_vsel (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+
+  if (try_vfp_nsyn (3, do_vfp_nsyn_fpv8) != SUCCESS)
+    first_error (_("invalid instruction shape"));
+}
+
+static void
+do_vmaxnm (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+
+  if (try_vfp_nsyn (3, do_vfp_nsyn_fpv8) == SUCCESS)
+    return;
+
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
+    return;
+
+  neon_dyadic_misc (NT_untyped, N_F32, 0);
+}
+
+static void
+do_vrint_1 (enum neon_cvt_mode mode)
+{
+  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et;
+
+  if (rs == NS_NULL)
+    return;
+
+  et = neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+  if (et.type != NT_invtype)
+    {
+      /* VFP encodings.  */
+      if (mode == neon_cvt_mode_a || mode == neon_cvt_mode_n
+         || mode == neon_cvt_mode_p || mode == neon_cvt_mode_m)
+       set_it_insn_type (OUTSIDE_IT_INSN);
+
+      NEON_ENCODE (FPV8, inst);
+      if (rs == NS_FF)
+       do_vfp_sp_monadic ();
+      else
+       do_vfp_dp_rd_rm ();
+
+      switch (mode)
+       {
+       case neon_cvt_mode_r: inst.instruction |= 0x00000000; break;
+       case neon_cvt_mode_z: inst.instruction |= 0x00000080; break;
+       case neon_cvt_mode_x: inst.instruction |= 0x00010000; break;
+       case neon_cvt_mode_a: inst.instruction |= 0xf0000000; break;
+       case neon_cvt_mode_n: inst.instruction |= 0xf0010000; break;
+       case neon_cvt_mode_p: inst.instruction |= 0xf0020000; break;
+       case neon_cvt_mode_m: inst.instruction |= 0xf0030000; break;
+       default: abort ();
+       }
+
+      inst.instruction |= (rs == NS_DD) << 8;
+      do_vfp_cond_or_thumb ();
+    }
+  else
+    {
+      /* Neon encodings (or something broken...).  */
+      inst.error = NULL;
+      et = neon_check_type (2, rs, N_EQK, N_F32 | N_KEY);
+
+      if (et.type == NT_invtype)
+       return;
+
+      set_it_insn_type (OUTSIDE_IT_INSN);
+      NEON_ENCODE (FLOAT, inst);
+
+      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
+       return;
+
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+      inst.instruction |= LOW4 (inst.operands[1].reg);
+      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+      inst.instruction |= neon_quad (rs) << 6;
+      switch (mode)
+       {
+       case neon_cvt_mode_z: inst.instruction |= 3 << 7; break;
+       case neon_cvt_mode_x: inst.instruction |= 1 << 7; break;
+       case neon_cvt_mode_a: inst.instruction |= 2 << 7; break;
+       case neon_cvt_mode_n: inst.instruction |= 0 << 7; break;
+       case neon_cvt_mode_p: inst.instruction |= 7 << 7; break;
+       case neon_cvt_mode_m: inst.instruction |= 5 << 7; break;
+       case neon_cvt_mode_r: inst.error = _("invalid rounding mode"); break;
+       default: abort ();
+       }
+
+      if (thumb_mode)
+       inst.instruction |= 0xfc000000;
+      else
+       inst.instruction |= 0xf0000000;
+    }
+}
+
+static void
+do_vrintx (void)
+{
+  do_vrint_1 (neon_cvt_mode_x);
+}
+
+static void
+do_vrintz (void)
+{
+  do_vrint_1 (neon_cvt_mode_z);
+}
+
+static void
+do_vrintr (void)
+{
+  do_vrint_1 (neon_cvt_mode_r);
+}
+
+static void
+do_vrinta (void)
+{
+  do_vrint_1 (neon_cvt_mode_a);
+}
+
+static void
+do_vrintn (void)
+{
+  do_vrint_1 (neon_cvt_mode_n);
+}
+
+static void
+do_vrintp (void)
+{
+  do_vrint_1 (neon_cvt_mode_p);
+}
+
+static void
+do_vrintm (void)
+{
+  do_vrint_1 (neon_cvt_mode_m);
+}
+
+/* Crypto v1 instructions.  */
+static void
+do_crypto_2op_1 (unsigned elttype, int op)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+
+  if (neon_check_type (2, NS_QQ, N_EQK | N_UNT, elttype | N_UNT | N_KEY).type
+      == NT_invtype)
+    return;
+
+  inst.error = NULL;
+
+  NEON_ENCODE (INTEGER, inst);
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg);
+  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+  if (op != -1)
+    inst.instruction |= op << 6;
+
+  if (thumb_mode)
+    inst.instruction |= 0xfc000000;
+  else
+    inst.instruction |= 0xf0000000;
+}
+
+static void
+do_crypto_3op_1 (int u, int op)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+
+  if (neon_check_type (3, NS_QQQ, N_EQK | N_UNT, N_EQK | N_UNT,
+                      N_32 | N_UNT | N_KEY).type == NT_invtype)
+    return;
+
+  inst.error = NULL;
+
+  NEON_ENCODE (INTEGER, inst);
+  neon_three_same (1, u, 8 << op);
+}
+
+static void
+do_aese (void)
+{
+  do_crypto_2op_1 (N_8, 0);
+}
+
+static void
+do_aesd (void)
+{
+  do_crypto_2op_1 (N_8, 1);
+}
+
+static void
+do_aesmc (void)
+{
+  do_crypto_2op_1 (N_8, 2);
+}
+
+static void
+do_aesimc (void)
+{
+  do_crypto_2op_1 (N_8, 3);
+}
+
+static void
+do_sha1c (void)
+{
+  do_crypto_3op_1 (0, 0);
+}
+
+static void
+do_sha1p (void)
+{
+  do_crypto_3op_1 (0, 1);
+}
+
+static void
+do_sha1m (void)
+{
+  do_crypto_3op_1 (0, 2);
+}
+
+static void
+do_sha1su0 (void)
+{
+  do_crypto_3op_1 (0, 3);
+}
+
+static void
+do_sha256h (void)
+{
+  do_crypto_3op_1 (1, 0);
+}
+
+static void
+do_sha256h2 (void)
+{
+  do_crypto_3op_1 (1, 1);
+}
+
+static void
+do_sha256su1 (void)
+{
+  do_crypto_3op_1 (1, 2);
+}
+
+static void
+do_sha1h (void)
+{
+  do_crypto_2op_1 (N_32, -1);
+}
+
+static void
+do_sha1su1 (void)
+{
+  do_crypto_2op_1 (N_32, 0);
+}
+
+static void
+do_sha256su0 (void)
+{
+  do_crypto_2op_1 (N_32, 1);
+}
+
+static void
+do_crc32_1 (unsigned int poly, unsigned int sz)
+{
+  unsigned int Rd = inst.operands[0].reg;
+  unsigned int Rn = inst.operands[1].reg;
+  unsigned int Rm = inst.operands[2].reg;
+
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  inst.instruction |= LOW4 (Rd) << (thumb_mode ? 8 : 12);
+  inst.instruction |= LOW4 (Rn) << 16;
+  inst.instruction |= LOW4 (Rm);
+  inst.instruction |= sz << (thumb_mode ? 4 : 21);
+  inst.instruction |= poly << (thumb_mode ? 20 : 9);
+
+  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
+do_crc32b (void)
+{
+  do_crc32_1 (0, 0);
+}
+
+static void
+do_crc32h (void)
+{
+  do_crc32_1 (0, 1);
+}
+
+static void
+do_crc32w (void)
+{
+  do_crc32_1 (0, 2);
+}
+
+static void
+do_crc32cb (void)
+{
+  do_crc32_1 (1, 0);
+}
+
+static void
+do_crc32ch (void)
+{
+  do_crc32_1 (1, 1);
+}
+
+static void
+do_crc32cw (void)
+{
+  do_crc32_1 (1, 2);
+}
+
 \f
 /* Overall per-instruction processing. */
 
@@ -16003,6 +16789,8 @@ new_automatic_it_block (int cond)
   now_it.block_length = 1;
   mapping_state (MAP_THUMB);
   now_it.insn = output_it_inst (cond, now_it.mask, NULL);
+  now_it.warn_deprecated = FALSE;
+  now_it.insn_cond = TRUE;
 }
 
 /* Close an automatic IT block.
@@ -16110,6 +16898,7 @@ static int
 handle_it_state (void)
 {
   now_it.state_handled = 1;
+  now_it.insn_cond = FALSE;
 
   switch (now_it.state)
     {
@@ -16187,6 +16976,7 @@ handle_it_state (void)
            }
          else
            {
+             now_it.insn_cond = TRUE;
              now_it_add_mask (inst.cond);
            }
 
@@ -16198,6 +16988,7 @@ handle_it_state (void)
 
        case NEUTRAL_IT_INSN:
          now_it.block_length++;
+         now_it.insn_cond = TRUE;
 
          if (now_it.block_length > 4)
            force_automatic_it_block_close ();
@@ -16220,6 +17011,7 @@ handle_it_state (void)
        now_it.mask <<= 1;
        now_it.mask &= 0x1f;
        is_last = (now_it.mask == 0x10);
+       now_it.insn_cond = TRUE;
 
        switch (inst.it_insn_type)
          {
@@ -16264,6 +17056,25 @@ handle_it_state (void)
   return SUCCESS;
 }
 
+struct depr_insn_mask
+{
+  unsigned long pattern;
+  unsigned long mask;
+  const char* description;
+};
+
+/* List of 16-bit instruction patterns deprecated in an IT block in
+   ARMv8.  */
+static const struct depr_insn_mask depr_it_insns[] = {
+  { 0xc000, 0xc000, N_("Short branches, Undefined, SVC, LDM/STM") },
+  { 0xb000, 0xb000, N_("Miscellaneous 16-bit instructions") },
+  { 0xa000, 0xb800, N_("ADR") },
+  { 0x4800, 0xf800, N_("Literal loads") },
+  { 0x4478, 0xf478, N_("Hi-register ADD, MOV, CMP, BX, BLX using pc") },
+  { 0x4487, 0xfc87, N_("Hi-register ADD, MOV, CMP using pc") },
+  { 0, 0, NULL }
+};
+
 static void
 it_fsm_post_encode (void)
 {
@@ -16272,6 +17083,44 @@ it_fsm_post_encode (void)
   if (!now_it.state_handled)
     handle_it_state ();
 
+  if (now_it.insn_cond
+      && !now_it.warn_deprecated
+      && warn_on_deprecated
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+    {
+      if (inst.instruction >= 0x10000)
+       {
+         as_warn (_("IT blocks containing 32-bit Thumb instructions are "
+                    "deprecated in ARMv8"));
+         now_it.warn_deprecated = TRUE;
+       }
+      else
+       {
+         const struct depr_insn_mask *p = depr_it_insns;
+
+         while (p->mask != 0)
+           {
+             if ((inst.instruction & p->mask) == p->pattern)
+               {
+                 as_warn (_("IT blocks containing 16-bit Thumb instructions "
+                            "of the following class are deprecated in ARMv8: "
+                            "%s"), p->description);
+                 now_it.warn_deprecated = TRUE;
+                 break;
+               }
+
+             ++p;
+           }
+       }
+
+      if (now_it.block_length > 1)
+       {
+         as_warn (_("IT blocks containing more than one conditional "
+                    "instruction are deprecated in ARMv8"));
+         now_it.warn_deprecated = TRUE;
+       }
+    }
+
   is_last = (now_it.mask == 0x10);
   if (is_last)
     {
@@ -16671,7 +17520,7 @@ static const struct reg_entry reg_names[] =
   REGDEF(R10_fiq,512|(10<<16),RNB), REGDEF(r10_fiq,512|(10<<16),RNB),
   REGDEF(R11_fiq,512|(11<<16),RNB), REGDEF(r11_fiq,512|(11<<16),RNB),
   REGDEF(R12_fiq,512|(12<<16),RNB), REGDEF(r12_fiq,512|(12<<16),RNB),
-  REGDEF(SP_fiq,512|(13<<16),RNB), REGDEF(SP_fiq,512|(13<<16),RNB),
+  REGDEF(SP_fiq,512|(13<<16),RNB), REGDEF(sp_fiq,512|(13<<16),RNB),
   REGDEF(LR_fiq,512|(14<<16),RNB), REGDEF(lr_fiq,512|(14<<16),RNB),
   REGDEF(SPSR_fiq,512|(14<<16)|SPSR_BIT,RNB), REGDEF(spsr_fiq,512|(14<<16)|SPSR_BIT,RNB),
 
@@ -16682,7 +17531,7 @@ static const struct reg_entry reg_names[] =
   SPLRBANK(12,MON,RNB), SPLRBANK(12,mon,RNB),
   REGDEF(elr_hyp,768|(14<<16),RNB), REGDEF(ELR_hyp,768|(14<<16),RNB),
   REGDEF(sp_hyp,768|(15<<16),RNB), REGDEF(SP_hyp,768|(15<<16),RNB),
-  REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB), 
+  REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB),
   REGDEF(SPSR_hyp,768|(14<<16)|SPSR_BIT,RNB),
 
   /* FPA registers.  */
@@ -16902,22 +17751,32 @@ static const struct asm_cond conds[] =
   {"al", 0xe}
 };
 
+#define UL_BARRIER(L,U,CODE,FEAT) \
+  { L, CODE, ARM_FEATURE (FEAT, 0) }, \
+  { U, CODE, ARM_FEATURE (FEAT, 0) }
+
 static struct asm_barrier_opt barrier_opt_names[] =
 {
-  { "sy",    0xf }, { "SY",    0xf },
-  { "un",    0x7 }, { "UN",    0x7 },
-  { "st",    0xe }, { "ST",    0xe },
-  { "unst",  0x6 }, { "UNST",  0x6 },
-  { "ish",   0xb }, { "ISH",   0xb },
-  { "sh",    0xb }, { "SH",    0xb },
-  { "ishst", 0xa }, { "ISHST", 0xa },
-  { "shst",  0xa }, { "SHST",  0xa },
-  { "nsh",   0x7 }, { "NSH",   0x7 },
-  { "nshst", 0x6 }, { "NSHST", 0x6 },
-  { "osh",   0x3 }, { "OSH",   0x3 },
-  { "oshst", 0x2 }, { "OSHST", 0x2 }
+  UL_BARRIER ("sy",    "SY",    0xf, ARM_EXT_BARRIER),
+  UL_BARRIER ("st",    "ST",    0xe, ARM_EXT_BARRIER),
+  UL_BARRIER ("ld",    "LD",    0xd, ARM_EXT_V8),
+  UL_BARRIER ("ish",   "ISH",   0xb, ARM_EXT_BARRIER),
+  UL_BARRIER ("sh",    "SH",    0xb, ARM_EXT_BARRIER),
+  UL_BARRIER ("ishst", "ISHST", 0xa, ARM_EXT_BARRIER),
+  UL_BARRIER ("shst",  "SHST",  0xa, ARM_EXT_BARRIER),
+  UL_BARRIER ("ishld", "ISHLD", 0x9, ARM_EXT_V8),
+  UL_BARRIER ("un",    "UN",    0x7, ARM_EXT_BARRIER),
+  UL_BARRIER ("nsh",   "NSH",   0x7, ARM_EXT_BARRIER),
+  UL_BARRIER ("unst",  "UNST",  0x6, ARM_EXT_BARRIER),
+  UL_BARRIER ("nshst", "NSHST", 0x6, ARM_EXT_BARRIER),
+  UL_BARRIER ("nshld", "NSHLD", 0x5, ARM_EXT_V8),
+  UL_BARRIER ("osh",   "OSH",   0x3, ARM_EXT_BARRIER),
+  UL_BARRIER ("oshst", "OSHST", 0x2, ARM_EXT_BARRIER),
+  UL_BARRIER ("oshld", "OSHLD", 0x1, ARM_EXT_V8)
 };
 
+#undef UL_BARRIER
+
 /* Table of ARM-format instructions.   */
 
 /* Macros for gluing together operand strings.  N.B. In all cases
@@ -16975,38 +17834,6 @@ static struct asm_barrier_opt barrier_opt_names[] =
 #define tC3w(mnem, aop, top, nops, ops, ae, te) \
       TxC3w (mnem, aop, T_MNEM##top, nops, ops, ae, te)
 
-/* Mnemonic with a conditional infix in an unusual place.  Each and every variant has to
-   appear in the condition table.  */
-#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te)  \
-  { m1 #m2 m3, OPS##nops ops, sizeof (#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof (m1) - 1, \
-    0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
-
-#define TxCM(m1, m2, op, top, nops, ops, ae, te)       \
-  TxCM_ (m1,   , m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, eq, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ne, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, cs, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, hs, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, cc, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ul, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, lo, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, mi, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, pl, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, vs, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, vc, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, hi, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ls, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ge, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, lt, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, gt, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, le, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, al, m2, op, top, nops, ops, ae, te)
-
-#define TCM(m1,m2, aop, top, nops, ops, ae, te)                \
-      TxCM (m1,m2, aop, 0x##top, nops, ops, ae, te)
-#define tCM(m1,m2, aop, top, nops, ops, ae, te)                \
-      TxCM (m1,m2, aop, T_MNEM##top, nops, ops, ae, te)
-
 /* Mnemonic that cannot be conditionalized.  The ARM condition-code
    field is still 0xE.  Many of the Thumb variants can be executed
    conditionally, so this is checked separately.  */
@@ -17014,6 +17841,13 @@ static struct asm_barrier_opt barrier_opt_names[] =
   { mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
     THUMB_VARIANT, do_##ae, do_##te }
 
+/* Same as TUE but the encoding function for ARM and Thumb modes is the same.
+   Used by mnemonics that have very minimal differences in the encoding for
+   ARM and Thumb variants and can be handled in a common function.  */
+#define TUEc(mnem, op, top, nops, ops, en) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
+    THUMB_VARIANT, do_##en, do_##en }
+
 /* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
    condition code field.  */
 #define TUF(mnem, op, top, nops, ops, ae, te)                          \
@@ -17298,8 +18132,8 @@ static const struct asm_opcode insns[] =
  tC3("strh",   00000b0, _strh,     2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
  tC3("ldrsh",  01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
  tC3("ldrsb",  01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
- tCM("ld","sh",        01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
- tCM("ld","sb",        01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldsh",   01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldsb",   01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
 
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v4t_5
@@ -17413,17 +18247,23 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6_notm
  TUF("rfeia",  8900a00, e990c000, 1, (RRw),                       rfe, rfe),
+ TUF("rfe",    8900a00, e990c000, 1, (RRw),                       rfe, rfe),
   UF(rfeib,    9900a00,           1, (RRw),                       rfe),
   UF(rfeda,    8100a00,           1, (RRw),                       rfe),
  TUF("rfedb",  9100a00, e810c000, 1, (RRw),                       rfe, rfe),
  TUF("rfefd",  8900a00, e990c000, 1, (RRw),                       rfe, rfe),
-  UF(rfefa,    9900a00,           1, (RRw),                       rfe),
 UF(rfeea,    8100a00,           1, (RRw),                       rfe),
TUF("rfeed",  9100a00, e810c000, 1, (RRw),                       rfe, rfe),
+  UF(rfefa,    8100a00,           1, (RRw),                       rfe),
TUF("rfeea",  9100a00, e810c000, 1, (RRw),                       rfe, rfe),
 UF(rfeed,    9900a00,           1, (RRw),                       rfe),
  TUF("srsia",  8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("srs",    8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("srsea",  8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
   UF(srsib,    9c00500,           2, (oRRw, I31w),                srs),
+  UF(srsfa,    9c00500,           2, (oRRw, I31w),                srs),
   UF(srsda,    8400500,           2, (oRRw, I31w),                srs),
+  UF(srsed,    8400500,           2, (oRRw, I31w),                srs),
  TUF("srsdb",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("srsfd",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
 
 /*  ARM V6 not included in V7M (eg. integer SIMD).  */
 #undef  THUMB_VARIANT
@@ -17645,9 +18485,9 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_barrier
 
- TUF("dmb",    57ff050, f3bf8f50, 1, (oBARRIER_I15), barrier,  t_barrier),
- TUF("dsb",    57ff040, f3bf8f40, 1, (oBARRIER_I15), barrier,  t_barrier),
- TUF("isb",    57ff060, f3bf8f60, 1, (oBARRIER_I15), barrier,  t_barrier),
+ TUF("dmb",    57ff050, f3bf8f50, 1, (oBARRIER_I15), barrier, barrier),
+ TUF("dsb",    57ff040, f3bf8f40, 1, (oBARRIER_I15), barrier, barrier),
+ TUF("isb",    57ff060, f3bf8f60, 1, (oBARRIER_I15), barrier, barrier),
 
  /* ARM V7 instructions.  */
 #undef  ARM_VARIANT
@@ -17665,8 +18505,101 @@ static const struct asm_opcode insns[] =
 
  TUF("pldw",   410f000, f830f000, 1, (ADDR),   pld,    t_pld),
 
+ /* AArchv8 instructions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_v8
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8
+
+ tCE("sevl",   320f005, _sevl,    0, (),               noargs, t_hint),
+ TUE("hlt",    1000070, ba80,     1, (oIffffb),        bkpt,   t_hlt),
+ TCE("ldaex",  1900e9f, e8d00fef, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldaexd", 1b00e9f, e8d000ff, 3, (RRnpc, oRRnpc, RRnpcb),
+                                                       ldrexd, t_ldrexd),
+ TCE("ldaexb", 1d00e9f, e8d00fcf, 2, (RRnpc,RRnpcb),   rd_rn,  rd_rn),
+ TCE("ldaexh", 1f00e9f, e8d00fdf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("stlex",  1800e90, e8c00fe0, 3, (RRnpc, RRnpc, RRnpcb),
+                                                       stlex,  t_stlex),
+ TCE("stlexd", 1a00e90, e8c000f0, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb),
+                                                       strexd, t_strexd),
+ TCE("stlexb", 1c00e90, e8c00fc0, 3, (RRnpc, RRnpc, RRnpcb),
+                                                       stlex, t_stlex),
+ TCE("stlexh", 1e00e90, e8c00fd0, 3, (RRnpc, RRnpc, RRnpcb),
+                                                       stlex, t_stlex),
+ TCE("lda",    1900c9f, e8d00faf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldab",   1d00c9f, e8d00f8f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldah",   1f00c9f, e8d00f9f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("stl",    180fc90, e8c00faf, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("stlb",   1c0fc90, e8c00f8f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("stlh",   1e0fc90, e8c00f9f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+
+ /* ARMv8 T32 only.  */
+#undef ARM_VARIANT
+#define ARM_VARIANT  NULL
+ TUF("dcps1",  0,       f78f8001, 0, (),       noargs, noargs),
+ TUF("dcps2",  0,       f78f8002, 0, (),       noargs, noargs),
+ TUF("dcps3",  0,       f78f8003, 0, (),       noargs, noargs),
+
+  /* FP for ARMv8.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT & fpu_vfp_ext_armv8
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & fpu_vfp_ext_armv8
+
+  nUF(vseleq, _vseleq, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vselvs, _vselvs, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vselge, _vselge, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vselgt, _vselgt, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vmaxnm, _vmaxnm, 3, (RNSDQ, oRNSDQ, RNSDQ),      vmaxnm),
+  nUF(vminnm, _vminnm, 3, (RNSDQ, oRNSDQ, RNSDQ),      vmaxnm),
+  nUF(vcvta,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvta),
+  nUF(vcvtn,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvtn),
+  nUF(vcvtp,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvtp),
+  nUF(vcvtm,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvtm),
+  nCE(vrintr, _vrintr, 2, (RNSDQ, oRNSDQ),             vrintr),
+  nCE(vrintz, _vrintr, 2, (RNSDQ, oRNSDQ),             vrintz),
+  nCE(vrintx, _vrintr, 2, (RNSDQ, oRNSDQ),             vrintx),
+  nUF(vrinta, _vrinta, 2, (RNSDQ, oRNSDQ),             vrinta),
+  nUF(vrintn, _vrinta, 2, (RNSDQ, oRNSDQ),             vrintn),
+  nUF(vrintp, _vrinta, 2, (RNSDQ, oRNSDQ),             vrintp),
+  nUF(vrintm, _vrinta, 2, (RNSDQ, oRNSDQ),             vrintm),
+
+  /* Crypto v1 extensions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT & fpu_crypto_ext_armv8
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & fpu_crypto_ext_armv8
+
+  nUF(aese, _aes, 2, (RNQ, RNQ), aese),
+  nUF(aesd, _aes, 2, (RNQ, RNQ), aesd),
+  nUF(aesmc, _aes, 2, (RNQ, RNQ), aesmc),
+  nUF(aesimc, _aes, 2, (RNQ, RNQ), aesimc),
+  nUF(sha1c, _sha3op, 3, (RNQ, RNQ, RNQ), sha1c),
+  nUF(sha1p, _sha3op, 3, (RNQ, RNQ, RNQ), sha1p),
+  nUF(sha1m, _sha3op, 3, (RNQ, RNQ, RNQ), sha1m),
+  nUF(sha1su0, _sha3op, 3, (RNQ, RNQ, RNQ), sha1su0),
+  nUF(sha256h, _sha3op, 3, (RNQ, RNQ, RNQ), sha256h),
+  nUF(sha256h2, _sha3op, 3, (RNQ, RNQ, RNQ), sha256h2),
+  nUF(sha256su1, _sha3op, 3, (RNQ, RNQ, RNQ), sha256su1),
+  nUF(sha1h, _sha1h, 2, (RNQ, RNQ), sha1h),
+  nUF(sha1su1, _sha2op, 2, (RNQ, RNQ), sha1su1),
+  nUF(sha256su0, _sha2op, 2, (RNQ, RNQ), sha256su0),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT & crc_ext_armv8
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & crc_ext_armv8
+  TUEc("crc32b", 1000040, fac0f080, 3, (RR, oRR, RR), crc32b),
+  TUEc("crc32h", 1200040, fac0f090, 3, (RR, oRR, RR), crc32h),
+  TUEc("crc32w", 1400040, fac0f0a0, 3, (RR, oRR, RR), crc32w),
+  TUEc("crc32cb",1000240, fad0f080, 3, (RR, oRR, RR), crc32cb),
+  TUEc("crc32ch",1200240, fad0f090, 3, (RR, oRR, RR), crc32ch),
+  TUEc("crc32cw",1400240, fad0f0a0, 3, (RR, oRR, RR), crc32cw),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT NULL
 
  cCE("wfs",    e200110, 1, (RR),            rd),
  cCE("rfs",    e300110, 1, (RR),            rd),
@@ -18116,8 +19049,8 @@ static const struct asm_opcode insns[] =
  cCE("fmrs",   e100a10, 2, (RR, RVS),        vfp_reg_from_sp),
  cCE("fmsr",   e000a10, 2, (RVS, RR),        vfp_sp_from_reg),
  cCE("fmstat", ef1fa10, 0, (),               noargs),
- cCE("vmrs",   ef10a10, 2, (APSR_RR, RVC),   vmrs),
- cCE("vmsr",   ee10a10, 2, (RVC, RR),        vmsr),
+ cCE("vmrs",   ef00a10, 2, (APSR_RR, RVC),   vmrs),
+ cCE("vmsr",   ee00a10, 2, (RVC, RR),        vmsr),
  cCE("fsitos", eb80ac0, 2, (RVS, RVS),       vfp_sp_monadic),
  cCE("fuitos", eb80a40, 2, (RVS, RVS),       vfp_sp_monadic),
  cCE("ftosis", ebd0a40, 2, (RVS, RVS),       vfp_sp_monadic),
@@ -18271,8 +19204,8 @@ static const struct asm_opcode insns[] =
 
  nCEF(vcvt,     _vcvt,   3, (RNSDQ, RNSDQ, oI32z), neon_cvt),
  nCEF(vcvtr,    _vcvt,   2, (RNSDQ, RNSDQ), neon_cvtr),
nCEF(vcvtb,   _vcvt,   2, (RVS, RVS), neon_cvtb),
nCEF(vcvtt,   _vcvt,   2, (RVS, RVS), neon_cvtt),
NCEF(vcvtb,   eb20a40, 2, (RVSD, RVSD), neon_cvtb),
NCEF(vcvtt,   eb20a40, 2, (RVSD, RVSD), neon_cvtt),
 
 
   /* NOTE: All VMOV encoding is special-cased!  */
@@ -18896,7 +19829,6 @@ static const struct asm_opcode insns[] =
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
 #undef TCE
-#undef TCM
 #undef TUE
 #undef TUF
 #undef TCC
@@ -18967,6 +19899,26 @@ md_chars_to_number (char * buf, int n)
 
 /* MD interface: Sections.  */
 
+/* Calculate the maximum variable size (i.e., excluding fr_fix)
+   that an rs_machine_dependent frag may reach.  */
+
+unsigned int
+arm_frag_max_var (fragS *fragp)
+{
+  /* We only use rs_machine_dependent for variable-size Thumb instructions,
+     which are either THUMB_SIZE (2) or INSN_SIZE (4).
+
+     Note that we generate relaxable instructions even for cases that don't
+     really need it, like an immediate that's a trivial constant.  So we're
+     overestimating the instruction size for some of those cases.  Rather
+     than putting more intelligence here, it would probably be better to
+     avoid generating a relaxation frag in the first place when it can be
+     determined up front that a short instruction will suffice.  */
+
+  gas_assert (fragp->fr_type == rs_machine_dependent);
+  return INSN_SIZE;
+}
+
 /* Estimate the size of a frag before relaxing.  Assume everything fits in
    2 bytes.  */
 
@@ -19538,7 +20490,7 @@ arm_frag_align_code (int n, int max)
     {
       char err_msg[128];
 
-      sprintf (err_msg, 
+      sprintf (err_msg,
         _("alignments greater than %d bytes not supported in .text sections."),
         MAX_MEM_FOR_RS_ALIGN_CODE + 1);
       as_fatal ("%s", err_msg);
@@ -19896,8 +20848,12 @@ create_unwind_entry (int have_data)
        size = unwind.opcode_count - 2;
     }
   else
-    /* An extra byte is required for the opcode count. */
-    size = unwind.opcode_count + 1;
+    {
+      gas_assert (unwind.personality_index == -1);
+
+      /* An extra byte is required for the opcode count.       */
+      size = unwind.opcode_count + 1;
+    }
 
   size = (size + 3) >> 2;
   if (size > 0xff)
@@ -19909,6 +20865,8 @@ create_unwind_entry (int have_data)
 
   /* Allocate the table entry. */
   ptr = frag_more ((size << 2) + 4);
+  /* PR 13449: Zero the table entries in case some of them are not used.  */
+  memset (ptr, 0, (size << 2) + 4);
   where = frag_now_fix () - ((size << 2) + 4);
 
   switch (unwind.personality_index)
@@ -19923,7 +20881,7 @@ create_unwind_entry (int have_data)
       ptr += 4;
 
       /* Set the first byte to the number of additional words. */
-      data = size - 1;
+      data = size > 0 ? size - 1 : 0;
       n = 3;
       break;
 
@@ -20437,7 +21395,7 @@ encode_thumb2_b_bl_offset (char * buf, offsetT value)
   I1 = (value >> 23) & 0x01;
   I2 = (value >> 22) & 0x01;
   hi = (value >> 12) & 0x3ff;
-  lo = (value >> 1) & 0x7ff; 
+  lo = (value >> 1) & 0x7ff;
   newval   = md_chars_to_number (buf, THUMB_SIZE);
   newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
   newval  |= (S << 10) | hi;
@@ -20513,13 +21471,22 @@ md_apply_fix (fixS *  fixP,
            }
        }
 
-      newimm = encode_arm_immediate (value);
       temp = md_chars_to_number (buf, INSN_SIZE);
 
-      /* If the instruction will fail, see if we can fix things up by
-        changing the opcode.  */
-      if (newimm == (unsigned int) FAIL
-         && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
+      /* If the offset is negative, we should use encoding A2 for ADR.  */
+      if ((temp & 0xfff0000) == 0x28f0000 && value < 0)
+       newimm = negate_data_op (&temp, value);
+      else
+       {
+         newimm = encode_arm_immediate (value);
+
+         /* If the instruction will fail, see if we can fix things up by
+            changing the opcode.  */
+         if (newimm == (unsigned int) FAIL)
+           newimm = negate_data_op (&temp, value);
+       }
+
+      if (newimm == (unsigned int) FAIL)
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
                        _("invalid constant (%lx) after fixup"),
@@ -20554,7 +21521,7 @@ md_apply_fix (fixS *    fixP,
                break;
              }
          }
-       
+
        newimm = encode_arm_immediate (value);
        temp = md_chars_to_number (buf, INSN_SIZE);
 
@@ -20645,8 +21612,9 @@ md_apply_fix (fixS *    fixP,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("invalid literal constant: pool needs to be closer"));
          else
-           as_bad (_("bad immediate value for 8-bit offset (%ld)"),
-                   (long) value);
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("bad immediate value for 8-bit offset (%ld)"),
+                         (long) value);
          break;
        }
 
@@ -21148,28 +22116,28 @@ md_apply_fix (fixS *  fixP,
 
     thumb_bl_common:
 
-#ifdef OBJ_ELF
-       if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4 &&
-          fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
-        fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23;
-#endif
-
       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
        /* For a BLX instruction, make sure that the relocation is rounded up
           to a word boundary.  This follows the semantics of the instruction
           which specifies that bit 1 of the target address will come from bit
           1 of the base address.  */
-       value = (value + 1) & ~ 1;
-
-       if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
-        {
-          if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2)))
-            as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
-          else if ((value & ~0x1ffffff)
-                   && ((value & ~0x1ffffff) != ~0x1ffffff))
-            as_bad_where (fixP->fx_file, fixP->fx_line,
-                          _("Thumb2 branch out of range"));
-        }
+       value = (value + 3) & ~ 3;
+
+#ifdef OBJ_ELF
+       if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4
+          && fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+        fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23;
+#endif
+
+      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
+       {
+         if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2)))
+           as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
+         else if ((value & ~0x1ffffff)
+                  && ((value & ~0x1ffffff) != ~0x1ffffff))
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("Thumb2 branch out of range"));
+       }
 
       if (fixP->fx_done || !seg->use_rela_p)
        encode_thumb2_b_bl_offset (buf, value);
@@ -22174,6 +23142,10 @@ elf32_arm_target_format (void)
   return (target_big_endian
          ? "elf32-bigarm-vxworks"
          : "elf32-littlearm-vxworks");
+#elif defined (TE_NACL)
+  return (target_big_endian
+         ? "elf32-bigarm-nacl"
+         : "elf32-littlearm-nacl");
 #else
   if (target_big_endian)
     return "elf32-bigarm";
@@ -22417,8 +23389,16 @@ md_begin (void)
     hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template_name,
                 (void *) (barrier_opt_names + i));
 #ifdef OBJ_ELF
-  for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++)
-    hash_insert (arm_reloc_hsh, reloc_names[i].name, (void *) (reloc_names + i));
+  for (i = 0; i < ARRAY_SIZE (reloc_names); i++)
+    {
+      struct reloc_entry * entry = reloc_names + i;
+
+      if (arm_is_eabi() && entry->reloc == BFD_RELOC_ARM_PLT32)
+       /* This makes encode_branch() use the EABI versions of this relocation.  */
+       entry->reloc = BFD_RELOC_UNUSED;
+
+      hash_insert (arm_reloc_hsh, entry->name, (void *) entry);
+    }
 #endif
 
   set_constant_flonums ();
@@ -22851,6 +23831,7 @@ const struct arm_legacy_option_table arm_legacy_opts[] =
 struct arm_cpu_option_table
 {
   char *name;
+  size_t name_len;
   const arm_feature_set        value;
   /* For some CPUs we assume an FPU unless the user explicitly sets
      -mfpu=... */
@@ -22862,208 +23843,245 @@ struct arm_cpu_option_table
 
 /* 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 }
 static const struct arm_cpu_option_table arm_cpus[] =
 {
-  {"all",              ARM_ANY,         FPU_ARCH_FPA,    NULL},
-  {"arm1",             ARM_ARCH_V1,     FPU_ARCH_FPA,    NULL},
-  {"arm2",             ARM_ARCH_V2,     FPU_ARCH_FPA,    NULL},
-  {"arm250",           ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL},
-  {"arm3",             ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL},
-  {"arm6",             ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm60",            ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm600",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm610",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm620",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7",             ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7m",            ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL},
-  {"arm7d",            ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7dm",           ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL},
-  {"arm7di",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7dmi",          ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL},
-  {"arm70",            ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm700",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm700i",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm710",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm710t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm720",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm720t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm740t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm710c",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7100",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7500",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7500fe",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7t",            ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm7tdmi",         ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm7tdmi-s",       ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm8",             ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"arm810",           ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm",                ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm1",       ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm110",     ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm1100",    ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm1110",    ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"arm9",             ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm920",           ARM_ARCH_V4T,    FPU_ARCH_FPA,    "ARM920T"},
-  {"arm920t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm922t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm940t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm9tdmi",         ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"fa526",            ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"fa626",            ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
+  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),
   /* For V5 or later processors we default to using VFP; but the user
      should really set the FPU type explicitly.         */
-  {"arm9e-r0",         ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
-  {"arm9e",            ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm926ej",         ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"},
-  {"arm926ejs",                ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"},
-  {"arm926ej-s",       ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL},
-  {"arm946e-r0",       ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
-  {"arm946e",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM946E-S"},
-  {"arm946e-s",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm966e-r0",       ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
-  {"arm966e",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM966E-S"},
-  {"arm966e-s",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm968e-s",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm10t",           ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL},
-  {"arm10tdmi",                ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL},
-  {"arm10e",           ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1020",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM1020E"},
-  {"arm1020t",         ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL},
-  {"arm1020e",         ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1022e",         ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1026ejs",       ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM1026EJ-S"},
-  {"arm1026ej-s",      ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL},
-  {"fa606te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fa616te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fa626te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fmp626",           ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fa726te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1136js",                ARM_ARCH_V6,     FPU_NONE,        "ARM1136J-S"},
-  {"arm1136j-s",       ARM_ARCH_V6,     FPU_NONE,        NULL},
-  {"arm1136jfs",       ARM_ARCH_V6,     FPU_ARCH_VFP_V2, "ARM1136JF-S"},
-  {"arm1136jf-s",      ARM_ARCH_V6,     FPU_ARCH_VFP_V2, NULL},
-  {"mpcore",           ARM_ARCH_V6K,    FPU_ARCH_VFP_V2, "MPCore"},
-  {"mpcorenovfp",      ARM_ARCH_V6K,    FPU_NONE,        "MPCore"},
-  {"arm1156t2-s",      ARM_ARCH_V6T2,   FPU_NONE,        NULL},
-  {"arm1156t2f-s",     ARM_ARCH_V6T2,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1176jz-s",      ARM_ARCH_V6ZK,   FPU_NONE,        NULL},
-  {"arm1176jzf-s",     ARM_ARCH_V6ZK,   FPU_ARCH_VFP_V2, NULL},
-  {"cortex-a5",                ARM_ARCH_V7A_MP_SEC, 
-                                        FPU_NONE,        "Cortex-A5"},
-  {"cortex-a8",                ARM_ARCH_V7A_SEC,
-                                        ARM_FEATURE (0, FPU_VFP_V3
+  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_V6ZK,   FPU_NONE,        NULL),
+  ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6ZK,   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_V7A_IDIV_MP_SEC_VIRT,
+                                                FPU_ARCH_NEON_VFP_V4,
+                                                                 "Cortex-A7"),
+  ARM_CPU_OPT ("cortex-a8",    ARM_ARCH_V7A_SEC,
+                                                ARM_FEATURE (0, FPU_VFP_V3
                                                         | FPU_NEON_EXT_V1),
-                                                          "Cortex-A8"},
-  {"cortex-a9",                ARM_ARCH_V7A_MP_SEC,
-                                        ARM_FEATURE (0, FPU_VFP_V3
+                                                                 "Cortex-A8"),
+  ARM_CPU_OPT ("cortex-a9",    ARM_ARCH_V7A_MP_SEC,
+                                                ARM_FEATURE (0, FPU_VFP_V3
                                                         | FPU_NEON_EXT_V1),
-                                                          "Cortex-A9"},
-  {"cortex-a15",       ARM_ARCH_V7A_IDIV_MP_SEC_VIRT,
-                                        FPU_ARCH_NEON_VFP_V4,
-                                                          "Cortex-A15"},
-  {"cortex-r4",                ARM_ARCH_V7R,    FPU_NONE,        "Cortex-R4"},
-  {"cortex-r4f",       ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,
-                                                         "Cortex-R4F"},
-  {"cortex-r5",                ARM_ARCH_V7R_IDIV,
-                                        FPU_NONE,        "Cortex-R5"},
-  {"cortex-m4",                ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M4"},
-  {"cortex-m3",                ARM_ARCH_V7M,    FPU_NONE,        "Cortex-M3"},
-  {"cortex-m1",                ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M1"},
-  {"cortex-m0",                ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0"},
+                                                                 "Cortex-A9"),
+  ARM_CPU_OPT ("cortex-a15",   ARM_ARCH_V7A_IDIV_MP_SEC_VIRT,
+                                                FPU_ARCH_NEON_VFP_V4,
+                                                                 "Cortex-A15"),
+  ARM_CPU_OPT ("cortex-a53",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A53"),
+  ARM_CPU_OPT ("cortex-a57",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A57"),
+  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-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+"),
   /* ??? XSCALE is really an architecture.  */
-  {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
+  ARM_CPU_OPT ("xscale",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
   /* ??? iwmmxt is not a processor.  */
-  {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
-  {"iwmmxt2",          ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
-  {"i80200",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
+  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 */
-  {"ep9312",   ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
-  {NULL,               ARM_ARCH_NONE,   ARM_ARCH_NONE, NULL}
+  ARM_CPU_OPT ("ep9312",       ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK),
+                                                FPU_ARCH_MAVERICK, "ARM920T"),
+  /* Marvell processors.  */
+  ARM_CPU_OPT ("marvell-pj4",   ARM_FEATURE (ARM_AEXT_V7A | ARM_EXT_MP | ARM_EXT_SEC, 0),
+                                               FPU_ARCH_VFP_V3D16, NULL),
+
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
 };
+#undef ARM_CPU_OPT
 
 struct arm_arch_option_table
 {
   char *name;
+  size_t name_len;
   const arm_feature_set        value;
   const arm_feature_set        default_fpu;
 };
 
 /* 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 }
 static const struct arm_arch_option_table arm_archs[] =
 {
-  {"all",              ARM_ANY,         FPU_ARCH_FPA},
-  {"armv1",            ARM_ARCH_V1,     FPU_ARCH_FPA},
-  {"armv2",            ARM_ARCH_V2,     FPU_ARCH_FPA},
-  {"armv2a",           ARM_ARCH_V2S,    FPU_ARCH_FPA},
-  {"armv2s",           ARM_ARCH_V2S,    FPU_ARCH_FPA},
-  {"armv3",            ARM_ARCH_V3,     FPU_ARCH_FPA},
-  {"armv3m",           ARM_ARCH_V3M,    FPU_ARCH_FPA},
-  {"armv4",            ARM_ARCH_V4,     FPU_ARCH_FPA},
-  {"armv4xm",          ARM_ARCH_V4xM,   FPU_ARCH_FPA},
-  {"armv4t",           ARM_ARCH_V4T,    FPU_ARCH_FPA},
-  {"armv4txm",         ARM_ARCH_V4TxM,  FPU_ARCH_FPA},
-  {"armv5",            ARM_ARCH_V5,     FPU_ARCH_VFP},
-  {"armv5t",           ARM_ARCH_V5T,    FPU_ARCH_VFP},
-  {"armv5txm",         ARM_ARCH_V5TxM,  FPU_ARCH_VFP},
-  {"armv5te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP},
-  {"armv5texp",                ARM_ARCH_V5TExP, FPU_ARCH_VFP},
-  {"armv5tej",         ARM_ARCH_V5TEJ,  FPU_ARCH_VFP},
-  {"armv6",            ARM_ARCH_V6,     FPU_ARCH_VFP},
-  {"armv6j",           ARM_ARCH_V6,     FPU_ARCH_VFP},
-  {"armv6k",           ARM_ARCH_V6K,    FPU_ARCH_VFP},
-  {"armv6z",           ARM_ARCH_V6Z,    FPU_ARCH_VFP},
-  {"armv6zk",          ARM_ARCH_V6ZK,   FPU_ARCH_VFP},
-  {"armv6t2",          ARM_ARCH_V6T2,   FPU_ARCH_VFP},
-  {"armv6kt2",         ARM_ARCH_V6KT2,  FPU_ARCH_VFP},
-  {"armv6zt2",         ARM_ARCH_V6ZT2,  FPU_ARCH_VFP},
-  {"armv6zkt2",                ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
-  {"armv6-m",          ARM_ARCH_V6M,    FPU_ARCH_VFP},
-  {"armv6s-m",         ARM_ARCH_V6SM,   FPU_ARCH_VFP},
-  {"armv7",            ARM_ARCH_V7,     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_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 ("armv6zk",     ARM_ARCH_V6ZK,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6t2",     ARM_ARCH_V6T2,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6kt2",    ARM_ARCH_V6KT2,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zt2",    ARM_ARCH_V6ZT2,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zkt2",   ARM_ARCH_V6ZKT2, FPU_ARCH_VFP),
+  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),
   /* The official spelling of the ARMv7 profile variants is the dashed form.
      Accept the non-dashed form for compatibility with old toolchains.  */
-  {"armv7a",           ARM_ARCH_V7A,    FPU_ARCH_VFP},
-  {"armv7r",           ARM_ARCH_V7R,    FPU_ARCH_VFP},
-  {"armv7m",           ARM_ARCH_V7M,    FPU_ARCH_VFP},
-  {"armv7-a",          ARM_ARCH_V7A,    FPU_ARCH_VFP},
-  {"armv7-r",          ARM_ARCH_V7R,    FPU_ARCH_VFP},
-  {"armv7-m",          ARM_ARCH_V7M,    FPU_ARCH_VFP},
-  {"armv7e-m",         ARM_ARCH_V7EM,   FPU_ARCH_VFP},
-  {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP},
-  {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
-  {"iwmmxt2",          ARM_ARCH_IWMMXT2,FPU_ARCH_VFP},
-  {NULL,               ARM_ARCH_NONE,   ARM_ARCH_NONE}
+  ARM_ARCH_OPT ("armv7a",      ARM_ARCH_V7A,    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-a",     ARM_ARCH_V8A,    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 }
 };
+#undef ARM_ARCH_OPT
 
 /* ISA extensions in the co-processor and main instruction set space.  */
 struct arm_option_extension_value_table
 {
   char *name;
+  size_t name_len;
   const arm_feature_set value;
   const arm_feature_set allowed_archs;
 };
 
 /* The following table must be in alphabetical order with a NULL last entry.
    */
+#define ARM_EXT_OPT(N, V, AA) { N, sizeof (N) - 1, V, AA }
 static const struct arm_option_extension_value_table arm_extensions[] =
 {
-  {"idiv",     ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0),
-                                  ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)},
-  {"iwmmxt",   ARM_FEATURE (0, ARM_CEXT_IWMMXT),       ARM_ANY},
-  {"iwmmxt2",  ARM_FEATURE (0, ARM_CEXT_IWMMXT2),      ARM_ANY},
-  {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK),     ARM_ANY},
-  {"mp",       ARM_FEATURE (ARM_EXT_MP, 0),
-                    ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)},
-  {"os",       ARM_FEATURE (ARM_EXT_OS, 0),
-                                  ARM_FEATURE (ARM_EXT_V6M, 0)},
-  {"sec",      ARM_FEATURE (ARM_EXT_SEC, 0),
-                    ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)},
-  {"virt",     ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV | ARM_EXT_DIV, 0),
-                                  ARM_FEATURE (ARM_EXT_V7A, 0)},
-  {"xscale",   ARM_FEATURE (0, ARM_CEXT_XSCALE),       ARM_ANY},
-  {NULL,       ARM_ARCH_NONE,                    ARM_ARCH_NONE}
+  ARM_EXT_OPT ("crc",  ARCH_CRC_ARMV8, ARM_FEATURE (ARM_EXT_V8, 0)),
+  ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                  ARM_FEATURE (ARM_EXT_V8, 0)),
+  ARM_EXT_OPT ("fp",     FPU_ARCH_VFP_ARMV8,
+                                  ARM_FEATURE (ARM_EXT_V8, 0)),
+  ARM_EXT_OPT ("idiv", ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0),
+                                  ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)),
+  ARM_EXT_OPT ("iwmmxt",ARM_FEATURE (0, ARM_CEXT_IWMMXT),      ARM_ANY),
+  ARM_EXT_OPT ("iwmmxt2",
+                       ARM_FEATURE (0, ARM_CEXT_IWMMXT2),      ARM_ANY),
+  ARM_EXT_OPT ("maverick",
+                        ARM_FEATURE (0, ARM_CEXT_MAVERICK),    ARM_ANY),
+  ARM_EXT_OPT ("mp",   ARM_FEATURE (ARM_EXT_MP, 0),
+                                  ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)),
+  ARM_EXT_OPT ("simd",   FPU_ARCH_NEON_VFP_ARMV8,
+                                  ARM_FEATURE (ARM_EXT_V8, 0)),
+  ARM_EXT_OPT ("os",   ARM_FEATURE (ARM_EXT_OS, 0),
+                                  ARM_FEATURE (ARM_EXT_V6M, 0)),
+  ARM_EXT_OPT ("sec",  ARM_FEATURE (ARM_EXT_SEC, 0),
+                                  ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)),
+  ARM_EXT_OPT ("virt", ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV
+                                    | ARM_EXT_DIV, 0),
+                                  ARM_FEATURE (ARM_EXT_V7A, 0)),
+  ARM_EXT_OPT ("xscale",ARM_FEATURE (0, ARM_CEXT_XSCALE),      ARM_ANY),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
+#undef ARM_EXT_OPT
 
 /* ISA floating-point and Advanced SIMD extensions.  */
 struct arm_option_fpu_value_table
@@ -23110,6 +24128,10 @@ static const struct arm_option_fpu_value_table arm_fpus[] =
   {"vfpv4-d16",                FPU_ARCH_VFP_V4D16},
   {"fpv4-sp-d16",      FPU_ARCH_VFP_V4_SP_D16},
   {"neon-vfpv4",       FPU_ARCH_NEON_VFP_V4},
+  {"fp-armv8",         FPU_ARCH_VFP_ARMV8},
+  {"neon-fp-armv8",    FPU_ARCH_NEON_VFP_ARMV8},
+  {"crypto-neon-fp-armv8",
+                       FPU_ARCH_CRYPTO_NEON_VFP_ARMV8},
   {NULL,               ARM_ARCH_NONE}
 };
 
@@ -23147,16 +24169,16 @@ struct arm_long_option_table
 };
 
 static bfd_boolean
-arm_parse_extension (char * str, const arm_feature_set **opt_p)
+arm_parse_extension (char *str, const arm_feature_set **opt_p)
 {
   arm_feature_set *ext_set = (arm_feature_set *)
       xmalloc (sizeof (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 
+     extensions being added before being removed.  We achieve this by having
+     the global ARM_EXTENSIONS table in alphabetical order, and using the
      ADDING_VALUE variable to indicate whether we are adding an extension (1)
-     or removing it (0) and only allowing it to change in the order 
+     or removing it (0) and only allowing it to change in the order
      -1 -> 1 -> 0.  */
   const struct arm_option_extension_value_table * opt = NULL;
   int adding_value = -1;
@@ -23167,8 +24189,8 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 
   while (str != NULL && *str != 0)
     {
-      char * ext;
-      size_t optlen;
+      char *ext;
+      size_t len;
 
       if (*str != '+')
        {
@@ -23180,12 +24202,11 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
       ext = strchr (str, '+');
 
       if (ext != NULL)
-       optlen = ext - str;
+       len = ext - str;
       else
-       optlen = strlen (str);
+       len = strlen (str);
 
-      if (optlen >= 2
-         && strncmp (str, "no", 2) == 0)
+      if (len >= 2 && strncmp (str, "no", 2) == 0)
        {
          if (adding_value != 0)
            {
@@ -23193,10 +24214,10 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
              opt = arm_extensions;
            }
 
-         optlen -= 2;
+         len -= 2;
          str += 2;
        }
-      else if (optlen > 0)
+      else if (len > 0)
        {
          if (adding_value == -1)
            {
@@ -23211,7 +24232,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
            }
        }
 
-      if (optlen == 0)
+      if (len == 0)
        {
          as_bad (_("missing architectural extension"));
          return FALSE;
@@ -23222,8 +24243,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 
       /* Scan over the options table trying to find an exact match. */
       for (; opt->name != NULL; opt++)
-       if (strncmp (opt->name, str, optlen) == 0
-           && strlen (opt->name) == optlen)
+       if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
          {
            /* Check we can apply the extension to this architecture.  */
            if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs))
@@ -23247,7 +24267,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
             alphabetical order, or because it does not exist?  */
 
          for (opt = arm_extensions; opt->name != NULL; opt++)
-           if (strncmp (opt->name, str, optlen) == 0)
+           if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
              break;
 
          if (opt->name == NULL)
@@ -23272,25 +24292,25 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 }
 
 static bfd_boolean
-arm_parse_cpu (char * str)
+arm_parse_cpu (char *str)
 {
-  const struct arm_cpu_option_table * opt;
-  char * ext = strchr (str, '+');
-  int optlen;
+  const struct arm_cpu_option_table *opt;
+  char *ext = strchr (str, '+');
+  size_t len;
 
   if (ext != NULL)
-    optlen = ext - str;
+    len = ext - str;
   else
-    optlen = strlen (str);
+    len = strlen (str);
 
-  if (optlen == 0)
+  if (len == 0)
     {
       as_bad (_("missing cpu name `%s'"), str);
       return FALSE;
     }
 
   for (opt = arm_cpus; opt->name != NULL; opt++)
-    if (strncmp (opt->name, str, optlen) == 0)
+    if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
       {
        mcpu_cpu_opt = &opt->value;
        mcpu_fpu_opt = &opt->default_fpu;
@@ -23298,9 +24318,9 @@ arm_parse_cpu (char * str)
          strcpy (selected_cpu_name, opt->canonical_name);
        else
          {
-           int i;
+           size_t i;
 
-           for (i = 0; i < optlen; i++)
+           for (i = 0; i < len; i++)
              selected_cpu_name[i] = TOUPPER (opt->name[i]);
            selected_cpu_name[i] = 0;
          }
@@ -23316,25 +24336,25 @@ arm_parse_cpu (char * str)
 }
 
 static bfd_boolean
-arm_parse_arch (char * str)
+arm_parse_arch (char *str)
 {
   const struct arm_arch_option_table *opt;
   char *ext = strchr (str, '+');
-  int optlen;
+  size_t len;
 
   if (ext != NULL)
-    optlen = ext - str;
+    len = ext - str;
   else
-    optlen = strlen (str);
+    len = strlen (str);
 
-  if (optlen == 0)
+  if (len == 0)
     {
       as_bad (_("missing architecture name `%s'"), str);
       return FALSE;
     }
 
   for (opt = arm_archs; opt->name != NULL; opt++)
-    if (strncmp (opt->name, str, optlen) == 0)
+    if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
       {
        march_cpu_opt = &opt->value;
        march_fpu_opt = &opt->default_fpu;
@@ -23586,9 +24606,10 @@ static const cpu_arch_ver_table cpu_arch_ver[] =
     {11, ARM_ARCH_V6M},
     {12, ARM_ARCH_V6SM},
     {8, ARM_ARCH_V6T2},
-    {10, ARM_ARCH_V7A},
+    {10, ARM_ARCH_V7A_IDIV_MP_SEC_VIRT},
     {10, ARM_ARCH_V7R},
     {10, ARM_ARCH_V7M},
+    {14, ARM_ARCH_V8A},
     {0, ARM_ARCH_NONE}
 };
 
@@ -23616,7 +24637,9 @@ static void
 aeabi_set_public_attributes (void)
 {
   int arch;
+  char profile;
   int virt_sec = 0;
+  int fp16_optional = 0;
   arm_feature_set flags;
   arm_feature_set tmp;
   const cpu_arch_ver_table *p;
@@ -23626,7 +24649,14 @@ aeabi_set_public_attributes (void)
   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);
-  /*Allow the user to override the reported architecture.  */
+
+  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any))
+    ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v1);
+
+  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_any))
+    ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t);
+
+  /* Allow the user to override the reported architecture.  */
   if (object_arch)
     {
       ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
@@ -23686,11 +24716,16 @@ aeabi_set_public_attributes (void)
 
   /* Tag_CPU_arch_profile.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
-    aeabi_set_attribute_int (Tag_CPU_arch_profile, 'A');
+    profile = 'A';
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
-    aeabi_set_attribute_int (Tag_CPU_arch_profile, 'R');
+    profile = 'R';
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_m))
-    aeabi_set_attribute_int (Tag_CPU_arch_profile, 'M');
+    profile = 'M';
+  else
+    profile = '\0';
+
+  if (profile != '\0')
+    aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
 
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
@@ -23704,14 +24739,22 @@ aeabi_set_public_attributes (void)
        ARM_CPU_HAS_FEATURE (flags, arm_arch_t2) ? 2 : 1);
 
   /* Tag_VFP_arch.  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma))
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8))
+    aeabi_set_attribute_int (Tag_VFP_arch, 7);
+  else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma))
     aeabi_set_attribute_int (Tag_VFP_arch,
                             ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32)
                             ? 5 : 6);
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32))
-    aeabi_set_attribute_int (Tag_VFP_arch, 3);
+    {
+      fp16_optional = 1;
+      aeabi_set_attribute_int (Tag_VFP_arch, 3);
+    }
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v3xd))
-    aeabi_set_attribute_int (Tag_VFP_arch, 4);
+    {
+      aeabi_set_attribute_int (Tag_VFP_arch, 4);
+      fp16_optional = 1;
+    }
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v2))
     aeabi_set_attribute_int (Tag_VFP_arch, 2);
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1)
@@ -23730,22 +24773,43 @@ aeabi_set_public_attributes (void)
     aeabi_set_attribute_int (Tag_WMMX_arch, 1);
 
   /* Tag_Advanced_SIMD_arch (formerly Tag_NEON_arch).  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1))
-    aeabi_set_attribute_int
-      (Tag_Advanced_SIMD_arch, (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_fma)
-                               ? 2 : 1));
-  
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_armv8))
+    aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 3);
+  else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1))
+    {
+      if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_fma))
+       {
+         aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 2);
+       }
+      else
+       {
+         aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 1);
+         fp16_optional = 1;
+       }
+    }
+
   /* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch).  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16))
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16) && fp16_optional)
     aeabi_set_attribute_int (Tag_VFP_HP_extension, 1);
 
-  /* Tag_DIV_use.  */
-  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv))
-    aeabi_set_attribute_int (Tag_DIV_use, 2);
-  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_div))
+  /* Tag_DIV_use.
+
+     We set Tag_DIV_use to two when integer divide instructions have been used
+     in ARM state, or when Thumb integer divide instructions have been used,
+     but we have no architecture profile set, nor have we any ARM instructions.
+
+     For ARMv8 we set the tag to 0 as integer divide is implied by the base
+     architecture.
+
+     For new architectures we will have to check these tests.  */
+  gas_assert (arch <= TAG_CPU_ARCH_V8);
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v8))
     aeabi_set_attribute_int (Tag_DIV_use, 0);
-  else
-    aeabi_set_attribute_int (Tag_DIV_use, 1);
+  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv)
+          || (profile == '\0'
+              && ARM_CPU_HAS_FEATURE (flags, arm_ext_div)
+              && !ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any)))
+    aeabi_set_attribute_int (Tag_DIV_use, 2);
 
   /* Tag_MP_extension_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_mp))
@@ -23800,6 +24864,7 @@ s_arm_cpu (int ignored ATTRIBUTE_UNUSED)
            int i;
            for (i = 0; opt->name[i]; i++)
              selected_cpu_name[i] = TOUPPER (opt->name[i]);
+
            selected_cpu_name[i] = 0;
          }
        ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);