]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-aarch64.c
aarch64: Enable Cortex-A720 CPU
[thirdparty/binutils-gdb.git] / gas / config / tc-aarch64.c
index 19a5d49d09067c85aed55739e219cd2259e31f5b..19fbc7c46466ab30725e9ae16ae576aea4de5d6d 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-aarch64.c -- Assemble for the AArch64 ISA
 
-   Copyright (C) 2009-2021 Free Software Foundation, Inc.
+   Copyright (C) 2009-2023 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GAS.
 #ifdef OBJ_ELF
 #include "elf/aarch64.h"
 #include "dw2gencfi.h"
+#include "sframe.h"
+#include "gen-sframe.h"
 #endif
 
+#include "dw2gencfi.h"
 #include "dwarf2dbg.h"
 
 /* Types of processor to assemble for.  */
@@ -61,21 +64,30 @@ static aarch64_instr_sequence *insn_sequence = NULL;
 #ifdef OBJ_ELF
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 static symbolS *GOT_symbol;
+#endif
 
 /* Which ABI to use.  */
 enum aarch64_abi_type
 {
   AARCH64_ABI_NONE = 0,
   AARCH64_ABI_LP64 = 1,
-  AARCH64_ABI_ILP32 = 2
+  AARCH64_ABI_ILP32 = 2,
+  AARCH64_ABI_LLP64 = 3
 };
 
+unsigned int aarch64_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame stack trace info.  */
+unsigned int aarch64_sframe_cfa_fp_reg;
+unsigned int aarch64_sframe_cfa_ra_reg;
+
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "aarch64"
 #endif
 
+#ifdef OBJ_ELF
 /* DEFAULT_ARCH is initialized in gas/configure.tgt.  */
 static const char *default_arch = DEFAULT_ARCH;
+#endif
 
 /* AArch64 ABI for the output file.  */
 static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_NONE;
@@ -85,7 +97,10 @@ static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_NONE;
    64-bit model, in which the C int type is 32-bits but the C long type
    and all pointer types are 64-bit objects (LP64).  */
 #define ilp32_p                (aarch64_abi == AARCH64_ABI_ILP32)
-#endif
+
+/* When non zero, C types int and long are 32 bit,
+   pointers, however are 64 bit */
+#define llp64_p (aarch64_abi == AARCH64_ABI_LLP64)
 
 enum vector_el_type
 {
@@ -108,6 +123,7 @@ struct vector_type_el
 {
   enum vector_el_type type;
   unsigned char defined;
+  unsigned element_size;
   unsigned width;
   int64_t index;
 };
@@ -129,11 +145,7 @@ struct aarch64_instruction
   /* libopcodes structure for instruction intermediate representation.  */
   aarch64_inst base;
   /* Record assembly errors found during the parsing.  */
-  struct
-    {
-      enum aarch64_operand_error_kind kind;
-      const char *error;
-    } parsing_error;
+  aarch64_operand_error parsing_error;
   /* The condition that appears in the assembly line.  */
   int cond;
   /* Relocation information (including the GAS internal fixup).  */
@@ -149,12 +161,31 @@ static aarch64_instruction inst;
 static bool parse_operands (char *, const aarch64_opcode *);
 static bool programmer_friendly_fixup (aarch64_instruction *);
 
-#ifdef OBJ_ELF
-#  define now_instr_sequence seg_info \
-               (now_seg)->tc_segment_info_data.insn_sequence
-#else
-static struct aarch64_instr_sequence now_instr_sequence;
-#endif
+/* If an AARCH64_OPDE_SYNTAX_ERROR has no error string, its first three
+   data fields contain the following information:
+
+   data[0].i:
+     A mask of register types that would have been acceptable as bare
+     operands, outside of a register list.  In addition, SEF_DEFAULT_ERROR
+     is set if a general parsing error occured for an operand (that is,
+     an error not related to registers, and having no error string).
+
+   data[1].i:
+     A mask of register types that would have been acceptable inside
+     a register list.  In addition, SEF_IN_REGLIST is set if the
+     operand contained a '{' and if we got to the point of trying
+     to parse a register inside a list.
+
+   data[2].i:
+     The mask associated with the register that was actually seen, or 0
+     if none.  A nonzero value describes a register inside a register
+     list if data[1].i & SEF_IN_REGLIST, otherwise it describes a bare
+     register.
+
+   The idea is that stringless errors from multiple opcode templates can
+   be ORed together to give a summary of the available alternatives.  */
+#define SEF_DEFAULT_ERROR (1U << 31)
+#define SEF_IN_REGLIST (1U << 31)
 
 /* Diagnostics inline function utilities.
 
@@ -176,8 +207,8 @@ static struct aarch64_instr_sequence now_instr_sequence;
 static inline void
 clear_error (void)
 {
+  memset (&inst.parsing_error, 0, sizeof (inst.parsing_error));
   inst.parsing_error.kind = AARCH64_OPDE_NIL;
-  inst.parsing_error.error = NULL;
 }
 
 static inline bool
@@ -186,21 +217,11 @@ error_p (void)
   return inst.parsing_error.kind != AARCH64_OPDE_NIL;
 }
 
-static inline const char *
-get_error_message (void)
-{
-  return inst.parsing_error.error;
-}
-
-static inline enum aarch64_operand_error_kind
-get_error_kind (void)
-{
-  return inst.parsing_error.kind;
-}
-
 static inline void
 set_error (enum aarch64_operand_error_kind kind, const char *error)
 {
+  memset (&inst.parsing_error, 0, sizeof (inst.parsing_error));
+  inst.parsing_error.index = -1;
   inst.parsing_error.kind = kind;
   inst.parsing_error.error = error;
 }
@@ -217,6 +238,14 @@ static inline void
 set_default_error (void)
 {
   set_error (AARCH64_OPDE_SYNTAX_ERROR, NULL);
+  inst.parsing_error.data[0].i = SEF_DEFAULT_ERROR;
+}
+
+static inline void
+set_expected_error (unsigned int flags)
+{
+  set_error (AARCH64_OPDE_SYNTAX_ERROR, NULL);
+  inst.parsing_error.data[0].i = flags;
 }
 
 static inline void
@@ -268,63 +297,88 @@ struct reloc_entry
   BASIC_REG_TYPE(R_64) /* x[0-30] */   \
   BASIC_REG_TYPE(SP_32)        /* wsp     */   \
   BASIC_REG_TYPE(SP_64)        /* sp      */   \
-  BASIC_REG_TYPE(Z_32) /* wzr     */   \
-  BASIC_REG_TYPE(Z_64) /* xzr     */   \
+  BASIC_REG_TYPE(ZR_32)        /* wzr     */   \
+  BASIC_REG_TYPE(ZR_64)        /* xzr     */   \
   BASIC_REG_TYPE(FP_B) /* b[0-31] *//* NOTE: keep FP_[BHSDQ] consecutive! */\
   BASIC_REG_TYPE(FP_H) /* h[0-31] */   \
   BASIC_REG_TYPE(FP_S) /* s[0-31] */   \
   BASIC_REG_TYPE(FP_D) /* d[0-31] */   \
   BASIC_REG_TYPE(FP_Q) /* q[0-31] */   \
-  BASIC_REG_TYPE(VN)   /* v[0-31] */   \
-  BASIC_REG_TYPE(ZN)   /* z[0-31] */   \
-  BASIC_REG_TYPE(PN)   /* p[0-15] */   \
+  BASIC_REG_TYPE(V)    /* v[0-31] */   \
+  BASIC_REG_TYPE(Z)    /* z[0-31] */   \
+  BASIC_REG_TYPE(P)    /* p[0-15] */   \
+  BASIC_REG_TYPE(PN)   /* pn[0-15] */  \
+  BASIC_REG_TYPE(ZA)   /* za */        \
+  BASIC_REG_TYPE(ZAT)  /* za[0-15] (ZA tile) */                        \
+  BASIC_REG_TYPE(ZATH) /* za[0-15]h (ZA tile horizontal slice) */      \
+  BASIC_REG_TYPE(ZATV) /* za[0-15]v (ZA tile vertical slice) */        \
+  BASIC_REG_TYPE(ZT0)  /* zt0 */                                       \
   /* Typecheck: any 64-bit int reg         (inc SP exc XZR).  */       \
   MULTI_REG_TYPE(R64_SP, REG_TYPE(R_64) | REG_TYPE(SP_64))             \
   /* Typecheck: same, plus SVE registers.  */                          \
   MULTI_REG_TYPE(SVE_BASE, REG_TYPE(R_64) | REG_TYPE(SP_64)            \
-                | REG_TYPE(ZN))                                        \
+                | REG_TYPE(Z))                                         \
   /* 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))                     \
+  MULTI_REG_TYPE(R_ZR, REG_TYPE(R_32) | REG_TYPE(R_64)                 \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_64))                   \
   /* Typecheck: same, plus SVE registers.  */                          \
   MULTI_REG_TYPE(SVE_OFFSET, REG_TYPE(R_32) | REG_TYPE(R_64)           \
-                | REG_TYPE(Z_32) | REG_TYPE(Z_64)                      \
-                | REG_TYPE(ZN))                                        \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_64)                    \
+                | REG_TYPE(Z))                                         \
   /* 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)               \
+  MULTI_REG_TYPE(R_ZR_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))                     \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_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).  */ \
-  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)       \
+  MULTI_REG_TYPE(R_ZR_BHSDQ_V, REG_TYPE(R_32) | REG_TYPE(R_64)         \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_64) | REG_TYPE(V)      \
                 | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
                 | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q))    \
   /* Typecheck: as above, but also Zn, Pn, and {W}SP.  This should only        \
      be used for SVE instructions, since Zn and Pn are valid symbols   \
      in other contexts.  */                                            \
-  MULTI_REG_TYPE(R_Z_SP_BHSDQ_VZP, REG_TYPE(R_32) | REG_TYPE(R_64)     \
+  MULTI_REG_TYPE(R_ZR_SP_BHSDQ_VZP, REG_TYPE(R_32) | REG_TYPE(R_64)    \
                 | REG_TYPE(SP_32) | REG_TYPE(SP_64)                    \
-                | REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN)       \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_64) | REG_TYPE(V)      \
                 | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
                 | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q)     \
-                | REG_TYPE(ZN) | REG_TYPE(PN))                         \
+                | REG_TYPE(Z) | REG_TYPE(P))                           \
+  /* Likewise, but with predicate-as-counter registers added.  */      \
+  MULTI_REG_TYPE(R_ZR_SP_BHSDQ_VZP_PN, REG_TYPE(R_32) | REG_TYPE(R_64) \
+                | REG_TYPE(SP_32) | REG_TYPE(SP_64)                    \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_64) | REG_TYPE(V)      \
+                | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
+                | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q)     \
+                | REG_TYPE(Z) | REG_TYPE(P) | REG_TYPE(PN))            \
   /* Any integer register; used for error messages only.  */           \
   MULTI_REG_TYPE(R_N, REG_TYPE(R_32) | REG_TYPE(R_64)                  \
                 | REG_TYPE(SP_32) | REG_TYPE(SP_64)                    \
-                | REG_TYPE(Z_32) | REG_TYPE(Z_64))                     \
+                | REG_TYPE(ZR_32) | REG_TYPE(ZR_64))                   \
+  /* Any vector register.  */                                          \
+  MULTI_REG_TYPE(VZ, REG_TYPE(V) | REG_TYPE(Z))                                \
+  /* An SVE vector or predicate register.  */                          \
+  MULTI_REG_TYPE(ZP, REG_TYPE(Z) | REG_TYPE(P))                                \
+  /* Any vector or predicate register.  */                             \
+  MULTI_REG_TYPE(VZP, REG_TYPE(V) | REG_TYPE(Z) | REG_TYPE(P))         \
+  /* The whole of ZA or a single tile.  */                             \
+  MULTI_REG_TYPE(ZA_ZAT, REG_TYPE(ZA) | REG_TYPE(ZAT))                 \
+  /* A horizontal or vertical slice of a ZA tile.  */                  \
+  MULTI_REG_TYPE(ZATHV, REG_TYPE(ZATH) | REG_TYPE(ZATV))               \
   /* Pseudo type to mark the end of the enumerator sequence.  */       \
-  BASIC_REG_TYPE(MAX)
+  END_REG_TYPE(MAX)
 
 #undef BASIC_REG_TYPE
 #define BASIC_REG_TYPE(T)      REG_TYPE_##T,
 #undef MULTI_REG_TYPE
 #define MULTI_REG_TYPE(T,V)    BASIC_REG_TYPE(T)
+#undef END_REG_TYPE
+#define END_REG_TYPE(T)                BASIC_REG_TYPE(T)
 
 /* Register type enumerators.  */
 typedef enum aarch64_reg_type_
@@ -339,6 +393,8 @@ typedef enum aarch64_reg_type_
 #define REG_TYPE(T)            (1 << REG_TYPE_##T)
 #undef MULTI_REG_TYPE
 #define MULTI_REG_TYPE(T,V)    V,
+#undef END_REG_TYPE
+#define END_REG_TYPE(T)                0
 
 /* Structure for a hash table entry for a register.  */
 typedef struct
@@ -358,84 +414,146 @@ static const unsigned reg_type_masks[] =
 #undef BASIC_REG_TYPE
 #undef REG_TYPE
 #undef MULTI_REG_TYPE
+#undef END_REG_TYPE
 #undef AARCH64_REG_TYPES
 
-/* Diagnostics used when we don't get a register of the expected type.
-   Note:  this has to synchronized with aarch64_reg_type definitions
-   above.  */
+/* We expected one of the registers in MASK to be specified.  If a register
+   of some kind was specified, SEEN is a mask that contains that register,
+   otherwise it is zero.
+
+   If it is possible to provide a relatively pithy message that describes
+   the error exactly, return a string that does so, reporting the error
+   against "operand %d".  Return null otherwise.
+
+   From a QoI perspective, any REG_TYPE_* that is passed as the first
+   argument to set_expected_reg_error should generally have its own message.
+   Providing messages for combinations of such REG_TYPE_*s can be useful if
+   it is possible to summarize the combination in a relatively natural way.
+   On the other hand, it seems better to avoid long lists of unrelated
+   things.  */
+
 static const char *
-get_reg_expected_msg (aarch64_reg_type reg_type)
+get_reg_expected_msg (unsigned int mask, unsigned int seen)
+{
+  /* First handle messages that use SEEN.  */
+  if ((mask & reg_type_masks[REG_TYPE_ZAT])
+      && (seen & reg_type_masks[REG_TYPE_ZATHV]))
+    return N_("expected an unsuffixed ZA tile at operand %d");
+
+  if ((mask & reg_type_masks[REG_TYPE_ZATHV])
+      && (seen & reg_type_masks[REG_TYPE_ZAT]))
+    return N_("missing horizontal or vertical suffix at operand %d");
+
+  if ((mask & reg_type_masks[REG_TYPE_ZA])
+      && (seen & (reg_type_masks[REG_TYPE_ZAT]
+                 | reg_type_masks[REG_TYPE_ZATHV])))
+    return N_("expected 'za' rather than a ZA tile at operand %d");
+
+  if ((mask & reg_type_masks[REG_TYPE_PN])
+      && (seen & reg_type_masks[REG_TYPE_P]))
+    return N_("expected a predicate-as-counter rather than predicate-as-mask"
+             " register at operand %d");
+
+  if ((mask & reg_type_masks[REG_TYPE_P])
+      && (seen & reg_type_masks[REG_TYPE_PN]))
+    return N_("expected a predicate-as-mask rather than predicate-as-counter"
+             " register at operand %d");
+
+  /* Integer, zero and stack registers.  */
+  if (mask == reg_type_masks[REG_TYPE_R_64])
+    return N_("expected a 64-bit integer register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_R_ZR])
+    return N_("expected an integer or zero register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_R_SP])
+    return N_("expected an integer or stack pointer register at operand %d");
+
+  /* Floating-point and SIMD registers.  */
+  if (mask == reg_type_masks[REG_TYPE_BHSDQ])
+    return N_("expected a scalar SIMD or floating-point register"
+             " at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_V])
+    return N_("expected an Advanced SIMD vector register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_Z])
+    return N_("expected an SVE vector register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_P]
+      || mask == (reg_type_masks[REG_TYPE_P] | reg_type_masks[REG_TYPE_PN]))
+    /* Use this error for "predicate-as-mask only" and "either kind of
+       predicate".  We report a more specific error if P is used where
+       PN is expected, and vice versa, so the issue at this point is
+       "predicate-like" vs. "not predicate-like".  */
+    return N_("expected an SVE predicate register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_PN])
+    return N_("expected an SVE predicate-as-counter register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_VZ])
+    return N_("expected a vector register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_ZP])
+    return N_("expected an SVE vector or predicate register at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_VZP])
+    return N_("expected a vector or predicate register at operand %d");
+
+  /* SME-related registers.  */
+  if (mask == reg_type_masks[REG_TYPE_ZA])
+    return N_("expected a ZA array vector at operand %d");
+  if (mask == (reg_type_masks[REG_TYPE_ZA_ZAT] | reg_type_masks[REG_TYPE_ZT0]))
+    return N_("expected ZT0 or a ZA mask at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_ZAT])
+    return N_("expected a ZA tile at operand %d");
+  if (mask == reg_type_masks[REG_TYPE_ZATHV])
+    return N_("expected a ZA tile slice at operand %d");
+
+  /* Integer and vector combos.  */
+  if (mask == (reg_type_masks[REG_TYPE_R_ZR] | reg_type_masks[REG_TYPE_V]))
+    return N_("expected an integer register or Advanced SIMD vector register"
+             " at operand %d");
+  if (mask == (reg_type_masks[REG_TYPE_R_ZR] | reg_type_masks[REG_TYPE_Z]))
+    return N_("expected an integer register or SVE vector register"
+             " at operand %d");
+  if (mask == (reg_type_masks[REG_TYPE_R_ZR] | reg_type_masks[REG_TYPE_VZ]))
+    return N_("expected an integer or vector register at operand %d");
+  if (mask == (reg_type_masks[REG_TYPE_R_ZR] | reg_type_masks[REG_TYPE_P]))
+    return N_("expected an integer or predicate register at operand %d");
+  if (mask == (reg_type_masks[REG_TYPE_R_ZR] | reg_type_masks[REG_TYPE_VZP]))
+    return N_("expected an integer, vector or predicate register"
+             " at operand %d");
+
+  /* SVE and SME combos.  */
+  if (mask == (reg_type_masks[REG_TYPE_Z] | reg_type_masks[REG_TYPE_ZATHV]))
+    return N_("expected an SVE vector register or ZA tile slice"
+             " at operand %d");
+
+  return NULL;
+}
+
+/* Record that we expected a register of type TYPE but didn't see one.
+   REG is the register that we actually saw, or null if we didn't see a
+   recognized register.  FLAGS is SEF_IN_REGLIST if we are parsing the
+   contents of a register list, otherwise it is zero.  */
+
+static inline void
+set_expected_reg_error (aarch64_reg_type type, const reg_entry *reg,
+                       unsigned int flags)
 {
-  const char *msg;
+  assert (flags == 0 || flags == SEF_IN_REGLIST);
+  set_error (AARCH64_OPDE_SYNTAX_ERROR, NULL);
+  if (flags & SEF_IN_REGLIST)
+    inst.parsing_error.data[1].i = reg_type_masks[type] | flags;
+  else
+    inst.parsing_error.data[0].i = reg_type_masks[type];
+  if (reg)
+    inst.parsing_error.data[2].i = reg_type_masks[reg->type];
+}
 
-  switch (reg_type)
-    {
-    case REG_TYPE_R_32:
-      msg = N_("integer 32-bit register expected");
-      break;
-    case REG_TYPE_R_64:
-      msg = N_("integer 64-bit register expected");
-      break;
-    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_SVE_BASE:
-      msg = N_("base register expected");
-      break;
-    case REG_TYPE_R_Z:
-      msg = N_("integer or zero register expected");
-      break;
-    case REG_TYPE_SVE_OFFSET:
-      msg = N_("offset 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;
-    case REG_TYPE_FP_B:
-      msg = N_("8-bit SIMD scalar register expected");
-      break;
-    case REG_TYPE_FP_H:
-      msg = N_("16-bit SIMD scalar or floating-point half precision "
-              "register expected");
-      break;
-    case REG_TYPE_FP_S:
-      msg = N_("32-bit SIMD scalar or floating-point single precision "
-              "register expected");
-      break;
-    case REG_TYPE_FP_D:
-      msg = N_("64-bit SIMD scalar or floating-point double precision "
-              "register expected");
-      break;
-    case REG_TYPE_FP_Q:
-      msg = N_("128-bit SIMD scalar or floating-point quad precision "
-              "register expected");
-      break;
-    case REG_TYPE_R_Z_BHSDQ_V:
-    case REG_TYPE_R_Z_SP_BHSDQ_VZP:
-      msg = N_("register expected");
-      break;
-    case REG_TYPE_BHSDQ:       /* any [BHSDQ]P FP  */
-      msg = N_("SIMD scalar or floating-point register expected");
-      break;
-    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);
-    }
-  return msg;
+/* Record that we expected a register list containing registers of type TYPE,
+   but didn't see the opening '{'.  If we saw a register instead, REG is the
+   register that we saw, otherwise it is null.  */
+
+static inline void
+set_expected_reglist_error (aarch64_reg_type type, const reg_entry *reg)
+{
+  set_error (AARCH64_OPDE_SYNTAX_ERROR, NULL);
+  inst.parsing_error.data[1].i = reg_type_masks[type];
+  if (reg)
+    inst.parsing_error.data[2].i = reg_type_masks[reg->type];
 }
 
 /* Some well known registers that we refer to directly elsewhere.  */
@@ -558,25 +676,18 @@ static bool in_aarch64_get_expression = false;
 #define ALLOW_ABSENT  false
 #define REJECT_ABSENT true
 
-/* Fifth argument to aarch64_get_expression.  */
-#define NORMAL_RESOLUTION false
-
 /* Return TRUE if the string pointed by *STR is successfully parsed
    as an valid expression; *EP will be filled with the information of
    such an expression.  Otherwise return FALSE.
 
    If ALLOW_IMMEDIATE_PREFIX is true then skip a '#' at the start.
-   If REJECT_ABSENT is true then trat missing expressions as an error.
-   If DEFER_RESOLUTION is true, then do not resolve expressions against
-   constant symbols.  Necessary if the expression is part of a fixup
-   that uses a reloc that must be emitted.  */
+   If REJECT_ABSENT is true then trat missing expressions as an error.  */
 
 static bool
 aarch64_get_expression (expressionS *  ep,
                        char **        str,
                        bool           allow_immediate_prefix,
-                       bool           reject_absent,
-                       bool           defer_resolution)
+                       bool           reject_absent)
 {
   char *save_in;
   segT seg;
@@ -596,10 +707,7 @@ aarch64_get_expression (expressionS *  ep,
   save_in = input_line_pointer;
   input_line_pointer = *str;
   in_aarch64_get_expression = true;
-  if (defer_resolution)
-    seg = deferred_expression (ep);
-  else
-    seg = expression (ep);
+  seg = expression (ep);
   in_aarch64_get_expression = false;
 
   if (ep->X_op == O_illegal || (reject_absent && ep->X_op == O_absent))
@@ -694,6 +802,81 @@ first_error_fmt (const char *format, ...)
     }
 }
 
+/* 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 vector_type_el *vectype)
+{
+  /* 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_4B,
+      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 | NTA_HASVARWIDTH))
+    {
+      /* Special case S_4B.  */
+      if (vectype->type == NT_b && vectype->width == 4)
+       return AARCH64_OPND_QLF_S_4B;
+
+      /* Special case S_2H.  */
+      if (vectype->type == NT_h && vectype->width == 2)
+       return AARCH64_OPND_QLF_S_2H;
+
+      /* Vector element register.  */
+      return AARCH64_OPND_QLF_S_B + vectype->type;
+    }
+  else
+    {
+      /* Vector register.  */
+      int reg_size = ele_size[vectype->type] * vectype->width;
+      unsigned offset;
+      unsigned shift;
+      if (reg_size != 16 && reg_size != 8 && reg_size != 4)
+       goto vectype_conversion_fail;
+
+      /* 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 = 3;
+      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_4B <= offset
+                 && offset <= AARCH64_OPND_QLF_V_1Q);
+      return offset;
+    }
+
+ vectype_conversion_fail:
+  first_error (_("bad vector arrangement type"));
+  return AARCH64_OPND_QLF_NIL;
+}
+
 /* Register parsing.  */
 
 /* Generic register parser which is called by other specialized
@@ -733,6 +916,38 @@ parse_reg (char **ccp)
   return reg;
 }
 
+/* Return the operand qualifier associated with all uses of REG, or
+   AARCH64_OPND_QLF_NIL if none.  AARCH64_OPND_QLF_NIL means either
+   that qualifiers don't apply to REG or that qualifiers are added
+   using suffixes.  */
+
+static aarch64_opnd_qualifier_t
+inherent_reg_qualifier (const reg_entry *reg)
+{
+  switch (reg->type)
+    {
+    case REG_TYPE_R_32:
+    case REG_TYPE_SP_32:
+    case REG_TYPE_ZR_32:
+      return AARCH64_OPND_QLF_W;
+
+    case REG_TYPE_R_64:
+    case REG_TYPE_SP_64:
+    case REG_TYPE_ZR_64:
+      return AARCH64_OPND_QLF_X;
+
+    case REG_TYPE_FP_B:
+    case REG_TYPE_FP_H:
+    case REG_TYPE_FP_S:
+    case REG_TYPE_FP_D:
+    case REG_TYPE_FP_Q:
+      return AARCH64_OPND_QLF_S_B + (reg->type - REG_TYPE_FP_B);
+
+    default:
+      return AARCH64_OPND_QLF_NIL;
+    }
+}
+
 /* Return TRUE if REG->TYPE is a valid type of TYPE; otherwise
    return FALSE.  */
 static bool
@@ -760,20 +975,8 @@ aarch64_addr_reg_parse (char **ccp, aarch64_reg_type reg_type,
 
   switch (reg->type)
     {
-    case REG_TYPE_R_32:
-    case REG_TYPE_SP_32:
-    case REG_TYPE_Z_32:
-      *qualifier = AARCH64_OPND_QLF_W;
-      break;
-
-    case REG_TYPE_R_64:
-    case REG_TYPE_SP_64:
-    case REG_TYPE_Z_64:
-      *qualifier = AARCH64_OPND_QLF_X;
-      break;
-
-    case REG_TYPE_ZN:
-      if ((reg_type_masks[reg_type] & (1 << REG_TYPE_ZN)) == 0
+    case REG_TYPE_Z:
+      if ((reg_type_masks[reg_type] & (1 << REG_TYPE_Z)) == 0
          || str[0] != '.')
        return NULL;
       switch (TOLOWER (str[1]))
@@ -791,7 +994,10 @@ aarch64_addr_reg_parse (char **ccp, aarch64_reg_type reg_type,
       break;
 
     default:
-      return NULL;
+      if (!aarch64_check_reg_type (reg, REG_TYPE_R_ZR_SP))
+       return NULL;
+      *qualifier = inherent_reg_qualifier (reg);
+      break;
     }
 
   *ccp = str;
@@ -808,7 +1014,7 @@ aarch64_addr_reg_parse (char **ccp, aarch64_reg_type reg_type,
 static const reg_entry *
 aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
 {
-  return aarch64_addr_reg_parse (ccp, REG_TYPE_R_Z_SP, qualifier);
+  return aarch64_addr_reg_parse (ccp, REG_TYPE_R_ZR_SP, qualifier);
 }
 
 /* Parse the qualifier of a vector register or vector element of type
@@ -831,7 +1037,7 @@ parse_vector_type_for_operand (aarch64_reg_type reg_type,
   gas_assert (*ptr == '.');
   ptr++;
 
-  if (reg_type == REG_TYPE_ZN || reg_type == REG_TYPE_PN || !ISDIGIT (*ptr))
+  if (reg_type != REG_TYPE_V || !ISDIGIT (*ptr))
     {
       width = 0;
       goto elt_size;
@@ -863,7 +1069,7 @@ parse_vector_type_for_operand (aarch64_reg_type reg_type,
       element_size = 64;
       break;
     case 'q':
-      if (reg_type == REG_TYPE_ZN || width == 1)
+      if (reg_type != REG_TYPE_V || width == 1)
        {
          type = NT_q;
          element_size = 128;
@@ -891,6 +1097,7 @@ parse_vector_type_for_operand (aarch64_reg_type reg_type,
 
   parsed_type->type = type;
   parsed_type->width = width;
+  parsed_type->element_size = element_size;
 
   *str = ptr;
 
@@ -929,67 +1136,135 @@ parse_predication_for_operand (struct vector_type_el *parsed_type, char **str)
   return true;
 }
 
+/* Return true if CH is a valid suffix character for registers of
+   type TYPE.  */
+
+static bool
+aarch64_valid_suffix_char_p (aarch64_reg_type type, char ch)
+{
+  switch (type)
+    {
+    case REG_TYPE_V:
+    case REG_TYPE_Z:
+    case REG_TYPE_ZA:
+    case REG_TYPE_ZAT:
+    case REG_TYPE_ZATH:
+    case REG_TYPE_ZATV:
+      return ch == '.';
+
+    case REG_TYPE_P:
+    case REG_TYPE_PN:
+      return ch == '.' || ch == '/';
+
+    default:
+      return false;
+    }
+}
+
+/* Parse an index expression at *STR, storing it in *IMM on success.  */
+
+static bool
+parse_index_expression (char **str, int64_t *imm)
+{
+  expressionS exp;
+
+  aarch64_get_expression (&exp, str, GE_NO_PREFIX, REJECT_ABSENT);
+  if (exp.X_op != O_constant)
+    {
+      first_error (_("constant expression required"));
+      return false;
+    }
+  *imm = exp.X_add_number;
+  return true;
+}
+
 /* Parse a register of the type TYPE.
 
-   Return PARSE_FAIL if the string pointed by *CCP is not a valid register
+   Return null if the string pointed to by *CCP is not a valid register
    name or the parsed register is not of TYPE.
 
-   Otherwise return the register number, and optionally fill in the actual
-   type of the register in *RTYPE when multiple alternatives were given, and
-   return the register shape and element index information in *TYPEINFO.
+   Otherwise return the register, and optionally return the register
+   shape and element index information in *TYPEINFO.
 
-   IN_REG_LIST should be set with TRUE if the caller is parsing a register
-   list.  */
+   FLAGS includes PTR_IN_REGLIST if the caller is parsing a register list.
 
-static int
-parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
-                struct vector_type_el *typeinfo, bool in_reg_list)
+   FLAGS includes PTR_FULL_REG if the function should ignore any potential
+   register index.
+
+   FLAGS includes PTR_GOOD_MATCH if we are sufficiently far into parsing
+   an operand that we can be confident that it is a good match.  */
+
+#define PTR_IN_REGLIST (1U << 0)
+#define PTR_FULL_REG (1U << 1)
+#define PTR_GOOD_MATCH (1U << 2)
+
+static const reg_entry *
+parse_typed_reg (char **ccp, aarch64_reg_type type,
+                struct vector_type_el *typeinfo, unsigned int flags)
 {
   char *str = *ccp;
+  bool isalpha = ISALPHA (*str);
   const reg_entry *reg = parse_reg (&str);
   struct vector_type_el atype;
   struct vector_type_el parsetype;
   bool is_typed_vecreg = false;
+  unsigned int err_flags = (flags & PTR_IN_REGLIST) ? SEF_IN_REGLIST : 0;
 
   atype.defined = 0;
   atype.type = NT_invtype;
   atype.width = -1;
+  atype.element_size = 0;
   atype.index = 0;
 
   if (reg == NULL)
     {
       if (typeinfo)
        *typeinfo = atype;
-      set_default_error ();
-      return PARSE_FAIL;
+      if (!isalpha && (flags & PTR_IN_REGLIST))
+       set_fatal_syntax_error (_("syntax error in register list"));
+      else if (flags & PTR_GOOD_MATCH)
+       set_fatal_syntax_error (NULL);
+      else
+       set_expected_reg_error (type, reg, err_flags);
+      return NULL;
     }
 
   if (! aarch64_check_reg_type (reg, type))
     {
       DEBUG_TRACE ("reg type check failed");
-      set_default_error ();
-      return PARSE_FAIL;
+      if (flags & PTR_GOOD_MATCH)
+       set_fatal_syntax_error (NULL);
+      else
+       set_expected_reg_error (type, reg, err_flags);
+      return NULL;
     }
   type = reg->type;
 
-  if ((type == REG_TYPE_VN || type == REG_TYPE_ZN || type == REG_TYPE_PN)
-      && (*str == '.' || (type == REG_TYPE_PN && *str == '/')))
+  if (aarch64_valid_suffix_char_p (reg->type, *str))
     {
       if (*str == '.')
        {
          if (!parse_vector_type_for_operand (type, &parsetype, &str))
-           return PARSE_FAIL;
+           return NULL;
+         if ((reg->type == REG_TYPE_ZAT
+              || reg->type == REG_TYPE_ZATH
+              || reg->type == REG_TYPE_ZATV)
+             && reg->number * 8 >= parsetype.element_size)
+           {
+             set_syntax_error (_("ZA tile number out of range"));
+             return NULL;
+           }
        }
       else
        {
          if (!parse_predication_for_operand (&parsetype, &str))
-           return PARSE_FAIL;
+           return NULL;
        }
 
       /* Register if of the form Vn.[bhsdq].  */
       is_typed_vecreg = true;
 
-      if (type == REG_TYPE_ZN || type == REG_TYPE_PN)
+      if (type != REG_TYPE_V)
        {
          /* The width is always variable; we don't allow an integer width
             to be specified.  */
@@ -1009,48 +1284,41 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
       atype.width = parsetype.width;
     }
 
-  if (skip_past_char (&str, '['))
+  if (!(flags & PTR_FULL_REG) && skip_past_char (&str, '['))
     {
-      expressionS exp;
-
       /* Reject Sn[index] syntax.  */
-      if (!is_typed_vecreg)
+      if (reg->type != REG_TYPE_Z
+         && reg->type != REG_TYPE_PN
+         && reg->type != REG_TYPE_ZT0
+         && !is_typed_vecreg)
        {
          first_error (_("this type of register can't be indexed"));
-         return PARSE_FAIL;
+         return NULL;
        }
 
-      if (in_reg_list)
+      if (flags & PTR_IN_REGLIST)
        {
          first_error (_("index not allowed inside register list"));
-         return PARSE_FAIL;
+         return NULL;
        }
 
       atype.defined |= NTA_HASINDEX;
 
-      aarch64_get_expression (&exp, &str, GE_NO_PREFIX, REJECT_ABSENT,
-                             NORMAL_RESOLUTION);
-
-      if (exp.X_op != O_constant)
-       {
-         first_error (_("constant expression required"));
-         return PARSE_FAIL;
-       }
+      if (!parse_index_expression (&str, &atype.index))
+       return NULL;
 
       if (! skip_past_char (&str, ']'))
-       return PARSE_FAIL;
-
-      atype.index = exp.X_add_number;
+       return NULL;
     }
-  else if (!in_reg_list && (atype.defined & NTA_HASINDEX) != 0)
+  else if (!(flags & PTR_IN_REGLIST) && (atype.defined & NTA_HASINDEX) != 0)
     {
       /* Indexed vector register expected.  */
       first_error (_("indexed vector register expected"));
-      return PARSE_FAIL;
+      return NULL;
     }
 
   /* A vector reg Vn should be typed or indexed.  */
-  if (type == REG_TYPE_VN && atype.defined == 0)
+  if (type == REG_TYPE_V && atype.defined == 0)
     {
       first_error (_("invalid use of vector register"));
     }
@@ -1058,53 +1326,43 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
   if (typeinfo)
     *typeinfo = atype;
 
-  if (rtype)
-    *rtype = type;
-
   *ccp = str;
 
-  return reg->number;
+  return reg;
 }
 
 /* Parse register.
 
-   Return the register number on success; return PARSE_FAIL otherwise.
-
-   If RTYPE is not NULL, return in *RTYPE the (possibly restricted) type of
-   the register (e.g. NEON double or quad reg when either has been requested).
+   Return the register on success; return null otherwise.
 
    If this is a NEON vector register with additional type information, fill
    in the struct pointed to by VECTYPE (if non-NULL).
 
-   This parser does not handle register list.  */
+   This parser does not handle register lists.  */
 
-static int
+static const reg_entry *
 aarch64_reg_parse (char **ccp, aarch64_reg_type type,
-                  aarch64_reg_type *rtype, struct vector_type_el *vectype)
+                  struct vector_type_el *vectype)
 {
-  struct vector_type_el atype;
-  char *str = *ccp;
-  int reg = parse_typed_reg (&str, type, rtype, &atype,
-                            /*in_reg_list= */ false);
-
-  if (reg == PARSE_FAIL)
-    return PARSE_FAIL;
-
-  if (vectype)
-    *vectype = atype;
-
-  *ccp = str;
-
-  return reg;
+  return parse_typed_reg (ccp, type, vectype, 0);
 }
 
 static inline bool
 eq_vector_type_el (struct vector_type_el e1, struct vector_type_el e2)
 {
-  return
-    e1.type == e2.type
-    && e1.defined == e2.defined
-    && e1.width == e2.width && e1.index == e2.index;
+  return (e1.type == e2.type
+         && e1.defined == e2.defined
+         && e1.width == e2.width
+         && e1.element_size == e2.element_size
+         && e1.index == e2.index);
+}
+
+/* Return the register number mask for registers of type REG_TYPE.  */
+
+static inline int
+reg_type_mask (aarch64_reg_type reg_type)
+{
+  return reg_type == REG_TYPE_P ? 15 : 31;
 }
 
 /* This function parses a list of vector registers of type TYPE.
@@ -1135,16 +1393,16 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
   char *str = *ccp;
   int nb_regs;
   struct vector_type_el typeinfo, typeinfo_first;
-  int val, val_range;
+  uint32_t val, val_range, mask;
   int in_range;
   int ret_val;
-  int i;
   bool error = false;
   bool expect_index = false;
+  unsigned int ptr_flags = PTR_IN_REGLIST;
 
   if (*str != '{')
     {
-      set_syntax_error (_("expecting {"));
+      set_expected_reglist_error (type, parse_reg (&str));
       return PARSE_FAIL;
     }
   str++;
@@ -1153,11 +1411,13 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
   typeinfo_first.defined = 0;
   typeinfo_first.type = NT_invtype;
   typeinfo_first.width = -1;
+  typeinfo_first.element_size = 0;
   typeinfo_first.index = 0;
   ret_val = 0;
-  val = -1;
-  val_range = -1;
+  val = -1u;
+  val_range = -1u;
   in_range = 0;
+  mask = reg_type_mask (type);
   do
     {
       if (in_range)
@@ -1165,16 +1425,17 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
          str++;                /* skip over '-' */
          val_range = val;
        }
-      val = parse_typed_reg (&str, type, NULL, &typeinfo,
-                            /*in_reg_list= */ true);
-      if (val == PARSE_FAIL)
+      const reg_entry *reg = parse_typed_reg (&str, type, &typeinfo,
+                                             ptr_flags);
+      if (!reg)
        {
          set_first_syntax_error (_("invalid vector register in list"));
          error = true;
          continue;
        }
+      val = reg->number;
       /* reject [bhsd]n */
-      if (type == REG_TYPE_VN && typeinfo.defined == 0)
+      if (type == REG_TYPE_V && typeinfo.defined == 0)
        {
          set_first_syntax_error (_("invalid scalar register in list"));
          error = true;
@@ -1186,13 +1447,13 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
 
       if (in_range)
        {
-         if (val < val_range)
+         if (val == val_range)
            {
              set_first_syntax_error
                (_("invalid range in vector register list"));
              error = true;
            }
-         val_range++;
+         val_range = (val_range + 1) & mask;
        }
       else
        {
@@ -1207,12 +1468,16 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
            }
        }
       if (! error)
-       for (i = val_range; i <= val; i++)
+       for (;;)
          {
-           ret_val |= i << (5 * nb_regs);
+           ret_val |= val_range << ((5 * nb_regs) & 31);
            nb_regs++;
+           if (val_range == val)
+             break;
+           val_range = (val_range + 1) & mask;
          }
       in_range = 0;
+      ptr_flags |= PTR_GOOD_MATCH;
     }
   while (skip_past_comma (&str) || (in_range = 1, *str == '-'));
 
@@ -1230,19 +1495,10 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
     {
       if (skip_past_char (&str, '['))
        {
-         expressionS exp;
-
-         aarch64_get_expression (&exp, &str, GE_NO_PREFIX, REJECT_ABSENT,
-                                 NORMAL_RESOLUTION);
-         if (exp.X_op != O_constant)
-           {
-             set_first_syntax_error (_("constant expression required."));
-             error = true;
-           }
+         if (!parse_index_expression (&str, &typeinfo_first.index))
+           error = true;
          if (! skip_past_char (&str, ']'))
            error = true;
-         else
-           typeinfo_first.index = exp.X_add_number;
        }
       else
        {
@@ -1405,11 +1661,7 @@ s_unreq (int a ATTRIBUTE_UNUSED)
   char saved_char;
 
   name = input_line_pointer;
-
-  while (*input_line_pointer != 0
-        && *input_line_pointer != ' ' && *input_line_pointer != '\n')
-    ++input_line_pointer;
-
+  input_line_pointer = find_end_of_line (input_line_pointer, flag_m68k_mri);
   saved_char = *input_line_pointer;
   *input_line_pointer = 0;
 
@@ -1468,7 +1720,7 @@ s_unreq (int a ATTRIBUTE_UNUSED)
 
 /* Directives: Instruction set selection.  */
 
-#ifdef OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
 /* This code is to handle mapping symbols as defined in the ARM AArch64 ELF
    spec.  (See "Mapping symbols", section 4.5.4, ARM AAELF64 version 0.05).
    Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
@@ -1883,10 +2135,9 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
     }
 }
 
-#ifdef OBJ_ELF
+#if defined(OBJ_ELF) || defined(OBJ_COFF)
 /* Forward declarations for functions below, in the MD interface
    section.  */
-static fixS *fix_new_aarch64 (fragS *, int, short, expressionS *, int, int);
 static struct reloc_table_entry * find_reloc_table_entry (char **);
 
 /* Directives: Data.  */
@@ -1894,7 +2145,7 @@ static struct reloc_table_entry * find_reloc_table_entry (char **);
    implemented properly.  */
 
 static void
-s_aarch64_elf_cons (int nbytes)
+s_aarch64_cons (int nbytes)
 {
   expressionS exp;
 
@@ -1944,6 +2195,12 @@ s_aarch64_elf_cons (int nbytes)
   input_line_pointer--;
   demand_empty_rest_of_line ();
 }
+#endif
+
+#ifdef OBJ_ELF
+/* Forward declarations for functions below, in the MD interface
+   section.  */
+ static fixS *fix_new_aarch64 (fragS *, int, short, expressionS *, int, int);
 
 /* Mark symbol that it follows a variant PCS convention.  */
 
@@ -1975,6 +2232,7 @@ static void
 s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
 {
   expressionS exp;
+  unsigned n = 0;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -2013,10 +2271,13 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
          unsigned int val = exp.X_add_number;
          exp.X_add_number = SWAP_32 (val);
        }
-      emit_expr (&exp, 4);
+      emit_expr (&exp, INSN_SIZE);
+      ++n;
     }
   while (*input_line_pointer++ == ',');
 
+  dwarf2_emit_insn (n * INSN_SIZE);
+
   /* Put terminator back into stream.  */
   input_line_pointer--;
   demand_empty_rest_of_line ();
@@ -2046,41 +2307,92 @@ s_tlsdescadd (int ignored ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-/* Emit BFD_RELOC_AARCH64_TLSDESC_CALL on the next BLR instruction.  */
-
-static void
-s_tlsdesccall (int ignored ATTRIBUTE_UNUSED)
+/* Emit BFD_RELOC_AARCH64_TLSDESC_CALL on the next BLR instruction.  */
+
+static void
+s_tlsdesccall (int ignored ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+
+  /* Since we're just labelling the code, there's no need to define a
+     mapping symbol.  */
+  expression (&exp);
+  /* Make sure there is enough room in this frag for the following
+     blr.  This trick only works if the blr follows immediately after
+     the .tlsdesc directive.  */
+  frag_grow (4);
+  fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 4, &exp, 0,
+                  BFD_RELOC_AARCH64_TLSDESC_CALL);
+
+  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 */
+
+#ifdef TE_PE
+static void
+s_secrel (int dummy ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+
+  do
+    {
+      expression (&exp);
+      if (exp.X_op == O_symbol)
+       exp.X_op = O_secrel;
+
+      emit_expr (&exp, 4);
+    }
+  while (*input_line_pointer++ == ',');
+
+  input_line_pointer--;
+  demand_empty_rest_of_line ();
+}
+
+void
+tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
 {
   expressionS exp;
 
-  /* Since we're just labelling the code, there's no need to define a
-     mapping symbol.  */
-  expression (&exp);
-  /* Make sure there is enough room in this frag for the following
-     blr.  This trick only works if the blr follows immediately after
-     the .tlsdesc directive.  */
-  frag_grow (4);
-  fix_new_aarch64 (frag_now, frag_more (0) - frag_now->fr_literal, 4, &exp, 0,
-                  BFD_RELOC_AARCH64_TLSDESC_CALL);
-
-  demand_empty_rest_of_line ();
+  exp.X_op = O_secrel;
+  exp.X_add_symbol = symbol;
+  exp.X_add_number = 0;
+  emit_expr (&exp, size);
 }
 
-/* Emit BFD_RELOC_AARCH64_TLSDESC_LDR on the next LDR instruction.  */
-
 static void
-s_tlsdescldr (int ignored ATTRIBUTE_UNUSED)
+s_secidx (int dummy 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);
+  do
+    {
+      expression (&exp);
+      if (exp.X_op == O_symbol)
+       exp.X_op = O_secidx;
 
+      emit_expr (&exp, 2);
+    }
+  while (*input_line_pointer++ == ',');
+
+  input_line_pointer--;
   demand_empty_rest_of_line ();
 }
-#endif /* OBJ_ELF */
+#endif /* TE_PE */
 
 static void s_aarch64_arch (int);
 static void s_aarch64_cpu (int);
@@ -2109,11 +2421,17 @@ const pseudo_typeS md_pseudo_table[] = {
   {"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},
-  {"dword", s_aarch64_elf_cons, 8},
   {"variant_pcs", s_variant_pcs, 0},
+#endif
+#if defined(OBJ_ELF) || defined(OBJ_COFF)
+  {"word", s_aarch64_cons, 4},
+  {"long", s_aarch64_cons, 4},
+  {"xword", s_aarch64_cons, 8},
+  {"dword", s_aarch64_cons, 8},
+#endif
+#ifdef TE_PE
+  {"secrel32", s_secrel, 0},
+  {"secidx", s_secidx, 0},
 #endif
   {"float16", float_cons, 'h'},
   {"bfloat16", float_cons, 'b'},
@@ -2136,18 +2454,18 @@ const pseudo_typeS md_pseudo_table[] = {
 static bool
 reg_name_p (char *str, aarch64_reg_type reg_type)
 {
-  int reg;
+  const reg_entry *reg;
 
   /* Prevent the diagnostics state from being spoiled.  */
   if (error_p ())
     return false;
 
-  reg = aarch64_reg_parse (&str, reg_type, NULL, NULL);
+  reg = aarch64_reg_parse (&str, reg_type, NULL);
 
   /* Clear the parsing error that may be set by the reg parser.  */
   clear_error ();
 
-  if (reg == PARSE_FAIL)
+  if (!reg)
     return false;
 
   skip_whitespace (str);
@@ -2176,8 +2494,7 @@ parse_immediate_expression (char **str, expressionS *exp,
       return false;
     }
 
-  aarch64_get_expression (exp, str, GE_OPT_PREFIX, REJECT_ABSENT,
-                         NORMAL_RESOLUTION);
+  aarch64_get_expression (exp, str, GE_OPT_PREFIX, REJECT_ABSENT);
 
   if (exp->X_op == O_absent)
     {
@@ -2411,8 +2728,7 @@ parse_big_immediate (char **str, int64_t *imm, aarch64_reg_type reg_type)
       return false;
     }
 
-  aarch64_get_expression (&inst.reloc.exp, &ptr, GE_OPT_PREFIX, REJECT_ABSENT,
-                         NORMAL_RESOLUTION);
+  aarch64_get_expression (&inst.reloc.exp, &ptr, GE_OPT_PREFIX, REJECT_ABSENT);
 
   if (inst.reloc.exp.X_op == O_constant)
     *imm = inst.reloc.exp.X_add_number;
@@ -3069,7 +3385,7 @@ aarch64_force_reloc (unsigned int type)
     case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC:
       /* Pseudo relocs that need to be fixed up according to
         ilp32_p.  */
-      return 0;
+      return 1;
 
     case BFD_RELOC_AARCH64_ADD_LO12:
     case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
@@ -3086,6 +3402,7 @@ aarch64_force_reloc (unsigned int type)
     case BFD_RELOC_AARCH64_LDST32_LO12:
     case BFD_RELOC_AARCH64_LDST64_LO12:
     case BFD_RELOC_AARCH64_LDST8_LO12:
+    case BFD_RELOC_AARCH64_LDST_LO12:
     case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
     case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
     case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
@@ -3119,6 +3436,8 @@ aarch64_force_reloc (unsigned int type)
     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_LDST_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_LDST_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:
@@ -3132,6 +3451,8 @@ aarch64_force_reloc (unsigned int type)
     case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC:
     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:
@@ -3304,8 +3625,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode)
          p++;
          exp_has_prefix = 1;
        }
-      (void) aarch64_get_expression (&exp, &p, GE_NO_PREFIX, ALLOW_ABSENT,
-                                    NORMAL_RESOLUTION);
+      aarch64_get_expression (&exp, &p, GE_NO_PREFIX, ALLOW_ABSENT);
     }
   if (kind == AARCH64_MOD_MUL_VL)
     /* For consistency, give MUL VL the same shift amount as an implicit
@@ -3369,7 +3689,7 @@ parse_shifter_operand_imm (char **str, aarch64_opnd_info *operand,
 
   /* Accept an immediate expression.  */
   if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX,
-                               REJECT_ABSENT, NORMAL_RESOLUTION))
+                               REJECT_ABSENT))
     return false;
 
   /* Accept optional LSL for arithmetic immediate values.  */
@@ -3421,9 +3741,9 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand,
          return false;
        }
 
-      if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
+      if (!aarch64_check_reg_type (reg, REG_TYPE_R_ZR))
        {
-         set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
+         set_expected_reg_error (REG_TYPE_R_ZR, reg, 0);
          return false;
        }
 
@@ -3493,8 +3813,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
 
       /* Next, we parse the expression.  */
       if (! aarch64_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX,
-                                   REJECT_ABSENT,
-                                   aarch64_force_reloc (entry->add_type) == 1))
+                                   REJECT_ABSENT))
        return false;
       
       /* Record the relocation type (use the ADD variant here).  */
@@ -3640,8 +3959,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
            }
 
          /* #:<reloc_op>:  */
-         if (! aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT,
-                                       aarch64_force_reloc (entry->add_type) == 1))
+         if (! aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT))
            {
              set_syntax_error (_("invalid relocation expression"));
              return false;
@@ -3657,8 +3975,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
            /* =immediate; need to generate the literal in the literal pool. */
            inst.gen_lit_pool = 1;
 
-         if (!aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT,
-                                      NORMAL_RESOLUTION))
+         if (!aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT))
            {
              set_syntax_error (_("invalid address"));
              return false;
@@ -3671,10 +3988,18 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
 
   /* [ */
 
+  bool alpha_base_p = ISALPHA (*p);
   reg = aarch64_addr_reg_parse (&p, base_type, base_qualifier);
   if (!reg || !aarch64_check_reg_type (reg, base_type))
     {
-      set_syntax_error (_(get_reg_expected_msg (base_type)));
+      if (reg
+         && aarch64_check_reg_type (reg, REG_TYPE_R_SP)
+         && *base_qualifier == AARCH64_OPND_QLF_W)
+       set_syntax_error (_("expected a 64-bit base register"));
+      else if (alpha_base_p)
+       set_syntax_error (_("invalid base register"));
+      else
+       set_syntax_error (_("expected a base register"));
       return false;
     }
   operand->addr.base_regno = reg->number;
@@ -3690,7 +4015,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
        {
          if (!aarch64_check_reg_type (reg, offset_type))
            {
-             set_syntax_error (_(get_reg_expected_msg (offset_type)));
+             set_syntax_error (_("invalid offset register"));
              return false;
            }
 
@@ -3764,8 +4089,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
              /* We now have the group relocation table entry corresponding to
                 the name in the assembler source.  Next, we parse the
                 expression.  */
-             if (! aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT,
-                                           aarch64_force_reloc (entry->add_type) == 1))
+             if (! aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT))
                {
                  set_syntax_error (_("invalid relocation expression"));
                  return false;
@@ -3778,8 +4102,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
            }
          else
            {
-             if (! aarch64_get_expression (exp, &p, GE_OPT_PREFIX, REJECT_ABSENT,
-                                           NORMAL_RESOLUTION))
+             if (! aarch64_get_expression (exp, &p, GE_OPT_PREFIX, REJECT_ABSENT))
                {
                  set_syntax_error (_("invalid expression in the address"));
                  return false;
@@ -3828,15 +4151,14 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
          /* [Xn],Xm */
          if (!aarch64_check_reg_type (reg, REG_TYPE_R_64))
            {
-             set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_64)));
+             set_syntax_error (_("invalid offset register"));
              return false;
            }
 
          operand->addr.offset.regno = reg->number;
          operand->addr.offset.is_reg = 1;
        }
-      else if (! aarch64_get_expression (exp, &p, GE_OPT_PREFIX, REJECT_ABSENT,
-                                        NORMAL_RESOLUTION))
+      else if (! aarch64_get_expression (exp, &p, GE_OPT_PREFIX, REJECT_ABSENT))
        {
          /* [Xn],#expr */
          set_syntax_error (_("invalid expression in the address"));
@@ -3895,7 +4217,7 @@ parse_address (char **str, aarch64_opnd_info *operand)
 {
   aarch64_opnd_qualifier_t base_qualifier, offset_qualifier;
   return parse_address_main (str, operand, &base_qualifier, &offset_qualifier,
-                            REG_TYPE_R64_SP, REG_TYPE_R_Z, SHIFTED_NONE);
+                            REG_TYPE_R64_SP, REG_TYPE_R_ZR, SHIFTED_NONE);
 }
 
 /* Parse an address in which SVE vector registers and MUL VL are allowed.
@@ -3911,6 +4233,22 @@ parse_sve_address (char **str, aarch64_opnd_info *operand,
                             SHIFTED_MUL_VL);
 }
 
+/* Parse a register X0-X30.  The register must be 64-bit and register 31
+   is unallocated.  */
+static bool
+parse_x0_to_x30 (char **str, aarch64_opnd_info *operand)
+{
+  const reg_entry *reg = parse_reg (str);
+  if (!reg || !aarch64_check_reg_type (reg, REG_TYPE_R_64))
+    {
+      set_expected_reg_error (REG_TYPE_R_64, reg, 0);
+      return false;
+    }
+  operand->reg.regno = reg->number;
+  operand->qualifier = AARCH64_OPND_QLF_X;
+  return true;
+}
+
 /* Parse an operand for a MOVZ, MOVN or MOVK instruction.
    Return TRUE on success; otherwise return FALSE.  */
 static bool
@@ -3948,8 +4286,7 @@ parse_half (char **str, int *internal_fixup_p)
   else
     *internal_fixup_p = 1;
 
-  if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, REJECT_ABSENT,
-                               aarch64_force_reloc (inst.reloc.type) == 1))
+  if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, REJECT_ABSENT))
     return false;
 
   *str = p;
@@ -3991,8 +4328,7 @@ parse_adrp (char **str)
     inst.reloc.type = BFD_RELOC_AARCH64_ADR_HI21_PCREL;
 
   inst.reloc.pc_rel = 1;
-  if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, REJECT_ABSENT,
-                               aarch64_force_reloc (inst.reloc.type) == 1))
+  if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, REJECT_ABSENT))
     return false;
   *str = p;
   return true;
@@ -4002,8 +4338,10 @@ parse_adrp (char **str)
 
 /* Parse a symbolic operand such as "pow2" at *STR.  ARRAY is an array
    of SIZE tokens in which index I gives the token for field value I,
-   or is null if field value I is invalid.  REG_TYPE says which register
-   names should be treated as registers rather than as symbolic immediates.
+   or is null if field value I is invalid.  If the symbolic operand
+   can also be given as a 0-based integer, REG_TYPE says which register
+   names should be treated as registers rather than as symbolic immediates
+   while parsing that integer.  REG_TYPE is REG_TYPE_MAX otherwise.
 
    Return true on success, moving *STR past the operand and storing the
    field value in *VAL.  */
@@ -4031,6 +4369,9 @@ parse_enum_string (char **str, int64_t *val, const char *const *array,
        return true;
       }
 
+  if (reg_type == REG_TYPE_MAX)
+    return false;
+
   if (!parse_immediate_expression (&p, &exp, reg_type))
     return false;
 
@@ -4080,88 +4421,425 @@ parse_barrier (char **str)
   while (ISALPHA (*q))
     q++;
 
-  o = str_hash_find_n (aarch64_barrier_opt_hsh, p, q - p);
-  if (!o)
-    return PARSE_FAIL;
+  o = str_hash_find_n (aarch64_barrier_opt_hsh, p, q - p);
+  if (!o)
+    return PARSE_FAIL;
+
+  *str = q;
+  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 = str_hash_find_n (aarch64_hint_opt_hsh, p, q - p);
+  if (!o)
+    {
+      set_fatal_syntax_error
+       ( _("unknown or missing option to PSB/TSB"));
+      return PARSE_FAIL;
+    }
+
+  if (o->value != 0x11)
+    {
+      /* PSB only accepts option name 'CSYNC'.  */
+      set_syntax_error
+       (_("the specified option is not accepted for PSB/TSB"));
+      return PARSE_FAIL;
+    }
+
+  *str = q;
+  *hint_opt = o;
+  return 0;
+}
+
+/* Parse an operand for BTI.  Set *HINT_OPT to the hint-option record
+   return 0 if successful.  Otherwise return PARSE_FAIL.  */
+
+static int
+parse_bti_operand (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 = str_hash_find_n (aarch64_hint_opt_hsh, p, q - p);
+  if (!o)
+    {
+      set_fatal_syntax_error
+       ( _("unknown option to BTI"));
+      return PARSE_FAIL;
+    }
+
+  switch (o->value)
+    {
+    /* Valid BTI operands.  */
+    case HINT_OPD_C:
+    case HINT_OPD_J:
+    case HINT_OPD_JC:
+      break;
+
+    default:
+      set_syntax_error
+       (_("unknown option to BTI"));
+      return PARSE_FAIL;
+    }
+
+  *str = q;
+  *hint_opt = o;
+  return 0;
+}
+
+/* Parse STR for reg of REG_TYPE and following '.' and QUALIFIER.
+   Function returns REG_ENTRY struct and QUALIFIER [bhsdq] or NULL
+   on failure. Format:
+
+     REG_TYPE.QUALIFIER
+
+   Side effect: Update STR with current parse position of success.
+
+   FLAGS is as for parse_typed_reg.  */
+
+static const reg_entry *
+parse_reg_with_qual (char **str, aarch64_reg_type reg_type,
+                    aarch64_opnd_qualifier_t *qualifier, unsigned int flags)
+{
+  struct vector_type_el vectype;
+  const reg_entry *reg = parse_typed_reg (str, reg_type, &vectype,
+                                         PTR_FULL_REG | flags);
+  if (!reg)
+    return NULL;
+
+  if (vectype.type == NT_invtype)
+    *qualifier = AARCH64_OPND_QLF_NIL;
+  else
+    {
+      *qualifier = vectype_to_qualifier (&vectype);
+      if (*qualifier == AARCH64_OPND_QLF_NIL)
+       return NULL;
+    }
+
+  return reg;
+}
+
+/* Parse STR for unsigned, immediate (1-2 digits) in format:
+
+     #<imm>
+     <imm>
+
+  Function return TRUE if immediate was found, or FALSE.
+*/
+static bool
+parse_sme_immediate (char **str, int64_t *imm)
+{
+  int64_t val;
+  if (! parse_constant_immediate (str, &val, REG_TYPE_R_N))
+    return false;
+
+  *imm = val;
+  return true;
+}
+
+/* Parse index with selection register and immediate offset:
+
+   [<Wv>, <imm>]
+   [<Wv>, #<imm>]
+
+   Return true on success, populating OPND with the parsed index.  */
+
+static bool
+parse_sme_za_index (char **str, struct aarch64_indexed_za *opnd)
+{
+  const reg_entry *reg;
+
+  if (!skip_past_char (str, '['))
+    {
+      set_syntax_error (_("expected '['"));
+      return false;
+    }
+
+  /* The selection register, encoded in the 2-bit Rv field.  */
+  reg = parse_reg (str);
+  if (reg == NULL || reg->type != REG_TYPE_R_32)
+    {
+      set_syntax_error (_("expected a 32-bit selection register"));
+      return false;
+    }
+  opnd->index.regno = reg->number;
+
+  if (!skip_past_char (str, ','))
+    {
+      set_syntax_error (_("missing immediate offset"));
+      return false;
+    }
+
+  if (!parse_sme_immediate (str, &opnd->index.imm))
+    {
+      set_syntax_error (_("expected a constant immediate offset"));
+      return false;
+    }
+
+  if (skip_past_char (str, ':'))
+    {
+      int64_t end;
+      if (!parse_sme_immediate (str, &end))
+       {
+         set_syntax_error (_("expected a constant immediate offset"));
+         return false;
+       }
+      if (end < opnd->index.imm)
+       {
+         set_syntax_error (_("the last offset is less than the"
+                             " first offset"));
+         return false;
+       }
+      if (end == opnd->index.imm)
+       {
+         set_syntax_error (_("the last offset is equal to the"
+                             " first offset"));
+         return false;
+       }
+      opnd->index.countm1 = (uint64_t) end - opnd->index.imm;
+    }
+
+  opnd->group_size = 0;
+  if (skip_past_char (str, ','))
+    {
+      if (strncasecmp (*str, "vgx2", 4) == 0 && !ISALPHA ((*str)[4]))
+       {
+         *str += 4;
+         opnd->group_size = 2;
+       }
+      else if (strncasecmp (*str, "vgx4", 4) == 0 && !ISALPHA ((*str)[4]))
+       {
+         *str += 4;
+         opnd->group_size = 4;
+       }
+      else
+       {
+         set_syntax_error (_("invalid vector group size"));
+         return false;
+       }
+    }
+
+  if (!skip_past_char (str, ']'))
+    {
+      set_syntax_error (_("expected ']'"));
+      return false;
+    }
+
+  return true;
+}
+
+/* Parse a register of type REG_TYPE that might have an element type
+   qualifier and that is indexed by two values: a 32-bit register,
+   followed by an immediate.  The ranges of the register and the
+   immediate vary by opcode and are checked in libopcodes.
+
+   Return true on success, populating OPND with information about
+   the operand and setting QUALIFIER to the register qualifier.
+
+   Field format examples:
+
+   <Pm>.<T>[<Wv>< #<imm>]
+   ZA[<Wv>, #<imm>]
+   <ZAn><HV>.<T>[<Wv>, #<imm>]
+
+   FLAGS is as for parse_typed_reg.  */
+
+static bool
+parse_dual_indexed_reg (char **str, aarch64_reg_type reg_type,
+                       struct aarch64_indexed_za *opnd,
+                       aarch64_opnd_qualifier_t *qualifier,
+                       unsigned int flags)
+{
+  const reg_entry *reg = parse_reg_with_qual (str, reg_type, qualifier, flags);
+  if (!reg)
+    return false;
+
+  opnd->v = aarch64_check_reg_type (reg, REG_TYPE_ZATV);
+  opnd->regno = reg->number;
+
+  return parse_sme_za_index (str, opnd);
+}
+
+/* Like parse_sme_za_hv_tiles_operand, but expect braces around the
+   operand.  */
+
+static bool
+parse_sme_za_hv_tiles_operand_with_braces (char **str,
+                                          struct aarch64_indexed_za *opnd,
+                                           aarch64_opnd_qualifier_t *qualifier)
+{
+  if (!skip_past_char (str, '{'))
+    {
+      set_expected_reglist_error (REG_TYPE_ZATHV, parse_reg (str));
+      return false;
+    }
+
+  if (!parse_dual_indexed_reg (str, REG_TYPE_ZATHV, opnd, qualifier,
+                              PTR_IN_REGLIST))
+    return false;
+
+  if (!skip_past_char (str, '}'))
+    {
+      set_syntax_error (_("expected '}'"));
+      return false;
+    }
+
+  return true;
+}
+
+/* Parse list of up to eight 64-bit element tile names separated by commas in
+   SME's ZERO instruction:
+
+     ZERO { <mask> }
+
+   Function returns <mask>:
+
+     an 8-bit list of 64-bit element tiles named ZA0.D to ZA7.D.
+*/
+static int
+parse_sme_zero_mask(char **str)
+{
+  char *q;
+  int mask;
+  aarch64_opnd_qualifier_t qualifier;
+  unsigned int ptr_flags = PTR_IN_REGLIST;
+
+  mask = 0x00;
+  q = *str;
+  do
+    {
+      const reg_entry *reg = parse_reg_with_qual (&q, REG_TYPE_ZA_ZAT,
+                                                 &qualifier, ptr_flags);
+      if (!reg)
+       return PARSE_FAIL;
+
+      if (reg->type == REG_TYPE_ZA)
+       {
+         if (qualifier != AARCH64_OPND_QLF_NIL)
+           {
+             set_syntax_error ("ZA should not have a size suffix");
+             return PARSE_FAIL;
+           }
+          /* { ZA } is assembled as all-ones immediate.  */
+          mask = 0xff;
+       }
+      else
+       {
+          int regno = reg->number;
+          if (qualifier == AARCH64_OPND_QLF_S_B)
+            {
+              /* { ZA0.B } is assembled as all-ones immediate.  */
+              mask = 0xff;
+            }
+          else if (qualifier == AARCH64_OPND_QLF_S_H)
+            mask |= 0x55 << regno;
+          else if (qualifier == AARCH64_OPND_QLF_S_S)
+            mask |= 0x11 << regno;
+          else if (qualifier == AARCH64_OPND_QLF_S_D)
+            mask |= 0x01 << regno;
+         else if (qualifier == AARCH64_OPND_QLF_S_Q)
+           {
+              set_syntax_error (_("ZA tile masks do not operate at .Q"
+                                 " granularity"));
+              return PARSE_FAIL;
+           }
+         else if (qualifier == AARCH64_OPND_QLF_NIL)
+           {
+              set_syntax_error (_("missing ZA tile size"));
+              return PARSE_FAIL;
+           }
+          else
+            {
+              set_syntax_error (_("invalid ZA tile"));
+              return PARSE_FAIL;
+            }
+        }
+      ptr_flags |= PTR_GOOD_MATCH;
+    }
+  while (skip_past_char (&q, ','));
 
   *str = q;
-  return o->value;
+  return mask;
 }
 
-/* Parse an operand for a PSB barrier.  Set *HINT_OPT to the hint-option record
-   return 0 if successful.  Otherwise return PARSE_FAIL.  */
+/* Wraps in curly braces <mask> operand ZERO instruction:
+
+   ZERO { <mask> }
 
+   Function returns value of <mask> bit-field.
+*/
 static int
-parse_barrier_psb (char **str,
-                  const struct aarch64_name_value_pair ** hint_opt)
+parse_sme_list_of_64bit_tiles (char **str)
 {
-  char *p, *q;
-  const struct aarch64_name_value_pair *o;
-
-  p = q = *str;
-  while (ISALPHA (*q))
-    q++;
+  int regno;
 
-  o = str_hash_find_n (aarch64_hint_opt_hsh, p, q - p);
-  if (!o)
+  if (!skip_past_char (str, '{'))
     {
-      set_fatal_syntax_error
-       ( _("unknown or missing option to PSB/TSB"));
+      set_syntax_error (_("expected '{'"));
       return PARSE_FAIL;
     }
 
-  if (o->value != 0x11)
+  /* Empty <mask> list is an all-zeros immediate.  */
+  if (!skip_past_char (str, '}'))
     {
-      /* PSB only accepts option name 'CSYNC'.  */
-      set_syntax_error
-       (_("the specified option is not accepted for PSB/TSB"));
-      return PARSE_FAIL;
+      regno = parse_sme_zero_mask (str);
+      if (regno == PARSE_FAIL)
+         return PARSE_FAIL;
+
+      if (!skip_past_char (str, '}'))
+        {
+          set_syntax_error (_("expected '}'"));
+          return PARSE_FAIL;
+        }
     }
+  else
+    regno = 0x00;
 
-  *str = q;
-  *hint_opt = o;
-  return 0;
+  return regno;
 }
 
-/* Parse an operand for BTI.  Set *HINT_OPT to the hint-option record
-   return 0 if successful.  Otherwise return PARSE_FAIL.  */
+/* Parse streaming mode operand for SMSTART and SMSTOP.
+
+   {SM | ZA}
 
+   Function returns 's' if SM or 'z' if ZM is parsed. Otherwise PARSE_FAIL.
+*/
 static int
-parse_bti_operand (char **str,
-                  const struct aarch64_name_value_pair ** hint_opt)
+parse_sme_sm_za (char **str)
 {
   char *p, *q;
-  const struct aarch64_name_value_pair *o;
 
   p = q = *str;
   while (ISALPHA (*q))
     q++;
 
-  o = str_hash_find_n (aarch64_hint_opt_hsh, p, q - p);
-  if (!o)
-    {
-      set_fatal_syntax_error
-       ( _("unknown option to BTI"));
-      return PARSE_FAIL;
-    }
-
-  switch (o->value)
+  if ((q - p != 2)
+      || (strncasecmp ("sm", p, 2) != 0 && strncasecmp ("za", p, 2) != 0))
     {
-    /* Valid BTI operands.  */
-    case HINT_OPD_C:
-    case HINT_OPD_J:
-    case HINT_OPD_JC:
-      break;
-
-    default:
-      set_syntax_error
-       (_("unknown option to BTI"));
+      set_syntax_error (_("expected SM or ZA operand"));
       return PARSE_FAIL;
     }
 
   *str = q;
-  *hint_opt = o;
-  return 0;
+  return TOLOWER (p[0]);
 }
 
 /* Parse a system register or a PSTATE field name for an MSR/MRS instruction.
@@ -4282,23 +4960,20 @@ parse_sys_ins_reg (char **str, htab_t sys_ins_regs)
 } while (0)
 
 #define po_reg_or_fail(regtype) do {                           \
-    val = aarch64_reg_parse (&str, regtype, &rtype, NULL);     \
-    if (val == PARSE_FAIL)                                     \
-      {                                                                \
-       set_default_error ();                                   \
-       goto failure;                                           \
-      }                                                                \
+    reg = aarch64_reg_parse (&str, regtype, NULL);             \
+    if (!reg)                                                  \
+      goto failure;                                            \
   } while (0)
 
-#define po_int_reg_or_fail(reg_type) do {                      \
-    reg = aarch64_reg_parse_32_64 (&str, &qualifier);          \
+#define po_int_fp_reg_or_fail(reg_type) do {                   \
+    reg = parse_reg (&str);                                    \
     if (!reg || !aarch64_check_reg_type (reg, reg_type))       \
       {                                                                \
-       set_default_error ();                                   \
+       set_expected_reg_error (reg_type, reg, 0);              \
        goto failure;                                           \
       }                                                                \
     info->reg.regno = reg->number;                             \
-    info->qualifier = qualifier;                               \
+    info->qualifier = inherent_reg_qualifier (reg);            \
   } while (0)
 
 #define po_imm_nc_or_fail() do {                               \
@@ -4323,11 +4998,31 @@ parse_sys_ins_reg (char **str, htab_t sys_ins_regs)
       goto failure;                                            \
   } while (0)
 
+#define po_strict_enum_or_fail(array) do {                     \
+    if (!parse_enum_string (&str, &val, array,                 \
+                           ARRAY_SIZE (array), REG_TYPE_MAX))  \
+      goto failure;                                            \
+  } while (0)
+
 #define po_misc_or_fail(expr) do {                             \
     if (!expr)                                                 \
       goto failure;                                            \
   } while (0)
 \f
+/* A primitive log calculator.  */
+
+static inline unsigned int
+get_log2 (unsigned int n)
+{
+  unsigned int count = 0;
+  while (n > 1)
+    {
+      n >>= 1;
+      count += 1;
+    }
+  return count;
+}
+
 /* encode the 12-bit imm field of Add/sub immediate */
 static inline uint32_t
 encode_addsub_imm (uint32_t imm)
@@ -4460,13 +5155,20 @@ const char* operand_mismatch_kind_names[] =
 {
   "AARCH64_OPDE_NIL",
   "AARCH64_OPDE_RECOVERABLE",
+  "AARCH64_OPDE_A_SHOULD_FOLLOW_B",
+  "AARCH64_OPDE_EXPECTED_A_AFTER_B",
   "AARCH64_OPDE_SYNTAX_ERROR",
   "AARCH64_OPDE_FATAL_SYNTAX_ERROR",
   "AARCH64_OPDE_INVALID_VARIANT",
+  "AARCH64_OPDE_INVALID_VG_SIZE",
+  "AARCH64_OPDE_REG_LIST_LENGTH",
+  "AARCH64_OPDE_REG_LIST_STRIDE",
+  "AARCH64_OPDE_UNTIED_IMMS",
+  "AARCH64_OPDE_UNTIED_OPERAND",
   "AARCH64_OPDE_OUT_OF_RANGE",
   "AARCH64_OPDE_UNALIGNED",
-  "AARCH64_OPDE_REG_LIST",
   "AARCH64_OPDE_OTHER_ERROR",
+  "AARCH64_OPDE_INVALID_REGNO",
 };
 #endif /* DEBUG_AARCH64 */
 
@@ -4481,13 +5183,19 @@ operand_error_higher_severity_p (enum aarch64_operand_error_kind lhs,
                                 enum aarch64_operand_error_kind rhs)
 {
   gas_assert (AARCH64_OPDE_RECOVERABLE > AARCH64_OPDE_NIL);
-  gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_RECOVERABLE);
+  gas_assert (AARCH64_OPDE_A_SHOULD_FOLLOW_B > AARCH64_OPDE_RECOVERABLE);
+  gas_assert (AARCH64_OPDE_EXPECTED_A_AFTER_B > AARCH64_OPDE_RECOVERABLE);
+  gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_A_SHOULD_FOLLOW_B);
+  gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_EXPECTED_A_AFTER_B);
   gas_assert (AARCH64_OPDE_FATAL_SYNTAX_ERROR > AARCH64_OPDE_SYNTAX_ERROR);
   gas_assert (AARCH64_OPDE_INVALID_VARIANT > AARCH64_OPDE_FATAL_SYNTAX_ERROR);
-  gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_INVALID_VARIANT);
+  gas_assert (AARCH64_OPDE_INVALID_VG_SIZE > AARCH64_OPDE_INVALID_VARIANT);
+  gas_assert (AARCH64_OPDE_REG_LIST_LENGTH > AARCH64_OPDE_INVALID_VG_SIZE);
+  gas_assert (AARCH64_OPDE_REG_LIST_STRIDE > AARCH64_OPDE_REG_LIST_LENGTH);
+  gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST_STRIDE);
   gas_assert (AARCH64_OPDE_UNALIGNED > AARCH64_OPDE_OUT_OF_RANGE);
-  gas_assert (AARCH64_OPDE_REG_LIST > AARCH64_OPDE_UNALIGNED);
-  gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST);
+  gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST_STRIDE);
+  gas_assert (AARCH64_OPDE_INVALID_REGNO > AARCH64_OPDE_OTHER_ERROR);
   return lhs > rhs;
 }
 
@@ -4674,9 +5382,9 @@ record_operand_error_with_data (const aarch64_opcode *opcode, int idx,
   info.index = idx;
   info.kind = kind;
   info.error = error;
-  info.data[0] = extra_data[0];
-  info.data[1] = extra_data[1];
-  info.data[2] = extra_data[2];
+  info.data[0].i = extra_data[0];
+  info.data[1].i = extra_data[1];
+  info.data[2].i = extra_data[2];
   info.non_fatal = false;
   record_operand_error_info (opcode, &info);
 }
@@ -4774,6 +5482,41 @@ assign_qualifier_sequence (aarch64_inst *instr,
     instr->operands[i].qualifier = *qualifiers;
 }
 
+/* Callback used by aarch64_print_operand to apply STYLE to the
+   disassembler output created from FMT and ARGS.  The STYLER object holds
+   any required state.  Must return a pointer to a string (created from FMT
+   and ARGS) that will continue to be valid until the complete disassembled
+   instruction has been printed.
+
+   We don't currently add any styling to the output of the disassembler as
+   used within assembler error messages, and so STYLE is ignored here.  A
+   new string is allocated on the obstack help within STYLER and returned
+   to the caller.  */
+
+static const char *aarch64_apply_style
+       (struct aarch64_styler *styler,
+        enum disassembler_style style ATTRIBUTE_UNUSED,
+        const char *fmt, va_list args)
+{
+  int res;
+  char *ptr;
+  struct obstack *stack = (struct obstack *) styler->state;
+  va_list ap;
+
+  /* Calculate the required space.  */
+  va_copy (ap, args);
+  res = vsnprintf (NULL, 0, fmt, ap);
+  va_end (ap);
+  gas_assert (res >= 0);
+
+  /* Allocate space on the obstack and format the result.  */
+  ptr = (char *) obstack_alloc (stack, res + 1);
+  res = vsnprintf (ptr, (res + 1), fmt, args);
+  gas_assert (res >= 0);
+
+  return ptr;
+}
+
 /* Print operands for the diagnosis purpose.  */
 
 static void
@@ -4781,10 +5524,17 @@ print_operands (char *buf, const aarch64_opcode *opcode,
                const aarch64_opnd_info *opnds)
 {
   int i;
+  struct aarch64_styler styler;
+  struct obstack content;
+  obstack_init (&content);
+
+  styler.apply_style = aarch64_apply_style;
+  styler.state = (void *) &content;
 
   for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
     {
       char str[128];
+      char cmt[128];
 
       /* We regard the opcode operand info more, however we also look into
         the inst->operands to support the disassembling of the optional
@@ -4797,7 +5547,7 @@ print_operands (char *buf, const aarch64_opcode *opcode,
 
       /* Generate the operand string in STR.  */
       aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL,
-                            NULL, cpu_variant);
+                            NULL, cmt, sizeof (cmt), cpu_variant, &styler);
 
       /* Delimiter.  */
       if (str[0] != '\0')
@@ -4805,7 +5555,18 @@ print_operands (char *buf, const aarch64_opcode *opcode,
 
       /* Append the operand string.  */
       strcat (buf, str);
+
+      /* Append a comment.  This works because only the last operand ever
+        adds a comment.  If that ever changes then we'll need to be
+        smarter here.  */
+      if (cmt[0] != '\0')
+       {
+         strcat (buf, "\t// ");
+         strcat (buf, cmt);
+       }
     }
+
+  obstack_free (&content, NULL);
 }
 
 /* Send to stderr a string as information.  */
@@ -4832,6 +5593,64 @@ output_info (const char *format, ...)
   (void) putc ('\n', stderr);
 }
 
+/* See if the AARCH64_OPDE_SYNTAX_ERROR error described by DETAIL
+   relates to registers or register lists.  If so, return a string that
+   reports the error against "operand %d", otherwise return null.  */
+
+static const char *
+get_reg_error_message (const aarch64_operand_error *detail)
+{
+  /* Handle the case where we found a register that was expected
+     to be in a register list outside of a register list.  */
+  if ((detail->data[1].i & detail->data[2].i) != 0
+      && (detail->data[1].i & SEF_IN_REGLIST) == 0)
+    return _("missing braces at operand %d");
+
+  /* If some opcodes expected a register, and we found a register,
+     complain about the difference.  */
+  if (detail->data[2].i)
+    {
+      unsigned int expected = (detail->data[1].i & SEF_IN_REGLIST
+                              ? detail->data[1].i & ~SEF_IN_REGLIST
+                              : detail->data[0].i & ~SEF_DEFAULT_ERROR);
+      const char *msg = get_reg_expected_msg (expected, detail->data[2].i);
+      if (!msg)
+       msg = N_("unexpected register type at operand %d");
+      return msg;
+    }
+
+  /* Handle the case where we got to the point of trying to parse a
+     register within a register list, but didn't find a known register.  */
+  if (detail->data[1].i & SEF_IN_REGLIST)
+    {
+      unsigned int expected = detail->data[1].i & ~SEF_IN_REGLIST;
+      const char *msg = get_reg_expected_msg (expected, 0);
+      if (!msg)
+       msg = _("invalid register list at operand %d");
+      return msg;
+    }
+
+  /* Punt if register-related problems weren't the only errors.  */
+  if (detail->data[0].i & SEF_DEFAULT_ERROR)
+    return NULL;
+
+  /* Handle the case where the only acceptable things are registers.  */
+  if (detail->data[1].i == 0)
+    {
+      const char *msg = get_reg_expected_msg (detail->data[0].i, 0);
+      if (!msg)
+       msg = _("expected a register at operand %d");
+      return msg;
+    }
+
+  /* Handle the case where the only acceptable things are register lists,
+     and there was no opening '{'.  */
+  if (detail->data[0].i == 0)
+    return _("expected '{' at operand %d");
+
+  return _("expected a register or register list at operand %d");
+}
+
 /* Output one operand error record.  */
 
 static void
@@ -4845,25 +5664,52 @@ output_operand_error_record (const operand_error_record *record, char *str)
 
   typedef void (*handler_t)(const char *format, ...);
   handler_t handler = detail->non_fatal ? as_warn : as_bad;
+  const char *msg = detail->error;
 
   switch (detail->kind)
     {
     case AARCH64_OPDE_NIL:
       gas_assert (0);
       break;
+
+    case AARCH64_OPDE_A_SHOULD_FOLLOW_B:
+      handler (_("this `%s' should have an immediately preceding `%s'"
+                " -- `%s'"),
+              detail->data[0].s, detail->data[1].s, str);
+      break;
+
+    case AARCH64_OPDE_EXPECTED_A_AFTER_B:
+      handler (_("the preceding `%s' should be followed by `%s` rather"
+                " than `%s` -- `%s'"),
+              detail->data[1].s, detail->data[0].s, opcode->name, str);
+      break;
+
     case AARCH64_OPDE_SYNTAX_ERROR:
+      if (!msg && idx >= 0)
+       {
+         msg = get_reg_error_message (detail);
+         if (msg)
+           {
+             char *full_msg = xasprintf (msg, idx + 1);
+             handler (_("%s -- `%s'"), full_msg, str);
+             free (full_msg);
+             break;
+           }
+       }
+      /* Fall through.  */
+
     case AARCH64_OPDE_RECOVERABLE:
     case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
     case AARCH64_OPDE_OTHER_ERROR:
       /* Use the prepared error message if there is, otherwise use the
         operand description string to describe the error.  */
-      if (detail->error != NULL)
+      if (msg != NULL)
        {
          if (idx < 0)
-           handler (_("%s -- `%s'"), detail->error, str);
+           handler (_("%s -- `%s'"), msg, str);
          else
            handler (_("%s at operand %d -- `%s'"),
-                    detail->error, idx + 1, str);
+                    msg, idx + 1, str);
        }
       else
        {
@@ -4970,37 +5816,76 @@ output_operand_error_record (const operand_error_record *record, char *str)
        }
       break;
 
+    case AARCH64_OPDE_UNTIED_IMMS:
+      handler (_("operand %d must have the same immediate value "
+                 "as operand 1 -- `%s'"),
+               detail->index + 1, str);
+      break;
+
     case AARCH64_OPDE_UNTIED_OPERAND:
       handler (_("operand %d must be the same register as operand 1 -- `%s'"),
-              detail->index + 1, str);
+               detail->index + 1, str);
+      break;
+
+    case AARCH64_OPDE_INVALID_REGNO:
+      handler (_("%s%d-%s%d expected at operand %d -- `%s'"),
+              detail->data[0].s, detail->data[1].i,
+              detail->data[0].s, detail->data[2].i, idx + 1, str);
       break;
 
     case AARCH64_OPDE_OUT_OF_RANGE:
-      if (detail->data[0] != detail->data[1])
+      if (detail->data[0].i != detail->data[1].i)
        handler (_("%s out of range %d to %d at operand %d -- `%s'"),
-                detail->error ? detail->error : _("immediate value"),
-                detail->data[0], detail->data[1], idx + 1, str);
+                msg ? msg : _("immediate value"),
+                detail->data[0].i, detail->data[1].i, idx + 1, str);
       else
        handler (_("%s must be %d at operand %d -- `%s'"),
-                detail->error ? detail->error : _("immediate value"),
-                detail->data[0], idx + 1, str);
+                msg ? msg : _("immediate value"),
+                detail->data[0].i, idx + 1, str);
+      break;
+
+    case AARCH64_OPDE_INVALID_VG_SIZE:
+      if (detail->data[0].i == 0)
+       handler (_("unexpected vector group size at operand %d -- `%s'"),
+                idx + 1, str);
+      else
+       handler (_("operand %d must have a vector group size of %d -- `%s'"),
+                idx + 1, detail->data[0].i, str);
       break;
 
-    case AARCH64_OPDE_REG_LIST:
-      if (detail->data[0] == 1)
-       handler (_("invalid number of registers in the list; "
-                  "only 1 register is expected at operand %d -- `%s'"),
+    case AARCH64_OPDE_REG_LIST_LENGTH:
+      if (detail->data[0].i == (1 << 1))
+       handler (_("expected a single-register list at operand %d -- `%s'"),
                 idx + 1, str);
+      else if ((detail->data[0].i & -detail->data[0].i) == detail->data[0].i)
+       handler (_("expected a list of %d registers at operand %d -- `%s'"),
+                get_log2 (detail->data[0].i), idx + 1, str);
+      else if (detail->data[0].i == 0x14)
+       handler (_("expected a list of %d or %d registers at"
+                  " operand %d -- `%s'"),
+                2, 4, idx + 1, str);
+      else
+       handler (_("invalid number of registers in the list"
+                  " at operand %d -- `%s'"), idx + 1, str);
+      break;
+
+    case AARCH64_OPDE_REG_LIST_STRIDE:
+      if (detail->data[0].i == (1 << 1))
+       handler (_("the register list must have a stride of %d"
+                  " at operand %d -- `%s'"), 1, idx + 1, str);
+      else if (detail->data[0].i == 0x12 || detail->data[0].i == 0x102)
+       handler (_("the register list must have a stride of %d or %d"
+                  " at operand %d -- `%s`"), 1,
+                detail->data[0].i == 0x12 ? 4 : 8, idx + 1, str);
       else
-       handler (_("invalid number of registers in the list; "
-                  "%d registers are expected at operand %d -- `%s'"),
-              detail->data[0], idx + 1, str);
+       handler (_("invalid register stride at operand %d -- `%s'"),
+                idx + 1, str);
       break;
 
     case AARCH64_OPDE_UNALIGNED:
       handler (_("immediate value must be a multiple of "
                 "%d at operand %d -- `%s'"),
-              detail->data[0], idx + 1, str);
+              detail->data[0].i, idx + 1, str);
       break;
 
     default:
@@ -5009,6 +5894,44 @@ output_operand_error_record (const operand_error_record *record, char *str)
     }
 }
 
+/* Return true if the presence of error A against an instruction means
+   that error B should not be reported.  This is only used as a first pass,
+   to pick the kind of error that we should report.  */
+
+static bool
+better_error_p (operand_error_record *a, operand_error_record *b)
+{
+  /* For errors reported during parsing, prefer errors that relate to
+     later operands, since that implies that the earlier operands were
+     syntactically valid.
+
+     For example, if we see a register R instead of an immediate in
+     operand N, we'll report that as a recoverable "immediate operand
+     required" error.  This is because there is often another opcode
+     entry that accepts a register operand N, and any errors about R
+     should be reported against the register forms of the instruction.
+     But if no such register form exists, the recoverable error should
+     still win over a syntax error against operand N-1.
+
+     For these purposes, count an error reported at the end of the
+     assembly string as equivalent to an error reported against the
+     final operand.  This means that opcode entries that expect more
+     operands win over "unexpected characters following instruction".  */
+  if (a->detail.kind <= AARCH64_OPDE_FATAL_SYNTAX_ERROR
+      && b->detail.kind <= AARCH64_OPDE_FATAL_SYNTAX_ERROR)
+    {
+      int a_index = (a->detail.index < 0
+                    ? aarch64_num_of_operands (a->opcode) - 1
+                    : a->detail.index);
+      int b_index = (b->detail.index < 0
+                    ? aarch64_num_of_operands (b->opcode) - 1
+                    : b->detail.index);
+      if (a_index != b_index)
+       return a_index > b_index;
+    }
+  return operand_error_higher_severity_p (a->detail.kind, b->detail.kind);
+}
+
 /* Process and output the error message about the operand mismatching.
 
    When this function is called, the operand error information had
@@ -5024,12 +5947,10 @@ output_operand_error_record (const operand_error_record *record, char *str)
 static void
 output_operand_error_report (char *str, bool non_fatal_only)
 {
-  int largest_error_pos;
-  const char *msg = NULL;
   enum aarch64_operand_error_kind kind;
   operand_error_record *curr;
   operand_error_record *head = operand_error_report.head;
-  operand_error_record *record = NULL;
+  operand_error_record *record;
 
   /* No error to report.  */
   if (head == NULL)
@@ -5053,20 +5974,38 @@ output_operand_error_report (char *str, bool non_fatal_only)
 
   /* Find the error kind of the highest severity.  */
   DEBUG_TRACE ("multiple opcode entries with error kind");
-  kind = AARCH64_OPDE_NIL;
+  record = NULL;
   for (curr = head; curr != NULL; curr = curr->next)
     {
       gas_assert (curr->detail.kind != AARCH64_OPDE_NIL);
-      DEBUG_TRACE ("\t%s", operand_mismatch_kind_names[curr->detail.kind]);
-      if (operand_error_higher_severity_p (curr->detail.kind, kind)
-         && (!non_fatal_only || (non_fatal_only && curr->detail.non_fatal)))
-       kind = curr->detail.kind;
+      if (curr->detail.kind == AARCH64_OPDE_SYNTAX_ERROR)
+       {
+         DEBUG_TRACE ("\t%s [%x, %x, %x]",
+                      operand_mismatch_kind_names[curr->detail.kind],
+                      curr->detail.data[0].i, curr->detail.data[1].i,
+                      curr->detail.data[2].i);
+       }
+      else if (curr->detail.kind == AARCH64_OPDE_REG_LIST_LENGTH
+              || curr->detail.kind == AARCH64_OPDE_REG_LIST_STRIDE)
+       {
+         DEBUG_TRACE ("\t%s [%x]",
+                      operand_mismatch_kind_names[curr->detail.kind],
+                      curr->detail.data[0].i);
+       }
+      else
+       {
+         DEBUG_TRACE ("\t%s", operand_mismatch_kind_names[curr->detail.kind]);
+       }
+      if ((!non_fatal_only || curr->detail.non_fatal)
+         && (!record || better_error_p (curr, record)))
+       record = curr;
     }
 
+  kind = (record ? record->detail.kind : AARCH64_OPDE_NIL);
   gas_assert (kind != AARCH64_OPDE_NIL || non_fatal_only);
 
   /* Pick up one of errors of KIND to report.  */
-  largest_error_pos = -2; /* Index can be -1 which means unknown index.  */
+  record = NULL;
   for (curr = head; curr != NULL; curr = curr->next)
     {
       /* If we don't want to print non-fatal errors then don't consider them
@@ -5078,13 +6017,35 @@ output_operand_error_report (char *str, bool non_fatal_only)
         mismatching operand index.  In the case of multiple errors with
         the equally highest operand index, pick up the first one or the
         first one with non-NULL error message.  */
-      if (curr->detail.index > largest_error_pos
-         || (curr->detail.index == largest_error_pos && msg == NULL
-             && curr->detail.error != NULL))
+      if (!record || curr->detail.index > record->detail.index)
+       record = curr;
+      else if (curr->detail.index == record->detail.index
+              && !record->detail.error)
        {
-         largest_error_pos = curr->detail.index;
-         record = curr;
-         msg = record->detail.error;
+         if (curr->detail.error)
+           record = curr;
+         else if (kind == AARCH64_OPDE_SYNTAX_ERROR)
+           {
+             record->detail.data[0].i |= curr->detail.data[0].i;
+             record->detail.data[1].i |= curr->detail.data[1].i;
+             record->detail.data[2].i |= curr->detail.data[2].i;
+             DEBUG_TRACE ("\t--> %s [%x, %x, %x]",
+                          operand_mismatch_kind_names[kind],
+                          curr->detail.data[0].i, curr->detail.data[1].i,
+                          curr->detail.data[2].i);
+           }
+         else if (kind == AARCH64_OPDE_REG_LIST_LENGTH
+                  || kind == AARCH64_OPDE_REG_LIST_STRIDE)
+           {
+             record->detail.data[0].i |= curr->detail.data[0].i;
+             DEBUG_TRACE ("\t--> %s [%x]",
+                          operand_mismatch_kind_names[kind],
+                          curr->detail.data[0].i);
+           }
+         /* Pick the variant with the cloest match.  */
+         else if (kind == AARCH64_OPDE_INVALID_VARIANT
+                  && record->detail.data[0].i > curr->detail.data[0].i)
+           record = curr;
        }
     }
 
@@ -5099,9 +6060,9 @@ output_operand_error_report (char *str, bool non_fatal_only)
   if (non_fatal_only && !record)
     return;
 
-  gas_assert (largest_error_pos != -2 && record != NULL);
+  gas_assert (record);
   DEBUG_TRACE ("Pick up error kind %s to report",
-              operand_mismatch_kind_names[record->detail.kind]);
+              operand_mismatch_kind_names[kind]);
 
   /* Output.  */
   output_operand_error_record (record, str);
@@ -5182,25 +6143,18 @@ lookup_mnemonic (const char *start, int len)
 }
 
 /* Subroutine of md_assemble, responsible for looking up the primary
-   opcode from the mnemonic the user wrote.  STR points to the
-   beginning of the mnemonic. */
+   opcode from the mnemonic the user wrote.  BASE points to the beginning
+   of the mnemonic, DOT points to the first '.' within the mnemonic
+   (if any) and END points to the end of the mnemonic.  */
 
 static templates *
-opcode_lookup (char **str)
+opcode_lookup (char *base, char *dot, char *end)
 {
-  char *end, *base, *dot;
   const aarch64_cond *cond;
   char condname[16];
   int len;
 
-  /* Scan up to the end of the mnemonic, which must end in white space,
-     '.', or end of string.  */
-  dot = 0;
-  for (base = end = *str; is_part_of_name(*end); end++)
-    if (*end == '.' && !dot)
-      dot = end;
-
-  if (end == base || dot == base)
+  if (dot == end)
     return 0;
 
   inst.cond = COND_ALWAYS;
@@ -5209,115 +6163,30 @@ opcode_lookup (char **str)
   if (dot)
     {
       cond = str_hash_find_n (aarch64_cond_hsh, dot + 1, end - dot - 1);
-      if (cond)
-       {
-         inst.cond = cond->value;
-         *str = end;
-       }
-      else
-       {
-         *str = dot;
-         return 0;
-       }
+      if (!cond)
+       return 0;
+      inst.cond = cond->value;
       len = dot - base;
     }
   else
-    {
-      *str = end;
-      len = end - base;
-    }
+    len = end - base;
 
   if (inst.cond == COND_ALWAYS)
-    {
-      /* Look for unaffixed mnemonic.  */
-      return lookup_mnemonic (base, len);
-    }
-  else if (len <= 13)
-    {
-      /* append ".c" to mnemonic if conditional */
-      memcpy (condname, base, len);
-      memcpy (condname + len, ".c", 2);
-      base = condname;
-      len += 2;
-      return lookup_mnemonic (base, len);
-    }
-
-  return NULL;
-}
-
-/* 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 vector_type_el *vectype)
-{
-  /* 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_4B,
-      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 | NTA_HASVARWIDTH))
-    {
-      /* Special case S_4B.  */
-      if (vectype->type == NT_b && vectype->width == 4)
-       return AARCH64_OPND_QLF_S_4B;
-
-      /* Special case S_2H.  */
-      if (vectype->type == NT_h && vectype->width == 2)
-       return AARCH64_OPND_QLF_S_2H;
-
-      /* Vector element register.  */
-      return AARCH64_OPND_QLF_S_B + vectype->type;
-    }
-  else
-    {
-      /* Vector register.  */
-      int reg_size = ele_size[vectype->type] * vectype->width;
-      unsigned offset;
-      unsigned shift;
-      if (reg_size != 16 && reg_size != 8 && reg_size != 4)
-       goto vectype_conversion_fail;
-
-      /* 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 = 3;
-      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_4B <= offset
-                 && offset <= AARCH64_OPND_QLF_V_1Q);
-      return offset;
+    {
+      /* Look for unaffixed mnemonic.  */
+      return lookup_mnemonic (base, len);
+    }
+  else if (len <= 13)
+    {
+      /* append ".c" to mnemonic if conditional */
+      memcpy (condname, base, len);
+      memcpy (condname + len, ".c", 2);
+      base = condname;
+      len += 2;
+      return lookup_mnemonic (base, len);
     }
 
- vectype_conversion_fail:
-  first_error (_("bad vector arrangement type"));
-  return AARCH64_OPND_QLF_NIL;
+  return NULL;
 }
 
 /* Process an optional operand that is found omitted from the assembly line.
@@ -5521,22 +6390,6 @@ process_movw_reloc_info (void)
   return true;
 }
 
-/* A primitive log calculator.  */
-
-static inline unsigned int
-get_logsz (unsigned int size)
-{
-  const unsigned char ls[16] =
-    {0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4};
-  if (size > 16)
-    {
-      gas_assert (0);
-      return -1;
-    }
-  gas_assert (ls[size - 1] != (unsigned char)-1);
-  return ls[size - 1];
-}
-
 /* Determine and return the real reloc type code for an instruction
    with the pseudo reloc type code BFD_RELOC_AARCH64_LDST_LO12.  */
 
@@ -5601,7 +6454,7 @@ ldst_lo12_determine_real_reloc_type (void)
                                      1, opd0_qlf, 0);
   gas_assert (opd1_qlf != AARCH64_OPND_QLF_NIL);
 
-  logsz = get_logsz (aarch64_get_qualifier_esize (opd1_qlf));
+  logsz = get_log2 (aarch64_get_qualifier_esize (opd1_qlf));
 
   if (inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
       || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC
@@ -5625,34 +6478,43 @@ ldst_lo12_determine_real_reloc_type (void)
   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
-   numbered in increasing order (modulo 32), in increments of one or two.
+/* Check whether a register list REGINFO is valid.  The registers have type
+   REG_TYPE and must be numbered in increasing order (modulo the register
+   bank size).  They must have a consistent stride.
 
-   If ACCEPT_ALTERNATE is non-zero, the register numbers should be in
-   increments of two.
-
-   Return FALSE if such a register list is invalid, otherwise return TRUE.  */
+   Return true if the list is valid, describing it in LIST if so.  */
 
 static bool
-reg_list_valid_p (uint32_t reginfo, int accept_alternate)
+reg_list_valid_p (uint32_t reginfo, struct aarch64_reglist *list,
+                 aarch64_reg_type reg_type)
 {
-  uint32_t i, nb_regs, prev_regno, incr;
+  uint32_t i, nb_regs, prev_regno, incr, mask;
+  mask = reg_type_mask (reg_type);
 
   nb_regs = 1 + (reginfo & 0x3);
   reginfo >>= 2;
   prev_regno = reginfo & 0x1f;
-  incr = accept_alternate ? 2 : 1;
+  incr = 1;
+
+  list->first_regno = prev_regno;
+  list->num_regs = nb_regs;
 
   for (i = 1; i < nb_regs; ++i)
     {
-      uint32_t curr_regno;
+      uint32_t curr_regno, curr_incr;
       reginfo >>= 5;
       curr_regno = reginfo & 0x1f;
-      if (curr_regno != ((prev_regno + incr) & 0x1f))
+      curr_incr = (curr_regno - prev_regno) & mask;
+      if (curr_incr == 0)
+       return false;
+      else if (i == 1)
+       incr = curr_incr;
+      else if (curr_incr != incr)
        return false;
       prev_regno = curr_regno;
     }
 
+  list->stride = incr;
   return true;
 }
 
@@ -5672,17 +6534,20 @@ parse_operands (char *str, const aarch64_opcode *opcode)
   clear_error ();
   skip_whitespace (str);
 
-  if (AARCH64_CPU_HAS_FEATURE (AARCH64_FEATURE_SVE, *opcode->avariant))
-    imm_reg_type = REG_TYPE_R_Z_SP_BHSDQ_VZP;
+  if (AARCH64_CPU_HAS_FEATURE (*opcode->avariant, AARCH64_FEATURE_SME2))
+    imm_reg_type = REG_TYPE_R_ZR_SP_BHSDQ_VZP_PN;
+  else if (AARCH64_CPU_HAS_ANY_FEATURES (*opcode->avariant,
+                                        AARCH64_FEATURE_SVE
+                                        | AARCH64_FEATURE_SVE2))
+    imm_reg_type = REG_TYPE_R_ZR_SP_BHSDQ_VZP;
   else
-    imm_reg_type = REG_TYPE_R_Z_BHSDQ_V;
+    imm_reg_type = REG_TYPE_R_ZR_BHSDQ_V;
 
   for (i = 0; operands[i] != AARCH64_OPND_NIL; i++)
     {
       int64_t val;
       const reg_entry *reg;
       int comma_skipped_p = 0;
-      aarch64_reg_type rtype;
       struct vector_type_el vectype;
       aarch64_opnd_qualifier_t qualifier, base_qualifier, offset_qualifier;
       aarch64_opnd_info *info = &inst.base.operands[i];
@@ -5723,7 +6588,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Rt_SYS:
        case AARCH64_OPND_PAIRREG:
        case AARCH64_OPND_SVE_Rm:
-         po_int_reg_or_fail (REG_TYPE_R_Z);
+         po_int_fp_reg_or_fail (REG_TYPE_R_ZR);
 
          /* In LS64 load/store instructions Rt register number must be even
             and <=22.  */
@@ -5746,7 +6611,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Rt_SP:
        case AARCH64_OPND_SVE_Rn_SP:
        case AARCH64_OPND_Rm_SP:
-         po_int_reg_or_fail (REG_TYPE_R_SP);
+         po_int_fp_reg_or_fail (REG_TYPE_R_SP);
          break;
 
        case AARCH64_OPND_Rm_EXT:
@@ -5781,16 +6646,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_Vd:
        case AARCH64_OPND_SVE_Vm:
        case AARCH64_OPND_SVE_Vn:
-         val = aarch64_reg_parse (&str, REG_TYPE_BHSDQ, &rtype, NULL);
-         if (val == PARSE_FAIL)
-           {
-             first_error (_(get_reg_expected_msg (REG_TYPE_BHSDQ)));
-             goto failure;
-           }
-         gas_assert (rtype >= REG_TYPE_FP_B && rtype <= REG_TYPE_FP_Q);
-
-         info->reg.regno = val;
-         info->qualifier = AARCH64_OPND_QLF_S_B + (rtype - REG_TYPE_FP_B);
+         po_int_fp_reg_or_fail (REG_TYPE_BHSDQ);
          break;
 
        case AARCH64_OPND_SVE_Pd:
@@ -5801,7 +6657,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_Pm:
        case AARCH64_OPND_SVE_Pn:
        case AARCH64_OPND_SVE_Pt:
-         reg_type = REG_TYPE_PN;
+       case AARCH64_OPND_SME_Pm:
+         reg_type = REG_TYPE_P;
          goto vector_reg;
 
        case AARCH64_OPND_SVE_Za_5:
@@ -5811,28 +6668,38 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_Zm_16:
        case AARCH64_OPND_SVE_Zn:
        case AARCH64_OPND_SVE_Zt:
-         reg_type = REG_TYPE_ZN;
+       case AARCH64_OPND_SME_Zm:
+         reg_type = REG_TYPE_Z;
+         goto vector_reg;
+
+       case AARCH64_OPND_SVE_PNd:
+       case AARCH64_OPND_SVE_PNg4_10:
+       case AARCH64_OPND_SVE_PNn:
+       case AARCH64_OPND_SVE_PNt:
+       case AARCH64_OPND_SME_PNd3:
+       case AARCH64_OPND_SME_PNg3:
+       case AARCH64_OPND_SME_PNn:
+         reg_type = REG_TYPE_PN;
          goto vector_reg;
 
        case AARCH64_OPND_Va:
        case AARCH64_OPND_Vd:
        case AARCH64_OPND_Vn:
        case AARCH64_OPND_Vm:
-         reg_type = REG_TYPE_VN;
+         reg_type = REG_TYPE_V;
        vector_reg:
-         val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
-         if (val == PARSE_FAIL)
-           {
-             first_error (_(get_reg_expected_msg (reg_type)));
-             goto failure;
-           }
+         reg = aarch64_reg_parse (&str, reg_type, &vectype);
+         if (!reg)
+           goto failure;
          if (vectype.defined & NTA_HASINDEX)
            goto failure;
 
-         info->reg.regno = val;
-         if ((reg_type == REG_TYPE_PN || reg_type == REG_TYPE_ZN)
+         info->reg.regno = reg->number;
+         if ((reg_type == REG_TYPE_P
+              || reg_type == REG_TYPE_PN
+              || reg_type == REG_TYPE_Z)
              && vectype.type == NT_invtype)
-           /* Unqualified Pn and Zn registers are allowed in certain
+           /* Unqualified P and Z registers are allowed in certain
               contexts.  Rely on F_STRICT qualifier checking to catch
               invalid uses.  */
            info->qualifier = AARCH64_OPND_QLF_NIL;
@@ -5846,19 +6713,16 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_VdD1:
        case AARCH64_OPND_VnD1:
-         val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
-         if (val == PARSE_FAIL)
-           {
-             set_first_syntax_error (_(get_reg_expected_msg (REG_TYPE_VN)));
-             goto failure;
-           }
+         reg = aarch64_reg_parse (&str, REG_TYPE_V, &vectype);
+         if (!reg)
+           goto failure;
          if (vectype.type != NT_d || vectype.index != 1)
            {
              set_fatal_syntax_error
                (_("the top half of a 128-bit FP/SIMD register is expected"));
              goto failure;
            }
-         info->reg.regno = val;
+         info->reg.regno = reg->number;
          /* N.B: VdD1 and VnD1 are treated as an fp or advsimd scalar register
             here; it is correct for the purpose of encoding/decoding since
             only the register number is explicitly encoded in the related
@@ -5868,11 +6732,25 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_SVE_Zm3_INDEX:
        case AARCH64_OPND_SVE_Zm3_22_INDEX:
+       case AARCH64_OPND_SVE_Zm3_19_INDEX:
        case AARCH64_OPND_SVE_Zm3_11_INDEX:
        case AARCH64_OPND_SVE_Zm4_11_INDEX:
        case AARCH64_OPND_SVE_Zm4_INDEX:
        case AARCH64_OPND_SVE_Zn_INDEX:
-         reg_type = REG_TYPE_ZN;
+       case AARCH64_OPND_SME_Zm_INDEX1:
+       case AARCH64_OPND_SME_Zm_INDEX2:
+       case AARCH64_OPND_SME_Zm_INDEX3_1:
+       case AARCH64_OPND_SME_Zm_INDEX3_2:
+       case AARCH64_OPND_SME_Zm_INDEX3_10:
+       case AARCH64_OPND_SME_Zm_INDEX4_1:
+       case AARCH64_OPND_SME_Zm_INDEX4_10:
+       case AARCH64_OPND_SME_Zn_INDEX1_16:
+       case AARCH64_OPND_SME_Zn_INDEX2_15:
+       case AARCH64_OPND_SME_Zn_INDEX2_16:
+       case AARCH64_OPND_SME_Zn_INDEX3_14:
+       case AARCH64_OPND_SME_Zn_INDEX3_15:
+       case AARCH64_OPND_SME_Zn_INDEX4_14:
+         reg_type = REG_TYPE_Z;
          goto vector_reg_index;
 
        case AARCH64_OPND_Ed:
@@ -5880,47 +6758,64 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Em:
        case AARCH64_OPND_Em16:
        case AARCH64_OPND_SM3_IMM2:
-         reg_type = REG_TYPE_VN;
+         reg_type = REG_TYPE_V;
        vector_reg_index:
-         val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
-         if (val == PARSE_FAIL)
+         reg = aarch64_reg_parse (&str, reg_type, &vectype);
+         if (!reg)
+           goto failure;
+         if (!(vectype.defined & NTA_HASINDEX))
+           goto failure;
+
+         if (reg->type == REG_TYPE_Z && vectype.type == NT_invtype)
+           /* Unqualified Zn[index] is allowed in LUTI2 instructions.  */
+           info->qualifier = AARCH64_OPND_QLF_NIL;
+         else
            {
-             first_error (_(get_reg_expected_msg (reg_type)));
-             goto failure;
+             if (vectype.type == NT_invtype)
+               goto failure;
+             info->qualifier = vectype_to_qualifier (&vectype);
+             if (info->qualifier == AARCH64_OPND_QLF_NIL)
+               goto failure;
            }
-         if (vectype.type == NT_invtype || !(vectype.defined & NTA_HASINDEX))
-           goto failure;
 
-         info->reglane.regno = val;
+         info->reglane.regno = reg->number;
          info->reglane.index = vectype.index;
-         info->qualifier = vectype_to_qualifier (&vectype);
-         if (info->qualifier == AARCH64_OPND_QLF_NIL)
-           goto failure;
          break;
 
        case AARCH64_OPND_SVE_ZnxN:
        case AARCH64_OPND_SVE_ZtxN:
-         reg_type = REG_TYPE_ZN;
+       case AARCH64_OPND_SME_Zdnx2:
+       case AARCH64_OPND_SME_Zdnx4:
+       case AARCH64_OPND_SME_Zmx2:
+       case AARCH64_OPND_SME_Zmx4:
+       case AARCH64_OPND_SME_Znx2:
+       case AARCH64_OPND_SME_Znx4:
+       case AARCH64_OPND_SME_Ztx2_STRIDED:
+       case AARCH64_OPND_SME_Ztx4_STRIDED:
+         reg_type = REG_TYPE_Z;
+         goto vector_reg_list;
+
+       case AARCH64_OPND_SME_Pdx2:
+       case AARCH64_OPND_SME_PdxN:
+         reg_type = REG_TYPE_P;
          goto vector_reg_list;
 
        case AARCH64_OPND_LVn:
        case AARCH64_OPND_LVt:
        case AARCH64_OPND_LVt_AL:
        case AARCH64_OPND_LEt:
-         reg_type = REG_TYPE_VN;
+         reg_type = REG_TYPE_V;
        vector_reg_list:
-         if (reg_type == REG_TYPE_ZN
+         if (reg_type == REG_TYPE_Z
              && get_opcode_dependent_value (opcode) == 1
              && *str != '{')
            {
-             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;
+             reg = aarch64_reg_parse (&str, reg_type, &vectype);
+             if (!reg)
+               goto failure;
+             info->reglist.first_regno = reg->number;
              info->reglist.num_regs = 1;
+             info->reglist.stride = 1;
            }
          else
            {
@@ -5928,21 +6823,18 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              if (val == PARSE_FAIL)
                goto failure;
 
-             if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+             if (! reg_list_valid_p (val, &info->reglist, reg_type))
                {
                  set_fatal_syntax_error (_("invalid register list"));
                  goto failure;
                }
 
-             if (vectype.width != 0 && *str != ',')
+             if ((int) vectype.width > 0 && *str != ',')
                {
                  set_fatal_syntax_error
                    (_("expected element type rather than vector type"));
                  goto failure;
                }
-
-             info->reglist.first_regno = (val >> 2) & 0x1f;
-             info->reglist.num_regs = (val & 0x3) + 1;
            }
          if (operands[i] == AARCH64_OPND_LEt)
            {
@@ -5957,7 +6849,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
                goto failure;
              if (!(vectype.defined & NTA_HASTYPE))
                {
-                 if (reg_type == REG_TYPE_ZN)
+                 if (reg_type == REG_TYPE_Z || reg_type == REG_TYPE_P)
                    set_fatal_syntax_error (_("missing type suffix"));
                  goto failure;
                }
@@ -6010,6 +6902,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_SHLIMM_PRED:
        case AARCH64_OPND_SVE_SHLIMM_UNPRED:
        case AARCH64_OPND_SVE_SHLIMM_UNPRED_22:
+       case AARCH64_OPND_SME_SHRIMM4:
+       case AARCH64_OPND_SME_SHRIMM5:
        case AARCH64_OPND_SVE_SHRIMM_PRED:
        case AARCH64_OPND_SVE_SHRIMM_UNPRED:
        case AARCH64_OPND_SVE_SHRIMM_UNPRED_22:
@@ -6027,6 +6921,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_IMM_ROT1:
        case AARCH64_OPND_SVE_IMM_ROT2:
        case AARCH64_OPND_SVE_IMM_ROT3:
+       case AARCH64_OPND_CSSC_SIMM8:
+       case AARCH64_OPND_CSSC_UIMM8:
          po_imm_nc_or_fail ();
          info->imm.value = val;
          break;
@@ -6115,13 +7011,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_IMM_MOV:
          {
            char *saved = str;
-           if (reg_name_p (str, REG_TYPE_R_Z_SP) ||
-               reg_name_p (str, REG_TYPE_VN))
+           if (reg_name_p (str, REG_TYPE_R_ZR_SP)
+               || reg_name_p (str, REG_TYPE_V))
              goto failure;
            str = saved;
            po_misc_or_fail (aarch64_get_expression (&inst.reloc.exp, &str,
-                                                    GE_OPT_PREFIX, REJECT_ABSENT,
-                                                    NORMAL_RESOLUTION));
+                                                    GE_OPT_PREFIX, REJECT_ABSENT));
            /* The MOV immediate alias will be fixed up by fix_mov_imm_insn
               later.  fix_mov_imm_insn will try to determine a machine
               instruction (MOVZ, MOVN or ORR) for it and will issue an error
@@ -6560,9 +7455,27 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          /* No qualifier.  */
          break;
 
+       case AARCH64_OPND_SME_SM_ZA:
+         /* { SM | ZA }  */
+         if ((val = parse_sme_sm_za (&str)) == PARSE_FAIL)
+           {
+             set_syntax_error (_("unknown or missing PSTATE field name"));
+             goto failure;
+           }
+         info->reg.regno = val;
+         break;
+
+       case AARCH64_OPND_SME_PnT_Wm_imm:
+         if (!parse_dual_indexed_reg (&str, REG_TYPE_P,
+                                      &info->indexed_za, &qualifier, 0))
+           goto failure;
+         info->qualifier = qualifier;
+         break;
+
        case AARCH64_OPND_SVE_ADDR_RI_S4x16:
        case AARCH64_OPND_SVE_ADDR_RI_S4x32:
        case AARCH64_OPND_SVE_ADDR_RI_S4xVL:
+       case AARCH64_OPND_SME_ADDR_RI_U4xVL:
        case AARCH64_OPND_SVE_ADDR_RI_S4x2xVL:
        case AARCH64_OPND_SVE_ADDR_RI_S4x3xVL:
        case AARCH64_OPND_SVE_ADDR_RI_S4x4xVL:
@@ -6618,11 +7531,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              goto failure;
            }
          goto regoff_addr;
-         
+
        case AARCH64_OPND_SVE_ADDR_RR:
        case AARCH64_OPND_SVE_ADDR_RR_LSL1:
        case AARCH64_OPND_SVE_ADDR_RR_LSL2:
        case AARCH64_OPND_SVE_ADDR_RR_LSL3:
+       case AARCH64_OPND_SVE_ADDR_RR_LSL4:
        case AARCH64_OPND_SVE_ADDR_RX:
        case AARCH64_OPND_SVE_ADDR_RX_LSL1:
        case AARCH64_OPND_SVE_ADDR_RX_LSL2:
@@ -6747,14 +7661,18 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          }
 
        case AARCH64_OPND_PSTATEFIELD:
-         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, NULL))
-             == PARSE_FAIL)
-           {
-             set_syntax_error (_("unknown or missing PSTATE field name"));
-             goto failure;
-           }
-         inst.base.operands[i].pstatefield = val;
-         break;
+         {
+           uint32_t sysreg_flags;
+           if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1,
+                                     &sysreg_flags)) == PARSE_FAIL)
+             {
+               set_syntax_error (_("unknown or missing PSTATE field name"));
+               goto failure;
+             }
+           inst.base.operands[i].pstatefield = val;
+           inst.base.operands[i].sysreg.flags = sysreg_flags;
+           break;
+         }
 
        case AARCH64_OPND_SYSREG_IC:
          inst.base.operands[i].sysins_op =
@@ -6855,18 +7773,139 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          inst.base.operands[i].prfop = aarch64_prfops + val;
          break;
 
+       case AARCH64_OPND_RPRFMOP:
+         po_enum_or_fail (aarch64_rprfmop_array);
+         info->imm.value = val;
+         break;
+
        case AARCH64_OPND_BARRIER_PSB:
          val = parse_barrier_psb (&str, &(info->hint_option));
          if (val == PARSE_FAIL)
            goto failure;
          break;
 
+       case AARCH64_OPND_SME_ZT0:
+         po_reg_or_fail (REG_TYPE_ZT0);
+         break;
+
+       case AARCH64_OPND_SME_ZT0_INDEX:
+         reg = aarch64_reg_parse (&str, REG_TYPE_ZT0, &vectype);
+         if (!reg || vectype.type != NT_invtype)
+           goto failure;
+         if (!(vectype.defined & NTA_HASINDEX))
+           {
+             set_syntax_error (_("missing register index"));
+             goto failure;
+           }
+         info->imm.value = vectype.index;
+         break;
+
+       case AARCH64_OPND_SME_ZT0_LIST:
+         if (*str != '{')
+           {
+             set_expected_reglist_error (REG_TYPE_ZT0, parse_reg (&str));
+             goto failure;
+           }
+         str++;
+         if (!parse_typed_reg (&str, REG_TYPE_ZT0, &vectype, PTR_IN_REGLIST))
+           goto failure;
+         if (*str != '}')
+           {
+             set_syntax_error (_("expected '}' after ZT0"));
+             goto failure;
+           }
+         str++;
+         break;
+
+       case AARCH64_OPND_SME_PNn3_INDEX1:
+       case AARCH64_OPND_SME_PNn3_INDEX2:
+         reg = aarch64_reg_parse (&str, REG_TYPE_PN, &vectype);
+         if (!reg)
+           goto failure;
+         if (!(vectype.defined & NTA_HASINDEX))
+           {
+             set_syntax_error (_("missing register index"));
+             goto failure;
+           }
+         info->reglane.regno = reg->number;
+         info->reglane.index = vectype.index;
+         if (vectype.type == NT_invtype)
+           info->qualifier = AARCH64_OPND_QLF_NIL;
+         else
+           info->qualifier = vectype_to_qualifier (&vectype);
+         break;
+
        case AARCH64_OPND_BTI_TARGET:
          val = parse_bti_operand (&str, &(info->hint_option));
          if (val == PARSE_FAIL)
            goto failure;
          break;
 
+       case AARCH64_OPND_SME_ZAda_2b:
+       case AARCH64_OPND_SME_ZAda_3b:
+         reg = parse_reg_with_qual (&str, REG_TYPE_ZAT, &qualifier, 0);
+         if (!reg)
+           goto failure;
+         info->reg.regno = reg->number;
+         info->qualifier = qualifier;
+         break;
+
+       case AARCH64_OPND_SME_ZA_HV_idx_src:
+       case AARCH64_OPND_SME_ZA_HV_idx_srcxN:
+       case AARCH64_OPND_SME_ZA_HV_idx_dest:
+       case AARCH64_OPND_SME_ZA_HV_idx_destxN:
+       case AARCH64_OPND_SME_ZA_HV_idx_ldstr:
+         if (operands[i] == AARCH64_OPND_SME_ZA_HV_idx_ldstr
+             ? !parse_sme_za_hv_tiles_operand_with_braces (&str,
+                                                           &info->indexed_za,
+                                                           &qualifier)
+             : !parse_dual_indexed_reg (&str, REG_TYPE_ZATHV,
+                                        &info->indexed_za, &qualifier, 0))
+           goto failure;
+         info->qualifier = qualifier;
+         break;
+
+       case AARCH64_OPND_SME_list_of_64bit_tiles:
+         val = parse_sme_list_of_64bit_tiles (&str);
+         if (val == PARSE_FAIL)
+           goto failure;
+         info->imm.value = val;
+         break;
+
+       case AARCH64_OPND_SME_ZA_array_off1x4:
+       case AARCH64_OPND_SME_ZA_array_off2x2:
+       case AARCH64_OPND_SME_ZA_array_off2x4:
+       case AARCH64_OPND_SME_ZA_array_off3_0:
+       case AARCH64_OPND_SME_ZA_array_off3_5:
+       case AARCH64_OPND_SME_ZA_array_off3x2:
+       case AARCH64_OPND_SME_ZA_array_off4:
+         if (!parse_dual_indexed_reg (&str, REG_TYPE_ZA,
+                                      &info->indexed_za, &qualifier, 0))
+           goto failure;
+         info->qualifier = qualifier;
+         break;
+
+       case AARCH64_OPND_SME_VLxN_10:
+       case AARCH64_OPND_SME_VLxN_13:
+         po_strict_enum_or_fail (aarch64_sme_vlxn_array);
+         info->imm.value = val;
+         break;
+
+       case AARCH64_OPND_MOPS_ADDR_Rd:
+       case AARCH64_OPND_MOPS_ADDR_Rs:
+         po_char_or_fail ('[');
+         if (!parse_x0_to_x30 (&str, info))
+           goto failure;
+         po_char_or_fail (']');
+         po_char_or_fail ('!');
+         break;
+
+       case AARCH64_OPND_MOPS_WB_Rn:
+         if (!parse_x0_to_x30 (&str, info))
+           goto failure;
+         po_char_or_fail ('!');
+         break;
+
        default:
          as_fatal (_("unhandled operand code %d"), operands[i]);
        }
@@ -6945,15 +7984,15 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
   if (error_p ())
     {
+      inst.parsing_error.index = i;
       DEBUG_TRACE ("parsing FAIL: %s - %s",
-                  operand_mismatch_kind_names[get_error_kind ()],
-                  get_error_message ());
+                  operand_mismatch_kind_names[inst.parsing_error.kind],
+                  inst.parsing_error.error);
       /* Record the operand error properly; this is useful when there
         are multiple instruction templates for a mnemonic name, so that
         later on, we can select the error that most closely describes
         the problem.  */
-      record_operand_error (opcode, i, get_error_kind (),
-                           get_error_message ());
+      record_operand_error_info (opcode, &inst.parsing_error);
       return false;
     }
   else
@@ -7170,11 +8209,15 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
 static void
 force_automatic_sequence_close (void)
 {
-  if (now_instr_sequence.instr)
+  struct aarch64_segment_info_type *tc_seg_info;
+
+  tc_seg_info = &seg_info (now_seg)->tc_segment_info_data;
+  if (tc_seg_info->insn_sequence.instr)
     {
-      as_warn (_("previous `%s' sequence has not been closed"),
-              now_instr_sequence.instr->opcode->name);
-      init_insn_sequence (NULL, &now_instr_sequence);
+      as_warn_where (tc_seg_info->last_file, tc_seg_info->last_line,
+                    _("previous `%s' sequence has not been closed"),
+                    tc_seg_info->insn_sequence.instr->opcode->name);
+      init_insn_sequence (NULL, &tc_seg_info->insn_sequence);
     }
 }
 
@@ -7222,9 +8265,9 @@ dump_opcode_operands (const aarch64_opcode *opcode)
 void
 md_assemble (char *str)
 {
-  char *p = str;
   templates *template;
   const aarch64_opcode *opcode;
+  struct aarch64_segment_info_type *tc_seg_info;
   aarch64_inst *inst_base;
   unsigned saved_cond;
 
@@ -7237,7 +8280,9 @@ md_assemble (char *str)
     }
 
   /* Update the current insn_sequence from the segment.  */
-  insn_sequence = &seg_info (now_seg)->tc_segment_info_data.insn_sequence;
+  tc_seg_info = &seg_info (now_seg)->tc_segment_info_data;
+  insn_sequence = &tc_seg_info->insn_sequence;
+  tc_seg_info->last_file = as_where (&tc_seg_info->last_line);
 
   inst.reloc.type = BFD_RELOC_UNUSED;
 
@@ -7245,14 +8290,28 @@ md_assemble (char *str)
   DEBUG_TRACE ("==============================");
   DEBUG_TRACE ("Enter md_assemble with %s", str);
 
-  template = opcode_lookup (&p);
+  /* Scan up to the end of the mnemonic, which must end in whitespace,
+     '.', or end of string.  */
+  char *p = str;
+  char *dot = 0;
+  for (; is_part_of_name (*p); p++)
+    if (*p == '.' && !dot)
+      dot = p;
+
+  if (p == str)
+    {
+      as_bad (_("unknown mnemonic -- `%s'"), str);
+      return;
+    }
+
+  if (!dot && create_register_alias (str, p))
+    return;
+
+  template = opcode_lookup (str, dot, p);
   if (!template)
     {
-      /* It wasn't an instruction, but it might be a register alias of
-         the form alias .req reg directive.  */
-      if (!create_register_alias (str, p))
-       as_bad (_("unknown mnemonic `%s' -- `%s'"), get_mnemonic_name (str),
-               str);
+      as_bad (_("unknown mnemonic `%s' -- `%s'"), get_mnemonic_name (str),
+             str);
       return;
     }
 
@@ -7314,8 +8373,7 @@ md_assemble (char *str)
          && do_encode (inst_base->opcode, &inst.base, &inst_base->value))
        {
          /* Check that this instruction is supported for this CPU.  */
-         if (!opcode->avariant
-             || !AARCH64_CPU_HAS_ALL_FEATURES (cpu_variant, *opcode->avariant))
+         if (!aarch64_cpu_supports_inst_p (cpu_variant, inst_base))
            {
              as_bad (_("selected processor does not support `%s'"), str);
              return;
@@ -7411,11 +8469,17 @@ aarch64_canonicalize_symbol_name (char *name)
 #define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, true }
 #define REGDEF_ALIAS(s, n, t) { #s, n, REG_TYPE_##t, false}
 #define REGNUM(p,n,t) REGDEF(p##n, n, t)
+#define REGNUMS(p,n,s,t) REGDEF(p##n##s, n, 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)
+#define REGSET16S(p,s,t) \
+  REGNUMS(p, 0,s,t), REGNUMS(p, 1,s,t), REGNUMS(p, 2,s,t), REGNUMS(p, 3,s,t), \
+  REGNUMS(p, 4,s,t), REGNUMS(p, 5,s,t), REGNUMS(p, 6,s,t), REGNUMS(p, 7,s,t), \
+  REGNUMS(p, 8,s,t), REGNUMS(p, 9,s,t), REGNUMS(p,10,s,t), REGNUMS(p,11,s,t), \
+  REGNUMS(p,12,s,t), REGNUMS(p,13,s,t), REGNUMS(p,14,s,t), REGNUMS(p,15,s,t)
 #define REGSET31(p,t) \
   REGSET16(p, t), \
   REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
@@ -7438,8 +8502,8 @@ static const reg_entry reg_names[] = {
   REGDEF (wsp, 31, SP_32), REGDEF (WSP, 31, SP_32),
   REGDEF (sp, 31, SP_64), REGDEF (SP, 31, SP_64),
 
-  REGDEF (wzr, 31, Z_32), REGDEF (WZR, 31, Z_32),
-  REGDEF (xzr, 31, Z_64), REGDEF (XZR, 31, Z_64),
+  REGDEF (wzr, 31, ZR_32), REGDEF (WZR, 31, ZR_32),
+  REGDEF (xzr, 31, ZR_64), REGDEF (XZR, 31, ZR_64),
 
   /* Floating-point single precision registers.  */
   REGSET (s, FP_S), REGSET (S, FP_S),
@@ -7457,13 +8521,32 @@ static const reg_entry reg_names[] = {
   REGSET (q, FP_Q), REGSET (Q, FP_Q),
 
   /* FP/SIMD registers.  */
-  REGSET (v, VN), REGSET (V, VN),
+  REGSET (v, V), REGSET (V, V),
 
   /* SVE vector registers.  */
-  REGSET (z, ZN), REGSET (Z, ZN),
+  REGSET (z, Z), REGSET (Z, Z),
+
+  /* SVE predicate(-as-mask) registers.  */
+  REGSET16 (p, P), REGSET16 (P, P),
+
+  /* SVE predicate-as-counter registers.  */
+  REGSET16 (pn, PN), REGSET16 (PN, PN),
+
+  /* SME ZA.  We model this as a register because it acts syntactically
+     like ZA0H, supporting qualifier suffixes and indexing.  */
+  REGDEF (za, 0, ZA), REGDEF (ZA, 0, ZA),
+
+  /* SME ZA tile registers.  */
+  REGSET16 (za, ZAT), REGSET16 (ZA, ZAT),
+
+  /* SME ZA tile registers (horizontal slice).  */
+  REGSET16S (za, h, ZATH), REGSET16S (ZA, H, ZATH),
+
+  /* SME ZA tile registers (vertical slice).  */
+  REGSET16S (za, v, ZATV), REGSET16S (ZA, V, ZATV),
 
-  /* SVE predicate registers.  */
-  REGSET16 (p, PN), REGSET16 (P, PN)
+  /* SME2 ZT0.  */
+  REGDEF (zt0, 0, ZT0), REGDEF (ZT0, 0, ZT0)
 };
 
 #undef REGDEF
@@ -7594,7 +8677,7 @@ aarch64_handle_align (fragS * fragP)
   fix = bytes & (noop_size - 1);
   if (fix)
     {
-#ifdef OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
       insert_data_mapping_symbol (MAP_INSN, fragP->fr_fix, fragP, fix);
 #endif
       memset (p, 0, fix);
@@ -7652,6 +8735,51 @@ aarch64_init_frag (fragS * fragP, int max_chars)
       break;
     }
 }
+
+/* Whether SFrame stack trace info is supported.  */
+
+bool
+aarch64_support_sframe_p (void)
+{
+  /* At this time, SFrame is supported for aarch64 only.  */
+  return (aarch64_abi == AARCH64_ABI_LP64);
+}
+
+/* Specify if RA tracking is needed.  */
+
+bool
+aarch64_sframe_ra_tracking_p (void)
+{
+  return true;
+}
+
+/* Specify the fixed offset to recover RA from CFA.
+   (useful only when RA tracking is not needed).  */
+
+offsetT
+aarch64_sframe_cfa_ra_offset (void)
+{
+  return (offsetT) SFRAME_CFA_FIXED_RA_INVALID;
+}
+
+/* Get the abi/arch indentifier for SFrame.  */
+
+unsigned char
+aarch64_sframe_get_abi_arch (void)
+{
+  unsigned char sframe_abi_arch = 0;
+
+  if (aarch64_support_sframe_p ())
+    {
+      sframe_abi_arch = target_big_endian
+       ? SFRAME_ABI_AARCH64_ENDIAN_BIG
+       : SFRAME_ABI_AARCH64_ENDIAN_LITTLE;
+    }
+
+  return sframe_abi_arch;
+}
+
+#endif /* OBJ_ELF */
 \f
 /* Initialize the DWARF-2 unwind information for this procedure.  */
 
@@ -7660,7 +8788,6 @@ tc_aarch64_frame_initial_instructions (void)
 {
   cfi_add_CFA_def_cfa (REG_SP, 0);
 }
-#endif /* OBJ_ELF */
 
 /* Convert REGNAME to a DWARF-2 register number.  */
 
@@ -7697,10 +8824,10 @@ tc_aarch64_regname_to_dw2regnum (char *regname)
 int
 aarch64_dwarf2_addr_size (void)
 {
-#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
   if (ilp32_p)
     return 4;
-#endif
+  else if (llp64_p)
+    return 8;
   return bfd_arch_bits_per_address (stdoutput) / 8;
 }
 
@@ -8107,7 +9234,8 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
 
   /* Note whether this will delete the relocation.  */
 
-  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
+  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel
+      && aarch64_force_reloc (fixP->fx_r_type) <= 0)
     fixP->fx_done = 1;
 
   /* Process the relocations.  */
@@ -8456,6 +9584,11 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       /* An error will already have been reported.  */
       break;
 
+    case BFD_RELOC_RVA:
+    case BFD_RELOC_32_SECREL:
+    case BFD_RELOC_16_SECIDX:
+      break;
+
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
                    _("unexpected %s fixup"),
@@ -8539,33 +9672,48 @@ cons_fix_new_aarch64 (fragS * frag, int where, int size, expressionS * exp)
   bfd_reloc_code_real_type type;
   int pcrel = 0;
 
-  /* Pick a reloc.
-     FIXME: @@ Should look at CPU word size.  */
-  switch (size)
+#ifdef TE_PE
+  if (exp->X_op == O_secrel)
     {
-    case 1:
-      type = BFD_RELOC_8;
-      break;
-    case 2:
-      type = BFD_RELOC_16;
-      break;
-    case 4:
-      type = BFD_RELOC_32;
-      break;
-    case 8:
-      type = BFD_RELOC_64;
-      break;
-    default:
-      as_bad (_("cannot do %u-byte relocation"), size);
-      type = BFD_RELOC_UNUSED;
-      break;
+      exp->X_op = O_symbol;
+      type = BFD_RELOC_32_SECREL;
+    }
+  else if (exp->X_op == O_secidx)
+    {
+      exp->X_op = O_symbol;
+      type = BFD_RELOC_16_SECIDX;
+    }
+  else
+    {
+#endif
+    /* Pick a reloc.
+       FIXME: @@ Should look at CPU word size.  */
+    switch (size)
+      {
+      case 1:
+       type = BFD_RELOC_8;
+       break;
+      case 2:
+       type = BFD_RELOC_16;
+       break;
+      case 4:
+       type = BFD_RELOC_32;
+       break;
+      case 8:
+       type = BFD_RELOC_64;
+       break;
+      default:
+       as_bad (_("cannot do %u-byte relocation"), size);
+       type = BFD_RELOC_UNUSED;
+       break;
+      }
+#ifdef TE_PE
     }
+#endif
 
   fix_new_exp (frag, where, (int) size, exp, pcrel, type);
 }
 
-#ifdef OBJ_ELF
-
 /* Implement md_after_parse_args.  This is the earliest time we need to decide
    ABI.  If no -mabi specified, the ABI will be decided by target triplet.  */
 
@@ -8575,13 +9723,18 @@ aarch64_after_parse_args (void)
   if (aarch64_abi != AARCH64_ABI_NONE)
     return;
 
+#ifdef OBJ_ELF
   /* DEFAULT_ARCH will have ":32" extension if it's configured for ILP32.  */
   if (strlen (default_arch) > 7 && strcmp (default_arch + 7, ":32") == 0)
     aarch64_abi = AARCH64_ABI_ILP32;
   else
     aarch64_abi = AARCH64_ABI_LP64;
+#else
+  aarch64_abi = AARCH64_ABI_LLP64;
+#endif
 }
 
+#ifdef OBJ_ELF
 const char *
 elf64_aarch64_target_format (void)
 {
@@ -8604,6 +9757,12 @@ aarch64elf_frob_symbol (symbolS * symp, int *puntp)
 {
   elf_frob_symbol (symp, puntp);
 }
+#elif defined OBJ_COFF
+const char *
+coff_aarch64_target_format (void)
+{
+  return "pe-aarch64-little";
+}
 #endif
 
 /* MD interface: Finalization. */
@@ -8919,9 +10078,20 @@ md_begin (void)
   cpu_variant = *mcpu_cpu_opt;
 
   /* Record the CPU type.  */
-  mach = ilp32_p ? bfd_mach_aarch64_ilp32 : bfd_mach_aarch64;
+  if(ilp32_p)
+    mach = bfd_mach_aarch64_ilp32;
+  else if (llp64_p)
+    mach = bfd_mach_aarch64_llp64;
+  else
+    mach = bfd_mach_aarch64;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
+#ifdef OBJ_ELF
+  /* FIXME - is there a better way to do it ?  */
+  aarch64_sframe_cfa_sp_reg = 31;
+  aarch64_sframe_cfa_fp_reg = 29; /* x29.  */
+  aarch64_sframe_cfa_ra_reg = 30;
+#endif
 }
 
 /* Command line processing.  */
@@ -9051,6 +10221,27 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = {
                    | AARCH64_FEATURE_RCPC
                    | AARCH64_FEATURE_SSBS),
    "Cortex-A78C"},
+  {"cortex-a510", AARCH64_FEATURE (AARCH64_ARCH_V9,
+                  AARCH64_FEATURE_BFLOAT16
+                  | AARCH64_FEATURE_I8MM
+                  | AARCH64_FEATURE_MEMTAG
+                  | AARCH64_FEATURE_SVE2_BITPERM),
+   "Cortex-A510"},
+  {"cortex-a520", AARCH64_FEATURE (AARCH64_ARCH_V9_2,
+                  AARCH64_FEATURE_MEMTAG
+                  | AARCH64_FEATURE_SVE2_BITPERM),
+   "Cortex-A520"},
+  {"cortex-a710", AARCH64_FEATURE (AARCH64_ARCH_V9,
+                  AARCH64_FEATURE_BFLOAT16
+                  | AARCH64_FEATURE_I8MM
+                  | AARCH64_FEATURE_MEMTAG
+                  | AARCH64_FEATURE_SVE2_BITPERM),
+   "Cortex-A710"},
+  {"cortex-a720", AARCH64_FEATURE (AARCH64_ARCH_V9_2,
+                  AARCH64_FEATURE_MEMTAG
+                 | AARCH64_FEATURE_PROFILE
+                  | AARCH64_FEATURE_SVE2_BITPERM),
+   "Cortex-A720"},
   {"ares", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
                                  AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16
                                  | AARCH64_FEATURE_DOTPROD
@@ -9120,6 +10311,12 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = {
                 | AARCH64_FEATURE_SSBS
                 | AARCH64_FEATURE_PROFILE),
                 "Cortex-X1"},
+  {"cortex-x2", AARCH64_FEATURE (AARCH64_ARCH_V9,
+                AARCH64_FEATURE_BFLOAT16
+                | AARCH64_FEATURE_I8MM
+                | AARCH64_FEATURE_MEMTAG
+                | AARCH64_FEATURE_SVE2_BITPERM),
+                "Cortex-X2"},
   {"generic", AARCH64_ARCH_V8, NULL},
 
   {NULL, AARCH64_ARCH_NONE, NULL}
@@ -9143,7 +10340,12 @@ static const struct aarch64_arch_option_table aarch64_archs[] = {
   {"armv8.5-a", AARCH64_ARCH_V8_5},
   {"armv8.6-a", AARCH64_ARCH_V8_6},
   {"armv8.7-a", AARCH64_ARCH_V8_7},
+  {"armv8.8-a", AARCH64_ARCH_V8_8},
   {"armv8-r",  AARCH64_ARCH_V8_R},
+  {"armv9-a",  AARCH64_ARCH_V9},
+  {"armv9.1-a",        AARCH64_ARCH_V9_1},
+  {"armv9.2-a",        AARCH64_ARCH_V9_2},
+  {"armv9.3-a",        AARCH64_ARCH_V9_3},
   {NULL, AARCH64_ARCH_NONE}
 };
 
@@ -9177,14 +10379,11 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"fp16",             AARCH64_FEATURE (AARCH64_FEATURE_F16, 0),
                        AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
   {"fp16fml",          AARCH64_FEATURE (AARCH64_FEATURE_F16_FML, 0),
-                       AARCH64_FEATURE (AARCH64_FEATURE_FP
-                                        | AARCH64_FEATURE_F16, 0)},
+                       AARCH64_FEATURE (AARCH64_FEATURE_F16, 0)},
   {"profile",          AARCH64_FEATURE (AARCH64_FEATURE_PROFILE, 0),
                        AARCH64_ARCH_NONE},
   {"sve",              AARCH64_FEATURE (AARCH64_FEATURE_SVE, 0),
-                       AARCH64_FEATURE (AARCH64_FEATURE_F16
-                                        | AARCH64_FEATURE_SIMD
-                                        | AARCH64_FEATURE_COMPNUM, 0)},
+                       AARCH64_FEATURE (AARCH64_FEATURE_COMPNUM, 0)},
   {"tme",              AARCH64_FEATURE (AARCH64_FEATURE_TME, 0),
                        AARCH64_ARCH_NONE},
   {"compnum",          AARCH64_FEATURE (AARCH64_FEATURE_COMPNUM, 0),
@@ -9193,17 +10392,17 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"rcpc",             AARCH64_FEATURE (AARCH64_FEATURE_RCPC, 0),
                        AARCH64_ARCH_NONE},
   {"dotprod",          AARCH64_FEATURE (AARCH64_FEATURE_DOTPROD, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
   {"sha2",             AARCH64_FEATURE (AARCH64_FEATURE_SHA2, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
   {"sb",               AARCH64_FEATURE (AARCH64_FEATURE_SB, 0),
                        AARCH64_ARCH_NONE},
   {"predres",          AARCH64_FEATURE (AARCH64_FEATURE_PREDRES, 0),
                        AARCH64_ARCH_NONE},
   {"aes",              AARCH64_FEATURE (AARCH64_FEATURE_AES, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
   {"sm4",              AARCH64_FEATURE (AARCH64_FEATURE_SM4, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
   {"sha3",             AARCH64_FEATURE (AARCH64_FEATURE_SHA3, 0),
                        AARCH64_FEATURE (AARCH64_FEATURE_SHA2, 0)},
   {"rng",              AARCH64_FEATURE (AARCH64_FEATURE_RNG, 0),
@@ -9225,10 +10424,23 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
                                         | AARCH64_FEATURE_SHA3, 0)},
   {"sve2-bitperm",     AARCH64_FEATURE (AARCH64_FEATURE_SVE2_BITPERM, 0),
                        AARCH64_FEATURE (AARCH64_FEATURE_SVE2, 0)},
+  {"sme",              AARCH64_FEATURE (AARCH64_FEATURE_SME, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SVE2
+                                        | AARCH64_FEATURE_BFLOAT16, 0)},
+  {"sme-f64",          AARCH64_FEATURE (AARCH64_FEATURE_SME_F64F64, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SME, 0)},
+  {"sme-f64f64",       AARCH64_FEATURE (AARCH64_FEATURE_SME_F64F64, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SME, 0)},
+  {"sme-i64",          AARCH64_FEATURE (AARCH64_FEATURE_SME_I16I64, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SME, 0)},
+  {"sme-i16i64",       AARCH64_FEATURE (AARCH64_FEATURE_SME_I16I64, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SME, 0)},
+  {"sme2",             AARCH64_FEATURE (AARCH64_FEATURE_SME2, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SME, 0)},
   {"bf16",             AARCH64_FEATURE (AARCH64_FEATURE_BFLOAT16, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
   {"i8mm",             AARCH64_FEATURE (AARCH64_FEATURE_I8MM, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
   {"f32mm",            AARCH64_FEATURE (AARCH64_FEATURE_F32MM, 0),
                        AARCH64_FEATURE (AARCH64_FEATURE_SVE, 0)},
   {"f64mm",            AARCH64_FEATURE (AARCH64_FEATURE_F64MM, 0),
@@ -9239,6 +10451,12 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
                        AARCH64_ARCH_NONE},
   {"pauth",            AARCH64_FEATURE (AARCH64_FEATURE_PAC, 0),
                        AARCH64_ARCH_NONE},
+  {"mops",             AARCH64_FEATURE (AARCH64_FEATURE_MOPS, 0),
+                       AARCH64_ARCH_NONE},
+  {"hbc",              AARCH64_FEATURE (AARCH64_FEATURE_HBC, 0),
+                       AARCH64_ARCH_NONE},
+  {"cssc",             AARCH64_FEATURE (AARCH64_FEATURE_CSSC, 0),
+                       AARCH64_ARCH_NONE},
   {NULL,               AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
 };
 
@@ -9449,8 +10667,12 @@ struct aarch64_option_abi_value_table
 };
 
 static const struct aarch64_option_abi_value_table aarch64_abis[] = {
+#ifdef OBJ_ELF
   {"ilp32",            AARCH64_ABI_ILP32},
   {"lp64",             AARCH64_ABI_LP64},
+#else
+  {"llp64",            AARCH64_ABI_LLP64},
+#endif
 };
 
 static int
@@ -9476,10 +10698,8 @@ aarch64_parse_abi (const char *str)
 }
 
 static struct aarch64_long_option_table aarch64_long_opts[] = {
-#ifdef OBJ_ELF
   {"mabi=", N_("<abi name>\t  specify for ABI <abi name>"),
    aarch64_parse_abi, NULL},
-#endif /* OBJ_ELF */
   {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
    aarch64_parse_cpu, NULL},
   {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
@@ -9593,8 +10813,7 @@ s_aarch64_cpu (int ignored ATTRIBUTE_UNUSED)
   size_t optlen;
 
   name = input_line_pointer;
-  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
-    input_line_pointer++;
+  input_line_pointer = find_end_of_line (input_line_pointer, flag_m68k_mri);
   saved_char = *input_line_pointer;
   *input_line_pointer = 0;
 
@@ -9639,8 +10858,7 @@ s_aarch64_arch (int ignored ATTRIBUTE_UNUSED)
   size_t optlen;
 
   name = input_line_pointer;
-  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
-    input_line_pointer++;
+  input_line_pointer = find_end_of_line (input_line_pointer, flag_m68k_mri);
   saved_char = *input_line_pointer;
   *input_line_pointer = 0;
 
@@ -9679,10 +10897,9 @@ static void
 s_aarch64_arch_extension (int ignored ATTRIBUTE_UNUSED)
 {
   char saved_char;
-  char *ext = input_line_pointer;;
+  char *ext = input_line_pointer;
 
-  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
-    input_line_pointer++;
+  input_line_pointer = find_end_of_line (input_line_pointer, flag_m68k_mri);
   saved_char = *input_line_pointer;
   *input_line_pointer = 0;
 
@@ -9719,17 +10936,17 @@ aarch64_elf_copy_symbol_attributes (symbolS *dest, symbolS *src)
 {
   struct elf_obj_sy *srcelf = symbol_get_obj (src);
   struct elf_obj_sy *destelf = symbol_get_obj (dest);
-  if (srcelf->size)
-    {
-      if (destelf->size == NULL)
-       destelf->size = XNEW (expressionS);
-      *destelf->size = *srcelf->size;
-    }
-  else
+  /* If size is unset, copy size from src.  Because we don't track whether
+     .size has been used, we can't differentiate .size dest, 0 from the case
+     where dest's size is unset.  */
+  if (!destelf->size && S_GET_SIZE (dest) == 0)
     {
-      free (destelf->size);
-      destelf->size = NULL;
+      if (srcelf->size)
+       {
+         destelf->size = XNEW (expressionS);
+         *destelf->size = *srcelf->size;
+       }
+      S_SET_SIZE (dest, S_GET_SIZE (src));
     }
-  S_SET_SIZE (dest, S_GET_SIZE (src));
 }
 #endif