aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2023-03-30 11:09:10 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2023-03-30 11:09:10 +0100
commitf5b57feac2389eba64bea45f0115474fbbb13d8e (patch)
treeafbb46bf8da4e5bc451623cf340271fae73c4a38 /gas
parentb5c36ad2e03bc9b8a45a8e495b690c1424cf018f (diff)
downloadfsf-binutils-gdb-f5b57feac2389eba64bea45f0115474fbbb13d8e.zip
fsf-binutils-gdb-f5b57feac2389eba64bea45f0115474fbbb13d8e.tar.gz
fsf-binutils-gdb-f5b57feac2389eba64bea45f0115474fbbb13d8e.tar.bz2
aarch64: Add support for strided register lists
SME2 has instructions that accept strided register lists, such as { z0.s, z4.s, z8.s, z12.s }. The purpose of this patch is to extend binutils to support such lists. The parsing code already had (unused) support for strides of 2. The idea here is instead to accept all strides during parsing and reject invalid strides during constraint checking. The SME2 instructions that accept strided operands also have non-strided forms. The errors about invalid strides therefore take a bitmask of acceptable strides, which allows multiple possibilities to be summed up in a single message. I've tried to update all code that handles register lists.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-aarch64.c58
-rw-r--r--gas/testsuite/gas/aarch64/diagnostic.l2
-rw-r--r--gas/testsuite/gas/aarch64/illegal-sve2.l19
-rw-r--r--gas/testsuite/gas/aarch64/illegal-sve2.s1
4 files changed, 53 insertions, 27 deletions
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index c6cc654..0acb364 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -5065,7 +5065,8 @@ const char* operand_mismatch_kind_names[] =
"AARCH64_OPDE_SYNTAX_ERROR",
"AARCH64_OPDE_FATAL_SYNTAX_ERROR",
"AARCH64_OPDE_INVALID_VARIANT",
- "AARCH64_OPDE_REG_LIST",
+ "AARCH64_OPDE_REG_LIST_LENGTH",
+ "AARCH64_OPDE_REG_LIST_STRIDE",
"AARCH64_OPDE_UNTIED_IMMS",
"AARCH64_OPDE_UNTIED_OPERAND",
"AARCH64_OPDE_OUT_OF_RANGE",
@@ -5092,10 +5093,11 @@ 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 > AARCH64_OPDE_INVALID_VARIANT);
- gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST);
+ gas_assert (AARCH64_OPDE_REG_LIST_LENGTH > AARCH64_OPDE_INVALID_VARIANT);
+ gas_assert (AARCH64_OPDE_REG_LIST_STRIDE > AARCH64_OPDE_REG_LIST_LENGTH);
+ gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST_STRIDE);
gas_assert (AARCH64_OPDE_UNALIGNED > AARCH64_OPDE_OUT_OF_RANGE);
- gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST);
+ gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST_STRIDE);
gas_assert (AARCH64_OPDE_INVALID_REGNO > AARCH64_OPDE_OTHER_ERROR);
return lhs > rhs;
}
@@ -5745,7 +5747,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
detail->data[0].i, idx + 1, str);
break;
- case AARCH64_OPDE_REG_LIST:
+ case AARCH64_OPDE_REG_LIST_LENGTH:
if (detail->data[0].i == (1 << 1))
handler (_("expected a single-register list at operand %d -- `%s'"),
idx + 1, str);
@@ -5757,6 +5759,15 @@ output_operand_error_record (const operand_error_record *record, char *str)
" at operand %d -- `%s'"), idx + 1, str);
break;
+ case AARCH64_OPDE_REG_LIST_STRIDE:
+ if (detail->data[0].i == (1 << 1))
+ handler (_("the register list must have a stride of %d"
+ " at operand %d -- `%s'"), 1, idx + 1, str);
+ else
+ handler (_("invalid register stride at operand %d -- `%s'"),
+ idx + 1, str);
+ break;
+
case AARCH64_OPDE_UNALIGNED:
handler (_("immediate value must be a multiple of "
"%d at operand %d -- `%s'"),
@@ -5860,7 +5871,8 @@ output_operand_error_report (char *str, bool non_fatal_only)
curr->detail.data[0].i, curr->detail.data[1].i,
curr->detail.data[2].i);
}
- else if (curr->detail.kind == AARCH64_OPDE_REG_LIST)
+ else if (curr->detail.kind == AARCH64_OPDE_REG_LIST_LENGTH
+ || curr->detail.kind == AARCH64_OPDE_REG_LIST_STRIDE)
{
DEBUG_TRACE ("\t%s [%x]",
operand_mismatch_kind_names[curr->detail.kind],
@@ -5908,7 +5920,8 @@ output_operand_error_report (char *str, bool non_fatal_only)
curr->detail.data[0].i, curr->detail.data[1].i,
curr->detail.data[2].i);
}
- else if (kind == AARCH64_OPDE_REG_LIST)
+ else if (kind == AARCH64_OPDE_REG_LIST_LENGTH
+ || kind == AARCH64_OPDE_REG_LIST_STRIDE)
{
record->detail.data[0].i |= curr->detail.data[0].i;
DEBUG_TRACE ("\t--> %s [%x]",
@@ -6352,33 +6365,40 @@ ldst_lo12_determine_real_reloc_type (void)
}
/* Check whether a register list REGINFO is valid. The registers must be
- numbered in increasing order (modulo 32), in increments of one or two.
+ numbered in increasing order (modulo 32). They must also have a
+ consistent stride.
- If ACCEPT_ALTERNATE is non-zero, the register numbers should be in
- increments of two.
-
- Return FALSE if such a register list is invalid, otherwise return TRUE. */
+ Return true if the list is valid, describing it in LIST if so. */
static bool
-reg_list_valid_p (uint32_t reginfo, int accept_alternate)
+reg_list_valid_p (uint32_t reginfo, struct aarch64_reglist *list)
{
uint32_t i, nb_regs, prev_regno, incr;
nb_regs = 1 + (reginfo & 0x3);
reginfo >>= 2;
prev_regno = reginfo & 0x1f;
- incr = accept_alternate ? 2 : 1;
+ incr = 1;
+
+ list->first_regno = prev_regno;
+ list->num_regs = nb_regs;
for (i = 1; i < nb_regs; ++i)
{
- uint32_t curr_regno;
+ uint32_t curr_regno, curr_incr;
reginfo >>= 5;
curr_regno = reginfo & 0x1f;
- if (curr_regno != ((prev_regno + incr) & 0x1f))
+ curr_incr = (curr_regno - prev_regno) & 0x1f;
+ if (curr_incr == 0)
+ return false;
+ else if (i == 1)
+ incr = curr_incr;
+ else if (curr_incr != incr)
return false;
prev_regno = curr_regno;
}
+ list->stride = incr;
return true;
}
@@ -6628,6 +6648,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
goto failure;
info->reglist.first_regno = reg->number;
info->reglist.num_regs = 1;
+ info->reglist.stride = 1;
}
else
{
@@ -6635,7 +6656,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
if (val == PARSE_FAIL)
goto failure;
- if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+ if (! reg_list_valid_p (val, &info->reglist))
{
set_fatal_syntax_error (_("invalid register list"));
goto failure;
@@ -6647,9 +6668,6 @@ parse_operands (char *str, const aarch64_opcode *opcode)
(_("expected element type rather than vector type"));
goto failure;
}
-
- info->reglist.first_regno = (val >> 2) & 0x1f;
- info->reglist.num_regs = (val & 0x3) + 1;
}
if (operands[i] == AARCH64_OPND_LEt)
{
diff --git a/gas/testsuite/gas/aarch64/diagnostic.l b/gas/testsuite/gas/aarch64/diagnostic.l
index 6d59564..85ec9fe 100644
--- a/gas/testsuite/gas/aarch64/diagnostic.l
+++ b/gas/testsuite/gas/aarch64/diagnostic.l
@@ -78,7 +78,7 @@
[^:]*:80: Error: immediate value out of range 0 to 15 at operand 1 -- `dmb #16'
[^:]*:81: Error: immediate value out of range 0 to 31 at operand 2 -- `tbz w0,#40,0x17c'
[^:]*:82: Error: expected a list of 2 registers at operand 1 -- `st2 \{v4.2d,v5.2d,v6.2d\},\[x3\]'
-[^:]*:83: Error: invalid register list at operand 1 -- `ld2 \{v1.4h,v0.4h\},\[x1\]'
+[^:]*:83: Error: the register list must have a stride of 1 at operand 1 -- `ld2 \{v1.4h,v0.4h\},\[x1\]'
[^:]*:84: Error: the specified option is not accepted in ISB at operand 1 -- `isb osh'
[^:]*:85: Error: invalid address at operand 2 -- `st2 \{v4.2d,v5.2d,v6.2d\},\\\[x3\\\]'
[^:]*:86: Error: immediate value must be a multiple of 4 at operand 3 -- `ldnp w7,w15,\[x3,#3\]'
diff --git a/gas/testsuite/gas/aarch64/illegal-sve2.l b/gas/testsuite/gas/aarch64/illegal-sve2.l
index 369c0e6..48281fc 100644
--- a/gas/testsuite/gas/aarch64/illegal-sve2.l
+++ b/gas/testsuite/gas/aarch64/illegal-sve2.l
@@ -239,7 +239,7 @@
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `eortb z0\.s,z32\.s,z0\.s'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `eortb z0\.s,z0\.s,z32\.s'
[^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `ext z0\.b,{,},#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z0\.b,z2\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z0\.b,z2\.b},#0'
[^ :]+:[0-9]+: Error: operand mismatch -- `ext z0\.h,{z0\.b,z1\.b},#0'
[^ :]+:[0-9]+: Info: did you mean this\?
[^ :]+:[0-9]+: Info: ext z0\.b, {z0\.b, z1\.b}, #0
@@ -251,8 +251,8 @@
[^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `ext z0\.b,{z0\.b,z1\.b,z2\.b},#0'
[^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `ext z0\.b,{z0\.b},#0'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `ext z0\.b,z0\.b,#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z31\.b,z1\.b},#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z0\.b,z31\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z31\.b,z1\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z0\.b,z31\.b},#0'
[^ :]+:[0-9]+: Error: immediate value out of range 0 to 255 at operand 3 -- `ext z0\.b,{z0\.b,z1\.b},#256'
[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `ext z32\.b,{z0\.b,z1\.b},#0'
[^ :]+:[0-9]+: Error: operand 2 must be a list of SVE vector registers -- `ext z0\.b,{z31\.b,z32\.b},#0'
@@ -1277,7 +1277,7 @@
[^ :]+:[0-9]+: Info: other valid variant\(s\):
[^ :]+:[0-9]+: Info: smullt z0\.s, z0\.h, z0\.h
[^ :]+:[0-9]+: Info: smullt z0\.d, z0\.s, z0\.s
-[^ :]+:[0-9]+: Error: invalid register list at operand 3 -- `splice z0\.b,p0,{z0\.b,z2\.b}'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 3 -- `splice z0\.b,p0,{z0\.b,z2\.b}'
[^ :]+:[0-9]+: Error: operand mismatch -- `splice z0\.h,p0,{z0\.b,z1\.b}'
[^ :]+:[0-9]+: Info: did you mean this\?
[^ :]+:[0-9]+: Info: splice z0\.b, p0, {z0\.b, z1\.b}
@@ -1289,7 +1289,7 @@
[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 3 -- `splice z0\.b,p0,{z0\.b,z1\.h}'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `splice z32\.b,p0,{z0\.b,z1\.b}'
[^ :]+:[0-9]+: Error: p0-p7 expected at operand 2 -- `splice z0\.b,p8,{z0\.b,z1\.b}'
-[^ :]+:[0-9]+: Error: invalid register list at operand 3 -- `splice z0\.b,p0,{z31\.b,z1\.b}'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 3 -- `splice z0\.b,p0,{z31\.b,z1\.b}'
[^ :]+:[0-9]+: Error: operand 3 must be a list of SVE vector registers -- `splice z0\.b,p0,{z31\.b,z32\.b}'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `splice z0\.b,p0,{z32\.b,z1\.b}'
[^ :]+:[0-9]+: Error: expected a register at operand 1 -- `sqabs z32\.b,p0/m,z0\.b'
@@ -2332,7 +2332,7 @@
[^ :]+:[0-9]+: Info: suqadd z0\.d, p0/m, z0\.d, z0\.d
[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `tbl z32\.b,{z0\.b,z1\.b},z0\.b'
[^ :]+:[0-9]+: Error: operand 2 must be a list of SVE vector registers -- `tbl z0\.b,{z31\.b,z32\.b},z0\.b'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `tbl z0\.b,{z31\.b,z1\.b},z0\.b'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `tbl z0\.b,{z31\.b,z1\.b},z0\.b'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `tbl z0\.b,{z0\.b,z1\.b},z32\.b'
[^ :]+:[0-9]+: Error: operand mismatch -- `tbl z0\.b,{z0\.b,z1\.b},z0\.h'
[^ :]+:[0-9]+: Info: did you mean this\?
@@ -2344,6 +2344,13 @@
[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 2 -- `tbl z0\.b,{z0\.b,z1\.h},z0\.b'
[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 2 -- `tbl z0\.b,{z0\.h,z0\.b},z0\.b'
[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `tbl z0\.h,{z0\.b,z0\.b},z0\.b'
+[^ :]+:[0-9]+: Error: operand mismatch -- `tbl z0\.h,{z0\.b,z1\.b},z0\.b'
+[^ :]+:[0-9]+: Info: did you mean this\?
+[^ :]+:[0-9]+: Info: tbl z0\.b, {z0\.b, z1\.b}, z0\.b
+[^ :]+:[0-9]+: Info: other valid variant\(s\):
+[^ :]+:[0-9]+: Info: tbl z0\.h, {z0\.h, z1\.h}, z0\.h
+[^ :]+:[0-9]+: Info: tbl z0\.s, {z0\.s, z1\.s}, z0\.s
+[^ :]+:[0-9]+: Info: tbl z0\.d, {z0\.d, z1\.d}, z0\.d
[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `tbx z32\.h,z0\.b,z0\.b'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `tbx z0\.h,z32\.b,z0\.b'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `tbx z0\.h,z0\.b,z32\.b'
diff --git a/gas/testsuite/gas/aarch64/illegal-sve2.s b/gas/testsuite/gas/aarch64/illegal-sve2.s
index 4b6285c..172d0f4 100644
--- a/gas/testsuite/gas/aarch64/illegal-sve2.s
+++ b/gas/testsuite/gas/aarch64/illegal-sve2.s
@@ -1526,6 +1526,7 @@ tbl z0.b, { z0.b, z1.b }, z0.h
tbl z0.b, { z0.b, z1.h }, z0.b
tbl z0.b, { z0.h, z0.b }, z0.b
tbl z0.h, { z0.b, z0.b }, z0.b
+tbl z0.h, { z0.b, z1.b }, z0.b
tbx z32.h, z0.b, z0.b
tbx z0.h, z32.b, z0.b