aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:55:49 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:55:49 +0100
commit4df068de5214ff55b01ae320ec580f2928eb74e5 (patch)
tree8ca6efd2456f0f920e8cd9ac5bb5dcb9614a84e0 /gas
parent2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e (diff)
downloadgdb-4df068de5214ff55b01ae320ec580f2928eb74e5.zip
gdb-4df068de5214ff55b01ae320ec580f2928eb74e5.tar.gz
gdb-4df068de5214ff55b01ae320ec580f2928eb74e5.tar.bz2
[AArch64][SVE 25/32] Add support for SVE addressing modes
This patch adds most of the new SVE addressing modes and associated operands. A follow-on patch adds MUL VL, since handling it separately makes the changes easier to read. The patch also introduces a new "operand-dependent data" field to the operand flags, based closely on the existing one for opcode flags. For SVE this new field needs only 2 bits, but it could be widened in future if necessary. include/ * opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd. (AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4) (AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR) (AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2) (AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX) (AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2) (AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ) (AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2) (AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14) (AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14) (AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14) (AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14) (AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5) (AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4) (AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL) (AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW): Likewise. opcodes/ * aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE address operands. * aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14) (FLD_SVE_xs_22): New aarch64_field_kinds. (OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags. (get_operand_specific_data): New function. * aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14 and FLD_SVE_xs_22. (operand_general_constraint_met_p): Handle the new SVE address operands. (sve_reg): New array. (get_addr_sve_reg_name): New function. (aarch64_print_operand): Handle the new SVE address operands. * aarch64-opc-2.c: Regenerate. * aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl) (ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl) (ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters. * aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function. (aarch64_ins_sve_addr_rr_lsl): Likewise. (aarch64_ins_sve_addr_rz_xtw): Likewise. (aarch64_ins_sve_addr_zi_u5): Likewise. (aarch64_ins_sve_addr_zz): Likewise. (aarch64_ins_sve_addr_zz_lsl): Likewise. (aarch64_ins_sve_addr_zz_sxtw): Likewise. (aarch64_ins_sve_addr_zz_uxtw): Likewise. * aarch64-asm-2.c: Regenerate. * aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl) (ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl) (ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors. * aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function. (aarch64_ext_sve_addr_ri_u6): Likewise. (aarch64_ext_sve_addr_rr_lsl): Likewise. (aarch64_ext_sve_addr_rz_xtw): Likewise. (aarch64_ext_sve_addr_zi_u5): Likewise. (aarch64_ext_sve_addr_zz): Likewise. (aarch64_ext_sve_addr_zz_lsl): Likewise. (aarch64_ext_sve_addr_zz_sxtw): Likewise. (aarch64_ext_sve_addr_zz_uxtw): Likewise. * aarch64-dis-2.c: Regenerate. gas/ * config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New register types. (get_reg_expected_msg): Handle them. (aarch64_addr_reg_parse): New function, split out from aarch64_reg_parse_32_64. Handle Z registers too. (aarch64_reg_parse_32_64): Call it. (parse_address_main): Add base_qualifier, offset_qualifier, base_type and offset_type parameters. Handle SVE base and offset registers. (parse_address): Update call to parse_address_main. (parse_sve_address): New function. (parse_operands): Parse the new SVE address operands.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog15
-rw-r--r--gas/config/tc-aarch64.c245
2 files changed, 237 insertions, 23 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 97f1a61..c1f4152 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,20 @@
2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+ * config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
+ register types.
+ (get_reg_expected_msg): Handle them.
+ (aarch64_addr_reg_parse): New function, split out from
+ aarch64_reg_parse_32_64. Handle Z registers too.
+ (aarch64_reg_parse_32_64): Call it.
+ (parse_address_main): Add base_qualifier, offset_qualifier,
+ base_type and offset_type parameters. Handle SVE base and offset
+ registers.
+ (parse_address): Update call to parse_address_main.
+ (parse_sve_address): New function.
+ (parse_operands): Parse the new SVE address operands.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* config/tc-aarch64.c (SHIFTED_MUL): New parse_shift_mode.
(parse_shift): Handle it. Reject AARCH64_MOD_MUL for all other
shift modes. Skip range tests for AARCH64_MOD_MUL.
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 79ee054..e59333f 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -272,9 +272,16 @@ struct reloc_entry
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: same, plus SVE registers. */ \
+ MULTI_REG_TYPE(SVE_BASE, REG_TYPE(R_64) | REG_TYPE(SP_64) \
+ | REG_TYPE(ZN)) \
/* 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: same, plus SVE registers. */ \
+ MULTI_REG_TYPE(SVE_OFFSET, REG_TYPE(R_32) | REG_TYPE(R_64) \
+ | REG_TYPE(Z_32) | REG_TYPE(Z_64) \
+ | REG_TYPE(ZN)) \
/* 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)) \
@@ -358,9 +365,15 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
case REG_TYPE_R64_SP:
msg = N_("64-bit integer or SP register expected");
break;
+ case REG_TYPE_SVE_BASE:
+ msg = N_("base register expected");
+ break;
case REG_TYPE_R_Z:
msg = N_("integer or zero register expected");
break;
+ case REG_TYPE_SVE_OFFSET:
+ msg = N_("offset register expected");
+ break;
case REG_TYPE_R_SP:
msg = N_("integer or SP register expected");
break;
@@ -697,14 +710,16 @@ aarch64_check_reg_type (const reg_entry *reg, aarch64_reg_type type)
return (reg_type_masks[type] & (1 << reg->type)) != 0;
}
-/* Try to parse a base or offset register. Return the register entry
- on success, setting *QUALIFIER to the register qualifier. Return null
- otherwise.
+/* Try to parse a base or offset register. Allow SVE base and offset
+ registers if REG_TYPE includes SVE registers. 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 const reg_entry *
-aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
+aarch64_addr_reg_parse (char **ccp, aarch64_reg_type reg_type,
+ aarch64_opnd_qualifier_t *qualifier)
{
char *str = *ccp;
const reg_entry *reg = parse_reg (&str);
@@ -726,6 +741,24 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
*qualifier = AARCH64_OPND_QLF_X;
break;
+ case REG_TYPE_ZN:
+ if ((reg_type_masks[reg_type] & (1 << REG_TYPE_ZN)) == 0
+ || str[0] != '.')
+ return NULL;
+ switch (TOLOWER (str[1]))
+ {
+ case 's':
+ *qualifier = AARCH64_OPND_QLF_S_S;
+ break;
+ case 'd':
+ *qualifier = AARCH64_OPND_QLF_S_D;
+ break;
+ default:
+ return NULL;
+ }
+ str += 2;
+ break;
+
default:
return NULL;
}
@@ -735,6 +768,18 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
return reg;
}
+/* 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 const reg_entry *
+aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
+{
+ return aarch64_addr_reg_parse (ccp, REG_TYPE_R_Z_SP, qualifier);
+}
+
/* 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.
@@ -3209,8 +3254,8 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
The A64 instruction set has the following addressing modes:
Offset
- [base] // in SIMD ld/st structure
- [base{,#0}] // in ld/st exclusive
+ [base] // in SIMD ld/st structure
+ [base{,#0}] // in ld/st exclusive
[base{,#imm}]
[base,Xm{,LSL #imm}]
[base,Xm,SXTX {#imm}]
@@ -3219,10 +3264,18 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
[base,#imm]!
Post-indexed
[base],#imm
- [base],Xm // in SIMD ld/st structure
+ [base],Xm // in SIMD ld/st structure
PC-relative (literal)
label
- =immediate
+ SVE:
+ [base,Zm.D{,LSL #imm}]
+ [base,Zm.S,(S|U)XTW {#imm}]
+ [base,Zm.D,(S|U)XTW {#imm}] // ignores top 32 bits of Zm.D elements
+ [Zn.S,#imm]
+ [Zn.D,#imm]
+ [Zn.S,Zm.S{,LSL #imm}] // in ADR
+ [Zn.D,Zm.D{,LSL #imm}] // in ADR
+ [Zn.D,Zm.D,(S|U)XTW {#imm}] // in ADR
(As a convenience, the notation "=immediate" is permitted in conjunction
with the pc-relative literal load instructions to automatically place an
@@ -3249,19 +3302,27 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
.pcrel=1; .preind=1; .postind=0; .writeback=0
The shift/extension information, if any, will be stored in .shifter.
+ The base and offset qualifiers will be stored in *BASE_QUALIFIER and
+ *OFFSET_QUALIFIER respectively, with NIL being used if there's no
+ corresponding register.
- It is the caller's responsibility to check for addressing modes not
+ BASE_TYPE says which types of base register should be accepted and
+ OFFSET_TYPE says the same for offset registers. In all other respects,
+ it is the caller's responsibility to check for addressing modes not
supported by the instruction, and to set inst.reloc.type. */
static bfd_boolean
-parse_address_main (char **str, aarch64_opnd_info *operand)
+parse_address_main (char **str, aarch64_opnd_info *operand,
+ aarch64_opnd_qualifier_t *base_qualifier,
+ aarch64_opnd_qualifier_t *offset_qualifier,
+ aarch64_reg_type base_type, aarch64_reg_type offset_type)
{
char *p = *str;
const reg_entry *reg;
- aarch64_opnd_qualifier_t base_qualifier;
- aarch64_opnd_qualifier_t offset_qualifier;
expressionS *exp = &inst.reloc.exp;
+ *base_qualifier = AARCH64_OPND_QLF_NIL;
+ *offset_qualifier = AARCH64_OPND_QLF_NIL;
if (! skip_past_char (&p, '['))
{
/* =immediate or label. */
@@ -3336,10 +3397,10 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
/* [ */
- reg = aarch64_reg_parse_32_64 (&p, &base_qualifier);
- if (!reg || !aarch64_check_reg_type (reg, REG_TYPE_R64_SP))
+ reg = aarch64_addr_reg_parse (&p, base_type, base_qualifier);
+ if (!reg || !aarch64_check_reg_type (reg, base_type))
{
- set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R64_SP)));
+ set_syntax_error (_(get_reg_expected_msg (base_type)));
return FALSE;
}
operand->addr.base_regno = reg->number;
@@ -3350,12 +3411,12 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
/* [Xn, */
operand->addr.preind = 1;
- reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+ reg = aarch64_addr_reg_parse (&p, offset_type, offset_qualifier);
if (reg)
{
- if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
+ if (!aarch64_check_reg_type (reg, offset_type))
{
- set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
+ set_syntax_error (_(get_reg_expected_msg (offset_type)));
return FALSE;
}
@@ -3379,13 +3440,19 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
|| operand->shifter.kind == AARCH64_MOD_LSL
|| operand->shifter.kind == AARCH64_MOD_SXTX)
{
- if (offset_qualifier == AARCH64_OPND_QLF_W)
+ if (*offset_qualifier == AARCH64_OPND_QLF_W)
{
set_syntax_error (_("invalid use of 32-bit register offset"));
return FALSE;
}
+ if (aarch64_get_qualifier_esize (*base_qualifier)
+ != aarch64_get_qualifier_esize (*offset_qualifier))
+ {
+ set_syntax_error (_("offset has different size from base"));
+ return FALSE;
+ }
}
- else if (offset_qualifier == AARCH64_OPND_QLF_X)
+ else if (*offset_qualifier == AARCH64_OPND_QLF_X)
{
set_syntax_error (_("invalid use of 64-bit register offset"));
return FALSE;
@@ -3468,7 +3535,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
return FALSE;
}
- reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+ reg = aarch64_reg_parse_32_64 (&p, offset_qualifier);
if (reg)
{
/* [Xn],Xm */
@@ -3513,7 +3580,21 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
static bfd_boolean
parse_address (char **str, aarch64_opnd_info *operand)
{
- return parse_address_main (str, operand);
+ aarch64_opnd_qualifier_t base_qualifier, offset_qualifier;
+ return parse_address_main (str, operand, &base_qualifier, &offset_qualifier,
+ REG_TYPE_R64_SP, REG_TYPE_R_Z);
+}
+
+/* Parse an address in which SVE vector registers are allowed.
+ The arguments have the same meaning as for parse_address_main.
+ Return TRUE on success. */
+static bfd_boolean
+parse_sve_address (char **str, aarch64_opnd_info *operand,
+ aarch64_opnd_qualifier_t *base_qualifier,
+ aarch64_opnd_qualifier_t *offset_qualifier)
+{
+ return parse_address_main (str, operand, base_qualifier, offset_qualifier,
+ REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET);
}
/* Parse an operand for a MOVZ, MOVN or MOVK instruction.
@@ -5123,7 +5204,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
int comma_skipped_p = 0;
aarch64_reg_type rtype;
struct vector_type_el vectype;
- aarch64_opnd_qualifier_t qualifier;
+ aarch64_opnd_qualifier_t qualifier, base_qualifier, offset_qualifier;
aarch64_opnd_info *info = &inst.base.operands[i];
aarch64_reg_type reg_type;
@@ -5757,6 +5838,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
case AARCH64_OPND_ADDR_REGOFF:
/* [<Xn|SP>, <R><m>{, <extend> {<amount>}}] */
po_misc_or_fail (parse_address (&str, info));
+ regoff_addr:
if (info->addr.pcrel || !info->addr.offset.is_reg
|| !info->addr.preind || info->addr.postind
|| info->addr.writeback)
@@ -5856,6 +5938,123 @@ parse_operands (char *str, const aarch64_opcode *opcode)
/* No qualifier. */
break;
+ case AARCH64_OPND_SVE_ADDR_RI_U6:
+ case AARCH64_OPND_SVE_ADDR_RI_U6x2:
+ case AARCH64_OPND_SVE_ADDR_RI_U6x4:
+ case AARCH64_OPND_SVE_ADDR_RI_U6x8:
+ /* [X<n>{, #imm}]
+ but recognizing SVE registers. */
+ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+ &offset_qualifier));
+ if (base_qualifier != AARCH64_OPND_QLF_X)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ sve_regimm:
+ if (info->addr.pcrel || info->addr.offset.is_reg
+ || !info->addr.preind || info->addr.writeback)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ if (inst.reloc.type != BFD_RELOC_UNUSED
+ || inst.reloc.exp.X_op != O_constant)
+ {
+ /* Make sure this has priority over
+ "invalid addressing mode". */
+ set_fatal_syntax_error (_("constant offset required"));
+ goto failure;
+ }
+ info->addr.offset.imm = inst.reloc.exp.X_add_number;
+ break;
+
+ case AARCH64_OPND_SVE_ADDR_RR:
+ case AARCH64_OPND_SVE_ADDR_RR_LSL1:
+ case AARCH64_OPND_SVE_ADDR_RR_LSL2:
+ case AARCH64_OPND_SVE_ADDR_RR_LSL3:
+ case AARCH64_OPND_SVE_ADDR_RX:
+ case AARCH64_OPND_SVE_ADDR_RX_LSL1:
+ case AARCH64_OPND_SVE_ADDR_RX_LSL2:
+ case AARCH64_OPND_SVE_ADDR_RX_LSL3:
+ /* [<Xn|SP>, <R><m>{, lsl #<amount>}]
+ but recognizing SVE registers. */
+ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+ &offset_qualifier));
+ if (base_qualifier != AARCH64_OPND_QLF_X
+ || offset_qualifier != AARCH64_OPND_QLF_X)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ goto regoff_addr;
+
+ case AARCH64_OPND_SVE_ADDR_RZ:
+ case AARCH64_OPND_SVE_ADDR_RZ_LSL1:
+ case AARCH64_OPND_SVE_ADDR_RZ_LSL2:
+ case AARCH64_OPND_SVE_ADDR_RZ_LSL3:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW_14:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW_22:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW1_14:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW1_22:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW2_14:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW2_22:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW3_14:
+ case AARCH64_OPND_SVE_ADDR_RZ_XTW3_22:
+ /* [<Xn|SP>, Z<m>.D{, LSL #<amount>}]
+ [<Xn|SP>, Z<m>.<T>, <extend> {#<amount>}] */
+ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+ &offset_qualifier));
+ if (base_qualifier != AARCH64_OPND_QLF_X
+ || (offset_qualifier != AARCH64_OPND_QLF_S_S
+ && offset_qualifier != AARCH64_OPND_QLF_S_D))
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ info->qualifier = offset_qualifier;
+ goto regoff_addr;
+
+ case AARCH64_OPND_SVE_ADDR_ZI_U5:
+ case AARCH64_OPND_SVE_ADDR_ZI_U5x2:
+ case AARCH64_OPND_SVE_ADDR_ZI_U5x4:
+ case AARCH64_OPND_SVE_ADDR_ZI_U5x8:
+ /* [Z<n>.<T>{, #imm}] */
+ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+ &offset_qualifier));
+ if (base_qualifier != AARCH64_OPND_QLF_S_S
+ && base_qualifier != AARCH64_OPND_QLF_S_D)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ info->qualifier = base_qualifier;
+ goto sve_regimm;
+
+ case AARCH64_OPND_SVE_ADDR_ZZ_LSL:
+ case AARCH64_OPND_SVE_ADDR_ZZ_SXTW:
+ case AARCH64_OPND_SVE_ADDR_ZZ_UXTW:
+ /* [Z<n>.<T>, Z<m>.<T>{, LSL #<amount>}]
+ [Z<n>.D, Z<m>.D, <extend> {#<amount>}]
+
+ We don't reject:
+
+ [Z<n>.S, Z<m>.S, <extend> {#<amount>}]
+
+ here since we get better error messages by leaving it to
+ the qualifier checking routines. */
+ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+ &offset_qualifier));
+ if ((base_qualifier != AARCH64_OPND_QLF_S_S
+ && base_qualifier != AARCH64_OPND_QLF_S_D)
+ || offset_qualifier != base_qualifier)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ info->qualifier = base_qualifier;
+ goto regoff_addr;
+
case AARCH64_OPND_SYSREG:
if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0))
== PARSE_FAIL)