[AArch64][SVE 22/32] Add qualifiers for merging and zeroing predication
[deliverable/binutils-gdb.git] / gas / config / tc-aarch64.c
index dec50c757cae65ba24ee016a56a381d1209ab701..f87726244e0e582ebfd5ad53a2a13b45908c3392 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-aarch64.c -- Assemble for the AArch64 ISA
 
-   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+   Copyright (C) 2009-2016 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GAS.
@@ -76,23 +76,26 @@ static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_LP64;
 #define ilp32_p                (aarch64_abi == AARCH64_ABI_ILP32)
 #endif
 
-enum neon_el_type
+enum vector_el_type
 {
   NT_invtype = -1,
   NT_b,
   NT_h,
   NT_s,
   NT_d,
-  NT_q
+  NT_q,
+  NT_zero,
+  NT_merge
 };
 
-/* Bits for DEFINED field in neon_type_el.  */
-#define NTA_HASTYPE  1
-#define NTA_HASINDEX 2
+/* Bits for DEFINED field in vector_type_el.  */
+#define NTA_HASTYPE     1
+#define NTA_HASINDEX    2
+#define NTA_HASVARWIDTH 4
 
-struct neon_type_el
+struct vector_type_el
 {
-  enum neon_el_type type;
+  enum vector_el_type type;
   unsigned char defined;
   unsigned width;
   int64_t index;
@@ -247,15 +250,6 @@ struct reloc_entry
   bfd_reloc_code_real_type reloc;
 };
 
-/* Structure for a hash table entry for a register.  */
-typedef struct
-{
-  const char *name;
-  unsigned char number;
-  unsigned char type;
-  unsigned char builtin;
-} reg_entry;
-
 /* Macros to define the register types and masks for the purpose
    of parsing.  */
 
@@ -274,16 +268,24 @@ typedef struct
   BASIC_REG_TYPE(FP_Q) /* q[0-31] */   \
   BASIC_REG_TYPE(CN)   /* c[0-7]  */   \
   BASIC_REG_TYPE(VN)   /* v[0-31] */   \
-  /* Typecheck: any 64-bit int reg         (inc SP exc XZR) */         \
+  BASIC_REG_TYPE(ZN)   /* z[0-31] */   \
+  BASIC_REG_TYPE(PN)   /* p[0-15] */   \
+  /* Typecheck: any 64-bit int reg         (inc SP exc XZR).  */       \
   MULTI_REG_TYPE(R64_SP, REG_TYPE(R_64) | REG_TYPE(SP_64))             \
-  /* Typecheck: any int                    (inc {W}SP inc [WX]ZR) */   \
+  /* Typecheck: x[0-30], w[0-30] or [xw]zr.  */                                \
+  MULTI_REG_TYPE(R_Z, REG_TYPE(R_32) | REG_TYPE(R_64)                  \
+                | REG_TYPE(Z_32) | REG_TYPE(Z_64))                     \
+  /* Typecheck: x[0-30], w[0-30] or {w}sp.  */                         \
+  MULTI_REG_TYPE(R_SP, REG_TYPE(R_32) | REG_TYPE(R_64)                 \
+                | REG_TYPE(SP_32) | REG_TYPE(SP_64))                   \
+  /* Typecheck: any int                    (inc {W}SP inc [WX]ZR).  */ \
   MULTI_REG_TYPE(R_Z_SP, REG_TYPE(R_32) | REG_TYPE(R_64)               \
                 | REG_TYPE(SP_32) | REG_TYPE(SP_64)                    \
                 | REG_TYPE(Z_32) | REG_TYPE(Z_64))                     \
   /* Typecheck: any [BHSDQ]P FP.  */                                   \
   MULTI_REG_TYPE(BHSDQ, REG_TYPE(FP_B) | REG_TYPE(FP_H)                        \
                 | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q))    \
-  /* Typecheck: any int or [BHSDQ]P FP or V reg (exc SP inc [WX]ZR)  */        \
+  /* Typecheck: any int or [BHSDQ]P FP or V reg (exc SP inc [WX]ZR).  */ \
   MULTI_REG_TYPE(R_Z_BHSDQ_V, REG_TYPE(R_32) | REG_TYPE(R_64)          \
                 | REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN)       \
                 | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
@@ -301,7 +303,7 @@ typedef struct
 #define MULTI_REG_TYPE(T,V)    BASIC_REG_TYPE(T)
 
 /* Register type enumerators.  */
-typedef enum
+typedef enum aarch64_reg_type_
 {
   /* A list of REG_TYPE_*.  */
   AARCH64_REG_TYPES
@@ -314,6 +316,15 @@ typedef enum
 #undef MULTI_REG_TYPE
 #define MULTI_REG_TYPE(T,V)    V,
 
+/* Structure for a hash table entry for a register.  */
+typedef struct
+{
+  const char *name;
+  unsigned char number;
+  ENUM_BITFIELD (aarch64_reg_type_) type : 8;
+  unsigned char builtin;
+} reg_entry;
+
 /* Values indexed by aarch64_reg_type to assist the type checking.  */
 static const unsigned reg_type_masks[] =
 {
@@ -344,6 +355,15 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
     case REG_TYPE_R_N:
       msg = N_("integer register expected");
       break;
+    case REG_TYPE_R64_SP:
+      msg = N_("64-bit integer or SP register expected");
+      break;
+    case REG_TYPE_R_Z:
+      msg = N_("integer or zero register expected");
+      break;
+    case REG_TYPE_R_SP:
+      msg = N_("integer or SP register expected");
+      break;
     case REG_TYPE_R_Z_SP:
       msg = N_("integer, zero or SP register expected");
       break;
@@ -378,6 +398,12 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
     case REG_TYPE_VN:          /* any V reg  */
       msg = N_("vector register expected");
       break;
+    case REG_TYPE_ZN:
+      msg = N_("SVE vector register expected");
+      break;
+    case REG_TYPE_PN:
+      msg = N_("SVE predicate register expected");
+      break;
     default:
       as_fatal (_("invalid register type %d"), reg_type);
     }
@@ -390,9 +416,6 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
 /* Instructions take 4 bytes in the object file.  */
 #define INSN_SIZE      4
 
-/* Define some common error messages.  */
-#define BAD_SP          _("SP not allowed here")
-
 static struct hash_control *aarch64_ops_hsh;
 static struct hash_control *aarch64_cond_hsh;
 static struct hash_control *aarch64_shift_hsh;
@@ -406,6 +429,7 @@ static struct hash_control *aarch64_reg_hsh;
 static struct hash_control *aarch64_barrier_opt_hsh;
 static struct hash_control *aarch64_nzcv_hsh;
 static struct hash_control *aarch64_pldop_hsh;
+static struct hash_control *aarch64_hint_opt_hsh;
 
 /* Stuff needed to resolve the label ambiguity
    As:
@@ -572,7 +596,7 @@ my_get_expression (expressionS * ep, char **str, int prefix_mode,
    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
    returned, or NULL on OK.  */
 
-char *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
   return ieee_md_atof (type, litP, sizeP, target_big_endian);
@@ -670,93 +694,68 @@ parse_reg (char **ccp)
 static bfd_boolean
 aarch64_check_reg_type (const reg_entry *reg, aarch64_reg_type type)
 {
-  if (reg->type == type)
-    return TRUE;
-
-  switch (type)
-    {
-    case REG_TYPE_R64_SP:      /* 64-bit integer reg (inc SP exc XZR).  */
-    case REG_TYPE_R_Z_SP:      /* Integer reg (inc {X}SP inc [WX]ZR).  */
-    case REG_TYPE_R_Z_BHSDQ_V: /* Any register apart from Cn.  */
-    case REG_TYPE_BHSDQ:       /* Any [BHSDQ]P FP or SIMD scalar register.  */
-    case REG_TYPE_VN:          /* Vector register.  */
-      gas_assert (reg->type < REG_TYPE_MAX && type < REG_TYPE_MAX);
-      return ((reg_type_masks[reg->type] & reg_type_masks[type])
-             == reg_type_masks[reg->type]);
-    default:
-      as_fatal ("unhandled type %d", type);
-      abort ();
-    }
+  return (reg_type_masks[type] & (1 << reg->type)) != 0;
 }
 
-/* Parse a register and return PARSE_FAIL if the register is not of type R_Z_SP.
-   Return the register number otherwise.  *ISREG32 is set to one if the
-   register is 32-bit wide; *ISREGZERO is set to one if the register is
-   of type Z_32 or Z_64.
+/* Try to parse a base or offset register.  Return the register entry
+   on success, setting *QUALIFIER to the register qualifier.  Return null
+   otherwise.
+
    Note that this function does not issue any diagnostics.  */
 
-static int
-aarch64_reg_parse_32_64 (char **ccp, int reject_sp, int reject_rz,
-                        int *isreg32, int *isregzero)
+static const reg_entry *
+aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
 {
   char *str = *ccp;
   const reg_entry *reg = parse_reg (&str);
 
   if (reg == NULL)
-    return PARSE_FAIL;
-
-  if (! aarch64_check_reg_type (reg, REG_TYPE_R_Z_SP))
-    return PARSE_FAIL;
+    return NULL;
 
   switch (reg->type)
     {
+    case REG_TYPE_R_32:
     case REG_TYPE_SP_32:
-    case REG_TYPE_SP_64:
-      if (reject_sp)
-       return PARSE_FAIL;
-      *isreg32 = reg->type == REG_TYPE_SP_32;
-      *isregzero = 0;
+    case REG_TYPE_Z_32:
+      *qualifier = AARCH64_OPND_QLF_W;
       break;
-    case REG_TYPE_R_32:
+
     case REG_TYPE_R_64:
-      *isreg32 = reg->type == REG_TYPE_R_32;
-      *isregzero = 0;
-      break;
-    case REG_TYPE_Z_32:
+    case REG_TYPE_SP_64:
     case REG_TYPE_Z_64:
-      if (reject_rz)
-       return PARSE_FAIL;
-      *isreg32 = reg->type == REG_TYPE_Z_32;
-      *isregzero = 1;
+      *qualifier = AARCH64_OPND_QLF_X;
       break;
+
     default:
-      return PARSE_FAIL;
+      return NULL;
     }
 
   *ccp = str;
 
-  return reg->number;
+  return reg;
 }
 
-/* Parse the qualifier of a SIMD vector register or a SIMD vector element.
-   Fill in *PARSED_TYPE and return TRUE if the parsing succeeds;
-   otherwise return FALSE.
+/* Parse the qualifier of a vector register or vector element of type
+   REG_TYPE.  Fill in *PARSED_TYPE and return TRUE if the parsing
+   succeeds; otherwise return FALSE.
 
    Accept only one occurrence of:
-   8b 16b 4h 8h 2s 4s 1d 2d
+   8b 16b 2h 4h 8h 2s 4s 1d 2d
    b h s d q  */
 static bfd_boolean
-parse_neon_type_for_operand (struct neon_type_el *parsed_type, char **str)
+parse_vector_type_for_operand (aarch64_reg_type reg_type,
+                              struct vector_type_el *parsed_type, char **str)
 {
   char *ptr = *str;
   unsigned width;
   unsigned element_size;
-  enum neon_el_type type;
+  enum vector_el_type type;
 
   /* skip '.' */
+  gas_assert (*ptr == '.');
   ptr++;
 
-  if (!ISDIGIT (*ptr))
+  if (reg_type == REG_TYPE_ZN || reg_type == REG_TYPE_PN || !ISDIGIT (*ptr))
     {
       width = 0;
       goto elt_size;
@@ -802,7 +801,8 @@ elt_size:
        first_error (_("missing element size"));
       return FALSE;
     }
-  if (width != 0 && width * element_size != 64 && width * element_size != 128)
+  if (width != 0 && width * element_size != 64 && width * element_size != 128
+      && !(width == 2 && element_size == 16))
     {
       first_error_fmt (_
                       ("invalid element size %d and vector size combination %c"),
@@ -819,28 +819,35 @@ elt_size:
   return TRUE;
 }
 
-/* Parse a single type, e.g. ".8b", leading period included.
-   Only applicable to Vn registers.
+/* *STR contains an SVE zero/merge predication suffix.  Parse it into
+   *PARSED_TYPE and point *STR at the end of the suffix.  */
 
-   Return TRUE on success; otherwise return FALSE.  */
 static bfd_boolean
-parse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
+parse_predication_for_operand (struct vector_type_el *parsed_type, char **str)
 {
-  char *str = *ccp;
+  char *ptr = *str;
 
-  if (*str == '.')
+  /* Skip '/'.  */
+  gas_assert (*ptr == '/');
+  ptr++;
+  switch (TOLOWER (*ptr))
     {
-      if (! parse_neon_type_for_operand (vectype, &str))
-       {
-         first_error (_("vector type expected"));
-         return FALSE;
-       }
+    case 'z':
+      parsed_type->type = NT_zero;
+      break;
+    case 'm':
+      parsed_type->type = NT_merge;
+      break;
+    default:
+      if (*ptr != '\0' && *ptr != ',')
+       first_error_fmt (_("unexpected character `%c' in predication type"),
+                        *ptr);
+      else
+       first_error (_("missing predication type"));
+      return FALSE;
     }
-  else
-    return FALSE;
-
-  *ccp = str;
-
+  parsed_type->width = 0;
+  *str = ptr + 1;
   return TRUE;
 }
 
@@ -858,12 +865,12 @@ parse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
 
 static int
 parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
-                struct neon_type_el *typeinfo, bfd_boolean in_reg_list)
+                struct vector_type_el *typeinfo, bfd_boolean in_reg_list)
 {
   char *str = *ccp;
   const reg_entry *reg = parse_reg (&str);
-  struct neon_type_el atype;
-  struct neon_type_el parsetype;
+  struct vector_type_el atype;
+  struct vector_type_el parsetype;
   bfd_boolean is_typed_vecreg = FALSE;
 
   atype.defined = 0;
@@ -887,13 +894,31 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
     }
   type = reg->type;
 
-  if (type == REG_TYPE_VN
-      && parse_neon_operand_type (&parsetype, &str))
+  if ((type == REG_TYPE_VN || type == REG_TYPE_ZN || type == REG_TYPE_PN)
+      && (*str == '.' || (type == REG_TYPE_PN && *str == '/')))
     {
+      if (*str == '.')
+       {
+         if (!parse_vector_type_for_operand (type, &parsetype, &str))
+           return PARSE_FAIL;
+       }
+      else
+       {
+         if (!parse_predication_for_operand (&parsetype, &str))
+           return PARSE_FAIL;
+       }
+
       /* Register if of the form Vn.[bhsdq].  */
       is_typed_vecreg = TRUE;
 
-      if (parsetype.width == 0)
+      if (type == REG_TYPE_ZN || type == REG_TYPE_PN)
+       {
+         /* The width is always variable; we don't allow an integer width
+            to be specified.  */
+         gas_assert (parsetype.width == 0);
+         atype.defined |= NTA_HASVARWIDTH | NTA_HASTYPE;
+       }
+      else if (parsetype.width == 0)
        /* Expect index. In the new scheme we cannot have
           Vn.[bhsdq] represent a scalar. Therefore any
           Vn.[bhsdq] should have an index following it.
@@ -976,9 +1001,9 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
 
 static int
 aarch64_reg_parse (char **ccp, aarch64_reg_type type,
-                  aarch64_reg_type *rtype, struct neon_type_el *vectype)
+                  aarch64_reg_type *rtype, struct vector_type_el *vectype)
 {
-  struct neon_type_el atype;
+  struct vector_type_el atype;
   char *str = *ccp;
   int reg = parse_typed_reg (&str, type, rtype, &atype,
                             /*in_reg_list= */ FALSE);
@@ -995,7 +1020,7 @@ aarch64_reg_parse (char **ccp, aarch64_reg_type type,
 }
 
 static inline bfd_boolean
-eq_neon_type_el (struct neon_type_el e1, struct neon_type_el e2)
+eq_vector_type_el (struct vector_type_el e1, struct vector_type_el e2)
 {
   return
     e1.type == e2.type
@@ -1003,8 +1028,9 @@ eq_neon_type_el (struct neon_type_el e1, struct neon_type_el e2)
     && e1.width == e2.width && e1.index == e2.index;
 }
 
-/* This function parses the NEON register list.  On success, it returns
-   the parsed register list information in the following encoded format:
+/* This function parses a list of vector registers of type TYPE.
+   On success, it returns the parsed register list information in the
+   following encoded format:
 
    bit   18-22   |   13-17   |   7-11    |    2-6    |   0-1
        4th regno | 3rd regno | 2nd regno | 1st regno | num_of_reg
@@ -1024,11 +1050,12 @@ eq_neon_type_el (struct neon_type_el e1, struct neon_type_el e2)
    (by reg_list_valid_p).  */
 
 static int
-parse_neon_reg_list (char **ccp, struct neon_type_el *vectype)
+parse_vector_reg_list (char **ccp, aarch64_reg_type type,
+                      struct vector_type_el *vectype)
 {
   char *str = *ccp;
   int nb_regs;
-  struct neon_type_el typeinfo, typeinfo_first;
+  struct vector_type_el typeinfo, typeinfo_first;
   int val, val_range;
   int in_range;
   int ret_val;
@@ -1059,7 +1086,7 @@ parse_neon_reg_list (char **ccp, struct neon_type_el *vectype)
          str++;                /* skip over '-' */
          val_range = val;
        }
-      val = parse_typed_reg (&str, REG_TYPE_VN, NULL, &typeinfo,
+      val = parse_typed_reg (&str, type, NULL, &typeinfo,
                             /*in_reg_list= */ TRUE);
       if (val == PARSE_FAIL)
        {
@@ -1068,7 +1095,7 @@ parse_neon_reg_list (char **ccp, struct neon_type_el *vectype)
          continue;
        }
       /* reject [bhsd]n */
-      if (typeinfo.defined == 0)
+      if (type == REG_TYPE_VN && typeinfo.defined == 0)
        {
          set_first_syntax_error (_("invalid scalar register in list"));
          error = TRUE;
@@ -1093,7 +1120,7 @@ parse_neon_reg_list (char **ccp, struct neon_type_el *vectype)
          val_range = val;
          if (nb_regs == 0)
            typeinfo_first = typeinfo;
-         else if (! eq_neon_type_el (typeinfo_first, typeinfo))
+         else if (! eq_vector_type_el (typeinfo_first, typeinfo))
            {
              set_first_syntax_error
                (_("type mismatch in vector register list"));
@@ -1185,7 +1212,7 @@ insert_reg_alias (char *str, int number, aarch64_reg_type type)
     }
 
   name = xstrdup (str);
-  new = xmalloc (sizeof (reg_entry));
+  new = XNEW (reg_entry);
 
   new->name = name;
   new->number = number;
@@ -1239,9 +1266,7 @@ create_register_alias (char *newname, char *p)
   nlen = strlen (newname);
 #endif
 
-  nbuf = alloca (nlen + 1);
-  memcpy (nbuf, newname, nlen);
-  nbuf[nlen] = '\0';
+  nbuf = xmemdup0 (newname, nlen);
 
   /* Create aliases under the new name as stated; an all-lowercase
      version of the new name; and an all-uppercase version of the new
@@ -1263,7 +1288,10 @@ create_register_alias (char *newname, char *p)
             the artificial FOO alias because it has already been created by the
             first .req.  */
          if (insert_reg_alias (nbuf, old->number, old->type) == NULL)
-           return TRUE;
+           {
+             free (nbuf);
+             return TRUE;
+           }
        }
 
       for (p = nbuf; *p; p++)
@@ -1273,6 +1301,7 @@ create_register_alias (char *newname, char *p)
        insert_reg_alias (nbuf, old->number, old->type);
     }
 
+  free (nbuf);
   return TRUE;
 }
 
@@ -1460,17 +1489,17 @@ mapping_state (enum mstate state)
 {
   enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
 
-  if (mapstate == state)
-    /* The mapping symbol has already been emitted.
-       There is nothing else to do.  */
-    return;
-
   if (state == MAP_INSN)
     /* AArch64 instructions require 4-byte alignment.  When emitting
        instructions into any section, record the appropriate section
        alignment.  */
     record_alignment (now_seg, 2);
 
+  if (mapstate == state)
+    /* The mapping symbol has already been emitted.
+       There is nothing else to do.  */
+    return;
+
 #define TRANSITION(from, to) (mapstate == (from) && state == (to))
   if (TRANSITION (MAP_UNDEFINED, MAP_DATA) && !subseg_text_p (now_seg))
     /* Emit MAP_DATA within executable section in order.  Otherwise, it will be
@@ -1571,7 +1600,7 @@ find_or_make_literal_pool (int size)
   if (pool == NULL)
     {
       /* Create a new pool.  */
-      pool = xmalloc (sizeof (*pool));
+      pool = XNEW (literal_pool);
       if (!pool)
        return NULL;
 
@@ -1648,7 +1677,8 @@ add_to_lit_pool (expressionS *exp, int size)
        {
          /* PR 16688: Bignums are held in a single global array.  We must
             copy and preserve that value now, before it is overwritten.  */
-         pool->literals[entry].bignum = xmalloc (CHARS_PER_LITTLENUM * exp->X_add_number);
+         pool->literals[entry].bignum = XNEWVEC (LITTLENUM_TYPE,
+                                                 exp->X_add_number);
          memcpy (pool->literals[entry].bignum, generic_bignum,
                  CHARS_PER_LITTLENUM * exp->X_add_number);
        }
@@ -1731,13 +1761,13 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
       if (pool == NULL || pool->symbol == NULL || pool->next_free_entry == 0)
        continue;
 
-      mapping_state (MAP_DATA);
-
       /* Align pool as you have word accesses.
          Only make a frag if we have to.  */
       if (!need_pass_2)
        frag_align (align, 0, 0);
 
+      mapping_state (MAP_DATA);
+
       record_alignment (now_seg, align);
 
       sprintf (sym_name, "$$lit_\002%x", pool->id);
@@ -1858,10 +1888,9 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
   /* Sections are assumed to start aligned. In executable section, there is no
      MAP_DATA symbol pending. So we only align the address during
      MAP_DATA --> MAP_INSN transition.
-     For other sections, this is not guaranteed, align it anyway.  */
+     For other sections, this is not guaranteed.  */
   enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
-  if (!need_pass_2 && ((subseg_text_p (now_seg) && mapstate == MAP_DATA)
-                      || !subseg_text_p (now_seg)))
+  if (!need_pass_2 && subseg_text_p (now_seg) && mapstate == MAP_DATA)
     frag_align_code (2, 0);
 
 #ifdef OBJ_ELF
@@ -1893,6 +1922,21 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
 }
 
 #ifdef OBJ_ELF
+/* Emit BFD_RELOC_AARCH64_TLSDESC_ADD on the next ADD instruction.  */
+
+static void
+s_tlsdescadd (int ignored ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+
+  expression (&exp);
+  frag_grow (4);
+  fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 4, &exp, 0,
+                  BFD_RELOC_AARCH64_TLSDESC_ADD);
+
+  demand_empty_rest_of_line ();
+}
+
 /* Emit BFD_RELOC_AARCH64_TLSDESC_CALL on the next BLR instruction.  */
 
 static void
@@ -1912,6 +1956,21 @@ s_tlsdesccall (int ignored ATTRIBUTE_UNUSED)
 
   demand_empty_rest_of_line ();
 }
+
+/* Emit BFD_RELOC_AARCH64_TLSDESC_LDR on the next LDR instruction.  */
+
+static void
+s_tlsdescldr (int ignored ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+
+  expression (&exp);
+  frag_grow (4);
+  fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 4, &exp, 0,
+                  BFD_RELOC_AARCH64_TLSDESC_LDR);
+
+  demand_empty_rest_of_line ();
+}
 #endif /* OBJ_ELF */
 
 static void s_aarch64_arch (int);
@@ -1937,7 +1996,9 @@ const pseudo_typeS md_pseudo_table[] = {
   {"arch_extension", s_aarch64_arch_extension, 0},
   {"inst", s_aarch64_inst, 0},
 #ifdef OBJ_ELF
+  {"tlsdescadd", s_tlsdescadd, 0},
   {"tlsdesccall", s_tlsdesccall, 0},
+  {"tlsdescldr", s_tlsdescldr, 0},
   {"word", s_aarch64_elf_cons, 4},
   {"long", s_aarch64_elf_cons, 4},
   {"xword", s_aarch64_elf_cons, 8},
@@ -1989,14 +2050,14 @@ reg_name_p (char *str, aarch64_reg_type reg_type)
 
    To prevent the expression parser from pushing a register name
    into the symbol table as an undefined symbol, firstly a check is
-   done to find out whether STR is a valid register name followed
-   by a comma or the end of line.  Return FALSE if STR is such a
-   string.  */
+   done to find out whether STR is a register of type REG_TYPE followed
+   by a comma or the end of line.  Return FALSE if STR is such a string.  */
 
 static bfd_boolean
-parse_immediate_expression (char **str, expressionS *exp)
+parse_immediate_expression (char **str, expressionS *exp,
+                           aarch64_reg_type reg_type)
 {
-  if (reg_name_p (*str, REG_TYPE_R_Z_BHSDQ_V))
+  if (reg_name_p (*str, reg_type))
     {
       set_recoverable_error (_("immediate operand required"));
       return FALSE;
@@ -2015,16 +2076,17 @@ parse_immediate_expression (char **str, expressionS *exp)
 
 /* Constant immediate-value read function for use in insn parsing.
    STR points to the beginning of the immediate (with the optional
-   leading #); *VAL receives the value.
+   leading #); *VAL receives the value.  REG_TYPE says which register
+   names should be treated as registers rather than as symbolic immediates.
 
    Return TRUE on success; otherwise return FALSE.  */
 
 static bfd_boolean
-parse_constant_immediate (char **str, int64_t * val)
+parse_constant_immediate (char **str, int64_t *val, aarch64_reg_type reg_type)
 {
   expressionS exp;
 
-  if (! parse_immediate_expression (str, &exp))
+  if (! parse_immediate_expression (str, &exp, reg_type))
     return FALSE;
 
   if (exp.X_op != O_constant)
@@ -2077,68 +2139,67 @@ aarch64_imm_float_p (uint32_t imm)
     && ((imm & 0x7e000000) == pattern);        /* bits 25 - 29 == ~ bit 30.  */
 }
 
-/* Like aarch64_imm_float_p but for a double-precision floating-point value.
-
-   Return TRUE if the value encoded in IMM can be expressed in the AArch64
-   8-bit signed floating-point format with 3-bit exponent and normalized 4
-   bits of precision (i.e. can be used in an FMOV instruction); return the
-   equivalent single-precision encoding in *FPWORD.
-
-   Otherwise return FALSE.  */
+/* Return TRUE if the IEEE double value encoded in IMM can be expressed
+   as an IEEE float without any loss of precision.  Store the value in
+   *FPWORD if so.  */
 
 static bfd_boolean
-aarch64_double_precision_fmovable (uint64_t imm, uint32_t *fpword)
+can_convert_double_to_float (uint64_t imm, uint32_t *fpword)
 {
   /* If a double-precision floating-point value has the following bit
-     pattern, it can be expressed in the AArch64 8-bit floating-point
-     format:
+     pattern, it can be expressed in a float:
 
-     6 66655555555 554444444...21111111111
-     3 21098765432 109876543...098765432109876543210
-     n Eeeeeeeeexx xxxx00000...000000000000000000000
+     6 66655555555 5544 44444444 33333333 33222222 22221111 111111
+     3 21098765432 1098 76543210 98765432 10987654 32109876 54321098 76543210
+     n E~~~eeeeeee ssss ssssssss ssssssss SSS00000 00000000 00000000 00000000
 
-     where n, e and each x are either 0 or 1 independently, with
-     E == ~ e.  */
+       ----------------------------->     nEeeeeee esssssss ssssssss sssssSSS
+        if Eeee_eeee != 1111_1111
+
+     where n, e, s and S are either 0 or 1 independently and where ~ is the
+     inverse of E.  */
 
   uint32_t pattern;
   uint32_t high32 = imm >> 32;
+  uint32_t low32 = imm;
 
-  /* Lower 32 bits need to be 0s.  */
-  if ((imm & 0xffffffff) != 0)
+  /* Lower 29 bits need to be 0s.  */
+  if ((imm & 0x1fffffff) != 0)
     return FALSE;
 
   /* Prepare the pattern for 'Eeeeeeeee'.  */
   if (((high32 >> 30) & 0x1) == 0)
-    pattern = 0x3fc00000;
+    pattern = 0x38000000;
   else
     pattern = 0x40000000;
 
-  if ((high32 & 0xffff) == 0                   /* bits 32 - 47 are 0.  */
-      && (high32 & 0x7fc00000) == pattern)     /* bits 54 - 61 == ~ bit 62.  */
-    {
-      /* Convert to the single-precision encoding.
-         i.e. convert
-          n Eeeeeeeeexx xxxx00000...000000000000000000000
-        to
-          n Eeeeeexx xxxx0000000000000000000.  */
-      *fpword = ((high32 & 0xfe000000)                 /* nEeeeee.  */
-                | (((high32 >> 16) & 0x3f) << 19));    /* xxxxxx.  */
-      return TRUE;
-    }
-  else
+  /* Check E~~~.  */
+  if ((high32 & 0x78000000) != pattern)
+    return FALSE;
+
+  /* Check Eeee_eeee != 1111_1111.  */
+  if ((high32 & 0x7ff00000) == 0x47f00000)
     return FALSE;
+
+  *fpword = ((high32 & 0xc0000000)             /* 1 n bit and 1 E bit.  */
+            | ((high32 << 3) & 0x3ffffff8)     /* 7 e and 20 s bits.  */
+            | (low32 >> 29));                  /* 3 S bits.  */
+  return TRUE;
 }
 
 /* Parse a floating-point immediate.  Return TRUE on success and return the
    value in *IMMED in the format of IEEE754 single-precision encoding.
    *CCP points to the start of the string; DP_P is TRUE when the immediate
    is expected to be in double-precision (N.B. this only matters when
-   hexadecimal representation is involved).
+   hexadecimal representation is involved).  REG_TYPE says which register
+   names should be treated as registers rather than as symbolic immediates.
 
-   N.B. 0.0 is accepted by this function.  */
+   This routine accepts any IEEE float; it is up to the callers to reject
+   invalid ones.  */
 
 static bfd_boolean
-parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p)
+parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
+                        aarch64_reg_type reg_type)
 {
   char *str = *ccp;
   char *fpnum;
@@ -2158,12 +2219,12 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p)
       /* Support the hexadecimal representation of the IEEE754 encoding.
         Double-precision is expected when DP_P is TRUE, otherwise the
         representation should be in single-precision.  */
-      if (! parse_constant_immediate (&str, &val))
+      if (! parse_constant_immediate (&str, &val, reg_type))
        goto invalid_fp;
 
       if (dp_p)
        {
-         if (! aarch64_double_precision_fmovable (val, &fpword))
+         if (!can_convert_double_to_float (val, &fpword))
            goto invalid_fp;
        }
       else if ((uint64_t) val > 0xffffffff)
@@ -2175,6 +2236,12 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p)
     }
   else
     {
+      if (reg_name_p (str, reg_type))
+       {
+         set_recoverable_error (_("immediate operand required"));
+         return FALSE;
+       }
+
       /* We must not accidentally parse an integer as a floating-point number.
         Make sure that the value we parse is not an integer by checking for
         special characters '.' or 'e'.  */
@@ -2204,12 +2271,9 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p)
        }
     }
 
-  if (aarch64_imm_float_p (fpword) || (fpword & 0x7fffffff) == 0)
-    {
-      *immed = fpword;
-      *ccp = str;
-      return TRUE;
-    }
+  *immed = fpword;
+  *ccp = str;
+  return TRUE;
 
 invalid_fp:
   set_fatal_syntax_error (_("invalid floating-point constant"));
@@ -2222,15 +2286,15 @@ invalid_fp:
 
    To prevent the expression parser from pushing a register name into the
    symbol table as an undefined symbol, a check is firstly done to find
-   out whether STR is a valid register name followed by a comma or the end
-   of line.  Return FALSE if STR is such a register.  */
+   out whether STR is a register of type REG_TYPE followed by a comma or
+   the end of line.  Return FALSE if STR is such a register.  */
 
 static bfd_boolean
-parse_big_immediate (char **str, int64_t *imm)
+parse_big_immediate (char **str, int64_t *imm, aarch64_reg_type reg_type)
 {
   char *ptr = *str;
 
-  if (reg_name_p (ptr, REG_TYPE_R_Z_BHSDQ_V))
+  if (reg_name_p (ptr, reg_type))
     {
       set_syntax_error (_("immediate operand required"));
       return FALSE;
@@ -2456,6 +2520,51 @@ static struct reloc_table_entry reloc_table[] = {
    BFD_RELOC_AARCH64_LD_GOT_LO12_NC,
    0},
 
+  /* 0-15 bits of address/value: MOVk, no check.  */
+  {"gotoff_g0_nc", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 16-31 of address/value: MOVZ.  */
+  {"gotoff_g1", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_GOTOFF_G1,
+   0,
+   0,
+   0},
+
+  /* 15 bit offset into the page containing GOT entry for that symbol.  */
+  {"gotoff_lo15", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   0,
+   BFD_RELOC_AARCH64_LD64_GOTOFF_LO15,
+   0},
+
+  /* Get to the page containing GOT TLS entry for a symbol */
+  {"gottprel_g0_nc", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC,
+   0,
+   0,
+   0},
+
+  /* Get to the page containing GOT TLS entry for a symbol */
+  {"gottprel_g1", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1,
+   0,
+   0,
+   0},
+
   /* Get to the page containing GOT TLS entry for a symbol */
   {"tlsgd", 0,
    BFD_RELOC_AARCH64_TLSGD_ADR_PREL21, /* adr_type */
@@ -2474,6 +2583,24 @@ static struct reloc_table_entry reloc_table[] = {
    0,
    0},
 
+  /* Lower 16 bits address/value: MOVk.  */
+  {"tlsgd_g0_nc", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 16-31 of address/value: MOVZ.  */
+  {"tlsgd_g1", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSGD_MOVW_G1,
+   0,
+   0,
+   0},
+
   /* Get to the page containing GOT TLS entry for a symbol */
   {"tlsdesc", 0,
    BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, /* adr_type */
@@ -2492,6 +2619,118 @@ static struct reloc_table_entry reloc_table[] = {
    BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC,
    0},
 
+  /* Get to the page containing GOT TLS entry for a symbol.
+     The same as GD, we allocate two consecutive GOT slots
+     for module index and module offset, the only difference
+     with GD is the module offset should be intialized to
+     zero without any outstanding runtime relocation. */
+  {"tlsldm", 0,
+   BFD_RELOC_AARCH64_TLSLD_ADR_PREL21, /* adr_type */
+   BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21,
+   0,
+   0,
+   0,
+   0},
+
+  /* 12 bit offset into the page containing GOT TLS entry for a symbol */
+  {"tlsldm_lo12_nc", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC,
+   0,
+   0},
+
+  /* 12 bit offset into the module TLS base address.  */
+  {"dtprel_lo12", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12,
+   BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12,
+   0},
+
+  /* Same as dtprel_lo12, no overflow check.  */
+  {"dtprel_lo12_nc", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,
+   BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC,
+   0},
+
+  /* bits[23:12] of offset to the module TLS base address.  */
+  {"dtprel_hi12", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12,
+   0,
+   0},
+
+  /* bits[15:0] of offset to the module TLS base address.  */
+  {"dtprel_g0", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0,
+   0,
+   0,
+   0},
+
+  /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0.  */
+  {"dtprel_g0_nc", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC,
+   0,
+   0,
+   0},
+
+  /* bits[31:16] of offset to the module TLS base address.  */
+  {"dtprel_g1", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1,
+   0,
+   0,
+   0},
+
+  /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1.  */
+  {"dtprel_g1_nc", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC,
+   0,
+   0,
+   0},
+
+  /* bits[47:32] of offset to the module TLS base address.  */
+  {"dtprel_g2", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2,
+   0,
+   0,
+   0},
+
+  /* Lower 16 bit offset into GOT entry for a symbol */
+  {"tlsdesc_off_g0_nc", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC,
+   0,
+   0,
+   0},
+
+  /* Higher 16 bit offset into GOT entry for a symbol */
+  {"tlsdesc_off_g1", 0,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_TLSDESC_OFF_G1,
+   0,
+   0,
+   0},
+
   /* Get to the page containing GOT TLS entry for a symbol */
   {"gottprel", 0,
    0,                          /* adr_type */
@@ -2590,6 +2829,24 @@ static struct reloc_table_entry reloc_table[] = {
    0,
    0,
    0},
+
+  /* 15bit offset from got entry to base address of GOT table.  */
+  {"gotpage_lo15", 0,
+   0,
+   0,
+   0,
+   0,
+   BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15,
+   0},
+
+  /* 14bit offset from got entry to base address of GOT table.  */
+  {"gotpage_lo14", 0,
+   0,
+   0,
+   0,
+   0,
+   BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14,
+   0},
 };
 
 /* Given the address of a pointer pointing to the textual name of a
@@ -2821,13 +3078,13 @@ static bfd_boolean
 parse_shifter_operand (char **str, aarch64_opnd_info *operand,
                       enum parse_shift_mode mode)
 {
-  int reg;
-  int isreg32, isregzero;
+  const reg_entry *reg;
+  aarch64_opnd_qualifier_t qualifier;
   enum aarch64_operand_class opd_class
     = aarch64_get_operand_class (operand->type);
 
-  if ((reg =
-       aarch64_reg_parse_32_64 (str, 0, 0, &isreg32, &isregzero)) != PARSE_FAIL)
+  reg = aarch64_reg_parse_32_64 (str, &qualifier);
+  if (reg)
     {
       if (opd_class == AARCH64_OPND_CLASS_IMMEDIATE)
        {
@@ -2835,14 +3092,14 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand,
          return FALSE;
        }
 
-      if (!isregzero && reg == REG_SP)
+      if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
        {
-         set_syntax_error (BAD_SP);
+         set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
          return FALSE;
        }
 
-      operand->reg.regno = reg;
-      operand->qualifier = isreg32 ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X;
+      operand->reg.regno = reg->number;
+      operand->qualifier = qualifier;
 
       /* Accept optional shift operation on register.  */
       if (! skip_past_comma (str))
@@ -2977,12 +3234,12 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
    supported by the instruction, and to set inst.reloc.type.  */
 
 static bfd_boolean
-parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
-                   int accept_reg_post_index)
+parse_address_main (char **str, aarch64_opnd_info *operand)
 {
   char *p = *str;
-  int reg;
-  int isreg32, isregzero;
+  const reg_entry *reg;
+  aarch64_opnd_qualifier_t base_qualifier;
+  aarch64_opnd_qualifier_t offset_qualifier;
   expressionS *exp = &inst.reloc.exp;
 
   if (! skip_past_char (&p, '['))
@@ -2993,7 +3250,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
 
       /* #:<reloc_op>:<symbol>  */
       skip_past_char (&p, '#');
-      if (reloc && skip_past_char (&p, ':'))
+      if (skip_past_char (&p, ':'))
        {
          bfd_reloc_code_real_type ty;
          struct reloc_table_entry *entry;
@@ -3059,14 +3316,13 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
 
   /* [ */
 
-  /* Accept SP and reject ZR */
-  reg = aarch64_reg_parse_32_64 (&p, 0, 1, &isreg32, &isregzero);
-  if (reg == PARSE_FAIL || isreg32)
+  reg = aarch64_reg_parse_32_64 (&p, &base_qualifier);
+  if (!reg || !aarch64_check_reg_type (reg, REG_TYPE_R64_SP))
     {
-      set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_64)));
+      set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R64_SP)));
       return FALSE;
     }
-  operand->addr.base_regno = reg;
+  operand->addr.base_regno = reg->number;
 
   /* [Xn */
   if (skip_past_comma (&p))
@@ -3074,12 +3330,17 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
       /* [Xn, */
       operand->addr.preind = 1;
 
-      /* Reject SP and accept ZR */
-      reg = aarch64_reg_parse_32_64 (&p, 1, 0, &isreg32, &isregzero);
-      if (reg != PARSE_FAIL)
+      reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+      if (reg)
        {
+         if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
+           {
+             set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
+             return FALSE;
+           }
+
          /* [Xn,Rm  */
-         operand->addr.offset.regno = reg;
+         operand->addr.offset.regno = reg->number;
          operand->addr.offset.is_reg = 1;
          /* Shifted index.  */
          if (skip_past_comma (&p))
@@ -3098,13 +3359,13 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
              || operand->shifter.kind == AARCH64_MOD_LSL
              || operand->shifter.kind == AARCH64_MOD_SXTX)
            {
-             if (isreg32)
+             if (offset_qualifier == AARCH64_OPND_QLF_W)
                {
                  set_syntax_error (_("invalid use of 32-bit register offset"));
                  return FALSE;
                }
            }
-         else if (!isreg32)
+         else if (offset_qualifier == AARCH64_OPND_QLF_X)
            {
              set_syntax_error (_("invalid use of 64-bit register offset"));
              return FALSE;
@@ -3114,7 +3375,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
        {
          /* [Xn,#:<reloc_op>:<symbol>  */
          skip_past_char (&p, '#');
-         if (reloc && skip_past_char (&p, ':'))
+         if (skip_past_char (&p, ':'))
            {
              struct reloc_table_entry *entry;
 
@@ -3187,17 +3448,17 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
          return FALSE;
        }
 
-      if (accept_reg_post_index
-         && (reg = aarch64_reg_parse_32_64 (&p, 1, 1, &isreg32,
-                                            &isregzero)) != PARSE_FAIL)
+      reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+      if (reg)
        {
          /* [Xn],Xm */
-         if (isreg32)
+         if (!aarch64_check_reg_type (reg, REG_TYPE_R_64))
            {
-             set_syntax_error (_("invalid 32-bit register offset"));
+             set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_64)));
              return FALSE;
            }
-         operand->addr.offset.regno = reg;
+
+         operand->addr.offset.regno = reg->number;
          operand->addr.offset.is_reg = 1;
        }
       else if (! my_get_expression (exp, &p, GE_OPT_PREFIX, 1))
@@ -3227,19 +3488,12 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
   return TRUE;
 }
 
-/* Return TRUE on success; otherwise return FALSE.  */
+/* Parse a base AArch64 address (as opposed to an SVE one).  Return TRUE
+   on success.  */
 static bfd_boolean
-parse_address (char **str, aarch64_opnd_info *operand,
-              int accept_reg_post_index)
+parse_address (char **str, aarch64_opnd_info *operand)
 {
-  return parse_address_main (str, operand, 0, accept_reg_post_index);
-}
-
-/* Return TRUE on success; otherwise return FALSE.  */
-static bfd_boolean
-parse_address_reloc (char **str, aarch64_opnd_info *operand)
-{
-  return parse_address_main (str, operand, 1, 0);
+  return parse_address_main (str, operand);
 }
 
 /* Parse an operand for a MOVZ, MOVN or MOVK instruction.
@@ -3247,10 +3501,8 @@ parse_address_reloc (char **str, aarch64_opnd_info *operand)
 static bfd_boolean
 parse_half (char **str, int *internal_fixup_p)
 {
-  char *p, *saved;
-  int dummy;
+  char *p = *str;
 
-  p = *str;
   skip_past_char (&p, '#');
 
   gas_assert (internal_fixup_p);
@@ -3280,12 +3532,6 @@ parse_half (char **str, int *internal_fixup_p)
   else
     *internal_fixup_p = 1;
 
-  /* Avoid parsing a register as a general symbol.  */
-  saved = p;
-  if (aarch64_reg_parse_32_64 (&p, 0, 0, &dummy, &dummy) != PARSE_FAIL)
-    return FALSE;
-  p = saved;
-
   if (! my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, 1))
     return FALSE;
 
@@ -3380,14 +3626,54 @@ parse_barrier (char **str)
   return o->value;
 }
 
+/* Parse an operand for a PSB barrier.  Set *HINT_OPT to the hint-option record
+   return 0 if successful.  Otherwise return PARSE_FAIL.  */
+
+static int
+parse_barrier_psb (char **str,
+                  const struct aarch64_name_value_pair ** hint_opt)
+{
+  char *p, *q;
+  const struct aarch64_name_value_pair *o;
+
+  p = q = *str;
+  while (ISALPHA (*q))
+    q++;
+
+  o = hash_find_n (aarch64_hint_opt_hsh, p, q - p);
+  if (!o)
+    {
+      set_fatal_syntax_error
+       ( _("unknown or missing option to PSB"));
+      return PARSE_FAIL;
+    }
+
+  if (o->value != 0x11)
+    {
+      /* PSB only accepts option name 'CSYNC'.  */
+      set_syntax_error
+       (_("the specified option is not accepted for PSB"));
+      return PARSE_FAIL;
+    }
+
+  *str = q;
+  *hint_opt = o;
+  return 0;
+}
+
 /* Parse a system register or a PSTATE field name for an MSR/MRS instruction.
    Returns the encoding for the option, or PARSE_FAIL.
 
    If IMPLE_DEFINED_P is non-zero, the function will also try to parse the
-   implementation defined system register name S<op0>_<op1>_<Cn>_<Cm>_<op2>.  */
+   implementation defined system register name S<op0>_<op1>_<Cn>_<Cm>_<op2>.
+
+   If PSTATEFIELD_P is non-zero, the function will parse the name as a PSTATE
+   field, otherwise as a system register.
+*/
 
 static int
-parse_sys_reg (char **str, struct hash_control *sys_regs, int imple_defined_p)
+parse_sys_reg (char **str, struct hash_control *sys_regs,
+              int imple_defined_p, int pstatefield_p)
 {
   char *p, *q;
   char buf[32];
@@ -3422,9 +3708,15 @@ parse_sys_reg (char **str, struct hash_control *sys_regs, int imple_defined_p)
     }
   else
     {
+      if (pstatefield_p && !aarch64_pstatefield_supported_p (cpu_variant, o))
+       as_bad (_("selected processor does not support PSTATE field "
+                 "name '%s'"), buf);
+      if (!pstatefield_p && !aarch64_sys_reg_supported_p (cpu_variant, o))
+       as_bad (_("selected processor does not support system register "
+                 "name '%s'"), buf);
       if (aarch64_sys_reg_deprecated_p (o))
        as_warn (_("system register name '%s' is deprecated and may be "
-"removed in a future release"), buf);
+                  "removed in a future release"), buf);
       value = o->value;
     }
 
@@ -3452,6 +3744,10 @@ parse_sys_ins_reg (char **str, struct hash_control *sys_ins_regs)
   if (!o)
     return NULL;
 
+  if (!aarch64_sys_ins_reg_supported_p (cpu_variant, o))
+    as_bad (_("selected processor does not support system register "
+             "name '%s'"), buf);
+
   *str = q;
   return o;
 }
@@ -3470,28 +3766,24 @@ parse_sys_ins_reg (char **str, struct hash_control *sys_ins_regs)
       }                                                                \
   } while (0)
 
-#define po_int_reg_or_fail(reject_sp, reject_rz) do {          \
-    val = aarch64_reg_parse_32_64 (&str, reject_sp, reject_rz, \
-                                   &isreg32, &isregzero);      \
-    if (val == PARSE_FAIL)                                     \
+#define po_int_reg_or_fail(reg_type) do {                      \
+    reg = aarch64_reg_parse_32_64 (&str, &qualifier);          \
+    if (!reg || !aarch64_check_reg_type (reg, reg_type))       \
       {                                                                \
        set_default_error ();                                   \
        goto failure;                                           \
       }                                                                \
-    info->reg.regno = val;                                     \
-    if (isreg32)                                               \
-      info->qualifier = AARCH64_OPND_QLF_W;                    \
-    else                                                       \
-      info->qualifier = AARCH64_OPND_QLF_X;                    \
+    info->reg.regno = reg->number;                             \
+    info->qualifier = qualifier;                               \
   } while (0)
 
 #define po_imm_nc_or_fail() do {                               \
-    if (! parse_constant_immediate (&str, &val))               \
+    if (! parse_constant_immediate (&str, &val, imm_reg_type)) \
       goto failure;                                            \
   } while (0)
 
 #define po_imm_or_fail(min, max) do {                          \
-    if (! parse_constant_immediate (&str, &val))               \
+    if (! parse_constant_immediate (&str, &val, imm_reg_type)) \
       goto failure;                                            \
     if (val < min || val > max)                                        \
       {                                                                \
@@ -3779,9 +4071,7 @@ add_operand_error_record (const operand_error_record* new_record)
       /* Get one empty record.  */
       if (free_opnd_error_record_nodes == NULL)
        {
-         record = xmalloc (sizeof (operand_error_record));
-         if (record == NULL)
-           abort ();
+         record = XNEW (operand_error_record);
        }
       else
        {
@@ -3905,7 +4195,7 @@ find_best_match (const aarch64_inst *instr,
     }
 
   max_num_matched = 0;
-  idx = -1;
+  idx = 0;
 
   /* For each pattern.  */
   for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i, ++qualifiers_list)
@@ -3917,9 +4207,6 @@ find_best_match (const aarch64_inst *instr,
       if (empty_qualifier_sequence_p (qualifiers) == TRUE)
        {
          DEBUG_TRACE_IF (i == 0, "empty list of qualifier sequence");
-         if (i != 0 && idx == -1)
-           /* If nothing has been matched, return the 1st sequence.  */
-           idx = 0;
          break;
        }
 
@@ -3962,8 +4249,7 @@ print_operands (char *buf, const aarch64_opcode *opcode,
 
   for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
     {
-      const size_t size = 128;
-      char str[size];
+      char str[128];
 
       /* We regard the opcode operand info more, however we also look into
         the inst->operands to support the disassembling of the optional
@@ -3975,7 +4261,7 @@ print_operands (char *buf, const aarch64_opcode *opcode,
        break;
 
       /* Generate the operand string in STR.  */
-      aarch64_print_operand (str, size, 0, opcode, opnds, i, NULL, NULL);
+      aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL);
 
       /* Delimiter.  */
       if (str[0] != '\0')
@@ -3991,11 +4277,11 @@ print_operands (char *buf, const aarch64_opcode *opcode,
 static void
 output_info (const char *format, ...)
 {
-  char *file;
+  const char *file;
   unsigned int line;
   va_list args;
 
-  as_where (&file, &line);
+  file = as_where (&line);
   if (file)
     {
       if (line != 0)
@@ -4081,8 +4367,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
          size_t len = strlen (get_mnemonic_name (str));
          int i, qlf_idx;
          bfd_boolean result;
-         const size_t size = 2048;
-         char buf[size];
+         char buf[2048];
          aarch64_inst *inst_base = &inst.base;
          const aarch64_opnd_qualifier_seq_t *qualifiers_list;
 
@@ -4112,7 +4397,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
 
          /* Print the hint.  */
          output_info (_("   did you mean this?"));
-         snprintf (buf, size, "\t%s", get_mnemonic_name (str));
+         snprintf (buf, sizeof (buf), "\t%s", get_mnemonic_name (str));
          print_operands (buf, opcode, inst_base->operands);
          output_info (_("   %s"), buf);
 
@@ -4133,7 +4418,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
              if (i != qlf_idx)
                {
                  /* Mnemonics name.  */
-                 snprintf (buf, size, "\t%s", get_mnemonic_name (str));
+                 snprintf (buf, sizeof (buf), "\t%s", get_mnemonic_name (str));
 
                  /* Assign the qualifiers.  */
                  assign_qualifier_sequence (inst_base, *qualifiers_list);
@@ -4147,6 +4432,11 @@ output_operand_error_record (const operand_error_record *record, char *str)
        }
       break;
 
+    case AARCH64_OPDE_UNTIED_OPERAND:
+      as_bad (_("operand %d must be the same register as operand 1 -- `%s'"),
+             detail->index + 1, str);
+      break;
+
     case AARCH64_OPDE_OUT_OF_RANGE:
       if (detail->data[0] != detail->data[1])
        as_bad (_("%s out of range %d to %d at operand %d -- `%s'"),
@@ -4387,22 +4677,35 @@ opcode_lookup (char **str)
   return NULL;
 }
 
-/* Internal helper routine converting a vector neon_type_el structure
-   *VECTYPE to a corresponding operand qualifier.  */
+/* Internal helper routine converting a vector_type_el structure *VECTYPE
+   to a corresponding operand qualifier.  */
 
 static inline aarch64_opnd_qualifier_t
-vectype_to_qualifier (const struct neon_type_el *vectype)
+vectype_to_qualifier (const struct vector_type_el *vectype)
 {
-  /* Element size in bytes indexed by neon_el_type.  */
+  /* Element size in bytes indexed by vector_el_type.  */
   const unsigned char ele_size[5]
     = {1, 2, 4, 8, 16};
+  const unsigned int ele_base [5] =
+    {
+      AARCH64_OPND_QLF_V_8B,
+      AARCH64_OPND_QLF_V_2H,
+      AARCH64_OPND_QLF_V_2S,
+      AARCH64_OPND_QLF_V_1D,
+      AARCH64_OPND_QLF_V_1Q
+  };
 
   if (!vectype->defined || vectype->type == NT_invtype)
     goto vectype_conversion_fail;
 
+  if (vectype->type == NT_zero)
+    return AARCH64_OPND_QLF_P_Z;
+  if (vectype->type == NT_merge)
+    return AARCH64_OPND_QLF_P_M;
+
   gas_assert (vectype->type >= NT_b && vectype->type <= NT_q);
 
-  if (vectype->defined & NTA_HASINDEX)
+  if (vectype->defined & (NTA_HASINDEX | NTA_HASVARWIDTH))
     /* Vector element register.  */
     return AARCH64_OPND_QLF_S_B + vectype->type;
   else
@@ -4410,14 +4713,28 @@ vectype_to_qualifier (const struct neon_type_el *vectype)
       /* Vector register.  */
       int reg_size = ele_size[vectype->type] * vectype->width;
       unsigned offset;
-      if (reg_size != 16 && reg_size != 8)
+      unsigned shift;
+      if (reg_size != 16 && reg_size != 8 && reg_size != 4)
        goto vectype_conversion_fail;
-      /* The conversion is calculated based on the relation of the order of
-        qualifiers to the vector element size and vector register size.  */
-      offset = (vectype->type == NT_q)
-       ? 8 : (vectype->type << 1) + (reg_size >> 4);
-      gas_assert (offset <= 8);
-      return AARCH64_OPND_QLF_V_8B + offset;
+
+      /* The conversion is by calculating the offset from the base operand
+        qualifier for the vector type.  The operand qualifiers are regular
+        enough that the offset can established by shifting the vector width by
+        a vector-type dependent amount.  */
+      shift = 0;
+      if (vectype->type == NT_b)
+       shift = 4;
+      else if (vectype->type == NT_h || vectype->type == NT_s)
+       shift = 2;
+      else if (vectype->type >= NT_d)
+       shift = 1;
+      else
+       gas_assert (0);
+
+      offset = ele_base [vectype->type] + (vectype->width >> shift);
+      gas_assert (AARCH64_OPND_QLF_V_8B <= offset
+                 && offset <= AARCH64_OPND_QLF_V_1Q);
+      return offset;
     }
 
 vectype_conversion_fail:
@@ -4521,6 +4838,7 @@ process_movw_reloc_info (void)
       case BFD_RELOC_AARCH64_MOVW_G0_S:
       case BFD_RELOC_AARCH64_MOVW_G1_S:
       case BFD_RELOC_AARCH64_MOVW_G2_S:
+      case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
@@ -4534,22 +4852,35 @@ process_movw_reloc_info (void)
   switch (inst.reloc.type)
     {
     case BFD_RELOC_AARCH64_MOVW_G0:
-    case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_G0_S:
+    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+    case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
       shift = 0;
       break;
     case BFD_RELOC_AARCH64_MOVW_G1:
-    case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_MOVW_G1_NC:
+    case BFD_RELOC_AARCH64_MOVW_G1_S:
+    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+    case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+    case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+    case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
       shift = 16;
       break;
     case BFD_RELOC_AARCH64_MOVW_G2:
-    case BFD_RELOC_AARCH64_MOVW_G2_S:
     case BFD_RELOC_AARCH64_MOVW_G2_NC:
+    case BFD_RELOC_AARCH64_MOVW_G2_S:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
       if (is32)
        {
@@ -4603,17 +4934,38 @@ get_logsz (unsigned int size)
 static inline bfd_reloc_code_real_type
 ldst_lo12_determine_real_reloc_type (void)
 {
-  int logsz;
+  unsigned logsz;
   enum aarch64_opnd_qualifier opd0_qlf = inst.base.operands[0].qualifier;
   enum aarch64_opnd_qualifier opd1_qlf = inst.base.operands[1].qualifier;
 
-  const bfd_reloc_code_real_type reloc_ldst_lo12[5] = {
-      BFD_RELOC_AARCH64_LDST8_LO12, BFD_RELOC_AARCH64_LDST16_LO12,
-      BFD_RELOC_AARCH64_LDST32_LO12, BFD_RELOC_AARCH64_LDST64_LO12,
+  const bfd_reloc_code_real_type reloc_ldst_lo12[3][5] = {
+    {
+      BFD_RELOC_AARCH64_LDST8_LO12,
+      BFD_RELOC_AARCH64_LDST16_LO12,
+      BFD_RELOC_AARCH64_LDST32_LO12,
+      BFD_RELOC_AARCH64_LDST64_LO12,
       BFD_RELOC_AARCH64_LDST128_LO12
+    },
+    {
+      BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12,
+      BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12,
+      BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12,
+      BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12,
+      BFD_RELOC_AARCH64_NONE
+    },
+    {
+      BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC,
+      BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC,
+      BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
+      BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
+      BFD_RELOC_AARCH64_NONE
+    }
   };
 
-  gas_assert (inst.reloc.type == BFD_RELOC_AARCH64_LDST_LO12);
+  gas_assert (inst.reloc.type == BFD_RELOC_AARCH64_LDST_LO12
+             || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
+             || (inst.reloc.type
+                 == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC));
   gas_assert (inst.base.opcode->operands[1] == AARCH64_OPND_ADDR_UIMM12);
 
   if (opd1_qlf == AARCH64_OPND_QLF_NIL)
@@ -4623,9 +4975,16 @@ ldst_lo12_determine_real_reloc_type (void)
   gas_assert (opd1_qlf != AARCH64_OPND_QLF_NIL);
 
   logsz = get_logsz (aarch64_get_qualifier_esize (opd1_qlf));
-  gas_assert (logsz >= 0 && logsz <= 4);
+  if (inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
+      || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+    gas_assert (logsz <= 3);
+  else
+    gas_assert (logsz <= 4);
 
-  return reloc_ldst_lo12[logsz];
+  /* In reloc.c, these pseudo relocation types should be defined in similar
+     order as above reloc_ldst_lo12 array. Because the array index calcuation
+     below relies on this.  */
+  return reloc_ldst_lo12[inst.reloc.type - BFD_RELOC_AARCH64_LDST_LO12][logsz];
 }
 
 /* Check whether a register list REGINFO is valid.  The registers must be
@@ -4670,18 +5029,23 @@ parse_operands (char *str, const aarch64_opcode *opcode)
   int i;
   char *backtrack_pos = 0;
   const enum aarch64_opnd *operands = opcode->operands;
+  aarch64_reg_type imm_reg_type;
 
   clear_error ();
   skip_whitespace (str);
 
+  imm_reg_type = REG_TYPE_R_Z_BHSDQ_V;
+
   for (i = 0; operands[i] != AARCH64_OPND_NIL; i++)
     {
       int64_t val;
-      int isreg32, isregzero;
+      const reg_entry *reg;
       int comma_skipped_p = 0;
       aarch64_reg_type rtype;
-      struct neon_type_el vectype;
+      struct vector_type_el vectype;
+      aarch64_opnd_qualifier_t qualifier;
       aarch64_opnd_info *info = &inst.base.operands[i];
+      aarch64_reg_type reg_type;
 
       DEBUG_TRACE ("parse operand %d", i);
 
@@ -4716,12 +5080,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Ra:
        case AARCH64_OPND_Rt_SYS:
        case AARCH64_OPND_PAIRREG:
-         po_int_reg_or_fail (1, 0);
+         po_int_reg_or_fail (REG_TYPE_R_Z);
          break;
 
        case AARCH64_OPND_Rd_SP:
        case AARCH64_OPND_Rn_SP:
-         po_int_reg_or_fail (0, 1);
+         po_int_reg_or_fail (REG_TYPE_R_SP);
          break;
 
        case AARCH64_OPND_Rm_EXT:
@@ -4764,22 +5128,54 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->qualifier = AARCH64_OPND_QLF_S_B + (rtype - REG_TYPE_FP_B);
          break;
 
+       case AARCH64_OPND_SVE_Pd:
+       case AARCH64_OPND_SVE_Pg3:
+       case AARCH64_OPND_SVE_Pg4_5:
+       case AARCH64_OPND_SVE_Pg4_10:
+       case AARCH64_OPND_SVE_Pg4_16:
+       case AARCH64_OPND_SVE_Pm:
+       case AARCH64_OPND_SVE_Pn:
+       case AARCH64_OPND_SVE_Pt:
+         reg_type = REG_TYPE_PN;
+         goto vector_reg;
+
+       case AARCH64_OPND_SVE_Za_5:
+       case AARCH64_OPND_SVE_Za_16:
+       case AARCH64_OPND_SVE_Zd:
+       case AARCH64_OPND_SVE_Zm_5:
+       case AARCH64_OPND_SVE_Zm_16:
+       case AARCH64_OPND_SVE_Zn:
+       case AARCH64_OPND_SVE_Zt:
+         reg_type = REG_TYPE_ZN;
+         goto vector_reg;
+
        case AARCH64_OPND_Vd:
        case AARCH64_OPND_Vn:
        case AARCH64_OPND_Vm:
-         val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
+         reg_type = REG_TYPE_VN;
+       vector_reg:
+         val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
          if (val == PARSE_FAIL)
            {
-             first_error (_(get_reg_expected_msg (REG_TYPE_VN)));
+             first_error (_(get_reg_expected_msg (reg_type)));
              goto failure;
            }
          if (vectype.defined & NTA_HASINDEX)
            goto failure;
 
          info->reg.regno = val;
-         info->qualifier = vectype_to_qualifier (&vectype);
-         if (info->qualifier == AARCH64_OPND_QLF_NIL)
-           goto failure;
+         if ((reg_type == REG_TYPE_PN || reg_type == REG_TYPE_ZN)
+             && vectype.type == NT_invtype)
+           /* Unqualified Pn and Zn registers are allowed in certain
+              contexts.  Rely on F_STRICT qualifier checking to catch
+              invalid uses.  */
+           info->qualifier = AARCH64_OPND_QLF_NIL;
+         else
+           {
+             info->qualifier = vectype_to_qualifier (&vectype);
+             if (info->qualifier == AARCH64_OPND_QLF_NIL)
+               goto failure;
+           }
          break;
 
        case AARCH64_OPND_VdD1:
@@ -4804,13 +5200,19 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->qualifier = AARCH64_OPND_QLF_S_D;
          break;
 
+       case AARCH64_OPND_SVE_Zn_INDEX:
+         reg_type = REG_TYPE_ZN;
+         goto vector_reg_index;
+
        case AARCH64_OPND_Ed:
        case AARCH64_OPND_En:
        case AARCH64_OPND_Em:
-         val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
+         reg_type = REG_TYPE_VN;
+       vector_reg_index:
+         val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
          if (val == PARSE_FAIL)
            {
-             first_error (_(get_reg_expected_msg (REG_TYPE_VN)));
+             first_error (_(get_reg_expected_msg (reg_type)));
              goto failure;
            }
          if (vectype.type == NT_invtype || !(vectype.defined & NTA_HASINDEX))
@@ -4823,19 +5225,43 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            goto failure;
          break;
 
+       case AARCH64_OPND_SVE_ZnxN:
+       case AARCH64_OPND_SVE_ZtxN:
+         reg_type = REG_TYPE_ZN;
+         goto vector_reg_list;
+
        case AARCH64_OPND_LVn:
        case AARCH64_OPND_LVt:
        case AARCH64_OPND_LVt_AL:
        case AARCH64_OPND_LEt:
-         if ((val = parse_neon_reg_list (&str, &vectype)) == PARSE_FAIL)
-           goto failure;
-         if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+         reg_type = REG_TYPE_VN;
+       vector_reg_list:
+         if (reg_type == REG_TYPE_ZN
+             && get_opcode_dependent_value (opcode) == 1
+             && *str != '{')
            {
-             set_fatal_syntax_error (_("invalid register list"));
-             goto failure;
+             val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
+             if (val == PARSE_FAIL)
+               {
+                 first_error (_(get_reg_expected_msg (reg_type)));
+                 goto failure;
+               }
+             info->reglist.first_regno = val;
+             info->reglist.num_regs = 1;
+           }
+         else
+           {
+             val = parse_vector_reg_list (&str, reg_type, &vectype);
+             if (val == PARSE_FAIL)
+               goto failure;
+             if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+               {
+                 set_fatal_syntax_error (_("invalid register list"));
+                 goto failure;
+               }
+             info->reglist.first_regno = (val >> 2) & 0x1f;
+             info->reglist.num_regs = (val & 0x3) + 1;
            }
-         info->reglist.first_regno = (val >> 2) & 0x1f;
-         info->reglist.num_regs = (val & 0x3) + 1;
          if (operands[i] == AARCH64_OPND_LEt)
            {
              if (!(vectype.defined & NTA_HASINDEX))
@@ -4843,8 +5269,17 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              info->reglist.has_index = 1;
              info->reglist.index = vectype.index;
            }
-         else if (!(vectype.defined & NTA_HASTYPE))
-           goto failure;
+         else
+           {
+             if (vectype.defined & NTA_HASINDEX)
+               goto failure;
+             if (!(vectype.defined & NTA_HASTYPE))
+               {
+                 if (reg_type == REG_TYPE_ZN)
+                   set_fatal_syntax_error (_("missing type suffix"));
+                 goto failure;
+               }
+           }
          info->qualifier = vectype_to_qualifier (&vectype);
          if (info->qualifier == AARCH64_OPND_QLF_NIL)
            goto failure;
@@ -4908,8 +5343,11 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            bfd_boolean res1 = FALSE, res2 = FALSE;
            /* N.B. -0.0 will be rejected; although -0.0 shouldn't be rejected,
               it is probably not worth the effort to support it.  */
-           if (!(res1 = parse_aarch64_imm_float (&str, &qfloat, FALSE))
-               && !(res2 = parse_constant_immediate (&str, &val)))
+           if (!(res1 = parse_aarch64_imm_float (&str, &qfloat, FALSE,
+                                                 imm_reg_type))
+               && (error_p ()
+                   || !(res2 = parse_constant_immediate (&str, &val,
+                                                         imm_reg_type))))
              goto failure;
            if ((res1 && qfloat == 0) || (res2 && val == 0))
              {
@@ -4942,7 +5380,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_SIMD_IMM:
        case AARCH64_OPND_SIMD_IMM_SFT:
-         if (! parse_big_immediate (&str, &val))
+         if (! parse_big_immediate (&str, &val, imm_reg_type))
            goto failure;
          assign_imm_if_const_or_fixup_later (&inst.reloc, info,
                                              /* addr_off_p */ 0,
@@ -4973,11 +5411,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            bfd_boolean dp_p
              = (aarch64_get_qualifier_esize (inst.base.operands[0].qualifier)
                 == 8);
-           if (! parse_aarch64_imm_float (&str, &qfloat, dp_p))
-             goto failure;
-           if (qfloat == 0)
+           if (!parse_aarch64_imm_float (&str, &qfloat, dp_p, imm_reg_type)
+               || !aarch64_imm_float_p (qfloat))
              {
-               set_fatal_syntax_error (_("invalid floating-point constant"));
+               if (!error_p ())
+                 set_fatal_syntax_error (_("invalid floating-point"
+                                           " constant"));
                goto failure;
              }
            inst.base.operands[i].imm.value = encode_imm_float_bits (qfloat);
@@ -5061,7 +5500,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_EXCEPTION:
-         po_misc_or_fail (parse_immediate_expression (&str, &inst.reloc.exp));
+         po_misc_or_fail (parse_immediate_expression (&str, &inst.reloc.exp,
+                                                      imm_reg_type));
          assign_imm_if_const_or_fixup_later (&inst.reloc, info,
                                              /* addr_off_p */ 0,
                                              /* need_libopcodes_p */ 0,
@@ -5110,7 +5550,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_ADDR_PCREL19:
        case AARCH64_OPND_ADDR_PCREL21:
        case AARCH64_OPND_ADDR_PCREL26:
-         po_misc_or_fail (parse_address_reloc (&str, info));
+         po_misc_or_fail (parse_address (&str, info));
          if (!info->addr.pcrel)
            {
              set_syntax_error (_("invalid pc-relative address"));
@@ -5176,28 +5616,43 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_ADDR_SIMPLE:
        case AARCH64_OPND_SIMD_ADDR_SIMPLE:
-         /* [<Xn|SP>{, #<simm>}]  */
-         po_char_or_fail ('[');
-         po_reg_or_fail (REG_TYPE_R64_SP);
-         /* Accept optional ", #0".  */
-         if (operands[i] == AARCH64_OPND_ADDR_SIMPLE
-             && skip_past_char (&str, ','))
-           {
-             skip_past_char (&str, '#');
-             if (! skip_past_char (&str, '0'))
-               {
-                 set_fatal_syntax_error
-                   (_("the optional immediate offset can only be 0"));
-                 goto failure;
-               }
-           }
-         po_char_or_fail (']');
-         info->addr.base_regno = val;
-         break;
+         {
+           /* [<Xn|SP>{, #<simm>}]  */
+           char *start = str;
+           /* First use the normal address-parsing routines, to get
+              the usual syntax errors.  */
+           po_misc_or_fail (parse_address (&str, info));
+           if (info->addr.pcrel || info->addr.offset.is_reg
+               || !info->addr.preind || info->addr.postind
+               || info->addr.writeback)
+             {
+               set_syntax_error (_("invalid addressing mode"));
+               goto failure;
+             }
+
+           /* Then retry, matching the specific syntax of these addresses.  */
+           str = start;
+           po_char_or_fail ('[');
+           po_reg_or_fail (REG_TYPE_R64_SP);
+           /* Accept optional ", #0".  */
+           if (operands[i] == AARCH64_OPND_ADDR_SIMPLE
+               && skip_past_char (&str, ','))
+             {
+               skip_past_char (&str, '#');
+               if (! skip_past_char (&str, '0'))
+                 {
+                   set_fatal_syntax_error
+                     (_("the optional immediate offset can only be 0"));
+                   goto failure;
+                 }
+             }
+           po_char_or_fail (']');
+           break;
+         }
 
        case AARCH64_OPND_ADDR_REGOFF:
          /* [<Xn|SP>, <R><m>{, <extend> {<amount>}}]  */
-         po_misc_or_fail (parse_address (&str, info, 0));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || !info->addr.offset.is_reg
              || !info->addr.preind || info->addr.postind
              || info->addr.writeback)
@@ -5216,13 +5671,18 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_ADDR_SIMM7:
-         po_misc_or_fail (parse_address (&str, info, 0));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || (!info->addr.preind && !info->addr.postind))
            {
              set_syntax_error (_("invalid addressing mode"));
              goto failure;
            }
+         if (inst.reloc.type != BFD_RELOC_UNUSED)
+           {
+             set_syntax_error (_("relocation not allowed"));
+             goto failure;
+           }
          assign_imm_if_const_or_fixup_later (&inst.reloc, info,
                                              /* addr_off_p */ 1,
                                              /* need_libopcodes_p */ 1,
@@ -5231,7 +5691,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_ADDR_SIMM9:
        case AARCH64_OPND_ADDR_SIMM9_2:
-         po_misc_or_fail (parse_address_reloc (&str, info));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || (!info->addr.preind && !info->addr.postind)
              || (operands[i] == AARCH64_OPND_ADDR_SIMM9_2
@@ -5252,7 +5712,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_ADDR_UIMM12:
-         po_misc_or_fail (parse_address_reloc (&str, info));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || !info->addr.preind || info->addr.writeback)
            {
@@ -5261,14 +5721,18 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            }
          if (inst.reloc.type == BFD_RELOC_UNUSED)
            aarch64_set_gas_internal_fixup (&inst.reloc, info, 1);
-         else if (inst.reloc.type == BFD_RELOC_AARCH64_LDST_LO12)
+         else if (inst.reloc.type == BFD_RELOC_AARCH64_LDST_LO12
+                  || (inst.reloc.type
+                      == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12)
+                  || (inst.reloc.type
+                      == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC))
            inst.reloc.type = ldst_lo12_determine_real_reloc_type ();
          /* Leave qualifier to be determined by libopcodes.  */
          break;
 
        case AARCH64_OPND_SIMD_ADDR_POST:
          /* [<Xn|SP>], <Xm|#<amount>>  */
-         po_misc_or_fail (parse_address (&str, info, 1));
+         po_misc_or_fail (parse_address (&str, info));
          if (!info->addr.postind || !info->addr.writeback)
            {
              set_syntax_error (_("invalid addressing mode"));
@@ -5289,7 +5753,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_SYSREG:
-         if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1))
+         if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0))
              == PARSE_FAIL)
            {
              set_syntax_error (_("unknown or missing system register name"));
@@ -5299,7 +5763,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_PSTATEFIELD:
-         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0))
+         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1))
              == PARSE_FAIL)
            {
              set_syntax_error (_("unknown or missing PSTATE field name"));
@@ -5358,6 +5822,12 @@ sys_reg_ins:
          inst.base.operands[i].prfop = aarch64_prfops + val;
          break;
 
+       case AARCH64_OPND_BARRIER_PSB:
+         val = parse_barrier_psb (&str, &(info->hint_option));
+         if (val == PARSE_FAIL)
+           goto failure;
+         break;
+
        default:
          as_fatal (_("unhandled operand code %d"), operands[i]);
        }
@@ -5690,6 +6160,14 @@ md_assemble (char *str)
 
   init_operand_error_report ();
 
+  /* Sections are assumed to start aligned. In executable section, there is no
+     MAP_DATA symbol pending. So we only align the address during
+     MAP_DATA --> MAP_INSN transition.
+     For other sections, this is not guaranteed.  */
+  enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
+  if (!need_pass_2 && subseg_text_p (now_seg) && mapstate == MAP_DATA)
+    frag_align_code (2, 0);
+
   saved_cond = inst.cond;
   reset_aarch64_instruction (&inst);
   inst.cond = saved_cond;
@@ -5705,15 +6183,6 @@ md_assemble (char *str)
        dump_opcode_operands (opcode);
 #endif /* DEBUG_AARCH64 */
 
-    /* Sections are assumed to start aligned. In executable section, there is no
-       MAP_DATA symbol pending. So we only align the address during
-       MAP_DATA --> MAP_INSN transition.
-       For other sections, this is not guaranteed, align it anyway.  */
-    enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
-    if (!need_pass_2 && ((subseg_text_p (now_seg) && mapstate == MAP_DATA)
-                        || !subseg_text_p (now_seg)))
-      frag_align_code (2, 0);
-
       mapping_state (MAP_INSN);
 
       inst_base = &inst.base;
@@ -5740,7 +6209,7 @@ md_assemble (char *str)
        {
          /* Check that this instruction is supported for this CPU.  */
          if (!opcode->avariant
-             || !AARCH64_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
+             || !AARCH64_CPU_HAS_ALL_FEATURES (cpu_variant, *opcode->avariant))
            {
              as_bad (_("selected processor does not support `%s'"), str);
              return;
@@ -5757,8 +6226,7 @@ md_assemble (char *str)
                 store the instruction information for the future fix-up.  */
              struct aarch64_inst *copy;
              gas_assert (inst.reloc.type != BFD_RELOC_UNUSED);
-             if ((copy = xmalloc (sizeof (struct aarch64_inst))) == NULL)
-               abort ();
+             copy = XNEW (struct aarch64_inst);
              memcpy (copy, &inst.base, sizeof (struct aarch64_inst));
              output_inst (copy);
            }
@@ -5826,11 +6294,13 @@ aarch64_canonicalize_symbol_name (char *name)
 
 #define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE }
 #define REGNUM(p,n,t) REGDEF(p##n, n, t)
-#define REGSET31(p,t) \
+#define REGSET16(p,t) \
   REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
   REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
   REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
-  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t), \
+  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
+#define REGSET31(p,t) \
+  REGSET16(p, t), \
   REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
   REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
   REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
@@ -5870,10 +6340,18 @@ static const reg_entry reg_names[] = {
 
   /* FP/SIMD registers.  */
   REGSET (v, VN), REGSET (V, VN),
+
+  /* SVE vector registers.  */
+  REGSET (z, ZN), REGSET (Z, ZN),
+
+  /* SVE predicate registers.  */
+  REGSET16 (p, PN), REGSET16 (P, PN)
 };
 
 #undef REGDEF
 #undef REGNUM
+#undef REGSET16
+#undef REGSET31
 #undef REGSET
 
 #define N 1
@@ -5977,7 +6455,7 @@ aarch64_handle_align (fragS * fragP)
 {
   /* NOP = d503201f */
   /* AArch64 instructions are always little-endian.  */
-  static char const aarch64_noop[4] = { 0x1f, 0x20, 0x03, 0xd5 };
+  static unsigned char const aarch64_noop[4] = { 0x1f, 0x20, 0x03, 0xd5 };
 
   int bytes, fix, noop_size;
   char *p;
@@ -6030,21 +6508,24 @@ aarch64_init_frag (fragS * fragP, int max_chars)
   /* Record a mapping symbol for alignment frags.  We will delete this
      later if the alignment ends up empty.  */
   if (!fragP->tc_frag_data.recorded)
+    fragP->tc_frag_data.recorded = 1;
+
+  switch (fragP->fr_type)
     {
-      fragP->tc_frag_data.recorded = 1;
-      switch (fragP->fr_type)
-       {
-       case rs_align:
-       case rs_align_test:
-       case rs_fill:
-         mapping_state_2 (MAP_DATA, max_chars);
-         break;
-       case rs_align_code:
-         mapping_state_2 (MAP_INSN, max_chars);
-         break;
-       default:
-         break;
-       }
+    case rs_align_test:
+    case rs_fill:
+      mapping_state_2 (MAP_DATA, max_chars);
+      break;
+    case rs_align:
+      /* PR 20364: We can get alignment frags in code sections,
+        so do not just assume that we should use the MAP_DATA state.  */
+      mapping_state_2 (subseg_text_p (now_seg) ? MAP_INSN : MAP_DATA, max_chars);
+      break;
+    case rs_align_code:
+      mapping_state_2 (MAP_INSN, max_chars);
+      break;
+    default:
+      break;
     }
 }
 \f
@@ -6604,8 +7085,8 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
        }
       break;
 
-    case BFD_RELOC_AARCH64_JUMP26:
     case BFD_RELOC_AARCH64_CALL26:
+    case BFD_RELOC_AARCH64_JUMP26:
       if (fixP->fx_done || !seg->use_rela_p)
        {
          if (value & 3)
@@ -6621,18 +7102,36 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       break;
 
     case BFD_RELOC_AARCH64_MOVW_G0:
-    case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_G0_S:
+    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
       scale = 0;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G1:
-    case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_MOVW_G1_NC:
+    case BFD_RELOC_AARCH64_MOVW_G1_S:
+    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
       scale = 16;
       goto movw_common;
+    case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+      scale = 0;
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      /* Should always be exported to object file, see
+        aarch64_force_relocation().  */
+      gas_assert (!fixP->fx_done);
+      gas_assert (seg->use_rela_p);
+      goto movw_common;
+    case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+      scale = 16;
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      /* Should always be exported to object file, see
+        aarch64_force_relocation().  */
+      gas_assert (!fixP->fx_done);
+      gas_assert (seg->use_rela_p);
+      goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G2:
-    case BFD_RELOC_AARCH64_MOVW_G2_S:
     case BFD_RELOC_AARCH64_MOVW_G2_NC:
+    case BFD_RELOC_AARCH64_MOVW_G2_S:
       scale = 32;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G3:
@@ -6658,6 +7157,8 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
                case BFD_RELOC_AARCH64_MOVW_G1:
                case BFD_RELOC_AARCH64_MOVW_G2:
                case BFD_RELOC_AARCH64_MOVW_G3:
+               case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+               case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
                  if (unsigned_overflow (value, scale + 16))
                    as_bad_where (fixP->fx_file, fixP->fx_line,
                                  _("unsigned value out of range"));
@@ -6726,10 +7227,33 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
     case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
     case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+    case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
     case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
     case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+    case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+    case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+    case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -6755,18 +7279,21 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       gas_assert (seg->use_rela_p);
       break;
 
-    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
-    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
     case BFD_RELOC_AARCH64_ADD_LO12:
-    case BFD_RELOC_AARCH64_LDST8_LO12:
+    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+    case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+    case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LDST128_LO12:
     case BFD_RELOC_AARCH64_LDST16_LO12:
     case BFD_RELOC_AARCH64_LDST32_LO12:
     case BFD_RELOC_AARCH64_LDST64_LO12:
-    case BFD_RELOC_AARCH64_LDST128_LO12:
-    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
-    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
-    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
-    case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LDST8_LO12:
       /* Should always be exported to object file, see
         aarch64_force_relocation().  */
       gas_assert (!fixP->fx_done);
@@ -6774,8 +7301,8 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       break;
 
     case BFD_RELOC_AARCH64_TLSDESC_ADD:
-    case BFD_RELOC_AARCH64_TLSDESC_LDR:
     case BFD_RELOC_AARCH64_TLSDESC_CALL:
+    case BFD_RELOC_AARCH64_TLSDESC_LDR:
       break;
 
     case BFD_RELOC_UNUSED:
@@ -6808,9 +7335,9 @@ tc_gen_reloc (asection * section, fixS * fixp)
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = xmalloc (sizeof (arelent));
+  reloc = XNEW (arelent);
 
-  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
@@ -6901,9 +7428,9 @@ aarch64_force_relocation (struct fix *fixp)
          even if the symbol is extern or weak.  */
       return 0;
 
-    case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC:
     case BFD_RELOC_AARCH64_LD_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC:
       /* Pseudo relocs that need to be fixed up according to
         ilp32_p.  */
       return 0;
@@ -6914,6 +7441,9 @@ aarch64_force_relocation (struct fix *fixp)
     case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
     case BFD_RELOC_AARCH64_GOT_LD_PREL19:
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+    case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
     case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
     case BFD_RELOC_AARCH64_LDST128_LO12:
     case BFD_RELOC_AARCH64_LDST16_LO12:
@@ -6926,13 +7456,38 @@ aarch64_force_relocation (struct fix *fixp)
     case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
     case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
     case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+    case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
     case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
     case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+    case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
     case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
     case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+    case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+    case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+   case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+    case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
+    case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -6956,6 +7511,11 @@ aarch64_force_relocation (struct fix *fixp)
 const char *
 elf64_aarch64_target_format (void)
 {
+  if (strcmp (TARGET_OS, "cloudabi") == 0)
+    {
+      /* FIXME: What to do for ilp32_p ?  */
+      return target_big_endian ? "elf64-bigaarch64-cloudabi" : "elf64-littleaarch64-cloudabi";
+    }
   if (target_big_endian)
     return ilp32_p ? "elf32-bigaarch64" : "elf64-bigaarch64";
   else
@@ -7087,7 +7647,7 @@ fill_instruction_hash_table (void)
       templates *templ, *new_templ;
       templ = hash_find (aarch64_ops_hsh, opcode->name);
 
-      new_templ = (templates *) xmalloc (sizeof (templates));
+      new_templ = XNEW (templates);
       new_templ->opcode = opcode;
       new_templ->next = NULL;
 
@@ -7118,8 +7678,7 @@ get_upper_str (const char *str)
 {
   char *ret;
   size_t len = strlen (str);
-  if ((ret = xmalloc (len + 1)) == NULL)
-    abort ();
+  ret = XNEWVEC (char, len + 1);
   convert_to_upper (ret, str, len);
   return ret;
 }
@@ -7144,7 +7703,8 @@ md_begin (void)
       || (aarch64_reg_hsh = hash_new ()) == NULL
       || (aarch64_barrier_opt_hsh = hash_new ()) == NULL
       || (aarch64_nzcv_hsh = hash_new ()) == NULL
-      || (aarch64_pldop_hsh = hash_new ()) == NULL)
+      || (aarch64_pldop_hsh = hash_new ()) == NULL
+      || (aarch64_hint_opt_hsh = hash_new ()) == NULL)
     as_fatal (_("virtual memory exhausted"));
 
   fill_instruction_hash_table ();
@@ -7158,24 +7718,24 @@ md_begin (void)
                         aarch64_pstatefields[i].name,
                         (void *) (aarch64_pstatefields + i));
 
-  for (i = 0; aarch64_sys_regs_ic[i].template != NULL; i++)
+  for (i = 0; aarch64_sys_regs_ic[i].name != NULL; i++)
     checked_hash_insert (aarch64_sys_regs_ic_hsh,
-                        aarch64_sys_regs_ic[i].template,
+                        aarch64_sys_regs_ic[i].name,
                         (void *) (aarch64_sys_regs_ic + i));
 
-  for (i = 0; aarch64_sys_regs_dc[i].template != NULL; i++)
+  for (i = 0; aarch64_sys_regs_dc[i].name != NULL; i++)
     checked_hash_insert (aarch64_sys_regs_dc_hsh,
-                        aarch64_sys_regs_dc[i].template,
+                        aarch64_sys_regs_dc[i].name,
                         (void *) (aarch64_sys_regs_dc + i));
 
-  for (i = 0; aarch64_sys_regs_at[i].template != NULL; i++)
+  for (i = 0; aarch64_sys_regs_at[i].name != NULL; i++)
     checked_hash_insert (aarch64_sys_regs_at_hsh,
-                        aarch64_sys_regs_at[i].template,
+                        aarch64_sys_regs_at[i].name,
                         (void *) (aarch64_sys_regs_at + i));
 
-  for (i = 0; aarch64_sys_regs_tlbi[i].template != NULL; i++)
+  for (i = 0; aarch64_sys_regs_tlbi[i].name != NULL; i++)
     checked_hash_insert (aarch64_sys_regs_tlbi_hsh,
-                        aarch64_sys_regs_tlbi[i].template,
+                        aarch64_sys_regs_tlbi[i].name,
                         (void *) (aarch64_sys_regs_tlbi + i));
 
   for (i = 0; i < ARRAY_SIZE (reg_names); i++)
@@ -7240,6 +7800,17 @@ md_begin (void)
                           (void *) (aarch64_prfops + i));
     }
 
+  for (i = 0; aarch64_hint_options[i].name != NULL; i++)
+    {
+      const char* name = aarch64_hint_options[i].name;
+
+      checked_hash_insert (aarch64_hint_opt_hsh, name,
+                          (void *) (aarch64_hint_options + i));
+      /* Also hash the name in the upper case.  */
+      checked_hash_insert (aarch64_pldop_hsh, get_upper_str (name),
+                          (void *) (aarch64_hint_options + i));
+    }
+
   /* Set the cpu variant based on the command-line options.  */
   if (!mcpu_cpu_opt)
     mcpu_cpu_opt = march_cpu_opt;
@@ -7284,8 +7855,8 @@ size_t md_longopts_size = sizeof (md_longopts);
 
 struct aarch64_option_table
 {
-  char *option;                        /* Option name to match.  */
-  char *help;                  /* Help information.  */
+  const char *option;                  /* Option name to match.  */
+  const char *help;                    /* Help information.  */
   int *var;                    /* Variable to change.  */
   int value;                   /* What to change it to.  */
   char *deprecated;            /* If non-null, print this message.  */
@@ -7307,7 +7878,7 @@ static struct aarch64_option_table aarch64_opts[] = {
 
 struct aarch64_cpu_option_table
 {
-  char *name;
+  const char *name;
   const aarch64_feature_set value;
   /* The canonical name of the CPU, or NULL to use NAME converted to upper
      case.  */
@@ -7318,18 +7889,28 @@ struct aarch64_cpu_option_table
    recognized by GCC.  */
 static const struct aarch64_cpu_option_table aarch64_cpus[] = {
   {"all", AARCH64_ANY, NULL},
+  {"cortex-a35", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                 AARCH64_FEATURE_CRC), "Cortex-A35"},
   {"cortex-a53", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                  AARCH64_FEATURE_CRC), "Cortex-A53"},
   {"cortex-a57", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                  AARCH64_FEATURE_CRC), "Cortex-A57"},
   {"cortex-a72", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                  AARCH64_FEATURE_CRC), "Cortex-A72"},
+  {"cortex-a73", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                 AARCH64_FEATURE_CRC), "Cortex-A73"},
   {"exynos-m1", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                 AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
                                "Samsung Exynos M1"},
+  {"qdf24xx", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                              AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
+   "Qualcomm QDF24XX"},
   {"thunderx", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
    "Cavium ThunderX"},
+  {"vulcan", AARCH64_FEATURE (AARCH64_ARCH_V8_1,
+                             AARCH64_FEATURE_CRYPTO),
+  "Broadcom Vulcan"},
   /* The 'xgene-1' name is an older name for 'xgene1', which was used
      in earlier releases and is superseded by 'xgene1' in all
      tools.  */
@@ -7344,7 +7925,7 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = {
 
 struct aarch64_arch_option_table
 {
-  char *name;
+  const char *name;
   const aarch64_feature_set value;
 };
 
@@ -7353,35 +7934,87 @@ struct aarch64_arch_option_table
 static const struct aarch64_arch_option_table aarch64_archs[] = {
   {"all", AARCH64_ANY},
   {"armv8-a", AARCH64_ARCH_V8},
+  {"armv8.1-a", AARCH64_ARCH_V8_1},
+  {"armv8.2-a", AARCH64_ARCH_V8_2},
   {NULL, AARCH64_ARCH_NONE}
 };
 
 /* ISA extensions.  */
 struct aarch64_option_cpu_value_table
 {
-  char *name;
+  const char *name;
   const aarch64_feature_set value;
+  const aarch64_feature_set require; /* Feature dependencies.  */
 };
 
 static const struct aarch64_option_cpu_value_table aarch64_features[] = {
-  {"crc",              AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0)},
-  {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0)},
-  {"fp",               AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
-  {"lse",              AARCH64_FEATURE (AARCH64_FEATURE_LSE, 0)},
-  {"simd",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
-  {NULL,               AARCH64_ARCH_NONE}
+  {"crc",              AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0),
+                       AARCH64_ARCH_NONE},
+  {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0),
+                       AARCH64_ARCH_NONE},
+  {"fp",               AARCH64_FEATURE (AARCH64_FEATURE_FP, 0),
+                       AARCH64_ARCH_NONE},
+  {"lse",              AARCH64_FEATURE (AARCH64_FEATURE_LSE, 0),
+                       AARCH64_ARCH_NONE},
+  {"simd",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0),
+                       AARCH64_ARCH_NONE},
+  {"pan",              AARCH64_FEATURE (AARCH64_FEATURE_PAN, 0),
+                       AARCH64_ARCH_NONE},
+  {"lor",              AARCH64_FEATURE (AARCH64_FEATURE_LOR, 0),
+                       AARCH64_ARCH_NONE},
+  {"ras",              AARCH64_FEATURE (AARCH64_FEATURE_RAS, 0),
+                       AARCH64_ARCH_NONE},
+  {"rdma",             AARCH64_FEATURE (AARCH64_FEATURE_RDMA, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
+  {"fp16",             AARCH64_FEATURE (AARCH64_FEATURE_F16, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
+  {"profile",          AARCH64_FEATURE (AARCH64_FEATURE_PROFILE, 0),
+                       AARCH64_ARCH_NONE},
+  {NULL,               AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
 };
 
 struct aarch64_long_option_table
 {
-  char *option;                        /* Substring to match.  */
-  char *help;                  /* Help information.  */
-  int (*func) (char *subopt);  /* Function to decode sub-option.  */
+  const char *option;                  /* Substring to match.  */
+  const char *help;                    /* Help information.  */
+  int (*func) (const char *subopt);    /* Function to decode sub-option.  */
   char *deprecated;            /* If non-null, print this message.  */
 };
 
+/* Transitive closure of features depending on set.  */
+static aarch64_feature_set
+aarch64_feature_disable_set (aarch64_feature_set set)
+{
+  const struct aarch64_option_cpu_value_table *opt;
+  aarch64_feature_set prev = 0;
+
+  while (prev != set) {
+    prev = set;
+    for (opt = aarch64_features; opt->name != NULL; opt++)
+      if (AARCH64_CPU_HAS_ANY_FEATURES (opt->require, set))
+        AARCH64_MERGE_FEATURE_SETS (set, set, opt->value);
+  }
+  return set;
+}
+
+/* Transitive closure of dependencies of set.  */
+static aarch64_feature_set
+aarch64_feature_enable_set (aarch64_feature_set set)
+{
+  const struct aarch64_option_cpu_value_table *opt;
+  aarch64_feature_set prev = 0;
+
+  while (prev != set) {
+    prev = set;
+    for (opt = aarch64_features; opt->name != NULL; opt++)
+      if (AARCH64_CPU_HAS_FEATURE (set, opt->value))
+        AARCH64_MERGE_FEATURE_SETS (set, set, opt->require);
+  }
+  return set;
+}
+
 static int
-aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
+aarch64_parse_features (const char *str, const aarch64_feature_set **opt_p,
                        bfd_boolean ext_only)
 {
   /* We insist on extensions being added before being removed.  We achieve
@@ -7389,7 +8022,7 @@ aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
      adding an extension (1) or removing it (0) and only allowing it to
      change in the order -1 -> 1 -> 0.  */
   int adding_value = -1;
-  aarch64_feature_set *ext_set = xmalloc (sizeof (aarch64_feature_set));
+  aarch64_feature_set *ext_set = XNEW (aarch64_feature_set);
 
   /* Copy the feature set, so that we can modify it.  */
   *ext_set = **opt_p;
@@ -7398,7 +8031,7 @@ aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
   while (str != NULL && *str != 0)
     {
       const struct aarch64_option_cpu_value_table *opt;
-      char *ext = NULL;
+      const char *ext = NULL;
       int optlen;
 
       if (!ext_only)
@@ -7447,11 +8080,19 @@ aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
       for (opt = aarch64_features; opt->name != NULL; opt++)
        if (strncmp (opt->name, str, optlen) == 0)
          {
+           aarch64_feature_set set;
+
            /* Add or remove the extension.  */
            if (adding_value)
-             AARCH64_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
+             {
+               set = aarch64_feature_enable_set (opt->value);
+               AARCH64_MERGE_FEATURE_SETS (*ext_set, *ext_set, set);
+             }
            else
-             AARCH64_CLEAR_FEATURE (*ext_set, *ext_set, opt->value);
+             {
+               set = aarch64_feature_disable_set (opt->value);
+               AARCH64_CLEAR_FEATURE (*ext_set, *ext_set, set);
+             }
            break;
          }
 
@@ -7468,10 +8109,10 @@ aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
 }
 
 static int
-aarch64_parse_cpu (char *str)
+aarch64_parse_cpu (const char *str)
 {
   const struct aarch64_cpu_option_table *opt;
-  char *ext = strchr (str, '+');
+  const char *ext = strchr (str, '+');
   size_t optlen;
 
   if (ext != NULL)
@@ -7500,10 +8141,10 @@ aarch64_parse_cpu (char *str)
 }
 
 static int
-aarch64_parse_arch (char *str)
+aarch64_parse_arch (const char *str)
 {
   const struct aarch64_arch_option_table *opt;
-  char *ext = strchr (str, '+');
+  const char *ext = strchr (str, '+');
   size_t optlen;
 
   if (ext != NULL)
@@ -7534,32 +8175,30 @@ aarch64_parse_arch (char *str)
 /* ABIs.  */
 struct aarch64_option_abi_value_table
 {
-  char *name;
+  const char *name;
   enum aarch64_abi_type value;
 };
 
 static const struct aarch64_option_abi_value_table aarch64_abis[] = {
   {"ilp32",            AARCH64_ABI_ILP32},
   {"lp64",             AARCH64_ABI_LP64},
-  {NULL,               0}
 };
 
 static int
-aarch64_parse_abi (char *str)
+aarch64_parse_abi (const char *str)
 {
-  const struct aarch64_option_abi_value_table *opt;
-  size_t optlen = strlen (str);
+  unsigned int i;
 
-  if (optlen == 0)
+  if (str[0] == '\0')
     {
       as_bad (_("missing abi name `%s'"), str);
       return 0;
     }
 
-  for (opt = aarch64_abis; opt->name != NULL; opt++)
-    if (strlen (opt->name) == optlen && strncmp (str, opt->name, optlen) == 0)
+  for (i = 0; i < ARRAY_SIZE (aarch64_abis); i++)
+    if (strcmp (str, aarch64_abis[i].name) == 0)
       {
-       aarch64_abi = opt->value;
+       aarch64_abi = aarch64_abis[i].value;
        return 1;
       }
 
@@ -7580,7 +8219,7 @@ static struct aarch64_long_option_table aarch64_long_opts[] = {
 };
 
 int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
 {
   struct aarch64_option_table *opt;
   struct aarch64_long_option_table *lopt;
This page took 0.06707 seconds and 4 git commands to generate.