[AArch64][SVE 22/32] Add qualifiers for merging and zeroing predication
[deliverable/binutils-gdb.git] / gas / config / tc-aarch64.c
index eec08c7dd3087e67effa54ecd489d09c52ce1617..f87726244e0e582ebfd5ad53a2a13b45908c3392 100644 (file)
@@ -83,12 +83,15 @@ enum vector_el_type
   NT_h,
   NT_s,
   NT_d,
-  NT_q
+  NT_q,
+  NT_zero,
+  NT_merge
 };
 
 /* Bits for DEFINED field in vector_type_el.  */
-#define NTA_HASTYPE  1
-#define NTA_HASINDEX 2
+#define NTA_HASTYPE     1
+#define NTA_HASINDEX    2
+#define NTA_HASVARWIDTH 4
 
 struct vector_type_el
 {
@@ -265,16 +268,24 @@ struct reloc_entry
   BASIC_REG_TYPE(FP_Q) /* q[0-31] */   \
   BASIC_REG_TYPE(CN)   /* c[0-7]  */   \
   BASIC_REG_TYPE(VN)   /* v[0-31] */   \
-  /* Typecheck: any 64-bit int reg         (inc SP exc XZR) */         \
+  BASIC_REG_TYPE(ZN)   /* z[0-31] */   \
+  BASIC_REG_TYPE(PN)   /* p[0-15] */   \
+  /* Typecheck: any 64-bit int reg         (inc SP exc XZR).  */       \
   MULTI_REG_TYPE(R64_SP, REG_TYPE(R_64) | REG_TYPE(SP_64))             \
-  /* Typecheck: any int                    (inc {W}SP inc [WX]ZR) */   \
+  /* Typecheck: x[0-30], w[0-30] or [xw]zr.  */                                \
+  MULTI_REG_TYPE(R_Z, REG_TYPE(R_32) | REG_TYPE(R_64)                  \
+                | REG_TYPE(Z_32) | REG_TYPE(Z_64))                     \
+  /* Typecheck: x[0-30], w[0-30] or {w}sp.  */                         \
+  MULTI_REG_TYPE(R_SP, REG_TYPE(R_32) | REG_TYPE(R_64)                 \
+                | REG_TYPE(SP_32) | REG_TYPE(SP_64))                   \
+  /* Typecheck: any int                    (inc {W}SP inc [WX]ZR).  */ \
   MULTI_REG_TYPE(R_Z_SP, REG_TYPE(R_32) | REG_TYPE(R_64)               \
                 | REG_TYPE(SP_32) | REG_TYPE(SP_64)                    \
                 | REG_TYPE(Z_32) | REG_TYPE(Z_64))                     \
   /* Typecheck: any [BHSDQ]P FP.  */                                   \
   MULTI_REG_TYPE(BHSDQ, REG_TYPE(FP_B) | REG_TYPE(FP_H)                        \
                 | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q))    \
-  /* Typecheck: any int or [BHSDQ]P FP or V reg (exc SP inc [WX]ZR)  */        \
+  /* Typecheck: any int or [BHSDQ]P FP or V reg (exc SP inc [WX]ZR).  */ \
   MULTI_REG_TYPE(R_Z_BHSDQ_V, REG_TYPE(R_32) | REG_TYPE(R_64)          \
                 | REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN)       \
                 | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
@@ -344,6 +355,15 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
     case REG_TYPE_R_N:
       msg = N_("integer register expected");
       break;
+    case REG_TYPE_R64_SP:
+      msg = N_("64-bit integer or SP register expected");
+      break;
+    case REG_TYPE_R_Z:
+      msg = N_("integer or zero register expected");
+      break;
+    case REG_TYPE_R_SP:
+      msg = N_("integer or SP register expected");
+      break;
     case REG_TYPE_R_Z_SP:
       msg = N_("integer, zero or SP register expected");
       break;
@@ -378,6 +398,12 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
     case REG_TYPE_VN:          /* any V reg  */
       msg = N_("vector register expected");
       break;
+    case REG_TYPE_ZN:
+      msg = N_("SVE vector register expected");
+      break;
+    case REG_TYPE_PN:
+      msg = N_("SVE predicate register expected");
+      break;
     default:
       as_fatal (_("invalid register type %d"), reg_type);
     }
@@ -390,9 +416,6 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
 /* Instructions take 4 bytes in the object file.  */
 #define INSN_SIZE      4
 
-/* Define some common error messages.  */
-#define BAD_SP          _("SP not allowed here")
-
 static struct hash_control *aarch64_ops_hsh;
 static struct hash_control *aarch64_cond_hsh;
 static struct hash_control *aarch64_shift_hsh;
@@ -671,83 +694,57 @@ parse_reg (char **ccp)
 static bfd_boolean
 aarch64_check_reg_type (const reg_entry *reg, aarch64_reg_type type)
 {
-  if (reg->type == type)
-    return TRUE;
-
-  switch (type)
-    {
-    case REG_TYPE_R64_SP:      /* 64-bit integer reg (inc SP exc XZR).  */
-    case REG_TYPE_R_Z_SP:      /* Integer reg (inc {X}SP inc [WX]ZR).  */
-    case REG_TYPE_R_Z_BHSDQ_V: /* Any register apart from Cn.  */
-    case REG_TYPE_BHSDQ:       /* Any [BHSDQ]P FP or SIMD scalar register.  */
-    case REG_TYPE_VN:          /* Vector register.  */
-      gas_assert (reg->type < REG_TYPE_MAX && type < REG_TYPE_MAX);
-      return ((reg_type_masks[reg->type] & reg_type_masks[type])
-             == reg_type_masks[reg->type]);
-    default:
-      as_fatal ("unhandled type %d", type);
-      abort ();
-    }
+  return (reg_type_masks[type] & (1 << reg->type)) != 0;
 }
 
-/* Parse a register and return PARSE_FAIL if the register is not of type R_Z_SP.
-   Return the register number otherwise.  *ISREG32 is set to one if the
-   register is 32-bit wide; *ISREGZERO is set to one if the register is
-   of type Z_32 or Z_64.
+/* Try to parse a base or offset register.  Return the register entry
+   on success, setting *QUALIFIER to the register qualifier.  Return null
+   otherwise.
+
    Note that this function does not issue any diagnostics.  */
 
-static int
-aarch64_reg_parse_32_64 (char **ccp, int reject_sp, int reject_rz,
-                        int *isreg32, int *isregzero)
+static const reg_entry *
+aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
 {
   char *str = *ccp;
   const reg_entry *reg = parse_reg (&str);
 
   if (reg == NULL)
-    return PARSE_FAIL;
-
-  if (! aarch64_check_reg_type (reg, REG_TYPE_R_Z_SP))
-    return PARSE_FAIL;
+    return NULL;
 
   switch (reg->type)
     {
+    case REG_TYPE_R_32:
     case REG_TYPE_SP_32:
-    case REG_TYPE_SP_64:
-      if (reject_sp)
-       return PARSE_FAIL;
-      *isreg32 = reg->type == REG_TYPE_SP_32;
-      *isregzero = 0;
+    case REG_TYPE_Z_32:
+      *qualifier = AARCH64_OPND_QLF_W;
       break;
-    case REG_TYPE_R_32:
+
     case REG_TYPE_R_64:
-      *isreg32 = reg->type == REG_TYPE_R_32;
-      *isregzero = 0;
-      break;
-    case REG_TYPE_Z_32:
+    case REG_TYPE_SP_64:
     case REG_TYPE_Z_64:
-      if (reject_rz)
-       return PARSE_FAIL;
-      *isreg32 = reg->type == REG_TYPE_Z_32;
-      *isregzero = 1;
+      *qualifier = AARCH64_OPND_QLF_X;
       break;
+
     default:
-      return PARSE_FAIL;
+      return NULL;
     }
 
   *ccp = str;
 
-  return reg->number;
+  return reg;
 }
 
-/* Parse the qualifier of a SIMD vector register or a SIMD vector element.
-   Fill in *PARSED_TYPE and return TRUE if the parsing succeeds;
-   otherwise return FALSE.
+/* Parse the qualifier of a vector register or vector element of type
+   REG_TYPE.  Fill in *PARSED_TYPE and return TRUE if the parsing
+   succeeds; otherwise return FALSE.
 
    Accept only one occurrence of:
    8b 16b 2h 4h 8h 2s 4s 1d 2d
    b h s d q  */
 static bfd_boolean
-parse_vector_type_for_operand (struct vector_type_el *parsed_type, char **str)
+parse_vector_type_for_operand (aarch64_reg_type reg_type,
+                              struct vector_type_el *parsed_type, char **str)
 {
   char *ptr = *str;
   unsigned width;
@@ -755,9 +752,10 @@ parse_vector_type_for_operand (struct vector_type_el *parsed_type, char **str)
   enum vector_el_type type;
 
   /* skip '.' */
+  gas_assert (*ptr == '.');
   ptr++;
 
-  if (!ISDIGIT (*ptr))
+  if (reg_type == REG_TYPE_ZN || reg_type == REG_TYPE_PN || !ISDIGIT (*ptr))
     {
       width = 0;
       goto elt_size;
@@ -821,6 +819,38 @@ elt_size:
   return TRUE;
 }
 
+/* *STR contains an SVE zero/merge predication suffix.  Parse it into
+   *PARSED_TYPE and point *STR at the end of the suffix.  */
+
+static bfd_boolean
+parse_predication_for_operand (struct vector_type_el *parsed_type, char **str)
+{
+  char *ptr = *str;
+
+  /* Skip '/'.  */
+  gas_assert (*ptr == '/');
+  ptr++;
+  switch (TOLOWER (*ptr))
+    {
+    case 'z':
+      parsed_type->type = NT_zero;
+      break;
+    case 'm':
+      parsed_type->type = NT_merge;
+      break;
+    default:
+      if (*ptr != '\0' && *ptr != ',')
+       first_error_fmt (_("unexpected character `%c' in predication type"),
+                        *ptr);
+      else
+       first_error (_("missing predication type"));
+      return FALSE;
+    }
+  parsed_type->width = 0;
+  *str = ptr + 1;
+  return TRUE;
+}
+
 /* Parse a register of the type TYPE.
 
    Return PARSE_FAIL if the string pointed by *CCP is not a valid register
@@ -864,15 +894,31 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
     }
   type = reg->type;
 
-  if (type == REG_TYPE_VN && *str == '.')
+  if ((type == REG_TYPE_VN || type == REG_TYPE_ZN || type == REG_TYPE_PN)
+      && (*str == '.' || (type == REG_TYPE_PN && *str == '/')))
     {
-      if (!parse_vector_type_for_operand (&parsetype, &str))
-       return PARSE_FAIL;
+      if (*str == '.')
+       {
+         if (!parse_vector_type_for_operand (type, &parsetype, &str))
+           return PARSE_FAIL;
+       }
+      else
+       {
+         if (!parse_predication_for_operand (&parsetype, &str))
+           return PARSE_FAIL;
+       }
 
       /* Register if of the form Vn.[bhsdq].  */
       is_typed_vecreg = TRUE;
 
-      if (parsetype.width == 0)
+      if (type == REG_TYPE_ZN || type == REG_TYPE_PN)
+       {
+         /* The width is always variable; we don't allow an integer width
+            to be specified.  */
+         gas_assert (parsetype.width == 0);
+         atype.defined |= NTA_HASVARWIDTH | NTA_HASTYPE;
+       }
+      else if (parsetype.width == 0)
        /* Expect index. In the new scheme we cannot have
           Vn.[bhsdq] represent a scalar. Therefore any
           Vn.[bhsdq] should have an index following it.
@@ -1049,7 +1095,7 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
          continue;
        }
       /* reject [bhsd]n */
-      if (typeinfo.defined == 0)
+      if (type == REG_TYPE_VN && typeinfo.defined == 0)
        {
          set_first_syntax_error (_("invalid scalar register in list"));
          error = TRUE;
@@ -2093,56 +2139,52 @@ aarch64_imm_float_p (uint32_t imm)
     && ((imm & 0x7e000000) == pattern);        /* bits 25 - 29 == ~ bit 30.  */
 }
 
-/* Like aarch64_imm_float_p but for a double-precision floating-point value.
-
-   Return TRUE if the value encoded in IMM can be expressed in the AArch64
-   8-bit signed floating-point format with 3-bit exponent and normalized 4
-   bits of precision (i.e. can be used in an FMOV instruction); return the
-   equivalent single-precision encoding in *FPWORD.
-
-   Otherwise return FALSE.  */
+/* Return TRUE if the IEEE double value encoded in IMM can be expressed
+   as an IEEE float without any loss of precision.  Store the value in
+   *FPWORD if so.  */
 
 static bfd_boolean
-aarch64_double_precision_fmovable (uint64_t imm, uint32_t *fpword)
+can_convert_double_to_float (uint64_t imm, uint32_t *fpword)
 {
   /* If a double-precision floating-point value has the following bit
-     pattern, it can be expressed in the AArch64 8-bit floating-point
-     format:
+     pattern, it can be expressed in a float:
 
-     6 66655555555 554444444...21111111111
-     3 21098765432 109876543...098765432109876543210
-     n Eeeeeeeeexx xxxx00000...000000000000000000000
+     6 66655555555 5544 44444444 33333333 33222222 22221111 111111
+     3 21098765432 1098 76543210 98765432 10987654 32109876 54321098 76543210
+     n E~~~eeeeeee ssss ssssssss ssssssss SSS00000 00000000 00000000 00000000
 
-     where n, e and each x are either 0 or 1 independently, with
-     E == ~ e.  */
+       ----------------------------->     nEeeeeee esssssss ssssssss sssssSSS
+        if Eeee_eeee != 1111_1111
+
+     where n, e, s and S are either 0 or 1 independently and where ~ is the
+     inverse of E.  */
 
   uint32_t pattern;
   uint32_t high32 = imm >> 32;
+  uint32_t low32 = imm;
 
-  /* Lower 32 bits need to be 0s.  */
-  if ((imm & 0xffffffff) != 0)
+  /* Lower 29 bits need to be 0s.  */
+  if ((imm & 0x1fffffff) != 0)
     return FALSE;
 
   /* Prepare the pattern for 'Eeeeeeeee'.  */
   if (((high32 >> 30) & 0x1) == 0)
-    pattern = 0x3fc00000;
+    pattern = 0x38000000;
   else
     pattern = 0x40000000;
 
-  if ((high32 & 0xffff) == 0                   /* bits 32 - 47 are 0.  */
-      && (high32 & 0x7fc00000) == pattern)     /* bits 54 - 61 == ~ bit 62.  */
-    {
-      /* Convert to the single-precision encoding.
-         i.e. convert
-          n Eeeeeeeeexx xxxx00000...000000000000000000000
-        to
-          n Eeeeeexx xxxx0000000000000000000.  */
-      *fpword = ((high32 & 0xfe000000)                 /* nEeeeee.  */
-                | (((high32 >> 16) & 0x3f) << 19));    /* xxxxxx.  */
-      return TRUE;
-    }
-  else
+  /* Check E~~~.  */
+  if ((high32 & 0x78000000) != pattern)
     return FALSE;
+
+  /* Check Eeee_eeee != 1111_1111.  */
+  if ((high32 & 0x7ff00000) == 0x47f00000)
+    return FALSE;
+
+  *fpword = ((high32 & 0xc0000000)             /* 1 n bit and 1 E bit.  */
+            | ((high32 << 3) & 0x3ffffff8)     /* 7 e and 20 s bits.  */
+            | (low32 >> 29));                  /* 3 S bits.  */
+  return TRUE;
 }
 
 /* Parse a floating-point immediate.  Return TRUE on success and return the
@@ -2152,7 +2194,8 @@ aarch64_double_precision_fmovable (uint64_t imm, uint32_t *fpword)
    hexadecimal representation is involved).  REG_TYPE says which register
    names should be treated as registers rather than as symbolic immediates.
 
-   N.B. 0.0 is accepted by this function.  */
+   This routine accepts any IEEE float; it is up to the callers to reject
+   invalid ones.  */
 
 static bfd_boolean
 parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
@@ -2181,7 +2224,7 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
 
       if (dp_p)
        {
-         if (! aarch64_double_precision_fmovable (val, &fpword))
+         if (!can_convert_double_to_float (val, &fpword))
            goto invalid_fp;
        }
       else if ((uint64_t) val > 0xffffffff)
@@ -2193,6 +2236,12 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
     }
   else
     {
+      if (reg_name_p (str, reg_type))
+       {
+         set_recoverable_error (_("immediate operand required"));
+         return FALSE;
+       }
+
       /* We must not accidentally parse an integer as a floating-point number.
         Make sure that the value we parse is not an integer by checking for
         special characters '.' or 'e'.  */
@@ -2222,12 +2271,9 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
        }
     }
 
-  if (aarch64_imm_float_p (fpword) || fpword == 0)
-    {
-      *immed = fpword;
-      *ccp = str;
-      return TRUE;
-    }
+  *immed = fpword;
+  *ccp = str;
+  return TRUE;
 
 invalid_fp:
   set_fatal_syntax_error (_("invalid floating-point constant"));
@@ -3032,13 +3078,13 @@ static bfd_boolean
 parse_shifter_operand (char **str, aarch64_opnd_info *operand,
                       enum parse_shift_mode mode)
 {
-  int reg;
-  int isreg32, isregzero;
+  const reg_entry *reg;
+  aarch64_opnd_qualifier_t qualifier;
   enum aarch64_operand_class opd_class
     = aarch64_get_operand_class (operand->type);
 
-  if ((reg =
-       aarch64_reg_parse_32_64 (str, 0, 0, &isreg32, &isregzero)) != PARSE_FAIL)
+  reg = aarch64_reg_parse_32_64 (str, &qualifier);
+  if (reg)
     {
       if (opd_class == AARCH64_OPND_CLASS_IMMEDIATE)
        {
@@ -3046,14 +3092,14 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand,
          return FALSE;
        }
 
-      if (!isregzero && reg == REG_SP)
+      if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
        {
-         set_syntax_error (BAD_SP);
+         set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
          return FALSE;
        }
 
-      operand->reg.regno = reg;
-      operand->qualifier = isreg32 ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X;
+      operand->reg.regno = reg->number;
+      operand->qualifier = qualifier;
 
       /* Accept optional shift operation on register.  */
       if (! skip_past_comma (str))
@@ -3188,12 +3234,12 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
    supported by the instruction, and to set inst.reloc.type.  */
 
 static bfd_boolean
-parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
-                   int accept_reg_post_index)
+parse_address_main (char **str, aarch64_opnd_info *operand)
 {
   char *p = *str;
-  int reg;
-  int isreg32, isregzero;
+  const reg_entry *reg;
+  aarch64_opnd_qualifier_t base_qualifier;
+  aarch64_opnd_qualifier_t offset_qualifier;
   expressionS *exp = &inst.reloc.exp;
 
   if (! skip_past_char (&p, '['))
@@ -3204,7 +3250,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
 
       /* #:<reloc_op>:<symbol>  */
       skip_past_char (&p, '#');
-      if (reloc && skip_past_char (&p, ':'))
+      if (skip_past_char (&p, ':'))
        {
          bfd_reloc_code_real_type ty;
          struct reloc_table_entry *entry;
@@ -3270,14 +3316,13 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
 
   /* [ */
 
-  /* Accept SP and reject ZR */
-  reg = aarch64_reg_parse_32_64 (&p, 0, 1, &isreg32, &isregzero);
-  if (reg == PARSE_FAIL || isreg32)
+  reg = aarch64_reg_parse_32_64 (&p, &base_qualifier);
+  if (!reg || !aarch64_check_reg_type (reg, REG_TYPE_R64_SP))
     {
-      set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_64)));
+      set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R64_SP)));
       return FALSE;
     }
-  operand->addr.base_regno = reg;
+  operand->addr.base_regno = reg->number;
 
   /* [Xn */
   if (skip_past_comma (&p))
@@ -3285,12 +3330,17 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
       /* [Xn, */
       operand->addr.preind = 1;
 
-      /* Reject SP and accept ZR */
-      reg = aarch64_reg_parse_32_64 (&p, 1, 0, &isreg32, &isregzero);
-      if (reg != PARSE_FAIL)
+      reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+      if (reg)
        {
+         if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
+           {
+             set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
+             return FALSE;
+           }
+
          /* [Xn,Rm  */
-         operand->addr.offset.regno = reg;
+         operand->addr.offset.regno = reg->number;
          operand->addr.offset.is_reg = 1;
          /* Shifted index.  */
          if (skip_past_comma (&p))
@@ -3309,13 +3359,13 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
              || operand->shifter.kind == AARCH64_MOD_LSL
              || operand->shifter.kind == AARCH64_MOD_SXTX)
            {
-             if (isreg32)
+             if (offset_qualifier == AARCH64_OPND_QLF_W)
                {
                  set_syntax_error (_("invalid use of 32-bit register offset"));
                  return FALSE;
                }
            }
-         else if (!isreg32)
+         else if (offset_qualifier == AARCH64_OPND_QLF_X)
            {
              set_syntax_error (_("invalid use of 64-bit register offset"));
              return FALSE;
@@ -3325,7 +3375,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
        {
          /* [Xn,#:<reloc_op>:<symbol>  */
          skip_past_char (&p, '#');
-         if (reloc && skip_past_char (&p, ':'))
+         if (skip_past_char (&p, ':'))
            {
              struct reloc_table_entry *entry;
 
@@ -3398,17 +3448,17 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
          return FALSE;
        }
 
-      if (accept_reg_post_index
-         && (reg = aarch64_reg_parse_32_64 (&p, 1, 1, &isreg32,
-                                            &isregzero)) != PARSE_FAIL)
+      reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+      if (reg)
        {
          /* [Xn],Xm */
-         if (isreg32)
+         if (!aarch64_check_reg_type (reg, REG_TYPE_R_64))
            {
-             set_syntax_error (_("invalid 32-bit register offset"));
+             set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_64)));
              return FALSE;
            }
-         operand->addr.offset.regno = reg;
+
+         operand->addr.offset.regno = reg->number;
          operand->addr.offset.is_reg = 1;
        }
       else if (! my_get_expression (exp, &p, GE_OPT_PREFIX, 1))
@@ -3438,19 +3488,12 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
   return TRUE;
 }
 
-/* Return TRUE on success; otherwise return FALSE.  */
-static bfd_boolean
-parse_address (char **str, aarch64_opnd_info *operand,
-              int accept_reg_post_index)
-{
-  return parse_address_main (str, operand, 0, accept_reg_post_index);
-}
-
-/* Return TRUE on success; otherwise return FALSE.  */
+/* Parse a base AArch64 address (as opposed to an SVE one).  Return TRUE
+   on success.  */
 static bfd_boolean
-parse_address_reloc (char **str, aarch64_opnd_info *operand)
+parse_address (char **str, aarch64_opnd_info *operand)
 {
-  return parse_address_main (str, operand, 1, 0);
+  return parse_address_main (str, operand);
 }
 
 /* Parse an operand for a MOVZ, MOVN or MOVK instruction.
@@ -3723,19 +3766,15 @@ parse_sys_ins_reg (char **str, struct hash_control *sys_ins_regs)
       }                                                                \
   } while (0)
 
-#define po_int_reg_or_fail(reject_sp, reject_rz) do {          \
-    val = aarch64_reg_parse_32_64 (&str, reject_sp, reject_rz, \
-                                   &isreg32, &isregzero);      \
-    if (val == PARSE_FAIL)                                     \
+#define po_int_reg_or_fail(reg_type) do {                      \
+    reg = aarch64_reg_parse_32_64 (&str, &qualifier);          \
+    if (!reg || !aarch64_check_reg_type (reg, reg_type))       \
       {                                                                \
        set_default_error ();                                   \
        goto failure;                                           \
       }                                                                \
-    info->reg.regno = val;                                     \
-    if (isreg32)                                               \
-      info->qualifier = AARCH64_OPND_QLF_W;                    \
-    else                                                       \
-      info->qualifier = AARCH64_OPND_QLF_X;                    \
+    info->reg.regno = reg->number;                             \
+    info->qualifier = qualifier;                               \
   } while (0)
 
 #define po_imm_nc_or_fail() do {                               \
@@ -4156,7 +4195,7 @@ find_best_match (const aarch64_inst *instr,
     }
 
   max_num_matched = 0;
-  idx = -1;
+  idx = 0;
 
   /* For each pattern.  */
   for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i, ++qualifiers_list)
@@ -4168,9 +4207,6 @@ find_best_match (const aarch64_inst *instr,
       if (empty_qualifier_sequence_p (qualifiers) == TRUE)
        {
          DEBUG_TRACE_IF (i == 0, "empty list of qualifier sequence");
-         if (i != 0 && idx == -1)
-           /* If nothing has been matched, return the 1st sequence.  */
-           idx = 0;
          break;
        }
 
@@ -4396,6 +4432,11 @@ output_operand_error_record (const operand_error_record *record, char *str)
        }
       break;
 
+    case AARCH64_OPDE_UNTIED_OPERAND:
+      as_bad (_("operand %d must be the same register as operand 1 -- `%s'"),
+             detail->index + 1, str);
+      break;
+
     case AARCH64_OPDE_OUT_OF_RANGE:
       if (detail->data[0] != detail->data[1])
        as_bad (_("%s out of range %d to %d at operand %d -- `%s'"),
@@ -4657,9 +4698,14 @@ vectype_to_qualifier (const struct vector_type_el *vectype)
   if (!vectype->defined || vectype->type == NT_invtype)
     goto vectype_conversion_fail;
 
+  if (vectype->type == NT_zero)
+    return AARCH64_OPND_QLF_P_Z;
+  if (vectype->type == NT_merge)
+    return AARCH64_OPND_QLF_P_M;
+
   gas_assert (vectype->type >= NT_b && vectype->type <= NT_q);
 
-  if (vectype->defined & NTA_HASINDEX)
+  if (vectype->defined & (NTA_HASINDEX | NTA_HASVARWIDTH))
     /* Vector element register.  */
     return AARCH64_OPND_QLF_S_B + vectype->type;
   else
@@ -4993,11 +5039,13 @@ parse_operands (char *str, const aarch64_opcode *opcode)
   for (i = 0; operands[i] != AARCH64_OPND_NIL; i++)
     {
       int64_t val;
-      int isreg32, isregzero;
+      const reg_entry *reg;
       int comma_skipped_p = 0;
       aarch64_reg_type rtype;
       struct vector_type_el vectype;
+      aarch64_opnd_qualifier_t qualifier;
       aarch64_opnd_info *info = &inst.base.operands[i];
+      aarch64_reg_type reg_type;
 
       DEBUG_TRACE ("parse operand %d", i);
 
@@ -5032,12 +5080,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Ra:
        case AARCH64_OPND_Rt_SYS:
        case AARCH64_OPND_PAIRREG:
-         po_int_reg_or_fail (1, 0);
+         po_int_reg_or_fail (REG_TYPE_R_Z);
          break;
 
        case AARCH64_OPND_Rd_SP:
        case AARCH64_OPND_Rn_SP:
-         po_int_reg_or_fail (0, 1);
+         po_int_reg_or_fail (REG_TYPE_R_SP);
          break;
 
        case AARCH64_OPND_Rm_EXT:
@@ -5080,22 +5128,54 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->qualifier = AARCH64_OPND_QLF_S_B + (rtype - REG_TYPE_FP_B);
          break;
 
+       case AARCH64_OPND_SVE_Pd:
+       case AARCH64_OPND_SVE_Pg3:
+       case AARCH64_OPND_SVE_Pg4_5:
+       case AARCH64_OPND_SVE_Pg4_10:
+       case AARCH64_OPND_SVE_Pg4_16:
+       case AARCH64_OPND_SVE_Pm:
+       case AARCH64_OPND_SVE_Pn:
+       case AARCH64_OPND_SVE_Pt:
+         reg_type = REG_TYPE_PN;
+         goto vector_reg;
+
+       case AARCH64_OPND_SVE_Za_5:
+       case AARCH64_OPND_SVE_Za_16:
+       case AARCH64_OPND_SVE_Zd:
+       case AARCH64_OPND_SVE_Zm_5:
+       case AARCH64_OPND_SVE_Zm_16:
+       case AARCH64_OPND_SVE_Zn:
+       case AARCH64_OPND_SVE_Zt:
+         reg_type = REG_TYPE_ZN;
+         goto vector_reg;
+
        case AARCH64_OPND_Vd:
        case AARCH64_OPND_Vn:
        case AARCH64_OPND_Vm:
-         val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
+         reg_type = REG_TYPE_VN;
+       vector_reg:
+         val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
          if (val == PARSE_FAIL)
            {
-             first_error (_(get_reg_expected_msg (REG_TYPE_VN)));
+             first_error (_(get_reg_expected_msg (reg_type)));
              goto failure;
            }
          if (vectype.defined & NTA_HASINDEX)
            goto failure;
 
          info->reg.regno = val;
-         info->qualifier = vectype_to_qualifier (&vectype);
-         if (info->qualifier == AARCH64_OPND_QLF_NIL)
-           goto failure;
+         if ((reg_type == REG_TYPE_PN || reg_type == REG_TYPE_ZN)
+             && vectype.type == NT_invtype)
+           /* Unqualified Pn and Zn registers are allowed in certain
+              contexts.  Rely on F_STRICT qualifier checking to catch
+              invalid uses.  */
+           info->qualifier = AARCH64_OPND_QLF_NIL;
+         else
+           {
+             info->qualifier = vectype_to_qualifier (&vectype);
+             if (info->qualifier == AARCH64_OPND_QLF_NIL)
+               goto failure;
+           }
          break;
 
        case AARCH64_OPND_VdD1:
@@ -5120,13 +5200,19 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->qualifier = AARCH64_OPND_QLF_S_D;
          break;
 
+       case AARCH64_OPND_SVE_Zn_INDEX:
+         reg_type = REG_TYPE_ZN;
+         goto vector_reg_index;
+
        case AARCH64_OPND_Ed:
        case AARCH64_OPND_En:
        case AARCH64_OPND_Em:
-         val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
+         reg_type = REG_TYPE_VN;
+       vector_reg_index:
+         val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
          if (val == PARSE_FAIL)
            {
-             first_error (_(get_reg_expected_msg (REG_TYPE_VN)));
+             first_error (_(get_reg_expected_msg (reg_type)));
              goto failure;
            }
          if (vectype.type == NT_invtype || !(vectype.defined & NTA_HASINDEX))
@@ -5139,20 +5225,43 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            goto failure;
          break;
 
+       case AARCH64_OPND_SVE_ZnxN:
+       case AARCH64_OPND_SVE_ZtxN:
+         reg_type = REG_TYPE_ZN;
+         goto vector_reg_list;
+
        case AARCH64_OPND_LVn:
        case AARCH64_OPND_LVt:
        case AARCH64_OPND_LVt_AL:
        case AARCH64_OPND_LEt:
-         if ((val = parse_vector_reg_list (&str, REG_TYPE_VN,
-                                           &vectype)) == PARSE_FAIL)
-           goto failure;
-         if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+         reg_type = REG_TYPE_VN;
+       vector_reg_list:
+         if (reg_type == REG_TYPE_ZN
+             && get_opcode_dependent_value (opcode) == 1
+             && *str != '{')
            {
-             set_fatal_syntax_error (_("invalid register list"));
-             goto failure;
+             val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
+             if (val == PARSE_FAIL)
+               {
+                 first_error (_(get_reg_expected_msg (reg_type)));
+                 goto failure;
+               }
+             info->reglist.first_regno = val;
+             info->reglist.num_regs = 1;
+           }
+         else
+           {
+             val = parse_vector_reg_list (&str, reg_type, &vectype);
+             if (val == PARSE_FAIL)
+               goto failure;
+             if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+               {
+                 set_fatal_syntax_error (_("invalid register list"));
+                 goto failure;
+               }
+             info->reglist.first_regno = (val >> 2) & 0x1f;
+             info->reglist.num_regs = (val & 0x3) + 1;
            }
-         info->reglist.first_regno = (val >> 2) & 0x1f;
-         info->reglist.num_regs = (val & 0x3) + 1;
          if (operands[i] == AARCH64_OPND_LEt)
            {
              if (!(vectype.defined & NTA_HASINDEX))
@@ -5160,8 +5269,17 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              info->reglist.has_index = 1;
              info->reglist.index = vectype.index;
            }
-         else if (!(vectype.defined & NTA_HASTYPE))
-           goto failure;
+         else
+           {
+             if (vectype.defined & NTA_HASINDEX)
+               goto failure;
+             if (!(vectype.defined & NTA_HASTYPE))
+               {
+                 if (reg_type == REG_TYPE_ZN)
+                   set_fatal_syntax_error (_("missing type suffix"));
+                 goto failure;
+               }
+           }
          info->qualifier = vectype_to_qualifier (&vectype);
          if (info->qualifier == AARCH64_OPND_QLF_NIL)
            goto failure;
@@ -5227,8 +5345,9 @@ parse_operands (char *str, const aarch64_opcode *opcode)
               it is probably not worth the effort to support it.  */
            if (!(res1 = parse_aarch64_imm_float (&str, &qfloat, FALSE,
                                                  imm_reg_type))
-               && !(res2 = parse_constant_immediate (&str, &val,
-                                                     imm_reg_type)))
+               && (error_p ()
+                   || !(res2 = parse_constant_immediate (&str, &val,
+                                                         imm_reg_type))))
              goto failure;
            if ((res1 && qfloat == 0) || (res2 && val == 0))
              {
@@ -5292,11 +5411,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            bfd_boolean dp_p
              = (aarch64_get_qualifier_esize (inst.base.operands[0].qualifier)
                 == 8);
-           if (! parse_aarch64_imm_float (&str, &qfloat, dp_p, imm_reg_type))
-             goto failure;
-           if (qfloat == 0)
+           if (!parse_aarch64_imm_float (&str, &qfloat, dp_p, imm_reg_type)
+               || !aarch64_imm_float_p (qfloat))
              {
-               set_fatal_syntax_error (_("invalid floating-point constant"));
+               if (!error_p ())
+                 set_fatal_syntax_error (_("invalid floating-point"
+                                           " constant"));
                goto failure;
              }
            inst.base.operands[i].imm.value = encode_imm_float_bits (qfloat);
@@ -5430,7 +5550,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_ADDR_PCREL19:
        case AARCH64_OPND_ADDR_PCREL21:
        case AARCH64_OPND_ADDR_PCREL26:
-         po_misc_or_fail (parse_address_reloc (&str, info));
+         po_misc_or_fail (parse_address (&str, info));
          if (!info->addr.pcrel)
            {
              set_syntax_error (_("invalid pc-relative address"));
@@ -5496,28 +5616,43 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_ADDR_SIMPLE:
        case AARCH64_OPND_SIMD_ADDR_SIMPLE:
-         /* [<Xn|SP>{, #<simm>}]  */
-         po_char_or_fail ('[');
-         po_reg_or_fail (REG_TYPE_R64_SP);
-         /* Accept optional ", #0".  */
-         if (operands[i] == AARCH64_OPND_ADDR_SIMPLE
-             && skip_past_char (&str, ','))
-           {
-             skip_past_char (&str, '#');
-             if (! skip_past_char (&str, '0'))
-               {
-                 set_fatal_syntax_error
-                   (_("the optional immediate offset can only be 0"));
-                 goto failure;
-               }
-           }
-         po_char_or_fail (']');
-         info->addr.base_regno = val;
-         break;
+         {
+           /* [<Xn|SP>{, #<simm>}]  */
+           char *start = str;
+           /* First use the normal address-parsing routines, to get
+              the usual syntax errors.  */
+           po_misc_or_fail (parse_address (&str, info));
+           if (info->addr.pcrel || info->addr.offset.is_reg
+               || !info->addr.preind || info->addr.postind
+               || info->addr.writeback)
+             {
+               set_syntax_error (_("invalid addressing mode"));
+               goto failure;
+             }
+
+           /* Then retry, matching the specific syntax of these addresses.  */
+           str = start;
+           po_char_or_fail ('[');
+           po_reg_or_fail (REG_TYPE_R64_SP);
+           /* Accept optional ", #0".  */
+           if (operands[i] == AARCH64_OPND_ADDR_SIMPLE
+               && skip_past_char (&str, ','))
+             {
+               skip_past_char (&str, '#');
+               if (! skip_past_char (&str, '0'))
+                 {
+                   set_fatal_syntax_error
+                     (_("the optional immediate offset can only be 0"));
+                   goto failure;
+                 }
+             }
+           po_char_or_fail (']');
+           break;
+         }
 
        case AARCH64_OPND_ADDR_REGOFF:
          /* [<Xn|SP>, <R><m>{, <extend> {<amount>}}]  */
-         po_misc_or_fail (parse_address (&str, info, 0));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || !info->addr.offset.is_reg
              || !info->addr.preind || info->addr.postind
              || info->addr.writeback)
@@ -5536,13 +5671,18 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_ADDR_SIMM7:
-         po_misc_or_fail (parse_address (&str, info, 0));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || (!info->addr.preind && !info->addr.postind))
            {
              set_syntax_error (_("invalid addressing mode"));
              goto failure;
            }
+         if (inst.reloc.type != BFD_RELOC_UNUSED)
+           {
+             set_syntax_error (_("relocation not allowed"));
+             goto failure;
+           }
          assign_imm_if_const_or_fixup_later (&inst.reloc, info,
                                              /* addr_off_p */ 1,
                                              /* need_libopcodes_p */ 1,
@@ -5551,7 +5691,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_ADDR_SIMM9:
        case AARCH64_OPND_ADDR_SIMM9_2:
-         po_misc_or_fail (parse_address_reloc (&str, info));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || (!info->addr.preind && !info->addr.postind)
              || (operands[i] == AARCH64_OPND_ADDR_SIMM9_2
@@ -5572,7 +5712,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_ADDR_UIMM12:
-         po_misc_or_fail (parse_address_reloc (&str, info));
+         po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || !info->addr.preind || info->addr.writeback)
            {
@@ -5592,7 +5732,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_SIMD_ADDR_POST:
          /* [<Xn|SP>], <Xm|#<amount>>  */
-         po_misc_or_fail (parse_address (&str, info, 1));
+         po_misc_or_fail (parse_address (&str, info));
          if (!info->addr.postind || !info->addr.writeback)
            {
              set_syntax_error (_("invalid addressing mode"));
@@ -6154,11 +6294,13 @@ aarch64_canonicalize_symbol_name (char *name)
 
 #define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE }
 #define REGNUM(p,n,t) REGDEF(p##n, n, t)
-#define REGSET31(p,t) \
+#define REGSET16(p,t) \
   REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
   REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
   REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
-  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t), \
+  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
+#define REGSET31(p,t) \
+  REGSET16(p, t), \
   REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
   REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
   REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
@@ -6198,10 +6340,18 @@ static const reg_entry reg_names[] = {
 
   /* FP/SIMD registers.  */
   REGSET (v, VN), REGSET (V, VN),
+
+  /* SVE vector registers.  */
+  REGSET (z, ZN), REGSET (Z, ZN),
+
+  /* SVE predicate registers.  */
+  REGSET16 (p, PN), REGSET16 (P, PN)
 };
 
 #undef REGDEF
 #undef REGNUM
+#undef REGSET16
+#undef REGSET31
 #undef REGSET
 
 #define N 1
This page took 0.037894 seconds and 4 git commands to generate.