]> 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 b4e0b937605f5a57eaca860deb253b72bfe0f1b8..19fbc7c46466ab30725e9ae16ae576aea4de5d6d 100644 (file)
@@ -307,10 +307,12 @@ struct reloc_entry
   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.  */                          \
@@ -347,6 +349,13 @@ struct reloc_entry
                 | 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))                           \
+  /* 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)                    \
@@ -440,6 +449,16 @@ get_reg_expected_msg (unsigned int mask, unsigned int seen)
                  | 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");
@@ -456,8 +475,15 @@ get_reg_expected_msg (unsigned int mask, unsigned int seen)
     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])
+  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])
@@ -465,11 +491,11 @@ get_reg_expected_msg (unsigned int mask, unsigned int seen)
   if (mask == reg_type_masks[REG_TYPE_VZP])
     return N_("expected a vector or predicate register at operand %d");
 
-  /* ZA-related registers.  */
+  /* 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])
-    return N_("expected 'za' or a ZA tile 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])
@@ -1127,6 +1153,7 @@ aarch64_valid_suffix_char_p (aarch64_reg_type type, char ch)
       return ch == '.';
 
     case REG_TYPE_P:
+    case REG_TYPE_PN:
       return ch == '.' || ch == '/';
 
     default:
@@ -1260,7 +1287,10 @@ parse_typed_reg (char **ccp, aarch64_reg_type type,
   if (!(flags & PTR_FULL_REG) && skip_past_char (&str, '['))
     {
       /* 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 NULL;
@@ -1327,6 +1357,14 @@ eq_vector_type_el (struct vector_type_el e1, struct vector_type_el e2)
          && 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.
    On success, it returns the parsed register list information in the
    following encoded format:
@@ -1355,7 +1393,7 @@ 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;
   bool error = false;
@@ -1376,9 +1414,10 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
   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)
@@ -1414,7 +1453,7 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
                (_("invalid range in vector register list"));
              error = true;
            }
-         val_range = (val_range + 1) & 0x1f;
+         val_range = (val_range + 1) & mask;
        }
       else
        {
@@ -1431,11 +1470,11 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
       if (! error)
        for (;;)
          {
-           ret_val |= val_range << (5 * nb_regs);
+           ret_val |= val_range << ((5 * nb_regs) & 31);
            nb_regs++;
            if (val_range == val)
              break;
-           val_range = (val_range + 1) & 0x1f;
+           val_range = (val_range + 1) & mask;
          }
       in_range = 0;
       ptr_flags |= PTR_GOOD_MATCH;
@@ -4299,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.  */
@@ -4328,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;
 
@@ -4550,6 +4594,49 @@ parse_sme_za_index (char **str, struct aarch64_indexed_za *opnd)
       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 ']'"));
@@ -4911,6 +4998,12 @@ 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;                                            \
@@ -5067,6 +5160,7 @@ const char* operand_mismatch_kind_names[] =
   "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",
@@ -5095,7 +5189,8 @@ operand_error_higher_severity_p (enum aarch64_operand_error_kind lhs,
   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_REG_LIST_LENGTH > 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);
@@ -5749,6 +5844,15 @@ output_operand_error_record (const operand_error_record *record, char *str)
                 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_LENGTH:
       if (detail->data[0].i == (1 << 1))
        handler (_("expected a single-register list at operand %d -- `%s'"),
@@ -5756,6 +5860,10 @@ output_operand_error_record (const operand_error_record *record, char *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);
@@ -5765,6 +5873,10 @@ output_operand_error_record (const operand_error_record *record, char *str)
       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 register stride at operand %d -- `%s'"),
                 idx + 1, str);
@@ -6366,16 +6478,18 @@ 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).  They must also have a
-   consistent stride.
+/* 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.
 
    Return true if the list is valid, describing it in LIST if so.  */
 
 static bool
-reg_list_valid_p (uint32_t reginfo, struct aarch64_reglist *list)
+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;
@@ -6390,7 +6504,7 @@ reg_list_valid_p (uint32_t reginfo, struct aarch64_reglist *list)
       uint32_t curr_regno, curr_incr;
       reginfo >>= 5;
       curr_regno = reginfo & 0x1f;
-      curr_incr = (curr_regno - prev_regno) & 0x1f;
+      curr_incr = (curr_regno - prev_regno) & mask;
       if (curr_incr == 0)
        return false;
       else if (i == 1)
@@ -6420,9 +6534,11 @@ parse_operands (char *str, const aarch64_opcode *opcode)
   clear_error ();
   skip_whitespace (str);
 
-  if (AARCH64_CPU_HAS_ANY_FEATURES (*opcode->avariant,
-                                   AARCH64_FEATURE_SVE
-                                   | AARCH64_FEATURE_SVE2))
+  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_ZR_BHSDQ_V;
@@ -6552,9 +6668,20 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_Zm_16:
        case AARCH64_OPND_SVE_Zn:
        case AARCH64_OPND_SVE_Zt:
+       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:
@@ -6568,7 +6695,9 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            goto failure;
 
          info->reg.regno = reg->number;
-         if ((reg_type == REG_TYPE_P || reg_type == REG_TYPE_Z)
+         if ((reg_type == REG_TYPE_P
+              || reg_type == REG_TYPE_PN
+              || reg_type == REG_TYPE_Z)
              && vectype.type == NT_invtype)
            /* Unqualified P and Z registers are allowed in certain
               contexts.  Rely on F_STRICT qualifier checking to catch
@@ -6603,10 +6732,24 @@ 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:
+       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;
 
@@ -6620,21 +6763,43 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          reg = aarch64_reg_parse (&str, reg_type, &vectype);
          if (!reg)
            goto failure;
-         if (vectype.type == NT_invtype || !(vectype.defined & NTA_HASINDEX))
+         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
+           {
+             if (vectype.type == NT_invtype)
+               goto failure;
+             info->qualifier = vectype_to_qualifier (&vectype);
+             if (info->qualifier == AARCH64_OPND_QLF_NIL)
+               goto failure;
+           }
+
          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:
+       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:
@@ -6658,13 +6823,13 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              if (val == PARSE_FAIL)
                goto failure;
 
-             if (! reg_list_valid_p (val, &info->reglist))
+             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"));
@@ -6684,7 +6849,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
                goto failure;
              if (!(vectype.defined & NTA_HASTYPE))
                {
-                 if (reg_type == REG_TYPE_Z)
+                 if (reg_type == REG_TYPE_Z || reg_type == REG_TYPE_P)
                    set_fatal_syntax_error (_("missing type suffix"));
                  goto failure;
                }
@@ -6737,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:
@@ -7606,12 +7773,68 @@ 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)
@@ -7628,7 +7851,9 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          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,
@@ -7647,6 +7872,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          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))
@@ -7654,6 +7885,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          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 ('[');
@@ -8289,9 +8526,12 @@ static const reg_entry reg_names[] = {
   /* SVE vector registers.  */
   REGSET (z, Z), REGSET (Z, Z),
 
-  /* SVE predicate registers.  */
+  /* 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),
@@ -8303,7 +8543,10 @@ static const reg_entry reg_names[] = {
   REGSET16S (za, h, ZATH), REGSET16S (ZA, H, ZATH),
 
   /* SME ZA tile registers (vertical slice).  */
-  REGSET16S (za, v, ZATV), REGSET16S (ZA, V, ZATV)
+  REGSET16S (za, v, ZATV), REGSET16S (ZA, V, ZATV),
+
+  /* SME2 ZT0.  */
+  REGDEF (zt0, 0, ZT0), REGDEF (ZT0, 0, ZT0)
 };
 
 #undef REGDEF
@@ -9984,12 +10227,21 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = {
                   | 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