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
{
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) \
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;
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);
}
/* 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;
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;
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;
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
}
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.
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;
&& ((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
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,
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)
}
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'. */
}
}
- 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"));
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)
{
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))
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, '['))
/* #:<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;
/* [ */
- /* 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))
/* [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))
|| 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;
{
/* [Xn,#:<reloc_op>:<symbol> */
skip_past_char (&p, '#');
- if (reloc && skip_past_char (&p, ':'))
+ if (skip_past_char (&p, ':'))
{
struct reloc_table_entry *entry;
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))
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.
} \
} 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 { \
}
max_num_matched = 0;
- idx = -1;
+ idx = 0;
/* For each pattern. */
for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i, ++qualifiers_list)
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;
}
}
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'"),
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
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);
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:
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:
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))
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))
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;
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))
{
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);
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"));
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)
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,
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
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)
{
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"));
#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), \
/* 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